For automatic scrolling, the only thing left to decide is how you want the ScrollBars to be displayed if the work
window dynamically grows or shrinks. There may be situations where the work window is the same size as or smaller
than the clip window. In this case, you may not want to display the ScrollBars, since they are not needed. If so, you
can set XmN-scrollBarDisplayPolicy to XmAS_NEEDED. If you always want the ScrollBars to be visible,
whether or not they are needed, you can set the resource to XmSTATIC. Some people prefer static ScrollBars, so that
consistency is maintained in the interface; having ScrollBars appear and disappear frequently may be confusing.
Perhaps the best thing to do is to allow the user to specify the XmNscrollBarDisplayPolicy. You can always
set your preference in the application defaults file, as shown below:
*XmScrolledWindow.scrollBarDisplayPolicy: static
10.2.2 Application−defined Scrolling
In the application−defined scrolling mode, XmNscrollingPolicy is set to XmAPPLICATION_DEFINED. In this
case, the work window must be the same size as the clip window, so the size of the work window is set by the toolkit.
As a result, the XmNvisualPolicy resource has the value of XmVARIABLE, which indicates that the work window
grows and shrinks with the ScrolledWindow. Since the two windows are the same size, the ScrolledWindow doesn't
need to have a clip window, so it doesn't create one.
Because application−defined scrolling implies that you are responsible for the creation and management of the
ScrollBars, the toolkit forces the XmNscrollBarDisplayPolicy to XmSTATIC. which means that the
ScrolledWindow always displays the ScrollBars if they are managed. Since the ScrolledWindow cannot know the size
of the entire data, it cannot automate the visibility of the ScrollBars. If you want your application to emulate the
XmAS_NEEDED behavior, you must monitor the size of the ScrolledWindow and the work area and manage the
ScrollBars manually.
10.2.3 Additional Resources
Another ScrolledWindow resource is the XmNworkWindow, which is used to identify the widget that acts as the
ScrolledWindow's work window. A ScrolledWindow can have only one work window and a work window can be
associated with only one ScrolledWindow. In other words, you cannot assign the same widget ID to multiple
ScrolledWindows to get multiple views into the same object. There are ways of achieving this effect, though, that will
become apparent as we go through the chapter.
The XmNclipWindow resource specifies the widget ID for the clip window. This resource is read−only, so it is
illegal to set the clip window manually or to reset it to NULL. For practical purposes, this resource should be left
alone. The XmNverticalScrollBar and XmNhorizontalScrollBar resources specify the widget IDs of the
ScrollBars in the ScrolledWindow. These resources allow you to set and retrieve the ScrollBars, which is useful for
monitoring scrolling actions and setting up application−defined scrolling. Like any other manager, the
ScrolledWindow also has resources that control the margin height and width and other visual attributes.
10.2.4 An Automatic ScrolledWindow Example
Automatic scrolling is the simpler of the two types of scrolling policies available. Fortunately, it is also the more
common of the two. You shouldn't let this simplicity sway you too much, though, as it is a common design error for
programmers to use the automatic scrolling mechanisms for designs that are better suited to the application−defined
model. On the other hand, if you merely want to monitor scrolling without necessarily controlling it, you can install
your own callback routines on the ScrollBars in an automatic ScrolledWindow, as we'll describe in the next section
In automatic mode, a ScrolledWindow automatically creates its own ScrollBars and handles their callback procedures
10 ScrolledWindows and ScrollBars10.2.2 Application−defined Scrolling
256
to position the work window in the clip window. All of the examples that use ScrolledWindows in the rest of the
chapters in this book (such as those in Chapter 4, The Main Window, and Chapter 10, The DrawingArea Widget) use
the automatic scrolling mode. The only exceptions are the ScrolledList and ScrolledText objects, but the List and Text
widgets handle application−defined scrolling internally.
the source code shows a large panel of Labels, ToggleButtons, and Text widgets that are arranged in a collection of
Form and RowColumn widgets and managed by a ScrolledWindow widget. XtSetLanguageProc() is only
available in X11R5; there is no corresponding function in X11R4.
/* getusers.c −− demonstrate a simple ScrolledWindow by showing
* how it can manage a RowColumn that contains a vertical stack of
* Form widgets, each of which contains a Toggle, two Labels and
* a Text widget. The program fills the values of the widgets
* using various pieces of information from the password file.
* Note: there are no callback routines associated with any of the
* widgets created here −− this is for demonstration purposes only.
*/
#include <Xm/PushBG.h>
#include <Xm/LabelG.h>
#include <Xm/ToggleB.h>
#include <Xm/ScrolledW.h>
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <pwd.h>
typedef struct {
String login;
int uid;
String name;
String homedir;
} UserInfo;
/* use getpwent() to read data in the password file to store
* information about all the users on the system. The list is
* a dynamically grown array, the last of which has a NULL login.
*/
UserInfo *
getusers()
{
/* extern struct *passwd getpwent(); */
extern char *strcpy();
struct passwd *pw;
UserInfo *users = NULL;
int n;
setpwent();
/* getpwent() returns NULL when there are no more users */
for (n = 0; pw = getpwent(); n++) {
/* reallocate the pointer to contain one more entry. You may choose
* to optimize by adding 10 entries at a time, or perhaps more?
*/
users = (UserInfo *) XtRealloc (users, (n+1) * sizeof (UserInfo));
users[n].login = strcpy (XtMalloc
(strlen (pw−>pw_name)+1), pw−>pw_name);
users[n].name = strcpy (XtMalloc
(strlen (pw−>pw_gecos)+1), pw−>pw_gecos);
users[n].homedir = strcpy (XtMalloc
10 ScrolledWindows and ScrollBars10.2.2 Application−defined Scrolling
257
(strlen (pw−>pw_dir)+1), pw−>pw_dir);
users[n].uid = pw−>pw_uid;
}
/* allocate one more item and set its login string to NULL */
users = (UserInfo *) XtRealloc (users, (n+1) * sizeof (UserInfo));
users[n].login = NULL;
endpwent();
return users; /* return new array */
}
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel, sw, main_rc, form, toggle;
XtAppContext app;
UserInfo *users;
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0,
&argc, argv, NULL, NULL);
/* Create a 500x300 scrolled window. This value is arbitrary,
* but happens to look good initially. It is resizable by the user.
*/
sw = XtVaCreateManagedWidget ("scrolled_w",
xmScrolledWindowWidgetClass, toplevel,
XmNwidth, 500,
XmNheight, 300,
XmNscrollingPolicy, XmAUTOMATIC,
NULL);
/* RowColumn is the work window for the widget */
main_rc = XtVaCreateWidget ("main_rc", xmRowColumnWidgetClass, sw, NULL);
/* load the users from the passwd file */
if (!(users = getusers())) {
perror ("Can't read user data info");
exit (1);
}
/* for each login entry found in the password file, create a
* form containing a toggle button, two labels and a text widget.
*/
while (users−>login) { /* NULL login terminates list */
char uid[8];
form = XtVaCreateWidget (NULL, xmFormWidgetClass, main_rc, NULL);
XtVaCreateManagedWidget (users−>login, xmToggleButtonWidgetClass, form,
XmNalignment, XmALIGNMENT_BEGINNING,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 15,
NULL);
sprintf (uid, "%d", users−>uid);
XtVaCreateManagedWidget (uid, xmLabelGadgetClass, form,
XmNalignment, XmALIGNMENT_END,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 15,
10 ScrolledWindows and ScrollBars10.2.2 Application−defined Scrolling
258
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 20,
NULL);
XtVaCreateManagedWidget (users−>name, xmLabelGadgetClass, form,
XmNalignment, XmALIGNMENT_BEGINNING,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 20,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 50,
NULL);
/* Although the home directory is readonly, it may be longer
* than expected, so don't use a Label widget. Use a Text widget
* so that left−right scrolling can take place.
*/
XtVaCreateManagedWidget (users−>homedir, xmTextWidgetClass, form,
XmNeditable, False,
XmNcursorPositionVisible, False,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 50,
XmNrightAttachment, XmATTACH_FORM,
XmNvalue, users−>homedir,
NULL);
XtManageChild (form);
users++;
}
XtManageChild (main_rc);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
Those of you who are familiar with UNIX programming techniques should find the use of getpwent() and
endpwent() quite familiar. If you are not aware of these functions, you should consult the documentation for your
UNIX system. In short, they can be used to return information about the contents of the password file (typically
/etc/passwd), which contains information about all of the users on the system. The first call to getpwent() opens
the password file and returns a data structure describing the first entry. Subsequent calls return consecutive entries.
When the entries have been exhausted, getpwent() returns NULL and endpwent() closes the password file. In
the source code the information from the password file is represented using ToggleButtons, Labels, and Text widgets,
as shown in the figure.
10 ScrolledWindows and ScrollBars10.2.2 Application−defined Scrolling
259
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.