[gnome-settings-daemon/wip/input-sources: 5/6] keyboard: Apply XKB layouts ourselves and stop relying on libgnomekbd
- From: Rui Matos <rtcm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-settings-daemon/wip/input-sources: 5/6] keyboard: Apply XKB layouts ourselves and stop relying on libgnomekbd
- Date: Tue, 17 Apr 2012 16:12:19 +0000 (UTC)
commit 5a5bc2c97e17e14cb238ac0ac3c726149b007e22
Author: Rui Matos <tiagomatos gmail com>
Date: Mon Apr 16 18:22:14 2012 +0200
keyboard: Apply XKB layouts ourselves and stop relying on libgnomekbd
libgnomekbd/xklavier aren't a good fit to have the keyboard input
story that we want since they rely on implementation details of the
XKB protocol to provide users with a means to switch keyboard layouts.
Of note here is a) their reliance on XKB groups, of which there can be
only up to 4, to specify the layouts the user is able to switch
between and b) their reliance on XKB options to specify the keybinding
to switch layouts which is a restricted set and falls outside the
regular GNOME desktop wide keybindings management as it's implemented
entirely on the X server side.
This commit introduces the use of a shared GSettings schema from
gsettings-desktop-schemas which will be the storage for our new
concept of "input sources". Input sources are basically a tuple of
keyboard layout and, if needed, an IBus input engine that work
together to provide the user with working keyboard input.
As a start we only handle the keyboard layout for now. We do it using
roughly the same method that setxkbmap(1) uses which should allow the
users that want to specify their own XKB features (except layout) to
still do so outside of GNOME (e.g. in a session startup script).
configure.ac | 10 +-
plugins/keyboard/Makefile.am | 5 +-
plugins/keyboard/gsd-keyboard-manager.c | 215 +++++++++++--
plugins/keyboard/gsd-keyboard-manager.h | 1 -
plugins/keyboard/gsd-keyboard-xkb.c | 554 -------------------------------
plugins/keyboard/gsd-keyboard-xkb.h | 39 ---
6 files changed, 197 insertions(+), 627 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 147faa2..f05cb88 100644
--- a/configure.ac
+++ b/configure.ac
@@ -175,8 +175,14 @@ dnl ---------------------------------------------------------------------------
dnl - Keyboard plugin stuff
dnl ---------------------------------------------------------------------------
-LIBGNOMEKBD_REQUIRED=3.5.1
-PKG_CHECK_MODULES(KEYBOARD, [libgnomekbdui >= $LIBGNOMEKBD_REQUIRED libgnomekbd >= $LIBGNOMEKBD_REQUIRED libxklavier >= 5.0 kbproto])
+PKG_CHECK_MODULES(KEYBOARD, [xkbfile])
+
+AC_ARG_WITH(xkb-config-root,
+ AS_HELP_STRING([--with-xkb-config-root=<paths>],
+ [Set default XKB config root (default: ${datadir}/X11/xkb)]),
+ [XKBCONFIGROOT="$withval"],
+ [XKBCONFIGROOT=${datadir}/X11/xkb])
+AC_SUBST([XKBCONFIGROOT])
dnl ---------------------------------------------------------------------------
dnl - Housekeeping plugin stuff
diff --git a/plugins/keyboard/Makefile.am b/plugins/keyboard/Makefile.am
index da59e83..8f5ec69 100644
--- a/plugins/keyboard/Makefile.am
+++ b/plugins/keyboard/Makefile.am
@@ -20,17 +20,18 @@ libkeyboard_la_SOURCES = \
gsd-keyboard-plugin.c \
gsd-keyboard-manager.h \
gsd-keyboard-manager.c \
- gsd-keyboard-xkb.h \
- gsd-keyboard-xkb.c \
delayed-dialog.h \
delayed-dialog.c \
$(NULL)
+XKBCONFIGROOT= XKBCONFIGROOT@
+
libkeyboard_la_CPPFLAGS = \
-I$(top_srcdir)/gnome-settings-daemon \
-I$(top_srcdir)/data \
-DDATADIR=\""$(pkgdatadir)"\" \
-DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+ -DDFLT_XKB_CONFIG_ROOT=\"$(XKBCONFIGROOT)\" \
$(AM_CPPFLAGS)
libkeyboard_la_CFLAGS = \
diff --git a/plugins/keyboard/gsd-keyboard-manager.c b/plugins/keyboard/gsd-keyboard-manager.c
index 26b2514..9905a92 100644
--- a/plugins/keyboard/gsd-keyboard-manager.c
+++ b/plugins/keyboard/gsd-keyboard-manager.c
@@ -39,13 +39,12 @@
#include <X11/XKBlib.h>
#include <X11/keysym.h>
+#include <X11/extensions/XKBrules.h>
#include "gnome-settings-profile.h"
#include "gsd-keyboard-manager.h"
#include "gsd-enums.h"
-#include "gsd-keyboard-xkb.h"
-
#define GSD_KEYBOARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_KEYBOARD_MANAGER, GsdKeyboardManagerPrivate))
#ifndef HOST_NAME_MAX
@@ -66,18 +65,41 @@
#define KEY_BELL_DURATION "bell-duration"
#define KEY_BELL_MODE "bell-mode"
+#define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources"
+
+#define KEY_CURRENT_IS "current"
+#define KEY_INPUT_SOURCES "sources"
+
+#ifndef DFLT_XKB_CONFIG_ROOT
+#define DFLT_XKB_CONFIG_ROOT "/usr/share/X11/xkb"
+#endif
+#ifndef DFLT_XKB_RULES_FILE
+#define DFLT_XKB_RULES_FILE "base"
+#endif
+#ifndef DFLT_XKB_LAYOUT
+#define DFLT_XKB_LAYOUT "us"
+#endif
+#ifndef DFLT_XKB_MODEL
+#define DFLT_XKB_MODEL "pc105"
+#endif
+
struct GsdKeyboardManagerPrivate
{
guint start_idle_id;
GSettings *settings;
+ GSettings *is_settings;
gboolean have_xkb;
gint xkb_event_base;
GsdNumLockState old_state;
+ gulong ignore_serial;
};
static void gsd_keyboard_manager_class_init (GsdKeyboardManagerClass *klass);
static void gsd_keyboard_manager_init (GsdKeyboardManager *keyboard_manager);
static void gsd_keyboard_manager_finalize (GObject *object);
+static void apply_settings (GSettings *settings,
+ const char *key,
+ GsdKeyboardManager *manager);
G_DEFINE_TYPE (GsdKeyboardManager, gsd_keyboard_manager, G_TYPE_OBJECT)
@@ -93,7 +115,7 @@ xkb_set_keyboard_autorepeat_rate (guint delay, guint interval)
}
static void
-numlock_xkb_init (GsdKeyboardManager *manager)
+xkb_init (GsdKeyboardManager *manager)
{
Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
gboolean have_xkb;
@@ -112,6 +134,10 @@ numlock_xkb_init (GsdKeyboardManager *manager)
XkbStateNotify,
XkbModifierLockMask,
XkbModifierLockMask);
+ XkbSelectEvents (dpy,
+ XkbUseCoreKbd,
+ XkbNewKeyboardNotifyMask,
+ XkbNewKeyboardNotifyMask);
} else {
g_warning ("XKB extension not available");
}
@@ -138,21 +164,20 @@ numlock_set_xkb_state (GsdNumLockState new_state)
}
static GdkFilterReturn
-numlock_xkb_callback (GdkXEvent *xev_,
- GdkEvent *gdkev_,
- gpointer user_data)
+xkb_callback (GdkXEvent *xev_,
+ GdkEvent *gdkev_,
+ gpointer user_data)
{
XEvent *xev = (XEvent *) xev_;
XkbEvent *xkbev = (XkbEvent *) xev;
GsdKeyboardManager *manager = (GsdKeyboardManager *) user_data;
- if (xev->type != manager->priv->xkb_event_base)
- return GDK_FILTER_CONTINUE;
-
- if (xkbev->any.xkb_type != XkbStateNotify)
+ if (xev->type != manager->priv->xkb_event_base ||
+ xev->xany.serial == manager->priv->ignore_serial)
return GDK_FILTER_CONTINUE;
- if (xkbev->state.changed & XkbModifierLockMask) {
+ if (xkbev->any.xkb_type == XkbStateNotify &&
+ xkbev->state.changed & XkbModifierLockMask) {
unsigned num_mask = numlock_NumLock_modifier_mask ();
unsigned locked_mods = xkbev->state.locked_mods;
GsdNumLockState numlock_state;
@@ -165,23 +190,156 @@ numlock_xkb_callback (GdkXEvent *xev_,
numlock_state);
manager->priv->old_state = numlock_state;
}
- }
+ } else if (xkbev->any.xkb_type == XkbNewKeyboardNotify) {
+ apply_settings (manager->priv->settings, NULL, manager);
+ }
return GDK_FILTER_CONTINUE;
}
static void
-numlock_install_xkb_callback (GsdKeyboardManager *manager)
+install_xkb_callback (GsdKeyboardManager *manager)
{
if (!manager->priv->have_xkb)
return;
gdk_window_add_filter (NULL,
- numlock_xkb_callback,
+ xkb_callback,
manager);
}
+static void
+get_xkb_values (gchar **rules, XkbRF_VarDefsRec *var_defs)
+{
+ Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ *rules = NULL;
+
+ /* Get it from the X property or fallback on defaults */
+ if (!XkbRF_GetNamesProp (display, rules, var_defs) || !*rules) {
+ *rules = strdup (DFLT_XKB_RULES_FILE);
+ var_defs->model = strdup (DFLT_XKB_MODEL);
+ var_defs->layout = strdup (DFLT_XKB_LAYOUT);
+ var_defs->variant = NULL;
+ var_defs->options = NULL;
+ }
+}
+
+static void
+free_xkb_var_defs (XkbRF_VarDefsRec *p)
+{
+ if (p->model)
+ free (p->model);
+ if (p->layout)
+ free (p->layout);
+ if (p->variant)
+ free (p->variant);
+ if (p->options)
+ free (p->options);
+ free (p);
+}
+
+static void
+free_xkb_component_names (XkbComponentNamesRec *p)
+{
+ if (p->keymap)
+ free (p->keymap);
+ if (p->keycodes)
+ free (p->keycodes);
+ if (p->types)
+ free (p->types);
+ if (p->compat)
+ free (p->compat);
+ if (p->symbols)
+ free (p->symbols);
+ if (p->geometry)
+ free (p->geometry);
+ free (p);
+}
+
+static void
+upload_xkb_description (gchar *rules_file,
+ XkbRF_VarDefsRec *var_defs,
+ XkbComponentNamesRec *comp_names)
+{
+ Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ XkbDescRec *xkb_desc;
+
+ /* Upload it to the X server using the same method as setxkbmap */
+ xkb_desc = XkbGetKeyboardByName (display,
+ XkbUseCoreKbd,
+ comp_names,
+ XkbGBN_AllComponentsMask,
+ XkbGBN_AllComponentsMask &
+ (~XkbGBN_GeometryMask), True);
+ if (!xkb_desc) {
+ g_warning ("Couldn't upload new XKB keyboard description");
+ return;
+ }
+
+ XkbFreeKeyboard (xkb_desc, 0, True);
+
+ if (!XkbRF_SetNamesProp (display, rules_file, var_defs))
+ g_warning ("Couldn't update the XKB root window property");
+}
+
+static void
+apply_xkb_layout (GsdKeyboardManager *manager,
+ const gchar *layout)
+{
+ Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ XkbRF_RulesRec *xkb_rules;
+ XkbRF_VarDefsRec *xkb_var_defs;
+ gchar *rules_file;
+ gchar *rules_path;
+
+ xkb_var_defs = calloc (1, sizeof (XkbRF_VarDefsRec));
+ get_xkb_values (&rules_file, xkb_var_defs);
+
+ if (rules_file[0] == '/')
+ rules_path = g_strdup (rules_file);
+ else
+ rules_path = g_strdup_printf ("%s/rules/%s",
+ DFLT_XKB_CONFIG_ROOT,
+ rules_file);
+
+ /* Replace the layout with our current setting */
+ if (xkb_var_defs->layout)
+ free (xkb_var_defs->layout);
+ xkb_var_defs->layout = strdup (layout);
+
+ xkb_rules = XkbRF_Load (rules_path, "C", True, True);
+ if (xkb_rules) {
+ XkbComponentNamesRec *xkb_comp_names;
+ xkb_comp_names = calloc (1, sizeof (XkbComponentNamesRec));
+
+ XkbRF_GetComponents (xkb_rules, xkb_var_defs, xkb_comp_names);
+ manager->priv->ignore_serial = XNextRequest (display);
+ upload_xkb_description (rules_file, xkb_var_defs, xkb_comp_names);
+
+ free_xkb_component_names (xkb_comp_names);
+ XkbRF_Free (xkb_rules, True);
+ } else {
+ g_warning ("Couldn't load XKB rules");
+ }
+
+ free_xkb_var_defs (xkb_var_defs);
+ free (rules_file);
+ g_free (rules_path);
+}
+
+static void
+apply_input_sources_settings (GSettings *settings,
+ gchar *key,
+ GsdKeyboardManager *manager)
+{
+ const gchar *layout;
+ const gchar *engine;
+ g_settings_get (manager->priv->is_settings, KEY_CURRENT_IS,
+ "(&sm&s)", &layout, &engine);
+
+ apply_xkb_layout (manager, layout);
+}
static void
apply_settings (GSettings *settings,
@@ -251,34 +409,31 @@ apply_settings (GSettings *settings,
gdk_error_trap_pop_ignored ();
}
-void
-gsd_keyboard_manager_apply_settings (GsdKeyboardManager *manager)
-{
- apply_settings (manager->priv->settings, NULL, manager);
-}
-
static gboolean
start_keyboard_idle_cb (GsdKeyboardManager *manager)
{
+ Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
gnome_settings_profile_start (NULL);
g_debug ("Starting keyboard manager");
manager->priv->have_xkb = 0;
manager->priv->settings = g_settings_new (GSD_KEYBOARD_DIR);
+ manager->priv->is_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR);
+ manager->priv->ignore_serial = XLastKnownRequestProcessed (display) - 1;
- /* Essential - xkb initialization should happen before */
- gsd_keyboard_xkb_init (manager);
-
- numlock_xkb_init (manager);
+ xkb_init (manager);
/* apply current settings before we install the callback */
- gsd_keyboard_manager_apply_settings (manager);
+ apply_settings (manager->priv->settings, NULL, manager);
+ apply_input_sources_settings (manager->priv->is_settings, NULL, manager);
g_signal_connect (G_OBJECT (manager->priv->settings), "changed",
G_CALLBACK (apply_settings), manager);
+ g_signal_connect (G_OBJECT (manager->priv->is_settings), "changed::" KEY_CURRENT_IS,
+ G_CALLBACK (apply_input_sources_settings), manager);
- numlock_install_xkb_callback (manager);
+ install_xkb_callback (manager);
gnome_settings_profile_end (NULL);
@@ -311,14 +466,16 @@ gsd_keyboard_manager_stop (GsdKeyboardManager *manager)
g_object_unref (p->settings);
p->settings = NULL;
}
+ if (p->is_settings != NULL) {
+ g_object_unref (p->is_settings);
+ p->is_settings = NULL;
+ }
if (p->have_xkb) {
gdk_window_remove_filter (NULL,
- numlock_xkb_callback,
+ xkb_callback,
manager);
}
-
- gsd_keyboard_xkb_shutdown ();
}
static void
diff --git a/plugins/keyboard/gsd-keyboard-manager.h b/plugins/keyboard/gsd-keyboard-manager.h
index 434e652..42e2600 100644
--- a/plugins/keyboard/gsd-keyboard-manager.h
+++ b/plugins/keyboard/gsd-keyboard-manager.h
@@ -51,7 +51,6 @@ GsdKeyboardManager * gsd_keyboard_manager_new (void);
gboolean gsd_keyboard_manager_start (GsdKeyboardManager *manager,
GError **error);
void gsd_keyboard_manager_stop (GsdKeyboardManager *manager);
-void gsd_keyboard_manager_apply_settings (GsdKeyboardManager *manager);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]