Next | Prev | Up | Top | Contents | Index

Drawing-Area Widget Setup and Creation

Most of the steps for writing a program that uses a GLwMDrawingArea widget are already discussed in "Integrating Your OpenGL Program With IRIS IM". This section explains how to initialize IRIS IM and how to create the drawing-area widget, using code fragments from the motif/simplest.c example program (Example 2-1). You learn about


Setting Up Fallback Resources

This section briefly explains how to work with resources in the context of an OpenGL program. In Xt, resources provide widget properties, allowing you to customize how your widgets will look. Note that the term "resource" used here refers to window properties stored by a resource manager in a resource database, not to the data structures for windows, pixmaps, and context discussed earlier.

Fallback resources inside a program are used when a widget is created and the application can't open the class resource file when it calls XtOpenApplication() to open the connection to the X server. (In the code fragment below, the first two resources are specific to Silicon Graphics and give the application a Silicon Graphics look and feel.)

static String  fallbackResources[] = {
    "*useSchemes: all","*sgimode:True",
    "*glxwidget*width: 300", 
    "*glxwidget*height: 300",
    "*frame*shadowType: SHADOW_IN",
    NULL};

Note: Applications should ship with resource files installed in a resource directory (in /usr/lib/X11/app-defaults). If you do install such a file automatically with your application, there is no need to duplicate the resources in your program.


Creating the Widgets

Widgets always exist in a hierarchy, with each widget contributing to what's visible on screen. There's always a top-level widget and almost always a container widget (for example, form or frame). In addition, you may decide to add buttons or scroll bars, which are also part of the IRIS IM widget set. Creating your drawing surface therefore consists of two steps:

  1. Create parent widgets, namely the top-level widget and a container widget. motif/simplest.c, Example 2-1, uses a Form container widget and a Frame widget to draw the 3D box:

    toplevel = XtOpenApplication(&app, "simplest", NULL, 0, &argc, argv,

    fallbackResources, applicationShellWidgetClass, NULL, 0);

    ...

    form = XmCreateForm(toplevel, "form", args, n);

    XtManageChild(form);

    ....

    frame = XmCreateFrame (form, "frame", args, n);

    ...

    For more information, see the reference pages for XmForm and XmFrame.

  2. Create the GLwMDrawingArea widget itself in either of two ways:

Caution: Creating the widget does not actually create the window. An application must wait until after it has realized the widget before performing any OpenGL operations to the window, or use the ginit callback to indicate when the window has been created. Note that unlike most other Motif widgets, the OpenGL widget explicitly sets the visual. Once a visual is set and the widget is realized, the visual can no longer be changed.


Choosing the Visual for the Drawing-Area Widget

There are three ways of configuring the GLwMDrawingArea widget when calling the widget creation function, all done through resources:

If you wish to provide error handling, call glXChooseVisual(), as all the example programs do (although for the sake of brevity, none of the examples actually provides error handling). If you provide the resources and let the widget choose the visual, the widget just prints an error message and quits. Note that a certain visual may be supported on one system but not on another, so appropriate error handling is critical to a robust program.

The advantage of using a list of resources is that you can override them with the app-defaults file.


Creating Multiple Widgets With Identical Characteristics

Most applications have one context per widget, though sharing is possible. If you want to use multiple widgets with the same configuration, you must use the same visual for each widget. Windows with different visuals can't share contexts. To share contexts:

  1. Extract the GLwNvisualInfo resource from the first widget you create.

  2. Use that visual in the creation of subsequent widgets.

Using Drawing-Area Widget Callbacks

The GLwMDrawingArea widget provides callbacks for redrawing, resizing, input, and initialization, as well as the standard XmNdestroyCallback provided by all widgets.

Each callback must first be defined and then added to the widget. In some cases, this is quite simple, as, for example, the resize callback from motif/simplest.c:

static void
resize(Widget w, XtPointer client_data, XtPointer call) {
   GLwDrawingAreaCallbackStruct *call_data;
   call_data = (GLwDrawingAreaCallbackStruct *) call;

   glViewport(0, 0, call_data->width, call_data->height);
}
Other cases are slightly more complex, such as the input callback from motif/simplest.c, which exits when the user presses the <Esc> key:

static void
input(Widget w, XtPointer client_data, XtPointer call) {

char buffer[31];

KeySym keysym;

XEvent *event = ((GLwDrawingAreaCallbackStruct *)call) ->event;


switch(event->type) {

case KeyRelease:

XLookupString(&event->xkey, buffer, 30, &keysym, NULL);

switch(keysym) {

case XK_Escape :

exit(EXIT_SUCCESS);

break;

default: break;

}

break;

}

}

To add callbacks to a widget, use XtAddCallback(); for example:

XtAddCallback(glxwidget, GLwNexposeCallback, expose, NULL);
XtAddCallback(glxwidget, GLwNresizeCallback, resize, NULL);
XtAddCallback(glxwidget, GLwNinputCallback, input, NULL);
Each callback must ensure that the thread is made current with the correct context to the window associated with the widget generating the callback. You can do this by calling either GLwMDrawingAreaMakeCurrent() or glXMakeCurrent().

If you're using only one GLwMDrawingArea, you can call a routine to make the widget "current" just once, after initializing the widget. However, if you're using more than one GLwMDrawingArea or rendering context, you need to make the correct context and the window current for each callback (see "Binding the Context to the Window").

The following callbacks are available:


Next | Prev | Up | Top | Contents | Index