GDK and XInput [Was: Re: Thanks for Tablet Testing]

2000-11-17 Thread Garry R. Osgood

Simon, Raphael, All...

I had the opportunity to spend three or four hours
yesterday afternoon/evening (GMT -5.00) seeking ways
to rescue Marching Ants (#10498).

I can confidently report that a call such as:

return_val = gdk_pointer_grab (gdisp-canvas-window, FALSE,
 GDK_POINTER_MOTION_HINT_MASK |
 GDK_BUTTON1_MOTION_MASK |
  GDK_BUTTON_RELEASE_MASK,
 NULL, NULL, bevent-time);

does not behave identically for core events (Defined in the
original X11 protocol) and XInput Extension events. This is
true when GTK+-1.2.8 has been built with the --xinput=xfree
option. While the GDK event request list is honored for core
X11 protocol events, the XInput events are subject to
special handling. The culprit,
gdk_input_common_find_events(), while nominally in charge of
just mapping the the GDK event request list into appropriate
XInput device classes [gtk+-1.2.8/gdk/gdkinputcommon.h], it
in fact asserts an internal policy of linking symmetric
events.  That is, this code virtually adds
GDK_BUTTON_PRESS_MASK when a client requests only
GDK_BUTTON_RELEASE_MASK -- and vice-versa.

The comment is unhelpful:

  /* We have to track press and release events in pairs to keep
 track of button state correctly and implement grabbing for
 the gxi support */
  if (mask  GDK_BUTTON_PRESS_MASK || mask  GDK_BUTTON_RELEASE_MASK)
{
  DeviceButtonPress (gdkdev-xdevice, gdkdev-buttonpress_type,
class);
  if (class != 0)
   classes[i++] = class;
...

[gdk_input_common_find_event() gdkinputcommon.h Line 322 ff]

It is not clear to me why "button state" matters to GDK or
why GTK+-1.2.8/GDK requires events to be linked in this
fashion -- for XInput Extension devices only.

To the contrary, Gimp' family of selection tools require the
alternate circumstance: that during the grab, button press
events cannot be permitted to arrive, else the grand Gimp
event dispatcher, gdisplay_canvas_events()
[disp_callbacks.c], would divert Gimp process flow into a
(likely) menu dispatch. Since many menu implementations are
"tool-like", this can lead to the unloading of the current
selection tool before it has had opportunity to put its
persistent state in order -- thaw the undo stack, for
example. This is especially true for the "Trojan Horse"
tool, edit-select, which, through invitation by some other
select tool (invoking init_edit_selection()), temporarily
substitutes its predecessor's tool methods for its
own. Should this tool become unloaded because of a
menu-related button press, the predecessor's finalize
methods are not called and the tool itself does not have
full opportunity to clean up.

What to do?

Certainly, bug reports to GTK are in order: GTK "promises"
to abstract the pointer so that the application writer does
not have to do anything special with core and extension type
events. Grab semantics should be uniform. Now that I am
confident of the chain of causuality, I can handle that.

In light of an (is it coming? Really?) 1.2 Release
The question I have for the group is:

1) Document, warn, but otherwise ignore the problem.
   It affects users with a certain type of tablet hardware
   and only when that hardware is being used as an explicit
   XInput device. Wait for a GDK fix to remove its hidden policy?

2) Make a Gimp level hack in the much-abused event loop to
   filter button presses that originate from devices when
   a grab is in effect. (not pretty -- except for possibly
   being pretty lame)?

3) Re-engineer select tool code to be more robust in button
   press events (much work here)?

Which of these is the best line of action? Do you have other
proposals?

If no one objects, I would like to elevate #10498 from 'critical'
to 'grave.' Through a chain of causuality originating with edit-select
not being able to perform a thaw, eventually (sometimes) there is
a fatal crash in undo. Not sure why, but grave bugs are the ones
that crash Gimp - at least sometimes.

Thank you to Simon and Raphael for thoughts, observations, snippets
of test code. As an aside, I think Simon is correct in observing
that this bug is also related to Bug #6901, "Can not continually move a
floating selection with a pressure sensitive pointer."?

Be good, be well

Garry





Re: Thanks for tablet testing...

2000-11-16 Thread Garry R. Osgood

Simon, Raphael

Simon: Thank you for the Havoc Pennington/X-11 Consortium documentation
   As Raphael points out, the GDK/XInputExtension glacis is where interesting
   affairs transpire.

Raphael wrote:
 I think that #10498 occurs because of a combination of two things:
 - A bug in GTK+ (in the interaction between XInput and the core
  pointer) breaks the semantics of the pointer grab, so the
  application (Gimp) receives some events that should never occur
  while the pointer is grabbed.

I suspect this. I'm not at the stage where I actually believe this.

 - For the ArtPad II under XFree86, another bug in XFree shadows the
  GTK+ bug and causes other strange things to happen.

Can't say anything useful here, since I am testing without XFree86 (Setup uses Xsgi)

 If this theory is correct, then the Gimp 1.2 should require a new
 release of GTK+.  :-(

I am rather leaning toward this sad conclusion. However, at Gimp level, we never
check gdk_pointer_grab() to confirm we have the pointer, and that is suspect [example:
app/rect_select.c line 173] Pennington tells us we should (See 10.6.2 GTK/Gnome App 
Dev,
first reference in Simon's mail]

Also, we limit grab to the current window only, not to child windows (like menu panes?)
so we can lose control of focus, no? When the pen point (simulated left mouse button)
is already down and a grab has been made from rect_select, then here's what watch
points at gdk_pointer grab report:

(Tablet device enabled and active)
(Rect Selection already made)
(Cursor in selection)
(pen point goes down...)

 only asking for grab on 
current window
 V
  0 gdk_pointer_grab(window = 0x107bcb50, owner_events = 0, event_mask = 552, 
confine_to = 0x0, cursor = 0x0, time = 42275620) ["gdk.c":694, 0x0400cdec]
   1 rect_select_button_press(tool = 0x10777d10, bevent = 0x103e79c8, gdisp_ptr = 
0x107bb6c8) ["rect_select.c":173, 0x101e3244]
   2 gdisplay_canvas_events(canvas = 0x107b6320, event = 0x103e79c8) 
["disp_callbacks.c":281, 0x100b0878]

rest of stack snipped...

gdk_xgrab_window = 0x107bcb50 -- gimp image display window
return_val = 0-- grab was a success

(Floating selection being dragged, then "right mouse button" simulated depressed on 
pen body)

 Menu pane asks for self  
child
 V
  0 gdk_pointer_grab(window = 0x1087a308, owner_events = 1, event_mask = 13060, 
confine_to = 0x0, cursor = 0x108bb570, time = 42288140) ["gdk.c":694, 0x0400cdec]
   1 gtk_menu_popup(menu = 0x1065ed70, parent_menu_shell = 0x0, parent_menu_item = 
0x0, func = 0x0, data = 0x0, button = 3, activate_time = 42288140) ["gtkmenu.c":493, 
0x5fed58bc]
   2 gdisplay_canvas_events(canvas = 0x107b6320, event = 0x103e79c8)

rest of stack snipped...

gdk_xgrab_window = 0x1087a308 -- menu pane window (child of gimp image window, yes 
???)
return_val = 0-- menu pane gets its pointer grab...

The hunt continues

Garry