[comp.windows.x] Xtoolkit extensions

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.