diff --git a/TODO b/TODO index 9a24e9d9..bbff6e62 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,5 @@ - modifier handling - step-by-step scaling of key labels -- GTK+ keyboard elements - matchbox-keyboard layout engine - emit key events using libfakekey or xtest - .spec diff --git a/configure.ac b/configure.ac index ecccb964..c33a52b7 100644 --- a/configure.ac +++ b/configure.ac @@ -34,7 +34,9 @@ PKG_CHECK_MODULES([PANGO], [pango], , [AC_MSG_ERROR([Pango not found])]) PKG_CHECK_MODULES([CLUTTER], [clutter-1.0], , [AC_MSG_ERROR([Clutter not found])]) -PKG_CHECK_MODULES([XKB], [gtk+-2.0 gdk-2.0 x11], , +PKG_CHECK_MODULES([GTK2], [gtk+-2.0 gdk-2.0], , + [AC_MSG_ERROR([GTK2 support not found])]) +PKG_CHECK_MODULES([XKB], [x11], , [AC_MSG_ERROR([XKB support not found])]) GTK_DOC_CHECK([1.14],[--flavour no-tmpl]) @@ -54,5 +56,6 @@ docs/reference/Makefile docs/reference/eek/Makefile eek/eek.pc eek/eek-clutter.pc -eek/eek-xkb.pc]) +eek/eek-xkb.pc +eek/eek-gtk.pc]) AC_OUTPUT diff --git a/eek/Makefile.am b/eek/Makefile.am index dacbf230..73d07660 100644 --- a/eek/Makefile.am +++ b/eek/Makefile.am @@ -16,7 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA -lib_LTLIBRARIES = libeek.la libeek-clutter.la libeek-xkb.la +lib_LTLIBRARIES = libeek.la libeek-clutter.la libeek-xkb.la libeek-gtk.la libeek_la_SOURCES = \ eek-layout.c \ @@ -67,8 +67,23 @@ libeek_xkb_la_SOURCES = \ eek-xkb-layout.c \ $(NULL) -libeek_xkb_la_CFLAGS = $(XKB_CFLAGS) -libeek_xkb_la_LIBADD = libeek.la $(XKB_LIBS) +libeek_xkb_la_CFLAGS = $(GTK2_CFLAGS) $(XKB_CFLAGS) +libeek_xkb_la_LIBADD = libeek.la $(GTK2_LIBS) $(XKB_LIBS) + +libeek_gtk_la_SOURCES = \ + eek-gtk-keyboard.c \ + eek-gtk-keyboard.h \ + eek-gtk-section.c \ + eek-gtk-section.h \ + eek-gtk-key.c \ + eek-gtk-key.h \ + eek-gtk-private.c \ + eek-gtk-private.h \ + eek-gtk.h \ + $(NULL) + +libeek_gtk_la_CFLAGS = $(GTK2_CFLAGS) +libeek_gtk_la_LIBADD = libeek.la $(GTK2_LIBS) eekdir = $(includedir)/eek-$(EEK_API_VERSION)/eek eek_HEADERS = \ @@ -96,7 +111,7 @@ eek-keyname-keysym-labels.h: keyname-keysym-labels.txt $(PYTHON) ./gen-keysym-labels.py keyname_keysym_labels < $< > $@ pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = eek.pc eek-clutter.pc eek-xkb.pc +pkgconfig_DATA = eek.pc eek-clutter.pc eek-xkb.pc eek-gtk.pc DISTCLEANFILES = \ eek-special-keysym-labels.h \ diff --git a/eek/eek-clutter-key.c b/eek/eek-clutter-key.c index cf4754d0..4a37ed5e 100644 --- a/eek/eek-clutter-key.c +++ b/eek/eek-clutter-key.c @@ -193,6 +193,12 @@ eek_key_iface_init (EekKeyIface *iface) static void eek_clutter_key_dispose (GObject *object) { + EekClutterKeyPrivate *priv = EEK_CLUTTER_KEY_GET_PRIVATE(object); + + if (priv->simple) { + g_object_unref (priv->simple); + priv->simple = NULL; + } clutter_group_remove_all (CLUTTER_GROUP(object)); G_OBJECT_CLASS (eek_clutter_key_parent_class)->dispose (object); } @@ -200,9 +206,6 @@ eek_clutter_key_dispose (GObject *object) static void eek_clutter_key_finalize (GObject *object) { - EekClutterKeyPrivate *priv = EEK_CLUTTER_KEY_GET_PRIVATE(object); - - g_object_unref (priv->simple); G_OBJECT_CLASS (eek_clutter_key_parent_class)->finalize (object); } diff --git a/eek/eek-clutter-key.h b/eek/eek-clutter-key.h index 28fb33ac..7c775fe0 100644 --- a/eek/eek-clutter-key.h +++ b/eek/eek-clutter-key.h @@ -50,11 +50,11 @@ struct _EekClutterKeyClass ClutterGroupClass parent_class; }; -GType eek_clutter_key_get_type (void) G_GNUC_CONST; +GType eek_clutter_key_get_type (void) G_GNUC_CONST; ClutterActor *eek_clutter_key_create_texture (EekClutterKey *key); -void eek_clutter_key_set_texture (EekClutterKey *key, - ClutterActor *texture); +void eek_clutter_key_set_texture (EekClutterKey *key, + ClutterActor *texture); G_END_DECLS #endif /* EEK_CLUTTER_KEY_H */ diff --git a/eek/eek-clutter-keyboard.c b/eek/eek-clutter-keyboard.c index 7df85163..291e27f8 100644 --- a/eek/eek-clutter-keyboard.c +++ b/eek/eek-clutter-keyboard.c @@ -185,6 +185,12 @@ eek_keyboard_iface_init (EekKeyboardIface *iface) static void eek_clutter_keyboard_dispose (GObject *object) { + EekClutterKeyboardPrivate *priv = EEK_CLUTTER_KEYBOARD_GET_PRIVATE(object); + + if (priv->simple) { + g_object_unref (priv->simple); + priv->simple = NULL; + } clutter_group_remove_all (CLUTTER_GROUP(object)); G_OBJECT_CLASS (eek_clutter_keyboard_parent_class)->dispose (object); } @@ -192,9 +198,6 @@ eek_clutter_keyboard_dispose (GObject *object) static void eek_clutter_keyboard_finalize (GObject *object) { - EekClutterKeyboardPrivate *priv = EEK_CLUTTER_KEYBOARD_GET_PRIVATE(object); - - g_object_unref (priv->simple); G_OBJECT_CLASS (eek_clutter_keyboard_parent_class)->finalize (object); } diff --git a/eek/eek-clutter-section.c b/eek/eek-clutter-section.c index 579315cb..74c1f93b 100644 --- a/eek/eek-clutter-section.c +++ b/eek/eek-clutter-section.c @@ -253,16 +253,19 @@ eek_section_iface_init (EekSectionIface *iface) static void eek_clutter_section_dispose (GObject *object) { + EekClutterSectionPrivate *priv = EEK_CLUTTER_SECTION_GET_PRIVATE(object); + clutter_group_remove_all (CLUTTER_GROUP(object)); + if (priv->simple) { + g_object_unref (priv->simple); + priv->simple = NULL; + } G_OBJECT_CLASS (eek_clutter_section_parent_class)->dispose (object); } static void eek_clutter_section_finalize (GObject *object) { - EekClutterSectionPrivate *priv = EEK_CLUTTER_SECTION_GET_PRIVATE(object); - - g_object_unref (priv->simple); G_OBJECT_CLASS (eek_clutter_section_parent_class)->finalize (object); } diff --git a/eek/eek-gtk-key.c b/eek/eek-gtk-key.c new file mode 100644 index 00000000..2965e0d8 --- /dev/null +++ b/eek/eek-gtk-key.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2010 Daiki Ueno + * Copyright (C) 2010 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-gtk-key + * @short_description: #EekKey implemented as a #GtkWidget + * + * The #EekClutterKey class implements the #EekKeyIface interface as a + * #GtkWidget. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ +#include "eek-gtk-key.h" +#include "eek-simple-key.h" +#include "eek-keysym.h" + +enum { + PROP_0, + PROP_KEYSYMS, + PROP_COLUMN, + PROP_ROW, + PROP_OUTLINE, + PROP_BOUNDS, + PROP_GROUP, + PROP_LEVEL, + PROP_LAST +}; + +static void eek_key_iface_init (EekKeyIface *iface); + +G_DEFINE_TYPE_WITH_CODE (EekGtkKey, eek_gtk_key, + GTK_TYPE_BUTTON, + G_IMPLEMENT_INTERFACE (EEK_TYPE_KEY, + eek_key_iface_init)); + +#define EEK_GTK_KEY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_GTK_KEY, EekGtkKeyPrivate)) + +struct _EekGtkKeyPrivate +{ + EekSimpleKey *simple; +}; + +static void +eek_gtk_key_real_set_keysyms (EekKey *self, + guint *keysyms, + gint groups, + gint levels) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_key_set_keysyms (EEK_KEY(priv->simple), keysyms, groups, levels); + eek_key_set_keysym_index (EEK_KEY(self), 0, 0); +} + +static gint +eek_gtk_key_real_get_groups (EekKey *self) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + + g_return_val_if_fail (priv, -1); + return eek_key_get_groups (EEK_KEY(priv->simple)); +} + +static guint +eek_gtk_key_real_get_keysym (EekKey *self) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + + g_return_val_if_fail (priv, EEK_INVALID_KEYSYM); + return eek_key_get_keysym (EEK_KEY(priv->simple)); +} + +static void +eek_gtk_key_real_set_index (EekKey *self, + gint column, + gint row) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_key_set_index (EEK_KEY(priv->simple), column, row); +} + +static void +eek_gtk_key_real_get_index (EekKey *self, + gint *column, + gint *row) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_key_get_index (EEK_KEY(priv->simple), column, row); +} + +static void +eek_gtk_key_real_set_outline (EekKey *self, EekOutline *outline) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_key_set_outline (EEK_KEY(priv->simple), outline); +} + +static EekOutline * +eek_gtk_key_real_get_outline (EekKey *self) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + + g_return_val_if_fail (priv, NULL); + return eek_key_get_outline (EEK_KEY(priv->simple)); +} + +static void +eek_gtk_key_real_set_bounds (EekKey *self, EekBounds *bounds) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_key_set_bounds (EEK_KEY(priv->simple), bounds); +} + +static void +eek_gtk_key_real_get_bounds (EekKey *self, + EekBounds *bounds) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + + g_return_if_fail (priv); + return eek_key_get_bounds (EEK_KEY(priv->simple), bounds); +} + +static void +eek_gtk_key_real_set_keysym_index (EekKey *self, + gint group, + gint level) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + guint keysym; + + g_return_if_fail (priv); + eek_key_set_keysym_index (EEK_KEY(priv->simple), group, level); + keysym = eek_key_get_keysym (self); + if (keysym != EEK_INVALID_KEYSYM) { + const gchar *label; + + label = eek_keysym_to_string (keysym); + gtk_button_set_label (GTK_BUTTON(self), label ? label : ""); + } +} + +static void +eek_gtk_key_real_get_keysym_index (EekKey *self, gint *group, gint *level) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(self); + + g_return_if_fail (priv); + return eek_key_get_keysym_index (EEK_KEY(priv->simple), group, level); +} + +static void +eek_key_iface_init (EekKeyIface *iface) +{ + iface->set_keysyms = eek_gtk_key_real_set_keysyms; + iface->get_groups = eek_gtk_key_real_get_groups; + iface->get_keysym = eek_gtk_key_real_get_keysym; + iface->set_index = eek_gtk_key_real_set_index; + iface->get_index = eek_gtk_key_real_get_index; + iface->set_outline = eek_gtk_key_real_set_outline; + iface->get_outline = eek_gtk_key_real_get_outline; + iface->set_bounds = eek_gtk_key_real_set_bounds; + iface->get_bounds = eek_gtk_key_real_get_bounds; + iface->set_keysym_index = eek_gtk_key_real_set_keysym_index; + iface->get_keysym_index = eek_gtk_key_real_get_keysym_index; +} + +static void +eek_gtk_key_dispose (GObject *object) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(object); + + if (priv->simple) { + g_object_unref (priv->simple); + priv->simple = NULL; + } + G_OBJECT_CLASS (eek_gtk_key_parent_class)->dispose (object); +} + +static void +eek_gtk_key_finalize (GObject *object) +{ + G_OBJECT_CLASS (eek_gtk_key_parent_class)->finalize (object); +} + +static void +eek_gtk_key_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(object); + EekKeysymMatrix *matrix; + + g_return_if_fail (priv); + switch (prop_id) { + case PROP_KEYSYMS: + matrix = g_value_get_boxed (value); + eek_key_set_keysyms (EEK_KEY(object), + matrix->data, + matrix->num_groups, + matrix->num_levels); + break; + case PROP_BOUNDS: + case PROP_OUTLINE: + case PROP_COLUMN: + case PROP_GROUP: + case PROP_ROW: + case PROP_LEVEL: + g_object_set_property (G_OBJECT(priv->simple), + g_param_spec_get_name (pspec), + value); + break; + default: + g_object_set_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +eek_gtk_key_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EekGtkKeyPrivate *priv = EEK_GTK_KEY_GET_PRIVATE(object); + + g_return_if_fail (priv); + switch (prop_id) { + case PROP_BOUNDS: + case PROP_KEYSYMS: + case PROP_COLUMN: + case PROP_ROW: + case PROP_OUTLINE: + case PROP_GROUP: + case PROP_LEVEL: + g_object_get_property (G_OBJECT(priv->simple), + g_param_spec_get_name (pspec), + value); + break; + default: + g_object_get_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +eek_gtk_key_class_init (EekGtkKeyClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (gobject_class, + sizeof (EekGtkKeyPrivate)); + + gobject_class->set_property = eek_gtk_key_set_property; + gobject_class->get_property = eek_gtk_key_get_property; + gobject_class->finalize = eek_gtk_key_finalize; + gobject_class->dispose = eek_gtk_key_dispose; + + g_object_class_override_property (gobject_class, + PROP_KEYSYMS, + "keysyms"); + g_object_class_override_property (gobject_class, + PROP_COLUMN, + "column"); + g_object_class_override_property (gobject_class, + PROP_ROW, + "row"); + g_object_class_override_property (gobject_class, + PROP_OUTLINE, + "outline"); + g_object_class_override_property (gobject_class, + PROP_BOUNDS, + "bounds"); + g_object_class_override_property (gobject_class, + PROP_GROUP, + "group"); + g_object_class_override_property (gobject_class, + PROP_LEVEL, + "level"); +} + +static void +eek_gtk_key_init (EekGtkKey *self) +{ + EekGtkKeyPrivate *priv; + + priv = self->priv = EEK_GTK_KEY_GET_PRIVATE(self); + priv->simple = g_object_new (EEK_TYPE_SIMPLE_KEY, NULL); +} diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c new file mode 100644 index 00000000..6f60d115 --- /dev/null +++ b/eek/eek-gtk-keyboard.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2010 Daiki Ueno + * Copyright (C) 2010 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-gtk-keyboard + * @short_description: #EekKeyboard implemented as a #GtkWidget + * + * The #EekGtkKeyboard class implements the #EekKeyboardIface + * interface as a #GtkWidget. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "eek-gtk-keyboard.h" +#include "eek-gtk-private.h" +#include "eek-simple-keyboard.h" + +enum { + PROP_0, + PROP_BOUNDS, + PROP_LAST +}; + +static void eek_keyboard_iface_init (EekKeyboardIface *iface); + +G_DEFINE_TYPE_WITH_CODE (EekGtkKeyboard, eek_gtk_keyboard, + GTK_TYPE_VBOX, + G_IMPLEMENT_INTERFACE (EEK_TYPE_KEYBOARD, + eek_keyboard_iface_init)); + +#define EEK_GTK_KEYBOARD_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_GTK_KEYBOARD, EekGtkKeyboardPrivate)) + + +struct _EekGtkKeyboardPrivate +{ + EekSimpleKeyboard *simple; + gint group; + gint level; +}; + +static void +eek_gtk_keyboard_real_set_bounds (EekKeyboard *self, + EekBounds *bounds) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_keyboard_set_bounds (EEK_KEYBOARD(priv->simple), bounds); +} + +static void +eek_gtk_keyboard_real_get_bounds (EekKeyboard *self, + EekBounds *bounds) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); + + g_return_if_fail (priv); + return eek_keyboard_get_bounds (EEK_KEYBOARD(priv->simple), bounds); +} + +struct keysym_index { + gint group; + gint level; +}; + +static void +key_set_keysym_index (gpointer self, gpointer user_data) +{ + struct keysym_index *ki; + + g_return_if_fail (EEK_IS_KEY(self)); + eek_key_set_keysym_index (self, ki->group, ki->level); +} + +static void +section_set_keysym_index (gpointer self, gpointer user_data) +{ + EekGtkCallbackData data; + + data.func = key_set_keysym_index; + data.user_data = user_data; + + g_return_if_fail (EEK_IS_GTK_SECTION(self)); + gtk_container_foreach (GTK_CONTAINER(self), eek_gtk_callback, &data); +} + +static void +eek_gtk_keyboard_real_set_keysym_index (EekKeyboard *self, + gint group, + gint level) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); + EekGtkCallbackData data; + struct keysym_index ki; + + g_return_if_fail (priv); + priv->group = group; + priv->level = level; + + ki.group = group; + ki.level = level; + + data.func = section_set_keysym_index; + data.user_data = &ki; + + gtk_container_foreach (GTK_CONTAINER(self), eek_gtk_callback, &data); +} + +static void +eek_gtk_keyboard_real_get_keysym_index (EekKeyboard *self, + gint *group, + gint *level) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); + + g_return_if_fail (priv); + *group = priv->group; + *level = priv->level; +} + +static EekSection * +eek_gtk_keyboard_real_create_section (EekKeyboard *self, + const gchar *name, + gint angle, + EekBounds *bounds) +{ + EekSection *section; + + g_return_if_fail (EEK_IS_GTK_KEYBOARD(self)); + + section = g_object_new (EEK_TYPE_GTK_SECTION, + "name", name, + "angle", angle, + "bounds", bounds, + NULL); + + gtk_box_pack_start (GTK_BOX(self), GTK_WIDGET(section), FALSE, FALSE, 0); + return section; +} + +static void +eek_gtk_keyboard_real_foreach_section (EekKeyboard *self, + GFunc func, + gpointer user_data) +{ + EekGtkCallbackData data; + + g_return_if_fail (EEK_IS_GTK_KEYBOARD(self)); + + data.func = func; + data.user_data = user_data; + + gtk_container_foreach (GTK_CONTAINER(self), + eek_gtk_callback, + &data); +} + +static void +eek_gtk_keyboard_real_set_layout (EekKeyboard *self, + EekLayout *layout) +{ + g_return_if_fail (EEK_IS_KEYBOARD(self)); + g_return_if_fail (EEK_IS_LAYOUT(layout)); + + EEK_LAYOUT_GET_CLASS(layout)->apply_to_keyboard (layout, self); + if (g_object_is_floating (layout)) + g_object_unref (layout); +} + +static void +eek_keyboard_iface_init (EekKeyboardIface *iface) +{ + iface->set_bounds = eek_gtk_keyboard_real_set_bounds; + iface->get_bounds = eek_gtk_keyboard_real_get_bounds; + iface->set_keysym_index = eek_gtk_keyboard_real_set_keysym_index; + iface->get_keysym_index = eek_gtk_keyboard_real_get_keysym_index; + iface->create_section = eek_gtk_keyboard_real_create_section; + iface->foreach_section = eek_gtk_keyboard_real_foreach_section; + iface->set_layout = eek_gtk_keyboard_real_set_layout; +} + +static void +eek_gtk_keyboard_dispose (GObject *object) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(object); + + if (priv->simple) { + g_object_unref (priv->simple); + priv->simple = NULL; + } + G_OBJECT_CLASS (eek_gtk_keyboard_parent_class)->dispose (object); +} + +static void +eek_gtk_keyboard_finalize (GObject *object) +{ + G_OBJECT_CLASS (eek_gtk_keyboard_parent_class)->finalize (object); +} + +static void +eek_gtk_keyboard_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(object); + + g_return_if_fail (priv); + switch (prop_id) { + case PROP_BOUNDS: + eek_keyboard_set_bounds (EEK_KEYBOARD(object), + g_value_get_boxed (value)); + break; + default: + g_object_set_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +eek_gtk_keyboard_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(object); + + g_return_if_fail (priv); + switch (prop_id) { + case PROP_BOUNDS: + eek_keyboard_set_bounds (EEK_KEYBOARD(object), + g_value_get_boxed (value)); + break; + default: + g_object_set_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (gobject_class, + sizeof (EekGtkKeyboardPrivate)); + + gobject_class->set_property = eek_gtk_keyboard_set_property; + gobject_class->get_property = eek_gtk_keyboard_get_property; + gobject_class->finalize = eek_gtk_keyboard_finalize; + gobject_class->dispose = eek_gtk_keyboard_dispose; + + g_object_class_override_property (gobject_class, + PROP_BOUNDS, + "bounds"); +} + +static void +eek_gtk_keyboard_init (EekGtkKeyboard *self) +{ + EekGtkKeyboardPrivate *priv; + + priv = self->priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); + priv->simple = g_object_new (EEK_TYPE_SIMPLE_KEYBOARD, NULL); + priv->group = priv->level = 0; +} + +/** + * eek_gtk_keyboard_new: + * + * Create a new #EekGtkKeyboard. + */ +EekKeyboard* +eek_gtk_keyboard_new (void) +{ + return g_object_new (EEK_TYPE_GTK_KEYBOARD, NULL); +} diff --git a/eek/eek-gtk-private.c b/eek/eek-gtk-private.c new file mode 100644 index 00000000..0c23db9e --- /dev/null +++ b/eek/eek-gtk-private.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010 Daiki Ueno + * Copyright (C) 2010 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 + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "eek-gtk-private.h" + +void +eek_gtk_callback (GtkWidget *widget, gpointer user_data) +{ + EekGtkCallbackData *data = user_data; + data->func (widget, data->user_data); +} diff --git a/eek/eek-gtk-section.c b/eek/eek-gtk-section.c new file mode 100644 index 00000000..21fb388b --- /dev/null +++ b/eek/eek-gtk-section.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2010 Daiki Ueno + * Copyright (C) 2010 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-gtk-section + * @short_description: #EekSection implemented as a #GtkWidget + * + * The #EekGtkSection class implements the #EekSectionIface + * interface as a #GtkWidget. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ +#include "eek-gtk-section.h" +#include "eek-gtk-private.h" +#include "eek-simple-section.h" +#include + +enum { + PROP_0, + PROP_COLUMNS, + PROP_ROWS, + PROP_ANGLE, + PROP_BOUNDS, + PROP_LAST +}; + +static void eek_section_iface_init (EekSectionIface *iface); + +G_DEFINE_TYPE_WITH_CODE (EekGtkSection, eek_gtk_section, + GTK_TYPE_VBOX, + G_IMPLEMENT_INTERFACE (EEK_TYPE_SECTION, + eek_section_iface_init)); + +#define EEK_GTK_SECTION_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_GTK_SECTION, EekGtkSectionPrivate)) + +struct _EekGtkSectionPrivate +{ + EekSimpleSection *simple; + GtkWidget **rows; /* GtkHBox * */ +}; + +static void +eek_gtk_section_real_set_rows (EekSection *self, + gint rows) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_section_set_rows (EEK_SECTION(priv->simple), rows); + priv->rows = g_slice_alloc0 (sizeof(GtkHBox *) * rows); +} + +static gint +eek_gtk_section_real_get_rows (EekSection *self) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + + g_return_val_if_fail (priv, -1); + return eek_section_get_rows (EEK_SECTION(priv->simple)); +} + +static void +eek_gtk_section_real_set_columns (EekSection *self, + gint row, + gint columns) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_section_set_columns (EEK_SECTION(priv->simple), row, columns); +} + +static gint +eek_gtk_section_real_get_columns (EekSection *self, + gint row) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + + g_return_val_if_fail (priv, -1); + return eek_section_get_columns (EEK_SECTION(priv->simple), row); +} + +static void +eek_gtk_section_real_set_orientation (EekSection *self, + gint row, + EekOrientation orientation) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_section_set_orientation (EEK_SECTION(priv->simple), row, orientation); +} + +static EekOrientation +eek_gtk_section_real_get_orientation (EekSection *self, + gint row) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + + g_return_val_if_fail (priv, EEK_ORIENTATION_INVALID); + return eek_section_get_orientation (EEK_SECTION(priv->simple), row); +} + +static void +eek_gtk_section_real_set_angle (EekSection *self, + gint angle) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_section_set_angle (EEK_SECTION(priv->simple), angle); +} + +static gint +eek_gtk_section_real_get_angle (EekSection *self) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + + g_return_val_if_fail (priv, 0); + eek_section_get_angle (EEK_SECTION(priv->simple)); +} + +static void +eek_gtk_section_real_set_bounds (EekSection *self, + EekBounds *bounds) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + + g_return_if_fail (priv); + eek_section_set_bounds (EEK_SECTION(priv->simple), bounds); +} + +static void +eek_gtk_section_real_get_bounds (EekSection *self, + EekBounds *bounds) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + + g_return_if_fail (priv); + return eek_section_get_bounds (EEK_SECTION(priv->simple), bounds); +} + +static EekKey * +eek_gtk_section_real_create_key (EekSection *self, + const gchar *name, + guint *keysyms, + gint num_groups, + gint num_levels, + gint column, + gint row, + EekOutline *outline, + EekBounds *bounds) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + EekKey *key; + EekKeysymMatrix matrix; + gint columns, rows; + + g_return_val_if_fail (priv, NULL); + + rows = eek_section_get_rows (self); + g_return_val_if_fail (0 <= row && row < rows, NULL); + columns = eek_section_get_columns (self, row); + g_return_val_if_fail (column < columns, NULL); + + matrix.data = keysyms; + matrix.num_groups = num_groups; + matrix.num_levels = num_levels; + key = g_object_new (EEK_TYPE_GTK_KEY, + "name", name, + "keysyms", &matrix, + "column", column, + "row", row, + "outline", outline, + "bounds", bounds, + NULL); + g_return_val_if_fail (key, NULL); + + if (priv->rows[row] == NULL) { + priv->rows[row] = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX(self), priv->rows[row], + FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX(self), priv->rows[row], row); + } + gtk_box_pack_start (GTK_BOX(priv->rows[row]), GTK_WIDGET(key), + FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX(priv->rows[row]), GTK_WIDGET(key), column); + return key; +} + +static void +eek_gtk_section_real_foreach_key (EekSection *self, + GFunc func, + gpointer user_data) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(self); + EekGtkCallbackData data; + gint i, num_rows; + + g_return_if_fail (priv); + + data.func = func; + data.user_data = user_data; + + num_rows = eek_section_get_rows (self); + for (i = 0; i < num_rows; i++) + gtk_container_foreach (GTK_CONTAINER(priv->rows[i]), + eek_gtk_callback, + &data); +} + +static void +eek_section_iface_init (EekSectionIface *iface) +{ + iface->set_rows = eek_gtk_section_real_set_rows; + iface->get_rows = eek_gtk_section_real_get_rows; + iface->set_columns = eek_gtk_section_real_set_columns; + iface->get_columns = eek_gtk_section_real_get_columns; + iface->set_orientation = eek_gtk_section_real_set_orientation; + iface->get_orientation = eek_gtk_section_real_get_orientation; + iface->set_angle = eek_gtk_section_real_set_angle; + iface->get_angle = eek_gtk_section_real_get_angle; + iface->set_bounds = eek_gtk_section_real_set_bounds; + iface->get_bounds = eek_gtk_section_real_get_bounds; + iface->create_key = eek_gtk_section_real_create_key; + iface->foreach_key = eek_gtk_section_real_foreach_key; +} + +static void +eek_gtk_section_dispose (GObject *object) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(object); + gint i, num_rows; + + num_rows = eek_section_get_rows (EEK_SECTION(object)); + for (i = 0; i < num_rows; i++) + if (priv->rows[i]) { + g_object_unref (priv->rows[i]); + priv->rows[i] = NULL; + } + if (priv->simple) { + g_object_unref (priv->simple); + priv->simple = NULL; + } + G_OBJECT_CLASS (eek_gtk_section_parent_class)->dispose (object); +} + +static void +eek_gtk_section_finalize (GObject *object) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(object); + + g_slice_free (GtkWidget *, priv->rows); + G_OBJECT_CLASS (eek_gtk_section_parent_class)->finalize (object); +} + +static void +eek_gtk_section_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(object); + + switch (prop_id) { + case PROP_ANGLE: + eek_section_set_angle (EEK_SECTION(object), + g_value_get_int (value)); + break; + case PROP_BOUNDS: + eek_section_set_bounds (EEK_SECTION(object), + g_value_get_boxed (value)); + break; + default: + g_object_set_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +eek_gtk_section_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EekGtkSectionPrivate *priv = EEK_GTK_SECTION_GET_PRIVATE(object); + EekBounds bounds; + + switch (prop_id) { + case PROP_ANGLE: + g_value_set_int (value, eek_section_get_angle (EEK_SECTION(object))); + break; + case PROP_BOUNDS: + eek_section_get_bounds (EEK_SECTION(object), &bounds); + g_value_set_boxed (value, &bounds); + break; + default: + g_object_get_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +eek_gtk_section_class_init (EekGtkSectionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (gobject_class, sizeof (EekGtkSectionPrivate)); + + gobject_class->set_property = eek_gtk_section_set_property; + gobject_class->get_property = eek_gtk_section_get_property; + gobject_class->finalize = eek_gtk_section_finalize; + gobject_class->dispose = eek_gtk_section_dispose; + + g_object_class_override_property (gobject_class, + PROP_ANGLE, + "angle"); + g_object_class_override_property (gobject_class, + PROP_BOUNDS, + "bounds"); +} + +static void +eek_gtk_section_init (EekGtkSection *self) +{ + EekGtkSectionPrivate *priv; + + priv = self->priv = EEK_GTK_SECTION_GET_PRIVATE (self); + priv->simple = g_object_new (EEK_TYPE_SIMPLE_SECTION, NULL); + priv->rows = NULL; +} diff --git a/eek/eek-gtk.pc.in b/eek/eek-gtk.pc.in new file mode 100644 index 00000000..a7496fa1 --- /dev/null +++ b/eek/eek-gtk.pc.in @@ -0,0 +1,30 @@ +# Copyright (C) 2010 Daiki Ueno +# Copyright (C) 2010 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: EEK-GTK +Description: A Library to Create Keyboard-like UI (GTK Support) +URL: http://github.com/ueno/eek +Version: @VERSION@ +Libs: -L${libdir} -leek -leek-gtk +Libs.private: @GTK2_LIBS@ +Cflags: -I${includedir}/eek-@EEK_API_VERSION@ diff --git a/eek/eek-xkb.pc.in b/eek/eek-xkb.pc.in index 9dd84bcd..b94e64be 100644 --- a/eek/eek-xkb.pc.in +++ b/eek/eek-xkb.pc.in @@ -26,5 +26,5 @@ Description: A Library to Create Keyboard-like UI (XKB Support) URL: http://github.com/ueno/eek Version: @VERSION@ Libs: -L${libdir} -leek -leek-xkb -Libs.private: @XKB_LIBS@ +Libs.private: @GTK2_LIBS@ @XKB_LIBS@ Cflags: -I${includedir}/eek-@EEK_API_VERSION@ diff --git a/examples/Makefile.am b/examples/Makefile.am index 48a27d09..d4e7bb68 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -16,6 +16,9 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA -noinst_PROGRAMS = eek-clutter-xkb-test +noinst_PROGRAMS = eek-clutter-xkb-test eek-gtk-xkb-test eek_clutter_xkb_test_CFLAGS = -I$(top_srcdir) $(GOBJECT2_CFLAGS) $(CLUTTER_CFLAGS) $(XKB_CFLAGS) eek_clutter_xkb_test_LDFLAGS = $(top_builddir)/eek/libeek.la $(top_builddir)/eek/libeek-xkb.la $(top_builddir)/eek/libeek-clutter.la $(GOBJECT2_LIBS) $(CLUTTER_LIBS) $(XKB_LIBS) + +eek_gtk_xkb_test_CFLAGS = -I$(top_srcdir) $(GOBJECT2_CFLAGS) $(GTK2_CFLAGS) $(XKB_CFLAGS) +eek_gtk_xkb_test_LDFLAGS = $(top_builddir)/eek/libeek.la $(top_builddir)/eek/libeek-xkb.la $(top_builddir)/eek/libeek-gtk.la $(GOBJECT2_LIBS) $(GTK2_LIBS) $(XKB_LIBS) diff --git a/examples/eek-gtk-xkb-test.c b/examples/eek-gtk-xkb-test.c new file mode 100644 index 00000000..b71b1fcc --- /dev/null +++ b/examples/eek-gtk-xkb-test.c @@ -0,0 +1,70 @@ +#include "eek/eek-gtk.h" +#include "eek/eek-xkb.h" +#include +#include +#include + +static gchar *symbols = NULL; +static gchar *keycodes = NULL; +static gchar *geometry = NULL; + +static const GOptionEntry options[] = { + {"symbols", '\0', 0, G_OPTION_ARG_STRING, &symbols, + "Symbols component of the keyboard. If you omit this option, it is " + "obtained from the X server; that is, the keyboard that is currently " + "configured is drawn. Examples: --symbols=us or " + "--symbols=us(pc104)+iso9995-3+group(switch)+ctrl(nocaps)", NULL}, + {"keycodes", '\0', 0, G_OPTION_ARG_STRING, &keycodes, + "Keycodes component of the keyboard. If you omit this option, it is " + "obtained from the X server; that is, the keyboard that is currently" + " configured is drawn. Examples: --keycodes=xfree86+aliases(qwerty)", + NULL}, + {"geometry", '\0', 0, G_OPTION_ARG_STRING, &geometry, + "Geometry xkb component. If you omit this option, it is obtained from the" + " X server; that is, the keyboard that is currently configured is drawn. " + "Example: --geometry=kinesis", NULL}, + {NULL}, +}; + +gfloat window_width, window_height; + +int +main (int argc, char *argv[]) +{ + EekKeyboard *keyboard; + EekLayout *layout; + GtkWidget *window; + GOptionContext *context; + + context = g_option_context_new ("test-xkb-gtk"); + g_option_context_add_main_entries (context, options, NULL); + g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_free (context); + + gtk_init (&argc, &argv); + + layout = eek_xkb_layout_new (keycodes, geometry, symbols); + if (layout == NULL) { + fprintf (stderr, "Failed to create layout\n"); + exit(1); + } + g_object_ref_sink (layout); + + keyboard = eek_gtk_keyboard_new (); + if (keyboard == NULL) { + g_object_unref (layout); + fprintf (stderr, "Failed to create keyboard\n"); + exit(1); + } + g_object_ref_sink (keyboard); + + eek_keyboard_set_layout (keyboard, layout); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_add (GTK_CONTAINER(window), GTK_WIDGET(keyboard)); + + gtk_widget_show_all (window); + gtk_main (); + + return 0; +}