Re: [gtk-osx-users] global menu (with quartz accelerators) precedence over widget key bindings

2012/1/11 John Ralls <jralls ceridwen us>

On Jan 11, 2012, at 4:16 AM, Jesse van den Kieboom wrote:

2012/1/9 John Ralls <jralls ceridwen us>

On Jan 9, 2012, at 5:30 AM, Jesse van den Kieboom wrote:

> When enabling quartz accelerators, the menu actions have priority over widget keybindings (since the menu accelerators are activated from the gdk event filter). However, normally in gtk+ the widget key bindings have priority over the menu of the window. I understand that in OS X, the menu is working slightly different and that the menu's sensitivity is based on the widget and which actions apply on that widget. However, I think it would be more consistent with the application currently to have keybindings activate prior to the menu. Would this be possible (or is it maybe better in this case not to use the quartz accelerators?)

I'm leaning towards it's better not to use the quartz accelerators, though that messes with the "Quit" handling because the quit menu item is presently provided by Quartz... so it goes to the NSApplicationDelegate stuff. If you have quartz accelerators disabled, then cmd-Q goes to the (hidden) Gtk menu item and doesn't go through NSApplicationDelegate. It's pretty easy to fix the main menu item, but the dock menu and "shutdown" signals from Finder are a bit harder.

I haven't tested it, but I think that even on a native Cocoa app a widget keybinding would override a menu accelerator, provided that the widget in question had focus and so was first in the NSResponder chain, or that the NSWindow parent of the widget had a handler that forwarded the event to the widget. I don't offhand see a good way to replicate that with Quartz handlers.

Thanks for the reply. I have been working a bit on this and finally settled on a slightly different approach. What I would like is to have events first be handled by gtk+ (but not the menu accelerators). Then if the event is not handled by anything in gtk, pass the event to the NSApp. Like this we have widget binding precedence, but at the same time that accelerators on the menu are properly flashed when activated (since they go through OS X). A nice side effect of this also is that some other key bindings which are handled in NSApp now also work (like Cmd+~ to cycle through windows).

I didn't find "good" way to implement this behavior, but I did find a "dirty" way. I guess at some point we will have this code for menus properly residing in gtk+ so that it's not needed anymore. Until that time I currently will use a global key snooper (gtk_key_snooper_install, which is executed just before events are handed to gtk+ widgets). In this snooper I replicate the event propagation method in gtk+ (a small amount of copy/pasted code) to emit the events on the appropriate widget. I can't use gtk+ methods for this because I need to know if the event was handled or not. In the case that the event is not actually handled in the end, I pass it to nsapp. In addition, I remove the accel group corresponding to the menu from the window so that menu accelerators are not handled by gtk+.

Anyway, for me it seems to work quite nicely and is I think closer to native behavior (even though the snooper stuff is quite a hack).

I don't think I'd want to publish anything like that! ;-)

Quite right. Looking a bit further and discussing with the other gedit guys, it turns out my assumption about gtk+ was wrong. The menu in gtk+ always goes first (there is special code for that in gtk_propagate_event), and not the keybindings for widgets. The thing is that in GeditWindow (subclass of GtkWindow) we also have special code again to first redirect to the focussed widget and only after that to the menu. So it's all a happy mess at this point. I think for now I will simply not use gtk-mac-integration quartz key handling, but instead implement in GeditWindow the desired behavior.

ISTM a more profitable approach would be to get the "Quit" Apple events handled correctly with Gdk handling the accelerators, which does produce a more reasonable behavior.

Maybe. It still remains though that there are accels like Cmd+~ which are handled by NSApp itself. So it would be desirable for accelerators that are not handled anywhere, to still be passed to NSApp. The other thing that remains is that it would be nice to flash the menu bar when a menu item is activated. This is done automatically when passing the event to NSApp (which passes it to the app menu).

Have you looked at the new menu code Ryan landed in gio a couple of weeks ago? I haven't had time yet.

I haven't looked actually. Also we are still not using GtkApplication in gedit because there are some things missing that we don't yet know how to otherwise implement.


John Ralls

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