rtc@masscomp.UUCP (Richard Carling) (11/20/87)
Below are some proposed minor enhancements to the XToolkit. I have included the file changes to incorporate them (manually). Below are some minor enhancements that allow the XToolkit to be placed in one of an applications windows. The change is to add the notion of parent_window to the top level widget. The routine XtDispatchEvent() is also enhanced so that applications can determine whether an Event was handled by the Xtoolkit or not (it returns true/false). (I renamed it to XtSpecificDispatchEvent() here but feel it should replace XtDispatchEvent). (Note:For better performance in a real application with many widgets, checking the event first for the application specific windows might be more efficient.) So the basic features: 1) The XToolkit topLevel to be placed on a subwindow of the client application. 2) A version of DispatchEvent() which returns True if a widget to handle the event was found. They do require the topLevel widget to have one field added to its class structure, the (Window) field parent_window. The XtSpecificDispatchEvent() can also be used if applications create non toolkit windows inside the Xtoolkit hierarchy and want to find out if the Event was handled by the toolkit widgets or not. This would be useful, but probably requires a new Widget Class which supports a widget in which to allocate the application window in. I haven't implemented a "widget" which does this. Please excuse the non-use of any unix standard tools to present the diff's for the enhancements. --------------------- The replacement XtInitialize call is Widget XtInitializeInWindow( dpy, parentWindow, name, classname, urlist, urlistCount, argc, argv ) where parentWindow is the window the application wants the XToolkit to be attached onto and dpy is an already open/existing display. Everything is the same as in XtInitialize(). Here is an application fragment which uses this call extern void callback1(); /* external callback routines */ extern void callback2(); extern void callback3(); extern void callback4(); extern void callback5(); extern void callback_exit(); create_user_interface( display, parent_window, x, y, width, height, argc, argv) Display *display; Window parent_window; int x, y, width, height; unsigned int argc; char **argv; { unsigned int mask; Widget toplevel, menu, command; static Arg arg[] = { {XtNfunction,(XtArgVal)(caddr_t)callback_exit} }; static Arg arg1[] = { {XtNfunction,(XtArgVal)(caddr_t)callback1} }; static Arg arg2[] = { {XtNfunction,(XtArgVal)(caddr_t)callback2} }; static Arg arg3[] = { {XtNfunction,(XtArgVal)(caddr_t)callback3} }; static Arg arg4[] = { {XtNfunction,(XtArgVal)(caddr_t)callback4} }; static Arg arg5[] = { {XtNfunction,(XtArgVal)(caddr_t)callback5} }; toplevel = XtInitializeInWindow( display, parent_window, NULL, "Paint", options, XtNumber( options ), &argc, argv ); /* this is a blatently illegal but quite useful routine */ /* topLevel widget handles it ok, it over rides geometry requests */ /* specified by argc & argv above */ XtPositionWidget( toplevel, x, y, width, height ); mask = _XtBuildEventMask( toplevel ); /* and notice this, using a private routine! */ menu = XtCreateWidget( "menu", buttonBoxWidgetClass, toplevel, NULL, (unsigned)0); XtManageChild(menu); command = XtCreateWidget( "Exit",commandWidgetClass,menu,arg,(unsigned)1); XtManageChild(command); command = XtCreateWidget( "Line",commandWidgetClass,menu,arg1,(unsigned)1); XtManageChild(command); command = XtCreateWidget( "Rectangle",commandWidgetClass,menu,arg2,(unsigned)1); XtManageChild(command); command = XtCreateWidget( "FilledBox",commandWidgetClass,menu,arg3,(unsigned)1); XtManageChild(command); command = XtCreateWidget( "Color", commandWidgetClass, menu, arg4, (unsigned)1); XtManageChild(command); command = XtCreateWidget( "Erase",commandWidgetClass,menu,arg5,(unsigned)1); XtManageChild(command); XtRealizeWidget(toplevel); /* I pass the event mask back so that the XSelectInput's for the * parent heirarchy windows can MAP in these events as well. */ return mask; } ------------ XToolkit file changes ------------- File: Event.c Change: add one routine (useful in its own right) ------------- /* * XtSpecificDispatchEvent (event) * * returns zero/false if no widget exists which owns that window * this allows programs which have private windows as well * as XToolkit windows to handle them correctly. * returns nonzero if the event was dispatched to a widget. */ XtSpecificDispatchEvent (event) XEvent *event; { Widget widget; EventMask mask; GrabType grabType; Boolean sensitivity; #define IsSensitive ((!sensitivity) || (widget->core.sensitive && widget->core.ancestor_sensitive)) widget =ConvertWindowToWidget (event->xany.window); if (widget == NULL) return 0; ConvertTypeToMask(event->xany.type, &mask, &grabType, &sensitivity); if ((grabType == pass || grabList == NULL) && IsSensitive) DispatchEvent(event,widget, mask); else if (onGrabList(widget)) { if (IsSensitive) DispatchEvent(event,widget,mask); else DispatchEvent(event, grabList->widget, mask); } else if (grabType == remap) DispatchEvent( event, widget, mask ); /* rtc modified 10-20-87 */ /* DispatchEvent( event, grabList->widget, mask ); it was This!, me no like! */ return 1; } ---------- File Initialize.c changes: 1) the Class structure TopLevelPart has one field added 2) a different XtInitialize is used (XtInitializeInWindow()) 3) topLevel's Realize() is slightly enhanced (ifdef'd here) 4) one line needs to be added to XtInitialize() as well. the changes to existing routines are ifdef'd ENHANCED and are ---------- typedef struct { int argc; char **argv; char *classname; char *icon_name; char *title; Pixmap icon_pixmap; Window icon_window; Boolean iconic; Boolean input; Boolean resizeable; char *geostr; int initial; XSizeHints hints; #ifdef ENHANCED Window parent_window; /* this field is added for enhancement */ #endif ENHANCED } TopLevelPart; static void Realize(wid, mask, attr) Widget wid; Mask mask; XSetWindowAttributes *attr; { TopLevelWidget w = (TopLevelWidget) wid; Window win; Display *dpy = XtDisplay(w); #ifdef ENHANCED Window root; #endif ENHANCED /* char hostname[1024]; */ XWMHints wmhints; mask &= ~(CWBackPixel); mask |= CWBackPixmap; attr->background_pixmap = None; /* I must have a background pixmap of none, and no background pixel. This should give me a transparent background so that if there is latency from when I get resized and when my child is resized it won't be as obvious. */ #ifdef ENHANCED root = w->top.parent_window; if (!root) root = w->core.screen->root; /* should never happen */ win = w->core.window = XCreateWindow( dpy, root, w->core.x, w->core.y, w->core.width, w->core.height, w->core.border_width, w->core.depth, CopyFromParent, CopyFromParent, mask, attr); #else win = w->core.window = XCreateWindow( dpy, w->core.screen->root, w->core.x, w->core.y, w->core.width, w->core.height, w->core.border_width, w->core.depth, CopyFromParent, CopyFromParent, mask, attr); #endif XStoreName(dpy, win, w->top.title); XSetIconName(dpy, win, w->top.icon_name); XSetCommand(dpy, win, w->top.argv, w->top.argc); #ifdef UNIX gethostname(hostname, sizeof(hostname)); #endif /* now hide everything needed to set the properties until realize is called */ wmhints.flags = 0; wmhints.flags |= InputHint ; if(w->top.input) wmhints.input = TRUE; else wmhints.input = FALSE; /* Should I tell the window manager to bring me up iconfied */ wmhints.initial_state = w->top.initial; if(w->top.iconic) wmhints.initial_state = IconicState; if(w->top.icon_pixmap != NULL) { wmhints.flags |= IconPixmapHint; wmhints.icon_pixmap = w->top.icon_pixmap; } if(w->top.icon_window != NULL) { wmhints.flags |= IconWindowHint; wmhints.icon_window = w->top.icon_window; } XSetWMHints(dpy, win, &wmhints); /* ||| XSetHostName(dpy, win, hostname); XSetClass(dpy, win, w->top.classname);/* And w->core.name XXX*/ w->top.hints.x = w->core.x; w->top.hints.y = w->core.y; w->top.hints.width = w->core.width; w->top.hints.height = w->core.height; XSetNormalHints(dpy, win, &w->top.hints); } #ifdef ENHANCED /* * This routine creates the desired widget and does the "Right Thing" for * the toolkit and for window managers. * * - * extended by rtc@MASSCOMP to handle already opened display * and application defined root (or parent) window */ Widget XtInitializeInWindow( dpy, rootWindow, name, classname, urlist, urlistCount, argc, argv ) Display *dpy; Window rootWindow; char *name; char *classname; XrmOptionDescRec *urlist; Cardinal urlistCount; Cardinal *argc; char *argv[]; { char displayName[256]; /* char *displayName_ptr = displayName; */ Arg args[8]; Cardinal num_args = 0; int i; /* int val; int flags = 0; */ char filename[MAXPATHLEN]; char **saved_argv; int saved_argc = *argc; char *ptr, *rindex(); TopLevelWidget w; Widget root; int squish = -1; Boolean dosync = FALSE; if( name == NULL) { ptr = rindex(argv[0], '/'); if(ptr) name = ++ ptr; else name = argv[0]; } /* save away argv and argc so I can set the properties latter */ saved_argv = (char **) XtCalloc( (unsigned) ((*argc) + 1) , (unsigned)sizeof(*saved_argv)); for (i = 0 ; i < *argc ; i++) saved_argv[i] = argv[i]; saved_argv[i] = NULL; toplevelDisplay = dpy; if (dosync) XSynchronize(dpy, TRUE); XtSetArg(args[num_args], "display", dpy); num_args++; XtSetArg(args[num_args], "screen", dpy->default_screen); num_args++; /* initialize the toolkit */ DO_Initialize(); #define UNIX #ifdef UNIX #define XAPPLOADDIR "/usr/lib/Xapps/" #endif (void) strcpy(filename, XAPPLOADDIR); (void) strcat(filename, classname); /*set up resource database */ XGetUsersDataBase(dpy, filename); /* This routine parses the command line arguments and removes them from argv. */ XrmParseCommand( opTable, XtNumber(opTable), name, argc, argv); if(urlistCount >0) { /* the application has some more defaults */ XrmParseCommand( urlist, urlistCount, name, argc, argv); } /* Resources are initialize and loaded */ /* I now must handle geometry specs a compond resource */ /* Create the top level widget. Unlike most classes the toplevel widget class has no classname The name is supplied in the call to XtInitialize. */ (void) strcpy( ((TopLevelClassRec *)(topLevelWidgetClass))->core_class.class_name = (String)XtMalloc((unsigned)strlen(classname)+1), classname); root = TopLevelCreate(name, topLevelWidgetClass, &(dpy->screens[dpy->default_screen]), args, num_args ); w = (TopLevelWidget) root; w->top.parent_window = rootWindow; /* THIS LINE is NEW */ w->top.argc = saved_argc; w->top.argv = saved_argv; (void) strcpy(w->top.classname = (char *)XtMalloc((unsigned)strlen(classname)+1) ,classname); init_atoms(dpy); return(root); } #endif ENHANCED One line is added to the XtInitialize() routine Widget XtInitialize(name, classname, urlist, urlistCount, argc, argv) . . . (same code until the end) . w = (TopLevelWidget) root; #ifdef ENHANCED w->top.parent_window = w->core.screen->root; #endif ENHANCED w->top.argc = saved_argc; w->top.argv = saved_argv; (void) strcpy(w->top.classname = (char *)XtMalloc((unsigned)strlen(classname)+1) ,classname); init_atoms(dpy); return(root); } ------------------------ /* this can be a quit useful routine, but its use is probably frowned upon more than bypassing QuickDraw on a Macintosh. */ XtPositionWidget( widget, x, y, wd, ht ) Widget widget; int x, y, wd, ht; { if ((wd > 0) && (ht > 0)) { widget->core.x = x; widget->core.y = y; widget->core.width = wd; widget->core.height = ht; } } ----------------------- I can post a small paint program that uses this capability if these enhancements appear to be useful. Richard Carling. As to questions about topLevel's inability to handle composite widgets, I just add in an extra level and use an additional layer of ButtonBox or (maybe someday) VPane.