Re: [Gtk-osx-users] accelerator problem with GtkOSXApplication



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-osx-users lists sourceforge net
> https://lists.sourceforge.net/lists/listinfo/gtk-osx-users





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