GNOME Bugzilla – Bug 107320
Popup windows do not close when window loses focus
Last modified: 2011-02-04 16:18:46 UTC
Popup menus and windows should close when the user moves to another application - by clicking on its window, or selecting it from the taskbar. At present, they remain open - even if another application completely obscures their owner/parent window. Cause: Modal message loops should be used to display popups and to prevent them from taking activation status from the owner window. Pan appears to be showing the windows as simple popup-windows, and is not tracking the activation state of the parent. When the parent becomes inactive, a click occurs outside of the popup window on the parent window, or the message loop receives a WM_CANCELMODE message, the popup window should be immediately destroyed (or hidden).
Pan just uses vanilla GtkItemFactory for menus; this is probably something to bounce to the gtk team.
Reassigning to the owner of the gtk win32 component
If you have a (native) menu up in win32, does a click on the title bar of another window immediately activate that window, or does the first click deactivate the menu and a second click is required to focus the window? In current GTK+ operation, window deactivation is done with a global pointer grab; if such a grab isn't possible in Windows, we may have to add additional code to GtkMenu to also deactivate the menu when the toplevel loses activation. (Doing this for popups is much harder, and in fact, not possible for most GTK+ apps without application modification, since GTK+ has no idea what window the popup belongs to)
"If you have a (native) menu up in win32, does a click on the title bar of another window immediately activate that window, or does the first click deactivate the menu and a second click is required to focus the window?" it immediately activates the window.
Implementing pointer grabs that would work like on X11 is hellish on Windows...
*** Bug 124140 has been marked as a duplicate of this bug. ***
I have high hopes that rewriting the pointer and keyboard grab code in gdk/win32 to use low-level mouse and keyboard hooks will fix this and many other problems. (Low-level hooks are present only in NT/2k/XP.) I have already mostly done the pointer grab rewrite, and see a clear improvement. Will do the keyboard grab next. Most apps written natively for Win32 pop down menus at once when the Alt key is pressed. Should GTK apps behave the same? It isn't obvious to me how well this would fit into GTK .
*** Bug 124144 has been marked as a duplicate of this bug. ***
Any news on this issue ? Apparently Windows apps will handle the alt key in the following way: pressing alt will select the menu bar without opening/displaying it. Pressing alt again if the menu is selected or display will automatically close the menu and unselect it. Arno
I did commit a hackish stopgap fix for this to the stable branch on 2003-10-25: On WM_CANCELMODE, if the pointer and keyboard are grabbed, fake a mouse click on the root window. This is an awful hack to get menus to pop down properly when switching to another top-level window using the task switcher (Alt-Tab). Using low-level hooks to implement pointer and keyboard grabbing would be cleaner, but low-level hooks sound a bit dangerous, and Owen says we should avoid using them if at all possible. Fix for #107320. I am not very fond of that fake mouse click solution, though. I have code sitting on my disk that uses low-level hooks, and solves this and related problems a bit better, perhaps. But, unfortunately I have found one minor regression so far with it: If you have clicked a mouse button just once on a button, scroll bar, etc in the GTK app, and then move the mouse to the bottom edge of the screen, Explorer doesn't display it's auto-hidden taskbar... You have to click once on the desktop to "wake up" Explorer. Anyway, perhaps I should commit what I have so far, to the stable branch? The use of low-level hooks can be skipped using a command- line switch or environment variable, if it does cause some more serious problems. (Owen mentions possible interaction with on-screen keyboards, drivers for two-wheel mice, etc.) I think much of these problems wouldn't occur if gtk would handle loss of focus in more places? (As it is more or less impossible on X11 to lose focus if you have the mouse and keyboard grabbed (I think), this problem doesn't occur on X11.) I did try to hack this into some place in gtk, but got nowhere. To summarize: I don't know what the correct way to go forward is;-) I have a fix, but it probably isn't the Right Way to do it. On the other hand, the Right Way might be something for HEAD only. Owen said in a private mail: instead of trying to *exactly* duplicate the X11 behavior on Windows, I'd like to instead to decide what behaviors we want the user to see, and make sure we have the necessary APIs to allow widgets to robustly implement those behaviors. There are a whole large list of problems with pointer grabs on X11 that I could go into here ... and *with* actual support in the windowing system. Trying to duplicate the X grab model on Windows really doesn't seem like a good idea to me.
I'm not sure if this is any help, but I have experienced this problem too. I showed the application to a hardcore windows programmer and he noticed it and said that if the context menu's parent window does NOT have focus at the time of creation, the menu behaves this way. Does this help?
This bug should be a MAJOR severity atleast. This problem seems to cause other problems too. I have been working on a work around for the menus staying up. I did this with the focus-out-event calling gtk_menu_shell_deactivate() on the menubar. This seems to work ok, but, I have found a similar, perhaps related bug. If I open a menu, then move the mouse over a button on the same window, and click that button, the menu is deactivated, BUT the button is unclickable. Only when the mouse cursor is moved off the button's dimensions, and back on again, can i click it. The funny thing is, I can press spacebar to activate the button at any time. I did some testing, it is not a timing issue, also, I tried using GetCursorPos() and SetCursorPos() and that makes no difference at all ? If I use gtk_widget_grab_focus(), gtk_widget_show(), gtk_widget_hide(), gtk_widget_set_sensitive() on any other widget or the same widget, it makes no difference either. Should I raise a separate bug for this other problem? Can we mark this bug as a priority ?
*** Bug 132427 has been marked as a duplicate of this bug. ***
*** Bug 139264 has been marked as a duplicate of this bug. ***
Please note that what I wrote in comment 10 about the "stable" branch referred to GTK+ 2.2.x. Now, GTK+ 2.4 is the officially stable branch, and there won't be any more GTK+ 2.2.x (source) releases. (I did release a binary snapshot builds for Windows, gtk+-2.2.4-20040124, and might do another one if it seems necessary.)
Yes, this bug is in 2.4 and IMHO is a major bug that needs attention. I'm willing to put together a patch for it, but the question is what event should be returned when the grab is broken. We do want the behavior that switching apps does end the mouse & keyboard grabs because this is what other win32 apps do. But because this is not possible on X11, it's not clear to me how to implement it. Is there a list somewhere of fixes in 2.2.x that are not in 2.4.x?
Created attachment 26984 [details] [review] Deactivate menu shell if lose focu Following up on Owen's suggestion on gtk-devel-list that menus should watch the focus signal, I've put together this patch which adds the focus_out_event menu handler to GtkMenuShell and modifies the win32 backend code to emit focus out to the pointer grabbing widget if FOCUS_CHANGE is in its event mask. A focus out is also emitted to the toplevel window losing focus because I think it will want it whether or not there's a grab in affect. Is this the correct approach? If so, I can go through gtk and add focus out handlers where needed.
In case it's useful, you can find an excellent example of how to build "fake" menus that work correctly under Windows in the Microsoft Windows Platform SDK, under: \PlatformSDK\Samples\winui\Shell\Fakemenu Full source code is provided... although ideas for how to integrate it with GTK's way of doing things are not...
Is there a way to print all the gdk events dispatched to gtk? I'd like to do this on both X11 and win32.
Yes, start the app with --gdk-debug=events (or set the GDK_DEBUG environment variable to "events").
*** Bug 145156 has been marked as a duplicate of this bug. ***
This still happens in 2.4.7. Perhaps the Version should be updated to 2.4.x.
Yes.
This bug occurs on X11 as well as on win32 and some sort of grab broken notification is needed to fix it. To reproduce it on X11, press the mouse button down, switch to another virtual desktop with a key accelerator, and then release the mouse button. When you return to the original desktop, the button will still appear depressed when the mouse is over it because it never received a mouse up event. This discussion regarding grabs and window visibility is also relevant here: http://mail.gnome.org/archives/gtk-devel-list/2003-June/msg00034.html Unless gdk objects are going to start emitting signals that are handled by gtk, I think the thing to do here is to define a GDK_EVENT_GRAB_BROKEN event and a 'grab_broken' signal on GtkWidget that can be handled by widgets that want to detect broken grabs. I can put together a patch to implement this if this is the approach we want to take.
jpe, have you had any time or inspiration to work on that grab broken signal/event idea?
I'll try to put together the start of a patch after Christmas and then send a message to gtk-devel asking for feedback.
Created attachment 35625 [details] [review] grab-broken implementation This patch adds a grab-broken gdk event and gtk widget signal. The win32 backend emits it in response to a WM_KILLFOCUS if an explicit or implicit grab is active. The GtkMenuShell and GtkButton provide handlers for the associated signal that deactivates the menu or releases the button, respectively, when the grab is lost. More widgets probably need to handle the grab broken signal and the X11 backend needs to emit it when an implicit mouse grab is broken by switching to a new virtual console via a keyboard accelerator. I will work on completing the patch if I get feedback that this to the right direction to take this.
Any feedback on the suggested patch and possible follow ups ? I guess many Windows users would love to see this fixed, so it would be great if we could make some prgoress on this issue. Arno
*** Bug 168272 has been marked as a duplicate of this bug. ***
I reported this bug over 2 years ago. So much for the "many eyes" making "quick bugfixes" with Open Source, eh?
There aren't really that many eyes working on the Win32 backend. New volunteers ar always needed. Plus, as can be seen from John Ehresman's patch above, fixing this properly requires changes also to the backend-independent parts of GTK+, which means it needs wider review and approval.
*** Bug 160395 has been marked as a duplicate of this bug. ***
This is a near-duplicate of bug 114744, which asks for notification on lost grabs and viewability changes.
Created attachment 48300 [details] [review] more complete grab-broken implementation I took jpe's patch and implemented grab-broken for x11, too. I also added some docs. I tested the menushell thing, and it in fact fixes the problem with menus staying up if the current desktop gets "spontaneously" changed. We should probably add the same code in other places where we pop up override-redirects under grabs, like gtkcombobox.
Committed this now. Still need to go over the remaining grabs and see where we need grab_broken implementations. 2005-06-25 Matthias Clasen <mclasen@redhat.com> Add a GrabBroken event to GDK, and a grab-broken-event signal to GtkWidget. (#107320, Simon Cooke, initial patch by John Ehresman) * gdk/gdkevents.h: Add a GDK_GRAB_BROKEN event type, define a GdkEventGrabBroken event struct. * gdk/win32/gdkevents-win32.c (gdk_event_translate): Generate GrabBroken events in response to WM_KILLFOCUS. * gdk/x11/gdkmain-x11.c: Generate GrabBroken events when a grab is broken by the window becoming unviewable, or by another grab from the same client. * gtk/gtkwidget.h (GtkWidgetClass): Add grab_broken_event. * gtk/gtkwidget.c (gtk_widget_event_internal): Translate GrabBroken events into grab_broken_event signals. * gtk/gtkmain.c (gtk_main_do_event): Propagate GrabBroken events. * gtk/gtkmenushell.c (gtk_menu_shell_grab_broken): Deactivate the menu when the grab is broken. * gtk/gtkcolorsel.c (gtk_color_selection_grab_broken): Stop the color picker if the grab is broken. * gtk/gtkpaned.c (gtk_paned_grab_broken): Stop the drag if the grab is broken.
After rebuilding gtk+ with this patch applied, nautilus' desktop popup menu cannot be displayed.
It's been fixed with this commit FYI: Sun Jun 26 00:04:36 2005 Manish Singh <yosh@gimp.org> * gdk/gdkevents.c (gdk_event_get_time, gdk_event_get_state): add GDK_GRAB_BROKEN to the switch cases. * gtk/gtkmenushell.c (gtk_menu_shell_grab_broken): remove unused variables. * gtk/gtkpaned.c (gtk_paned_grab_broken): return TRUE.
More likely by: 2005-06-25 Matthias Clasen <mclasen@redhat.com> * gdk/x11/gdkmain-x11.c (gdk_keyboard_grab, gdk_pointer_grab): Don't emit grab-broken for overgrabbing, until we figure out how to do that without breaking the menu code
I have committed further changes which make GrabBroken events useful for reporting grabs that are broken by overgrabbing inside the same application. The win32 code will need to be changed to emit those as well. 2005-06-27 Matthias Clasen <mclasen@redhat.com> * gtk/gtkmenushell.c (gtk_menu_shell_grab_broken): Ignore GrabBroken events which are caused by overgrabbing inside the application; menus rely on these for their operation. * gdk/gdkevents.h (struct _GdkEventGrabBroken): Add a grab_window field. * gdk/win32/gdkevents-win32.c (gdk_event_translate): Set grab_window to NULL when generating GrabBroken events for WM_KILLFOCUS messages. * gdk/x11/gdkmain-x11.c (_gdk_xgrab_check_unmap) (_gdk_xgrab_check_destroy): Set grab_window to NULL when generating GrabBroken events when the grab window becomes unviewable or is destroyed. * gdk/x11/gdkmain-x11.c (gdk_pointer_grab, gdk_keyboard_grab): Generate GrabBroken events when overriding a grab inside the application. In this case, set grab_window to the new grab_window.
Now also the Win32 code emits GrabBroken events also when overgrabbing. Can this bug be resolved now? 2005-07-29 Tor Lillqvist <tml@novell.com> * gdk/win32/gdkevents-win32.c (generate_grab_broken_event): New static function to generate and append the GDK_GRAB_BROKEN events. (gdk_pointer_grab, gdk_keyboard_grab): Generate grab broken events when overriding a grab inside the application, like in the X11 backend. Final bits of the fix for #107320, hopefully. (print_event): Handle also GDK_SETTING, GDK_OWNER_CHANGE and GDK_GRAB_BROKEN events. (gdk_event_translate): Call generate_grab_broken_event() in place of inline code.
I think so.
*** Bug 311029 has been marked as a duplicate of this bug. ***