Previous | Contents | Index |
Example 3-10 implements an application that interconnects two multiline CSText widgets. Text entered in one widget is also reflected in the other, as if both widgets were simultaneously editing the same file.
Example 3-10 Using Multiple Interconnected Displays |
---|
. . . #include <stdio> #include <Mrm/MrmAppl.h> #include <DXm/DXmCSText.h> static void change_cs(); (1)static Widget toplevel, toplevel_b, text_shell, text_shell_b, text_w, text_w_b; static int ignoreValueChanged = 1; int main(argc, argv) unsigned int argc; char **argv; { XtAppContext app_context; Arg arglist[15]; int ac = 0; XtCallbackRec callback_arg[2]; (2)Display *display, *display_b; XmString cstring; (3)XtToolkitInitialize(); (4)app_context = XtCreateApplicationContext(); (5) #ifdef VMS /* The two getenv lines only apply to UNIX and Windows NT systems. Do not include these lines in applications running on OpenVMS systems. */ #else /* These two lines apply only to applications running on UNIX and Windows NT systems. */ dpy1=getenv("dpy1"); dpy2=getenv("dpy2"); #endif display = XtOpenDisplay(app_context, "dpy1", "two_heads", "demo", NULL, 0, &argc, argv); display_b = XtOpenDisplay(app_context, "dpy2", "two_heads", "demo", NULL, 0, &argc, argv); if (!display) { XtWarning ("Can't open display...exiting"); exit(0); } if (!display_b) { XtWarning ("Can't open display...exiting"); exit(0); } (6)toplevel = XtAppCreateShell ("two_heads", NULL, applicationShellWidgetClass, display, NULL, 0); toplevel_b = XtAppCreateShell ("two_heads", NULL, applicationShellWidgetClass, display_b, NULL, 0); ac = 0; cstring = XmStringCreateLtoR("User Defined", XmSTRING_ISO8859_1); XtSetArg( arglist[ac], XmNdialogTitle, cstring);ac++; XtSetArg( arglist[ac], XmNallowOverlap, TRUE);ac++; XtSetArg( arglist[ac], XmNheight, 300);ac++; XtSetArg( arglist[ac], XmNwidth, 300);ac++; XtSetArg( arglist[ac], XmNresizePolicy, XmRESIZE_GROW);ac++; (7)text_shell = XmCreateBulletinBoard(toplevel, "CSText", arglist, ac ); text_shell_b = XmCreateBulletinBoard(toplevel_b, "CSText", arglist, ac ); XmStringFree(cstring); callback_arg[0].callback = change_cs; callback_arg[0].closure = 0; callback_arg[1].callback = NULL; callback_arg[1].closure = NULL; ac = 0; XtSetArg( arglist[ac], XmNx, 40);ac++; XtSetArg( arglist[ac], XmNy, 50);ac++; XtSetArg( arglist[ac], XmNrows, 20 ); ac++; XtSetArg( arglist[ac], XmNcolumns, 45 ); ac++; XtSetArg( arglist[ac], XmNvalueChangedCallback, callback_arg);ac++; XtSetArg( arglist[ac], XmNscrollVertical, TRUE);ac++; XtSetArg( arglist[ac], XmNeditMode, XmMULTI_LINE_EDIT);ac++; (8)text_w = DXmCreateScrolledCSText(text_shell, "textwidget", arglist, ac ); text_w_b = DXmCreateScrolledCSText(text_shell_b, "textwidget", arglist, ac ); (9)XtManageChild(text_w); XtManageChild(text_w_b); (10)XtManageChild(text_shell); XtManageChild(text_shell_b); (11)XtRealizeWidget(toplevel); XtRealizeWidget(toplevel_b); (12)ignoreValueChanged = 0; (13)XtAppMainLoop(app_context); } /* The user entered something*/ (14)static void change_cs(w, tag, reason) Widget w; int *tag; unsigned long *reason; { XmString new_text; DXmCSTextPosition last_pos; Widget ww; (15)if (ignoreValueChanged) return; (16)ignoreValueChanged = 1; (17)new_text = DXmCSTextGetString(w); (18)last_pos = DXmCSTextGetLastPosition(text_w); (19)if (w == text_w_b) ww = text_w; else ww = text_w_b; DXmCSTextSetString(ww, new_text); DXmCSTextSetInsertionPosition(ww, last_pos); DXmCSTextSetInsertionPosition(text_w_b, last_pos); XtFree(new_text); ignoreValueChanged = 0; } . . . |
The Toolkit includes a routine, DXmCreateCursor, that you can call to create a cursor for your application. On UNIX and Windows NT systems, you specify one of the cursor constants defined in the decwcursor.h include file to identify the cursor. Your application must include the DECspecific.h and decwcursor.h include files to use the DXmCreateCursor routine. On OpenVMS systems, you specify one of the cursor constants defined in the DECw$Cursor.h include file to identify the cursor. Your application must include the DECspecific.h and DECw$Cursor.h include files to use the DXmCreateCursor routine.
Example 3-11 shows how to use the DXmCreateCursor routine to create a wait cursor, define this cursor to be used in a window of an application, and then restore the parent's (original) cursor. You need only create the cursor once; you can then define it and undefine it as necessary.
Example 3-11 The DXmCreateCursor Routine |
---|
. . . #include <DXm/DECspecific.h> #ifdef VMS /* On OpenVMS systems, use the following include file to identify the cursor. */ #include <sys$library/DECw$Cursor.h> #else /* On UNIX and Windows NT systems, use the following include file to identify the cursor. */ #include <X11/decwcursor.h> #endif . . . Widget toplevel_widget, my_widget; Cursor cursor; cursor = DXmCreateCursor(toplevel_widget, decw$c_wait_cursor); XDefineCursor(XtDisplay(toplevel_widget), XtWindow(my_widget), cursor); . . . /* Perform some function */ XUndefineCursor(XtDisplay(toplevel_widget), XtWindow(my_widget)); |
As described in the X Window System Toolkit, you can use the XtAppAddInput routine to register an alternative source of input with the Toolkit. When input from this alternate source becomes available, the intrinsics call the supplied callback routine to notify it that input is available.
The XtAppAddInput routine has several operating-system-dependent arguments. The X Window System Toolkit describes all the arguments used for calling the XtAppAddInput routine on UNIX and Windows NT systems.
The remainder of this section applies only to OpenVMS systems. |
In the OpenVMS environment, the arguments used in calling the XtAppAddInput routine are as follows:
Your application needs a way to set the event flag to indicate that input is available. The most common method of setting the event flag is by using an AST completion routine. For example, in Example 3-13, the START_READ routine starts a $QIO read and specifies CompletionAst as the AST completion routine. CompletionAst sets the event flag.
Example 3-12 and Example 3-13 implement a program that traps broadcast messages and displays them in an XmScrolledList widget. The program uses mailboxes to handle communications between the processes.
The AllocateAddInputRec routine allocates and initializes a data structure containing allocated space, an application (widget) callback, and tag. This data structure is passed to the CompletionAst routine at AST level and then to your XtInputCallbackProc routine. You can use this data structure as needed by your application.
By using the data structure allocated by AllocateAddInputRec and by replacing the ProcessMessageRec and AddInputCallback routines based on your application's needs, you can use this code to do a $QIO read into a buffer, set an event flag to notify the Toolkit that input is available, and start another $QIO read.
You can use the following commands to compile and link this program:
$ UIL/MOTIF BTRAP.UIL $ CC/NOOPTIMIZE BTRAP $ LINK BTRAP,SYS$INPUT/OPT SYS$SHARE:DECW$DXMLIBSHR/SHARE,SYS$SHARE:DECW$XLIBSHR/SHARE |
One way to test this program is to run it from a DECterm window, give the window input focus, and then press Ctrl/T to generate broadcast messages to be trapped. |
Example 3-12 Using the XtAppAddInput Routine---UIL Module |
---|
module BTrap names = case_sensitive procedure LabelCreateCallback (); QuitCallback (); object bTrapMain : XmMainWindow { arguments { XmNwidth = 650; XmNheight = 150; }; controls { XmForm btrap_form; }; }; object btrap_form : XmForm{ controls { XmScrolledList bTrapLabel; XmPushButton bTrapQuitButton; }; }; (1)object bTrapLabel : XmScrolledList { arguments { XmNvisibleItemCount = 5; XmNunitType = XmPIXELS; XmNlistSizePolicy = XmVARIABLE; XmNscrollBarDisplayPolicy = XmSTATIC; XmNleftAttachment = XmATTACH_FORM; XmNleftOffset = 0; XmNrightAttachment = XmATTACH_FORM; XmNrightOffset = 0; XmNtopAttachment = XmATTACH_FORM; XmNtopOffset = 3; XmNbottomAttachment = XmATTACH_NONE; }; callbacks { MrmNcreateCallback = procedure LabelCreateCallback(); }; }; object bTrapQuitButton : XmPushButton { arguments { XmNlabelString = compound_string("Quit"); XmNleftAttachment = XmATTACH_NONE; XmNtopAttachment = XmATTACH_NONE; XmNbottomAttachment = XmATTACH_FORM; XmNbottomOffset = 5; XmNrightAttachment = XmATTACH_FORM; XmNrightOffset = 10; }; callbacks { XmNactivateCallback = procedure QuitCallback(); }; }; end module; . . . |
Example 3-13 Using the XtAppAddInput Routine---C Module |
---|
(1)#include <Mrm/MrmAppl.h> #include <descrip.h> #include <jpidef.h> #include <ssdef.h> #include <iodef.h> #include <libdef.h> #include <dvidef.h> #include <psldef.h> #include <prcdef.h> #include <ttdef.h> #include <tt2def.h> #include <msgdef.h> /* * Global Data * */ static MrmHierarchy s_MrmHierarchy; /* MRM database hierarchy ID */ static MrmType *dummy_class; /* and class variable. */ static char *db_filename_vec[] = /* Mrm hierarchy file list. */ {"btrap.uid" /* There is only one UID file for */ }; /* this application. */ static int db_filename_num = (sizeof db_filename_vec / sizeof db_filename_vec [0]); (2)#define MISC_EFN 2 /* use for system service calls */ (3)typedef struct { unsigned short type; unsigned short unit; unsigned char controllerNameLen; char controllerNameA[15]; unsigned short messageLen; char messageA[256]; } VmsMailboxMessage; /* Define a control block to contain information about the mailbox message. * This control block will be passed to the I/O completion routine. */ (4)typedef struct _MessageRec { unsigned short iosbA[4]; VmsMailboxMessage mailboxMessage; } MessageRec; static MessageRec messageRec; static short devChan, mbChan; /* Definitions for AST routines */ #define LIB$_QUEWASEMP 1409772 (5)#define ADD_INPUT_EFN 3 typedef struct { unsigned long queueEntryA[2]; /* must be first in struct */ char *mallocP; /* address actually malloc-ed */ void (*routineP)(); /* thread resumption routine */ Opaque closure; /* thread closure */ } AddInputRec; static _align(quadword) unsigned long addInputQueueHeaderA[2]; static int initialized; /* Application Context */ (6)XtAppContext app_context; /* Application Widgets */ static Widget appW, mainW, labelW; /* * Forward declarations */ static unsigned long StartReadQIO(); static void LabelCreateCallback(); static void QuitCallback(); static void AddInputCallback(); extern void CompletionAst(); extern Opaque AllocateAddInputRec(); /* The names and addresses of things that Mrm has to bind. The names do * not have to be in alphabetical order. */ static MrmRegisterArg reglist[] = { {"LabelCreateCallback", (caddr_t) LabelCreateCallback}, {"QuitCallback", (caddr_t) QuitCallback} }; static int reglist_num = (sizeof reglist / sizeof reglist [0]); (7)static void ProcessMessageRec(messageRecP) MessageRec *messageRecP; { VmsMailboxMessage *mailboxMessageP = &messageRecP->mailboxMessage; int bell = 0; char c, bufA[256]; char *fromBufP = mailboxMessageP->messageA; int fromBufLen = mailboxMessageP->messageLen; char *toBufP; Arg al[1]; XmString labelP; /* If this is a non-null broadcast message, pass it to XmScrolledList. */ if ((mailboxMessageP->type == MSG$_TRMBRDCST) && fromBufLen) { if (fromBufP[fromBufLen-1] != '\n') fromBufP[fromBufLen++] = '\n'; while (fromBufLen) { toBufP = bufA; bell = 0; while (1) { c = *(fromBufP++); fromBufLen--; if (c == 7) bell++; else if (c == '\t') *(toBufP++) = ' '; else if (c == '\n') {*toBufP = 0; break;} else *(toBufP++) = c; } if (bufA[0]) { labelP = XmStringLtoRCreate(bufA,""); XmListAddItem(labelW, labelP, 0); XtFree (labelP); } while (bell--) XBell (XtDisplay (labelW), 0); } } /* Start another asynchronous read. */ StartReadQIO (messageRecP); } (8)static unsigned long StartReadQIO(messageRecP) MessageRec *messageRecP; { unsigned long status; status = sys$qio ( MISC_EFN, /* always use this EFN */ mbChan, /* mailbox channel */ IO$_READVBLK, /* function code */ (9)messageRecP->iosbA, /* IOSB (in message control block) */ (10)CompletionAst, /* always use this ASTADR */ (11)AllocateAddInputRec(ProcessMessageRec, messageRecP), /* callback and its argument */ &messageRecP->mailboxMessage, /* buffer address */ sizeof(VmsMailboxMessage), /* buffer length */ 0, 0, 0, 0); /* unused QIO parameters */ return (status); } typedef struct { short bufferLength; short itemCode; char *bufP; unsigned short *bufLenP; } GetjpiItemList; static unsigned long masterPid; static GetjpiItemList masterPidItemListA[2] = { {4, JPI$_MASTER_PID, &masterPid, 0}, {0, 0, 0, 0}}; static char devNameBufA[64]; static unsigned short devNameLen; static GetjpiItemList devNameItemListA[2] = { {sizeof(devNameBufA)-1, JPI$_TERMINAL, devNameBufA, &devNameLen}, {0, 0, 0, 0}}; #define Check(s) if ((status = s) != SS$_NORMAL) return (status) (12)static unsigned long StartTrappingMessages() { unsigned long status; unsigned long modeBufA[3]; unsigned short dviBufA[2]; unsigned short iosbA[4]; /* Get the terminal name owned by the master process of our job tree. */ Check (sys$getjpiw (MISC_EFN, 0, 0, masterPidItemListA, iosbA, 0, 0)); Check (iosbA[0]); Check (sys$getjpiw (MISC_EFN, &masterPid, 0, devNameItemListA, iosbA, 0, 0)); Check (iosbA[0]); /* Assign a channel (with mailbox) to that terminal device, and enable * the mailbox so that messages will be sent to it. */ { struct dsc$descriptor_s devNameDsc = {devNameLen, DSC$K_DTYPE_T, DSC$K_CLASS_S, devNameBufA}; int maximumMessageSize = sizeof(VmsMailboxMessage); int bufferQuota = sizeof(VmsMailboxMessage)*32; Check (lib$asn_wth_mbx (&devNameDsc, &maximumMessageSize, &bufferQuota, &devChan, &mbChan)); } { char dummyBufA[4]; Check (sys$qiow (MISC_EFN, devChan, IO$_WRITEVBLK | IO$M_ENABLMBX, iosbA, 0, 0, dummyBufA, 0, 0, 0, 0, 0)); Check (iosbA[0]); } /* Set the terminal NOBROADCAST since messages will be displayed in * our window. */ Check (sys$qiow (MISC_EFN, devChan, IO$_SENSEMODE, iosbA, 0, 0, modeBufA, sizeof(modeBufA), 0, 0, 0, 0)); Check (iosbA[0]); { (13)modeBufA[1] |= TT$M_NOBRDCST; modeBufA[2] |= TT2$M_BRDCSTMBX; Check (sys$qiow (MISC_EFN, devChan, IO$_SETMODE, iosbA, 0, 0, modeBufA, sizeof(modeBufA), 0, 0, 0, 0)); Check (iosbA[0]); } /* Start the first asynchronous mailbox read. */ (14)Check (StartReadQIO (&messageRec)); printf("FYI - messages are being trapped\n"); return (SS$_NORMAL); } static int main(argc, argv) int argc; char **argv; { unsigned long status; MrmInitialize(); /* Initialize MRM before initializing /* the X Toolkit. */ /* Initialize the application. */ appW = XtAppInitialize(&app_context, /* App. context is returned */ "btrap$defaults", /* Root class name. */ NULL, /* No option list. */ 0, /* Number of options. */ &argc, /* Address of argc */ argv, /* argv */ NULL, /* No fallback resources */ NULL, /* No override resources */ 0); /* No override resources */ /* Open the UID files (the output of the UIL compiler) in the hierarchy*/ if (MrmOpenHierarchy(db_filename_num, /* Number of files. */ db_filename_vec, /* Array of file names. */ NULL, /* Default OS extension. */ &s_MrmHierarchy) /* Pointer to returned MRM ID */ !=MrmSUCCESS) printf("can't open hierarchy"); /* Register the items MRM needs to bind for us. */ MrmRegisterNames(reglist, reglist_num); /* Start to trap messages and do the $QIO read of the mailbox */ (15)if ((status = StartTrappingMessages ()) != SS$_NORMAL) { printf ("BTrap - Unable to trap broadcast messages"); return (status); }; /* Go get the main part of the application. */ if (MrmFetchWidget(s_MrmHierarchy, "bTrapMain", appW, &mainW, &dummy_class) != MrmSUCCESS) printf("can't fetch main window"); XtManageChild (mainW); /* manage the main window */ XtRealizeWidget (appW); /* realize the widget tree */ XtAppMainLoop(app_context); /* and go to work */ } /* The routine you want to be invoked by XtAppAddInput. * AddInputCallback does not use the tag argument of XtAppAddInput. */ (16)static void AddInputCallback() { unsigned long status; AddInputRec *addInputRecP; sys$clref (ADD_INPUT_EFN); /* clear flag so we can be called again */ while (lib$remqhi (addInputQueueHeaderA, &addInputRecP, 0) != LIB$_QUEWASEMP) { (*addInputRecP->routineP) (addInputRecP->closure); XtFree (addInputRecP->mallocP); } } /* Use CompletionAst as the ASTADR parameter on asynchronous system service * calls. This routine must not be called directly from the application. * It adds an application callback to the pending callback list. */ void CompletionAst(addInputRecP) AddInputRec *addInputRecP; { lib$insqti (addInputRecP, addInputQueueHeaderA, 0); sys$setef (ADD_INPUT_EFN); } /* Use AllocateAddInputRec as the ASTPRM parameter on asynchronous system * service calls. Arguments to this routine are the application callback * routine to be called when the system service completes and the parameter * to be passed to that callback. AllocateAddInputRec allocates and * initializes an application callback record to be passed to the * CompletionAst routine at AST level when the system service completes. */ Opaque AllocateAddInputRec(routineP, closure) void (*routineP)(); Opaque closure; { char *mallocP; AddInputRec *addInputRecP; if (!initialized) XtAppAddInput (app_context, ADD_INPUT_EFN, 0, AddInputCallback, 0); mallocP = XtMalloc (sizeof (AddInputRec) + 7); addInputRecP = (AddInputRec *)(((int)(mallocP) + 7) & (-8)); addInputRecP->mallocP = mallocP; addInputRecP->routineP = routineP; addInputRecP->closure = closure; return ((Opaque)addInputRecP); } /* Callback Routines */ static void LabelCreateCallback(w, tag, reason) Widget w; int *tag; XmAnyCallbackStruct *reason; { labelW = w; } static void QuitCallback(w, tag, reason) Widget w; int *tag; XmAnyCallbackStruct *reason; { exit (1); } |
Previous | Next | Contents | Index |