Re: NotifyUngrab handling




Felix Bellaby <felix@pooh.u-net.com> writes:

> Owen Taylor writes: 
>  > Do you have code that demonstrates the problem? 
> 
> Ok, try the following:

Well, I was hoping for a nice neat example program...

> 1) Start up gnome with the gnome-session manager.
> 
> 2) Start up a gnome-terminal (with an enabled menubar).
> 
> 3) Execute the command:
> 
> 	$ save-session &
> 
> 4) Quickly click on one of the menus on the gnome-terminal and move 
>    the mouse away over onto the root window (so that the menu stays up).
>    The gnome-terminal will now have a grab on the pointer waiting
>    for a button press or for a motion event over the menu.
> 
> 5) Wait for a few seconds until gnome-session has started the
>    save and gnome-terminal has responded by executing the following 
>    code in gnome-client.c(save_yourself_callback):
> 
>    gdk_pointer_ungrab (GDK_CURRENT_TIME);
>    gdk_keyboard_ungrab (GDK_CURRENT_TIME);
>    gtk_grab_add (client_grab_widget);
> 
>    This code removes the grab held by the gnome-terminal. The
>    pointer icon changes to reflect this event and a NotifyUngrab
>    is sent by the Xserver (see XUngrabPointer (3)).

Note that there is no "NotifyUngrab" event. There are
enter/leave notify events with a mode sent to Notify[Un]Grab,
but these events are not generated when the mouse
is over the grab window.
 
To call gdk_pointer_grab() when your code did not grab
the pointer is simply unsupported in GTK+. So your code
might well cause the pointer to be ungrabbed without 
the menu code having any knowledge of that at all.

> 6) Now, when you press the mouse button the gnome-terminal menu
>    does not recieve the event because it does not have the grab.
>    As a result, the menu stays may it is and remains there
>    until you send an event to the gnome terminal itself. 
> 
> 7) For example, you can drag the gnome-terminal out from under 
>    the menu using the window manager handles on its frame, but 
>    if you click on the gnome-terminal client window then the menu 
>    gets the event and pops down (gnome-client.c will have released 
>    its grab by now).

> Similar effects can be generated by the Xserver spontaneously
> when it issues a NotifyUngrab as a result of the menu becoming
> obscured. 

Not true, you can have a grab on an obscured window. You
can't have a grab on a window is not "Viewable" - i.e.,
it or one of its parent windows is hidden. 

Basically, when you grab the X the mouse or keyboard, the
only way that any other client can cause your to release
that grab is by hiding your windows.

> However, these are more tricky to reproduce because 
> the NotifyUngrab is rarely the LAST event to be recieved by the
> gtk app. Usually, the WM sends some other event (e.g. FocusOut) 
> which causes the menu system to close down. 

No, the only thing that causes the menu system to close
down is a ButtonPress or Release.
 
> That said, I have seen menus left hanging on the screen 
> occaisonally and my diagnosis of the problem lies with missed
> NotifyUngrab messages.

If anybody can provide a reproducible way of getting 
menus to hang on the screen, please do send it in.

>  > Offhand, I don't understand why the app needs to 
>  > to worry about NotifyUngrab at all. (Not saying there
>  > isn't a reason, I just don't know it.)
> 
> The reason is not to difficult to root out.
> 
> Grabs are set so that events that would usually go somewhere else
> go to the window with the grab. This must mean that the window
> intends to respond to these events in some way (e.g. deactivating
> a menu). If the grab is taken away then the events that the window
> was waiting for will go somewhere else. As a result the window
> will be left waiting for something that does not get there.
>
> In most circumstances, some other event gets through that has the 
> same effect as the events that were missed and there is no visible
> bug. However, this is a hit and miss approach that resembles
> reading from a stream without checking that the connection is still
> open and free of io errors.

But the point is, X does not provide a reliable way of 
detecting ungrabs, because there is no need for such a
mechanism, since no other client can cause you to forcibly
release a grab.

Now, I understand why you don't want to hold a grab while
waiting for SaveYourselfDone - other clients may need
to interact with the use. But Notify[Un]grab enter/leave
events don't do us any good.

If we want a mechanism for this, we need to invent it ourself.

(Actually, session management isn't the only case where this
type of thing comes up. In DND, when a drag starts, one
wants to convince the widget where the drag started that
it should ignore the button press event that started the
drag.)

Perhaps we need an GDK_ABORT_GRAB_REQUEST event which we
send to the window holding the grab to tell it to give
up the grab. But this would require quite a bit of 
code modification  - there are 15 uses of gdk_pointer_grab()
in GTK+, 9 in gnome-libs, 22 in the GIMP, etc...

(and it would require breaking binary compatibility to add 
 another event type)

I don't think we want to do that right now.

Isn't the right thing to do just to hold up the processing 
of the SaveYourself message until the grab was released -
i.e., poll in a timeout until !gdk_pointer_is_grabbed(). 

(There is no equivalent gdk_keyboard_is_grabbed(), but 
grabbing the keyboard without grabbing the pointer 
is a bug, so that should not be a problem)
 
Regards,
                                        Owen



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]