A callback is a function or method that is invoked under certain conditions. For example, a callback is called each time a user selects something in a GLG drawing with the mouse. The code is supplied by the application developer.
A callback can be invoked for one of a few possible reasons:
The user has used the mouse to select some graphical object in the drawing area of the widget, generating object selection and custom selection events.
The user has moved the mouse over some object in the drawing, which may generate selection events as well.
An input widget, such as button or slider, has received some input from the user. This usually arrives in the form of mouse motion or button clicking, although the text widget accepts typed input as well.
The window has received some window event, such as a window closing request, resize event, etc.
A SubWindow object has loaded the drawing that will be displayed in it, or a SubDrawing object has loaded its template.
The GLG Wrapper Widget also invokes callback functions at startup, when resources are set. For information about the wrapper widget and its callback lists, see Callback Resources of X Windows and Wrapper Widget on page 23.
An alarm handler is a special global callback that handles alarm events. Refer to GlgSetAlarmHandler on page 70 for more information.
In addition to these callbacks, the GLG Toolkit provides trace callbacks that are invoked whenever a GLG viewport receives any event. The trace callbacks are used as an escape mechanism to provide low-level access to native windowing events. There are two trace callbacks: a trace callback invoked before dispatching the event for processing, and a trace2 callback invoked after the event has been processed by the Toolkit.
A callbacks is attached to a viewport with the GlgAddCallback function, which takes the callback type and the callback function as parameters:
void GlgAddCallback( viewport, type, callback, client data ) GlgObject viewport; GlgCallbackType type; GlgCallbackProc callback; GlgAnyType client_data;The callback type may be one of GLG_INPUT_CB, GLG_SELECT_CB, GLG_TRACE_CB, GLG_TRACE2_CB or GLG_HIERARCHY_CB values defined in the GlgApi.h file.
All callbacks use the same function prototype:
typedef void (*GlgCallbackProc)( viewport, client_data, call_data ) GlgObject viewport; GlgAnyType client_data; GlgAnyType call_data;Callback-specific data supplying information about the event which caused the callback.
A callback must be attached to a viewport before the viewport's object hierarchy is set up (after the viewport is loaded but before it is drawn). Child viewports may have their own callbacks attached, different from the callbacks of their parent viewport. Only one callback of each type can be attached to one viewport object. To remove a callback, use NULL as a callback parameter.
In the Motif/Xt environment, a GLG callback can also be attached to the top level viewport of the GLG Wrapper Widget's drawing as an Xt callback using the XtAddCallback function. The callback types include
Notice that for the select and input callbacks two callback types are provided: one following the GLG generic cross-platform format and one following the Motif calling convention. The callbacks must be added before the widget is realized and its drawing hierarchy is set up.
There are two widget initialization callbacks: HInit and VInit , which allow an application to initialize drawing's resources before it is displayed in the widget. The HInit callback is invoked after the widget's drawing is loaded, but before its hierarchy is setup. It may be used to initialize values of H resources, such as a number of instances in a series object or a number of points in a graph. The VInit callback is invoked after the hierarchy setup, but before the drawing is displayed. It may be used for initializing V resources, such as initial data values for a graph.
The Xt callbacks use the standard XtCallbackProc prototype and pass the callback information to the application using the callback's call_data parameter. The following description of specific callback types includes the description of Motif-style callbacks.
The selection callback provides a simplified name-based interface to handle object selection. The input callback may be used to process object selection using more elaborate techniques, including custom selection events.
A selection callback is called when the user selects objects in the widget with a mouse click. If no objects are selected, the call_data parameter will be NULL. If some objects are selected by the click, the call_data parameter will contain a list of names of all selected objects. This list is a NULL-terminated list of pointers to strings, each of which represents the complete path name of one object selected by the mouse click. If more than one object is selected, the list will contain several strings. The objects drawn on top will be listed first. The pointer to the list as well as pointers to the individual strings point to internal data structures which should not be modified.
The GlgGetSelectionButton function may be used to find out which mouse button was pressed to activate the selection callback.
The path name obtained in the selection callback may be used to query or access resources of the selected object. For example, if the fifth bar of a bar graph was selected, one of the path names will be DataGroup/DataSample4. To query the value of this data sample, concatenate this path name with "Value" using the GlgConcatResNames function and use the resulting DataGroup/DataSample4/Value path name in a call to GlgGetDResource .
The following example shows how to highlight the selected data sample of a graph with a different color in the selection callback:
void Select( viewport, client_data, call_data ) GlgObject viewport; GlgAnyType client_data; GlgAnyType call_data; { int i; char ** name_array, * name, * resource_name; if( !name_array ) return; for( i=0; name = name_array[ i ]; ++i ) if( strstr( name, "DataGroup/DataSample" ) ) { /* Concatenate the name of the data sample with "FillColor". */ resource_name = GlgConcatResNames( name, "FillColor" ); GlgSetGResource( viewport, resource_name, 1., 0., 0. ); /* Red.*/ GlgFree( resource_name ); } }The Motif version of the GLG Wrapper Widget provides the Motif-style select callback (XtNglgMotifSelectionCB) in addition to the standard GLG callback (XtNglgSelectionCB). The call_data argument supplied to Motif version of the selection callback function is a structure defined as follows:
typedef struct _GlgSelectCBStruct { GlgCallbackType reason; XEvent * event; /* Event that triggered the callback */ GlgObject viewport; /* Viewport that received the mouse clickNote that the structure contains the same list of selected objects that is sent to a callback function when using the Xt version of the Wrapper Widget.
The Toolkit translates the low-level events of the native windowing system, such as mouse moves, and mouse clicks, into high-level GLG events, such as object selection events, custom events associated with GLG objects and input events such as slider moves and button presses. An input callback is the primary mechanism for handling any GLG events occurring in an application. It is invoked for several types of input activities:
When some input activity is detected by an input widget, like moving a slider or a knob with the mouse. The widget has an input handler attached to the widget's viewport to process incoming events, and the type of the widget is defined by the type of the handler.
When objects in the drawing are selected with the mouse over or mouse click events.
When custom events associated with objects in the drawing are triggered in response to mouse over or mouse move events.
When window events occur, such as closing a top level GLG window.
To activate processing of selection and custom selection events on the mouse click and mouse move, the viewport's ProcessMouse attribute must be set to GLG_MOUSE_CLICK or GLG_MOUSE_MOVE_AND_CLICK, respectively. The rest of the event are always processed and do not require any additional settings.
If a system event in a viewport is translated into some GLG event, the input callback of the viewport object is invoked. If the viewport doesn't have an input callback attached, the input callback of its closest parent with input callback is invoked. The call_data parameter of the callback contains a message object used to pass all information about the event to the callback. This information is present in the message object in the form of named resources of the message object and may be obtained from it by using methods for querying resources ( GlgGetSResource , GlgGetDResource and GlgGetGResource ). The message object should be passed as the first parameter, and a resource name defining the resource to query should be passed as the second parameter. For example, the following code extracts the value of the message object's Origin resource:
char * origin; GlgGetSResource( message_object, "Origin", &origin );The details of the message object for each event type are described in Message Object on page 98.
The Motif version of the GLG Wrapper Widget provides the Motif-style input callback (XtNglgMotifInputCB) in addition to the standard GLG callback (XtNglgInputCB). The call_data argument supplied to Motif version of the input callback is a structure defined as follows:
typedef struct _GlgInputCBStruct { GlgCallbackType reason; GlgObject viewport; /* Viewport that received the event thatNote that the structure contains the same message object that is sent to a callback function when using the Xt version of the Wrapper Widget; see Message Object, below.
The trace callbacks are used as an escape mechanism to provide low-level access to native windowing events. They are invoked whenever a viewport receives a native windowing event and passes the event to the application code for processing. If a viewport object has a trace callback attached, the trace callback will be invoked for all events received by the viewport and all of its child viewports. There are two trace callbacks: the trace callback is invoked before the event is dispatched for processing, and the trace2 callback is invoked after the event has been processed.
As with the other callbacks, it is attached to a viewport with the GlgAddCallback function, or through the resources of the GLG Wrapper Widget.
The information necessary to completely identify an event may be gathered by parsing window data returned to the callback function, or by invoking functions in the GLG Standard or Extended API.
The call_data passed to these callback functions is a structure of platform-specific window data given by the following. In the X Windows environment, the call_data structure looks like this:
typedef _GlgTraceCallbackStruct { GlgCallbackType callback_type; GlgObject viewport; Display display; Window window; XEvent * event; XEvent * event1; } GlgTraceCallbackStruct;The callback structure contains enough information to determine which viewport received the event (indicated by the viewport field), and where it is. It also contains a pointer to an XEvent structure, which may be used to provide details of the event. (The event1 pointer is reserved for future use).
Under Microsoft Windows, the trace callback structure looks like this:
typedef _GlgTraceCallbackStruct { GlgCallbackType callback_type; GlgObject viewport; void * display; HWND widget; HWND window; MSG * event; void * event1; } GlgTraceCallbackStruct;As with the X Windows version, this structure contains information enough to identify the viewport that received the event, and to provide more detail about the event itself. (The event1 pointer is reserved for future use). The callback_type field is set to the type of the callback: GLG_TRACE_CB or GLG_TRACE2_CB.
The hierarchy callback is used to get access to the drawing to be displayed in the SubWindow object before the drawing is displayed. SubWindows may be used to switch drawings displayed in them, and an application may want to install a separate input callback for each loaded drawing to handle user interaction instead of having one giant input callback that handles input events from all drawings. An input callback has to be added to the viewport of a drawing displayed in the subwindow before the drawing is set up and drawn. The hierarchy callback is invoked with the ID of the subwindow's drawing after it is loaded but before its hierarchy is setup, making it possible to add input callbacks as well as initialize the drawing with data before it is painted on the screen.
Similarly, the hierarchy callback is also invoked for the SubDrawing objects when they load their template drawings; the callback provides an object ID of the loaded object that will be displayed in the subdrawing.
The hierarchy callback is attached to a viewport with the GlgAddCallback function. A hierarchy callback may be added to the top level viewport or any of its children viewports. If any of a subwindow's (or subdrawing's) parent viewports has a hierarchy callback added, the callback of the closest parent viewport will be invoked each time the subwindow loads a new drawing or the subdrawing loads its template. The hierarchy callback is invoked twice for each template drawing: the first time when the drawing is loaded but before it is set up, and the second time when the drawing is setup but before it is drawn.
The call_data passed to the hierarchy callback is a structure that provides an object ID of the SubWindow object that triggered the callback, as well as an object ID of the viewport of the loaded drawing:
typedef _GlgHierarchyCallbackStruct { GlgCallbackType callback_type; GlgHierarchyCallbackType reason; GlgObject object; GlgObject subobject; } GlgHierarchyCallbackStruct;The callback_type field of the callback structure is always set to GLG_HIERARCHY_CB. The reason field indicates when the callback is invoked: it is set to GLG_BEFORE_SETUP_CB when the callback is called before the hierarchy setup and to GLG_AFTER_SETUP_CB when it is invoked after the setup.
The object field provides an object ID of the SubWindow or SubDrawing object that triggered the callback. The subobject field contains an ID of the drawing that will be displayed in the subwindow, or ID of the object that will be shown in the subdrawing (the Instance attribute).
The source code of the SCADA Viewer demo provides an example of using the callback.
A message object is a GLG object like any other. It is a group object, containing data in the form of named attributes just like other GLG objects. It is used to pass data to the input callbacks that may be associated with a viewport.
Any message object has the following named attributes:
A message object can have other resources as well, depending on the type of the event and, for input object events, the type of the input handler that generated the event. For events generated by input objects, the message object includes handler-related resources of the input widget. For example, the message object coming from a GLG slider object may also contain such resources as ValueX, ValueY, Granularity, Increment, DisableMotion and others. These resources may be queried from either the message object or the viewport object that generated the message.
Refer to Appendix B: Message Object Resources on page 302 for a complete list of all message types and their resources. Refer to Input Handlers of the GLG User's Guide for a complete list of resources for each input handler type.
The following examples demonstrate how to use GLG callbacks. Refer to the source code of the GLG demos for additional examples.
The following code adds both selection and input callbacks to the drawing viewport object:
GlgAddCallback( drawing, GLG_SELECT_CB, SelectCB, callback_data ); GlgAddCallback( drawing, GLG_INPUT_CB, InputCB, callback_data );A selection callback has several parameters, one of which is a list of names of all selected objects, including complete path identifying the place of objects in the drawing hierarchy. The following example shows a selection callback which prints names of all selected objects:
void SelectCB( drawing, client_data, call_data ) GlgObject drawing; GlgAnyType client_data; GlgAnyType call_data; { char ** name_ array; char * name; int i; name_array = (char **) call_data; if( !name_array ) PrintOnConsole( "Nothing was selected." ); else for( i=0; name = name_array[ i ]; ++i ) PrintOnConsole( name ); }While the select callback provides a simplified name-based interface for handling object selection, the input callback provides a more elaborate mechanism based on object IDs. The following example shows how to process selection using both the object selection messages (requires the use of the Extended API) and custom selection events (does not require the Extended API).
The object selection event is generated when the mouse is moved over an object in the drawing or an object is clicked on with the mouse. The custom selection events are generated if the object is selected and has the GlgMouseOverEvent or GlgMouseClickEvent property attached. The value of these properties is used as the custom event's label. The ProcessMouse attribute of the viewport object has to be set to Move & Click or Click to enable object selection and custom selection events. Refer to Integrated Features of the GLG Drawing of the GLG User's Guide for more information on object selection and custom selection events.
void InputCB( viewport, client_data, call_data ) GlgObject viewport; GlgAnyType client_data; GlgAnyType call_data; { GlgObject message_object, selection_array, selected_object; char * format, /* Message format */ * action, /* Message action */ * origin, /* Name of the object that generated custom event */ * name; double button_index; /* Button that caused object selection. */ int i, size; message_object = (GlgObject) call_data; GlgGetSResource( message_object, "Format", &format ); GlgGetSResource( message_object, "Action", &action ); if( strcmp( format, "ObjectSelection" ) == 0 ) { selection_array = GlgGetResourceObject( message_object, "SelectionArray" ); if( !selection_array ) { PrintToConsole( "No objects selected by ", action ); return; } /* For MouseClick actions, query the mouse button that caused the the selection (0 for MouseMove events). */ GlgGetDResource( message_object, "ButtonIndex", &button_index ); size = GlgGetSize( selection_array ); for( i=0; i < size; ++i ) { selected_object = GlgGetElement( selection_array, i ); GlgGetSResource( selected_object, "Name", &name ); /* Print MouseMove or MouseClick. */ PrintToConsole2( "Selected by: ", action ); if( !name || !*name ) PrintToConsole( "Unnamed object is selected." ); else PrintToConsole2( "Selected object: ", name ); } } else if( strcmp( format, "CustomEvent" ) == 0 ) { /* Origin is the name of the object that generated this event. */ GlgGetSResource( message_object, "Origin", &origin ); if( !origin || !*origin ) { PrintOnConsole2( "Unnamed object, mouse moved away or mouse", "button released." ); return; } /* Another way to query the selected object's name. */ GlgGetSResource( message_object, "Object/Name", &name ); /* For MouseClick actions, query the mouse button that generated this custom selection event (0 for custom MouseOver events). */ GlgGetDResource( message_object, "ButtonIndex", &button_index ); /* Prints MouseClick or MouseOver. */ PrintOnConsole2( "Custom event action: ", action ); PrintOnConsole2( "Selected object: ", origin ); } }The following example demonstrates a very simple input callback which terminates the application when a "Quit" button is pressed:
void InputCB( drawing, client_data, call_data ) GlgObject drawing; GlgAnyType client_data; GlgAnyType call_data; { GlgObject message_object; char * origin, /* Name of the input object */ * format, /* Type of the input object */ * action; /* Reason */ message_object = (GlgObject) call_data; GlgGetSResource( message_object, "Origin", &origin ); GlgGetSResource( message_object, "Format", &format ); GlgGetSResource( message_object, "Action", &action ); if( strcmp( format, "Button" ) == 0 && strcmp( action, "Activate" ) == 0 && strcmp( origin, "Quit" ) == 0 ) exit( 0 ); }The following code fragment shows an example of an input callback. The code determines which of the two gauges in the widget (the temperature gauge or pressure gauge) received user input, and calls the appropriate function to process the new gauge value specified by the user.
void InputCallback( viewport, client_data, call_data ) GlgObject viewport; GlgAnyType client_data; GlgAnyType call_data; { GlgObject message_obj; char * format, * action, * full_origin; double value; message_obj = (GlgObject)call_data; /* Extract callback data from the message object. */ GlgGetSResource( message_obj, "Format", &format ); GlgGetSResource( message_obj, "Action", &action ); GlgGetSResource( message_obj, "FullOrigin", &full_origin ); /* Ignore if message came not from a slider or not a ValueChanged. */ if( strcmp( format, "Slider" ) != 0 || strcmp( action, "ValueChanged" ) != 0 ) return; /* Obtain the new value of the slider. */ GlgGetDResource( message_obj, "Value", &value ); /* Call an appropriate function depending on the name of the slider. */ if( strcmp( full_origin, "TemperatureBlock/Gauge" ) == 0 ) ProcessTemperatureInput( widget, value ); else if( strcmp( full_origin, "PressureBlock/Gauge" ) == 0 ) ProcessPressureInput( widget, value ); else Error( "Unknown name." ); }