Partie prenante

Interface de configuration
Les raccourcis clavier peuvent être configurées grâce au programme gnome-keybinding-properties (gnome-control-center/capplets/keybindings/) du menu "Système > Préférences > Raccourcis clavier". Par exemple, l'action "Bureau > Prendre une capture d'écran" est associée à la touche "Impr".
Liste des actions
La liste des actions provient des fichiers xml qu'on retrouve dans le répertoire /usr/share/gnome-control-center/keybindings/. Par exemple, l'action "Bureau > Prendre une capture d'écran" est définie dans le fichier 50-metacity-desktop-key.xml (qui vient de metacity/src/50-metacity-desktop-key.xml.in), avec l'entrée suivante:
<KeyListEntries wm_name="Metacity" package="metacity" name="Desktop">
    <KeyListEntry name="/apps/metacity/global_keybindings/run_command_screenshot"/>
</KeyListEntries>
Valeur des actions
La valeur des actions est définie dans la base de données gconf (propre à chaque utilisateur) avec la valeur de l'attribut "name" du KeyListEntry. On peut voir cette valeur avec le logiciel "gconf-editor" ou dans le fichier texte "~/.gconf/apps/metacity/global_keybindings/%gconf.xml" sous l'entrée:
<gconf>
        <entry name="run_command_screenshot" mtime="1217392592" type="string">
                <stringvalue>Print</stringvalue>
        </entry>
</gconf>
Assignation aux applications
Lorsqu'on change un raccourci, c'est le logiciel "metacity" qui l'associe au "?". Le logiciel détecte le changement grâce à gconf.
Metacity
Le fichier "metacity/src/core/prefs.c" définit la constante KEY_SCREEN_BINDINGS_PREFIX pour écouter la configuration des touches de raccourcis. #define KEY_SCREEN_BINDINGS_PREFIX "/apps/metacity/global_keybindings". Le fichier écoute et enregistre la configuration avec la fonction update_screen_list_binding() / update_binding() et update_list_binding().
Le fichier "metacity/src/include/screen-bindings.h" contient la définition de la clée: keybind (run_command_screenshot, handle_run_command, 32, 0, "Print", _("Take a screenshot")). handle_run_command est une fonction dans src/core/keybindings.c.
Où sont configurer les commandes?
Si on regarde la fonction meta_prefs_get_gconf_key_for_command (fichier "metacity/src/core/prefs.c"), si l'option est la numéro 32, l'option run_command_screenshot (MAX_COMMAND_IDX (34) - 2), alors la clé est définie dans la configuration gconf /apps/metacity/keybinding_commands/command_screenshot.
Qui bloque l'écoute des commandes?
Dans le fichier "metacity/src/core/keybindings.c", dans la fonction meta_display_process_key_event, il est écrit:
  /* ignore key events on popup menus and such. */
  if (window == NULL &&
      meta_ui_window_is_widget (screen->ui, event->xany.window))
    return;
Qui appel la fonction qui filtre les touches?
metacity/core/display.c : event_callback appel le filtreur de commande meta_display_process_key_event.

NOTE: L'écoute par gnome-settings-daemon du répertoire /apps/gnome_settings_daemon/keybindings dans le fichier gnome-settings-daemon/plugins/keybindings/gsd-keybindings-manager.c n'est pas lié à cette configuration.

Brouillon
gdk/x11/gdkevents-x11.c
static gboolean
gdk_event_translate (GdkDisplay *display,
         GdkEvent   *event,
         XEvent     *xevent,
         gboolean    return_exposes)
{
  if (_gdk_default_filters) 
  {
      result = gdk_event_apply_filters (xevent, event, _gdk_default_filters);
  }
  ...
  switch (xevent->xvisibility.state)
  {
    case ClientMessage:
      tmp_list = display_x11->client_filters;
      GdkClientFilter *filter = tmp_list->data;
      result = (*filter->function) (xevent, event, filter->data);
  }
}

gdk/gdkglobals.c:GList              *_gdk_default_filters = NULL;
gdk/gdkinternals.h:extern GList            *_gdk_default_filters;

gdk/gdkwindow.c:
void          
gdk_window_add_filter (GdkWindow     *window,
           GdkFilterFunc  function,
           gpointer       data)
{
  GdkWindowObject *private;
  GList *tmp_list;

  // ...
  private = (GdkWindowObject*) window; 
  if (private)
    tmp_list = private->filters;
  else 
    tmp_list = _gdk_default_filters;

  ///...
  if (private)
    private->filters = g_list_append (private->filters, filter);
  else
    _gdk_default_filters = g_list_append (_gdk_default_filters, filter);

void
gdk_window_remove_filter (GdkWindow     *window,
        GdkFilterFunc  function,
        gpointer       data)
{
  // same condition with private
}


gdkdisplaymanager.c:
static GdkDisplay *default_display = NULL;
setter:
GdkDisplayManagerClass->set_property(GObject *object, PROP_DEFAULT_DISPLAY, const GValue *value)
gdk_display_manager_set_property(GObject *object, PROP_DEFAULT_DISPLAY, const GValue *value);
gdk_display_manager_set_default_display(GdkDisplayManager *display_manager, GdkDisplay *display)


setter called by:
gdk/gdkdisplay.c: gdk_display_dispose() ?

getter:
gdk_display_manager_get_default_display(0)
gdk_display_get_default()


plugins/keybindings/gsd-keybindings-manager.c
add filter on gdk_screen_get_root_window (screen)

Si on crée une application, gtk_init(), le filter du root_window sera un filtre sur un type GdkScreenX11.

gdk/x11/gdkevents-x11.c:

static Bool 
gdk_xsettings_watch_cb (Window   window,
      Bool   is_start,
      long     mask,
      void    *cb_data)
{
  GdkWindow *gdkwin;
  GdkScreen *screen = cb_data;
  // ...
  gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window);
  gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
  // ...
}

gdk_xsettings_watch_cb is called by:
void
_gdk_x11_events_init_screen (GdkScreen *screen)
{
  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
  screen_x11->xsettings_client = xsettings_client_new_with_grab_funcs (screen_x11->xdisplay,
                                   screen_x11->screen_num,
                                   gdk_xsettings_notify_cb,
                                   gdk_xsettings_watch_cb,
                                   screen, refcounted_grab_server,refcounted_ungrab_server);
}

Metacity adding

//core/display.c
gboolean meta_display_open (void) {
  /* Get events */
  meta_ui_add_event_func (the_display->xdisplay, event_callback, the_display);
  //ui/ui.c
  void meta_ui_add_event_func (Display *xdisplay, MetaEventFunc  func, gpointer data)
  {
      g_return_if_fail (ef == NULL);

      ef = g_new (EventFunc, 1);
      ef->func = func;
      ef->data = data;
      gdk_window_add_filter (NULL, filter_func, ef);
  }
}

//ui/ui.c
static GdkFilterReturn
filter_func (GdkXEvent *xevent,
             GdkEvent *event,
             gpointer data)
{
  g_return_val_if_fail (ef != NULL, GDK_FILTER_CONTINUE);

  if ((* ef->func) (xevent, ef->data))
    return GDK_FILTER_REMOVE;
  else
    return GDK_FILTER_CONTINUE;
}

//core/display
static gboolean
event_callback (XEvent   *event,
                gpointer  data)
{
  gboolean filter_out_event;
  ...

  filter_out_event = FALSE;

  switch (event->type)
    {
    case KeyPress:
    case KeyRelease:
      meta_display_process_key_event (display, window, event);
      break;
    } 
  return filter_out_event;
}