diff --git a/eek/eek-container.c b/eek/eek-container.c index 6d0a3976..4bc9d2ed 100644 --- a/eek/eek-container.c +++ b/eek/eek-container.c @@ -172,24 +172,14 @@ eek_container_dispose (GObject *object) EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(object); GSList *head; - for (head = priv->children; head; head = g_slist_next (head)) { - if (head->data) { - g_object_unref (head->data); - head->data = NULL; - } + for (head = priv->children; head; head = priv->children) { + g_object_unref (head->data); + priv->children = g_slist_next (head); + g_slist_free1 (head); } G_OBJECT_CLASS(eek_container_parent_class)->dispose (object); } -static void -eek_container_finalize (GObject *object) -{ - EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(object); - - g_slist_free (priv->children); - G_OBJECT_CLASS(eek_container_parent_class)->finalize (object); -} - static void eek_container_class_init (EekContainerClass *klass) { @@ -207,7 +197,6 @@ eek_container_class_init (EekContainerClass *klass) klass->child_added = NULL; klass->child_removed = NULL; - gobject_class->finalize = eek_container_finalize; gobject_class->dispose = eek_container_dispose; /** diff --git a/eekboard/Makefile.am b/eekboard/Makefile.am index 8448904e..4842a586 100644 --- a/eekboard/Makefile.am +++ b/eekboard/Makefile.am @@ -18,8 +18,13 @@ lib_LTLIBRARIES = libeekboard.la -libeekboard_headers = eekboard.h eekboard-keyboard.h -libeekboard_sources = eekboard-keyboard.c +libeekboard_headers = \ + eekboard.h \ + eekboard-server.h \ + eekboard-context.h +libeekboard_sources = \ + eekboard-server.c \ + eekboard-context.c libeekboard_la_SOURCES = $(libeekboard_sources) libeekboard_la_CFLAGS = -I$(top_srcdir) $(GIO2_CFLAGS) diff --git a/eekboard/eekboard-context.c b/eekboard/eekboard-context.c new file mode 100644 index 00000000..bcbedd70 --- /dev/null +++ b/eekboard/eekboard-context.c @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * + * 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 . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "eekboard/eekboard-context.h" + +enum { + ENABLED, + DISABLED, + KEY_PRESSED, + KEY_RELEASED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0, }; + +G_DEFINE_TYPE (EekboardContext, eekboard_context, G_TYPE_DBUS_PROXY); + +#define EEKBOARD_CONTEXT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_CONTEXT, EekboardContextPrivate)) + +struct _EekboardContextPrivate +{ + EekKeyboard *keyboard; + gboolean keyboard_visible; + gboolean enabled; +}; + +static void +eekboard_context_real_g_signal (GDBusProxy *self, + const gchar *sender_name, + const gchar *signal_name, + GVariant *parameters) +{ + EekboardContext *context = EEKBOARD_CONTEXT (self); + EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE (context); + + if (g_strcmp0 (signal_name, "Enabled") == 0) { + g_signal_emit_by_name (context, "enabled"); + return; + } + + if (g_strcmp0 (signal_name, "Disabled") == 0) { + g_signal_emit_by_name (context, "disabled"); + return; + } + + if (g_strcmp0 (signal_name, "KeyPressed") == 0) { + guint keycode; + g_variant_get (parameters, "(u)", &keycode); + g_signal_emit_by_name (context, "key-pressed", keycode); + return; + } + + if (g_strcmp0 (signal_name, "KeyReleased") == 0) { + guint keycode; + g_variant_get (parameters, "(u)", &keycode); + g_signal_emit_by_name (context, "key-released", keycode); + return; + } + + if (g_strcmp0 (signal_name, "KeyboardVisibilityChanged") == 0) { + g_variant_get (parameters, "(b)", &priv->keyboard_visible); + return; + } + + g_return_if_reached (); +} + +static void +eekboard_context_real_enabled (EekboardContext *self) +{ + EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE(self); + priv->enabled = TRUE; +} + +static void +eekboard_context_real_disabled (EekboardContext *self) +{ + EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE(self); + priv->enabled = FALSE; +} + +static void +eekboard_context_real_key_pressed (EekboardContext *self, + guint keycode) +{ + EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE(self); + if (priv->keyboard) { + EekKey *key = eek_keyboard_find_key_by_keycode (priv->keyboard, + keycode); + g_signal_emit_by_name (key, "pressed"); + } +} + +static void +eekboard_context_real_key_released (EekboardContext *self, + guint keycode) +{ + EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE(self); + if (priv->keyboard) { + EekKey *key = eek_keyboard_find_key_by_keycode (priv->keyboard, + keycode); + g_signal_emit_by_name (key, "released"); + } +} + +static void +eekboard_context_dispose (GObject *self) +{ + EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE (self); + + if (priv->keyboard) { + g_object_unref (priv->keyboard); + priv->keyboard = NULL; + } +} + +static void +eekboard_context_class_init (EekboardContextClass *klass) +{ + GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (gobject_class, + sizeof (EekboardContextPrivate)); + + klass->enabled = eekboard_context_real_enabled; + klass->disabled = eekboard_context_real_disabled; + klass->key_pressed = eekboard_context_real_key_pressed; + klass->key_released = eekboard_context_real_key_released; + + proxy_class->g_signal = eekboard_context_real_g_signal; + + gobject_class->dispose = eekboard_context_dispose; + + signals[ENABLED] = + g_signal_new ("enabled", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekboardContextClass, enabled), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + signals[DISABLED] = + g_signal_new ("disabled", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekboardContextClass, disabled), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + signals[KEY_PRESSED] = + g_signal_new ("key-pressed", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekboardContextClass, key_pressed), + NULL, + NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, + 1, + G_TYPE_UINT); + + signals[KEY_RELEASED] = + g_signal_new ("key-released", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekboardContextClass, key_released), + NULL, + NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, + 1, + G_TYPE_UINT); +} + +static void +eekboard_context_init (EekboardContext *self) +{ + EekboardContextPrivate *priv; + + priv = self->priv = EEKBOARD_CONTEXT_GET_PRIVATE(self); + priv->keyboard = NULL; + priv->keyboard_visible = FALSE; + priv->enabled = FALSE; +} + +EekboardContext * +eekboard_context_new (GDBusConnection *connection, + const gchar *object_path, + GCancellable *cancellable) +{ + GInitable *initable; + GError *error; + + g_assert (object_path != NULL); + g_assert (G_IS_DBUS_CONNECTION(connection)); + + error = NULL; + initable = + g_initable_new (EEKBOARD_TYPE_CONTEXT, + cancellable, + &error, + "g-name", "com.redhat.Eekboard.Server", + "g-connection", connection, + "g-interface-name", "com.redhat.Eekboard.Context", + "g-object-path", object_path, + NULL); + if (initable != NULL) + return EEKBOARD_CONTEXT (initable); + return NULL; +} + +static void +context_async_ready_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY(source_object), + res, + &error); + if (result) + g_variant_unref (result); +} + +void +eekboard_context_set_keyboard (EekboardContext *context, + EekKeyboard *keyboard, + GCancellable *cancellable) +{ + EekboardContextPrivate *priv; + GVariant *variant; + + g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); + g_return_if_fail (EEK_IS_KEYBOARD(keyboard)); + + priv = EEKBOARD_CONTEXT_GET_PRIVATE(context); + if (priv->keyboard) + g_object_unref (priv->keyboard); + priv->keyboard = g_object_ref (keyboard); + + variant = eek_serializable_serialize (EEK_SERIALIZABLE(priv->keyboard)); + g_dbus_proxy_call (G_DBUS_PROXY(context), + "SetKeyboard", + g_variant_new ("(v)", variant), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + context_async_ready_callback, + NULL); + g_variant_unref (variant); +} + +void +eekboard_context_set_group (EekboardContext *context, + gint group, + GCancellable *cancellable) +{ + EekboardContextPrivate *priv; + + g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); + + priv = EEKBOARD_CONTEXT_GET_PRIVATE (context); + + g_return_if_fail (priv->keyboard); + g_return_if_fail (group >= 0); + + eek_keyboard_set_group (priv->keyboard, group); + g_dbus_proxy_call (G_DBUS_PROXY(context), + "SetGroup", + g_variant_new ("(i)", group), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + context_async_ready_callback, + NULL); +} + +void +eekboard_context_show_keyboard (EekboardContext *context, + GCancellable *cancellable) +{ + EekboardContextPrivate *priv; + + g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); + + priv = EEKBOARD_CONTEXT_GET_PRIVATE (context); + if (!priv->enabled) + return; + + g_dbus_proxy_call (G_DBUS_PROXY(context), + "ShowKeyboard", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + context_async_ready_callback, + NULL); +} + +void +eekboard_context_hide_keyboard (EekboardContext *context, + GCancellable *cancellable) +{ + EekboardContextPrivate *priv; + + g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); + + priv = EEKBOARD_CONTEXT_GET_PRIVATE (context); + if (!priv->enabled) + return; + + g_dbus_proxy_call (G_DBUS_PROXY(context), + "HideKeyboard", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + context_async_ready_callback, + NULL); +} + +void +eekboard_context_press_key (EekboardContext *context, + guint keycode, + GCancellable *cancellable) +{ + EekboardContextPrivate *priv; + + g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); + + priv = EEKBOARD_CONTEXT_GET_PRIVATE (context); + if (!priv->enabled) + return; + + g_dbus_proxy_call (G_DBUS_PROXY(context), + "PressKey", + g_variant_new ("(u)", keycode), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + context_async_ready_callback, + NULL); +} + +void +eekboard_context_release_key (EekboardContext *context, + guint keycode, + GCancellable *cancellable) +{ + EekboardContextPrivate *priv; + + g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); + + priv = EEKBOARD_CONTEXT_GET_PRIVATE (context); + if (!priv->enabled) + return; + + g_dbus_proxy_call (G_DBUS_PROXY(context), + "ReleaseKey", + g_variant_new ("(u)", keycode), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + context_async_ready_callback, + NULL); +} + +gboolean +eekboard_context_is_keyboard_visible (EekboardContext *context) +{ + EekboardContextPrivate *priv; + + g_assert (EEKBOARD_IS_CONTEXT(context)); + + priv = EEKBOARD_CONTEXT_GET_PRIVATE (context); + return priv->enabled && priv->keyboard_visible; +} + +void +eekboard_context_set_enabled (EekboardContext *context, + gboolean enabled) +{ + EekboardContextPrivate *priv; + + g_assert (EEKBOARD_IS_CONTEXT(context)); + + priv = EEKBOARD_CONTEXT_GET_PRIVATE (context); + priv->enabled = enabled; +} diff --git a/eekboard/eekboard-context.h b/eekboard/eekboard-context.h new file mode 100644 index 00000000..d5af3d96 --- /dev/null +++ b/eekboard/eekboard-context.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * + * 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 . + */ +#ifndef EEKBOARD_CONTEXT_H +#define EEKBOARD_CONTEXT_H 1 + +#include +#include "eek/eek.h" + +G_BEGIN_DECLS + +#define EEKBOARD_TYPE_CONTEXT (eekboard_context_get_type()) +#define EEKBOARD_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_CONTEXT, EekboardContext)) +#define EEKBOARD_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_CONTEXT, EekboardContextClass)) +#define EEKBOARD_IS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_CONTEXT)) +#define EEKBOARD_IS_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CONTEXT)) +#define EEKBOARD_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CONTEXT, EekboardContextClass)) + +typedef struct _EekboardContext EekboardContext; +typedef struct _EekboardContextClass EekboardContextClass; +typedef struct _EekboardContextPrivate EekboardContextPrivate; + +struct _EekboardContext { + GDBusProxy parent; + + EekboardContextPrivate *priv; +}; + +struct _EekboardContextClass { + GDBusProxyClass parent_class; + + void (*enabled) (EekboardContext *self); + void (*disabled) (EekboardContext *self); + void (*key_pressed) (EekboardContext *self, + guint keycode); + void (*key_released) (EekboardContext *self, + guint keycode); +}; + +GType eekboard_context_get_type (void) G_GNUC_CONST; + +EekboardContext *eekboard_context_new (GDBusConnection *connection, + const gchar *object_path, + GCancellable *cancellable); +void eekboard_context_set_keyboard (EekboardContext *context, + EekKeyboard *keyboard, + GCancellable *cancellable); +void eekboard_context_show_keyboard (EekboardContext *context, + GCancellable *cancellable); +void eekboard_context_hide_keyboard (EekboardContext *context, + GCancellable *cancellable); +void eekboard_context_set_group (EekboardContext *context, + gint group, + GCancellable *cancellable); +void eekboard_context_press_key (EekboardContext *context, + guint keycode, + GCancellable *cancellable); +void eekboard_context_release_key (EekboardContext *context, + guint keycode, + GCancellable *cancellable); +gboolean eekboard_context_is_keyboard_visible + (EekboardContext *context); +void eekboard_context_set_enabled (EekboardContext *context, + gboolean enabled); + +G_END_DECLS +#endif /* EEKBOARD_CONTEXT_H */ diff --git a/eekboard/eekboard-keyboard.c b/eekboard/eekboard-keyboard.c deleted file mode 100644 index f4036ed9..00000000 --- a/eekboard/eekboard-keyboard.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (C) 2010-2011 Daiki Ueno - * Copyright (C) 2010-2011 Red Hat, Inc. - * - * 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 . - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "eekboard-keyboard.h" - -enum { - KEY_PRESSED, - KEY_RELEASED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0, }; - -G_DEFINE_TYPE (EekboardKeyboard, eekboard_keyboard, G_TYPE_DBUS_PROXY); - -#define EEKBOARD_KEYBOARD_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_KEYBOARD, EekboardKeyboardPrivate)) - -struct _EekboardKeyboardPrivate -{ - EekKeyboard *description; - gboolean visible; -}; - -static void -eekboard_keyboard_real_g_signal (GDBusProxy *self, - const gchar *sender_name, - const gchar *signal_name, - GVariant *parameters) -{ - EekboardKeyboard *keyboard = EEKBOARD_KEYBOARD (self); - EekboardKeyboardPrivate *priv = EEKBOARD_KEYBOARD_GET_PRIVATE (keyboard); - - if (g_strcmp0 (signal_name, "KeyPressed") == 0) { - guint keycode; - g_variant_get (parameters, "(u)", &keycode); - g_signal_emit_by_name (keyboard, "key-pressed", keycode); - return; - } - - if (g_strcmp0 (signal_name, "KeyReleased") == 0) { - guint keycode; - g_variant_get (parameters, "(u)", &keycode); - g_signal_emit_by_name (keyboard, "key-released", keycode); - return; - } - - if (g_strcmp0 (signal_name, "VisibilityChanged") == 0) { - g_variant_get (parameters, "(b)", &priv->visible); - return; - } - - g_return_if_reached (); -} - -static void -eekboard_keyboard_real_key_pressed (EekboardKeyboard *self, - guint keycode) -{ - EekboardKeyboardPrivate *priv = EEKBOARD_KEYBOARD_GET_PRIVATE(self); - if (priv->description) { - EekKey *key = eek_keyboard_find_key_by_keycode (priv->description, - keycode); - g_signal_emit_by_name (key, "pressed"); - } -} - -static void -eekboard_keyboard_real_key_released (EekboardKeyboard *self, - guint keycode) -{ - EekboardKeyboardPrivate *priv = EEKBOARD_KEYBOARD_GET_PRIVATE(self); - if (priv->description) { - EekKey *key = eek_keyboard_find_key_by_keycode (priv->description, - keycode); - g_signal_emit_by_name (key, "released"); - } -} - -static void -eekboard_keyboard_dispose (GObject *self) -{ - EekboardKeyboardPrivate *priv = EEKBOARD_KEYBOARD_GET_PRIVATE (self); - - if (priv->description) { - g_object_unref (priv->description); - priv->description = NULL; - } -} - -static void -eekboard_keyboard_class_init (EekboardKeyboardClass *klass) -{ - GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass); - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (gobject_class, - sizeof (EekboardKeyboardPrivate)); - - klass->key_pressed = eekboard_keyboard_real_key_pressed; - klass->key_released = eekboard_keyboard_real_key_released; - - proxy_class->g_signal = eekboard_keyboard_real_g_signal; - - gobject_class->dispose = eekboard_keyboard_dispose; - - signals[KEY_PRESSED] = - g_signal_new ("key-pressed", - G_TYPE_FROM_CLASS(gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(EekboardKeyboardClass, key_pressed), - NULL, - NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, - 1, - G_TYPE_UINT); - - signals[KEY_RELEASED] = - g_signal_new ("key-released", - G_TYPE_FROM_CLASS(gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(EekboardKeyboardClass, key_released), - NULL, - NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, - 1, - G_TYPE_UINT); -} - -static void -eekboard_keyboard_init (EekboardKeyboard *self) -{ - EekboardKeyboardPrivate *priv; - - priv = self->priv = EEKBOARD_KEYBOARD_GET_PRIVATE(self); - priv->description = NULL; - priv->visible = FALSE; -} - -/** - * eekboard_keyboard_new: - * @path: object path in DBus - * @connection: #GDBusConnection - * @cancellable: #GCancellable - * @error: a pointer of #GError - * - * Create a new #EekboardKeyboard. - */ -EekboardKeyboard * -eekboard_keyboard_new (const gchar *path, - GDBusConnection *connection, - GCancellable *cancellable, - GError **error) -{ - GInitable *initable; - - g_assert (path != NULL); - g_assert (G_IS_DBUS_CONNECTION(connection)); - - initable = - g_initable_new (EEKBOARD_TYPE_KEYBOARD, - cancellable, - error, - "g-connection", connection, - "g-name", "com.redhat.Eekboard.Keyboard", - "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - "g-interface-name", "com.redhat.Eekboard.Keyboard", - "g-object-path", path, - NULL); - if (initable != NULL) - return EEKBOARD_KEYBOARD (initable); - return NULL; -} - -static void -proxy_call_async_ready_cb (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - GError *error = NULL; - GVariant *result; - - result = g_dbus_proxy_call_finish (G_DBUS_PROXY(source_object), - res, - &error); - // g_assert_no_error (error); - if (result) - g_variant_unref (result); -} - -void -eekboard_keyboard_set_description (EekboardKeyboard *keyboard, - EekKeyboard *description) -{ - EekboardKeyboardPrivate *priv; - GVariant *variant; - - g_return_if_fail (EEKBOARD_IS_KEYBOARD(keyboard)); - g_return_if_fail (EEK_IS_KEYBOARD(description)); - - priv = EEKBOARD_KEYBOARD_GET_PRIVATE(keyboard); - if (priv->description) - g_object_unref (priv->description); - priv->description = g_object_ref (description); - - variant = eek_serializable_serialize (EEK_SERIALIZABLE(description)); - g_dbus_proxy_call (G_DBUS_PROXY(keyboard), - "SetDescription", - g_variant_new ("(v)", variant), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - proxy_call_async_ready_cb, - NULL); - g_variant_unref (variant); -} - -void -eekboard_keyboard_set_group (EekboardKeyboard *keyboard, - gint group) -{ - EekboardKeyboardPrivate *priv; - - g_return_if_fail (EEKBOARD_IS_KEYBOARD(keyboard)); - - priv = EEKBOARD_KEYBOARD_GET_PRIVATE (keyboard); - g_dbus_proxy_call (G_DBUS_PROXY(keyboard), - "SetGroup", - g_variant_new ("(i)", group), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - proxy_call_async_ready_cb, - NULL); - eek_keyboard_set_group (priv->description, group); -} - -void -eekboard_keyboard_show (EekboardKeyboard *keyboard) -{ - g_return_if_fail (EEKBOARD_IS_KEYBOARD(keyboard)); - g_dbus_proxy_call (G_DBUS_PROXY(keyboard), - "Show", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - proxy_call_async_ready_cb, - NULL); -} - -void -eekboard_keyboard_hide (EekboardKeyboard *keyboard) -{ - g_return_if_fail (EEKBOARD_IS_KEYBOARD(keyboard)); - g_dbus_proxy_call (G_DBUS_PROXY(keyboard), - "Hide", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - proxy_call_async_ready_cb, - NULL); -} - -void -eekboard_keyboard_press_key (EekboardKeyboard *keyboard, - guint keycode) -{ - g_return_if_fail (EEKBOARD_IS_KEYBOARD(keyboard)); - g_dbus_proxy_call (G_DBUS_PROXY(keyboard), - "PressKey", - g_variant_new ("(u)", keycode), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - proxy_call_async_ready_cb, - NULL); -} - -void -eekboard_keyboard_release_key (EekboardKeyboard *keyboard, - guint keycode) -{ - g_return_if_fail (EEKBOARD_IS_KEYBOARD(keyboard)); - g_dbus_proxy_call (G_DBUS_PROXY(keyboard), - "ReleaseKey", - g_variant_new ("(u)", keycode), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - proxy_call_async_ready_cb, - NULL); -} - -gboolean -eekboard_keyboard_get_visible (EekboardKeyboard *keyboard) -{ - EekboardKeyboardPrivate *priv; - - g_assert (EEKBOARD_IS_KEYBOARD(keyboard)); - - priv = EEKBOARD_KEYBOARD_GET_PRIVATE (keyboard); - return priv->visible; -} diff --git a/eekboard/eekboard-keyboard.h b/eekboard/eekboard-keyboard.h deleted file mode 100644 index 19f04dc5..00000000 --- a/eekboard/eekboard-keyboard.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2010-2011 Daiki Ueno - * Copyright (C) 2010-2011 Red Hat, Inc. - * - * 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 . - */ -#ifndef EEKBOARD_KEYBOARD_H -#define EEKBOARD_KEYBOARD_H 1 - -#include -#include "eek/eek.h" - -G_BEGIN_DECLS - -#define EEKBOARD_TYPE_KEYBOARD (eekboard_keyboard_get_type()) -#define EEKBOARD_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_KEYBOARD, EekboardKeyboard)) -#define EEKBOARD_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_KEYBOARD, EekboardKeyboardClass)) -#define EEKBOARD_IS_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_KEYBOARD)) -#define EEKBOARD_IS_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_KEYBOARD)) -#define EEKBOARD_KEYBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_KEYBOARD, EekboardKeyboardClass)) - -typedef struct _EekboardKeyboard EekboardKeyboard; -typedef struct _EekboardKeyboardClass EekboardKeyboardClass; -typedef struct _EekboardKeyboardPrivate EekboardKeyboardPrivate; - -struct _EekboardKeyboard { - GDBusProxy parent; - - EekboardKeyboardPrivate *priv; -}; - -struct _EekboardKeyboardClass { - GDBusProxyClass parent_class; - - void (*key_pressed) (EekboardKeyboard *self, - guint keycode); - void (*key_released) (EekboardKeyboard *self, - guint keycode); -}; - -GType eekboard_keyboard_get_type (void) G_GNUC_CONST; -EekboardKeyboard *eekboard_keyboard_new (const gchar *path, - GDBusConnection *connection, - GCancellable *cancellable, - GError **error); -void eekboard_keyboard_set_description - (EekboardKeyboard *keyboard, - EekKeyboard *description); -void eekboard_keyboard_set_group (EekboardKeyboard *keyboard, - gint group); -void eekboard_keyboard_show (EekboardKeyboard *keyboard); -void eekboard_keyboard_hide (EekboardKeyboard *keyboard); -void eekboard_keyboard_press_key (EekboardKeyboard *keyboard, - guint keycode); -void eekboard_keyboard_release_key (EekboardKeyboard *keyboard, - guint keycode); -gboolean eekboard_keyboard_get_visible (EekboardKeyboard *keyboard); - -G_END_DECLS -#endif /* EEKBOARD_KEYBOARD_H */ diff --git a/eekboard/eekboard-server.c b/eekboard/eekboard-server.c new file mode 100644 index 00000000..90d7f9ac --- /dev/null +++ b/eekboard/eekboard-server.c @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2011 Daiki Ueno + * Copyright (C) 2011 Red Hat, Inc. + * + * 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 . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "eekboard/eekboard-server.h" + +G_DEFINE_TYPE (EekboardServer, eekboard_server, G_TYPE_DBUS_PROXY); + +#define EEKBOARD_SERVER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_SERVER, EekboardServerPrivate)) + +struct _EekboardServerPrivate +{ + GHashTable *context_hash; + GSList *context_stack; + + /* used in eekboard_server_push_context and + eekboard_server_destroy_context as a callback data */ + EekboardContext *context; +}; + +static void +eekboard_server_dispose (GObject *object) +{ + EekboardServerPrivate *priv = EEKBOARD_SERVER_GET_PRIVATE(object); + GSList *head; + + if (priv->context_hash) { + g_hash_table_destroy (priv->context_hash); + priv->context_hash = NULL; + } + + for (head = priv->context_stack; head; head = priv->context_stack) { + g_object_unref (head->data); + priv->context_stack = g_slist_next (head); + g_slist_free1 (head); + } + + G_OBJECT_CLASS (eekboard_server_parent_class)->dispose (object); +} + +static void +eekboard_server_class_init (EekboardServerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (gobject_class, + sizeof (EekboardServerPrivate)); + + gobject_class->dispose = eekboard_server_dispose; +} + +static void +eekboard_server_init (EekboardServer *self) +{ + EekboardServerPrivate *priv; + + priv = self->priv = EEKBOARD_SERVER_GET_PRIVATE(self); + priv->context_hash = + g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)g_object_unref); + priv->context_stack = NULL; + priv->context = NULL; +} + +EekboardServer * +eekboard_server_new (GDBusConnection *connection, + GCancellable *cancellable) +{ + GInitable *initable; + GError *error; + + g_assert (G_IS_DBUS_CONNECTION(connection)); + + error = NULL; + initable = + g_initable_new (EEKBOARD_TYPE_SERVER, + cancellable, + &error, + "g-connection", connection, + "g-name", "com.redhat.Eekboard.Server", + "g-interface-name", "com.redhat.Eekboard.Server", + "g-object-path", "/com/redhat/Eekboard/Server", + NULL); + if (initable != NULL) + return EEKBOARD_SERVER (initable); + return NULL; +} + +EekboardContext * +eekboard_server_create_context (EekboardServer *server, + const gchar *client_name, + GCancellable *cancellable) +{ + GVariant *variant; + const gchar *object_path; + EekboardContext *context; + EekboardServerPrivate *priv; + GError *error; + GDBusConnection *connection; + + g_assert (EEKBOARD_IS_SERVER(server)); + g_assert (client_name); + + error = NULL; + variant = g_dbus_proxy_call_sync (G_DBUS_PROXY(server), + "CreateContext", + g_variant_new ("(s)", client_name), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + &error); + if (!variant) + return NULL; + + g_variant_get (variant, "(&s)", &object_path); + connection = g_dbus_proxy_get_connection (G_DBUS_PROXY(server)); + context = eekboard_context_new (connection, object_path, cancellable); + if (!context) { + g_variant_unref (variant); + return NULL; + } + + priv = EEKBOARD_SERVER_GET_PRIVATE(server); + g_hash_table_insert (priv->context_hash, g_strdup (object_path), context); + return context; +} + +static void +push_context_async_ready_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + EekboardServer *server = user_data; + EekboardServerPrivate *priv = EEKBOARD_SERVER_GET_PRIVATE(server); + GError *error = NULL; + GVariant *result; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY(source_object), + res, + &error); + if (result) { + g_variant_unref (result); + + if (priv->context_stack) + eekboard_context_set_enabled (priv->context_stack->data, FALSE); + priv->context_stack = g_slist_prepend (priv->context_stack, + priv->context); + g_object_ref (priv->context); + eekboard_context_set_enabled (priv->context, TRUE); + } +} + +void +eekboard_server_push_context (EekboardServer *server, + EekboardContext *context, + GCancellable *cancellable) +{ + EekboardServerPrivate *priv; + const gchar *object_path; + + g_return_if_fail (EEKBOARD_IS_SERVER(server)); + g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); + + object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(context)); + + priv = EEKBOARD_SERVER_GET_PRIVATE(server); + context = g_hash_table_lookup (priv->context_hash, object_path); + if (!context) + return; + + priv->context = context; + g_dbus_proxy_call (G_DBUS_PROXY(server), + "PushContext", + g_variant_new ("(s)", object_path), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + push_context_async_ready_callback, + server); +} + +static void +pop_context_async_ready_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + EekboardServer *server = user_data; + EekboardServerPrivate *priv = EEKBOARD_SERVER_GET_PRIVATE(server); + GError *error = NULL; + GVariant *result; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY(source_object), + res, + &error); + if (result) { + g_variant_unref (result); + + if (priv->context_stack) { + EekboardContext *context = priv->context_stack->data; + + eekboard_context_set_enabled (context, FALSE); + priv->context_stack = g_slist_next (priv->context_stack); + g_object_unref (context); + if (priv->context_stack) + eekboard_context_set_enabled (priv->context_stack->data, TRUE); + } + } +} + +void +eekboard_server_pop_context (EekboardServer *server, + GCancellable *cancellable) +{ + g_return_if_fail (EEKBOARD_IS_SERVER(server)); + + g_dbus_proxy_call (G_DBUS_PROXY(server), + "PopContext", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + pop_context_async_ready_callback, + server); +} + +static void +destroy_context_async_ready_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + EekboardServer *server = user_data; + EekboardServerPrivate *priv = EEKBOARD_SERVER_GET_PRIVATE(server); + GError *error = NULL; + GVariant *result; + const gchar *object_path; + GSList *head; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY(source_object), + res, + &error); + if (result) { + g_variant_unref (result); + + head = g_slist_find (priv->context_stack, priv->context); + if (head) { + priv->context_stack = g_slist_remove_link (priv->context_stack, + head); + g_slist_free1 (head); + } + + object_path = + g_dbus_proxy_get_object_path (G_DBUS_PROXY(priv->context)); + g_hash_table_remove (priv->context_hash, object_path); + } +} + +void +eekboard_server_destroy_context (EekboardServer *server, + EekboardContext *context, + GCancellable *cancellable) +{ + EekboardServerPrivate *priv; + const gchar *object_path; + + g_return_if_fail (EEKBOARD_IS_SERVER(server)); + g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); + + object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(context)); + + priv = EEKBOARD_SERVER_GET_PRIVATE(server); + priv->context = context; + g_dbus_proxy_call (G_DBUS_PROXY(server), + "DestroyContext", + g_variant_new ("(s)", object_path), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + destroy_context_async_ready_callback, + server); +} diff --git a/src/server.h b/eekboard/eekboard-server.h similarity index 52% rename from src/server.h rename to eekboard/eekboard-server.h index cbf5b9aa..633e4c76 100644 --- a/src/server.h +++ b/eekboard/eekboard-server.h @@ -19,6 +19,7 @@ #define EEKBOARD_SERVER_H 1 #include +#include "eekboard/eekboard-context.h" G_BEGIN_DECLS @@ -30,9 +31,34 @@ G_BEGIN_DECLS #define EEKBOARD_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_SERVER, EekboardServerClass)) typedef struct _EekboardServer EekboardServer; +typedef struct _EekboardServerClass EekboardServerClass; +typedef struct _EekboardServerPrivate EekboardServerPrivate; -EekboardServer *eekboard_server_new (const gchar *object_path, - GDBusConnection *connection); +struct _EekboardServer { + GDBusProxy parent; + + EekboardServerPrivate *priv; +}; + +struct _EekboardServerClass { + GDBusProxyClass parent_class; +}; + +GType eekboard_server_get_type (void) G_GNUC_CONST; + +EekboardServer *eekboard_server_new (GDBusConnection *connection, + GCancellable *cancellable); +EekboardContext *eekboard_server_create_context (EekboardServer *server, + const gchar *client_name, + GCancellable *cancellable); +void eekboard_server_push_context (EekboardServer *server, + EekboardContext *context, + GCancellable *cancellable); +void eekboard_server_pop_context (EekboardServer *server, + GCancellable *cancellable); +void eekboard_server_destroy_context (EekboardServer *server, + EekboardContext *context, + GCancellable *cancellable); G_END_DECLS #endif /* EEKBOARD_SERVER_H */ diff --git a/eekboard/eekboard.h b/eekboard/eekboard.h index 139fedd9..558690a9 100644 --- a/eekboard/eekboard.h +++ b/eekboard/eekboard.h @@ -18,6 +18,7 @@ #ifndef EEKBOARD_H #define EEKBOARD_H 1 -#include "eekboard/eekboard-keyboard.h" +#include "eekboard/eekboard-server.h" +#include "eekboard/eekboard-context.h" #endif /* EEKBOARD_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 4c8fbef3..e77518aa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -68,8 +68,8 @@ eekboard_server_LDADD = \ $(GIO2_LIBS) \ $(GTK_LIBS) -eekboard_server_headers = server.h -eekboard_server_SOURCES = server.c server-main.c +eekboard_server_headers = server-server.h server-context.h +eekboard_server_SOURCES = server-server.c server-context.c server-main.c if ENABLE_CLUTTER eekboard_server_CFLAGS += $(CLUTTER_CFLAGS) $(CLUTTER_GTK_CFLAGS) diff --git a/src/client-main.c b/src/client-main.c index 897eab32..5d988514 100644 --- a/src/client-main.c +++ b/src/client-main.c @@ -21,22 +21,22 @@ #include "eekboard/eekboard.h" -static gchar *opt_set_description = NULL; +static gchar *opt_set_keyboard = NULL; static gint opt_set_group = -1; -static gboolean opt_show = FALSE; -static gboolean opt_hide = FALSE; +static gboolean opt_show_keyboard = FALSE; +static gboolean opt_hide_keyboard = FALSE; static gint opt_press_key = -1; static gint opt_release_key = -1; static gboolean opt_listen = FALSE; static const GOptionEntry options[] = { - {"set-description", '\0', 0, G_OPTION_ARG_STRING, &opt_set_description, - "Set keyboard description from an XML file"}, + {"set-keyboard", '\0', 0, G_OPTION_ARG_STRING, &opt_set_keyboard, + "Set keyboard keyboard from an XML file"}, {"set-group", '\0', 0, G_OPTION_ARG_INT, &opt_set_group, "Set group of the keyboard"}, - {"show", '\0', 0, G_OPTION_ARG_NONE, &opt_show, + {"show-keyboard", '\0', 0, G_OPTION_ARG_NONE, &opt_show_keyboard, "Show keyboard"}, - {"hide", '\0', 0, G_OPTION_ARG_NONE, &opt_hide, + {"hide-keyboard", '\0', 0, G_OPTION_ARG_NONE, &opt_hide_keyboard, "Hide keyboard"}, {"press-key", '\0', 0, G_OPTION_ARG_INT, &opt_press_key, "Press key"}, @@ -62,20 +62,21 @@ on_key_released (guint keycode, gpointer user_data) int main (int argc, char **argv) { - EekboardKeyboard *keyboard = NULL; + EekboardServer *server = NULL; + EekboardContext *context = NULL; GDBusConnection *connection = NULL; GError *error; - GOptionContext *context; + GOptionContext *option_context; GMainLoop *loop = NULL; gint retval = 0; g_type_init (); g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL); - context = g_option_context_new ("eekboard-client"); - g_option_context_add_main_entries (context, options, NULL); - g_option_context_parse (context, &argc, &argv, NULL); - g_option_context_free (context); + option_context = g_option_context_new ("eekboard-client"); + g_option_context_add_main_entries (option_context, options, NULL); + g_option_context_parse (option_context, &argc, &argv, NULL); + g_option_context_free (option_context); error = NULL; connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); @@ -85,75 +86,82 @@ main (int argc, char **argv) goto out; } - error = NULL; - keyboard = eekboard_keyboard_new ("/com/redhat/Eekboard/Keyboard", - connection, - NULL, - &error); - if (error) { - g_printerr ("%s\n", error->message); + server = eekboard_server_new (connection, NULL); + if (!server) { + g_printerr ("Can't create server\n"); retval = 1; goto out; } - if (opt_set_description) { + context = eekboard_server_create_context (server, + "eekboard-client", + NULL); + if (!context) { + g_printerr ("Can't create context\n"); + retval = 1; + goto out; + } + + eekboard_server_push_context (server, context, NULL); + + if (opt_set_keyboard) { GFile *file; GFileInputStream *input; EekLayout *layout; - EekKeyboard *description; - GError *error; + EekKeyboard *keyboard; - file = g_file_new_for_path (opt_set_description); + file = g_file_new_for_path (opt_set_keyboard); error = NULL; input = g_file_read (file, NULL, &error); if (error) { g_printerr ("Can't read file %s: %s\n", - opt_set_description, error->message); + opt_set_keyboard, error->message); retval = 1; goto out; } layout = eek_xml_layout_new (G_INPUT_STREAM(input)); g_object_unref (input); - description = eek_keyboard_new (layout, 640, 480); + keyboard = eek_keyboard_new (layout, 640, 480); g_object_unref (layout); - eekboard_keyboard_set_description (keyboard, description); - g_object_unref (description); + + eekboard_context_set_keyboard (context, keyboard, NULL); + g_object_unref (keyboard); } if (opt_set_group >= 0) { - eekboard_keyboard_set_group (keyboard, opt_set_group); + eekboard_context_set_group (context, opt_set_group, NULL); } - if (opt_show) { - eekboard_keyboard_show (keyboard); + if (opt_show_keyboard) { + eekboard_context_show_keyboard (context, NULL); } - if (opt_hide) { - eekboard_keyboard_hide (keyboard); + if (opt_hide_keyboard) { + eekboard_context_hide_keyboard (context, NULL); } if (opt_press_key >= 0) { - eekboard_keyboard_press_key (keyboard, opt_press_key); + eekboard_context_press_key (context, opt_press_key, NULL); } if (opt_release_key >= 0) { - eekboard_keyboard_release_key (keyboard, opt_release_key); + eekboard_context_release_key (context, opt_release_key, NULL); } if (opt_listen) { - g_signal_connect (keyboard, "key-pressed", + g_signal_connect (context, "key-pressed", G_CALLBACK(on_key_pressed), NULL); - g_signal_connect (keyboard, "key-released", + g_signal_connect (context, "key-released", G_CALLBACK(on_key_released), NULL); loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); } out: - if (keyboard) - g_object_unref (keyboard); + if (context) + g_object_unref (context); if (connection) g_object_unref (connection); if (loop) diff --git a/src/server-context.c b/src/server-context.c new file mode 100644 index 00000000..ecebb6b8 --- /dev/null +++ b/src/server-context.c @@ -0,0 +1,619 @@ +/* + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * + * 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 . + */ +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "eek/eek.h" + +#if HAVE_CLUTTER_GTK +#include +#include "eek/eek-clutter.h" +#else /* HAVE_CLUTTER_GTK */ +#include "eek/eek-gtk.h" +#endif /* !HAVE_CLUTTER_GTK */ + +#include "server-context.h" + +#define CSW 640 +#define CSH 480 + +enum { + PROP_0, + PROP_OBJECT_PATH, + PROP_CONNECTION, + PROP_LAST +}; + +static const gchar introspection_xml[] = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + /* signals */ + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +typedef struct _ServerContextClass ServerContextClass; + +struct _ServerContext { + GObject parent; + GDBusConnection *connection; + GDBusNodeInfo *introspection_data; + guint registration_id; + char *object_path; + + gboolean enabled; + + GtkWidget *window; + GtkWidget *widget; + EekKeyboard *keyboard; + + gulong key_pressed_handler; + gulong key_released_handler; +}; + +struct _ServerContextClass { + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (ServerContext, server_context, G_TYPE_OBJECT); + +static void disconnect_keyboard_signals (ServerContext *context); +static void handle_method_call (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data); + +static const GDBusInterfaceVTable interface_vtable = +{ + handle_method_call, + NULL, + NULL +}; + +#if HAVE_CLUTTER_GTK +static void +on_allocation_changed (ClutterActor *stage, + ClutterActorBox *box, + ClutterAllocationFlags flags, + gpointer user_data) +{ + ClutterActor *actor = user_data; + clutter_actor_set_size (actor, + box->x2 - box->x1, + box->y2 - box->y1); +} +#endif + +static void +on_destroy (GtkWidget *widget, gpointer user_data) +{ + ServerContext *context = user_data; + + g_assert (widget == context->window); + context->window = NULL; + context->widget = NULL; +} + +static void +on_notify_visible (GObject *object, GParamSpec *spec, gpointer user_data) +{ + ServerContext *context = user_data; + gboolean visible; + GError *error; + + g_object_get (object, "visible", &visible, NULL); + + if (context->connection && context->enabled) { + error = NULL; + g_dbus_connection_emit_signal (context->connection, + NULL, + context->object_path, + SERVER_CONTEXT_INTERFACE, + "KeyboardVisibilityChanged", + g_variant_new ("(b)", visible), + &error); + g_assert_no_error (error); + } +} + +static void +update_widget (ServerContext *context) +{ + GdkScreen *screen; + GdkWindow *root; + gint monitor; + GdkRectangle rect; + EekBounds bounds; +#if HAVE_CLUTTER_GTK + ClutterActor *stage, *actor; + ClutterColor stage_color = { 0xff, 0xff, 0xff, 0xff }; +#endif + + if (context->widget) + gtk_widget_destroy (context->widget); + + if (context->window) + gtk_widget_destroy (context->window); + + eek_element_get_bounds (EEK_ELEMENT(context->keyboard), &bounds); +#if HAVE_CLUTTER_GTK + context->widget = gtk_clutter_embed_new (); + stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(context->widget)); + actor = eek_clutter_context_new (context->keyboard); + clutter_container_add_actor (CLUTTER_CONTAINER(stage), actor); + + clutter_stage_set_color (CLUTTER_STAGE(stage), &stage_color); + clutter_stage_set_user_resizable (CLUTTER_STAGE(stage), TRUE); + clutter_stage_set_minimum_size (CLUTTER_STAGE(stage), + bounds.width / 3, + bounds.height / 3); + g_signal_connect (stage, + "allocation-changed", + G_CALLBACK(on_allocation_changed), + actor); +#else + context->widget = eek_gtk_keyboard_new (context->keyboard); +#endif + gtk_widget_set_size_request (context->widget, bounds.width, bounds.height); + + context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (context->window, "destroy", + G_CALLBACK(on_destroy), context); + g_signal_connect (context->window, "notify::visible", + G_CALLBACK(on_notify_visible), context); + gtk_container_add (GTK_CONTAINER(context->window), context->widget); + + gtk_widget_set_can_focus (context->window, FALSE); + g_object_set (G_OBJECT(context->window), "accept_focus", FALSE, NULL); + gtk_window_set_title (GTK_WINDOW(context->window), "Context"); + gtk_window_set_keep_above (GTK_WINDOW(context->window), TRUE); + + screen = gdk_screen_get_default (); + root = gtk_widget_get_root_window (context->window); + monitor = gdk_screen_get_monitor_at_window (screen, root); + gdk_screen_get_monitor_geometry (screen, monitor, &rect); + gtk_window_move (GTK_WINDOW(context->window), + MAX(rect.width - 20 - bounds.width, 0), + MAX(rect.height - 40 - bounds.height, 0)); +} + +static void +server_context_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ServerContext *context = SERVER_CONTEXT(object); + GDBusConnection *connection; + + switch (prop_id) { + case PROP_OBJECT_PATH: + if (context->object_path) + g_free (context->object_path); + context->object_path = g_strdup (g_value_get_string (value)); + break; + case PROP_CONNECTION: + connection = g_value_get_object (value); + if (context->connection) + g_object_unref (context->connection); + context->connection = g_object_ref (connection); + break; + default: + g_object_set_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +server_context_dispose (GObject *object) +{ + ServerContext *context = SERVER_CONTEXT(object); + + if (context->keyboard) { + disconnect_keyboard_signals (context); + g_object_unref (context->keyboard); + context->keyboard = NULL; + } + + if (context->window) { + gtk_widget_destroy (context->window); + context->window = NULL; + } + + if (context->connection) { + if (context->registration_id > 0) { + g_dbus_connection_unregister_object (context->connection, + context->registration_id); + context->registration_id = 0; + } + + g_object_unref (context->connection); + context->connection = NULL; + } + + if (context->introspection_data) { + g_dbus_node_info_unref (context->introspection_data); + context->introspection_data = NULL; + } + + G_OBJECT_CLASS (server_context_parent_class)->dispose (object); +} + +static void +server_context_constructed (GObject *object) +{ + ServerContext *context = SERVER_CONTEXT (object); + if (context->connection && context->object_path) { + GError *error = NULL; + + context->registration_id = g_dbus_connection_register_object + (context->connection, + context->object_path, + context->introspection_data->interfaces[0], + &interface_vtable, + context, + NULL, + &error); + } +} + +static void +server_context_class_init (ServerContextClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + gobject_class->constructed = server_context_constructed; + gobject_class->set_property = server_context_set_property; + gobject_class->dispose = server_context_dispose; + + pspec = g_param_spec_string ("object-path", + "Object-path", + "Object-path", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); + g_object_class_install_property (gobject_class, + PROP_OBJECT_PATH, + pspec); + + pspec = g_param_spec_object ("connection", + "Connection", + "Connection", + G_TYPE_DBUS_CONNECTION, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); + g_object_class_install_property (gobject_class, + PROP_CONNECTION, + pspec); +} + +static void +server_context_init (ServerContext *context) +{ + GError *error; + + context->connection = NULL; + error = NULL; + context->introspection_data = + g_dbus_node_info_new_for_xml (introspection_xml, &error); + g_assert (context->introspection_data != NULL); + context->registration_id = 0; + context->object_path = NULL; + + context->keyboard = NULL; + context->widget = NULL; + context->window = NULL; + context->key_pressed_handler = 0; + context->key_released_handler = 0; +} + +static void +on_key_pressed (EekKeyboard *keyboard, + EekKey *key, + gpointer user_data) +{ + ServerContext *context = user_data; + + if (context->connection && context->enabled) { + guint keycode = eek_key_get_keycode (key); + GError *error; + + error = NULL; + g_dbus_connection_emit_signal (context->connection, + NULL, + context->object_path, + SERVER_CONTEXT_INTERFACE, + "KeyPressed", + g_variant_new ("(u)", keycode), + &error); + g_assert_no_error (error); + } +} + +static void +on_key_released (EekKeyboard *keyboard, + EekKey *key, + gpointer user_data) +{ + ServerContext *context = user_data; + + if (context->connection && context->enabled) { + guint keycode = eek_key_get_keycode (key); + GError *error; + + error = NULL; + g_dbus_connection_emit_signal (context->connection, + NULL, + context->object_path, + SERVER_CONTEXT_INTERFACE, + "KeyReleased", + g_variant_new ("(u)", keycode), + &error); + g_assert_no_error (error); + } +} + +static void +disconnect_keyboard_signals (ServerContext *context) +{ + if (g_signal_handler_is_connected (context->keyboard, + context->key_pressed_handler)) + g_signal_handler_disconnect (context->keyboard, + context->key_pressed_handler); + if (g_signal_handler_is_connected (context->keyboard, + context->key_released_handler)) + g_signal_handler_disconnect (context->keyboard, + context->key_released_handler); +} + +static void +handle_method_call (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + ServerContext *context = user_data; + + if (g_strcmp0 (method_name, "SetKeyboard") == 0) { + EekSerializable *serializable; + GVariant *variant; + + if (!context->enabled) { + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + g_variant_get (parameters, "(v)", &variant); + serializable = eek_serializable_deserialize (variant); + if (!EEK_IS_KEYBOARD(serializable)) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "not a keyboard"); + return; + } + + context->keyboard = EEK_KEYBOARD(serializable); + disconnect_keyboard_signals (context); + context->key_pressed_handler = + g_signal_connect (context->keyboard, "key-pressed", + G_CALLBACK(on_key_pressed), + context); + context->key_released_handler = + g_signal_connect (context->keyboard, "key-released", + G_CALLBACK(on_key_released), + context); + eek_keyboard_set_modifier_behavior (context->keyboard, + EEK_MODIFIER_BEHAVIOR_LATCH); + + if (context->window) { + gboolean was_visible = gtk_widget_get_visible (context->window); + update_widget (context); + if (was_visible) + gtk_widget_show_all (context->window); + } + + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (g_strcmp0 (method_name, "SetGroup") == 0) { + gint group; + + if (!context->enabled) { + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (!context->keyboard) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "keyboard is not set"); + return; + } + + g_variant_get (parameters, "(i)", &group); + eek_keyboard_set_group (context->keyboard, group); + + if (context->window) { + gboolean was_visible = gtk_widget_get_visible (context->window); + update_widget (context); + if (was_visible) + gtk_widget_show_all (context->window); + } + + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (g_strcmp0 (method_name, "ShowKeyboard") == 0) { + if (!context->keyboard) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "keyboard is not set"); + return; + } + + if (!context->window) + update_widget (context); + g_assert (context->window); + gtk_widget_show_all (context->window); + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (g_strcmp0 (method_name, "HideKeyboard") == 0) { + if (context->window) + gtk_widget_hide (context->window); + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (g_strcmp0 (method_name, "PressKey") == 0 || + g_strcmp0 (method_name, "ReleaseKey") == 0) { + EekKey *key; + guint keycode; + + if (!context->enabled) { + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (!context->keyboard) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "keyboard is not set"); + return; + } + + g_variant_get (parameters, "(u)", &keycode); + key = eek_keyboard_find_key_by_keycode (context->keyboard, keycode); + + if (!key) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "key for %u is not found", + keycode); + return; + } + + if (g_strcmp0 (method_name, "PressKey") == 0) { + g_signal_handler_block (context->keyboard, + context->key_pressed_handler); + g_signal_emit_by_name (key, "pressed"); + g_signal_handler_unblock (context->keyboard, + context->key_pressed_handler); + } else { + g_signal_handler_block (context->keyboard, + context->key_released_handler); + g_signal_emit_by_name (key, "released"); + g_signal_handler_unblock (context->keyboard, + context->key_released_handler); + } + + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + g_return_if_reached (); +} + +ServerContext * +server_context_new (const gchar *object_path, + GDBusConnection *connection) +{ + return g_object_new (SERVER_TYPE_CONTEXT, + "object-path", object_path, + "connection", connection, + NULL); +} + +void +server_context_set_enabled (ServerContext *context, gboolean enabled) +{ + GError *error; + + g_return_if_fail (SERVER_IS_CONTEXT(context)); + g_return_if_fail (context->connection); + + if (context->enabled == enabled) + return; + + if (enabled) { + error = NULL; + g_dbus_connection_emit_signal (context->connection, + NULL, + context->object_path, + SERVER_CONTEXT_INTERFACE, + "Enabled", + NULL, + &error); + g_assert_no_error (error); + } else { + error = NULL; + g_dbus_connection_emit_signal (context->connection, + NULL, + context->object_path, + SERVER_CONTEXT_INTERFACE, + "Disabled", + NULL, + &error); + g_assert_no_error (error); + } + context->enabled = enabled; +} diff --git a/src/server-context.h b/src/server-context.h new file mode 100644 index 00000000..c08f0a27 --- /dev/null +++ b/src/server-context.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * + * 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 . + */ +#ifndef SERVER_CONTEXT_H +#define SERVER_CONTEXT_H 1 + +#include + +G_BEGIN_DECLS + +#define SERVER_CONTEXT_PATH "/com/redhat/Eekboard/Context_%d" +#define SERVER_CONTEXT_INTERFACE "com.redhat.Eekboard.Context" + +#define SERVER_TYPE_CONTEXT (server_context_get_type()) +#define SERVER_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SERVER_TYPE_CONTEXT, ServerContext)) +#define SERVER_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SERVER_TYPE_CONTEXT, ServerContextClass)) +#define SERVER_IS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SERVER_TYPE_CONTEXT)) +#define SERVER_IS_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SERVER_TYPE_CONTEXT)) +#define SERVER_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SERVER_TYPE_CONTEXT, ServerContextClass)) + +typedef struct _ServerContext ServerContext; + +ServerContext *server_context_new (const gchar *object_path, + GDBusConnection *connection); +void server_context_set_enabled (ServerContext *context, + gboolean enabled); + +G_END_DECLS +#endif /* SERVER_CONTEXT_H */ diff --git a/src/server-main.c b/src/server-main.c index 19ed7dce..0a4c1a1a 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -27,13 +27,28 @@ #include #endif -#include "server.h" +#include "server-server.h" #include "eek/eek.h" +static void +on_name_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ +} + +static void +on_name_lost (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + exit (1); +} + int main (int argc, char **argv) { - EekboardServer *server; + ServerServer *server; GDBusConnection *connection; GError *error; GMainLoop *loop; @@ -66,18 +81,18 @@ main (int argc, char **argv) exit (1); } - server = eekboard_server_new ("/com/redhat/Eekboard/Keyboard", connection); + server = server_server_new (SERVER_SERVER_PATH, connection); if (server == NULL) { - g_printerr ("Can't start server\n"); + g_printerr ("Can't create server server\n"); exit (1); } owner_id = g_bus_own_name_on_connection (connection, - "com.redhat.Eekboard.Keyboard", + SERVER_SERVER_INTERFACE, G_BUS_NAME_OWNER_FLAGS_NONE, - NULL, - NULL, + on_name_acquired, + on_name_lost, NULL, NULL); if (owner_id == 0) { diff --git a/src/server-server.c b/src/server-server.c new file mode 100644 index 00000000..e0395494 --- /dev/null +++ b/src/server-server.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * + * 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 . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "server-server.h" +#include "server-context.h" + +enum { + PROP_0, + PROP_OBJECT_PATH, + PROP_CONNECTION, + PROP_LAST +}; + +static const gchar introspection_xml[] = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + /* signals */ + " " + ""; + +typedef struct _ServerServerClass ServerServerClass; + +struct _ServerServer { + GObject parent; + GDBusConnection *connection; + GDBusNodeInfo *introspection_data; + guint registration_id; + char *object_path; + + GHashTable *context_hash; + GSList *context_stack; +}; + +struct _ServerServerClass { + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (ServerServer, server_server, G_TYPE_OBJECT); + +static void handle_method_call (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data); + +static const GDBusInterfaceVTable interface_vtable = +{ + handle_method_call, + NULL, + NULL +}; + +static void +server_server_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ServerServer *server = SERVER_SERVER(object); + GDBusConnection *connection; + + switch (prop_id) { + case PROP_OBJECT_PATH: + if (server->object_path) + g_free (server->object_path); + server->object_path = g_strdup (g_value_get_string (value)); + break; + case PROP_CONNECTION: + connection = g_value_get_object (value); + if (server->connection) + g_object_unref (server->connection); + server->connection = g_object_ref (connection); + break; + default: + g_object_set_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +server_server_dispose (GObject *object) +{ + ServerServer *server = SERVER_SERVER(object); + GSList *head; + + if (server->context_hash) { + g_hash_table_destroy (server->context_hash); + server->context_hash = NULL; + } + + for (head = server->context_stack; head; head = server->context_stack) { + g_object_unref (head->data); + server->context_stack = g_slist_next (head); + g_slist_free1 (head); + } + + if (server->connection) { + if (server->registration_id > 0) { + g_dbus_connection_unregister_object (server->connection, + server->registration_id); + server->registration_id = 0; + } + + g_object_unref (server->connection); + server->connection = NULL; + } + + if (server->introspection_data) { + g_dbus_node_info_unref (server->introspection_data); + server->introspection_data = NULL; + } + + G_OBJECT_CLASS (server_server_parent_class)->dispose (object); +} + +static void +server_server_constructed (GObject *object) +{ + ServerServer *server = SERVER_SERVER (object); + if (server->connection && server->object_path) { + GError *error = NULL; + + server->registration_id = g_dbus_connection_register_object + (server->connection, + server->object_path, + server->introspection_data->interfaces[0], + &interface_vtable, + server, + NULL, + &error); + } +} + +static void +server_server_class_init (ServerServerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + gobject_class->constructed = server_server_constructed; + gobject_class->set_property = server_server_set_property; + gobject_class->dispose = server_server_dispose; + + pspec = g_param_spec_string ("object-path", + "Object-path", + "Object-path", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); + g_object_class_install_property (gobject_class, + PROP_OBJECT_PATH, + pspec); + + pspec = g_param_spec_object ("connection", + "Connection", + "Connection", + G_TYPE_DBUS_CONNECTION, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); + g_object_class_install_property (gobject_class, + PROP_CONNECTION, + pspec); +} + +static void +server_server_init (ServerServer *server) +{ + GError *error; + + server->connection = NULL; + error = NULL; + server->introspection_data = + g_dbus_node_info_new_for_xml (introspection_xml, &error); + g_assert (server->introspection_data != NULL); + server->registration_id = 0; + + server->context_hash = + g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)g_object_unref); + server->context_stack = NULL; +} + +static void +handle_method_call (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + ServerServer *server = user_data; + + if (g_strcmp0 (method_name, "CreateContext") == 0) { + const gchar *client_name; + gchar *object_path; + static gint context_id = 0; + ServerContext *context; + + g_variant_get (parameters, "(&s)", &client_name); + object_path = g_strdup_printf (SERVER_CONTEXT_PATH, context_id++); + context = server_context_new (object_path, server->connection); + g_hash_table_insert (server->context_hash, + object_path, + context); + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(s)", + object_path)); + return; + } + + if (g_strcmp0 (method_name, "PushContext") == 0) { + const gchar *object_path; + ServerContext *context; + + g_variant_get (parameters, "(&s)", &object_path); + context = g_hash_table_lookup (server->context_hash, object_path); + if (!context) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "context not found"); + return; + } + if (server->context_stack) + server_context_set_enabled (server->context_stack->data, FALSE); + server->context_stack = g_slist_prepend (server->context_stack, + context); + g_object_ref (context); + server_context_set_enabled (context, TRUE); + + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (g_strcmp0 (method_name, "PopContext") == 0) { + if (server->context_stack) { + ServerContext *context = server->context_stack->data; + + server_context_set_enabled (context, FALSE); + server->context_stack = g_slist_next (server->context_stack); + g_object_unref (context); + if (server->context_stack) + server_context_set_enabled (server->context_stack->data, TRUE); + } + + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (g_strcmp0 (method_name, "DestroyContext") == 0) { + const gchar *object_path; + ServerContext *context; + GSList *head; + + g_variant_get (parameters, "(&s)", &object_path); + context = g_hash_table_lookup (server->context_hash, object_path); + if (!context) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "context not found"); + return; + } + head = g_slist_find (server->context_stack, context); + if (head) { + server->context_stack = g_slist_remove_link (server->context_stack, + head); + g_slist_free1 (head); + } + + g_hash_table_remove (server->context_hash, object_path); + + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + g_return_if_reached (); +} + +ServerServer * +server_server_new (const gchar *object_path, + GDBusConnection *connection) +{ + return g_object_new (SERVER_TYPE_SERVER, + "object-path", object_path, + "connection", connection, + NULL); +} diff --git a/src/server-server.h b/src/server-server.h new file mode 100644 index 00000000..d5df1e60 --- /dev/null +++ b/src/server-server.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * + * 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 . + */ +#ifndef SERVER_KEYBOARD_H +#define SERVER_KEYBOARD_H 1 + +#include + +G_BEGIN_DECLS + +#define SERVER_SERVER_PATH "/com/redhat/Eekboard/Server" +#define SERVER_SERVER_INTERFACE "com.redhat.Eekboard.Server" + +#define SERVER_TYPE_SERVER (server_server_get_type()) +#define SERVER_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SERVER_TYPE_SERVER, ServerServer)) +#define SERVER_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SERVER_TYPE_SERVER, ServerServerClass)) +#define SERVER_IS_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SERVER_TYPE_SERVER)) +#define SERVER_IS_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SERVER_TYPE_SERVER)) +#define SERVER_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SERVER_TYPE_SERVER, ServerServerClass)) + +typedef struct _ServerServer ServerServer; + +ServerServer *server_server_new (const gchar *object_path, + GDBusConnection *connection); + +G_END_DECLS +#endif /* SERVER_SERVER_H */ diff --git a/src/server.c b/src/server.c deleted file mode 100644 index 29768ba6..00000000 --- a/src/server.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * Copyright (C) 2010-2011 Daiki Ueno - * Copyright (C) 2010-2011 Red Hat, Inc. - * - * 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 . - */ -#include - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "eek/eek.h" - -#if HAVE_CLUTTER_GTK -#include -#include "eek/eek-clutter.h" -#else /* HAVE_CLUTTER_GTK */ -#include "eek/eek-gtk.h" -#endif /* !HAVE_CLUTTER_GTK */ - -#include "server.h" - -#define CSW 640 -#define CSH 480 - -enum { - PROP_0, - PROP_OBJECT_PATH, - PROP_CONNECTION, - PROP_LAST -}; - -static const gchar introspection_xml[] = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -typedef struct _EekboardServerClass EekboardServerClass; - -struct _EekboardServer { - GObject parent; - GDBusConnection *connection; - GDBusNodeInfo *introspection_data; - guint registration_id; - char *object_path; - - GtkWidget *window; - GtkWidget *widget; - EekKeyboard *keyboard; - - gulong key_pressed_handler; - gulong key_released_handler; -}; - -struct _EekboardServerClass { - GObjectClass parent_class; -}; - -G_DEFINE_TYPE (EekboardServer, eekboard_server, G_TYPE_OBJECT); - -static void handle_method_call (GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data); - -static const GDBusInterfaceVTable interface_vtable = -{ - handle_method_call, - NULL, - NULL -}; - -#if HAVE_CLUTTER_GTK -static void -on_allocation_changed (ClutterActor *stage, - ClutterActorBox *box, - ClutterAllocationFlags flags, - gpointer user_data) -{ - ClutterActor *actor = user_data; - clutter_actor_set_size (actor, - box->x2 - box->x1, - box->y2 - box->y1); -} -#endif - -static void -on_destroy (GtkWidget *widget, gpointer user_data) -{ - EekboardServer *server = user_data; - - g_assert (widget == server->window); - server->window = NULL; - server->widget = NULL; -} - -static void -on_notify_visible (GObject *object, GParamSpec *spec, gpointer user_data) -{ - EekboardServer *server = user_data; - gboolean visible; - GError *error; - - g_object_get (object, "visible", &visible, NULL); - - error = NULL; - g_dbus_connection_emit_signal (server->connection, - "com.redhat.Eekboard.Keyboard", - "/com/redhat/Eekboard/Keyboard", - "com.redhat.Eekboard.Keyboard", - "VisibilityChanged", - g_variant_new ("(b)", visible), - &error); - g_assert_no_error (error); -} - -static void -update_widget (EekboardServer *server) -{ - GdkScreen *screen; - GdkWindow *root; - gint monitor; - GdkRectangle rect; - EekBounds bounds; -#if HAVE_CLUTTER_GTK - ClutterActor *stage, *actor; - ClutterColor stage_color = { 0xff, 0xff, 0xff, 0xff }; -#endif - - if (server->widget) - gtk_widget_destroy (server->widget); - - if (server->window) - gtk_widget_destroy (server->window); - - eek_element_get_bounds (EEK_ELEMENT(server->keyboard), &bounds); -#if HAVE_CLUTTER_GTK - server->widget = gtk_clutter_embed_new (); - stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(server->widget)); - actor = eek_clutter_keyboard_new (server->keyboard); - clutter_container_add_actor (CLUTTER_CONTAINER(stage), actor); - - clutter_stage_set_color (CLUTTER_STAGE(stage), &stage_color); - clutter_stage_set_user_resizable (CLUTTER_STAGE(stage), TRUE); - clutter_stage_set_minimum_size (CLUTTER_STAGE(stage), - bounds.width / 3, - bounds.height / 3); - g_signal_connect (stage, - "allocation-changed", - G_CALLBACK(on_allocation_changed), - actor); -#else - server->widget = eek_gtk_keyboard_new (server->keyboard); -#endif - gtk_widget_set_size_request (server->widget, bounds.width, bounds.height); - - server->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - g_signal_connect (server->window, "destroy", - G_CALLBACK(on_destroy), server); - g_signal_connect (server->window, "notify::visible", - G_CALLBACK(on_notify_visible), server); - gtk_container_add (GTK_CONTAINER(server->window), server->widget); - - gtk_widget_set_can_focus (server->window, FALSE); - g_object_set (G_OBJECT(server->window), "accept_focus", FALSE, NULL); - gtk_window_set_title (GTK_WINDOW(server->window), "Keyboard"); - gtk_window_set_keep_above (GTK_WINDOW(server->window), TRUE); - - screen = gdk_screen_get_default (); - root = gtk_widget_get_root_window (server->window); - monitor = gdk_screen_get_monitor_at_window (screen, root); - gdk_screen_get_monitor_geometry (screen, monitor, &rect); - gtk_window_move (GTK_WINDOW(server->window), - MAX(rect.width - 20 - bounds.width, 0), - MAX(rect.height - 40 - bounds.height, 0)); -} - -static void -eekboard_server_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - EekboardServer *server = EEKBOARD_SERVER(object); - GDBusConnection *connection; - - switch (prop_id) { - case PROP_OBJECT_PATH: - if (server->object_path) - g_free (server->object_path); - server->object_path = g_strdup (g_value_get_string (value)); - break; - case PROP_CONNECTION: - connection = g_value_get_object (value); - if (server->connection) - g_object_unref (server->connection); - server->connection = g_object_ref (connection); - break; - default: - g_object_set_property (object, - g_param_spec_get_name (pspec), - value); - break; - } -} - -static void -eekboard_server_dispose (GObject *object) -{ - EekboardServer *server = EEKBOARD_SERVER(object); - - if (server->connection) { - if (server->registration_id > 0) { - g_dbus_connection_unregister_object (server->connection, - server->registration_id); - server->registration_id = 0; - } - - g_object_unref (server->connection); - server->connection = NULL; - } - - if (server->introspection_data) { - g_dbus_node_info_unref (server->introspection_data); - server->introspection_data = NULL; - } - - G_OBJECT_CLASS (eekboard_server_parent_class)->dispose (object); -} - -static void -eekboard_server_constructed (GObject *object) -{ - EekboardServer *server = EEKBOARD_SERVER (object); - if (server->connection && server->object_path) { - GError *error = NULL; - - server->registration_id = g_dbus_connection_register_object - (server->connection, - server->object_path, - server->introspection_data->interfaces[0], - &interface_vtable, - server, - NULL, - &error); - } -} - -static void -eekboard_server_class_init (EekboardServerClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GParamSpec *pspec; - - gobject_class->constructed = eekboard_server_constructed; - gobject_class->set_property = eekboard_server_set_property; - gobject_class->dispose = eekboard_server_dispose; - - pspec = g_param_spec_string ("object-path", - "Object-path", - "Object-path", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); - g_object_class_install_property (gobject_class, - PROP_OBJECT_PATH, - pspec); - - pspec = g_param_spec_object ("connection", - "Connection", - "Connection", - G_TYPE_DBUS_CONNECTION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); - g_object_class_install_property (gobject_class, - PROP_CONNECTION, - pspec); -} - -static void -eekboard_server_init (EekboardServer *server) -{ - GError *error; - - error = NULL; - server->introspection_data = - g_dbus_node_info_new_for_xml (introspection_xml, &error); - g_assert (server->introspection_data != NULL); - server->registration_id = 0; - server->object_path = NULL; - server->keyboard = NULL; - server->widget = NULL; - server->window = NULL; - server->key_pressed_handler = 0; - server->key_released_handler = 0; -} - -static void -on_key_pressed (EekKeyboard *keyboard, - EekKey *key, - gpointer user_data) -{ - EekboardServer *server = user_data; - GError *error; - - error = NULL; - g_dbus_connection_emit_signal (server->connection, - "com.redhat.Eekboard.Keyboard", - "/com/redhat/Eekboard/Keyboard", - "com.redhat.Eekboard.Keyboard", - "KeyPressed", - g_variant_new ("(u)", - eek_key_get_keycode (key)), - &error); - g_assert_no_error (error); -} - -static void -on_key_released (EekKeyboard *keyboard, - EekKey *key, - gpointer user_data) -{ - EekboardServer *server = user_data; - GError *error; - - error = NULL; - g_dbus_connection_emit_signal (server->connection, - "com.redhat.Eekboard.Keyboard", - "/com/redhat/Eekboard/Keyboard", - "com.redhat.Eekboard.Keyboard", - "KeyReleased", - g_variant_new ("(u)", - eek_key_get_keycode (key)), - &error); - g_assert_no_error (error); -} - -static void -disconnect_keyboard_signals (EekboardServer *server) -{ - if (g_signal_handler_is_connected (server->keyboard, - server->key_pressed_handler)) - g_signal_handler_disconnect (server->keyboard, - server->key_pressed_handler); - if (g_signal_handler_is_connected (server->keyboard, - server->key_released_handler)) - g_signal_handler_disconnect (server->keyboard, - server->key_released_handler); -} - -static void -handle_method_call (GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - EekboardServer *server = user_data; - - // g_debug ("%s", method_name); - if (g_strcmp0 (method_name, "SetDescription") == 0) { - EekSerializable *serializable; - GVariant *variant; - - g_variant_get (parameters, "(v)", &variant); - serializable = eek_serializable_deserialize (variant); - if (!EEK_IS_KEYBOARD(serializable)) { - g_dbus_method_invocation_return_error (invocation, - G_IO_ERROR, - G_IO_ERROR_FAILED_HANDLED, - "not a keyboard"); - return; - } - - server->keyboard = EEK_KEYBOARD(serializable); - disconnect_keyboard_signals (server); - server->key_pressed_handler = - g_signal_connect (server->keyboard, "key-pressed", - G_CALLBACK(on_key_pressed), - server); - server->key_released_handler = - g_signal_connect (server->keyboard, "key-released", - G_CALLBACK(on_key_released), - server); - eek_keyboard_set_modifier_behavior (server->keyboard, - EEK_MODIFIER_BEHAVIOR_LATCH); - - if (server->window) { - gboolean was_visible = gtk_widget_get_visible (server->window); - update_widget (server); - if (was_visible) - gtk_widget_show_all (server->window); - } - - g_dbus_method_invocation_return_value (invocation, NULL); - return; - } - - if (g_strcmp0 (method_name, "SetGroup") == 0) { - gint group; - - if (!server->keyboard) { - g_dbus_method_invocation_return_error (invocation, - G_IO_ERROR, - G_IO_ERROR_FAILED_HANDLED, - "keyboard is not set"); - return; - } - - g_variant_get (parameters, "(i)", &group); - eek_keyboard_set_group (server->keyboard, group); - - if (server->window) { - gboolean was_visible = gtk_widget_get_visible (server->window); - update_widget (server); - if (was_visible) - gtk_widget_show_all (server->window); - } - - g_dbus_method_invocation_return_value (invocation, NULL); - return; - } - - if (g_strcmp0 (method_name, "Show") == 0) { - if (!server->keyboard) { - g_dbus_method_invocation_return_error (invocation, - G_IO_ERROR, - G_IO_ERROR_FAILED_HANDLED, - "keyboard is not set"); - return; - } - - if (!server->window) - update_widget (server); - g_assert (server->window); - gtk_widget_show_all (server->window); - g_dbus_method_invocation_return_value (invocation, NULL); - g_object_notify (G_OBJECT(server->window), "visible"); - return; - } - - if (g_strcmp0 (method_name, "Hide") == 0) { - if (server->window) - gtk_widget_hide (server->window); - g_dbus_method_invocation_return_value (invocation, NULL); - g_object_notify (G_OBJECT(server->window), "visible"); - return; - } - - if (g_strcmp0 (method_name, "PressKey") == 0 || - g_strcmp0 (method_name, "ReleaseKey") == 0) { - EekKey *key; - guint keycode; - - if (!server->keyboard) { - g_dbus_method_invocation_return_error (invocation, - G_IO_ERROR, - G_IO_ERROR_FAILED_HANDLED, - "keyboard is not set"); - return; - } - - g_variant_get (parameters, "(u)", &keycode); - key = eek_keyboard_find_key_by_keycode (server->keyboard, keycode); - - if (!key) { - g_dbus_method_invocation_return_error (invocation, - G_IO_ERROR, - G_IO_ERROR_FAILED_HANDLED, - "key for %u is not found", - keycode); - return; - } - - if (g_strcmp0 (method_name, "PressKey") == 0) { - g_signal_handler_block (server->keyboard, - server->key_pressed_handler); - g_signal_emit_by_name (key, "pressed"); - g_signal_handler_unblock (server->keyboard, - server->key_pressed_handler); - } else { - g_signal_handler_block (server->keyboard, - server->key_released_handler); - g_signal_emit_by_name (key, "released"); - g_signal_handler_unblock (server->keyboard, - server->key_released_handler); - } - - g_dbus_method_invocation_return_value (invocation, NULL); - return; - } - - g_return_if_reached (); -} - -EekboardServer * -eekboard_server_new (const gchar *object_path, - GDBusConnection *connection) -{ - return g_object_new (EEKBOARD_TYPE_SERVER, - "object-path", object_path, - "connection", connection, - NULL); -} diff --git a/src/system-client.c b/src/system-client.c index cb4f7c7d..bb101918 100644 --- a/src/system-client.c +++ b/src/system-client.c @@ -50,9 +50,10 @@ typedef struct _EekboardSystemClientClass EekboardSystemClientClass; struct _EekboardSystemClient { GObject parent; - EekboardKeyboard *keyboard; + EekboardServer *server; + EekboardContext *context; - EekKeyboard *description; + EekKeyboard *keyboard; GdkDisplay *display; XklEngine *xkl_engine; XklConfigRegistry *xkl_config_registry; @@ -101,7 +102,7 @@ static SPIBoolean keystroke_listener_cb (const AccessibleKeystroke *stroke, void *user_data); #endif /* HAVE_CSPI */ -static void set_description (EekboardSystemClient *client); +static void set_keyboard (EekboardSystemClient *client); static void eekboard_system_client_set_property (GObject *object, @@ -111,16 +112,21 @@ eekboard_system_client_set_property (GObject *object, { EekboardSystemClient *client = EEKBOARD_SYSTEM_CLIENT(object); GDBusConnection *connection; - GError *error; switch (prop_id) { case PROP_CONNECTION: connection = g_value_get_object (value); - error = NULL; - client->keyboard = eekboard_keyboard_new ("/com/redhat/Eekboard/Keyboard", - connection, - NULL, - &error); + + client->server = eekboard_server_new (connection, NULL); + g_assert (client->server); + + client->context = + eekboard_server_create_context (client->server, + "eekboard-system-client", + NULL); + g_assert (client->context); + + eekboard_server_push_context (client->server, client->context, NULL); break; default: g_object_set_property (object, @@ -146,16 +152,25 @@ eekboard_system_client_dispose (GObject *object) eekboard_system_client_disable_fakekey (client); #endif /* HAVE_FAKEKEY */ + if (client->context) { + if (client->server) { + eekboard_server_pop_context (client->server, NULL); + } + + g_object_unref (client->context); + client->context = NULL; + } + + if (client->server) { + g_object_unref (client->server); + client->server = NULL; + } + if (client->keyboard) { g_object_unref (client->keyboard); client->keyboard = NULL; } - if (client->description) { - g_object_unref (client->description); - client->description = NULL; - } - #ifdef HAVE_FAKEKEY if (client->fakekey) { client->fakekey = NULL; @@ -192,11 +207,12 @@ eekboard_system_client_class_init (EekboardSystemClientClass *klass) static void eekboard_system_client_init (EekboardSystemClient *client) { - client->keyboard = NULL; + client->server = NULL; + client->context = NULL; client->display = NULL; client->xkl_engine = NULL; client->xkl_config_registry = NULL; - client->description = NULL; + client->keyboard = NULL; client->key_pressed_handler = 0; client->key_released_handler = 0; client->xkl_config_changed_handler = 0; @@ -246,7 +262,7 @@ eekboard_system_client_enable_xkl (EekboardSystemClient *client) xkl_engine_start_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE); - set_description (client); + set_keyboard (client); return TRUE; } @@ -341,13 +357,15 @@ focus_listener_cb (const AccessibleEvent *event, case SPI_ROLE_PASSWORD_TEXT: case SPI_ROLE_TERMINAL: case SPI_ROLE_ENTRY: - if (g_strcmp0 (event->type, "focus") == 0 || event->detail1 == 1) - eekboard_keyboard_show (client->keyboard); + if (g_strcmp0 (event->type, "focus") == 0 || event->detail1 == 1) { + eekboard_context_show_keyboard (client->context, NULL); + } default: ; } - } else - eekboard_keyboard_hide (client->keyboard); + } else { + eekboard_context_hide_keyboard (client->context, NULL); + } return FALSE; } @@ -361,7 +379,7 @@ keystroke_listener_cb (const AccessibleKeystroke *stroke, /* Ignore modifiers since the keystroke listener does not called when a modifier key is released. */ - key = eek_keyboard_find_key_by_keycode (client->description, + key = eek_keyboard_find_key_by_keycode (client->keyboard, stroke->keycode); if (key) { EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0); @@ -369,10 +387,12 @@ keystroke_listener_cb (const AccessibleKeystroke *stroke, return FALSE; } - if (stroke->type == SPI_KEY_PRESSED) - eekboard_keyboard_press_key (client->keyboard, stroke->keycode); - else - eekboard_keyboard_release_key (client->keyboard, stroke->keycode); + if (stroke->type == SPI_KEY_PRESSED) { + eekboard_context_press_key (client->context, stroke->keycode, NULL); + } else { + eekboard_context_release_key (client->context, stroke->keycode, NULL); + } + return TRUE; } #endif /* HAVE_CSPI */ @@ -403,7 +423,7 @@ on_xkl_config_changed (XklEngine *xklengine, { EekboardSystemClient *client = user_data; - set_description (client); + set_keyboard (client); #ifdef HAVE_FAKEKEY if (client->fakekey) @@ -412,23 +432,23 @@ on_xkl_config_changed (XklEngine *xklengine, } static void -set_description (EekboardSystemClient *client) +set_keyboard (EekboardSystemClient *client) { EekLayout *layout; gchar *keyboard_name; static gint keyboard_serial = 0; - if (client->description) - g_object_unref (client->description); + if (client->keyboard) + g_object_unref (client->keyboard); layout = eek_xkl_layout_new (); - client->description = eek_keyboard_new (layout, CSW, CSH); - eek_keyboard_set_modifier_behavior (client->description, + client->keyboard = eek_keyboard_new (layout, CSW, CSH); + eek_keyboard_set_modifier_behavior (client->keyboard, EEK_MODIFIER_BEHAVIOR_LATCH); keyboard_name = g_strdup_printf ("keyboard%d", keyboard_serial++); - eek_element_set_name (EEK_ELEMENT(client->description), keyboard_name); + eek_element_set_name (EEK_ELEMENT(client->keyboard), keyboard_name); - eekboard_keyboard_set_description (client->keyboard, client->description); + eekboard_context_set_keyboard (client->context, client->keyboard, NULL); } static void @@ -440,11 +460,10 @@ on_xkl_state_changed (XklEngine *xklengine, { EekboardSystemClient *client = user_data; - if (type == GROUP_CHANGED && client->description) { - gint group = eek_keyboard_get_group (client->description); + if (type == GROUP_CHANGED && client->keyboard) { + gint group = eek_keyboard_get_group (client->keyboard); if (group != value) { - eek_keyboard_set_group (client->description, value); - eekboard_keyboard_set_group (client->keyboard, value); + eekboard_context_set_group (client->context, value, NULL); } } } @@ -480,7 +499,7 @@ on_key_pressed (EekKeyboard *keyboard, g_assert (client->fakekey); - modifiers = eek_keyboard_get_modifiers (client->description); + modifiers = eek_keyboard_get_modifiers (client->keyboard); fakekey_modefiers = get_fakekey_modifiers (modifiers); symbol = eek_key_get_symbol_with_fallback (key, 0, 0); keycode = eek_key_get_keycode (key); @@ -515,10 +534,10 @@ eekboard_system_client_enable_fakekey (EekboardSystemClient *client) g_assert (client->fakekey); client->key_pressed_handler = - g_signal_connect (client->description, "key-pressed", + g_signal_connect (client->keyboard, "key-pressed", G_CALLBACK(on_key_pressed), client); client->key_released_handler = - g_signal_connect (client->description, "key-released", + g_signal_connect (client->keyboard, "key-released", G_CALLBACK(on_key_released), client); return TRUE;