[comp.windows.x] Xt Intrinsics, extensions, and event handlers

furr@mdavcr.UUCP (Steven Furr) (05/30/91)

I would like to know if there is any way of providing Xt Event handlers
to handle events that come from X extensions.  The event type of these
events is not known until the extension is initialized, and the event
cannot be selected with XSelectInput.

I would like to access the multibuffering extension in order to use the
following technique for animation:


   void Canvas::realized( void )
   {
      .
      .
      .
      XtAddEventHandler( widget(), 0, TRUE,
			 Canvas::event_handler, (XtPointer)this )

      // Select UpdateNotify events for each buffer

      attributes.mask = MultibufferUpdateNotifyMask;
      for (int i = 0; i < num_bufs; i++ )
	 XmbufChangeBufferAttributes( dpy, buffer[i],
				      MultibufferEventMask, &attributes );
   }

   void Canvas::event_handler( Widget w, XtPointer client_data, XEvent * ev )
   {
      if ( event->type == MultibufferExt::event_base + UpdateNotify )
      {
	 Canvas * canvas = (Canvas *)client_data;
	 int delay = 100;    // milliseconds
	 canvas->cycle_buffer( delay );
      }
   }


The problem is that Xt doesn't seem capable of dispatching any nonmaskable
events to the event handler other than GraphicsExpose, NoExpose,
MappingNotify, SelectionClear, SelectionRequest, SelectionNotify, and
ClientMessage (as per p. 225 of O'Reilly vol. 4).

Shouldn't event types outside the range of the X standard protocol be
considered nonmaskable events by Xt? (i.e. those that get assigned to
extension events)

Since this appears not to be the case is there any possibility that this
will change with X11.R5?

Looking at the sample implementation, it seems that all that would be
required would be to check if eventType is greater than LASTEvent in
ConvertTypeToMask (in fact without this the current behaviour is not
guaranteed to be correct) and set up appropriate defaults (i.e. mask=0,
grabType=pass).  The relevant sections of code follow:



static Boolean DecideToDispatch(event)
    XEvent  *event;
{
    register    Widget widget;
    EventMask   mask;
    GrabType    grabType;
    Widget	dspWidget;
    Time	time = 0;
    XtPerDisplay pd;
    XtPerDisplayInput pdi;
    XtGrabList  grabList;

    widget = XtWindowToWidget (event->xany.display, event->xany.window);
    pd = _XtGetPerDisplay(event->xany.display);
    pdi = _XtGetPerDisplayInput(event->xany.display);
    grabList = *_XtGetGrabList(pdi);
    
    
    /* Lint complains about &grabType not matching the declaration.
       Don't bother trying to fix it, it won't work */
    ConvertTypeToMask(event->xany.type, &mask, &grabType);

    switch (event->xany.type) {

      case KeyPress:
      case KeyRelease:		time = event->xkey.time; break;

      case ButtonPress:
      case ButtonRelease:	time = event->xbutton.time; break;

      case MotionNotify:	time = event->xmotion.time; break;

      case EnterNotify:
      case LeaveNotify:		time = event->xcrossing.time; break;

      case PropertyNotify:	time = event->xproperty.time; break;

      case SelectionClear:	time = event->xselectionclear.time; break;
    }

    if (time) pd->last_timestamp = time;

    if (widget == NULL) {
	if (grabType != remap) return False;
	/* event occurred in a non-widget window, but we've promised also
	   to dispatch it to the nearest accessible spring_loaded widget */
	else if ((widget = LookupSpringLoaded(grabList)) != NULL)
	    return DispatchEvent(event, widget, mask, pd);
	return False;
    }

    switch(grabType) {
	case pass:
	    return DispatchEvent(event, widget, mask, pd);

	case ignore:
	    if ((grabList == NULL || _XtOnGrabList(widget,grabList))
		&& XtIsSensitive(widget)) {
		return DispatchEvent(event, widget, mask, pd);
	    }
	    return False;

	case remap:
	    
	    {
		Boolean was_dispatched = False;
		extern Widget _XtFindRemapWidget();
		extern void _XtUngrabBadGrabs();

		dspWidget = _XtFindRemapWidget(event, widget, mask, pdi);
		
		if ((grabList == NULL || 
		     _XtOnGrabList(dspWidget, grabList)) &&
		    XtIsSensitive(dspWidget)) {
		    was_dispatched = DispatchEvent(event, dspWidget,
						   mask, pd);
		}
		else _XtUngrabBadGrabs(event, widget, mask, pdi);
		
		/* Also dispatch to nearest accessible spring_loaded. */
		/* Fetch this afterward to reflect modal list changes */
		grabList = *_XtGetGrabList(pdi);
		widget = LookupSpringLoaded(grabList);
		if (widget != NULL && widget != dspWidget) {
		    was_dispatched |= DispatchEvent(event, widget,
						    mask, pd);
		}
		
		return was_dispatched;
	    }
    }
    /* should never reach here */
    return False;
}

typedef enum _GrabType {pass, ignore, remap} GrabType;

static void ConvertTypeToMask (eventType, mask, grabType)
    int		eventType;
    EventMask   *mask;
    GrabType    *grabType;
{

static Const struct {
    EventMask   mask;
    GrabType    grabType;
} masks[] = {
    {0,				pass},      /* shouldn't see 0  */
    {0,				pass},      /* shouldn't see 1  */
    {KeyPressMask,		remap},     /* KeyPress		*/
    {KeyReleaseMask,		remap},     /* KeyRelease       */
    {ButtonPressMask,		remap},     /* ButtonPress      */
    {ButtonReleaseMask,		remap},     /* ButtonRelease    */
    {PointerMotionMask
     | Button1MotionMask
     | Button2MotionMask
     | Button3MotionMask
     | Button4MotionMask
     | Button5MotionMask
     | ButtonMotionMask,	ignore},    /* MotionNotify	*/
    {EnterWindowMask,		ignore},    /* EnterNotify	*/
    {LeaveWindowMask,		pass},      /* LeaveNotify	*/
    {FocusChangeMask,		pass},      /* FocusIn		*/
    {FocusChangeMask,		pass},      /* FocusOut		*/
    {KeymapStateMask,		pass},      /* KeymapNotify	*/
    {ExposureMask,		pass},      /* Expose		*/
    {0,				pass},      /* GraphicsExpose   */
    {0,				pass},      /* NoExpose		*/
    {VisibilityChangeMask,      pass},      /* VisibilityNotify */
    {SubstructureNotifyMask,    pass},      /* CreateNotify	*/
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* DestroyNotify	*/
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* UnmapNotify	*/
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* MapNotify	*/
    {SubstructureRedirectMask,  pass},      /* MapRequest	*/
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* ReparentNotify   */
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* ConfigureNotify  */
    {SubstructureRedirectMask,  pass},      /* ConfigureRequest */
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* GravityNotify	*/
    {ResizeRedirectMask,	pass},      /* ResizeRequest	*/
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* CirculateNotify	*/
    {SubstructureRedirectMask,  pass},      /* CirculateRequest */
    {PropertyChangeMask,	pass},      /* PropertyNotify   */
    {0,				pass},      /* SelectionClear   */
    {0,				pass},      /* SelectionRequest */
    {0,				pass},      /* SelectionNotify  */
    {ColormapChangeMask,	pass},      /* ColormapNotify   */
    {0,				pass},      /* ClientMessage	*/
    {0,				pass},      /* MappingNotify	*/
  };

    eventType &= 0x7f;	/* Events sent with XSendEvent have high bit set. */
    (*mask)      = masks[eventType].mask;
    (*grabType)  = masks[eventType].grabType;
}

--
Steve Furr ( furr@mda.ca )

Lesser artists borrow,
great artists steal.

	- blatantly stolen from
	  Igor Stravinsky

rthomson@mesa.dsd.es.com (Rich Thomson) (05/30/91)

In article <1224@mdavcr.UUCP>
	furr@mdavcr.UUCP (Steven Furr) writes:
>I would like to know if there is any way of providing Xt Event handlers
>to handle events that come from X extensions.  The event type of these
>events is not known until the extension is initialized, and the event
>cannot be selected with XSelectInput.
>
 [...]
>
>The problem is that Xt doesn't seem capable of dispatching any nonmaskable
>events to the event handler other than GraphicsExpose, NoExpose,
>MappingNotify, SelectionClear, SelectionRequest, SelectionNotify, and
>ClientMessage (as per p. 225 of O'Reilly vol. 4).
>
>Shouldn't event types outside the range of the X standard protocol be
>considered nonmaskable events by Xt? (i.e. those that get assigned to
>extension events)
>
>Since this appears not to be the case is there any possibility that this
>will change with X11.R5?

I have been discussing this with Ralph Swick at MIT.  There was some
talk in this newsgroup earlier about dealing with such problems for
the input extension.

The problem is that the Intrinsics are generally extension-illiterate,
unlike Xlib.  I think it was initially thought that most extensions
wouldn't generate events, but this isn't a very good assumption.  E&S'
custom PEX picking extension generates events, the X Input Extension
(in the R5 release) generates events, etc.

In general, I think not only this problem with event handlers needs to
be addressed, but the larger problem of event management in general.
Most of the work is getting the Translation Manager to be literate of
extensions.  A workable minimum is some version of the TM that is at
least literate of the Input Extension for R5.  The problem is a sticky
one indeed.

Unfortunately, I can't comment (yet) on your proposed change to the
sample implementation because I haven't the time to learn the
internals of the Toolkit.  Maybe in the summer (yeah, right! :).

						-- Rich
-- 
  ``Read my MIPS -- no new VAXes!!'' -- George Bush after sniffing freon
	    Disclaimer: I speak for myself, except as noted.
UUCP: ...!uunet!dsd.es.com!rthomson		Rich Thomson
ARPA: rthomson@dsd.es.com			PEXt Programmer

rws@expo.lcs.mit.EDU (Bob Scheifler) (05/30/91)

    I would like to know if there is any way of providing Xt Event handlers
    to handle events that come from X extensions.

Nope.  It's a travesty that this issue has not yet been properly addressed.

    Shouldn't event types outside the range of the X standard protocol be
    considered nonmaskable events by Xt? (i.e. those that get assigned to
    extension events)

No, I don't think so, lumping everything together is rather undesirable.
There's no particularly good reason why my selection event handlers should
be inundated with input device extension motion notify events, for example.
The nonmaskable approach is flawed to begin with; I think a better approach
is to think about associating handlers with specific event type codes.  But
there are a number of issues to consider to do things "right".

    Since this appears not to be the case is there any possibility that this
    will change with X11.R5?

It's not likely that your approach will be adopted.  There is some slim
chance that some kind of support, perhaps only experimental in nature,
might work its way into R5.

swick@athena.mit.EDU (Ralph Swick) (05/30/91)

    I would like to know if there is any way of providing Xt Event handlers
    to handle events that come from X extensions.

Unfortunately no, not at the present time.

     The event type of these
    events is not known until the extension is initialized, and the event
    cannot be selected with XSelectInput.

Correct.  This is only one of the difficulties involved in adding
such support.

    The problem is that Xt doesn't seem capable of dispatching any nonmaskable
    events to the event handler other than GraphicsExpose, NoExpose,
    MappingNotify, SelectionClear, SelectionRequest, SelectionNotify, and
    ClientMessage

Also correct.  These are very explicitly specified to be the [only]
events referred to by the 'nonmaskable' argument to XtAddEventHandler.
Actually, MappingNotify is a mistake; see below.

    Shouldn't event types outside the range of the X standard protocol be
    considered nonmaskable events by Xt?

Perhaps but that would now be a significant backwards-incompatible
specification change and is therefore not acceptable.  An additional
difficulty is that it is not correct to assume (or require) that
all extension events have usable 'window' fields.  MappingNotify
is the only core event that doesn't contain a window and it requires
quite a bit of internal manipulation in Xt to dispatch it reasonably.

An aside; rather than "fixing" the implementation to dispatch
MappingNotify to all event handlers registered with nonmaskable==True,
we propose to change the spec to remove this event from the 'nonmaskable'
list.  As of R4, it is possible to express interest in MappingNotify
through the translation table mechanism and this appears adequate.

My own personal belief is that full extension event support in Xt
should allow a widget to register interest in any event, not just
those containing windows.  Extension events should also be supported
both through translation tables and through the more primitive
event handler mechanism.  Getting events dispatched to the right
place is only half the problem; the other half (and the harder
one, it appears to me) is requesting them from the server in the
first place.

    is there any possibility that this
    will change with X11.R5?

I can pretty much guarantee that full extension event support
will not appear in R5, sorry to say.  No guarantees, but some
"experimental" code might be included with the distribution.

    Looking at the sample implementation, it seems that all that would be
    required ...

I hope I've convinced you that this is far from sufficient.

    Steve Furr ( furr@mda.ca )

    Lesser artists borrow,
    great artists steal.

	- blatantly stolen from
	  Igor Stravinsky

and fools reinvent? :-)

asente@adobe.com (Paul Asente) (05/31/91)

In article <1224@mdavcr.UUCP> furr@mdavcr.UUCP (Steven Furr) writes:
>I would like to know if there is any way of providing Xt Event handlers
>to handle events that come from X extensions.  The event type of these
>events is not known until the extension is initialized, and the event
>cannot be selected with XSelectInput.

This is correct; Xt does not handle events from extensions.

>Shouldn't event types outside the range of the X standard protocol be
>considered nonmaskable events by Xt? (i.e. those that get assigned to
>extension events)

That would be a simple but not very helpful solution.  The Xt working group
prefers to come up with a solution that is more well integrated with the rest
of the Intrinsics, particularly the translation manager.

>Since this appears not to be the case is there any possibility that this
>will change with X11.R5?

Nope.

What you have to do now is not use XtAppMainLoop or XtAppProcessEvent.
XtAppMainLoop should be replaced with something like

while (1) {
    XEvent ev;

    XtAppNextEvent(app, &ev);
    if (!XtDispatchEvent(&ev)) {
	/* Must be an extension event; dispatch it myself */
    }
}

Note that because of a bug in the R4 Xt, this will not currently work, but it
has been fixed in R5.  The R4 XtDispatchEvent may croak if passed a
non-standard event; you need to do something like

while (1) {
    XEvent ev;

    XtAppNextEvent(app, &ev);
    if (/* ev is an extension event */) {
	/* Dispatch it myself */
    } else {
	if (!XtDispatchEvent(&ev)) {
	    /* Shouldn't normally happen */
	}
    }
}

XtAppProcessEvent is more problematical.  If you call it with a mask of
XtIMAll or XtIMXEvent and it encounters an extension event, it will quietly
drop the event on the floor (or possibly croak in XtDispatchEvent under R4).
You need to do something like (exact details depend on why you're using
XtAppProcessEvent instead of XtAppNextEvent and XtDispatchEvent):

XtInputMask mask;

mask = XtAppPending(app);
if (mask & XtIMXEvent /* && I-want-to-handle-it-now */) {
    /* Get event and process as above */
    mask &= !XtIMXEvent;		/* mask it out */
}

XtAppProcessEvent(app, mask);		/* won't handle X events */

This problem with XtAppProcessEvent will not go away in R5.

	-paul asente
		asente@adobe.com	...decwrl!adobe!asente

    Ratz put a bucket of liquid in front of me.
   "I wanted a glass of docs, Ratz.  What the hell is this?" I barked.
   "Motif don't fit in a glass anymore," he barked back.
    I looked at the liquid.  It was totally opaque to me.

pete@iris49.biosym.COM (Pete Ware) (05/31/91)

I understand the need for having a clean solution that supports
translations, selecting for events and dispatching events all working
on multiple displays (remember, event numbers can change from display
to display) is complicated, it's just that the current mechanism
provides absolutely no way to deal with extension events in a normal
dispatch loop!

>>   The problem is that Xt doesn't seem capable of dispatching any nonmaskable
>>   events to the event handler other than GraphicsExpose, NoExpose,
>>   MappingNotify, SelectionClear, SelectionRequest, SelectionNotify, and
>>   ClientMessage

>Also correct.  These are very explicitly specified to be the [only]
>events referred to by the 'nonmaskable' argument to XtAddEventHandler.
>Actually, MappingNotify is a mistake; see below.

>>    Shouldn't event types outside the range of the X standard protocol be
>>    considered nonmaskable events by Xt?
>>
>Perhaps but that would now be a significant backwards-incompatible
>specification change and is therefore not acceptable.  An additional
>difficulty is that it is not correct to assume (or require) that
>all extension events have usable 'window' fields.  MappingNotify
>is the only core event that doesn't contain a window and it requires
>quite a bit of internal manipulation in Xt to dispatch it reasonably.
>

Could you at least make it possible to handle non-recognized events
instead of just discarding them?  When I first started looking into
this I initially (and incorrectly) assumed that adding a raw event
handler and setting non-maskable to True, I'd get all the extension
events passed to this handler.  It made sense, since one cannont
select for the extension event and any handlers for non-maskable events
certainly have to check the event type in any case, but it didn't
work.

>An aside; rather than "fixing" the implementation to dispatch
>MappingNotify to all event handlers registered with nonmaskable==True,
>we propose to change the spec to remove this event from the 'nonmaskable'
>list.  As of R4, it is possible to express interest in MappingNotify
>through the translation table mechanism and this appears adequate.

It seems that removing MappingNotify from the list of nonmaskable
events is a far more serious a change than dispatching additional
events to handlers for nonmaskable events.  After all, handlers for
nonmaskable events already should handle GraphicsExpose, NoExpose,
SelectionClear, SelectionRequest, SelectionNotify, ClientMessage and
MappingNotify.

>I hope I've convinced you that this is far from sufficient.

I'm begging for minimal support so I don't have to force every
application that wants to use an extension to write it's own private
dispatch loop!  I can live without the ultimate solution, but life is
hard with the current situation.

--pete
Pete Ware / Biosym / San Diego CA / (619) 546-5532
     email: pete@biosym.com

rws@expo.lcs.mit.EDU (Bob Scheifler) (05/31/91)

    It seems that removing MappingNotify from the list of nonmaskable
    events is a far more serious a change than dispatching additional
    events to handlers for nonmaskable events.

Hardly, given that no implementation of Xt (to my knowledge) has ever
actually supported dispatching of MappingNotify in this way.  (The MIT
implementation sometimes dispatched to one window, that window being
the contents of an uninitialized variable.)

swick@athena.mit.EDU (Ralph Swick) (05/31/91)

    I'm begging for minimal support

We hear you.