17.2.1 Shell Positions
You can position a shell at a specific location on the screen using the XmNx and XmNy resources. In addition, you can
set the XmNx and XmNy resources of the immediate child of a shell widget to position the shell. This feature exists
because Motif dialogs are designed to make their shell widgets invisible to the programmer. It is typically easier to set
these resources directly on the child of a shell, as you are more likely to have a handle to that widget. The following
code fragment shows how you can position a MessageDialog in the center of the screen:
Widget dialog, parent;
Dimension width, height;
Screen screen = XtScreen (parent);
Position x, y;
dialog = XmCreateMessageDialog (parent, "dialog", NULL, 0);
/* get width and height of dialog */
XtVaGetValues (dialog,
XmNwidth, &width,
XmNheight, &height,
NULL);
/* center the dialog on the screen */
x = (WidthOfScreen (screen) / 2) − (width / 2);
y = (HeightOfScreen (screen) / 2) − (height / 2);
XtVaSetValues (dialog,
XmNx, x,
XmNy, y,
NULL);
You can position a dialog in this way because the Motif BulletinBoard widget passes positional information to its
shell parent. See Chapter 5, Introduction to Dialogs, and Chapter 7, Custom Dialogs, for further discussion. In most
cases, you shouldn't be setting the XmNx and XmNy resources for a dialog because it is the job of the window manager
to position shells. The user can also have some say in how placement should be handled. For example, if the user has
set the interactivePlacement resource for mwm to True, he gets to place the window himself when it first
appears. If you set the position of the window, then you are interfering with the positioning method preferred by the
user.
17.2.2 Shell Sizes
In some situations, an application may want to prevent one of its windows from growing or shrinking beyond certain
geometrical limits. For example, an application might want to keep a dialog box from getting so small that some of its
elements are clipped. A paint application might want to restrict its top−level window from growing larger than the size
of its canvas. An application can also constrain the increments by which the user can interactively resize the window.
For example, xterm only allows itself to be resized in character−size increments, where the character size is defined by
the font being used.
The WMShell defines the following resources that can be used to constrain the size of a -window:
XmNminWidth
XmNmaxWidth
XmNminHeight
XmNmaxHeight
XmNwidthInc
XmNheightInc
XmNbaseWidth
17 Interacting With the Window Manager 17.2.1 Shell Positions
473
XmNbaseHeight
The XmNminWidth, XmNmaxWidth, XmNminHeight, and XmNmaxHeight resources specify the minimum and
maximum width and height for the shell. The XmNwidthInc and XmNheightInc resources control the pixel
incrementals by which the window changes when it is being resized by the user. When mwm provides visual feedback
during a resize operation, it specifies the width and height in terms of these increments, rather than pixels. The
XmNbaseWidth and XmNbaseHeight resources specify the base values that are used when calculating the
preferred size of the shell.
the source code demonstrates incremental resizing. The application displays a shell widget that contains a PushButton.
When you click on the button, it displays the size of the window in pixels, but when you resize the window, the mwm
feedback window displays the size in terms of XmNwidthInc and XmNheightInc. XtSetLanguageProc() is
only available in X11R5; there is no corresponding function in X11R4.
/* resize_shell.c −− demonstrate the max and min heights and widths.
* This program should be run to really see how mwm displays the
* size of the window as it is resized.
*/
#include <Xm/PushB.h>
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel, button;
XtAppContext app;
extern void getsize();
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos",
NULL, 0, &argc, argv, NULL,
XmNminWidth, 75,
XmNminHeight, 25,
XmNmaxWidth, 150,
XmNmaxHeight, 100,
XmNbaseWidth, 5,
XmNbaseHeight, 5,
XmNwidthInc, 5,
XmNheightInc, 5,
NULL);
/* Pushbutton's callback prints the dimensions of the shell. */
button = XtVaCreateManagedWidget ("Print Size",
xmPushButtonWidgetClass, toplevel, NULL);
XtAddCallback (button, XmNactivateCallback, getsize, toplevel);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
void
getsize(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
Widget shell = (Widget) client_data;
17 Interacting With the Window Manager 17.2.1 Shell Positions
474
Dimension width, height;
XtVaGetValues (shell,
XmNwidth, &width,
XmNheight, &height,
NULL);
printf ("Width = %d, Height = %d0, width, height);
}
In our example, we arbitrarily specify the minimum and maximum extents of the shell. The width and height
increments are each set to five, so the user can only resize the window in five−pixel increments. As the window is
resized, the feedback window displays the size according to these incremental units, rather than using pixel values. If
you run resize_shell, you can press the PushButton to print the size of the shell in pixels and compare that size with
the size reported by the window manager. If you are going to specify the various size resources for a shell, it only
makes sense to hard−code the values as we have done here. If you specify the resources in an app−defaults file, the
user can override the settings, which defeats the whole point of setting them.
The problem with specifying minimum and maximum extents is that most real applications contain many components
whose sizes cannot be computed easily, making it difficult to determine exactly how large or small the window should
be. If the fonts and strings for PushButtons, Labels, and ToggleButtons can be set in a resource file, the equation
becomes far too difficult to calculate before the window is actually created and displayed. Incremental width and
height values are even more difficult to estimate because there are margins, border widths, and other resources to
consider.
However, all is not lost. If you need to constrain the size of an application, you should consider whether the
application's default initial size can be considered either its maximum or minimum size. If so, you can allow the
window to come up using default size and trap for ConfigureNotify events on the shell widget. You can then use
the default width and height reported in that event as your minimum or maximum size, as demonstrated in the source
code XtSetLanguageProc() is only available in X11R5; there is no corresponding function in X11R4.
/* set_minimum.c −− demonstrate how to set the minimum size of a
* window to its initial size. This method is useful if your program
* is initially displayed at its minimum size, but it would be too
* difficult to try to calculate ahead of time what the initial size
* would be.
*/
#include <Xm/PushB.h>
void getsize(), configure();
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel, button;
XtAppContext app;
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos",
NULL, 0, &argc, argv, NULL,
XmNmaxWidth, 150,
XmNmaxHeight, 100,
XmNbaseWidth, 5,
XmNbaseHeight, 5,
XmNwidthInc, 5,
XmNheightInc, 5,
17 Interacting With the Window Manager 17.2.1 Shell Positions
475
NULL);
/* Add an event handler to trap the first configure event */
XtAddEventHandler (toplevel, StructureNotifyMask, False, configure, NULL);
/* Pushbutton's callback prints the dimensions of the shell. */
button = XtVaCreateManagedWidget ("Print Size",
xmPushButtonWidgetClass, toplevel, NULL);
XtAddCallback (button, XmNactivateCallback, getsize, toplevel);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
void
getsize(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
Widget shell = (Widget) client_data;
Dimension width, height;
XtVaGetValues (shell,
XmNwidth, &width,
XmNheight, &height,
NULL);
printf ("Width = %d, Height = %d0, width, height);
}
void
configure(shell, client_data, event)
Widget shell;
XtPointer client_data;
XEvent *event;
{
XConfigureEvent *cevent = (XConfigureEvent *) event;
if (cevent−>type != ConfigureNotify)
return;
printf ("Width = %d, Height = %d0, cevent−>width, cevent−>height);
XtVaSetValues (shell,
XmNminWidth, cevent−>width,
XmNminHeight, cevent−>height,
NULL);
XtRemoveEventHandler (shell, StructureNotifyMask, False, configure, NULL);
}
We use XtAddEventHandler() to add an event handler to the top−level shell for events that satisfy the
StructureNotifyMask, which includes ConfigureNotify events indicating the window's dimensions. The
configure() function is called when the window is initially sized, so we can use the width and height fields of
the XConfigureEvent structure as values for the XmNminWidth and XmNminHeight resources for the shell.
To prevent the event handler from being called each time the window is resized, the event handler removes itself
using XtRemoveEventHandler().
One problem with this technique occurs when the user has the interactivePlacement resource for mwm set to
True. This specification allows the user to set the initial size and position of an application. However, once the user
sets the initial size, she will never be able to make the window any smaller. Although interactive placement adheres to
the constraints we have set, it cannot enforce a minimum size because we have not set one. Unfortunately, there is no
17 Interacting With the Window Manager 17.2.1 Shell Positions
476

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.