From: buzz@bear.com (Buzz Moschetti)
Newsgroups: comp.windows.x,comp.windows.x.intrinsics,comp.windows.x.motif
Subject: X/Xt/Motif Event Interleaving?
Date: 4 Jan 93 18:57:08 GMT
Reply-To: buzz@bear.com (Buzz Moschetti)
Organization: Bear, Stearns & Co. - FAST

We are trying to create a very simple "drag-n-drop" type UI.  All widgets 
that can be dragged or dropped on will live in the same container widget
(xmFormWidgetClass).  Thus, we thought it would be possible to add event
handlers to all child widgets as follows:

	XtAddEventHandler(widget,
		EnterWindowMask | 
		ButtonPressMask | ButtonReleaseMask | Button1MotionMask,
		      FALSE, my_event_proc, client_data);

Assume we have two button widgets.  Clicking on and dragging either widget
correctly hits my_event_proc() with event->type set accordingly, likewise
for entering the widgets.

What we thought would happen is while, say, widget 1 was dragged over
widget 2, the latter's EnterNotify event would appear in the "stream" of
widget 1's MotionNotify events, e.g.

	Dragging [w1]...
	Dragging [w1]...
	EnterNotify [w2]...
	Dragging [w1]...

We do *not* see this behavior.  The problem is that widget 2 never gets
the EnterNotify event until *after* the button is released, which is
too late:

	Dragging [w1]...
	Dragging [w1]...
	ButtonRelease [w1]...
	EnterNotify [w2]...

The setup *does* work if we drag widget 1 back over widget 1:

	Dragging [w1]...
	Dragging [w1]...
	EnterNotify [w1]...
	Dragging [w1]...

Is what we're trying to do possible?  Is the problem that the clicked-on
widget is grabbing all the events and forcing all others to be queued?
We tried "splitting up" the event callbacks:

	XtAddEventHandler(widget, EnterWindowMask,
		      FALSE, my_event_proc, client_data);

	XtAddEventHandler(widget,
		ButtonPressMask | ButtonReleaseMask | Button1MotionMask,
		      FALSE, OTHER_event_proc, client_data);

but this didn't work either.

Any help or direction is much appreciated.

P.S.  Here's a test program that demonstrates the problem.

/*
cc -g -I/usr/include/Motif1.1 -I/usr/include/X11R4 tester.c -o tester -L /usr/lib/Motif1.1  -L /usr/lib/X11R4 -lXm -lXt -lX11
 */


#include <Xm/Form.h>
#include <Xm/PushB.h>


#define   DRAG_THRESHOLD   5

static void my_event_proc();
static void my_event_proc2();


Widget TopLevel;
XtAppContext	AppContext;


main(argc,argv)
int 	argc;
char 	*argv[];
{
      Widget form;
      Widget w1, w2;

      TopLevel = XtAppInitialize(&AppContext, "xbaetest",
				 NULL, 0, &argc, argv, NULL, NULL, 0);


      form = XtVaCreateManagedWidget("main_form", xmFormWidgetClass, TopLevel,
				   XmNwidth, 50, XmNheight, 50,
				   NULL);


      w1 = XtVaCreateManagedWidget("w1", xmPushButtonWidgetClass, form,
				   XmNleftAttachment,  XmATTACH_FORM,
				 NULL);


      XtAddEventHandler(w1,
			ButtonPressMask | ButtonReleaseMask | Button1MotionMask,
			FALSE,my_event_proc, "w1");

      XtAddEventHandler(w1,
			EnterWindowMask,
			FALSE,my_event_proc2, "w1");

      

      w2 = XtVaCreateManagedWidget("w2", xmPushButtonWidgetClass, form,
				   XmNrightAttachment,  XmATTACH_FORM,
				 NULL);

      XtAddEventHandler(w2,
			ButtonPressMask | ButtonReleaseMask | Button1MotionMask,
			FALSE,my_event_proc, "w2");
      XtAddEventHandler(w2,
			EnterWindowMask,
			FALSE,my_event_proc2, "w2");



      XtRealizeWidget(TopLevel);
      XtAppMainLoop(AppContext);
      return 0;
}



static void
my_event_proc(w, client_data, event)
Widget w;
XtPointer client_data;
XEvent *event;
{
     static int drag_count = 0;


     switch(event->type) {
	  default:
	   (void) printf("my_event_proc: type: %d\n", event->type);
	    break;


	  case ButtonPress:
	    (void) printf("ButtonPress %s\n", client_data);
	    break;


	  case ButtonRelease:
	    drag_count = 0;
	    (void) printf("ButtonRelease %s\n", client_data);
	    break;


	  case MotionNotify:
	    if(++drag_count <= DRAG_THRESHOLD) {
		  break;
	    }

	    /*  Exceeded drag threshold; start changing!  Map the (x,y)
	     *  coords to actual floating point numbers as they would
	     *  appear on the graph:
	     */
	    /*    button_event->x, button_event->y, */
	    (void) printf("Dragging %s\n", client_data);
	    break;  /* 	  case MotionNotify: */
      }
}

static void
my_event_proc2(w, client_data, event)
Widget w;
XtPointer client_data;
XEvent *event;
{
     switch(event->type) {
	  default:
	   (void) printf("my_event_proc2: type: %d\n", event->type);
	    break;

	  case EnterNotify:
	    (void) printf("EnterNotify %s\n", client_data);
	    break;
      }
}