[gnome-flashback/wip/key-grabber: 2/2] libkey-grabber: initial version
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback/wip/key-grabber: 2/2] libkey-grabber: initial version
- Date: Sun, 2 Nov 2014 13:06:07 +0000 (UTC)
commit ffdd2d9853685b7167f9208d1a4153081ddef888
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Sun Nov 2 15:05:10 2014 +0200
libkey-grabber: initial version
configure.ac | 5 +
data/org.gnome.gnome-flashback.gschema.xml.in.in | 5 +
gnome-flashback/Makefile.am | 2 +
gnome-flashback/flashback-application.c | 14 +
gnome-flashback/libkey-grabber/Makefile.am | 38 +++
.../libkey-grabber/flashback-key-bindings.c | 298 ++++++++++++++++++
.../libkey-grabber/flashback-key-bindings.h | 61 ++++
.../libkey-grabber/flashback-key-grabber.c | 319 ++++++++++++++++++++
.../libkey-grabber/flashback-key-grabber.h | 51 +++
.../libkey-grabber/org.gnome.KeyGrabber.xml | 23 ++
10 files changed, 816 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 6f21bcd..e0acd12 100644
--- a/configure.ac
+++ b/configure.ac
@@ -57,6 +57,10 @@ PKG_CHECK_MODULES(IDLE_MONITOR, gtk+-3.0 >= $GTK_REQUIRED x11 xext)
AC_SUBST(IDLE_MONITOR_CFLAGS)
AC_SUBST(IDLE_MONITOR_LIBS)
+PKG_CHECK_MODULES(KEY_GRABBER, gtk+-3.0 >= $GTK_REQUIRED x11)
+AC_SUBST(KEY_GRABBER_CFLAGS)
+AC_SUBST(KEY_GRABBER_LIBS)
+
PKG_CHECK_MODULES(GVC, gobject-2.0 libpulse libpulse-mainloop-glib)
AM_CONDITIONAL(HAVE_INTROSPECTION, false)
@@ -73,6 +77,7 @@ gnome-flashback/libdesktop-background/Makefile
gnome-flashback/libdisplay-config/Makefile
gnome-flashback/libend-session-dialog/Makefile
gnome-flashback/libidle-monitor/Makefile
+gnome-flashback/libkey-grabber/Makefile
gnome-flashback/libsound-applet/Makefile
gnome-flashback/libsound-applet/gvc/Makefile
po/Makefile.in
diff --git a/data/org.gnome.gnome-flashback.gschema.xml.in.in
b/data/org.gnome.gnome-flashback.gschema.xml.in.in
index 5c766a2..9e91388 100644
--- a/data/org.gnome.gnome-flashback.gschema.xml.in.in
+++ b/data/org.gnome.gnome-flashback.gschema.xml.in.in
@@ -25,6 +25,11 @@
<_summary>Idle monitor</_summary>
<_description>If set to true, then GNOME Flashback application will be used for user
activity monitoring.</_description>
</key>
+ <key name="key-grabber" type="b">
+ <default>true</default>
+ <_summary>Key grabber</_summary>
+ <_description>If set to true, then GNOME Flashback application will be used for key
grabbing.</_description>
+ </key>
<key name="sound-applet" type="b">
<default>true</default>
<_summary>Sound applet</_summary>
diff --git a/gnome-flashback/Makefile.am b/gnome-flashback/Makefile.am
index 3a10388..b250193 100644
--- a/gnome-flashback/Makefile.am
+++ b/gnome-flashback/Makefile.am
@@ -4,6 +4,7 @@ SUBDIRS = \
libdisplay-config \
libend-session-dialog \
libidle-monitor \
+ libkey-grabber \
libsound-applet
bin_PROGRAMS = \
@@ -28,6 +29,7 @@ gnome_flashback_LDADD = \
$(top_builddir)/gnome-flashback/libdisplay-config/libdisplay-config.la \
$(top_builddir)/gnome-flashback/libend-session-dialog/libend-session-dialog.la \
$(top_builddir)/gnome-flashback/libidle-monitor/libidle-monitor.la \
+ $(top_builddir)/gnome-flashback/libkey-grabber/libkey-grabber.la \
$(top_builddir)/gnome-flashback/libsound-applet/libsound-applet.la
-include $(top_srcdir)/git.mk
diff --git a/gnome-flashback/flashback-application.c b/gnome-flashback/flashback-application.c
index 3153128..214c0ca 100644
--- a/gnome-flashback/flashback-application.c
+++ b/gnome-flashback/flashback-application.c
@@ -24,6 +24,7 @@
#include "libdisplay-config/flashback-display-config.h"
#include "libend-session-dialog/flashback-end-session-dialog.h"
#include "libidle-monitor/meta-idle-monitor-dbus.h"
+#include "libkey-grabber/flashback-key-grabber.h"
#include "libsound-applet/gvc-applet.h"
#define FLASHBACK_SCHEMA "org.gnome.gnome-flashback"
@@ -31,6 +32,7 @@
#define KEY_DESKTOP_BACKGROUND "desktop-background"
#define KEY_DISPLAY_CONFIG "display-config"
#define KEY_END_SESSION_DIALOG "end-session-dialog"
+#define KEY_KEY_GRABBER "key-grabber"
#define KEY_IDLE_MONITOR "idle-monitor"
#define KEY_SOUND_APPLET "sound-applet"
@@ -40,6 +42,7 @@ struct _FlashbackApplicationPrivate {
DesktopBackground *background;
FlashbackDisplayConfig *config;
FlashbackEndSessionDialog *dialog;
+ FlashbackKeyGrabber *grabber;
MetaIdleMonitorDBus *idle_monitor;
GvcApplet *applet;
};
@@ -106,6 +109,16 @@ flashback_application_settings_changed (GSettings *settings,
}
}
+ if (key == NULL || g_strcmp0 (key, KEY_KEY_GRABBER) == 0) {
+ if (g_settings_get_boolean (settings, KEY_KEY_GRABBER)) {
+ if (app->priv->grabber == NULL) {
+ app->priv->grabber = flashback_key_grabber_new ();
+ }
+ } else {
+ g_clear_object (&app->priv->grabber);
+ }
+ }
+
if (key == NULL || g_strcmp0 (key, KEY_SOUND_APPLET) == 0) {
if (g_settings_get_boolean (settings, KEY_SOUND_APPLET)) {
if (app->priv->applet == NULL) {
@@ -126,6 +139,7 @@ flashback_application_finalize (GObject *object)
g_clear_object (&app->priv->config);
g_clear_object (&app->priv->dialog);
g_clear_object (&app->priv->idle_monitor);
+ g_clear_object (&app->priv->grabber);
g_clear_object (&app->priv->applet);
g_clear_object (&app->priv->settings);
diff --git a/gnome-flashback/libkey-grabber/Makefile.am b/gnome-flashback/libkey-grabber/Makefile.am
new file mode 100644
index 0000000..5f59776
--- /dev/null
+++ b/gnome-flashback/libkey-grabber/Makefile.am
@@ -0,0 +1,38 @@
+noinst_LTLIBRARIES = \
+ libkey-grabber.la
+
+AM_CPPFLAGS = \
+ $(KEY_GRABBER_CFLAGS) \
+ -I$(top_builddir)/gnome-flashback/libkey-grabber
+
+libkey_grabber_la_SOURCES = \
+ dbus-key-grabber.c \
+ dbus-key-grabber.h \
+ flashback-key-grabber.c \
+ flashback-key-grabber.h \
+ flashback-key-bindings.c \
+ flashback-key-bindings.h
+
+libkey_grabber_la_LIBADD = \
+ $(KEY_GRABBER_LIBS)
+
+dbus-key-grabber.h:
+dbus-key-grabber.c: org.gnome.KeyGrabber.xml
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix org.gnome. \
+ --c-namespace DBus \
+ --generate-c-code dbus-key-grabber \
+ --c-generate-object-manager \
+ $(srcdir)/org.gnome.KeyGrabber.xml
+
+BUILT_SOURCES = \
+ dbus-key-grabber.c \
+ dbus-key-grabber.h
+
+EXTRA_DIST = \
+ org.gnome.KeyGrabber.xml
+
+CLEANFILES = \
+ $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/gnome-flashback/libkey-grabber/flashback-key-bindings.c
b/gnome-flashback/libkey-grabber/flashback-key-bindings.c
new file mode 100644
index 0000000..41f59d7
--- /dev/null
+++ b/gnome-flashback/libkey-grabber/flashback-key-bindings.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2014 Alberts Muktupāvels
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkx.h>
+
+#include <X11/Xlib.h>
+
+#include "flashback-key-bindings.h"
+
+struct _FlashbackKeyBindingsPrivate {
+ GHashTable *table;
+
+ Display *xdisplay;
+ Window xwindow;
+
+ guint ignored_modifier_mask;
+};
+
+enum {
+ BINDING_ACTIVATED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+typedef struct {
+ const gchar *name;
+ guint action;
+ guint keyval;
+ guint keycode;
+ guint modifiers;
+} KeyBinding;
+
+static guint MetaMask = 0;
+static guint SuperMask = 0;
+static guint HyperMask = 0;
+static guint NumLockMask = 0;
+static guint ScrollLockMask = 0;
+
+G_DEFINE_TYPE_WITH_PRIVATE (FlashbackKeyBindings, flashback_key_bindings, G_TYPE_OBJECT)
+
+static guint
+get_real_modifiers (GdkModifierType modifiers)
+{
+ guint mods = 0;
+
+ if (modifiers & GDK_SHIFT_MASK)
+ mods |= ShiftMask;
+ if (modifiers & GDK_CONTROL_MASK)
+ mods |= ControlMask;
+ if (modifiers & GDK_MOD1_MASK)
+ mods |= Mod1Mask;
+ if (modifiers & GDK_META_MASK)
+ mods |= MetaMask;
+ if (modifiers & GDK_HYPER_MASK)
+ mods |= HyperMask;
+ if (modifiers & GDK_SUPER_MASK)
+ mods |= SuperMask;
+ if (modifiers & GDK_MOD2_MASK)
+ mods |= Mod2Mask;
+ if (modifiers & GDK_MOD3_MASK)
+ mods |= Mod3Mask;
+ if (modifiers & GDK_MOD4_MASK)
+ mods |= Mod4Mask;
+ if (modifiers & GDK_MOD5_MASK)
+ mods |= Mod5Mask;
+
+ return mods;
+}
+
+static GdkFilterReturn
+filter_func (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ FlashbackKeyBindings *bindings;
+ XEvent *ev;
+
+ bindings = FLASHBACK_KEY_BINDINGS (user_data);
+ ev = xevent;
+
+ XAllowEvents (bindings->priv->xdisplay, AsyncKeyboard, ev->xkey.time);
+
+ if (ev->type == KeyPress) {
+ GList *values, *l;
+
+ values = g_hash_table_get_values (bindings->priv->table);
+
+ for (l = values; l; l = l->next) {
+ KeyBinding *binding = l->data;
+
+ if (binding->keycode == ev->xkey.keycode &&
+ binding->modifiers == (ev->xkey.state & 0xff &
~(bindings->priv->ignored_modifier_mask))) {
+ g_signal_emit (bindings, signals[BINDING_ACTIVATED], 0,
+ binding->action, 0, 0);
+ break;
+ }
+ }
+
+ g_list_free (values);
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+flashback_key_bindings_change_keygrab (FlashbackKeyBindings *bindings,
+ gboolean grab,
+ gint keyval,
+ guint keycode,
+ guint modifiers)
+{
+ guint ignored_mask;
+
+ gdk_error_trap_push ();
+
+ ignored_mask = 0;
+ while (ignored_mask <= bindings->priv->ignored_modifier_mask) {
+ if (ignored_mask & ~(bindings->priv->ignored_modifier_mask)) {
+ ++ignored_mask;
+ continue;
+ }
+
+ if (grab)
+ XGrabKey (bindings->priv->xdisplay, keycode,
+ modifiers | ignored_mask,
+ bindings->priv->xwindow,
+ True,
+ GrabModeAsync, GrabModeSync);
+ else
+ XUngrabKey (bindings->priv->xdisplay, keycode,
+ modifiers | ignored_mask,
+ bindings->priv->xwindow);
+
+ ++ignored_mask;
+ }
+
+ gdk_error_trap_pop_ignored ();
+}
+
+static void
+flashback_key_bindings_finalize (GObject *object)
+{
+ FlashbackKeyBindings *bindings;
+
+ bindings = FLASHBACK_KEY_BINDINGS (object);
+
+ gdk_window_remove_filter (NULL, filter_func, bindings);
+
+ if (bindings->priv->table) {
+ g_hash_table_destroy (bindings->priv->table);
+ bindings->priv->table = NULL;
+ }
+
+ G_OBJECT_CLASS (flashback_key_bindings_parent_class)->finalize (object);
+}
+
+static void
+flashback_key_bindings_init (FlashbackKeyBindings *bindings)
+{
+ FlashbackKeyBindingsPrivate *priv;
+
+ bindings->priv = flashback_key_bindings_get_instance_private (bindings);
+ priv = bindings->priv;
+
+ priv->xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ priv->xwindow = XDefaultRootWindow (priv->xdisplay);
+ priv->table = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+
+ MetaMask = XkbKeysymToModifiers (priv->xdisplay, XK_Meta_L);
+ if (MetaMask == 0)
+ MetaMask = XkbKeysymToModifiers (priv->xdisplay, XK_Meta_R);
+
+ SuperMask = XkbKeysymToModifiers (priv->xdisplay, XK_Super_L);
+ if (SuperMask == 0)
+ SuperMask = XkbKeysymToModifiers (priv->xdisplay, XK_Super_R);
+
+ HyperMask = XkbKeysymToModifiers (priv->xdisplay, XK_Hyper_L);
+ if (HyperMask == 0)
+ HyperMask = XkbKeysymToModifiers (priv->xdisplay, XK_Hyper_R);
+
+ NumLockMask = XkbKeysymToModifiers (priv->xdisplay, XK_Num_Lock);
+ ScrollLockMask = XkbKeysymToModifiers (priv->xdisplay, XK_Scroll_Lock);
+
+ priv->ignored_modifier_mask = NumLockMask | ScrollLockMask | LockMask;
+
+ gdk_window_add_filter (NULL, filter_func, bindings);
+}
+
+static void
+flashback_key_bindings_class_init (FlashbackKeyBindingsClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = flashback_key_bindings_finalize;
+
+ signals[BINDING_ACTIVATED] =
+ g_signal_new ("binding-activated",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (FlashbackKeyBindingsClass, binding_activated),
+ NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 3,
+ G_TYPE_UINT,
+ G_TYPE_UINT,
+ G_TYPE_UINT);
+}
+
+FlashbackKeyBindings *
+flashback_key_bindings_new (void)
+{
+ return g_object_new (FLASHBACK_TYPE_KEY_BINDINGS, NULL);
+}
+
+guint
+flashback_key_bindings_grab (FlashbackKeyBindings *bindings,
+ const gchar *accelerator)
+{
+ KeyBinding *binding;
+ guint keyval;
+ GdkModifierType modifiers;
+ guint real_modifiers;
+ guint keycode;
+ static next_action = 0;
+
+ gtk_accelerator_parse (accelerator, &keyval, &modifiers);
+ if (!gtk_accelerator_valid (keyval, modifiers)) {
+ return 0;
+ }
+
+ if (keyval == 0)
+ return 0;
+
+ keycode = XKeysymToKeycode (bindings->priv->xdisplay, keyval);
+ if (keycode == 0)
+ return 0;
+
+ real_modifiers = get_real_modifiers (modifiers);
+
+ flashback_key_bindings_change_keygrab (bindings,
+ TRUE,
+ keyval,
+ keycode,
+ real_modifiers);
+
+ binding = g_new0 (KeyBinding, 1);
+
+ binding->name = accelerator;
+ binding->action = ++next_action;
+ binding->keyval = keyval;
+ binding->keycode = keycode;
+ binding->modifiers = real_modifiers;
+
+ g_hash_table_insert (bindings->priv->table, GUINT_TO_POINTER (binding->action), binding);
+
+ return binding->action;
+}
+
+gboolean
+flashback_key_bindings_ungrab (FlashbackKeyBindings *bindings,
+ guint action)
+{
+ KeyBinding *binding;
+
+ binding = (KeyBinding *) g_hash_table_lookup (bindings->priv->table,
+ GUINT_TO_POINTER (action));
+
+ if (binding == NULL)
+ return FALSE;
+
+ flashback_key_bindings_change_keygrab (bindings,
+ FALSE,
+ binding->keyval,
+ binding->keycode,
+ binding->modifiers);
+
+ g_hash_table_remove (bindings->priv->table,
+ GUINT_TO_POINTER (action));
+
+ return TRUE;
+}
diff --git a/gnome-flashback/libkey-grabber/flashback-key-bindings.h
b/gnome-flashback/libkey-grabber/flashback-key-bindings.h
new file mode 100644
index 0000000..e53fabc
--- /dev/null
+++ b/gnome-flashback/libkey-grabber/flashback-key-bindings.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Alberts Muktupāvels
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FLASHBACK_KEY_BINDINGS_H
+#define FLASHBACK_KEY_BINDINGS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define FLASHBACK_TYPE_KEY_BINDINGS (flashback_key_bindings_get_type ())
+#define FLASHBACK_KEY_BINDINGS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FLASHBACK_TYPE_KEY_BINDINGS,
FlashbackKeyBindings))
+#define FLASHBACK_KEY_BINDINGS_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), FLASHBACK_TYPE_KEY_BINDINGS,
FlashbackKeyBindingsClass))
+#define FLASHBACK_IS_KEY_BINDINGS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), FLASHBACK_TYPE_KEY_BINDINGS))
+#define FLASHBACK_IS_KEY_BINDINGS_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), FLASHBACK_TYPE_KEY_BINDINGS))
+#define FLASHBACK_KEY_BINDINGS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), FLASHBACK_TYPE_KEY_BINDINGS,
FlashbackKeyBindingsClass))
+
+typedef struct _FlashbackKeyBindings FlashbackKeyBindings;
+typedef struct _FlashbackKeyBindingsClass FlashbackKeyBindingsClass;
+typedef struct _FlashbackKeyBindingsPrivate FlashbackKeyBindingsPrivate;
+
+struct _FlashbackKeyBindings {
+ GObject parent;
+ FlashbackKeyBindingsPrivate *priv;
+};
+
+struct _FlashbackKeyBindingsClass {
+ GObjectClass parent_class;
+
+ void (*binding_activated) (FlashbackKeyBindings *bindings,
+ guint action,
+ guint device,
+ guint timestamp);
+};
+
+GType flashback_key_bindings_get_type (void);
+
+FlashbackKeyBindings *flashback_key_bindings_new (void);
+
+guint flashback_key_bindings_grab (FlashbackKeyBindings *bindings,
+ const gchar *accelerator);
+gboolean flashback_key_bindings_ungrab (FlashbackKeyBindings *bindings,
+ guint action);
+
+G_END_DECLS
+
+#endif
diff --git a/gnome-flashback/libkey-grabber/flashback-key-grabber.c
b/gnome-flashback/libkey-grabber/flashback-key-grabber.c
new file mode 100644
index 0000000..e83d40e
--- /dev/null
+++ b/gnome-flashback/libkey-grabber/flashback-key-grabber.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2014 Alberts Muktupāvels
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+
+#include "flashback-key-grabber.h"
+#include "flashback-key-bindings.h"
+#include "dbus-key-grabber.h"
+
+#define KEY_GRABBER_DBUS_NAME "org.gnome.Shell"
+#define KEY_GRABBER_DBUS_PATH "/org/gnome/Shell"
+
+struct _FlashbackKeyGrabberPrivate {
+ gint bus_name;
+ GDBusInterfaceSkeleton *iface;
+
+ GHashTable *grabbed_accelerators;
+ GHashTable *grabbers;
+
+ FlashbackKeyBindings *bindings;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (FlashbackKeyGrabber, flashback_key_grabber, G_TYPE_OBJECT)
+
+static void
+binding_activated (FlashbackKeyBindings *bindings,
+ guint action,
+ guint device,
+ guint timestamp,
+ gpointer user_data)
+{
+ FlashbackKeyGrabber *grabber;
+
+ grabber = FLASHBACK_KEY_GRABBER (user_data);
+
+ dbus_key_grabber_emit_accelerator_activated (DBUS_KEY_GRABBER (grabber->priv->iface),
+ action,
+ device,
+ timestamp);
+}
+
+static gint
+real_grab (FlashbackKeyGrabber *grabber,
+ const gchar *accelerator)
+{
+ return flashback_key_bindings_grab (grabber->priv->bindings, accelerator);
+}
+
+static gboolean
+real_ungrab (FlashbackKeyGrabber *grabber,
+ gint action)
+{
+ return flashback_key_bindings_ungrab (grabber->priv->bindings, action);
+}
+
+typedef struct {
+ const gchar *sender;
+ FlashbackKeyGrabber *grabber;
+} Data;
+
+static void
+ungrab_accelerator (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ guint action;
+ gchar *sender;
+ Data *data;
+
+ action = GPOINTER_TO_UINT (key);
+ sender = (gchar *) value;
+ data = (Data *) user_data;
+
+ if (g_str_equal (sender, data->sender)) {
+ if (real_ungrab (data->grabber, action))
+ g_hash_table_remove (data->grabber->priv->grabbed_accelerators, key);
+ }
+}
+
+static void
+name_vanished_handler (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ FlashbackKeyGrabber *grabber;
+ guint id;
+ Data *data;
+
+ grabber = FLASHBACK_KEY_GRABBER (user_data);
+ id = GPOINTER_TO_UINT (g_hash_table_lookup (grabber->priv->grabbers, name));
+ data = g_new0 (Data, 1);
+
+ data->sender = name;
+ data->grabber = grabber;
+
+ g_hash_table_foreach (grabber->priv->grabbed_accelerators, (GHFunc) ungrab_accelerator, data);
+ g_free (data);
+
+ g_bus_unwatch_name (id);
+ g_hash_table_remove (grabber->priv->grabbers, name);
+}
+
+static guint
+grab_accelerator (FlashbackKeyGrabber *grabber,
+ const gchar *accelerator,
+ guint flags,
+ const gchar *sender)
+{
+ guint action;
+
+ action = real_grab (grabber, accelerator);
+ g_hash_table_insert (grabber->priv->grabbed_accelerators,
+ GUINT_TO_POINTER (action),
+ g_strdup (sender));
+
+ if (g_hash_table_lookup (grabber->priv->grabbers, sender) == NULL) {
+ guint id = g_bus_watch_name (G_BUS_TYPE_SESSION,
+ sender,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ NULL,
+ (GBusNameVanishedCallback) name_vanished_handler,
+ grabber,
+ NULL);
+ g_hash_table_insert (grabber->priv->grabbers,
+ g_strdup (sender),
+ GUINT_TO_POINTER (id));
+ }
+
+ return action;
+}
+
+static gboolean
+handle_grab_accelerator (DBusKeyGrabber *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *accelerator,
+ guint flags,
+ FlashbackKeyGrabber *grabber)
+{
+ const gchar *sender;
+ guint action;
+
+ sender = g_dbus_method_invocation_get_sender (invocation);
+ action = grab_accelerator (grabber, accelerator, flags, sender);
+
+ dbus_key_grabber_complete_grab_accelerator (object, invocation, action);
+
+ return TRUE;
+}
+
+static gboolean
+handle_grab_accelerators (DBusKeyGrabber *object,
+ GDBusMethodInvocation *invocation,
+ GVariant *accelerators,
+ FlashbackKeyGrabber *grabber)
+{
+ GVariantBuilder builder;
+ GVariantIter iter;
+ GVariant *child;
+ const gchar *sender;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE("au"));
+ g_variant_iter_init (&iter, accelerators);
+
+ sender = g_dbus_method_invocation_get_sender (invocation);
+
+ while ((child = g_variant_iter_next_value (&iter))) {
+ gchar *accelerator;
+ guint flags;
+ guint action;
+
+ g_variant_get (child, "(su)", &accelerator, &flags);
+
+ action = grab_accelerator (grabber, accelerator, flags, sender);
+ g_variant_builder_add (&builder, "u", action);
+
+ g_free (accelerator);
+ g_variant_unref (child);
+ }
+
+ dbus_key_grabber_complete_grab_accelerators (object, invocation, g_variant_builder_end (&builder));
+
+ return TRUE;
+}
+
+static gboolean
+handle_ungrab_accelerator (DBusKeyGrabber *object,
+ GDBusMethodInvocation *invocation,
+ guint action,
+ FlashbackKeyGrabber *grabber)
+{
+ gchar *sender;
+ gboolean ret;
+
+ ret = FALSE;
+ sender = (gchar *) g_hash_table_lookup (grabber->priv->grabbed_accelerators,
+ GUINT_TO_POINTER (action));
+
+ if (g_str_equal (sender, g_dbus_method_invocation_get_sender (invocation))) {
+ ret = real_ungrab (grabber, action);
+
+ if (ret)
+ g_hash_table_remove (grabber->priv->grabbed_accelerators, GUINT_TO_POINTER (action));
+ }
+
+ dbus_key_grabber_complete_ungrab_accelerator (object, invocation, ret);
+
+ return TRUE;
+}
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ FlashbackKeyGrabber *grabber;
+ DBusKeyGrabber *skeleton;
+ GError *error;
+
+ grabber = FLASHBACK_KEY_GRABBER (user_data);
+ skeleton = dbus_key_grabber_skeleton_new ();
+
+ grabber->priv->iface = G_DBUS_INTERFACE_SKELETON (skeleton);
+
+ g_signal_connect (grabber->priv->iface, "handle-grab-accelerator",
+ G_CALLBACK (handle_grab_accelerator), grabber);
+ g_signal_connect (grabber->priv->iface, "handle-grab-accelerators",
+ G_CALLBACK (handle_grab_accelerators), grabber);
+ g_signal_connect (grabber->priv->iface, "handle-ungrab-accelerator",
+ G_CALLBACK (handle_ungrab_accelerator), grabber);
+
+ error = NULL;
+ if (!g_dbus_interface_skeleton_export (grabber->priv->iface,
+ connection,
+ KEY_GRABBER_DBUS_PATH,
+ &error)) {
+ g_warning ("Failed to export interface: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+}
+
+static void
+flashback_key_grabber_finalize (GObject *object)
+{
+ FlashbackKeyGrabber *grabber;
+
+ grabber = FLASHBACK_KEY_GRABBER (object);
+
+ if (grabber->priv->bus_name) {
+ g_bus_unown_name (grabber->priv->bus_name);
+ grabber->priv->bus_name = 0;
+ }
+
+ if (grabber->priv->grabbed_accelerators) {
+ g_hash_table_destroy (grabber->priv->grabbed_accelerators);
+ grabber->priv->grabbed_accelerators = NULL;
+ }
+
+ if (grabber->priv->grabbers) {
+ g_hash_table_destroy (grabber->priv->grabbers);
+ grabber->priv->grabbers = NULL;
+ }
+
+ g_clear_object (&grabber->priv->bindings);
+
+ G_OBJECT_CLASS (flashback_key_grabber_parent_class)->finalize (object);
+}
+
+static void
+flashback_key_grabber_init (FlashbackKeyGrabber *grabber)
+{
+ grabber->priv = flashback_key_grabber_get_instance_private (grabber);
+
+ grabber->priv->grabbed_accelerators = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+ grabber->priv->grabbers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ grabber->priv->bindings = flashback_key_bindings_new ();
+ g_signal_connect (grabber->priv->bindings, "binding-activated",
+ G_CALLBACK (binding_activated), grabber);
+
+ grabber->priv->bus_name = g_bus_own_name (G_BUS_TYPE_SESSION,
+ KEY_GRABBER_DBUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
+ G_BUS_NAME_OWNER_FLAGS_REPLACE,
+ on_bus_acquired,
+ NULL,
+ NULL,
+ grabber,
+ NULL);
+}
+
+static void
+flashback_key_grabber_class_init (FlashbackKeyGrabberClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = flashback_key_grabber_finalize;
+}
+
+FlashbackKeyGrabber *
+flashback_key_grabber_new (void)
+{
+ return g_object_new (FLASHBACK_TYPE_KEY_GRABBER, NULL);
+}
diff --git a/gnome-flashback/libkey-grabber/flashback-key-grabber.h
b/gnome-flashback/libkey-grabber/flashback-key-grabber.h
new file mode 100644
index 0000000..ac8728d
--- /dev/null
+++ b/gnome-flashback/libkey-grabber/flashback-key-grabber.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 Alberts Muktupāvels
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FLASHBACK_KEY_GRABBER_H
+#define FLASHBACK_KEY_GRABBER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define FLASHBACK_TYPE_KEY_GRABBER (flashback_key_grabber_get_type ())
+#define FLASHBACK_KEY_GRABBER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FLASHBACK_TYPE_KEY_GRABBER,
FlashbackKeyGrabber))
+#define FLASHBACK_KEY_GRABBER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), FLASHBACK_TYPE_KEY_GRABBER,
FlashbackKeyGrabberClass))
+#define FLASHBACK_IS_KEY_GRABBER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), FLASHBACK_TYPE_KEY_GRABBER))
+#define FLASHBACK_IS_KEY_GRABBER_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), FLASHBACK_TYPE_KEY_GRABBER))
+#define FLASHBACK_KEY_GRABBER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), FLASHBACK_TYPE_KEY_GRABBER,
FlashbackKeyGrabberClass))
+
+typedef struct _FlashbackKeyGrabber FlashbackKeyGrabber;
+typedef struct _FlashbackKeyGrabberClass FlashbackKeyGrabberClass;
+typedef struct _FlashbackKeyGrabberPrivate FlashbackKeyGrabberPrivate;
+
+struct _FlashbackKeyGrabber {
+ GObject parent;
+ FlashbackKeyGrabberPrivate *priv;
+};
+
+struct _FlashbackKeyGrabberClass {
+ GObjectClass parent_class;
+};
+
+GType flashback_key_grabber_get_type (void);
+
+FlashbackKeyGrabber *flashback_key_grabber_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/gnome-flashback/libkey-grabber/org.gnome.KeyGrabber.xml
b/gnome-flashback/libkey-grabber/org.gnome.KeyGrabber.xml
new file mode 100644
index 0000000..b47e9c8
--- /dev/null
+++ b/gnome-flashback/libkey-grabber/org.gnome.KeyGrabber.xml
@@ -0,0 +1,23 @@
+<node>
+ <interface name="org.gnome.Shell">
+ <annotation name="org.gtk.GDBus.C.Name" value="KeyGrabber"/>
+ <method name="GrabAccelerator">
+ <arg type="s" direction="in" name="accelerator"/>
+ <arg type="u" direction="in" name="flags"/>
+ <arg type="u" direction="out" name="action"/>
+ </method>
+ <method name="GrabAccelerators">
+ <arg type="a(su)" direction="in" name="accelerators"/>
+ <arg type="au" direction="out" name="actions"/>
+ </method>
+ <method name="UngrabAccelerator">
+ <arg type="u" direction="in" name="action"/>
+ <arg type="b" direction="out" name="success"/>
+ </method>
+ <signal name="AcceleratorActivated">
+ <arg type="u" name="action"/>
+ <arg type="u" name="device"/>
+ <arg type="u" name="timestamp"/>
+ </signal>
+ </interface>
+</node>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]