From: neuhaus@vier.informatik.uni-kl.de (Stephan Neuhaus (HiWi Mattern))
Newsgroups: fj.mail-lists.x-window
Subject: Implementing click-and-drag
Date: 16 Oct 92 01:30:36 GMT
Distribution: fj
Organization: University of Kaiserslautern, Germany

Date: 15 Oct 92 12:27:11 GMT
Message-Id: <neuhaus.719152031@vier>
Newsgroups: comp.windows.x

Hi.

I am in the process of implementing a new X toolkit for
direct-manipulation user interfaces.  One characteristic of such
interfaces is that they allow a user to move objects about on the
screen, put them on top of other objects, and so on.

My implementation so far has associated each window with an internal
object called a widget.  There are display objects that distribute
incoming events to widgets, which in turn distribute them to
interested parties.  Except redrawing themselves on an Expose event,
widgets do not in and of themselves define any input semantics.

Implementing click-and-drag poses a problem, however.  To illustrate,
consider the following situation:

There are two widgets, A and B, which I will identify with their
windows.  Both widgets have selected ButtonPress, ButtonRelease,
EnterNotify, LeaveNotify, and ButtonMotion events.  A and B are not
connected by a parent-child relationship.  They might or might not
share a common parent (except the root window).  A's and B's
respective parents should not need to know what's going on.

Click-and-drag in this example happens as follows: a user moves the
pointer over A, presses a button, drags the pointer over B and
releases the button.

The sequence of events I'd *like* to have sent to my application is as
follows:

	Event(event_window)	Meaning
	-----------------------------------------------------
	EnterWindow(A)		Pointer enters A's window
	ButtonPress(A)		Button is pressed inside A
	ButtonMotion(A)		Pointer moves to A's edge...
	LeaveWindow(A)		...and leaves A's window
*	ButtonMotion(A)		Pointer moves between A and B
	EnterWindow(B)		Pointer enters B
*	ButtonMotion(A)		Pointer moves within B
	ButtonRelease(B)	Button is released

Now, if I select OwnerGrabButtonMask along with A's and B's events,
then (if they share a common parent), everything works as desired,
only that, upon entering B, MotionNotify events will be directed to B
instead of A.  (Note the line with a `*': the MotionNotify events
still go to A, even though A's parent might have selected MotionNotify
events, and, in second to last line, even though the pointer is within
B's window at that time.) If I don't select OwnerGrabButtonMask, then
the only event that B will see is the EnterNotify event *after* the
button is released.

One solution is to redirect the grab to a common ancestor of A and B
(if present), using XChangeActivePointerGrab(), and to resend events
with XSendEvent(), but that's quite tedious, and not easily managed,
since some programming bug could prevent the grab from being released
eventually (server hangs under most window managers).  All I want is
that B gets an EnterNotify event before the button is released, and
that A gets all the MotionNotify events between the ButtonPress and
the ButtonRelease.  The EnterNotify is needed for highlighting, and
the MotionNotify events are needed for moving the widget's outline
along with the pointer.

Another solution would be to unselect MotionNotify events for all
widgets other than A as soon as the ButtonPress is detected.  That's
not a good idea, especially since network delays could prevent the
XSelectInput message to arrive too late.  Also, each ButtonPress would
create a huge amount of traffic, because it is expected that a typical
application has hundreds of widgets.

So, if anybody has an idea how to solve this problem, possibly
maintaining the characteristics of the automatic grab, please send
mail to <neuhaus@informatik.uni-kl.de>.  Please don't follow up unless
you also send me a copy of your article, because I don't read this
newsgroup very often.

If you answer, please also try to address the problem of A and B not
having a common ancestor.

Thanks in advance, and have fun.

-- 
Stephan <neuhaus@informatik.uni-kl.de>
sig closed for inventory.  Please leave your pickaxe outside.
PGP 2.0 public key available on request.  Note the expiration date.