summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac10
-rw-r--r--data/Makefile.am1
-rw-r--r--data/org.mate.SettingsDaemon.plugins.keybindings.gschema.xml.in14
-rw-r--r--data/org.mate.keybindings.gschema.xml.in5
-rw-r--r--plugins/Makefile.am3
-rw-r--r--plugins/keybindings/Makefile.am55
-rw-r--r--plugins/keybindings/dconf-util.c113
-rw-r--r--plugins/keybindings/dconf-util.h45
-rw-r--r--plugins/keybindings/keybindings.mate-settings-plugin.in8
-rw-r--r--plugins/keybindings/msd-keybindings-manager.c721
-rw-r--r--plugins/keybindings/msd-keybindings-manager.h61
-rw-r--r--plugins/keybindings/msd-keybindings-plugin.c109
-rw-r--r--plugins/keybindings/msd-keybindings-plugin.h63
13 files changed, 1202 insertions, 6 deletions
diff --git a/configure.ac b/configure.ac
index 1526c37..e91ca27 100644
--- a/configure.ac
+++ b/configure.ac
@@ -80,6 +80,15 @@ case $host_os in
esac
AC_SUBST([MSD_PLUGIN_LDFLAGS])
+PKG_CHECK_MODULES([DCONF], [dconf >= 0.13],
+ [AC_DEFINE([HAVE_DCONF_0_13], [1], [Use DCONF >= 0.13])],
+ [PKG_CHECK_MODULES([DCONF], [dconf >= 0.10],
+ [AC_DEFINE([HAVE_DCONF_0_10], [1], [Use DCONF 0.10])
+ ])
+])
+AC_SUBST(DCONF_CFLAGS)
+AC_SUBST(DCONF_LIBS)
+
AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
GLIB_GSETTINGS
@@ -476,6 +485,7 @@ plugins/common/Makefile
plugins/datetime/Makefile
plugins/dummy/Makefile
plugins/housekeeping/Makefile
+plugins/keybindings/Makefile
plugins/keyboard/Makefile
plugins/media-keys/Makefile
plugins/media-keys/cut-n-paste/Makefile
diff --git a/data/Makefile.am b/data/Makefile.am
index a6f3631..4ae81d4 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -11,6 +11,7 @@ gsettings_SCHEMAS = \
org.mate.SettingsDaemon.plugins.clipboard.gschema.xml \
org.mate.SettingsDaemon.plugins.datetime.gschema.xml \
org.mate.SettingsDaemon.plugins.housekeeping.gschema.xml \
+ org.mate.SettingsDaemon.plugins.keybindings.gschema.xml \
org.mate.SettingsDaemon.plugins.keyboard.gschema.xml \
org.mate.SettingsDaemon.plugins.media-keys.gschema.xml \
org.mate.SettingsDaemon.plugins.mouse.gschema.xml \
diff --git a/data/org.mate.SettingsDaemon.plugins.keybindings.gschema.xml.in b/data/org.mate.SettingsDaemon.plugins.keybindings.gschema.xml.in
new file mode 100644
index 0000000..a371b84
--- /dev/null
+++ b/data/org.mate.SettingsDaemon.plugins.keybindings.gschema.xml.in
@@ -0,0 +1,14 @@
+<schemalist>
+ <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.mate.SettingsDaemon.plugins.keybindings" path="/org/mate/settings-daemon/plugins/keybindings/">
+ <key name="active" type="b">
+ <default>true</default>
+ <_summary>Activation of this plugin</_summary>
+ <_description>Whether this plugin would be activated by mate-settings-daemon or not</_description>
+ </key>
+ <key name="priority" type="i">
+ <default>6</default>
+ <_summary>Priority to use for this plugin</_summary>
+ <_description>Priority to use for this plugin in mate-settings-daemon startup queue</_description>
+ </key>
+ </schema>
+</schemalist>
diff --git a/data/org.mate.keybindings.gschema.xml.in b/data/org.mate.keybindings.gschema.xml.in
index 3ea2ace..7d1b7e3 100644
--- a/data/org.mate.keybindings.gschema.xml.in
+++ b/data/org.mate.keybindings.gschema.xml.in
@@ -1,10 +1,5 @@
<schemalist gettext-domain="@GETTEXT_PACKAGE@">
<schema id="org.mate.keybindings" path="/org/mate/desktop/keybindings/">
- <key name="allowed-keys" type="as">
- <default>[]</default>
- <_summary>Allowed keys</_summary>
- <_description>If non-empty, keybindings will be ignored unless their GSettings directory is in the list. This is useful for lockdown.</_description>
- </key>
<child name="magnifier" schema="org.mate.keybindings.magnifier"/>
<child name="screenreader" schema="org.mate.keybindings.screenreader"/>
<child name="onscreenkeyboard" schema="org.mate.keybindings.onscreenkeyboard"/>
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 4741ba6..6a2a418 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -6,7 +6,8 @@ enabled_plugins = \
clipboard \
datetime \
dummy \
- housekeeping \
+ housekeeping \
+ keybindings \
keyboard \
media-keys \
mouse \
diff --git a/plugins/keybindings/Makefile.am b/plugins/keybindings/Makefile.am
new file mode 100644
index 0000000..4106e22
--- /dev/null
+++ b/plugins/keybindings/Makefile.am
@@ -0,0 +1,55 @@
+NULL =
+
+plugin_LTLIBRARIES = \
+ libkeybindings.la \
+ $(NULL)
+
+libkeybindings_la_SOURCES = \
+ dconf-util.h \
+ dconf-util.c \
+ msd-keybindings-plugin.h \
+ msd-keybindings-plugin.c \
+ msd-keybindings-manager.h \
+ msd-keybindings-manager.c \
+ $(NULL)
+
+libkeybindings_la_CPPFLAGS = \
+ -I$(top_srcdir)/mate-settings-daemon \
+ -I$(top_srcdir)/plugins/common \
+ -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+ $(AM_CPPFLAGS)
+
+libkeybindings_la_CFLAGS = \
+ $(SETTINGS_PLUGIN_CFLAGS) \
+ $(DCONF_CFLAGS) \
+ $(AM_CFLAGS)
+
+libkeybindings_la_LDFLAGS = \
+ $(MSD_PLUGIN_LDFLAGS) \
+ $(NULL)
+
+libkeybindings_la_LIBADD = \
+ $(top_builddir)/plugins/common/libcommon.la \
+ $(SETTINGS_PLUGIN_LIBS) \
+ $(DCONF_LIBS) \
+ $(NULL)
+
+plugin_in_files = \
+ keybindings.mate-settings-plugin.in \
+ $(NULL)
+
+plugin_DATA = $(plugin_in_files:.mate-settings-plugin.in=.mate-settings-plugin)
+
+EXTRA_DIST = \
+ $(plugin_in_files) \
+ $(NULL)
+
+CLEANFILES = \
+ $(plugin_DATA) \
+ $(NULL)
+
+DISTCLEANFILES = \
+ $(plugin_DATA) \
+ $(NULL)
+
+@MSD_INTLTOOL_PLUGIN_RULE@
diff --git a/plugins/keybindings/dconf-util.c b/plugins/keybindings/dconf-util.c
new file mode 100644
index 0000000..4987a34
--- /dev/null
+++ b/plugins/keybindings/dconf-util.c
@@ -0,0 +1,113 @@
+/*
+ * dconf-util.c: helper API for dconf
+ *
+ * Copyright (C) 2012 Stefano Karapetsas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ * Stefano Karapetsas <[email protected]>
+ * Vincent Untz <[email protected]>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <dconf.h>
+
+#include "dconf-util.h"
+
+static DConfClient *
+dconf_util_client_get (void)
+{
+#ifdef HAVE_DCONF_0_13
+ return dconf_client_new ();
+#else
+ return dconf_client_new (NULL, NULL, NULL, NULL);
+#endif
+}
+
+gboolean
+dconf_util_write_sync (const gchar *key,
+ GVariant *value,
+ GError **error)
+{
+ gboolean ret;
+ DConfClient *client = dconf_util_client_get ();
+
+#ifdef HAVE_DCONF_0_13
+ ret = dconf_client_write_sync (client, key, value, NULL, NULL, error);
+#else
+ ret = dconf_client_write (client, key, value, NULL, NULL, error);
+#endif
+
+ g_object_unref (client);
+
+ return ret;
+}
+
+gboolean
+dconf_util_recursive_reset (const gchar *dir,
+ GError **error)
+{
+ gboolean ret;
+ DConfClient *client = dconf_util_client_get ();
+
+#ifdef HAVE_DCONF_0_13
+ ret = dconf_client_write_sync (client, dir, NULL, NULL, NULL, error);
+#else
+ ret = dconf_client_write (client, dir, NULL, NULL, NULL, error);
+#endif
+
+ g_object_unref (client);
+
+ return ret;
+}
+
+gchar **
+dconf_util_list_subdirs (const gchar *dir,
+ gboolean remove_trailing_slash)
+{
+ GArray *array;
+ gchar **children;
+ int len;
+ int i;
+ DConfClient *client = dconf_util_client_get ();
+
+ array = g_array_new (TRUE, TRUE, sizeof (gchar *));
+
+ children = dconf_client_list (client, dir, &len);
+
+ g_object_unref (client);
+
+ for (i = 0; children[i] != NULL; i++) {
+ if (dconf_is_rel_dir (children[i], NULL)) {
+ char *val = g_strdup (children[i]);
+
+ if (remove_trailing_slash)
+ val[strlen (val) - 1] = '\0';
+
+ array = g_array_append_val (array, val);
+ }
+ }
+
+ g_strfreev (children);
+
+ return (gchar **) g_array_free (array, FALSE);
+}
diff --git a/plugins/keybindings/dconf-util.h b/plugins/keybindings/dconf-util.h
new file mode 100644
index 0000000..fe782d9
--- /dev/null
+++ b/plugins/keybindings/dconf-util.h
@@ -0,0 +1,45 @@
+/*
+ * dconf-util.h: helper API for dconf
+ *
+ * Copyright (C) 2012 Stefano Karapetsas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ * Stefano Karapetsas <[email protected]>
+ * Vincent Untz <[email protected]>
+ */
+
+#ifndef __DCONF_UTIL_H__
+#define __DCONF_UTIL_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gboolean dconf_util_write_sync (const gchar *key,
+ GVariant *value,
+ GError **error);
+
+gboolean dconf_util_recursive_reset (const gchar *dir,
+ GError **error);
+
+gchar **dconf_util_list_subdirs (const gchar *dir,
+ gboolean remove_trailing_slash);
+
+G_END_DECLS
+
+#endif /* __DCONF_UTIL_H__ */
diff --git a/plugins/keybindings/keybindings.mate-settings-plugin.in b/plugins/keybindings/keybindings.mate-settings-plugin.in
new file mode 100644
index 0000000..f9c7208
--- /dev/null
+++ b/plugins/keybindings/keybindings.mate-settings-plugin.in
@@ -0,0 +1,8 @@
+[MATE Settings Plugin]
+Module=keybindings
+IAge=0
+_Name=Keybindings
+_Description=Keybindings plugin
+Authors=AUTHOR
+Copyright=Copyright © 2007 AUTHOR
+Website=
diff --git a/plugins/keybindings/msd-keybindings-manager.c b/plugins/keybindings/msd-keybindings-manager.c
new file mode 100644
index 0000000..c554945
--- /dev/null
+++ b/plugins/keybindings/msd-keybindings-manager.c
@@ -0,0 +1,721 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <X11/keysym.h>
+#include <gio/gio.h>
+#include <dconf.h>
+
+#include "mate-settings-profile.h"
+#include "msd-keybindings-manager.h"
+#include "dconf-util.h"
+
+#include "msd-keygrab.h"
+#include "eggaccelerators.h"
+
+#define GSETTINGS_KEYBINDINGS_DIR "/org/mate/desktop/keybindings/"
+#define CUSTOM_KEYBINDING_SCHEMA "org.mate.control-center.keybinding"
+
+#define MSD_KEYBINDINGS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MSD_TYPE_KEYBINDINGS_MANAGER, MsdKeybindingsManagerPrivate))
+
+typedef struct {
+ char *binding_str;
+ char *action;
+ char *settings_path;
+ Key key;
+ Key previous_key;
+} Binding;
+
+struct MsdKeybindingsManagerPrivate
+{
+ DConfClient *client;
+ GSList *binding_list;
+ GSList *screens;
+};
+
+static void msd_keybindings_manager_class_init (MsdKeybindingsManagerClass *klass);
+static void msd_keybindings_manager_init (MsdKeybindingsManager *keybindings_manager);
+static void msd_keybindings_manager_finalize (GObject *object);
+
+G_DEFINE_TYPE (MsdKeybindingsManager, msd_keybindings_manager, G_TYPE_OBJECT)
+
+static gpointer manager_object = NULL;
+
+static GSList *
+get_screens_list (void)
+{
+ GdkDisplay *display = gdk_display_get_default();
+ int n_screens;
+ GSList *list = NULL;
+ int i;
+
+ n_screens = gdk_display_get_n_screens (display);
+
+ if (n_screens == 1) {
+ list = g_slist_append (list, gdk_screen_get_default ());
+ } else {
+ for (i = 0; i < n_screens; i++) {
+ GdkScreen *screen;
+
+ screen = gdk_display_get_screen (display, i);
+ if (screen != NULL) {
+ list = g_slist_prepend (list, screen);
+ }
+ }
+ list = g_slist_reverse (list);
+ }
+
+ return list;
+}
+
+static gboolean
+parse_binding (Binding *binding)
+{
+ gboolean success;
+
+ g_return_val_if_fail (binding != NULL, FALSE);
+
+ binding->key.keysym = 0;
+ binding->key.state = 0;
+ g_free (binding->key.keycodes);
+ binding->key.keycodes = NULL;
+
+ if (binding->binding_str == NULL ||
+ binding->binding_str[0] == '\0' ||
+ g_strcmp0 (binding->binding_str, "Disabled") == 0 ||
+ g_strcmp0 (binding->binding_str, "disabled") == 0 ) {
+ return FALSE;
+ }
+
+ success = egg_accelerator_parse_virtual (binding->binding_str,
+ &binding->key.keysym,
+ &binding->key.keycodes,
+ &binding->key.state);
+
+ if (!success)
+ g_warning (_("Key binding (%s) is invalid"), binding->settings_path);
+
+ return success;
+}
+
+static gint
+compare_bindings (gconstpointer a,
+ gconstpointer b)
+{
+ Binding *key_a = (Binding *) a;
+ char *key_b = (char *) b;
+
+ return g_strcmp0 (key_b, key_a->settings_path);
+}
+
+static gboolean
+bindings_get_entry (MsdKeybindingsManager *manager,
+ const char *settings_path)
+{
+ GSettings *settings;
+ Binding *new_binding;
+ GSList *tmp_elem;
+ char *action = NULL;
+ char *key = NULL;
+
+ if (!settings_path) {
+ return FALSE;
+ }
+
+ /* Get entries for this binding */
+ settings = g_settings_new_with_path (CUSTOM_KEYBINDING_SCHEMA, settings_path);
+ action = g_settings_get_string (settings, "action");
+ key = g_settings_get_string (settings, "binding");
+ g_object_unref (settings);
+
+ if (!action || !key) {
+ g_warning (_("Key binding (%s) is incomplete"), settings_path);
+ g_free (action);
+ g_free (key);
+ return FALSE;
+ }
+
+ g_debug ("keybindings: get entries from '%s' (action: '%s', key: '%s')", settings_path, action, key);
+
+ tmp_elem = g_slist_find_custom (manager->priv->binding_list,
+ settings_path,
+ compare_bindings);
+
+ if (!tmp_elem) {
+ new_binding = g_new0 (Binding, 1);
+ } else {
+ new_binding = (Binding *) tmp_elem->data;
+ g_free (new_binding->binding_str);
+ g_free (new_binding->action);
+ g_free (new_binding->settings_path);
+
+ new_binding->previous_key.keysym = new_binding->key.keysym;
+ new_binding->previous_key.state = new_binding->key.state;
+ new_binding->previous_key.keycodes = new_binding->key.keycodes;
+ new_binding->key.keycodes = NULL;
+ }
+
+ new_binding->binding_str = key;
+ new_binding->action = action;
+ new_binding->settings_path = g_strdup (settings_path);
+
+ if (parse_binding (new_binding)) {
+ if (!tmp_elem)
+ manager->priv->binding_list = g_slist_prepend (manager->priv->binding_list, new_binding);
+ } else {
+ g_free (new_binding->binding_str);
+ g_free (new_binding->action);
+ g_free (new_binding->settings_path);
+ g_free (new_binding->previous_key.keycodes);
+ g_free (new_binding);
+
+ if (tmp_elem)
+ manager->priv->binding_list = g_slist_delete_link (manager->priv->binding_list, tmp_elem);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+bindings_clear (MsdKeybindingsManager *manager)
+{
+ MsdKeybindingsManagerPrivate *p = manager->priv;
+ GSList *l;
+
+ if (p->binding_list != NULL)
+ {
+ for (l = p->binding_list; l; l = l->next) {
+ Binding *b = l->data;
+ g_free (b->binding_str);
+ g_free (b->action);
+ g_free (b->settings_path);
+ g_free (b->previous_key.keycodes);
+ g_free (b->key.keycodes);
+ g_free (b);
+ }
+ g_slist_free (p->binding_list);
+ p->binding_list = NULL;
+ }
+}
+
+static void
+bindings_get_entries (MsdKeybindingsManager *manager)
+{
+ gchar **custom_list = NULL;
+ gint i;
+
+ bindings_clear (manager);
+
+ custom_list = dconf_util_list_subdirs (GSETTINGS_KEYBINDINGS_DIR, FALSE);
+
+ if (custom_list != NULL)
+ {
+ for (i = 0; custom_list[i] != NULL; i++)
+ {
+ gchar *settings_path;
+ settings_path = g_strdup_printf("%s%s", GSETTINGS_KEYBINDINGS_DIR, custom_list[i]);
+ bindings_get_entry (manager, settings_path);
+ g_free (settings_path);
+ }
+ g_strfreev (custom_list);
+ }
+
+}
+
+static gboolean
+same_keycode (const Key *key, const Key *other)
+{
+ if (key->keycodes != NULL && other->keycodes != NULL) {
+ guint *c;
+
+ for (c = key->keycodes; *c; ++c) {
+ if (key_uses_keycode (other, *c))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static gboolean
+same_key (const Key *key, const Key *other)
+{
+ if (key->state == other->state) {
+ if (key->keycodes != NULL && other->keycodes != NULL) {
+ guint *c1, *c2;
+
+ for (c1 = key->keycodes, c2 = other->keycodes;
+ *c1 || *c2; ++c1, ++c2) {
+ if (*c1 != *c2)
+ return FALSE;
+ }
+ } else if (key->keycodes != NULL || other->keycodes != NULL)
+ return FALSE;
+
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+key_already_used (MsdKeybindingsManager *manager,
+ Binding *binding)
+{
+ GSList *li;
+
+ for (li = manager->priv->binding_list; li != NULL; li = li->next) {
+ Binding *tmp_binding = (Binding*) li->data;
+
+ if (tmp_binding != binding &&
+ same_keycode (&tmp_binding->key, &binding->key) &&
+ tmp_binding->key.state == binding->key.state) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+binding_unregister_keys (MsdKeybindingsManager *manager)
+{
+ GSList *li;
+ gboolean need_flush = FALSE;
+
+ gdk_error_trap_push ();
+
+ for (li = manager->priv->binding_list; li != NULL; li = li->next) {
+ Binding *binding = (Binding *) li->data;
+
+ if (binding->key.keycodes) {
+ need_flush = TRUE;
+ grab_key_unsafe (&binding->key, FALSE, manager->priv->screens);
+ }
+ }
+
+ if (need_flush)
+ gdk_flush ();
+ gdk_error_trap_pop ();
+}
+
+static void
+binding_register_keys (MsdKeybindingsManager *manager)
+{
+ GSList *li;
+ gboolean need_flush = FALSE;
+
+ gdk_error_trap_push ();
+
+ /* Now check for changes and grab new key if not already used */
+ for (li = manager->priv->binding_list; li != NULL; li = li->next) {
+ Binding *binding = (Binding *) li->data;
+
+ if (!same_key (&binding->previous_key, &binding->key)) {
+ /* Ungrab key if it changed and not clashing with previously set binding */
+ if (!key_already_used (manager, binding)) {
+ gint i;
+
+ need_flush = TRUE;
+ if (binding->previous_key.keycodes) {
+ grab_key_unsafe (&binding->previous_key, FALSE, manager->priv->screens);
+ }
+ grab_key_unsafe (&binding->key, TRUE, manager->priv->screens);
+
+ binding->previous_key.keysym = binding->key.keysym;
+ binding->previous_key.state = binding->key.state;
+ g_free (binding->previous_key.keycodes);
+ for (i = 0; binding->key.keycodes[i]; ++i);
+ binding->previous_key.keycodes = g_new0 (guint, i);
+ for (i = 0; binding->key.keycodes[i]; ++i)
+ binding->previous_key.keycodes[i] = binding->key.keycodes[i];
+ } else
+ g_warning ("Key binding (%s) is already in use", binding->binding_str);
+ }
+ }
+
+ if (need_flush)
+ gdk_flush ();
+ if (gdk_error_trap_pop ())
+ g_warning ("Grab failed for some keys, another application may already have access the them.");
+
+}
+
+extern char **environ;
+
+static char *
+screen_exec_display_string (GdkScreen *screen)
+{
+ GString *str;
+ const char *old_display;
+ char *p;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+ old_display = gdk_display_get_name (gdk_screen_get_display (screen));
+
+ str = g_string_new ("DISPLAY=");
+ g_string_append (str, old_display);
+
+ p = strrchr (str->str, '.');
+ if (p && p > strchr (str->str, ':')) {
+ g_string_truncate (str, p - str->str);
+ }
+
+ g_string_append_printf (str, ".%d", gdk_screen_get_number (screen));
+
+ return g_string_free (str, FALSE);
+}
+
+/**
+ * get_exec_environment:
+ *
+ * Description: Modifies the current program environment to
+ * ensure that $DISPLAY is set such that a launched application
+ * inheriting this environment would appear on screen.
+ *
+ * Returns: a newly-allocated %NULL-terminated array of strings or
+ * %NULL on error. Use g_strfreev() to free it.
+ *
+ * mainly ripped from egg_screen_exec_display_string in
+ * mate-panel/egg-screen-exec.c
+ **/
+static char **
+get_exec_environment (XEvent *xevent)
+{
+ char **retval = NULL;
+ int i;
+ int display_index = -1;
+ GdkScreen *screen = NULL;
+ GdkWindow *window = gdk_xid_table_lookup (xevent->xkey.root);
+
+ if (window) {
+ screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
+ }
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+ for (i = 0; environ [i]; i++) {
+ if (!strncmp (environ [i], "DISPLAY", 7)) {
+ display_index = i;
+ }
+ }
+
+ if (display_index == -1) {
+ display_index = i++;
+ }
+
+ retval = g_new (char *, i + 1);
+
+ for (i = 0; environ [i]; i++) {
+ if (i == display_index) {
+ retval [i] = screen_exec_display_string (screen);
+ } else {
+ retval [i] = g_strdup (environ [i]);
+ }
+ }
+
+ retval [i] = NULL;
+
+ return retval;
+}
+
+static GdkFilterReturn
+keybindings_filter (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ MsdKeybindingsManager *manager)
+{
+ XEvent *xevent = (XEvent *) gdk_xevent;
+ GSList *li;
+
+ if (xevent->type != KeyPress) {
+ return GDK_FILTER_CONTINUE;
+ }
+
+ for (li = manager->priv->binding_list; li != NULL; li = li->next) {
+ Binding *binding = (Binding *) li->data;
+
+ if (match_key (&binding->key, xevent)) {
+ GError *error = NULL;
+ gboolean retval;
+ gchar **argv = NULL;
+ gchar **envp = NULL;
+
+ g_return_val_if_fail (binding->action != NULL, GDK_FILTER_CONTINUE);
+
+ if (!g_shell_parse_argv (binding->action,
+ NULL, &argv,
+ &error)) {
+ return GDK_FILTER_CONTINUE;
+ }
+
+ envp = get_exec_environment (xevent);
+
+ retval = g_spawn_async (NULL,
+ argv,
+ envp,
+ G_SPAWN_SEARCH_PATH,
+ NULL,
+ NULL,
+ NULL,
+ &error);
+ g_strfreev (argv);
+ g_strfreev (envp);
+
+ if (!retval) {
+ GtkWidget *dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE,
+ _("Error while trying to run (%s)\n"\
+ "which is linked to the key (%s)"),
+ binding->action,
+ binding->binding_str);
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+ gtk_widget_show (dialog);
+ }
+ return GDK_FILTER_REMOVE;
+ }
+ }
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+bindings_callback (DConfClient *client,
+ #ifdef HAVE_DCONF_0_13
+ gchar *prefix,
+ GStrv changes,
+ #else
+ const gchar *path,
+ const gchar * const *items,
+ gint n_items,
+ #endif
+ gchar *tag,
+ MsdKeybindingsManager *manager)
+{
+ g_debug ("keybindings: received 'changed' signal from dconf");
+
+ binding_unregister_keys (manager);
+
+ bindings_get_entries (manager);
+
+ binding_register_keys (manager);
+}
+
+gboolean
+msd_keybindings_manager_start (MsdKeybindingsManager *manager,
+ GError **error)
+{
+ GdkDisplay *dpy;
+ GdkScreen *screen;
+ int screen_num;
+ int i;
+
+ g_debug ("Starting keybindings manager");
+ mate_settings_profile_start (NULL);
+
+ dpy = gdk_display_get_default ();
+ screen_num = gdk_display_get_n_screens (dpy);
+
+ for (i = 0; i < screen_num; i++) {
+ screen = gdk_display_get_screen (dpy, i);
+ gdk_window_add_filter (gdk_screen_get_root_window (screen),
+ (GdkFilterFunc) keybindings_filter,
+ manager);
+ }
+ manager->priv->screens = get_screens_list ();
+
+ manager->priv->binding_list = NULL;
+ bindings_get_entries (manager);
+ binding_register_keys (manager);
+
+ /* DConf has different API between versions:
+ * http://developer.gnome.org/dconf/0.12/DConfClient.html
+ * http://developer.gnome.org/dconf/0.14/DConfClient.html
+ */
+ #ifdef HAVE_DCONF_0_13
+ manager->priv->client = dconf_client_new ();
+ dconf_client_watch_fast (manager->priv->client, GSETTINGS_KEYBINDINGS_DIR);
+ g_signal_connect (manager->priv->client, "changed", G_CALLBACK (bindings_callback), manager);
+ #else
+ manager->priv->client = dconf_client_new (NULL, (DConfWatchFunc) bindings_callback, manager, NULL);
+ dconf_client_watch (manager->priv->client, GSETTINGS_KEYBINDINGS_DIR, NULL, NULL);
+ #endif
+
+ mate_settings_profile_end (NULL);
+
+ return TRUE;
+}
+
+void
+msd_keybindings_manager_stop (MsdKeybindingsManager *manager)
+{
+ MsdKeybindingsManagerPrivate *p = manager->priv;
+ GSList *l;
+
+ g_debug ("Stopping keybindings manager");
+
+ if (p->client != NULL) {
+ g_object_unref (p->client);
+ p->client = NULL;
+ }
+
+ for (l = p->screens; l; l = l->next) {
+ GdkScreen *screen = l->data;
+ gdk_window_remove_filter (gdk_screen_get_root_window (screen),
+ (GdkFilterFunc) keybindings_filter,
+ manager);
+ }
+
+ binding_unregister_keys (manager);
+ bindings_clear (manager);
+
+ g_slist_free (p->screens);
+ p->screens = NULL;
+}
+
+static void
+msd_keybindings_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MsdKeybindingsManager *self;
+
+ self = MSD_KEYBINDINGS_MANAGER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+msd_keybindings_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MsdKeybindingsManager *self;
+
+ self = MSD_KEYBINDINGS_MANAGER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+msd_keybindings_manager_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ MsdKeybindingsManager *keybindings_manager;
+ MsdKeybindingsManagerClass *klass;
+
+ klass = MSD_KEYBINDINGS_MANAGER_CLASS (g_type_class_peek (MSD_TYPE_KEYBINDINGS_MANAGER));
+
+ keybindings_manager = MSD_KEYBINDINGS_MANAGER (G_OBJECT_CLASS (msd_keybindings_manager_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ return G_OBJECT (keybindings_manager);
+}
+
+static void
+msd_keybindings_manager_dispose (GObject *object)
+{
+ MsdKeybindingsManager *keybindings_manager;
+
+ keybindings_manager = MSD_KEYBINDINGS_MANAGER (object);
+
+ G_OBJECT_CLASS (msd_keybindings_manager_parent_class)->dispose (object);
+}
+
+static void
+msd_keybindings_manager_class_init (MsdKeybindingsManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = msd_keybindings_manager_get_property;
+ object_class->set_property = msd_keybindings_manager_set_property;
+ object_class->constructor = msd_keybindings_manager_constructor;
+ object_class->dispose = msd_keybindings_manager_dispose;
+ object_class->finalize = msd_keybindings_manager_finalize;
+
+ g_type_class_add_private (klass, sizeof (MsdKeybindingsManagerPrivate));
+}
+
+static void
+msd_keybindings_manager_init (MsdKeybindingsManager *manager)
+{
+ manager->priv = MSD_KEYBINDINGS_MANAGER_GET_PRIVATE (manager);
+
+}
+
+static void
+msd_keybindings_manager_finalize (GObject *object)
+{
+ MsdKeybindingsManager *keybindings_manager;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (MSD_IS_KEYBINDINGS_MANAGER (object));
+
+ keybindings_manager = MSD_KEYBINDINGS_MANAGER (object);
+
+ g_return_if_fail (keybindings_manager->priv != NULL);
+
+ G_OBJECT_CLASS (msd_keybindings_manager_parent_class)->finalize (object);
+}
+
+MsdKeybindingsManager *
+msd_keybindings_manager_new (void)
+{
+ if (manager_object != NULL) {
+ g_object_ref (manager_object);
+ } else {
+ manager_object = g_object_new (MSD_TYPE_KEYBINDINGS_MANAGER, NULL);
+ g_object_add_weak_pointer (manager_object,
+ (gpointer *) &manager_object);
+ }
+
+ return MSD_KEYBINDINGS_MANAGER (manager_object);
+}
diff --git a/plugins/keybindings/msd-keybindings-manager.h b/plugins/keybindings/msd-keybindings-manager.h
new file mode 100644
index 0000000..95b1bed
--- /dev/null
+++ b/plugins/keybindings/msd-keybindings-manager.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __MSD_KEYBINDINGS_MANAGER_H
+#define __MSD_KEYBINDINGS_MANAGER_H
+
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MSD_TYPE_KEYBINDINGS_MANAGER (msd_keybindings_manager_get_type ())
+#define MSD_KEYBINDINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MSD_TYPE_KEYBINDINGS_MANAGER, MsdKeybindingsManager))
+#define MSD_KEYBINDINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MSD_TYPE_KEYBINDINGS_MANAGER, MsdKeybindingsManagerClass))
+#define MSD_IS_KEYBINDINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MSD_TYPE_KEYBINDINGS_MANAGER))
+#define MSD_IS_KEYBINDINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MSD_TYPE_KEYBINDINGS_MANAGER))
+#define MSD_KEYBINDINGS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MSD_TYPE_KEYBINDINGS_MANAGER, MsdKeybindingsManagerClass))
+
+typedef struct MsdKeybindingsManagerPrivate MsdKeybindingsManagerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ MsdKeybindingsManagerPrivate *priv;
+} MsdKeybindingsManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} MsdKeybindingsManagerClass;
+
+GType msd_keybindings_manager_get_type (void);
+
+MsdKeybindingsManager * msd_keybindings_manager_new (void);
+gboolean msd_keybindings_manager_start (MsdKeybindingsManager *manager,
+ GError **error);
+void msd_keybindings_manager_stop (MsdKeybindingsManager *manager);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MSD_KEYBINDINGS_MANAGER_H */
diff --git a/plugins/keybindings/msd-keybindings-plugin.c b/plugins/keybindings/msd-keybindings-plugin.c
new file mode 100644
index 0000000..68b86d3
--- /dev/null
+++ b/plugins/keybindings/msd-keybindings-plugin.c
@@ -0,0 +1,109 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include "mate-settings-plugin.h"
+#include "msd-keybindings-plugin.h"
+#include "msd-keybindings-manager.h"
+
+struct MsdKeybindingsPluginPrivate {
+ MsdKeybindingsManager *manager;
+};
+
+#define MSD_KEYBINDINGS_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), MSD_TYPE_KEYBINDINGS_PLUGIN, MsdKeybindingsPluginPrivate))
+
+MATE_SETTINGS_PLUGIN_REGISTER (MsdKeybindingsPlugin, msd_keybindings_plugin)
+
+static void
+msd_keybindings_plugin_init (MsdKeybindingsPlugin *plugin)
+{
+ plugin->priv = MSD_KEYBINDINGS_PLUGIN_GET_PRIVATE (plugin);
+
+ g_debug ("MsdKeybindingsPlugin initializing");
+
+ plugin->priv->manager = msd_keybindings_manager_new ();
+}
+
+static void
+msd_keybindings_plugin_finalize (GObject *object)
+{
+ MsdKeybindingsPlugin *plugin;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (MSD_IS_KEYBINDINGS_PLUGIN (object));
+
+ g_debug ("MsdKeybindingsPlugin finalizing");
+
+ plugin = MSD_KEYBINDINGS_PLUGIN (object);
+
+ g_return_if_fail (plugin->priv != NULL);
+
+ if (plugin->priv->manager != NULL) {
+ g_object_unref (plugin->priv->manager);
+ }
+
+ G_OBJECT_CLASS (msd_keybindings_plugin_parent_class)->finalize (object);
+}
+
+static void
+impl_activate (MateSettingsPlugin *plugin)
+{
+ gboolean res;
+ GError *error;
+
+ g_debug ("Activating keybindings plugin");
+
+ error = NULL;
+ res = msd_keybindings_manager_start (MSD_KEYBINDINGS_PLUGIN (plugin)->priv->manager, &error);
+ if (! res) {
+ g_warning ("Unable to start keybindings manager: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+impl_deactivate (MateSettingsPlugin *plugin)
+{
+ g_debug ("Deactivating keybindings plugin");
+ msd_keybindings_manager_stop (MSD_KEYBINDINGS_PLUGIN (plugin)->priv->manager);
+}
+
+static void
+msd_keybindings_plugin_class_init (MsdKeybindingsPluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MateSettingsPluginClass *plugin_class = MATE_SETTINGS_PLUGIN_CLASS (klass);
+
+ object_class->finalize = msd_keybindings_plugin_finalize;
+
+ plugin_class->activate = impl_activate;
+ plugin_class->deactivate = impl_deactivate;
+
+ g_type_class_add_private (klass, sizeof (MsdKeybindingsPluginPrivate));
+}
+
+static void
+msd_keybindings_plugin_class_finalize (MsdKeybindingsPluginClass *klass)
+{
+} \ No newline at end of file
diff --git a/plugins/keybindings/msd-keybindings-plugin.h b/plugins/keybindings/msd-keybindings-plugin.h
new file mode 100644
index 0000000..f45d0f8
--- /dev/null
+++ b/plugins/keybindings/msd-keybindings-plugin.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __MSD_KEYBINDINGS_PLUGIN_H__
+#define __MSD_KEYBINDINGS_PLUGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gmodule.h>
+
+#include "mate-settings-plugin.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MSD_TYPE_KEYBINDINGS_PLUGIN (msd_keybindings_plugin_get_type ())
+#define MSD_KEYBINDINGS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MSD_TYPE_KEYBINDINGS_PLUGIN, MsdKeybindingsPlugin))
+#define MSD_KEYBINDINGS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MSD_TYPE_KEYBINDINGS_PLUGIN, MsdKeybindingsPluginClass))
+#define MSD_IS_KEYBINDINGS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MSD_TYPE_KEYBINDINGS_PLUGIN))
+#define MSD_IS_KEYBINDINGS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MSD_TYPE_KEYBINDINGS_PLUGIN))
+#define MSD_KEYBINDINGS_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MSD_TYPE_KEYBINDINGS_PLUGIN, MsdKeybindingsPluginClass))
+
+typedef struct MsdKeybindingsPluginPrivate MsdKeybindingsPluginPrivate;
+
+typedef struct
+{
+ MateSettingsPlugin parent;
+ MsdKeybindingsPluginPrivate *priv;
+} MsdKeybindingsPlugin;
+
+typedef struct
+{
+ MateSettingsPluginClass parent_class;
+} MsdKeybindingsPluginClass;
+
+GType msd_keybindings_plugin_get_type (void) G_GNUC_CONST;
+
+/* All the plugins must implement this function */
+G_MODULE_EXPORT GType register_mate_settings_plugin (GTypeModule *module);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MSD_KEYBINDINGS_PLUGIN_H__ */