Handling Input Events

Callback Events

A callback function is a segment of program code to be called by the GLG Toolkit 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, first paint event, etc.

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 Using the C/C++ version of the Toolkit.

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.

Attaching Callbacks to a Viewport Object

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 or GLG_TRACE2_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;
Parameters
viewport

A viewport handle corresponding to the viewport to which the callback was attached.

client_data

Application defined data specified by the GlgAddCallback function.

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 remove a callback, use NULL as a callback parameter.

Adding Callbacks to a GLG Wrapper Widget

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

XtNglgSelectCB

XtNglgMotifSelectCB

 

XtNglgInputCB

XtNglgMotifInputCB

 

XtNglgTraceCB

XtNglgTrace2CB

 

XtNglgNumInitCB

XtNglgValInitCB

 

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: NumInit and ValInit , which allow an application to initialize drawing's resources before it is displayed in the widget. The NumInit 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 ValInit 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.

Selection Callback

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 );
}
}
Motif Widget Selection Callback

The Motif version of the GLG Wrapper Widget provides the Motif version of the select callback. The call_data argument supplied to Motif version of the selection callback function is a structure defined as follows:

typedef struct _GlgMotifSelectCBStruct
{
GlgCallbackType reason;
XEvent * event; /* Event that triggered the callback */
GlgObject viewport; /* Wrapper widget's viewport */
Widget widget; /* Wrapper's widget ID */
long num_selected; /* The length of the selection list */
char ** selection_list; /* Same as in the Xt selection callback */
 
} GlgMotifSelectCBStruct;

Note 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.

Input Callback

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 first exposure or top level window closing.

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 are described in Message Object on page 91.

Motif Widget Input Callback

The Motif version of the GLG Wrapper Widget provides the Motif version of the input callback. The call_data argument supplied to Motif version of the input callback is a structure defined as follows:

typedef struct _GlgMotifInputCBStruct
{
GlgCallbackType reason;
GlgObject viewport; /* Wrapper widget's viewport */
Widget widget; /* Wrapper's widget ID */
GlgObject message_obj; /* Same as in the Xt input callback */
 
} GlgMotifInputCBStruct;

Note 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.

Trace Callbacks

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 reason;
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 parameter), 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 reason;
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).

Message Object

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:

 

Resource Name

Data Type

Description

Format

String

Defines the format of the message object and the resources present in it. It is defined by the event type and, for input messages, the type of the input handler which detected the input activity and sent the message. It may have values such as Button , Slider , Knob , ObjectSelection, CustomEvent.

Origin

String

Contains the name of the viewport that initiated the message.

FullOrigin

String

Contains the full path name of the viewport that initiated an input or window message, or the full path name of the object that initiated a custom event message. This resource will be set to an empty string for other types of messages.

Action

String

Describes the input action occurred. It may have values such as ValueChanged , Activated , CustomEvent, MouseClick and so on, depending on the event type.

SubAction

String

Describes the action in more details. For example, for the ValueChanged action it describes what caused the value change and may have values such as Pick , Motion , Increase , and so on.

Object

GlgObject

The viewport object that triggered the input callback, or the object that triggered a custom event or action. This resource is present in all messages except the ObjectSelection message.

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 281 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.

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 );

Printing Selected Object Names using Selection Callback

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 );
}

Printing Selected Object Names using Input Callback

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 );
}
}

Processing Input Object Messages

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 );
}

Refining Input Object Selection

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." );
}

Trace Callback examples

For examples of using the trace callback, refer to the source code of the Glg Diagram Demo.