From 4538ef38a1f431584694ae0e7f4eea942de1b9af Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Tue, 24 Apr 2012 10:06:09 +0900 Subject: [PATCH] Revert "Remove eek-xkb*." This reverts commit ee12d0240231d51e88d07dd1395327fd555e94b9. --- eek/Makefile.am | 5 +- eek/eek-xkb-0.90.pc.in | 30 ++ eek/eek-xkb-layout.c | 933 +++++++++++++++++++++++++++++++++++++++++ eek/eek-xkb-layout.h | 88 ++++ eek/eek-xkb.h | 26 ++ eek/eek-xkl-layout.c | 66 ++- eek/eek-xkl-layout.h | 6 +- 7 files changed, 1147 insertions(+), 7 deletions(-) create mode 100644 eek/eek-xkb-0.90.pc.in create mode 100644 eek/eek-xkb-layout.c create mode 100644 eek/eek-xkb-layout.h create mode 100644 eek/eek-xkb.h diff --git a/eek/Makefile.am b/eek/Makefile.am index fc2e7a58..c548c708 100644 --- a/eek/Makefile.am +++ b/eek/Makefile.am @@ -124,9 +124,12 @@ libeek_gtk_la_LIBADD = libeek.la $(GTK_LIBS) $(LIBCANBERRA_LIBS) libeek_xkl_public_headers = \ $(srcdir)/eek-xkl-layout.h \ - $(srcdir)/eek-xkl.h + $(srcdir)/eek-xkl.h \ + $(srcdir)/eek-xkb-layout.h \ + $(srcdir)/eek-xkb.h libeek_xkl_sources = \ + $(srcdir)/eek-xkb-layout.c \ $(srcdir)/eek-xkl-layout.c libeek_xkl_la_SOURCES = $(libeek_xkl_sources) diff --git a/eek/eek-xkb-0.90.pc.in b/eek/eek-xkb-0.90.pc.in new file mode 100644 index 00000000..421b6336 --- /dev/null +++ b/eek/eek-xkb-0.90.pc.in @@ -0,0 +1,30 @@ +# Copyright (C) 2010-2011 Daiki Ueno +# Copyright (C) 2010-2011 Red Hat, Inc. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. + +# This library 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 +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libeek-xkb +Description: A Library to Create Keyboard-like UI (XKB Support) +URL: http://fedorahosted.org/eekboard/ +Version: @VERSION@ +Requires: eek-@EEK_API_VERSION@ gtk+-x11-@GTK_API_VERSION@ +Libs: -L${libdir} -leek-xkb +Cflags: -I${includedir}/eek-@EEK_API_VERSION@ diff --git a/eek/eek-xkb-layout.c b/eek/eek-xkb-layout.c new file mode 100644 index 00000000..6b75195b --- /dev/null +++ b/eek/eek-xkb-layout.c @@ -0,0 +1,933 @@ +/* + * Copyright (C) 2006 Sergey V. Udaltsov + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +/** + * SECTION:eek-xkb-layout + * @short_description: Layout engine using XKB configuration + * + * The #EekXkbLayout inherits #EekLayout class and arranges keyboard + * elements using XKB. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include "eek-xkb-layout.h" +#include "eek-keyboard.h" +#include "eek-section.h" +#include "eek-key.h" +#include "eek-keysym.h" + +#define noKBDRAW_DEBUG + +static void initable_iface_init (GInitableIface *initable_iface); + +G_DEFINE_TYPE_WITH_CODE (EekXkbLayout, eek_xkb_layout, EEK_TYPE_LAYOUT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + initable_iface_init)); + +#define EEK_XKB_LAYOUT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_XKB_LAYOUT, EekXkbLayoutPrivate)) + +enum { + PROP_0, + PROP_DISPLAY, + PROP_KEYCODES, + PROP_GEOMETRY, + PROP_SYMBOLS, + PROP_LAST +}; + +struct _EekXkbLayoutPrivate +{ + /* Configuration names that should synch'ed to the symbolic names + in priv->xkb->names. Since we use GLib's memory allocator, + don't store any address returned from the X server here. */ + XkbComponentNamesRec names; + + Display *display; + + /* Actual XKB configuration of DISPLAY. */ + XkbDescRec *xkb; + + /* Hash table to cache orefs by shape address. */ + GHashTable *shape_oref_hash; + + gint scale_numerator; + gint scale_denominator; +}; + +static guint +find_keycode (EekXkbLayout *layout, gchar *key_name); + +static void +get_keyboard (EekXkbLayout *layout); + +static void +get_names (EekXkbLayout *layout); + +static void +setup_scaling (EekXkbLayout *layout, + gdouble width, + gdouble height); + +G_INLINE_FUNC gint +xkb_to_pixmap_coord (EekXkbLayout *layout, + gint n) +{ + EekXkbLayoutPrivate *priv = layout->priv; + return n * priv->scale_numerator / priv->scale_denominator; +} + +G_INLINE_FUNC gdouble +xkb_to_pixmap_double (EekXkbLayout *layout, + gdouble d) +{ + EekXkbLayoutPrivate *priv = layout->priv; + return d * priv->scale_numerator / priv->scale_denominator; +} + +static void +create_key (EekXkbLayout *layout, + EekKeyboard *keyboard, + EekSection *section, + gint column, + gint row, + gdouble x, + gdouble y, + XkbKeyRec *xkbkey) +{ + XkbGeometryRec *xkbgeometry; + XkbBoundsRec *xkbbounds; + XkbShapeRec *xkbshape; + XkbOutlineRec *xkboutline; + EekXkbLayoutPrivate *priv = layout->priv; + EekKey *key; + EekBounds bounds; + EekSymbolMatrix *matrix = NULL; + gchar name[XkbKeyNameLength + 1]; + KeyCode keycode; + gint num_groups, num_levels; + guint oref; + gpointer v; + + xkbgeometry = priv->xkb->geom; + xkbshape = &xkbgeometry->shapes[xkbkey->shape_ndx]; + if (g_hash_table_lookup_extended (priv->shape_oref_hash, xkbshape, + NULL, &v)) { + oref = GPOINTER_TO_UINT(v); + } else { + EekOutline *outline; + + xkboutline = xkbshape->primary == NULL ? &xkbshape->outlines[0] : + xkbshape->primary; + + outline = g_slice_new (EekOutline); + outline->corner_radius = xkb_to_pixmap_coord(layout, xkboutline->corner_radius); + + if (xkboutline->num_points <= 2) { /* rectangular */ + gdouble x1, y1, x2, y2; + + outline->num_points = 4; + outline->points = g_slice_alloc0 (sizeof (EekPoint) * + outline->num_points); + if (xkboutline->num_points == 1) { + x1 = xkb_to_pixmap_coord(layout, xkbshape->bounds.x1); + y1 = xkb_to_pixmap_coord(layout, xkbshape->bounds.y1); + x2 = xkb_to_pixmap_coord(layout, xkboutline->points[0].x); + y2 = xkb_to_pixmap_coord(layout, xkboutline->points[0].y); + } else { + x1 = xkb_to_pixmap_coord(layout, xkboutline->points[0].x); + y1 = xkb_to_pixmap_coord(layout, xkboutline->points[0].y); + x2 = xkb_to_pixmap_coord(layout, xkboutline->points[1].x); + y2 = xkb_to_pixmap_coord(layout, xkboutline->points[1].y); + } + outline->points[0].x = outline->points[3].x = x1; + outline->points[0].y = outline->points[1].y = y1; + outline->points[1].x = outline->points[2].x = x2; + outline->points[2].y = outline->points[3].y = y2; + } else { /* polygon */ + gint i; + + outline->num_points = xkboutline->num_points; + outline->points = g_new0 (EekPoint, outline->num_points); + for (i = 0; i < xkboutline->num_points; i++) { + outline->points[i].x = + xkb_to_pixmap_coord(layout, xkboutline->points[i].x); + outline->points[i].y = + xkb_to_pixmap_coord(layout, xkboutline->points[i].y); + } + } + oref = eek_keyboard_add_outline (keyboard, outline); + eek_outline_free (outline); + g_hash_table_insert (priv->shape_oref_hash, xkbshape, + GUINT_TO_POINTER(oref)); + } + + memset (name, 0, sizeof name); + memcpy (name, xkbkey->name.name, sizeof name - 1); + + xkbbounds = &xkbgeometry->shapes[xkbkey->shape_ndx].bounds; + bounds.x = xkb_to_pixmap_coord(layout, xkbbounds->x1 + x); + bounds.y = xkb_to_pixmap_coord(layout, xkbbounds->y1 + y); + bounds.width = xkb_to_pixmap_coord(layout, xkbbounds->x2 - xkbbounds->x1); + bounds.height = xkb_to_pixmap_coord(layout, xkbbounds->y2 - xkbbounds->y1); + + keycode = find_keycode (layout, name); + if (keycode == EEK_INVALID_KEYCODE) { + num_groups = num_levels = 0; + matrix = eek_symbol_matrix_new (0, 0); + } else { + KeySym keysym; + gint i, j; + + num_groups = XkbKeyNumGroups (priv->xkb, keycode); + num_levels = XkbKeyGroupsWidth (priv->xkb, keycode); + matrix = eek_symbol_matrix_new (num_groups, num_levels); + for (i = 0; i < num_groups; i++) + for (j = 0; j < num_levels; j++) { + EekModifierType modifier; + + keysym = XkbKeySymEntry (priv->xkb, keycode, j, i); + modifier = XkbKeysymToModifiers (priv->display, keysym); + matrix->data[i * num_levels + j] = + EEK_SYMBOL(eek_keysym_new_with_modifier (keysym, + modifier)); + } + } + + key = eek_section_create_key (section, keycode, column, row); + eek_element_set_name (EEK_ELEMENT(key), name); + eek_element_set_bounds (EEK_ELEMENT(key), &bounds); + eek_key_set_symbol_matrix (key, matrix); + eek_symbol_matrix_free (matrix); + eek_key_set_oref (key, oref); +} + +static void +create_section (EekXkbLayout *layout, + EekKeyboard *keyboard, + XkbSectionRec *xkbsection) +{ + XkbGeometryRec *xkbgeometry; + EekXkbLayoutPrivate *priv; + EekSection *section; + EekBounds bounds; + gchar *name; + gfloat left, top; + gint i, j; + + bounds.x = xkb_to_pixmap_coord(layout, xkbsection->left); + bounds.y = xkb_to_pixmap_coord(layout, xkbsection->top); + bounds.width = xkb_to_pixmap_coord(layout, xkbsection->width); + bounds.height = xkb_to_pixmap_coord(layout, xkbsection->height); + + priv = layout->priv; + xkbgeometry = priv->xkb->geom; + section = eek_keyboard_create_section (keyboard); + name = XGetAtomName (priv->display, xkbsection->name); + eek_element_set_name (EEK_ELEMENT(section), name); + XFree (name); + eek_element_set_bounds (EEK_ELEMENT(section), &bounds); + eek_section_set_angle (section, + /* angle is in tenth of degree */ + xkbsection->angle / 10); + + for (i = 0; i < xkbsection->num_rows; i++) { + XkbRowRec *xkbrow; + + xkbrow = &xkbsection->rows[i]; + left = xkbrow->left; + top = xkbrow->top; + eek_section_add_row (section, + xkbrow->num_keys, + xkbrow->vertical ? + EEK_ORIENTATION_VERTICAL : + EEK_ORIENTATION_HORIZONTAL); + for (j = 0; j < xkbrow->num_keys; j++) { + XkbKeyRec *xkbkey; + XkbBoundsRec *xkbbounds; + + xkbkey = &xkbrow->keys[j]; + if (xkbrow->vertical) + top += xkbkey->gap; + else + left += xkbkey->gap; + create_key (layout, keyboard, section, j, i, left, top, xkbkey); + xkbbounds = &xkbgeometry->shapes[xkbkey->shape_ndx].bounds; + if (xkbrow->vertical) + top += xkbbounds->y2 - xkbbounds->y1; + else + left += xkbbounds->x2 - xkbbounds->x1; + } + } +} + +static void +create_keyboard (EekXkbLayout *layout, EekKeyboard *keyboard) +{ + EekXkbLayoutPrivate *priv = layout->priv; + XkbGeometryRec *xkbgeometry; + EekBounds bounds; + gint i; + + g_return_if_fail (priv->xkb); + g_return_if_fail (priv->xkb->geom); + + xkbgeometry = priv->xkb->geom; + + eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds); + setup_scaling (EEK_XKB_LAYOUT(layout), bounds.width, bounds.height); + + bounds.x = bounds.y = 0; + bounds.width = xkb_to_pixmap_coord(layout, xkbgeometry->width_mm); + bounds.height = xkb_to_pixmap_coord(layout, xkbgeometry->height_mm); + + for (i = 0; i < xkbgeometry->num_sections; i++) { + XkbSectionRec *xkbsection; + + xkbsection = &xkbgeometry->sections[i]; + create_section (layout, keyboard, xkbsection); + } + eek_element_set_bounds (EEK_ELEMENT(keyboard), &bounds); +} + +static EekKeyboard * +eek_xkb_layout_real_create_keyboard (EekLayout *self, + gdouble initial_width, + gdouble initial_height) +{ + EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (self); + EekBounds bounds; + EekKeyboard *keyboard; + + keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", self, NULL); + bounds.x = bounds.y = 0.0; + bounds.width = initial_width; + bounds.height = initial_height; + eek_element_set_bounds (EEK_ELEMENT(keyboard), &bounds); + + /* resolve modifiers dynamically assigned at run time */ + eek_keyboard_set_num_lock_mask (keyboard, + XkbKeysymToModifiers (priv->display, + XK_Num_Lock)); + eek_keyboard_set_alt_gr_mask (keyboard, + XkbKeysymToModifiers (priv->display, + XK_ISO_Level3_Shift)); + + if (priv->shape_oref_hash) + g_hash_table_destroy (priv->shape_oref_hash); + + priv->shape_oref_hash = g_hash_table_new (g_direct_hash, g_direct_equal); + create_keyboard (EEK_XKB_LAYOUT(self), keyboard); + g_hash_table_destroy (priv->shape_oref_hash); + + return keyboard; +} + +static void +eek_xkb_layout_finalize (GObject *object) +{ + EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (object); + + g_free (priv->names.keycodes); + g_free (priv->names.geometry); + g_free (priv->names.symbols); + XkbFreeKeyboard (priv->xkb, 0, TRUE); /* free_all = TRUE */ + G_OBJECT_CLASS (eek_xkb_layout_parent_class)->finalize (object); +} + +static void +eek_xkb_layout_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EekXkbLayout *layout = EEK_XKB_LAYOUT (object); + const gchar *name; + + switch (prop_id) { + case PROP_DISPLAY: + layout->priv->display = g_value_get_pointer (value); + break; + case PROP_KEYCODES: + name = g_value_get_string (value); + eek_xkb_layout_set_keycodes (EEK_XKB_LAYOUT(object), name); + break; + case PROP_GEOMETRY: + name = g_value_get_string (value); + eek_xkb_layout_set_geometry (EEK_XKB_LAYOUT(object), name); + break; + case PROP_SYMBOLS: + name = g_value_get_string (value); + eek_xkb_layout_set_symbols (EEK_XKB_LAYOUT(object), name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +eek_xkb_layout_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EekXkbLayout *layout = EEK_XKB_LAYOUT (object); + const gchar *name; + + switch (prop_id) { + case PROP_DISPLAY: + g_value_set_pointer (value, layout->priv->display); + break; + case PROP_KEYCODES: + name = eek_xkb_layout_get_keycodes (EEK_XKB_LAYOUT(object)); + g_value_set_string (value, name); + break; + case PROP_GEOMETRY: + name = eek_xkb_layout_get_geometry (EEK_XKB_LAYOUT(object)); + g_value_set_string (value, name); + break; + case PROP_SYMBOLS: + name = eek_xkb_layout_get_symbols (EEK_XKB_LAYOUT(object)); + g_value_set_string (value, name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +eek_xkb_layout_class_init (EekXkbLayoutClass *klass) +{ + EekLayoutClass *layout_class = EEK_LAYOUT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (gobject_class, sizeof (EekXkbLayoutPrivate)); + + layout_class->create_keyboard = eek_xkb_layout_real_create_keyboard; + + gobject_class->finalize = eek_xkb_layout_finalize; + gobject_class->set_property = eek_xkb_layout_set_property; + gobject_class->get_property = eek_xkb_layout_get_property; + + pspec = g_param_spec_pointer ("display", + "Display", + "X Display", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (gobject_class, PROP_DISPLAY, pspec); + + pspec = g_param_spec_string ("keycodes", + "Keycodes", + "XKB keycodes component name", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_KEYCODES, pspec); + + pspec = g_param_spec_string ("geometry", + "Geometry", + "XKB geometry component name", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_GEOMETRY, pspec); + + pspec = g_param_spec_string ("symbols", + "Symbols", + "XKB symbols component name", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_SYMBOLS, pspec); +} + +static void +eek_xkb_layout_init (EekXkbLayout *self) +{ + self->priv = EEK_XKB_LAYOUT_GET_PRIVATE (self); +} + +static void +get_names (EekXkbLayout *layout) +{ + EekXkbLayoutPrivate *priv = layout->priv; + gchar *name; + + XkbGetNames (priv->display, XkbAllNamesMask, priv->xkb); + + if (priv->xkb->names->keycodes <= 0) + g_warning ("XKB keycodes setting is not loaded properly"); + else { + name = XGetAtomName (priv->display, priv->xkb->names->keycodes); + if (!name) + g_warning ("Can't get the name of keycodes"); + else if (!priv->names.keycodes || + g_strcmp0 (name, priv->names.keycodes)) { + g_free (priv->names.keycodes); + priv->names.keycodes = g_strdup (name); + XFree (name); + } + } + + if (priv->xkb->names->geometry <= 0) + g_warning ("XKB geometry setting is not loaded"); + else { + name = XGetAtomName (priv->display, priv->xkb->names->geometry); + if (!name) + g_warning ("Can't get the name of geometry"); + else if (!priv->names.geometry || + g_strcmp0 (name, priv->names.geometry)) { + g_free (priv->names.geometry); + priv->names.geometry = g_strdup (name); + XFree (name); + } + } + + if (priv->xkb->names->symbols <= 0) + g_warning ("XKB symbols setting is not loaded"); + else { + name = XGetAtomName (priv->display, priv->xkb->names->symbols); + if (!name) + g_warning ("Can't get the name of symbols"); + else if (!priv->names.symbols || + g_strcmp0 (name, priv->names.symbols)) { + g_free (priv->names.symbols); + priv->names.symbols = g_strdup (name); + XFree (name); + } + } +} + +/** + * eek_xkb_layout_new: + * + * Create a new #EekXkbLayout. + */ +EekLayout * +eek_xkb_layout_new (Display *display, + GError **error) +{ + return (EekLayout *) g_initable_new (EEK_TYPE_XKB_LAYOUT, + NULL, + error, + "display", display, + NULL); +} + +/** + * eek_xkb_layout_set_names: (skip) + * @layout: an #EekXkbLayout + * @names: XKB component names + * + * Set the XKB component names to @layout. + * Returns: %TRUE if any of the component names changed, %FALSE otherwise + */ +gboolean +eek_xkb_layout_set_names (EekXkbLayout *layout, XkbComponentNamesRec *names) +{ + EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout); + gboolean retval; + + g_return_val_if_fail (priv, FALSE); + + if (g_strcmp0 (names->keycodes, priv->names.keycodes)) { + g_free (priv->names.keycodes); + priv->names.keycodes = g_strdup (names->keycodes); + retval = TRUE; + } + + if (g_strcmp0 (names->geometry, priv->names.geometry)) { + g_free (priv->names.geometry); + priv->names.geometry = g_strdup (names->geometry); + retval = TRUE; + } + + if (g_strcmp0 (names->symbols, priv->names.symbols)) { + g_free (priv->names.symbols); + priv->names.symbols = g_strdup (names->symbols); + retval = TRUE; + } + + get_keyboard (layout); + g_assert (priv->xkb); + + return retval; +} + +/** + * eek_xkb_layout_set_names_full: + * @layout: an #EekXkbLayout + * @Varargs: pairs of component name and value, terminated by NULL. + * + * Set the XKB component names to @layout. This function is merely a + * wrapper around eek_xkb_layout_set_names() to avoid passing a + * pointer of XkbComponentNamesRec, which is not currently available + * in the gobject-introspection repository. + * + * Available component names are: keymap, keycodes, types, compat, + * symbols, geometry. + * + * Returns: %TRUE if the component name is successfully set, %FALSE otherwise + * Since: 0.0.2 + */ +gboolean +eek_xkb_layout_set_names_full (EekXkbLayout *layout, + ...) +{ + va_list var_args; + gboolean retval; + + va_start (var_args, layout); + retval = eek_xkb_layout_set_names_full_valist (layout, var_args); + va_end (var_args); + + return retval; +} + +/** + * eek_xkb_layout_set_names_full_valist: + * @layout: an #EekXkbLayout + * @var_args: va_list of pairs of component name and value. + * + * See eek_xkb_layout_set_names_full(), this version takes a + * va_list for language bindings to use. + * + * Since: 0.0.5 + */ +gboolean +eek_xkb_layout_set_names_full_valist (EekXkbLayout *layout, + va_list var_args) +{ + XkbComponentNamesRec names; + gchar *name, *value; + + memset (&names, 0, sizeof names); + name = va_arg (var_args, gchar *); + while (name) { + value = va_arg (var_args, gchar *); + if (g_strcmp0 (name, "keymap") == 0) + names.keymap = (char *)value; + else if (g_strcmp0 (name, "keycodes") == 0) + names.keycodes = (char *)value; + else if (g_strcmp0 (name, "types") == 0) + names.types = (char *)value; + else if (g_strcmp0 (name, "compat") == 0) + names.compat = (char *)value; + else if (g_strcmp0 (name, "symbols") == 0) + names.symbols = (char *)value; + else if (g_strcmp0 (name, "geometry") == 0) + names.geometry = (char *)value; + name = va_arg (var_args, gchar *); + } + return eek_xkb_layout_set_names (layout, &names); +} + +/** + * eek_xkb_layout_set_keycodes: + * @layout: an #EekXkbLayout + * @keycodes: component name for keycodes + * + * Set the keycodes component (in the XKB terminology). + * Returns: %TRUE if the component name is successfully set, %FALSE otherwise + */ +gboolean +eek_xkb_layout_set_keycodes (EekXkbLayout *layout, const gchar *keycodes) +{ + EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout); + XkbComponentNamesRec names; + + g_return_val_if_fail (priv, FALSE); + memcpy (&names, &priv->names, sizeof names); + names.keycodes = (gchar *)keycodes; + return eek_xkb_layout_set_names (layout, &names); +} + +/** + * eek_xkb_layout_set_geometry: + * @layout: an #EekXkbLayout + * @geometry: component name for geometry + * + * Returns: %TRUE if the component name is successfully set, %FALSE otherwise + */ +gboolean +eek_xkb_layout_set_geometry (EekXkbLayout *layout, const gchar *geometry) +{ + EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout); + XkbComponentNamesRec names; + + g_return_val_if_fail (priv, FALSE); + memcpy (&names, &priv->names, sizeof names); + names.geometry = (gchar *)geometry; + return eek_xkb_layout_set_names (layout, &names); +} + +/** + * eek_xkb_layout_set_symbols: + * @layout: an #EekXkbLayout + * @symbols: component name for symbols + * + * Set the symbols component (in the XKB terminology). + * Returns: %TRUE if the component name is successfully set, %FALSE otherwise + */ +gboolean +eek_xkb_layout_set_symbols (EekXkbLayout *layout, const gchar *symbols) +{ + EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout); + XkbComponentNamesRec names; + + g_return_val_if_fail (priv, FALSE); + memcpy (&names, &priv->names, sizeof names); + names.symbols = (gchar *)symbols; + return eek_xkb_layout_set_names (layout, &names); +} + +/** + * eek_xkb_layout_get_keycodes: + * @layout: an #EekXkbLayout + * + * Get the keycodes component name (in the XKB terminology). + */ +const gchar * +eek_xkb_layout_get_keycodes (EekXkbLayout *layout) +{ + EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout); + + g_return_val_if_fail (priv, NULL); + return priv->names.keycodes; +} + +/** + * eek_xkb_layout_get_geometry: + * @layout: an #EekXkbLayout + * + * Get the geometry component name (in the XKB terminology). + */ +const gchar * +eek_xkb_layout_get_geometry (EekXkbLayout *layout) +{ + EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout); + + g_return_val_if_fail (priv, NULL); + return priv->names.geometry; +} + +/** + * eek_xkb_layout_get_symbols: + * @layout: an #EekXkbLayout + * + * Get the symbols component name (in the XKB terminology). + */ +const gchar * +eek_xkb_layout_get_symbols (EekXkbLayout *layout) +{ + EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout); + + g_return_val_if_fail (priv, NULL); + return priv->names.symbols; +} + +static void +get_keyboard (EekXkbLayout *layout) +{ + EekXkbLayoutPrivate *priv = layout->priv; + + if (priv->xkb) + XkbFreeKeyboard (priv->xkb, 0, TRUE); /* free_all = TRUE */ + priv->xkb = NULL; + + if (priv->names.keycodes && + priv->names.geometry && + priv->names.symbols) { + priv->xkb = XkbGetKeyboardByName (priv->display, XkbUseCoreKbd, + &priv->names, 0, + XkbGBN_GeometryMask | + XkbGBN_KeyNamesMask | + XkbGBN_OtherNamesMask | + XkbGBN_ClientSymbolsMask | + XkbGBN_IndicatorMapMask, FALSE); + } else { + priv->xkb = XkbGetKeyboard (priv->display, + XkbGBN_GeometryMask | + XkbGBN_KeyNamesMask | + XkbGBN_OtherNamesMask | + XkbGBN_SymbolsMask | + XkbGBN_IndicatorMapMask, + XkbUseCoreKbd); + get_names (layout); + } + + if (priv->xkb == NULL) { + g_free (priv->names.keycodes); + priv->names.keycodes = NULL; + g_free (priv->names.geometry); + priv->names.geometry = NULL; + g_free (priv->names.symbols); + priv->names.symbols = NULL; + } +} + + +static guint +find_keycode (EekXkbLayout *layout, gchar *key_name) +{ +#define KEYSYM_NAME_MAX_LENGTH 4 + guint keycode; + gint i, j; + XkbKeyNamePtr pkey; + XkbKeyAliasPtr palias; + guint is_name_matched; + gchar *src, *dst; + EekXkbLayoutPrivate *priv = layout->priv; + + if (!priv->xkb) + return EEK_INVALID_KEYCODE; + +#ifdef KBDRAW_DEBUG + printf (" looking for keycode for (%c%c%c%c)\n", + key_name[0], key_name[1], key_name[2], key_name[3]); +#endif + + pkey = priv->xkb->names->keys + priv->xkb->min_key_code; + for (keycode = priv->xkb->min_key_code; + keycode <= priv->xkb->max_key_code; keycode++) { + is_name_matched = 1; + src = key_name; + dst = pkey->name; + for (i = KEYSYM_NAME_MAX_LENGTH; --i >= 0;) { + if ('\0' == *src) + break; + if (*src++ != *dst++) { + is_name_matched = 0; + break; + } + } + if (is_name_matched) { +#ifdef KBDRAW_DEBUG + printf (" found keycode %u\n", keycode); +#endif + return keycode; + } + pkey++; + } + + palias = priv->xkb->names->key_aliases; + for (j = priv->xkb->names->num_key_aliases; --j >= 0;) { + is_name_matched = 1; + src = key_name; + dst = palias->alias; + for (i = KEYSYM_NAME_MAX_LENGTH; --i >= 0;) { + if ('\0' == *src) + break; + if (*src++ != *dst++) { + is_name_matched = 0; + break; + } + } + + if (is_name_matched) { + keycode = find_keycode (layout, palias->real); +#ifdef KBDRAW_DEBUG + printf ("found alias keycode %u\n", keycode); +#endif + return keycode; + } + palias++; + } + + return EEK_INVALID_KEYCODE; +} + +static void +setup_scaling (EekXkbLayout *layout, + gdouble width, + gdouble height) +{ + EekXkbLayoutPrivate *priv = layout->priv; + + g_return_if_fail (priv->xkb); + + g_return_if_fail (priv->xkb->geom->width_mm > 0); + g_return_if_fail (priv->xkb->geom->height_mm > 0); + + if (width * priv->xkb->geom->height_mm < + height * priv->xkb->geom->width_mm) { + priv->scale_numerator = width; + priv->scale_denominator = priv->xkb->geom->width_mm; + } else { + priv->scale_numerator = height; + priv->scale_denominator = priv->xkb->geom->height_mm; + } +} + +static gboolean +initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + EekXkbLayout *layout = EEK_XKB_LAYOUT (initable); + + /* XXX: XkbClientMapMask | XkbIndicatorMapMask | XkbNamesMask | + XkbGeometryMask */ + layout->priv->xkb = XkbGetKeyboard (layout->priv->display, + XkbGBN_GeometryMask | + XkbGBN_KeyNamesMask | + XkbGBN_OtherNamesMask | + XkbGBN_SymbolsMask | + XkbGBN_IndicatorMapMask, + XkbUseCoreKbd); + + if (layout->priv->xkb == NULL) { + g_set_error (error, + EEK_ERROR, + EEK_ERROR_LAYOUT_ERROR, + "can't get initial XKB keyboard configuration"); + return FALSE; + } + + get_names (layout); + get_keyboard (layout); + + if (layout->priv->xkb == NULL) { + g_set_error (error, + EEK_ERROR, + EEK_ERROR_LAYOUT_ERROR, + "can't get XKB keyboard configuration"); + return FALSE; + } + + return TRUE; +} + +static void +initable_iface_init (GInitableIface *initable_iface) +{ + initable_iface->init = initable_init; +} diff --git a/eek/eek-xkb-layout.h b/eek/eek-xkb-layout.h new file mode 100644 index 00000000..2b2791fb --- /dev/null +++ b/eek/eek-xkb-layout.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#if !defined(__EEK_H_INSIDE__) && !defined(EEK_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef EEK_XKB_LAYOUT_H +#define EEK_XKB_LAYOUT_H 1 + +#include +#include +#include "eek-layout.h" + +G_BEGIN_DECLS + +#define EEK_TYPE_XKB_LAYOUT (eek_xkb_layout_get_type()) +#define EEK_XKB_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_XKB_LAYOUT, EekXkbLayout)) +#define EEK_XKB_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_XKB_LAYOUT, EekXkbLayoutClass)) +#define EEK_IS_XKB_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_XKB_LAYOUT)) +#define EEK_IS_XKB_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_XKB_LAYOUT)) +#define EEK_XKB_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_XKB_LAYOUT, EekXkbLayoutClass)) + +typedef struct _EekXkbLayout EekXkbLayout; +typedef struct _EekXkbLayoutClass EekXkbLayoutClass; +typedef struct _EekXkbLayoutPrivate EekXkbLayoutPrivate; + +struct _EekXkbLayout +{ + /*< private >*/ + EekLayout parent; + + EekXkbLayoutPrivate *priv; +}; + +struct _EekXkbLayoutClass +{ + /*< private >*/ + EekLayoutClass parent_class; + + /*< private >*/ + /* padding */ + gpointer pdummy[24]; +}; + +GType eek_xkb_layout_get_type (void) G_GNUC_CONST; +EekLayout *eek_xkb_layout_new (Display *display, + GError **error); + +gboolean eek_xkb_layout_set_names (EekXkbLayout *layout, + XkbComponentNamesRec *names); + +gboolean eek_xkb_layout_set_names_full (EekXkbLayout *layout, + ...); +gboolean eek_xkb_layout_set_names_full_valist + (EekXkbLayout *layout, + va_list var_args); + +gboolean eek_xkb_layout_set_keycodes (EekXkbLayout *layout, + const gchar *keycodes); +gboolean eek_xkb_layout_set_geometry (EekXkbLayout *layout, + const gchar *geometry); +gboolean eek_xkb_layout_set_symbols (EekXkbLayout *layout, + const gchar *symbols); + +const gchar *eek_xkb_layout_get_keycodes (EekXkbLayout *layout); +const gchar *eek_xkb_layout_get_geometry (EekXkbLayout *layout); +const gchar *eek_xkb_layout_get_symbols (EekXkbLayout *layout); + +G_END_DECLS +#endif /* #ifndef EEK_XKB_LAYOUT_H */ diff --git a/eek/eek-xkb.h b/eek/eek-xkb.h new file mode 100644 index 00000000..b810e784 --- /dev/null +++ b/eek/eek-xkb.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#ifndef EEK_XKB_H +#define EEK_XKB_H 1 + +#include "eek.h" +#include "eek-xkb-layout.h" + +#endif /* EEK_XKB_H */ diff --git a/eek/eek-xkl-layout.c b/eek/eek-xkl-layout.c index dfa158cd..da51732e 100644 --- a/eek/eek-xkl-layout.c +++ b/eek/eek-xkl-layout.c @@ -42,7 +42,7 @@ static GInitableIface *parent_initable_iface; static void initable_iface_init (GInitableIface *initable_iface); -G_DEFINE_TYPE_WITH_CODE (EekXklLayout, eek_xkl_layout, EEK_TYPE_LAYOUT, +G_DEFINE_TYPE_WITH_CODE (EekXklLayout, eek_xkl_layout, EEK_TYPE_XKB_LAYOUT, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)); @@ -64,6 +64,22 @@ struct _EekXklLayoutPrivate XklConfigRec *config; }; +/* from gnome-keyboard-properties-xkbpv.c: + * BAD STYLE: Taken from xklavier_private_xkb.h + * Any ideas on architectural improvements are WELCOME + */ +extern gboolean xkl_xkb_config_native_prepare (XklEngine * engine, + const XklConfigRec * data, + XkbComponentNamesPtr + component_names); + +extern void xkl_xkb_config_native_cleanup (XklEngine * engine, + XkbComponentNamesPtr + component_names); + +static gboolean set_xkb_component_names (EekXklLayout *layout, + XklConfigRec *config); + static void eek_xkl_layout_dispose (GObject *object) { @@ -258,7 +274,7 @@ eek_xkl_layout_set_config (EekXklLayout *layout, c = xkl_config_rec_new (); merge_xkl_config_rec (c, priv->config); merge_xkl_config_rec (c, config); - retval = xkl_config_rec_activate (c, priv->engine); + retval = set_xkb_component_names (layout, c); g_object_unref (c); merge_xkl_config_rec (priv->config, config); return retval; @@ -535,6 +551,50 @@ eek_xkl_layout_get_options (EekXklLayout *layout) return g_strdupv (priv->config->options); } +static gboolean +set_xkb_component_names (EekXklLayout *layout, XklConfigRec *config) +{ + EekXklLayoutPrivate *priv = layout->priv; + XkbComponentNamesRec names; + gboolean retval = FALSE; + +#if DEBUG + if (config->layouts) { + gint i; + + fprintf (stderr, "layout = "); + for (i = 0; config->layouts[i] != NULL; i++) + fprintf (stderr, "\"%s\" ", config->layouts[i]); + fputc ('\n', stderr); + } else + fprintf (stderr, "layouts = NULL\n"); + if (config->variants) { + gint i; + + fprintf (stderr, "variant = "); + for (i = 0; config->variants[i]; i++) + fprintf (stderr, "\"%s\" ", config->variants[i]); + fputc ('\n', stderr); + } else + fprintf (stderr, "variants = NULL\n"); + if (config->options) { + gint i; + + fprintf (stderr, "option = "); + for (i = 0; config->options[i]; i++) + fprintf (stderr, "\"%s\" ", config->options[i]); + fputc ('\n', stderr); + } else + fprintf (stderr, "options = NULL\n"); +#endif + + if (xkl_xkb_config_native_prepare (priv->engine, config, &names)) { + retval = eek_xkb_layout_set_names (EEK_XKB_LAYOUT(layout), &names); + xkl_xkb_config_native_cleanup (priv->engine, &names); + } + return retval; +} + /** * eek_xkl_layout_get_option: * @layout: an #EekXklLayout @@ -585,7 +645,7 @@ initable_init (GInitable *initable, return FALSE; } - xkl_config_rec_activate (layout->priv->config, layout->priv->engine); + set_xkb_component_names (layout, layout->priv->config); return TRUE; } diff --git a/eek/eek-xkl-layout.h b/eek/eek-xkl-layout.h index 9fac69c6..966b2918 100644 --- a/eek/eek-xkl-layout.h +++ b/eek/eek-xkl-layout.h @@ -26,7 +26,7 @@ #define EEK_XKL_LAYOUT_H 1 #include -#include "eek-layout.h" +#include "eek-xkb-layout.h" G_BEGIN_DECLS @@ -44,7 +44,7 @@ typedef struct _EekXklLayoutPrivate EekXklLayoutPrivate; struct _EekXklLayout { /*< private >*/ - EekLayout parent; + EekXkbLayout parent; EekXklLayoutPrivate *priv; }; @@ -52,7 +52,7 @@ struct _EekXklLayout struct _EekXklLayoutClass { /*< private >*/ - EekLayoutClass parent_class; + EekXkbLayoutClass parent_class; /*< private >*/ /* padding */