By this stage you should have a rudimentary understanding of how the Pandora Engine is structured, so it's time to look at an example program before we dive into the more technical side of the system. If you've seen a Hello World program before, you might be familiar with examples such as:
#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { printf("Hello World.\n"); return(0); }
And even:
10 PRINT "Hello World"
For the purposes of this example, we are going to make the exercise a little more interesting and open an Athene window that has "Hello World" printed inside of it. This will give you some working knowledge of the system in general, as well as the construction of a basic program interface.
If you're using the Pandora Engine to write programs within Athene, the only realistic option for writing a Hello World equivalent is to use DML. While we're going to show you how to write a Hello World executable in the next part of this section, for the amount of time it takes to write the same thing in DML, there is no practical reason for writing Hello World as an executable program. In this case we will make an exception for the sake of comparison and the fact that we want to show you how to write Pandora executables.
Here is a Hello World program written in DML:
<?xml version="1.0"?> <!DOCTYPE dml PUBLIC "-//ROCKLYTE//DTD DML 1.0//EN" "http://www.rocklyte.com/dtd/dml_1_0.xml"> <dml type="program"> <window title="Hello World" insideborder="1" insideheight="100" insidewidth="180"> <render x="[container.leftmargin]" y="[container.topmargin]" xoffset="[container.rightmargin]" yoffset="[container.bottommargin]" colour="#ffffff"> <text align="center" string="Hello World" colour="#000000"/> </render> </window> </dml>
The primary reason why we can write this program so quickly in DML is not due to the simplicity of the language, but because all the basic elements for creating the program (such as printing text) are already available as dynamic instructions. If we were creating something more complex, then using a combination of DML and class code would be necessary, which would make the process far more time consuming.
For the purposes of this part of the manual we will not discuss the intricacies of DML, but you can refer to the DML Whitepaper if you need further information on how DML works.
Writing a Pandora based executable from scratch is a fairly straight-forward affair and does not require a great deal of startup code. The following code illustrates a working program that displays a window containing the words "Hello World". When the user clicks on the window's close gadget, the program ends. Here's the code:
#include <pandora/system/all.h> #include <pandora/graphics/all.h> #include <pandora/functions/set.c> STRING ProgName = "Hello World"; STRING ProgAuthor = "Rocklyte Systems"; STRING ProgDate = "July 2001"; STRING ProgCopyright = "Copyright Rocklyte Systems (c) 2001. All rights reserved."; extern struct KernelBase *KernelBase; ERROR PROGRAM_ActionNotify(OBJECTPTR, struct acActionNotify *); FIELD FID_PrimaryObject, FID_Align, FID_Face, FID_String, FID_Colour; FIELD FID_TopMargin, FID_LeftMargin, FID_RightMargin, FID_BottomMargin; OBJECTID WindowID = 0; ERROR program(void) { struct Message message; struct NextMsg next; struct Render *render; APTR *actions; OBJECTPTR script, window, text, task; OBJECTID RenderID; FLOAT topmargin, bottommargin, rightmargin, leftmargin; if (ResolveFields("PrimaryObject", &FID_PrimaryObject, "LeftMargin", &FID_LeftMargin, "TopMargin", &FID_TopMargin, "BottomMargin", &FID_BottomMargin, "RightMargin", &FID_RightMargin, "Align", &FID_Align, "Face", &FID_Face, "String", &FID_String, "Colour", &FID_Colour, TAGEND) != ERR_Okay) return(ERR_ResolveFields); /*** Intercept some actions that are required for our program ***/ if (AttemptExclusive(CurrentTask(), 5000, &task) IS ERR_Okay) { if (GetField(task, FID_Actions, FT_POINTER, &actions) IS ERR_Okay) { actions[AC_ActionNotify] = PROGRAM_ActionNotify; } else { FreeExclusive(task); return(ERR_GetField); } FreeExclusive(task); } else return(ERR_ExclusiveDenied); /*** Open a window ***/ if (NewObject(ID_SCRIPT, NULL, &script, NULL) IS ERR_Okay) { SetField(script, FID_Location, FT_POINTER, "templates:window.dml"); SetUnlistedFields(script, "title", ProgName, "insideborder", "1", "container", "desktop", "insidewidth", "200", "insideheight", "100", TAGEND); if (Action(AC_Init, script, NULL) IS ERR_Okay) { if (Action(AC_Activate, script, NULL) IS ERR_Okay) { GetField(script, FID_PrimaryObject, FT_LONG, &WindowID); Action(AC_Free, script, NULL); script = NULL; /*** Get the window margins ***/ if (AttemptExclusive(WindowID, 10000, &window) IS ERR_Okay) { GetFields(window, FID_LeftMargin|TFLOAT, &leftmargin, FID_TopMargin|TFLOAT, &topmargin, FID_BottomMargin|TFLOAT, &bottommargin, FID_RightMargin|TFLOAT, &rightmargin, TAGEND); if (AttemptExclusive(CurrentTask(), 3000, &task) IS ERR_Okay) { SubscribeAction(window, AC_Free, task); FreeExclusive(task); } FreeExclusive(window); } /*** Create a render area for drawing graphics ***/ if (CreateObject(ID_RENDER, NULL, &render, &RenderID, FID_Container|TLONG, WindowID, FID_XCoord|TFLOAT, leftmargin, FID_YCoord|TFLOAT, topmargin, FID_XOffset|TFLOAT, rightmargin, FID_YOffset|TFLOAT, bottommargin, FID_Colour|TSTRING, "#ffffff", TAGEND) IS ERR_Okay) { /*** Create the Hello World text ***/ CreateObject(ID_TEXT, NULL, &text, NULL, FID_Container|TLONG, RenderID, FID_String|TSTRING, "Hello World", FID_Align|TLONG, ALIGN_CENTER, FID_Face|TSTRING, "Sans Serif", FID_Colour|TSTRING, "#000000", TAGEND); /*** Show the Render object ***/ Action(AC_Show, render, NULL); FreeExclusive(render); /*** Main loop ***/ while (ProcessMessages(&next, MF_WAIT) IS ERR_Okay) { if (next.Count > 0) { if (GetMessage(NULL, NULL, NULL, &message, sizeof(struct Message)) IS ERR_Okay) { if (message.Type IS MSGID_QUIT) { ActionMsg(AC_Free, WindowID, NULL); break; } else DPrintF("@Program:","Received unknown message type #%d.", message.Type); } } } } } } } if (script) Action(AC_Free, script, NULL); return(ERR_Okay); } ERROR PROGRAM_ActionNotify(OBJECTPTR Self, struct acActionNotify *Args) { if ((Args->ActionID IS AC_Free) AND (Args->ObjectID IS WindowID)) { SendMessage(NULL, MSGID_QUIT, NULL, NULL, NULL); } return(ERR_Okay); }
Please note that if you need exact detail on the functionality of this program, you can click on the hyperlinks to read the function documentation. Step-by-step, this is an overview of how the program works:
That's all there is to it - not quite a walk in the park for creating Hello World, but for a program that opens a window and draws graphics, it could have been a lot more difficult. This is the only working example of an executable program in this manual, so if you want to see more, please refer to the source code that is provided with the Pandora Engine to learn more from other programs.
Next: Object Management In Depth
Table of Contents