Thread: [Gtk-osx-users] accelerator problem with GtkOSXApplication
Status: Beta
Brought to you by:
jralls
|
From: Olivier S. <oli...@gm...> - 2011-02-13 21:32:48
|
Hi all, after I moved to GtkOSXApplication I have an issue with the menu accelerators. issue 1) menu accelerators use <control> instead of <command>, with ige-mac-integration everything was automatically converted to <command>. I did not set gtk_osxapplication_set_use_quartz_accelerators() (since that is enabled by default, right?) issue 2) <alt><control>X and <control>X are mapped to the same accelerator <control>X (e.g. <control><alt>c is now activated with <control>c, and both menu items show <control>c as accelerator) any ideas? Olivier |
|
From: John R. <jr...@ce...> - 2011-02-13 23:09:38
|
On Feb 13, 2011, at 1:32 PM, Olivier Sessink wrote: > Hi all, > > after I moved to GtkOSXApplication I have an issue with the menu accelerators. > > issue 1) menu accelerators use <control> instead of <command>, with > ige-mac-integration everything was automatically converted to > <command>. I did not set > gtk_osxapplication_set_use_quartz_accelerators() (since that is > enabled by default, right?) > > issue 2) <alt><control>X and <control>X are mapped to the same > accelerator <control>X (e.g. <control><alt>c is now activated with > <control>c, and both menu items show <control>c as accelerator) > > any ideas? Accelerator mapping in GtkOSXApplication is handled the Gtk way, with GtkAccelMaps. This is mentioned in the GtkOSXApplication documentation. Option/Alt is handled a bit too generically in gdk-quartz, where it's used for i18n regardless of context and consequently ignored when used as an accelerator. Ideally this handling should only occur in the input method, but I haven't figured out how to do that yet and Kristian Reitveld doesn't think it's important enough to do anything about. If anyone knows enough about the simple input method to write a patch to fix this it would be most welcome. Post it to https://bugzilla.gnome.org/show_bug.cgi?id=617583. Regards, John Ralls |
|
From: Olivier S. <oli...@gm...> - 2011-02-14 12:14:39
|
> Accelerator mapping in GtkOSXApplication is handled the Gtk way, with GtkAccelMaps. This is mentioned in the GtkOSXApplication documentation. > > Option/Alt is handled a bit too generically in gdk-quartz, where it's used for i18n regardless of context and consequently ignored when used as an accelerator. Ideally this handling should only occur in the input method, but I haven't figured out how to do that yet and Kristian Reitveld doesn't think it's important enough to do anything about. If anyone knows enough about the simple input method to write a patch to fix this it would be most welcome. Post it to https://bugzilla.gnome.org/show_bug.cgi?id=617583. > so what are my options if I do not know the details about input methods? I can go back to ige-mac-integration and try to get my menu problem solved, but that seems to be a step backwards.. Are there other options? Converting the shortcuts in the application code somehow? Olivier |
|
From: John R. <jr...@ce...> - 2011-02-14 15:03:37
|
On Feb 14, 2011, at 4:14 AM, Olivier Sessink wrote: >> Accelerator mapping in GtkOSXApplication is handled the Gtk way, with GtkAccelMaps. This is mentioned in the GtkOSXApplication documentation. >> >> Option/Alt is handled a bit too generically in gdk-quartz, where it's used for i18n regardless of context and consequently ignored when used as an accelerator. Ideally this handling should only occur in the input method, but I haven't figured out how to do that yet and Kristian Reitveld doesn't think it's important enough to do anything about. If anyone knows enough about the simple input method to write a patch to fix this it would be most welcome. Post it to https://bugzilla.gnome.org/show_bug.cgi?id=617583. >> > > so what are my options if I do not know the details about input > methods? I can go back to ige-mac-integration and try to get my menu > problem solved, but that seems to be a step backwards.. Are there > other options? Converting the shortcuts in the application code > somehow? Like I said, GtkAccelMaps: http://library.gnome.org/devel/gtk/stable/gtk-Accelerator-Maps.html There's even an example in test-integration. Learn to use your tools! Regards, John Ralls |
|
From: Olivier S. <oli...@gm...> - 2011-02-14 19:15:51
|
On 02/14/2011 04:03 PM, John Ralls wrote: > > On Feb 14, 2011, at 4:14 AM, Olivier Sessink wrote: > >>> Accelerator mapping in GtkOSXApplication is handled the Gtk way, with GtkAccelMaps. This is mentioned in the GtkOSXApplication documentation. >>> >>> Option/Alt is handled a bit too generically in gdk-quartz, where it's used for i18n regardless of context and consequently ignored when used as an accelerator. Ideally this handling should only occur in the input method, but I haven't figured out how to do that yet and Kristian Reitveld doesn't think it's important enough to do anything about. If anyone knows enough about the simple input method to write a patch to fix this it would be most welcome. Post it to https://bugzilla.gnome.org/show_bug.cgi?id=617583. >>> >> >> so what are my options if I do not know the details about input >> methods? I can go back to ige-mac-integration and try to get my menu >> problem solved, but that seems to be a step backwards.. Are there >> other options? Converting the shortcuts in the application code >> somehow? > > Like I said, GtkAccelMaps: http://library.gnome.org/devel/gtk/stable/gtk-Accelerator-Maps.html > > There's even an example in test-integration. sorry perhaps I've not understand you correctly. GtkAccelMaps as shown in test-integration.c can be used to modify the accelerator for an entry in the menu. But from your email I understood that this will not help to fix the problem with the <alt> key. Is that correct or not? Futhermore, why I really would like to get the 'magic' behavior of ige-mac-integration: I have about 295 menu entries in Bluefish (that's why I really need <alt> to maximise the number of entries that have an accelerator). In the old ige-mac-integration code all entries were automatically converted from <control> to <command>. With the new GtkOSXApplication code it seems I need something like 600 lines of extra code to replace all accelerators, and I should try to keep these in sync. Or is this again a misunderstanding and can I get the 'magic' behavior with a few lines of code? forgive me for my ignorance on this subject, I'm not a fulltime gtk programmer and it's sometimes hard to keep track of all the possibilities in gtk. Olivier |
|
From: John R. <jr...@ce...> - 2011-02-14 20:23:45
|
On Feb 14, 2011, at 11:15 AM, Olivier Sessink wrote: > On 02/14/2011 04:03 PM, John Ralls wrote: >> >> On Feb 14, 2011, at 4:14 AM, Olivier Sessink wrote: >> >>>> Accelerator mapping in GtkOSXApplication is handled the Gtk way, with GtkAccelMaps. This is mentioned in the GtkOSXApplication documentation. >>>> >>>> Option/Alt is handled a bit too generically in gdk-quartz, where it's used for i18n regardless of context and consequently ignored when used as an accelerator. Ideally this handling should only occur in the input method, but I haven't figured out how to do that yet and Kristian Reitveld doesn't think it's important enough to do anything about. If anyone knows enough about the simple input method to write a patch to fix this it would be most welcome. Post it to https://bugzilla.gnome.org/show_bug.cgi?id=617583. >>>> >>> >>> so what are my options if I do not know the details about input >>> methods? I can go back to ige-mac-integration and try to get my menu >>> problem solved, but that seems to be a step backwards.. Are there >>> other options? Converting the shortcuts in the application code >>> somehow? >> >> Like I said, GtkAccelMaps: http://library.gnome.org/devel/gtk/stable/gtk-Accelerator-Maps.html >> >> There's even an example in test-integration. > > sorry perhaps I've not understand you correctly. GtkAccelMaps as shown > in test-integration.c can be used to modify the accelerator for an entry > in the menu. But from your email I understood that this will not help to > fix the problem with the <alt> key. Is that correct or not? > > Futhermore, why I really would like to get the 'magic' behavior of > ige-mac-integration: I have about 295 menu entries in Bluefish (that's > why I really need <alt> to maximise the number of entries that have an > accelerator). In the old ige-mac-integration code all entries were > automatically converted from <control> to <command>. With the new > GtkOSXApplication code it seems I need something like 600 lines of extra > code to replace all accelerators, and I should try to keep these in > sync. Or is this again a misunderstanding and can I get the 'magic' > behavior with a few lines of code? > > forgive me for my ignorance on this subject, I'm not a fulltime gtk > programmer and it's sometimes hard to keep track of all the > possibilities in gtk. > 1. No, your map has to use something other than the alt key on OSX. The example in test-integration uses one line of code to modify ALL of the accelerators. Go RTFM. 2. I'm not going back to the automatic thing. Get a accelmap file, do sed -i '' s/alt/meta/i mapfile, and add it to your bundle. Add a call to load it somewhere (you should have that already if you've done a good job on the Gtk side). That's effectively what the automatic conversion in ige-mac-integration did. Rest assured that your non-english-speaking users would rather have the option key for typing non-ascii text than for accelerators, but if you want to turn that off, use the local copy of gtk-osx.modules (it's installed in ~/Source/jhbuild/modulesets by gtk-osx-build-setup.sh) and comment out the keymap patches. Aside: In what HIG does it say that you should have an accelerator for every menu item? Are you trying to compete with Emacs? No, no forgiveness. I am absolutely not going to teach you to use Gtk -- for one thing, I'm not good enough at it myself to do any teaching. Go study the documentation. Regards, John Ralls |
|
From: Richard P. <ric...@gm...> - 2011-02-14 20:16:33
|
On 15/02/2011, at 8:15 AM, Olivier Sessink wrote:
> [...]
> In the old ige-mac-integration code all entries were
> automatically converted from <control> to <command>. With the new
> GtkOSXApplication code it seems I need something like 600 lines of extra
> code to replace all accelerators, and I should try to keep these in
> sync. Or is this again a misunderstanding and can I get the 'magic'
> behavior with a few lines of code?
Just to jump in here: /if/ you're using the gtk AccelMap for keybindings,
which is a 1:1 mapping from application-specific binding names to key binding
definitions that can be altered at run-time, then you can achieve the
ige-mac-integration effect of converting all <ctrl> to <command> via
(in python; should be straightforward to transliterate into C):
am = gtk.accel_map_get()
def translate_control_key_to_meta(accel_path, accel_key, accel_mods, changed):
if accel_mods & gtk.gdk.CONTROL_MASK:
accel_mods &= ~gtk.gdk.CONTROL_MASK
accel_mods |= gtk.gdk.META_MASK
if not gtk.accel_map_change_entry(accel_path,
accel_key, accel_mods, replace=False):
assert False # as binding conflicts with existing, say
gtk.accel_map_foreach_unfiltered(translate_control_key_to_meta)
If you're /not/ using the AccelMap, then, AFAIK,
such run-time conversion is not possible.
warm regards,
Richard.
PS. For what it's worth, here're my notes on the GTK keybinding system
(which from where I'm standing strikes me as unnecessarily confusing):
*** AccelGroups
Accelerators must work, even if the widget with which they are
associated is not focused. However, it increases coupling if top-level
widgets in the hierarchy are responsible for the accelerators of their
children.
Therefore, we have the AccelGroup object, which fills this role of
- Listening for keyboard shortcuts and
- Dispatching them to the right handler.
The gist is:
Get an AccelGroup, a container of accelerators mapping key-press -> callback
Associate it with a top-level widget, eg, gtk.Window.add_accel_group()
gtk.Widgets.add_accelerator is /almost/ a convenience function which
lets us add an accelerator to an AccelGroup that emits a signal on the
widget when the key combination occurs. However, for menuitems it
provides a hook to setup the accelerator label appropriately.
Now, changing key bindings at run time is cumbersome for the user
because there is in general no user-visible name for the action a
key-press is associated with. Therefore the singleton accelerator map
provides a user-visible directory of named key bindings in the system.
see gtk.accel_map_change_entry(). These are "accel paths", which the
gtk.AccelGroup understands.
**** How do I retrieve the AccelGroups?
gtk.accel_groups_from_object(widget)
**** How can I retrieve bindings from an AccelGroup?
There doesn't seem to be a way?
**** How do AccelGroups receive key press events?
Via their TopLevel window key-press handler, see
gtk_window_key_press_event()
**** Can AccelGroup handlers decline to be activated?
gtk_window_key_press_event
-> gtk_window_activate_key
-> gtk_accel_groups_activate
-> gtk_accel_group_activate
-> emits 'accel_activate' on the accel group.
If this returns 'True', the key-press is considered handled.
Each callback registered with a binding
observes the accel_activate signal.
I can't see how the appropriate callback is invoked --- it
seems as if they all are?!
*** gtk.Actions and keyboard accelerators
We can bind a gtk.Action to a system accel path via
gtk.Action.set_accel_path
gtk.ActionGroup.add_action_with_accel is a convenience method which
1) creates an accel path, rooted in the ActionGroup name
("<Actions>/"<ActionGroupName>"/"<ActionName>)
2) adds a mapping from accel_path -> the keybinding spec, if any,
via gtk_accel_map_add_entry
3) Calls gtk.Action.set_accel_path.
4) Adds the action to the action group
*** How do AccelGroup and AccelPaths interact?
AccelPaths are just a mapping from string -> keybinding
AccelGroups map keybinding -> callback
They don't interact.
We may assign an AccelPath to an Action, which will then use the
keybinding when it sets up a callback with the AccelGroup when
gtk.Action.set_accel_group() is called.
>
> forgive me for my ignorance on this subject, I'm not a fulltime gtk
> programmer and it's sometimes hard to keep track of all the
> possibilities in gtk.
>
> Olivier
>
>
>
>
>
> ------------------------------------------------------------------------------
> The ultimate all-in-one performance toolkit: Intel(R) Parallel Studio XE:
> Pinpoint memory and threading errors before they happen.
> Find and fix more than 250 security defects in the development cycle.
> Locate bottlenecks in serial and parallel code that limit performance.
> http://p.sf.net/sfu/intel-dev2devfeb
> _______________________________________________
> Gtk-osx-users mailing list
> Gtk...@li...
> https://lists.sourceforge.net/lists/listinfo/gtk-osx-users
|
|
From: Olivier S. <oli...@gm...> - 2011-02-14 21:58:48
|
2011/2/14 Richard Procter <ric...@gm...>: > Just to jump in here: /if/ you're using the gtk AccelMap for keybindings, > which is a 1:1 mapping from application-specific binding names to key binding > definitions that can be altered at run-time, then you can achieve the > ige-mac-integration effect of converting all <ctrl> to <command> via > (in python; should be straightforward to transliterate into C): > > am = gtk.accel_map_get() > > def translate_control_key_to_meta(accel_path, accel_key, accel_mods, changed): > if accel_mods & gtk.gdk.CONTROL_MASK: > accel_mods &= ~gtk.gdk.CONTROL_MASK > accel_mods |= gtk.gdk.META_MASK > > if not gtk.accel_map_change_entry(accel_path, > accel_key, accel_mods, replace=False): > assert False # as binding conflicts with existing, say > > gtk.accel_map_foreach_unfiltered(translate_control_key_to_meta) great! thanks for this piece of sample code. You might want to to add this example to the GtkOSXApplication documentation because it will make life easier for a lot of programmers. I have everything converted to <command> now. Next I'll look at the <alt> issue. Perhaps I'll just remove all of the accelerators that use <alt>. Is the <fn> key on OSX also usable in combination with regular keys? thanks for your help Olivier |
|
From: Olivier S. <oli...@gm...> - 2011-02-14 22:36:18
|
I ended up with the following function, which replaces <control> with
<command and replaces <control><alt> with <command><control>
accelerators:
static void osx_accel_map_foreach_lcb(gpointer data,const gchar
*accel_path,guint accel_key, GdkModifierType accel_mods, gboolean
changed) {
if (accel_mods & GDK_MOD1_MASK && accel_mods & GDK_CONTROL_MASK) {
accel_mods &= ~ GDK_MOD1_MASK;
accel_mods |= GDK_META_MASK;
if (!gtk_accel_map_change_entry(accel_path,accel_key,accel_mods,FALSE)) {
g_print("could not change accelerator %s\n",accel_path);
}
} else if (accel_mods & GDK_CONTROL_MASK) {
accel_mods &= ~ GDK_CONTROL_MASK;
accel_mods |= GDK_META_MASK;
if (!gtk_accel_map_change_entry(accel_path,accel_key,accel_mods,FALSE)) {
g_print("could not change accelerator %s\n",accel_path);
}
}
}
|
|
From: Richard P. <ric...@gm...> - 2011-02-14 22:26:29
|
On 15/02/2011, at 10:58 AM, Olivier Sessink wrote:
> 2011/2/14 Richard Procter <ric...@gm...>:
>>
>> [snip]
>
> great! thanks for this piece of sample code. You might want to to add
> this example to the GtkOSXApplication documentation because it will
> make life easier for a lot of programmers.
Glad to be of help. Keep in mind that I'm just someone who has recently
trod the same path you're currently on: I don't consider myself an
expert in GTK and am not suggesting any of this is the canonical way to
do things. John's suggestion of an explicit keymap file may well be the
superior solution for your needs.
I like mine because:
+ve I needn't maintain multiple keymap files
+ve And also the bulk conversion doesn't silently clobber existing keybindings,
so it's relatively safe.
but
-ve It may well make things more confusing for the user who wants to
customise their bindings. They have to understand that <ctrl>
means <command> on OS X.
-ve Things get messy if you want both <command> and <ctrl> bindings.
> Is the <fn> key on OSX also usable in combination with regular keys?
I don't know, sorry.
warm regards,
Richard.
|
|
From: Richard P. <ric...@gm...> - 2011-02-14 22:53:16
|
On 15/02/2011, at 11:36 AM, Olivier Sessink wrote:
> I ended up with the following function, which replaces <control> with
> <command and replaces <control><alt> with <command><control>
> accelerators:
>
> static void osx_accel_map_foreach_lcb(gpointer data,const gchar
> *accel_path,guint accel_key, GdkModifierType accel_mods, gboolean
> changed) {
> if (accel_mods & GDK_MOD1_MASK && accel_mods & GDK_CONTROL_MASK) {
> accel_mods &= ~ GDK_MOD1_MASK;
> accel_mods |= GDK_META_MASK;
> if (!gtk_accel_map_change_entry(accel_path,accel_key,accel_mods,FALSE)) {
> g_print("could not change accelerator %s\n",accel_path);
> }
> } else if (accel_mods & GDK_CONTROL_MASK) {
> accel_mods &= ~ GDK_CONTROL_MASK;
> accel_mods |= GDK_META_MASK;
> if (!gtk_accel_map_change_entry(accel_path,accel_key,accel_mods,FALSE)) {
> g_print("could not change accelerator %s\n",accel_path);
> }
> }
> }
Stylistically, I'd be inclined to reduce this to:
static void osx_accel_map_foreach_lcb(gpointer data,const gchar
*accel_path,guint accel_key, GdkModifierType accel_mods, gboolean
changed) {
if (accel_mods & GDK_CONTROL_MASK) {
accel_mods |= GDK_META_MASK;
accel_mods &= (accel_mods & GDK_MOD1_MASK) ? ~GDK_MOD1_MASK : ~GDK_CONTROL_MASK;
if (!gtk_accel_map_change_entry(accel_path,accel_key,accel_mods,FALSE)) {
g_print("could not change accelerator %s\n",accel_path);
}
}
}
The logic is clearer to my eye, and there's less code to parse.
warm regards,
Richard.
|
|
From: Olivier S. <oli...@gm...> - 2011-02-15 19:41:08
|
2011/2/14 Richard Procter <ric...@gm...>:
> Stylistically, I'd be inclined to reduce this to:
>
> static void osx_accel_map_foreach_lcb(gpointer data,const gchar
> *accel_path,guint accel_key, GdkModifierType accel_mods, gboolean
> changed) {
> if (accel_mods & GDK_CONTROL_MASK) {
> accel_mods |= GDK_META_MASK;
> accel_mods &= (accel_mods & GDK_MOD1_MASK) ? ~GDK_MOD1_MASK : ~GDK_CONTROL_MASK;
>
> if (!gtk_accel_map_change_entry(accel_path,accel_key,accel_mods,FALSE)) {
> g_print("could not change accelerator %s\n",accel_path);
> }
> }
> }
looks better indeed, thanks :)
Olivier
|