XmSHADOW_IN
XmSHADOW_OUT
XmSHADOW_ETCHED_IN
XmSHADOW_ETCHED_OUT
The default value for XmNshadowThickness is 0, except when the BulletinBoard is the child of a DialogShell, in
which case the default value is 1. In either case, the value can be changed by the application or by the user.
The XmNbuttonFontList resource may be set to a font list as described in Chapter 19, Compound Strings. This
font list is used for each of the button children of the BulletinBoard, when the button does not specify its own font. If
the resource is not specified, its value is taken from the XmNbuttonFontList of the nearest ancestor that is a
subclass of BulletinBoard, VendorShell, or MenuShell. Similarly, the XmNlabelFontList and
XmNtextFontList resources can be set for the Labels and Text widgets, respectively, that are direct children of
the BulletinBoard.
9.3.2 Geometry Management
Since the BulletinBoard does not provide any geometry management by default, you must be prepared to manage the
positions and sizes of the widgets within a BulletinBoard. As a result, you must set the XmNx and XmNy resources for
each child. You may also have to set the XmNwidth and XmNheight resources if you need consistent or
predetermined sizes for the children. In order to maintain the layout, you must add an event handler for resize
(ConfigureNotify) events, so that the new sizes and positions of the children can be calculated. the source code
shows the use of an event handler with the BulletinBoard. XtSetLanguageProc() is only available in X11R5;
there is no corresponding function in X11R4.
/* corners.c −− demonstrate widget layout management for a
* BulletinBoard widget. There are four widgets each labeled
* top−left, top−right, bottom−left and bottom−right. Their
* positions in the bulletin board correspond to their names.
* Only when the widget is resized does the geometry management
* kick in and position the children in their correct locations.
*/
#include <Xm/BulletinB.h>
#include <Xm/PushB.h>
char *corners[] = {
"Top Left", "Top Right", "Bottom Left", "Bottom Right",
};
static void resize();
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel, bboard;
XtAppContext app;
XtActionsRec rec;
int i;
XtSetLanguageProc (NULL, NULL, NULL);
/* Initialize toolkit and create toplevel shell */
toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0,
&argc, argv, NULL, NULL);
/* Create your standard BulletinBoard widget */
9 Manager Widgets 9.3.2 Geometry Management
203
bboard = XtVaCreateManagedWidget ("bboard",
xmBulletinBoardWidgetClass, toplevel, NULL);
/* Set up a translation table that captures "Resize" events
* (also called ConfigureNotify or Configure events). If the
* event is generated, call the function resize().
*/
rec.string = "resize";
rec.proc = resize;
XtAppAddActions (app, &rec, 1);
XtOverrideTranslations (bboard,
XtParseTranslationTable ("<Configure>: resize()"));
/* Create children of the dialog −− a PushButton in each corner. */
for (i = 0; i < XtNumber (corners); i++)
XtVaCreateManagedWidget (corners[i],
xmPushButtonWidgetClass, bboard, NULL);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* resize(), the routine that is automatically called by Xt upon the
* delivery of a Configure event. This happens whenever the widget
* gets resized.
*/
static void
resize(w, event, args, num_args)
Widget w; /* The widget (BulletinBoard) that got resized */
XEvent *event; /* The event struct associated with the event */
String args[]; /* unused */
int *num_args; /* unused */
{
WidgetList children;
Dimension w_width, w_height;
short margin_w, margin_h;
XConfigureEvent *cevent = (XConfigureEvent *) event;
int width = cevent−>width;
int height = cevent−>height;
/* get handle to BulletinBoard's children and marginal spacing */
XtVaGetValues (w,
XmNchildren, &children,
XmNmarginWidth, &margin_w,
XmNmarginHeight, &margin_h,
NULL);
/* place the top left widget */
XtVaSetValues (children[0],
XmNx, margin_w,
XmNy, margin_h,
NULL);
/* top right */
XtVaGetValues (children[1], XmNwidth, &w_width, NULL);
XtVaSetValues (children[1],
XmNx, width − margin_w − w_width,
XmNy, margin_h,
NULL);
/* bottom left */
XtVaGetValues (children[2], XmNheight, &w_height, NULL);
XtVaSetValues (children[2],
9 Manager Widgets 9.3.2 Geometry Management
204
XmNx, margin_w,
XmNy, height − margin_h − w_height,
NULL);
/* bottom right */
XtVaGetValues (children[3],
XmNheight, &w_height,
XmNwidth, &w_width,
NULL);
XtVaSetValues (children[3],
XmNx, width − margin_w − w_width,
XmNy, height − margin_h − w_height,
NULL);
}
The program uses four widgets, labeled Top Left, Top Right, Bottom Left, and Bottom Right. The positions of the
buttons in the BulletinBoard correspond to their names. Since the widgets are not positioned when they are created,
the geometry management only happens when the widget is resized. the figure shows the application before and after
a resize event.
Output of corners.c before and after a resize event
When a resize event occurs, X generates a ConfigureNotify event. This event is interpreted by Xt and the
translation table of the widget corresponding to the resized window is searched to see if the application is interested in
being notified of the event. We have indicated interest in this event by calling XtAppAddActions() and
XtOverrideTranslations(), as shown below:
XtActionsRec rec;
...
rec.string = "resize";
rec.proc = resize;
XtAppAddActions (app, &rec, 1);
XtOverrideTranslations (bboard,
XtParseTranslationTable ("<Configure>: resize()"));
9 Manager Widgets 9.3.2 Geometry Management
205
As described in Volume Four, X Toolkit Intrinsics Programming Manual, a translation table pairs a sequence of one
or more events with a sequence of one or more functions that are called when the event sequence occurs. In this case,
the event is a ConfigureNotify event and the function is resize(). Translations are specified as strings and
then parsed into an internal format with the function XtParseTranslationTable(). The routine creates an
internal structure of events and the functions to which they correspond. Xt provides the table for translating event
strings such as <Configure> to the actual ConfigureNotify event, but Xt cannot convert the string
resize() to an actual function unless we provide a lookup table. The XtActionsRec type performs this task.
The structure is defined as follows:
typedef struct {
String string;
XtActionProc proc;
} XtActionsRec;
The action list is initialized to map the string resize to the actual function resize() using
XtAppAddActions(). We install the translation table on the widget using XtOverrideTranslations() so
that when a ConfigureNotify event occurs, the resize() function is called.
The resize() function takes four arguments. The first two arguments are a pointer to the widget in which the event
occurred and the event structure. The args and num_args parameters are ignored because we did not specify any
extra parameters to be passed to the function when we installed it. Since the function is called as a result of the event
happening on the BulletinBoard widget, we know that we are dealing with a composite widget. We also know that
there is only one event type that could have caused the function to be called, so we cast the event parameter
accordingly.
The task of the function is to position the children so that there is one per corner in the BulletinBoard. We get a handle
to all of the children of the BulletinBoard. Since we are going to place the children around the perimeter of the widget,
we also need to know how far from the edge to place them. This distance is taken from the values for
XmNmarginWidth and XmNmarginHeight. All three resource values are retrieved in the following call:
XtVaGetValues (w,
XmNchildren, &children,
XmNmarginWidth, &margin_w,
XmNmarginHeight, &margin_h,
NULL);
The remainder of the function simply places the children at the appropriate positions within the BulletinBoard. The
routine uses a very simple method for geometry management, but it does demonstrate the process.
The general issue of geometry management for composite widgets is not trivial. If you plan on doing your own
geometry management for a BulletinBoard or any other composite widget, you should be very careful to consider all
the resources that could possibly affect layout. In our example, we considered the margin width and height, but there
is also XmNallowOverlap, XmNborderWidth (which is a general Core widget resource),
XmN-shadowThickness (a general manager widget resource) and the same values associated with the children of
the BulletinBoard.
There are also issues about what to do if a child decides to resize itself, such as if a label widget gets wider. In this
case, you must first evaluate what the geometry layout of the widgets would be if you were to grant the Label
permission to resize itself as it wants. This evaluation is done by asking each of the children how big they want to be
and calculating the hypothetical layout. The BulletinBoard either accepts or rejects the new layout. Of course, the
BulletinBoard may have to make itself bigger too, which requires asking its parent for a new size, and so on. If the
BulletinBoard cannot resize itself, then you have to decide whether to force other children to be certain sizes or to
9 Manager Widgets 9.3.2 Geometry Management
206

Get Volume 6A: Motif Programming Manual now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.