Single or multiline editing is controlled through the XmNeditMode resource. The value of the resource can be either
XmSINGLE_LINE_EDIT or XmMULTI_LINE_EDIT. While the two editing modes are quite different in concept, it
should be quite intuitive when to use the different modes. Single−line text entry areas are commonly used to prompt
for file and directory names, short phrases, or single words. They are also useful for command−line entry in
applications that were originally based on a tty−style interface. Multiline editing is used for editing files or other large
quantities of text.
15.2.3 Scrollable Text
The layout of a multiline Text widget can be difficult to manage, especially if the text is editable by the user. An
application needs to decide how many lines of text are displayed, how to handle the layout when the user adds new
text, and how to deal with resizing the Text widget. The easiest way to manage an editable multiline Text widget is to
create it as part of a ScrolledText compound object. The ScrolledText object is not a widget class in and of itself, but
rather a compound object that is composed of a Text widget and a ScrolledWindow widget.
When you create a ScrolledText object, the ScrolledWindow automatically handles scrolling the text in the Text
widget. Basically, the two widget classes have hooks and procedures that allow them to cooperate intelligently with
each other. As of Motif 1.2, the performance of the ScrolledText object has improved considerably. One unfortunate
side−effect of the performance improvement is that subclasses of the Text widget may not work under Motif 1.2, due
to the addition of a new data structure. In previous releases, scrolling operations could be quite slow when the Text
widget contained a large amount of text.
You can create a ScrolledText object using the Motif convenience routine XmCreateScrolledText(), which
takes the following form:
Widget
XmCreateScrolledText(parent, name, arglist, argcount)
Widget parent;
char *name;
ArgList arglist;
Cardinal argcount;
This routine is not a variable−argument list function; it uses the argument−list style of setting resources with the
XtSetArg() macro.
XmCreateScrolledText() creates a ScrolledWindow widget and a Text widget as its child. The routine returns
a handle to the Text widget; you can get a handle to the ScrolledWindow using the function XtParent(). When
you are laying out an application that uses ScrolledText objects, you should be sure to use XtParent() to get the
ScrolledWindow widget, since that is the widget that you need to position.
For purposes of specifying resources, the ScrolledWindow takes the name of the Text widget with the suffix SW. For
example, if the name of the Text widget is name, its ScrolledWindow parent widget has the name nameSW.
If you specify an argument list in a call to XmCreateScrolledText(), the resources are set for the Text widget
or the ScrolledWindow as appropriate. The routine also sets some resources for the ScrolledWindow so that scrolling
is handled automatically. You should be sure to set the XmNeditMode resource to XmMULTI_LINE_EDIT, since it
doesn't make sense to have a single−line Text widget in a ScrolledWindow. If you don't set the resource, the Text
widget defaults to single−line editing mode. The behavior of a single−line Text widget (or a TextField widget) in a
ScrolledWindow is undefined.
XmCreateScrolledText() is adequate for most situations, but you can also create the two widgets separately, as
shown in the following code fragment:
15 Text Widgets 15.2.3 Scrollable Text
384
Widget scrolled_w, text_w;
scrolled_w = XtVaCreateManagedWidget ("scrolled_w",
xmScrolledWindowWidgetClass, parent,
XmNscrollingPolicy, XmAPPLICATION_DEFINED,
XmNvisualPolicy, XmVARIABLE,
XmNscrollBarDisplayPolicy, XmSTATIC,
XmNshadowThickness, 0,
NULL);
text_w = XtVaCreateManagedWidget ("text",
xmTextWidgetClass, scrolled_w,
XmNeditMode, XmMULTI_LINE_EDIT,
...
NULL);
We create the ScrolledWindow widget with the same resource setting that the Motif function uses. Since we are
creating the ScrolledWindow ourselves, we can give it our own name. The Text widget itself is created as a child of
the ScrolledWindow. In this situation, it is clear that the parent of the ScrolledWindow controls the position of both of
the widgets.
This creation method makes the programmer responsible for managing both of the widgets. You may also need to
handle the case in which the widgets are destroyed. When you call XmCreateScrolledText(), the routine
installs an XmNdestroyCallback on the Text widget that destroys the ScrolledWindow parent. When you create
the widgets yourself, you also need to be sure that they are destroyed together, either by destroying them explicitly or
installing a callback routine on the Text widget. Unless you are creating and destroying ScrolledText objects
dynamically, this issue should not be a concern.
the source code shows a simple file browser that displays the contents of a file using a ScrolledText object. The user
can specify a file by typing a filename in the TextField widget below the Filename: prompt. The user can also select a
file from the FileSelectionDialog that is popped up by the Open entry on the File menu. The specified file is displayed
immediately in the Text widget. XtSetLanguageProc() is only available in X11R5; there is no corresponding
function in X11R4. XmStringCreateLocalized() is only available in Motif 1.2;
XmStringCreateSimple() is the corresponding function in Motif 1.1. XmFONTLIST_DEFAULT_TAG replaces
XmSTRING_DEFAULT_CHARSET in Motif 1.2.
/* file_browser.c −− use a ScrolledText object to view the
* contents of arbitrary files chosen by the user from a
* FileSelectionDialog or from a single−line text widget.
*/
#include <X11/Xos.h>
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/FileSB.h>
#include <Xm/MainW.h>
#include <Xm/RowColumn.h>
#include <Xm/LabelG.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
main(argc, argv)
int argc;
char *argv[];
{
Widget top, main_w, menubar, menu, rc, text_w, file_w;
XtAppContext app;
15 Text Widgets 15.2.3 Scrollable Text
385
XmString file, open, exit;
extern void read_file(), file_cb();
Arg args[10];
int n;
XtSetLanguageProc (NULL, NULL, NULL);
/* initialize toolkit and create toplevel shell */
top = XtVaAppInitialize (&app, "Demos",
NULL, 0, &argc, argv, NULL, NULL);
/* MainWindow for the application −− contains menubar
* and ScrolledText/Prompt/TextField as WorkWindow.
*/
main_w = XtVaCreateManagedWidget ("main_w",
xmMainWindowWidgetClass, top, NULL);
/* Create a simple MenuBar that contains one menu */
file = XmStringCreateLocalized ("File");
menubar = XmVaCreateSimpleMenuBar (main_w, "menubar",
XmVaCASCADEBUTTON, file, 'F',
NULL);
XmStringFree (file);
/* Menu is "File" −− callback is file_cb() */
open = XmStringCreateLocalized ("Open...");
exit = XmStringCreateLocalized ("Exit");
menu = XmVaCreateSimplePulldownMenu (menubar, "file_menu", 0, file_cb,
XmVaPUSHBUTTON, open, 'O', NULL, NULL,
XmVaSEPARATOR,
XmVaPUSHBUTTON, exit, 'x', NULL, NULL,
NULL);
XmStringFree (open);
XmStringFree (exit);
/* Menubar is done −− manage it */
XtManageChild (menubar);
rc = XtVaCreateWidget ("work_area", xmRowColumnWidgetClass, main_w, NULL);
XtVaCreateManagedWidget ("Filename:", xmLabelGadgetClass, rc,
XmNalignment, XmALIGNMENT_BEGINNING,
NULL);
file_w = XtVaCreateManagedWidget ("text_field",
xmTextFieldWidgetClass, rc, NULL);
/* Create ScrolledText −− this is work area for the MainWindow */
n = 0;
XtSetArg(args[n], XmNrows, 12); n++;
XtSetArg(args[n], XmNcolumns, 70); n++;
XtSetArg(args[n], XmNeditable, False); n++;
XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
XtSetArg(args[n], XmNcursorPositionVisible, False); n++;
text_w = XmCreateScrolledText (rc, "text_w", args, n);
XtManageChild (text_w);
/* store text_w as user data in "File" menu for file_cb() callback */
XtVaSetValues (menu, XmNuserData, text_w, NULL);
/* add callback for TextField widget passing "text_w" as client data */
XtAddCallback (file_w, XmNactivateCallback, read_file, text_w);
XtManageChild (rc);
15 Text Widgets 15.2.3 Scrollable Text
386
/* Store the filename text widget to ScrolledText object */
XtVaSetValues (text_w, XmNuserData, file_w, NULL);
XmMainWindowSetAreas (main_w, menubar, NULL, NULL, NULL, rc);
XtRealizeWidget (top);
XtAppMainLoop (app);
}
/* file_cb() −− "File" menu item was selected so popup a
* FileSelectionDialog.
*/
void
file_cb(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
static Widget dialog;
Widget text_w;
extern void read_file();
int item_no = (int) client_data;
if (item_no == 1)
exit (0); /* user chose Exit */
if (!dialog) {
Widget menu = XtParent (widget);
dialog = XmCreateFileSelectionDialog (menu, "file_sb", NULL, 0);
/* Get the text widget handle stored as "user data" in File menu */
XtVaGetValues (menu, XmNuserData, &text_w, NULL);
XtAddCallback (dialog, XmNokCallback, read_file, text_w);
XtAddCallback (dialog, XmNcancelCallback, XtUnmanageChild, NULL);
}
XtManageChild (dialog);
XtPopup (XtParent (dialog), XtGrabNone);
XMapRaised (XtDisplay (dialog), XtWindow (XtParent (dialog)));
}
/* read_file() −− callback routine when the user selects OK in the
* FileSelection Dialog or presses Return in the single−line text widget.
* The specified file must be a regular file and readable.
* If so, it's contents are displayed in the text_w provided as the
* client_data to this function.
*/
void
read_file(widget, client_data, call_data)
Widget widget; /* file selection box or text field widget */
XtPointer client_data;
XtPointer call_data;
{
char *filename, *text;
struct stat statb;
FILE *fp;
Widget file_w;
Widget text_w = (Widget) client_data;
XmFileSelectionBoxCallbackStruct *cbs =
(XmFileSelectionBoxCallbackStruct *) call_data;
15 Text Widgets 15.2.3 Scrollable Text
387
if (XtIsSubclass (widget, xmTextFieldWidgetClass)) {
filename = XmTextFieldGetString (widget);
file_w = widget; /* this *is* the file_w */
}
else {
/* file was selected from FileSelectionDialog */
XmStringGetLtoR (cbs−>value, XmFONTLIST_DEFAULT_TAG, &filename);
/* the user data stored the file_w widget in the text_w */
XtVaGetValues (text_w, XmNuserData, &file_w, NULL);
}
if (!filename || !*filename) { /* nothing typed? */
if (filename)
XtFree (filename);
return;
}
/* make sure the file is a regular text file and open it */
if (stat (filename, &statb) == −1 ||
(statb.st_mode & S_IFMT) != S_IFREG ||
!(fp = fopen(filename, "r"))) {
if ((statb.st_mode & S_IFMT) == S_IFREG)
perror (filename); /* send to stderr why we can't read it */
else
fprintf (stderr, "%s: not a regular file0, filename);
XtFree (filename);
return;
}
/* put the contents of the file in the Text widget by allocating
* enough space for the entire file, reading the file into the
* allocated space, and using XmTextFieldSetString() to show the file.
*/
if (!(text = XtMalloc ((unsigned)(statb.st_size + 1)))) {
fprintf (stderr, "Can't alloc enough space for %s", filename);
XtFree (filename);
fclose (fp);
return;
}
if (!fread (text, sizeof (char), statb.st_size + 1, fp))
fprintf (stderr, "Warning: may not have read entire file!0);
text[statb.st_size] = 0; /* be sure to NULL−terminate */
/* insert file contents in Text widget */
XmTextSetString (text_w, text);
/* make sure text field is up to date */
if (file_w != widget) {
/* only necessary if activated from FileSelectionDialog */
XmTextFieldSetString (file_w, filename);
XmTextFieldSetCursorPosition (file_w, strlen(filename));
}
/* free all allocated space and */
XtFree (text);
XtFree (filename);
fclose (fp);
}
15 Text Widgets 15.2.3 Scrollable Text
388
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.