MediaWiki API result

This is the HTML representation of the JSON format. HTML is good for debugging, but is unsuitable for application use.

Specify the format parameter to change the output format. To see the non-HTML representation of the JSON format, set format=json.

See the complete documentation, or the API help for more information.

{
    "batchcomplete": "",
    "continue": {
        "gapcontinue": "Redirecting_Debug_Output_to_the_Serial_Port_on_Startup",
        "continue": "gapcontinue||"
    },
    "warnings": {
        "main": {
            "*": "Subscribe to the mediawiki-api-announce mailing list at <https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce> for notice of API deprecations and breaking changes."
        },
        "revisions": {
            "*": "Because \"rvslots\" was not specified, a legacy format has been used for the output. This format is deprecated, and in the future the new format will always be used."
        }
    },
    "query": {
        "pages": {
            "582": {
                "pageid": 582,
                "ns": 0,
                "title": "ReAction",
                "revisions": [
                    {
                        "contentformat": "text/x-wiki",
                        "contentmodel": "wikitext",
                        "*": "== Introduction ==\n\nReAction is a toolkit for [[GUI Programming|GUI programming]] in AmigaOS. Originally a third-party product, it became part of the operating system in AmigaOS 3.5. The system, whose original tools have been rather limited and limiting, received a comprehensive toolkit covering most GUI programming needs. Over the years ReAction has grown and matured, with many features added. It is now the recommended toolkit for GUI programming under AmigaOS.\n\nReAction is based on Intuition's [[BOOPSI_-_Object_Oriented_Intuition|BOOPSI]], an object-oriented philosophy. '''Understanding the basic concepts of BOOPSI is an important prerequisite for working with ReAction'''. Although this documentation tries to be as clear and helpful as possible, certain parts can make certain assumptions about the programmer's knowledge of BOOPSI, so make sure you have studied the BOOPSI article linked above.\n\nThere seems to be a certain degree of confusion as regards the actual relation between ReAction and BOOPSI. It must be understood that the two are not really interchangeable terms (although they are sometimes used in this way). ReAction is a BOOPSI toolkit so there is a ''part/whole'' relation between them. ReAction can\u2019t exist without BOOPSI, but BOOPSI can perfectly exist without ReAction. BOOPSI is a general object-oriented programming framework while ReAction is a set of ready-made classes based on this framework.\n\n=== Main features ===\n\nReAction is:\n\n; object-oriented\n: All GUI elements created via the toolkit \u2013 windows, gadgets, images, even ARexx ports \u2013 are manipulated as ''objects'' of a certain [[#Class Overview|class]]. The class determines the look, function and general properties of the object; objects of the same class serve the same purpose and share the same properties. In a program, a GUI element (object) is an ''instance'' of a class, therefore object creation is often referred to as [[#Object Creation (Instantiation) and Disposal|instantiation]].\n\n; modular and extensible\n: ReAction is implemented as a set of modules (class libraries) that reside on disk. New classes can be written or derived (\u201csubclassed\u201d) from existing classes, thus adding new functionality to the toolkit.\n\n; layout-based\n: GUI elements provided by the toolkit are meant to be placed in a ''layout'': a hierarchical structure determining how objects are positioned, sized and grouped in the GUI. Objects governed by a layout are not programmed for specific positions or sizes; instead, these parameters are automatically decided by the layout according to the properties of the individual objects.\n\n; BOOPSI-compatible\n: Program GUIs created through ReAction can include other AmigaOS components based on BOOPSI, such as [[Datatypes_Library|datatypes]] or Intuition\u2019s internal BOOPSI classes. On the other hand, ReAction is '''not''' compatible (= cannot exchange classes or combine GUI elements) with the MUI toolkit because the latter uses its own system of class management. Neither is ReAction compatible with the [[GadTools_Library|GadTools]] toolkit because it is not based on BOOPSI.\n\n=== Class Overview ===\n\nThe following classes are currently installed as part of the ReAction toolkit, in the directory \u201cSYS:Classes\u201d on your system disk:\n\n{| class=\"wikitable\"\n! class || public name (ClassID) || function / GUI element type\n|-\n| ARexx || arexx.class || Simplifies the creation and usage of ARexx ports in your programs.\n|-\n| PopUpMenu || popupmenu.class || Provides context (local) menus.\n|-\n| Requester || requester.class || Greatly extends the original concept of [[Intuition_Requesters_and_Alerts|Intuition requesters]], providing several requester types with many features.\n|-\n| Window || window.class || A powerful class to create windows with advanced features such as iconification, the AppWindow facility, or an automatic layouting system.\n|}\n\nThe following Gadget Class sub-classes are currently installed as part of the ReAction toolkit, in the directory \u201cSYS:Classes/Gadgets\u201d on your system disk (the parent, Gadget Class, is part of Intuition):\n\n{| class=\"wikitable\" style=\"text-align: left\"\n! class || public name (ClassID) || function / GUI element type\n|-\n| Button || button.gadget || \n|-\n| CheckBox || checkbox.gadget || \n|-\n| Chooser || chooser.gadget ||\n|-\n| ClickTab || clicktab.gadget || \n|-\n| DateBrowser || datebrowser.gadget || \n|-\n| FuelGauge || fuelgauge.gadget || \n|-\n| GetColor || getcolor.gadget ||\n|-\n| GetFile || getfile.gadget || \n|-\n| GetFont || getfont.gadget || \n|-\n| GetScreenMode || getscreenmode.gadget ||\n|-\n| Integer || integer.gadget || \n|-\n| Layout || layout.gadget || \n|-\n| ListBrowser || listbrowser.gadget ||\n|-\n| Page || page.gadget || \n|-\n| RadioButton || radiobutton.gadget || \n|-\n| Scroller || scroller.gadget || \n|-\n| SketchBoard || sketchboard.gadget ||\n|-\n| Slider || slider.gadget || \n|-\n| Space || space.gadget ||\n|-\n| SpeedBar || speedbar.gadget || \n|-\n| String || string.gadget ||\n|-\n| TextEditor || texteditor.gadget ||\n|-\n| Virtual || virtual.gadget ||\n|}\n\nThe following Image Class sub-classes are currently installed as part of the ReAction toolkit, in the directory \u201cSYS:Classes/Images\u201d on your system disk (the parent, Image Class, is part of Intuition):\n\n{| class=\"wikitable\" style=\"text-align: left\"\n! class || public name (ClassID) || function / GUI element type\n|-\n| Bevel || bevel.image || \n|-\n| BitMap || bitmap.image || \n|-\n| DrawList || drawlist.image ||\n|-\n| Filler || filler.image || \n|-\n| Glyph || glyph.image || \n|-\n| Label || label.image || \n|-\n| PenMap || penmap.image || \n|-\n| Table || table.image || \n|}\n\n=== Attributes and Methods ===\n\nBOOPSI objects (as defined by their respective classes) are described by ''attributes'' and manipulated through ''methods''.\n\n==== Attributes ====\n\nAn attribute is a particular property or feature of an object. While some classes implement attributes that are specific (and only relevant) to themselves, there are certain attributes that are common for a particular group of classes, eg. gadgets. In the AmigaOS implementation, an object attribute takes the form of a ''tag'', which is a name/value pair. As most classes support multiple attributes, complete ''tag lists'' can be used to describe an object:\n\n<syntaxhighlight>\nGA_Text, \"Don\u2019t ever dare to click on me!\",\nGA_ReadOnly, TRUE,\nBUTTON_Justification, BCJ_LEFT,\nBUTTON_SoftStyle, FSF_ITALIC,\nTAG_END\n</syntaxhighlight>\n\nThe tag list above describes a hypothetical Button Gadget object. The first two tags are applicable to gadget classes in general (\u201cGA\u201d standing for \u201cGadget Attribute\u201d). They say that the gadget should display the text \u201cDon\u2019t ever dare to click on me!\u201d and that it should be rendered as a non-selectable (read-only) GUI element. The other two tags are specific to the ReAction Button Gadget. They say, respectively, that the text in the gadget should be left-aligned and rendered in italics. TAG_END indicates the end of the tag list.\n\n==== Methods ====\n\nA method is a function that does something to the object: creates it, destroys it, changes its properties, etc. While you can call \u2013 or as we say, ''invoke'' \u2013 BOOPSI methods directly using Intuition functions IDoMethod() and DoGadgetMethod(), the most common methods are hidden from the programmer and take the form of \u201cnormal\u201d functions:\n\n{| class=\"wikitable\"\n! method || function(s) invoking this method || meaning\n|-\n| OM_NEW || NewObject() || creates a new object instance\n|-\n| OM_DISPOSE || DisposeObject() || destroys the object and frees all associated resources\n|-\n| OM_SET || SetAttrs(), SetGadgetAttrs() || sets or changes object properties\n|-\n| OM_GET || GetAttr(), GetAttrs() || query about a particular object property or multiple properties\n|}\n\nThe methods in the table above are applicable to all classes because they are defined at the highest (\u201crootclass\u201d) level in the BOOPSI class hierarchy. This is why they are also referred to as ''rootclass methods''.\n\n== Class Opening and Closing ==\n\nClasses are, in fact, standard Amiga libraries. The data structure describing a BOOPSI class is called ClassLibrary. As you can see from the C-language definition below, the structure contains the standard ''struct Library'' plus some additional fields. This makes it possible to treat classes as normal libraries and, at the same time, support BOOPSI-specific features:\n\n<syntaxhighlight>\nstruct ClassLibrary\n{\n    struct Library  cl_Lib;   /* Embedded library */\n    UWORD           cl_Pad;   /* Align the structure */\n    Class          *cl_Class; /* Class pointer */\n};\n</syntaxhighlight>\n\nLike other system libraries, classes must be opened before they are used. An exception to this rule are classes that are part of another component. For example, certain BOOPSI classes are \u201chardcoded\u201d in Intuition so they can be accessed as soon as you open the Intuition Library. Similarly, in the ReAction toolkit, the Page Gadget class is part of the Layout Gadget binary; therefore, pages can be used once the Layout Gadget class becomes available.\n\nIn the past, BOOPSI classes were opened/closed just like you would open/close any other library, that is, through the Exec functions OpenLibrary() and CloseLibrary(). Despite having being shown in numerous code examples, this practice is now considered deprecated and the AmigaOS 4 Intuition received dedicated functions, OpenClass() and CloseClass(). The opening call actually returns two variables in one go: the ''class library base'' and the ''class pointer''. When closing the class, the library base is passed as parameter. The class pointer can (and should) be used for [[#Object Creation (Instantiation) and Disposal|object instantiation]]; see below.\n\nThe following code snippet opens and closes the ReAction Layout Gadget class:\n\n<syntaxhighlight>\nstruct ClassLibrary *LayoutBase; /* the class library base */\nClass *LayoutClass;              /* the class pointer */\n\nLayoutBase = IIntuition->OpenClass(\"layout.gadget\", 52, &LayoutClass);\n\n/* do something */\n\nIIntuition->CloseClass(LayoutBase);\n</syntaxhighlight>\n\nThe number refers to the class version, 52 being a sensible minimum. This particular OpenClass() call returns the Layout Gadget class library base (LayoutBase) and stores the class pointer in the LayoutClass variable. The call, if successful, also sets the cl_Class field in the ClassLibrary data structure (see the definition above) so when it, later, comes to actually using the class pointer, you can either keep the LayoutClass value, or you can retrieve the pointer from the library base (ie. its data structure) like this:\n\n<syntaxhighlight>\nLayoutClass = LayoutBase->cl_Class;\n</syntaxhighlight>\n\nRemember that unlike OpenClass(), the more universal OpenLibrary() function is unaware of BOOPSI-specific features so it will neither return the class pointer, nor set the the cl_Class field in ''struct ClassLibrary''. The following section explains why the class pointer is so important.\n\n== Object Creation (Instantiation) and Disposal ==\n\nIn order to create a ReAction GUI element you have to ''instantiate its object'' from a particular class. Instantiation is performed through the Intuition function NewObject() which, if successful, returns an ''object pointer''. Internally, the function invokes the OM_NEW method, which every BOOPSI class must implement by specification and which creates an ''object instance''.\n\nNewObject() takes three arguments as input:\n\n* a ''class pointer'', as obtained from OpenClass();\n* a ''class public name'' (also called ClassID), which is a text string;\n* a tag list describing object properties ([[#Attributes and Methods|attributes]]).\n\nThe first two arguments are mutually exclusive: one of them will always be NULL. You can either instantiate the object from the class pointer, or from the public name (provided that the class is public \u2013 all ReAction classes are public classes). Using the class pointer is noticeably faster on lower-end systems. Instantiation via public names carries a certain overhead associated with walking through the system class list and processing name strings. For example, if twenty objects of the same class were to be instantiated using the class name, the NewObject() routine would go through the system list no less than twenty times, despite the class being identical! Compared to this, the class pointer is only obtained once \u2013 during OpenClass() \u2013 and points directly to the particular class without any further lookup. In other words, if you want your GUI to get created as fast as possible, use the class pointer in the NewObject() call whenever you can.\n\nClasses that are part of another component (such as the \u201cinternal\u201d BOOPSI classes in Intuition, or the ReAction Page Gadget class) are inherently public and can only be instantiated via their public name. As they are never opened directly (see [[#Class Opening and Closing|Class Opening and Closing]] above), you don\u2019t have access to their class pointer and must, therefore, use the name instead \u2013 there is no other way.\n\nThe following code instantiates a Layout Gadget object and a Page Gadget object. Both methods are shown here: the layout is created from the class pointer whereas the page is instantiated from the public name (remember that the Page Gadget class code is part of the Layout Gadget binary, so there is no class pointer for the page). When the objects are no longer needed, you are expected to call DisposeObject() to clean up after yourself. The function invokes the OM_DISPOSE method and frees all resources associated with the particular object instance:\n\n<syntaxhighlight>\nObject *LayoutGadget;  /* object pointers */\nObject *PageGadget;\n\n/* Instantiate the layout gadget using the class pointer. \n   The pointer variable, LayoutClass, is taken over from the OpenClass() example in the previous section. */\nLayoutGadget = IIntuition->NewObject(LayoutClass, NULL,\n      LAYOUT_Orientation, LAYOUT_ORIENT_VERT,\n      TAG_END);\n\n/* Instantiate the page gadget using the public class name. */\nPageGadget = IIntuition->NewObject(NULL, \"page.gadget\",\n      TAG_END);\n\n/* Do something and, ultimately, dispose of both objects. */\nIIntuition->DisposeObject(LayoutGadget);\nIIntuition->DisposeObject(PageGadget);\n</syntaxhighlight>\n\n=== Objects in Hierarchy ===\n\nCertain ReAction classes allow (or even expect) their objects to have ''children objects'' attached. For example, a Window Class object normally carries a layout object that defines the contents of the window. Similarly, a Page Gadget object typically embeds a layout object defining the page contents. Layouts \u2013 hierarchical by nature \u2013 also take other objects as children, allowing for simple as well as complex GUI structures spanning several object generations.\n\nObjects with children objects attached to them are disposed of together with all their children, including their children\u2019s children (should there be any). In other words, only the ''parent object'' is disposed of. This feature is illustrated by the following example, in which the page gadget receives a child object \u2013 a layout gadget; this entire parent-child structure is subsequently attached to another layout as its child object. As you can see, only one DisposeObject() call is necessary:\n\n<syntaxhighlight>\nObject *LayoutGadget_1;  /* object pointers */\nObject *LayoutGadget_2;\nObject *PageGadget;\n\n/* Instantiate the page gadget with a child layout object. */\nPageGadget = IIntuition->NewObject(NULL, \"page.gadget\",\n     PAGE_Add, LayoutGadget_1 = IIntuition->NewObject(LayoutClass, NULL,\n          LAYOUT_Orientation, LAYOUT_ORIENT_VERT,\n          TAG_END),\n     TAG_END);\n\n/* Now instantiate another layout gadget and add the page structure\n   created by the previous call as a child object. */\nLayoutGadget_2 = IIntuition->NewObject(LayoutClass, NULL,\n     LAYOUT_Orientation, LAYOUT_ORIENT_VERT,\n          LAYOUT_AddChild, PageGadget,\n     TAG_END);\n\n/* Do something and, ultimately, dispose of the parent object.\n   Both children (PageGadget and LayoutGadget_1) will be disposed of automatically. */\nIIntuition->DisposeObject(LayoutGadget_2);\n</syntaxhighlight>\n\n\n\n\n''(to be  continued)''\n\n== Context and Input/Output ==\n\nDescribe how input.task is involved, etc."
                    }
                ]
            },
            "632": {
                "pageid": 632,
                "ns": 0,
                "title": "RealTime Library",
                "revisions": [
                    {
                        "contentformat": "text/x-wiki",
                        "contentmodel": "wikitext",
                        "*": "The RealTime Library provides a convenient, higher-level interface to underlying hardware timers that is easy to use. The library also provides for the distribution of timing pulses to an unlimited number of client applications on a priority basis, thus supporting multitasking in the most robust manner possible.\n\n= Conductors and PlayerInfos =\n\nThe RealTime Library uses the Conductor structure to manage timing. There can be any number of Conductor structures, each of which represents a separate and independent timing context (i.e. a group of applications that want to be synced together). \n\nEach Conductor can have one or more client applications. A second structure called a PlayerInfo is set up by each client application that wants to get timing information from the Conductor. There is typically one PlayerInfo for each task that wants to get timing information (a task could have more than one but this would be unusual).\n\nBoth the Conductor and PlayerInfo structures are dynamic. You never create these structures by allocating and initializing them yourself. The system provides the functions to do this for you. Also, the structures are read-only. To change the fields within these structures, use the system-provided functions and tags.\n\nAn application will usually create a single PlayerInfo structure and then attach it to a Conductor. If the Conductor does not yet exist, it will be created by the system. To create a PlayerInfo structure you call CreatePlayer():\n\n<syntaxhighlight>\nstruct PlayerInfo *pi = IRealTime->CreatePlayer(Tag tag, ...);\n</syntaxhighlight>\n\nThis call takes a list of tag items that describe the attributes of the PlayerInfo structure you want to create. (A complete list of all the tags available can be found in the Autodoc for SetPlayerAttrs().) It returns a pointer to the PlayerInfo. Here\u2019s a fragment showing how to set up a PlayerInfo:\n\n<syntaxhighlight>\nstruct PlayerInfo *pPlayerInfo = IRealTime->CreatePlayer(\n  PLAYER_Name, \"My_player\",\n  PLAYER_Conductor, \"My_conductor\",\n  TAG_END);\n\nif (pPlayerInfo != NULL )\n{\n  // Your real-time application goes here...\n\n  IRealTime->DeletePlayer(pPlayerInfo);\n}\n</syntaxhighlight>\n\nIn the code above, a PlayerInfo will be created with the name of \"My_player\". It will be attached to the Conductor structure named \"My_conductor\". If a Conductor structure named \"My_conductor\" does not already exist, the system will create one. Other applications could also attach their PlayerInfos to \"My_conductor\".\n\nWhen your application finishes, you should delete any PlayerInfos you have created by calling DeletePlayer(). The Conductor will be automatically deleted by the system (however, this won\u2019t happen until '''all''' the PlayerInfos attached to a Conductor are deleted).\n\nOnce you have a PlayerInfo and Conductor set up, you can obtain timing pulses for your application. Timing pulses come from underlying timer chips and are passed to your application through the Conductor.\n\n= Getting Clock Ticks =\n\nThe RealTime Library uses a tick frequency of 600 Hz so clock pulses are delivered approximately every 1.66 ms. There are two ways to get this timing information:\n\n* An alarm's signal \n* A clock tick callback hook \n\n== Using the alarm facility ==\n\nYou can ask the RealTime Library to signal your task at some future time by using its alarm facility. This allows you to operate asynchronously. For instance, you could start a group of MIDI notes playing and set the realtime alarm to signal you when they should be stopped, then go on to some other job such as preparing the next group of notes before calling Wait() on the alarm signal.\n\nThe fragment below shows how to set up the library\u2019s alarm clock to signal the calling task at time = 1000 ticks (the fragment assumes that the RealTime Library interface is already obtained).\n\n<syntaxhighlight>\n// This fragment assumes the that IRealTime is already obtained.\nint8 midiSignal = IExec->AllocSignal(-1);  // Allocate a wake-up signal bit\nif (midiSignal != -1)\n{\n  struct PlayerInfo *pPlayerInfo = IRealTime->CreatePlayer(\n    PLAYER_Name, \"My_player\",\n    PLAYER_Conductor, \"My_conductor\",\n    PLAYER_SignalTask, IExec->FindTask(NULL),\n    PLAYER_AlarmSigBit, midiSignal,\n    TAG_END);\n\n  if (pPlayerInfo != NULL)\n  {\n    // Start the realtime clock running.\n    int32 res = IRealTime->SetConductorState(pPlayerInfo, CLOCKSTATE_RUNNING, 0);\n    if (!res)\n    {\n      BOOL timerr = IRealTime->SetPlayerAttrs(pPlayerInfo,\n        PLAYER_AlarmTime, 1000,\n        PLAYER_Ready, TRUE,\n        TAG_END);\n      if (timerr)\n      {\n        // You could do some other job before\n        // calling Wait() on the alarm signal.\n        IExec->Wait(1UL << midiSignal);\n      }\n      else IDOS->Print(\"Couldn't set alarm\\n\");\n    }\n    else IDOS->Printf(\"Couldn't start clock\\n\");\n  }\n  else IDOS->Printf(\"Couldn't set up PlayerInfo structure.\\n\");\n}\nelse IDOS->Printf(\"Couldn't allocate signal.\\n\");\n</syntaxhighlight>\n\nIn the fragment above, the calling task requests a PlayerInfo with an alarm clock feature by passing the PLAYER_AlarmSigBit tag to CreatePlayer() The ti_Data field of this tag contains the signal bit that will be set by the RealTime Library when the alarm goes off. The PLAYER_SignalTask tag indicates which task will be signaled.\n\nThe realtime clock is then started by calling SetConductorState() (discussed below). This is important since any alarm requests made when the clock is stopped will be ignored.\n\nFinally, the alarm time is set by calling SetPlayerAttrs(). The parameters to this call are:\n<syntaxhighlight>\nBOOL result = SetPlayerAttrs(struct PlayerInfo *pi, Tag tag, ...);\n</syntaxhighlight>\n\nThe pi parameter indicates which PlayerInfo structure is to have its attributes changed. The Tag items indicate the attributes and their new values. If the change is made successfully, then TRUE is returned. FALSE indicates failure. In the fragment above, a wake-up time is \nrequested using the PLAYER_AlarmTime tag. Also, the calling task indicates to the Conductor that it is ready by using the PLAYER_Ready tag (more on this below).\n\nAt this point, the call to Wait(1UL << midiSignal) causes the task to sleep until time = 1000 ticks.\n\n== Using the clock tick callback facility ==\n\nThe discussion so far has concentrated on the alarm facility of the RealTime Library. An even finer level of control over time is available using the clock tick callback hook facility. Instead of setting an alarm to signal your task at some future time, the hook facilities allow your application code to be invoked whenever Conductor time is updated.\n\nThe realtime clock is driven by an interrupt that simply increments the base time and then uses software interrupts to distribute the time to any Conductors. By using a callback hook, you can have your custom code invoked at the software interrupt level (before tasks) \nwhenever Conductor time is refreshed.\n\nTo set up a callback hook, you use the PLAYER_Hook tag with the address of a standard Hook structure as defined in <utilities/hook.h>. This structure contains the address of the code you want to be invoked whenever the RealTime Library updates your Conductor. Here\u2019s a code fragment showing how this is done:\n\n<syntaxhighlight>\nstruct Task *My_task;\nint8 My_signal;\n\nuint32 My_hookFunc(struct Hook *hook, struct pmTime *msg, struct PlayerInfo *pi);\n\nint main()\n{\n  // ...Open the RealTime Library and do other set up here...\n\n  struct Hook My_hook;\n  My_hook.h_Entry = (HOOKFUNC)My_hookFunc;\n  \n  uint32 ticks = 1000;\n  stuct PlayerInfo *pPlayerInfo = IRealTime->CreatePlayer(\n    PLAYER_Name, \"My_player\",\n    PLAYER_Conductor, \"My_conductor\",\n    PLAYER_Hook, &My_hook,\n    PLAYER_UserData, &ticks,\n    TAG_END);\n    \n  if (pPlayerInfo != NULL)\n  {\n    My_task   = IExec->FindTask(NULL);  // Initialize these globals so that\n    My_signal = IExec->AllocSignal(-1); // the hook function can signal us.\n    if (My_signal != -1)\n    {\n      // Start the clock running.\n      int32 res = IRealTime->SetConductorState(pPlayerInfo, CLOCKSTATE_RUNNING, 0);\n      if (!res)\n      {\n        // ...your code goes here...\n        IExec->Wait(1UL << My_signal | SIGBREAKF_CTRL_C);\n      }\n      \n      IExec->FreeSignal(My_signal);\n    }\n    \n    IRealTime->DeletePlayer(pPlayerInfo);\n  }\n\n  // ...Close the library, etc...\n}\n</syntaxhighlight>\n\nIn the code above the function named My_hookFunc() will be called by the RealTime Library whenever it updates Conductor time.\n\nHere\u2019s the callback hook function itself. This simply compares Conductor time to a variable, ticks, whose address is pointed to by pi\u00ad>pi_UserData. Notice how this address was filled in using the PLAYER_UserData tag in the call to SetPlayerAttrs() in main() above. When \nConductor time equals or exceeds ticks, the hook function signals the main task.\n\n<syntaxhighlight>\n// Hook code called whenever the RealTime Library updates Conductor time.\n// Normally this is 600 times/sec.\nuint32 My_hookFunc(struct Hook *hook, struct pmTime *msg, struct PlayerInfo *pi)\n{\n  switch (msg->pmt_Method)\n  {\n   case PM_TICK:\n     // Test whether Conductor time has exceeded the number in *ticks*.\n     // If it has, then signal the parent task.\n     if ((*uint32*)(pi->pi_Userdata)) < pi->pi_Source->cdt_ClockTime)\n       IExec->Signal(My_task, 1UL << My_signal);\n     break;\n\n   default:\n     break;     \n  }\n  \n  return 0;\n}\n</syntaxhighlight>\n\n= More About Conductors =\n\nIt is the job of the Conductor to act as middleman between the Amiga's timing hardware and client tasks represented by PlayerInfo structures. Each Conductor keeps track of:\n* an Exec list of all its client players \n* the state of the conductor (i.e. running, stopped, paused, locating \u2013 see below) \n* what time it is relative to start time\n* whether the Conductor is using the Amiga\u2019s internal hardware for its timing pulses or an external source\n\nAs shown in the examples above, the \"state\" of the Conductor can be changed at any time by calling SetConductorState(). If the call succeeds, zero is returned:\n\n<syntaxhighlight>\nint32 res = IRealTime->SetConductorState(struct PlayerInfo *pi, int32 newstate, int32 ti);\n</syntaxhighlight>\n\nThe pi parameter is a pointer to a PlayerInfo structure that is linked to the Conductor you want to change. The ti parameter is a time offset used for special cases (typically set to zero). The ''newstate'' parameter is one of the following:\n{| class=\"wikitable\"\n| CLOCKSTATE_STOPPED || The clock is not running\n|-\n| CLOCKSTATE_PAUSED || To the RealTime Library, this is exactly the same as stopped. This is provided as a convenience to those applications that wish to make a distinction between the two. \n|-\n| CLOCKSTATE_RUNNING || The clock is running and time pulses are being distributed to any client applications (PlayerInfos) that are ready.\n|-\n| CLOCKSTATE_LOCATE || This is the same as running with one exception: the clock does not actually start until ''all'' client applications have indicated that they are ready by setting the PLAYER_Ready attribute of their PlayerInfo to TRUE. This allows applications that cannot start immediately to set up before timing pulses actually begin.\n|}\n\nThe difference between locating and running requires some explanation. Each PlayerInfo has a \"ready bit\" which is used to tell the RealTime Library that the player is ready to receive ticks. This bit is reset each time the library relocates the clock to a new time.\n\nThe reason for the ready bit is that some applications need to find the appropriate location in the multimedia sequence or score before they can start playing at the new location. In some cases this can take a considerable amount of time. Hence, CLOCKSTATE__LOCATE is used with the ready bit to allow all players that are sharing a timing context to be synchronized together.\n\nPlayers can set the state of their ready bit by using the PLAYER_Ready tag attribute either when the PlayerInfo is created with CreatePlayer() or later with SetPlayerAttrs(). See the first code fragment above for an example of this."
                    }
                ]
            }
        }
    }
}