From bb85885e5d8d639e983c8b182a35ef75f279e800 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Sat, 20 Aug 2011 09:43:20 +0900 Subject: [PATCH] Revamp server-client API. --- .gitignore | 1 + bindings/python/eekboard/eekboard.py | 14 +- eekboard/Makefile.am | 40 +- ...{eekboard-eekboard.c => eekboard-client.c} | 104 +- eekboard/eekboard-client.h | 75 ++ eekboard/eekboard-context-service.c | 904 ++++++++++++++ eekboard/eekboard-context-service.h | 81 ++ eekboard/eekboard-context.c | 54 +- eekboard/eekboard-context.h | 13 +- eekboard/eekboard-eekboard.h | 81 -- .../eekboard-service.c | 321 ++--- eekboard/eekboard-service.h | 66 + src/xklutil.c => eekboard/eekboard-xklutil.c | 2 +- src/xklutil.h => eekboard/eekboard-xklutil.h | 0 eekboard/eekboard.h | 26 - examples/simple-client/main.c | 32 +- src/Makefile.am | 18 +- src/client-main.c | 64 +- src/client.c | 184 +-- src/client.h | 53 +- src/server-context-service.c | 473 ++++++++ src/server-context-service.h | 40 + src/server-context.c | 1070 ----------------- src/server-main.c | 16 +- src/server-server.h | 41 - src/server-service.c | 71 ++ src/server-service.h | 38 + src/xml-main.c | 2 +- 28 files changed, 2233 insertions(+), 1651 deletions(-) rename eekboard/{eekboard-eekboard.c => eekboard-client.c} (76%) create mode 100644 eekboard/eekboard-client.h create mode 100644 eekboard/eekboard-context-service.c create mode 100644 eekboard/eekboard-context-service.h delete mode 100644 eekboard/eekboard-eekboard.h rename src/server-server.c => eekboard/eekboard-service.c (50%) create mode 100644 eekboard/eekboard-service.h rename src/xklutil.c => eekboard/eekboard-xklutil.c (99%) rename src/xklutil.h => eekboard/eekboard-xklutil.h (100%) delete mode 100644 eekboard/eekboard.h create mode 100644 src/server-context-service.c create mode 100644 src/server-context-service.h delete mode 100644 src/server-context.c delete mode 100644 src/server-server.h create mode 100644 src/server-service.c create mode 100644 src/server-service.h diff --git a/.gitignore b/.gitignore index c8f98a00..7e0d8cad 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ eek/*.typelib eekboard/*.pc eekboard/*.gir eekboard/*.typelib +eekboard/eekboard-marshalers.[ch] tests/eek-simple-test tests/eek-xkb-test tests/eek-xml-test diff --git a/bindings/python/eekboard/eekboard.py b/bindings/python/eekboard/eekboard.py index 453d3305..0af27c9d 100644 --- a/bindings/python/eekboard/eekboard.py +++ b/bindings/python/eekboard/eekboard.py @@ -21,7 +21,7 @@ import gobject from context import Context class Eekboard(gobject.GObject): - __gtype_name__ = "PYEekboardEekboard" + __gtype_name__ = "PYEekboardClient" __gsignals__ = { 'destroyed': ( gobject.SIGNAL_RUN_LAST, @@ -32,18 +32,18 @@ class Eekboard(gobject.GObject): def __init__(self): super(Eekboard, self).__init__() self.__connection = Gio.bus_get_sync(Gio.BusType.SESSION, None) - self.__eekboard = gi.repository.Eekboard.Eekboard.new(self.__connection, None); - self.__eekboard.connect('destroyed', lambda *args: self.emit('destroyed')) + self.__client = gi.repository.Eekboard.Client.new(self.__connection, None); + self.__client.connect('destroyed', lambda *args: self.emit('destroyed')) def create_context(self, client_name): - context = self.__eekboard.create_context(client_name, None) + context = self.__client.create_context(client_name, None) return Context(context) def push_context(self, context): - self.__eekboard.push_context(context.get_giobject(), None) + self.__client.push_context(context.get_giobject(), None) def pop_context(self): - self.__eekboard.pop_context(None) + self.__client.pop_context(None) def destroy_context(self, context): - self.__eekboard.destroy_context(context.get_giobject(), None) + self.__client.destroy_context(context.get_giobject(), None) diff --git a/eekboard/Makefile.am b/eekboard/Makefile.am index 4ff33aaa..5478d291 100644 --- a/eekboard/Makefile.am +++ b/eekboard/Makefile.am @@ -18,29 +18,43 @@ lib_LTLIBRARIES = libeekboard.la -libeekboard_headers = \ - eekboard.h \ - eekboard-eekboard.h \ - eekboard-context.h -libeekboard_private_headers = \ +libeekboard_headers = \ + eekboard-service.h \ + eekboard-context-service.h \ + eekboard-client.h \ + eekboard-context.h \ + eekboard-xklutil.h +libeekboard_private_headers = \ eekboard-marshalers.h libeekboard_sources = \ - eekboard-eekboard.c \ - eekboard-context.c + eekboard-service.c \ + eekboard-context-service.c \ + eekboard-client.c \ + eekboard-context.c \ + eekboard-xklutil.c libeekboard_marshalers_sources = \ - eekboard-marshalers.c \ + eekboard-marshalers.c \ eekboard-marshalers.h -BUILT_SOURCES = \ +BUILT_SOURCES = \ $(libeekboard_marshalers_sources) -libeekboard_la_SOURCES = \ - $(libeekboard_sources) \ +libeekboard_la_SOURCES = \ + $(libeekboard_sources) \ eekboard-marshalers.c -libeekboard_la_CFLAGS = -DEEKBOARD_COMPILATION=1 -I$(top_srcdir) $(GIO2_CFLAGS) -libeekboard_la_LIBADD = $(top_builddir)/eek/libeek.la $(GIO2_LIBS) +libeekboard_la_CFLAGS = \ + -DEEKBOARD_COMPILATION=1 \ + -DKEYBOARDDIR=\"$(pkgdatadir)/keyboards\" \ + -I$(top_srcdir) \ + $(GIO2_CFLAGS) \ + $(LIBXKLAVIER_CFLAGS) +libeekboard_la_LIBADD = \ + $(top_builddir)/eek/libeek.la \ + $(top_builddir)/eek/libeek-xkl.la \ + $(GIO2_LIBS) \ + $(LIBXKLAVIER_LIBS) eekboarddir = $(includedir)/eekboard-$(EEK_API_VERSION)/eekboard eekboard_HEADERS = $(libeekboard_headers) diff --git a/eekboard/eekboard-eekboard.c b/eekboard/eekboard-client.c similarity index 76% rename from eekboard/eekboard-eekboard.c rename to eekboard/eekboard-client.c index 108807d9..234165c2 100644 --- a/eekboard/eekboard-eekboard.c +++ b/eekboard/eekboard-client.c @@ -17,17 +17,17 @@ */ /** - * SECTION:eekboard-eekboard + * SECTION:eekboard-client * @short_description: D-Bus proxy of eekboard-server * - * The #EekboardEekboard class provides a client side access to eekboard-server. + * The #EekboardClient class provides a client side access to eekboard-server. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ -#include "eekboard/eekboard-eekboard.h" +#include "eekboard/eekboard-client.h" enum { DESTROYED, @@ -36,53 +36,53 @@ enum { static guint signals[LAST_SIGNAL] = { 0, }; -G_DEFINE_TYPE (EekboardEekboard, eekboard_eekboard, G_TYPE_DBUS_PROXY); +G_DEFINE_TYPE (EekboardClient, eekboard_client, G_TYPE_DBUS_PROXY); -#define EEKBOARD_EEKBOARD_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_EEKBOARD, EekboardEekboardPrivate)) +#define EEKBOARD_CLIENT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_CLIENT, EekboardClientPrivate)) -struct _EekboardEekboardPrivate +struct _EekboardClientPrivate { GHashTable *context_hash; }; static void -eekboard_eekboard_real_destroyed (EekboardEekboard *self) +eekboard_client_real_destroyed (EekboardClient *self) { - EekboardEekboardPrivate *priv = EEKBOARD_EEKBOARD_GET_PRIVATE(self); + EekboardClientPrivate *priv = EEKBOARD_CLIENT_GET_PRIVATE(self); - // g_debug ("eekboard_eekboard_real_destroyed"); + // g_debug ("eekboard_client_real_destroyed"); g_hash_table_remove_all (priv->context_hash); } static void -eekboard_eekboard_dispose (GObject *object) +eekboard_client_dispose (GObject *object) { - EekboardEekboardPrivate *priv = EEKBOARD_EEKBOARD_GET_PRIVATE(object); + EekboardClientPrivate *priv = EEKBOARD_CLIENT_GET_PRIVATE(object); if (priv->context_hash) { g_hash_table_destroy (priv->context_hash); priv->context_hash = NULL; } - G_OBJECT_CLASS (eekboard_eekboard_parent_class)->dispose (object); + G_OBJECT_CLASS (eekboard_client_parent_class)->dispose (object); } static void -eekboard_eekboard_class_init (EekboardEekboardClass *klass) +eekboard_client_class_init (EekboardClientClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); g_type_class_add_private (gobject_class, - sizeof (EekboardEekboardPrivate)); + sizeof (EekboardClientPrivate)); - klass->destroyed = eekboard_eekboard_real_destroyed; + klass->destroyed = eekboard_client_real_destroyed; - gobject_class->dispose = eekboard_eekboard_dispose; + gobject_class->dispose = eekboard_client_dispose; /** - * EekboardEekboard::destroyed: - * @eekboard: an #EekboardEekboard + * EekboardClient::destroyed: + * @eekboard: an #EekboardClient * * The ::destroyed signal is emitted each time the name of remote * end is vanished. @@ -91,7 +91,7 @@ eekboard_eekboard_class_init (EekboardEekboardClass *klass) g_signal_new (I_("destroyed"), G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(EekboardEekboardClass, destroyed), + G_STRUCT_OFFSET(EekboardClientClass, destroyed), NULL, NULL, g_cclosure_marshal_VOID__VOID, @@ -100,11 +100,11 @@ eekboard_eekboard_class_init (EekboardEekboardClass *klass) } static void -eekboard_eekboard_init (EekboardEekboard *self) +eekboard_client_init (EekboardClient *self) { - EekboardEekboardPrivate *priv; + EekboardClientPrivate *priv; - priv = self->priv = EEKBOARD_EEKBOARD_GET_PRIVATE(self); + priv = self->priv = EEKBOARD_CLIENT_GET_PRIVATE(self); priv->context_hash = g_hash_table_new_full (g_str_hash, g_str_equal, @@ -117,19 +117,19 @@ eekboard_name_vanished_callback (GDBusConnection *connection, const gchar *name, gpointer user_data) { - EekboardEekboard *eekboard = user_data; + EekboardClient *eekboard = user_data; g_signal_emit_by_name (eekboard, "destroyed", NULL); } /** - * eekboard_eekboard_new: + * eekboard_client_new: * @connection: a #GDBusConnection * @cancellable: a #GCancellable * * Create a D-Bus proxy of eekboard-eekboard. */ -EekboardEekboard * -eekboard_eekboard_new (GDBusConnection *connection, +EekboardClient * +eekboard_client_new (GDBusConnection *connection, GCancellable *cancellable) { GInitable *initable; @@ -139,16 +139,16 @@ eekboard_eekboard_new (GDBusConnection *connection, error = NULL; initable = - g_initable_new (EEKBOARD_TYPE_EEKBOARD, + g_initable_new (EEKBOARD_TYPE_CLIENT, cancellable, &error, "g-connection", connection, - "g-name", "org.fedorahosted.Eekboard.Server", - "g-interface-name", "org.fedorahosted.Eekboard.Server", - "g-object-path", "/org/fedorahosted/Eekboard/Server", + "g-name", "org.fedorahosted.Eekboard", + "g-interface-name", "org.fedorahosted.Eekboard", + "g-object-path", "/org/fedorahosted/Eekboard", NULL); if (initable != NULL) { - EekboardEekboard *eekboard = EEKBOARD_EEKBOARD (initable); + EekboardClient *eekboard = EEKBOARD_CLIENT (initable); gchar *name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY(eekboard)); if (name_owner == NULL) { g_object_unref (eekboard); @@ -174,16 +174,16 @@ static void on_context_destroyed (EekboardContext *context, gpointer user_data) { - EekboardEekboard *eekboard = user_data; - EekboardEekboardPrivate *priv = EEKBOARD_EEKBOARD_GET_PRIVATE(eekboard); + EekboardClient *eekboard = user_data; + EekboardClientPrivate *priv = EEKBOARD_CLIENT_GET_PRIVATE(eekboard); g_hash_table_remove (priv->context_hash, g_dbus_proxy_get_object_path (G_DBUS_PROXY(context))); } /** - * eekboard_eekboard_create_context: - * @eekboard: an #EekboardEekboard + * eekboard_client_create_context: + * @eekboard: an #EekboardClient * @client_name: name of the client * @cancellable: a #GCancellable * @@ -192,14 +192,14 @@ on_context_destroyed (EekboardContext *context, * Return value: (transfer full): a newly created #EekboardContext. */ EekboardContext * -eekboard_eekboard_create_context (EekboardEekboard *eekboard, +eekboard_client_create_context (EekboardClient *eekboard, const gchar *client_name, GCancellable *cancellable) { GVariant *variant; const gchar *object_path; EekboardContext *context; - EekboardEekboardPrivate *priv; + EekboardClientPrivate *priv; GError *error; GDBusConnection *connection; @@ -225,7 +225,7 @@ eekboard_eekboard_create_context (EekboardEekboard *eekboard, return NULL; } - priv = EEKBOARD_EEKBOARD_GET_PRIVATE(eekboard); + priv = EEKBOARD_CLIENT_GET_PRIVATE(eekboard); g_hash_table_insert (priv->context_hash, g_strdup (object_path), g_object_ref (context)); @@ -250,19 +250,19 @@ eekboard_async_ready_callback (GObject *source_object, } /** - * eekboard_eekboard_push_context: - * @eekboard: an #EekboardEekboard + * eekboard_client_push_context: + * @eekboard: an #EekboardClient * @context: an #EekboardContext * @cancellable: a #GCancellable * * Enable the input context @context and disable the others. */ void -eekboard_eekboard_push_context (EekboardEekboard *eekboard, +eekboard_client_push_context (EekboardClient *eekboard, EekboardContext *context, GCancellable *cancellable) { - EekboardEekboardPrivate *priv; + EekboardClientPrivate *priv; const gchar *object_path; g_return_if_fail (EEKBOARD_IS_EEKBOARD(eekboard)); @@ -270,7 +270,7 @@ eekboard_eekboard_push_context (EekboardEekboard *eekboard, object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(context)); - priv = EEKBOARD_EEKBOARD_GET_PRIVATE(eekboard); + priv = EEKBOARD_CLIENT_GET_PRIVATE(eekboard); context = g_hash_table_lookup (priv->context_hash, object_path); if (!context) return; @@ -287,14 +287,14 @@ eekboard_eekboard_push_context (EekboardEekboard *eekboard, } /** - * eekboard_eekboard_pop_context: - * @eekboard: an #EekboardEekboard + * eekboard_client_pop_context: + * @eekboard: an #EekboardClient * @cancellable: a #GCancellable * * Disable the current input context and enable the previous one. */ void -eekboard_eekboard_pop_context (EekboardEekboard *eekboard, +eekboard_client_pop_context (EekboardClient *eekboard, GCancellable *cancellable) { g_return_if_fail (EEKBOARD_IS_EEKBOARD(eekboard)); @@ -310,25 +310,25 @@ eekboard_eekboard_pop_context (EekboardEekboard *eekboard, } /** - * eekboard_eekboard_destroy_context: - * @eekboard: an #EekboardEekboard + * eekboard_client_destroy_context: + * @eekboard: an #EekboardClient * @context: an #EekboardContext * @cancellable: a #GCancellable * * Remove @context from @eekboard. */ void -eekboard_eekboard_destroy_context (EekboardEekboard *eekboard, +eekboard_client_destroy_context (EekboardClient *eekboard, EekboardContext *context, GCancellable *cancellable) { - EekboardEekboardPrivate *priv; + EekboardClientPrivate *priv; const gchar *object_path; g_return_if_fail (EEKBOARD_IS_EEKBOARD(eekboard)); g_return_if_fail (EEKBOARD_IS_CONTEXT(context)); - priv = EEKBOARD_EEKBOARD_GET_PRIVATE(eekboard); + priv = EEKBOARD_CLIENT_GET_PRIVATE(eekboard); object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(context)); g_hash_table_remove (priv->context_hash, object_path); diff --git a/eekboard/eekboard-client.h b/eekboard/eekboard-client.h new file mode 100644 index 00000000..9a1adef4 --- /dev/null +++ b/eekboard/eekboard-client.h @@ -0,0 +1,75 @@ +/* + * 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_CLIENT_H +#define EEKBOARD_CLIENT_H 1 + +#define __EEKBOARD_CLIENT_H_INSIDE__ 1 + +#include +#include "eekboard/eekboard-context.h" + +G_BEGIN_DECLS + +#define EEKBOARD_TYPE_CLIENT (eekboard_client_get_type()) +#define EEKBOARD_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_CLIENT, EekboardClient)) +#define EEKBOARD_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_CLIENT, EekboardClientClass)) +#define EEKBOARD_IS_EEKBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_CLIENT)) +#define EEKBOARD_IS_EEKBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CLIENT)) +#define EEKBOARD_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CLIENT, EekboardClientClass)) + +typedef struct _EekboardClient EekboardClient; +typedef struct _EekboardClientClass EekboardClientClass; +typedef struct _EekboardClientPrivate EekboardClientPrivate; + +struct _EekboardClient { + /*< private >*/ + GDBusProxy parent; + + EekboardClientPrivate *priv; +}; + +struct _EekboardClientClass { + /*< private >*/ + GDBusProxyClass parent_class; + + /* signals */ + void (* destroyed) (EekboardClient *self); + + /*< private >*/ + /* padding */ + gpointer pdummy[23]; +}; + +GType eekboard_client_get_type (void) G_GNUC_CONST; + +EekboardClient *eekboard_client_new (GDBusConnection *connection, + GCancellable *cancellable); +EekboardContext *eekboard_client_create_context (EekboardClient *eekboard, + const gchar *client_name, + GCancellable *cancellable); +void eekboard_client_push_context (EekboardClient *eekboard, + EekboardContext *context, + GCancellable *cancellable); +void eekboard_client_pop_context (EekboardClient *eekboard, + GCancellable *cancellable); +void eekboard_client_destroy_context (EekboardClient *eekboard, + EekboardContext *context, + GCancellable *cancellable); + +G_END_DECLS +#endif /* EEKBOARD_CLIENT_H */ diff --git a/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c new file mode 100644 index 00000000..8b57f3cd --- /dev/null +++ b/eekboard/eekboard-context-service.c @@ -0,0 +1,904 @@ +/* + * 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-service.h" +#include "eekboard/eekboard-xklutil.h" +#include "eek/eek-xkl.h" + +#define CSW 640 +#define CSH 480 + +enum { + PROP_0, + PROP_OBJECT_PATH, + PROP_CONNECTION, + PROP_CLIENT_NAME, + PROP_KEYBOARD, + PROP_VISIBLE, + PROP_FULLSCREEN, + PROP_LAST +}; + +enum { + ENABLED, + DISABLED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0, }; + +#define EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServicePrivate)) + +struct _EekboardContextServicePrivate { + GDBusConnection *connection; + GDBusNodeInfo *introspection_data; + guint registration_id; + char *object_path; + char *client_name; + + gboolean enabled; + gboolean visible; + gboolean fullscreen; + + EekKeyboard *keyboard; + GHashTable *keyboard_hash; + + gulong key_pressed_handler; + gulong key_released_handler; + + EekKey *repeat_key; + guint repeat_timeout_id; + gboolean repeat_triggered; + + GSettings *settings; +}; + +G_DEFINE_TYPE (EekboardContextService, eekboard_context_service, G_TYPE_OBJECT); + +static const gchar introspection_xml[] = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + /* signals */ + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +static void connect_keyboard_signals (EekboardContextService *context); +static void disconnect_keyboard_signals + (EekboardContextService *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 void emit_visibility_changed_signal + (EekboardContextService *context, + gboolean visible); + +static const GDBusInterfaceVTable interface_vtable = +{ + handle_method_call, + NULL, + NULL +}; + +static EekKeyboard * +eekboard_context_service_real_create_keyboard (EekboardContextService *self, + const gchar *keyboard_type) +{ + EekKeyboard *keyboard; + EekLayout *layout; + + if (g_str_has_prefix (keyboard_type, "xkb:")) { + XklConfigRec *rec = + eekboard_xkl_config_rec_from_string (&keyboard_type[4]); + + layout = eek_xkl_layout_new (); + if (!eek_xkl_layout_set_config (EEK_XKL_LAYOUT(layout), rec)) { + g_object_unref (layout); + return NULL; + } + } else { + gchar *path; + GFile *file; + GFileInputStream *input; + GError *error; + + path = g_strdup_printf ("%s/%s.xml", KEYBOARDDIR, keyboard_type); + file = g_file_new_for_path (path); + g_free (path); + + error = NULL; + input = g_file_read (file, NULL, &error); + if (input == NULL) { + g_object_unref (file); + return NULL; + } + layout = eek_xml_layout_new (G_INPUT_STREAM(input)); + } + keyboard = eek_keyboard_new (layout, CSW, CSH); + g_object_unref (layout); + + return keyboard; +} + +static void +eekboard_context_service_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object); + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + GDBusConnection *connection; + gboolean was_visible; + + switch (prop_id) { + case PROP_OBJECT_PATH: + if (priv->object_path) + g_free (priv->object_path); + priv->object_path = g_strdup (g_value_get_string (value)); + break; + case PROP_CONNECTION: + connection = g_value_get_object (value); + if (priv->connection) + g_object_unref (priv->connection); + priv->connection = g_object_ref (connection); + break; + case PROP_CLIENT_NAME: + if (priv->client_name) + g_free (priv->client_name); + priv->client_name = g_strdup (g_value_get_string (value)); + break; + case PROP_KEYBOARD: + if (priv->keyboard) + g_object_unref (priv->keyboard); + priv->keyboard = g_value_get_object (value); + break; + case PROP_VISIBLE: + was_visible = priv->visible; + priv->visible = g_value_get_boolean (value); + if (was_visible != priv->visible) + emit_visibility_changed_signal (EEKBOARD_CONTEXT_SERVICE(object), + priv->visible); + break; + case PROP_FULLSCREEN: + priv->fullscreen = g_value_get_boolean (value); + break; + default: + g_object_set_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +eekboard_context_service_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object); + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + switch (prop_id) { + case PROP_OBJECT_PATH: + g_value_set_string (value, priv->object_path); + break; + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); + break; + case PROP_CLIENT_NAME: + g_value_set_string (value, priv->client_name); + break; + case PROP_KEYBOARD: + g_value_set_object (value, priv->keyboard); + break; + case PROP_VISIBLE: + g_value_set_boolean (value, priv->visible); + break; + case PROP_FULLSCREEN: + g_value_set_boolean (value, priv->fullscreen); + break; + default: + g_object_set_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +eekboard_context_service_dispose (GObject *object) +{ + EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object); + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + if (priv->keyboard_hash) { + g_hash_table_destroy (priv->keyboard_hash); + priv->keyboard_hash = NULL; + } + + if (priv->connection) { + if (priv->registration_id > 0) { + g_dbus_connection_unregister_object (priv->connection, + priv->registration_id); + priv->registration_id = 0; + } + + g_object_unref (priv->connection); + priv->connection = NULL; + } + + if (priv->introspection_data) { + g_dbus_node_info_unref (priv->introspection_data); + priv->introspection_data = NULL; + } + + G_OBJECT_CLASS (eekboard_context_service_parent_class)->dispose (object); +} + +static void +eekboard_context_service_finalize (GObject *object) +{ + EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object); + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + g_free (priv->object_path); + g_free (priv->client_name); + + G_OBJECT_CLASS (eekboard_context_service_parent_class)->finalize (object); +} + +static void +eekboard_context_service_constructed (GObject *object) +{ + EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE (object); + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + if (priv->connection && priv->object_path) { + GError *error = NULL; + + priv->registration_id = g_dbus_connection_register_object + (priv->connection, + priv->object_path, + priv->introspection_data->interfaces[0], + &interface_vtable, + context, + NULL, + &error); + } +} + +static void +eekboard_context_service_class_init (EekboardContextServiceClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (gobject_class, + sizeof (EekboardContextServicePrivate)); + + klass->create_keyboard = eekboard_context_service_real_create_keyboard; + klass->show_keyboard = NULL; + klass->hide_keyboard = NULL; + + gobject_class->constructed = eekboard_context_service_constructed; + gobject_class->set_property = eekboard_context_service_set_property; + gobject_class->get_property = eekboard_context_service_get_property; + gobject_class->dispose = eekboard_context_service_dispose; + gobject_class->finalize = eekboard_context_service_finalize; + + signals[ENABLED] = + g_signal_new (I_("enabled"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekboardContextServiceClass, enabled), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + signals[DISABLED] = + g_signal_new (I_("disabled"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekboardContextServiceClass, disabled), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + pspec = g_param_spec_string ("object-path", + "Object-path", + "Object-path", + NULL, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + 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 | G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_CONNECTION, + pspec); + + pspec = g_param_spec_string ("client-name", + "Client-name", + "Client-name", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_CLIENT_NAME, + pspec); + + pspec = g_param_spec_object ("keyboard", + "Keyboard", + "Keyboard", + EEK_TYPE_KEYBOARD, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_KEYBOARD, + pspec); + + pspec = g_param_spec_boolean ("visible", + "Visible", + "Visible", + FALSE, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_VISIBLE, + pspec); + + pspec = g_param_spec_boolean ("fullscreen", + "Fullscreen", + "Fullscreen", + FALSE, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_FULLSCREEN, + pspec); +} + +static void +eekboard_context_service_init (EekboardContextService *context) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + GError *error; + + error = NULL; + priv->introspection_data = + g_dbus_node_info_new_for_xml (introspection_xml, &error); + g_assert (priv->introspection_data != NULL); + + priv->keyboard_hash = + g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify)g_object_unref); + + priv->settings = g_settings_new ("org.fedorahosted.eekboard"); +} + +static void +disconnect_keyboard_signals (EekboardContextService *context) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + if (g_signal_handler_is_connected (priv->keyboard, + priv->key_pressed_handler)) + g_signal_handler_disconnect (priv->keyboard, + priv->key_pressed_handler); + if (g_signal_handler_is_connected (priv->keyboard, + priv->key_released_handler)) + g_signal_handler_disconnect (priv->keyboard, + priv->key_released_handler); +} + +static void +emit_visibility_changed_signal (EekboardContextService *context, + gboolean visible) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + if (priv->connection && priv->enabled) { + GError *error = NULL; + g_dbus_connection_emit_signal (priv->connection, + NULL, + priv->object_path, + EEKBOARD_CONTEXT_SERVICE_INTERFACE, + "VisibilityChanged", + g_variant_new ("(b)", visible), + &error); + g_assert_no_error (error); + } +} + +static void +emit_group_changed_signal (EekboardContextService *context, + gint group) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + if (priv->connection && priv->enabled) { + GError *error = NULL; + g_dbus_connection_emit_signal (priv->connection, + NULL, + priv->object_path, + EEKBOARD_CONTEXT_SERVICE_INTERFACE, + "GroupChanged", + g_variant_new ("(i)", group), + &error); + g_assert_no_error (error); + } +} + +static void +emit_key_pressed_dbus_signal (EekboardContextService *context, + EekKey *key) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + if (priv->connection && priv->enabled) { + const gchar *keyname = eek_element_get_name (EEK_ELEMENT(key)); + EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0); + guint modifiers = eek_keyboard_get_modifiers (priv->keyboard); + GVariant *variant; + GError *error; + + variant = eek_serializable_serialize (EEK_SERIALIZABLE(symbol)); + + error = NULL; + g_dbus_connection_emit_signal (priv->connection, + NULL, + priv->object_path, + EEKBOARD_CONTEXT_SERVICE_INTERFACE, + "KeyPressed", + g_variant_new ("(svu)", + keyname, + variant, + modifiers), + &error); + g_variant_unref (variant); + g_assert_no_error (error); + } +} + +static gboolean on_repeat_timeout (EekboardContextService *context); + +static gboolean +on_repeat_timeout (EekboardContextService *context) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + gint delay = g_settings_get_int (priv->settings, "repeat-interval"); + + emit_key_pressed_dbus_signal (context, priv->repeat_key); + + priv->repeat_timeout_id = + g_timeout_add (delay, + (GSourceFunc)on_repeat_timeout, + context); + + return FALSE; +} + +static gboolean +on_repeat_timeout_init (EekboardContextService *context) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + emit_key_pressed_dbus_signal (context, priv->repeat_key); + + /* FIXME: clear modifiers for further key repeat; better not + depend on modifier behavior is LATCH */ + eek_keyboard_set_modifiers (priv->keyboard, 0); + + /* reschedule repeat timeout only when "repeat" option is set */ + if (g_settings_get_boolean (priv->settings, "repeat")) { + gint delay = g_settings_get_int (priv->settings, "repeat-interval"); + priv->repeat_timeout_id = + g_timeout_add (delay, + (GSourceFunc)on_repeat_timeout, + context); + } else + priv->repeat_timeout_id = 0; + + return FALSE; +} + +static void +on_key_pressed (EekKeyboard *keyboard, + EekKey *key, + gpointer user_data) +{ + EekboardContextService *context = user_data; + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + gint delay = g_settings_get_int (priv->settings, "repeat-delay"); + + if (priv->repeat_timeout_id) { + g_source_remove (priv->repeat_timeout_id); + priv->repeat_timeout_id = 0; + } + + priv->repeat_key = key; + priv->repeat_timeout_id = + g_timeout_add (delay, + (GSourceFunc)on_repeat_timeout_init, + context); +} + +static void +on_key_released (EekKeyboard *keyboard, + EekKey *key, + gpointer user_data) +{ + EekboardContextService *context = user_data; + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + if (priv->repeat_timeout_id > 0) { + g_source_remove (priv->repeat_timeout_id); + priv->repeat_timeout_id = 0; + + /* KeyPressed signal has not been emitted in repeat handler */ + emit_key_pressed_dbus_signal (context, priv->repeat_key); + } +} + +static void +connect_keyboard_signals (EekboardContextService *context) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + + priv->key_pressed_handler = + g_signal_connect (priv->keyboard, "key-pressed", + G_CALLBACK(on_key_pressed), + context); + priv->key_released_handler = + g_signal_connect (priv->keyboard, "key-released", + G_CALLBACK(on_key_released), + 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) +{ + EekboardContextService *context = user_data; + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + EekboardContextServiceClass *klass = EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context); + + if (g_strcmp0 (method_name, "AddKeyboard") == 0) { + const gchar *keyboard_type; + static guint keyboard_id = 0; + EekKeyboard *keyboard; + + g_variant_get (parameters, "(&s)", &keyboard_type); + keyboard = klass->create_keyboard (context, keyboard_type); + + if (keyboard == NULL) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "can't create a keyboard"); + return; + } + + eek_keyboard_set_modifier_behavior (keyboard, + EEK_MODIFIER_BEHAVIOR_LATCH); + + keyboard_id++; + g_hash_table_insert (priv->keyboard_hash, + GUINT_TO_POINTER(keyboard_id), + keyboard); + g_object_set_data (G_OBJECT(keyboard), + "keyboard-id", + GUINT_TO_POINTER(keyboard_id)); + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(u)", + keyboard_id)); + return; + } + + if (g_strcmp0 (method_name, "RemoveKeyboard") == 0) { + guint keyboard_id, current_keyboard_id; + + g_variant_get (parameters, "(u)", &keyboard_id); + + current_keyboard_id = + GPOINTER_TO_UINT (g_object_get_data (G_OBJECT(priv->keyboard), + "keyboard-id")); + if (keyboard_id == current_keyboard_id) { + disconnect_keyboard_signals (context); + priv->keyboard = NULL; + g_object_notify (G_OBJECT(context), "keyboard"); + } + + g_hash_table_remove (priv->keyboard_hash, + GUINT_TO_POINTER(keyboard_id)); + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (g_strcmp0 (method_name, "SetKeyboard") == 0) { + EekKeyboard *keyboard; + guint keyboard_id; + gint group; + + g_variant_get (parameters, "(u)", &keyboard_id); + + keyboard = g_hash_table_lookup (priv->keyboard_hash, + GUINT_TO_POINTER(keyboard_id)); + if (!keyboard) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "no such keyboard"); + return; + } + + if (keyboard == priv->keyboard) { + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (priv->keyboard) + disconnect_keyboard_signals (context); + + priv->keyboard = keyboard; + connect_keyboard_signals (context); + + g_dbus_method_invocation_return_value (invocation, NULL); + + group = eek_element_get_group (EEK_ELEMENT(priv->keyboard)); + emit_group_changed_signal (context, group); + + g_object_notify (G_OBJECT(context), "keyboard"); + return; + } + + if (g_strcmp0 (method_name, "SetFullscreen") == 0) { + gboolean fullscreen; + + g_variant_get (parameters, "(b)", &fullscreen); + + if (priv->fullscreen == fullscreen) { + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + priv->fullscreen = fullscreen; + g_dbus_method_invocation_return_value (invocation, NULL); + + g_object_notify (G_OBJECT(context), "fullscreen"); + return; + } + + if (g_strcmp0 (method_name, "SetGroup") == 0) { + gint group; + + if (!priv->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_element_set_group (EEK_ELEMENT(priv->keyboard), group); + g_dbus_method_invocation_return_value (invocation, NULL); + emit_group_changed_signal (context, group); + return; + } + + if (g_strcmp0 (method_name, "ShowKeyboard") == 0) { + if (!priv->keyboard) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "keyboard is not set"); + return; + } + + if (klass->show_keyboard) + klass->show_keyboard (context); + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (g_strcmp0 (method_name, "HideKeyboard") == 0) { + if (klass->hide_keyboard) + klass->hide_keyboard (context); + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (g_strcmp0 (method_name, "PressKeycode") == 0 || + g_strcmp0 (method_name, "ReleaseKeycode") == 0) { + EekKey *key; + guint keycode; + + if (!priv->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 (priv->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, "PressKeycode") == 0) { + g_signal_handler_block (priv->keyboard, + priv->key_pressed_handler); + g_signal_emit_by_name (key, "pressed"); + g_signal_handler_unblock (priv->keyboard, + priv->key_pressed_handler); + } else { + g_signal_handler_block (priv->keyboard, + priv->key_released_handler); + g_signal_emit_by_name (key, "released"); + g_signal_handler_unblock (priv->keyboard, + priv->key_released_handler); + } + + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + g_return_if_reached (); +} + +void +eekboard_context_service_enable (EekboardContextService *context) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + GError *error; + + g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context)); + g_return_if_fail (priv->connection); + + if (!priv->enabled) { + priv->enabled = TRUE; + + error = NULL; + g_dbus_connection_emit_signal (priv->connection, + NULL, + priv->object_path, + EEKBOARD_CONTEXT_SERVICE_INTERFACE, + "Enabled", + NULL, + &error); + g_assert_no_error (error); + g_signal_emit_by_name (context, "enabled", NULL); + } +} + +void +eekboard_context_service_disable (EekboardContextService *context) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + GError *error; + + g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context)); + g_return_if_fail (priv->connection); + + if (priv->enabled) { + priv->enabled = FALSE; + + error = NULL; + g_dbus_connection_emit_signal (priv->connection, + NULL, + priv->object_path, + EEKBOARD_CONTEXT_SERVICE_INTERFACE, + "Disabled", + NULL, + &error); + g_assert_no_error (error); + g_signal_emit_by_name (context, "disabled", NULL); + } +} + +const EekKeyboard * +eekboard_context_service_get_keyboard (EekboardContextService *context) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + return priv->keyboard; +} + +gboolean +eekboard_context_service_get_fullscreen (EekboardContextService *context) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + return priv->fullscreen; +} + +const gchar * +eekboard_context_service_get_client_name (EekboardContextService *context) +{ + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + return priv->client_name; +} diff --git a/eekboard/eekboard-context-service.h b/eekboard/eekboard-context-service.h new file mode 100644 index 00000000..25f8e32d --- /dev/null +++ b/eekboard/eekboard-context-service.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 . + */ +#if !defined(__EEKBOARD_SERVICE_H_INSIDE__) && !defined(EEKBOARD_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef EEKBOARD_CONTEXT_SERVICE_H +#define EEKBOARD_CONTEXT_SERVICE_H 1 + +#include + +G_BEGIN_DECLS + +#define EEKBOARD_CONTEXT_SERVICE_PATH "/org/fedorahosted/Eekboard/Context_%d" +#define EEKBOARD_CONTEXT_SERVICE_INTERFACE "org.fedorahosted.Eekboard.Context" + +#define EEKBOARD_TYPE_CONTEXT_SERVICE (eekboard_context_service_get_type()) +#define EEKBOARD_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextService)) +#define EEKBOARD_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServiceClass)) +#define EEKBOARD_IS_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE)) +#define EEKBOARD_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CONTEXT_SERVICE)) +#define EEKBOARD_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServiceClass)) + +typedef struct _EekboardContextService EekboardContextService; +typedef struct _EekboardContextServiceClass EekboardContextServiceClass; +typedef struct _EekboardContextServicePrivate EekboardContextServicePrivate; + +struct _EekboardContextService { + GObject parent; + + EekboardContextServicePrivate *priv; +}; + +struct _EekboardContextServiceClass { + /*< private >*/ + GObjectClass parent_class; + + EekKeyboard *(*create_keyboard) (EekboardContextService *self, + const gchar *keyboard_type); + void (*show_keyboard) (EekboardContextService *self); + void (*hide_keyboard) (EekboardContextService *self); + + /* signals */ + void (*enabled) (EekboardContextService *self); + void (*disabled) (EekboardContextService *self); + + /*< private >*/ + /* padding */ + gpointer pdummy[24]; +}; + +GType eekboard_context_service_get_type + (void) G_GNUC_CONST; +void eekboard_context_service_enable + (EekboardContextService *context); +void eekboard_context_service_disable + (EekboardContextService *context); +const EekKeyboard *eekboard_context_service_get_keyboard + (EekboardContextService *context); +gboolean eekboard_context_service_get_fullscreen + (EekboardContextService *context); +const gchar * eekboard_context_service_get_client_name + (EekboardContextService *context); + +G_END_DECLS +#endif /* EEKBOARD_CONTEXT_SERVICE_H */ diff --git a/eekboard/eekboard-context.c b/eekboard/eekboard-context.c index c9570ec8..11be2446 100644 --- a/eekboard/eekboard-context.c +++ b/eekboard/eekboard-context.c @@ -45,7 +45,7 @@ static guint signals[LAST_SIGNAL] = { 0, }; enum { PROP_0, - PROP_KEYBOARD_VISIBLE, + PROP_VISIBLE, PROP_LAST }; @@ -56,7 +56,7 @@ G_DEFINE_TYPE (EekboardContext, eekboard_context, G_TYPE_DBUS_PROXY); struct _EekboardContextPrivate { - gboolean keyboard_visible; + gboolean visible; gboolean enabled; gboolean fullscreen; gint group; @@ -99,13 +99,13 @@ eekboard_context_real_g_signal (GDBusProxy *self, return; } - if (g_strcmp0 (signal_name, "KeyboardVisibilityChanged") == 0) { - gboolean keyboard_visible = FALSE; + if (g_strcmp0 (signal_name, "VisibilityChanged") == 0) { + gboolean visible = FALSE; - g_variant_get (parameters, "(b)", &keyboard_visible); - if (keyboard_visible != priv->keyboard_visible) { - priv->keyboard_visible = keyboard_visible; - g_object_notify (G_OBJECT(context), "keyboard-visible"); + g_variant_get (parameters, "(b)", &visible); + if (visible != priv->visible) { + priv->visible = visible; + g_object_notify (G_OBJECT(context), "visible"); } return; } @@ -159,8 +159,8 @@ eekboard_context_get_property (GObject *object, { EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE(object); switch (prop_id) { - case PROP_KEYBOARD_VISIBLE: - g_value_set_boolean (value, priv->keyboard_visible); + case PROP_VISIBLE: + g_value_set_boolean (value, priv->visible); break; default: g_object_get_property (object, @@ -190,17 +190,17 @@ eekboard_context_class_init (EekboardContextClass *klass) gobject_class->get_property = eekboard_context_get_property; /** - * EekboardContext:keyboard-visible: + * EekboardContext:visible: * * Flag to indicate if keyboard is visible or not. */ - pspec = g_param_spec_boolean ("keyboard-visible", - "Keyboard-visible", + pspec = g_param_spec_boolean ("visible", + "visible", "Flag that indicates if keyboard is visible", FALSE, G_PARAM_READABLE); g_object_class_install_property (gobject_class, - PROP_KEYBOARD_VISIBLE, + PROP_VISIBLE, pspec); /** @@ -321,7 +321,7 @@ eekboard_context_new (GDBusConnection *connection, g_initable_new (EEKBOARD_TYPE_CONTEXT, cancellable, &error, - "g-name", "org.fedorahosted.Eekboard.Server", + "g-name", "org.fedorahosted.Eekboard", "g-connection", connection, "g-interface-name", "org.fedorahosted.Eekboard.Context", "g-object-path", object_path, @@ -563,7 +563,7 @@ eekboard_context_hide_keyboard (EekboardContext *context, } /** - * eekboard_context_press_key: + * eekboard_context_press_keycode: * @context: an #EekboardContext * @keycode: keycode number * @cancellable: a #GCancellable @@ -571,9 +571,9 @@ eekboard_context_hide_keyboard (EekboardContext *context, * Tell eekboard-server that a key identified by @keycode is pressed. */ void -eekboard_context_press_key (EekboardContext *context, - guint keycode, - GCancellable *cancellable) +eekboard_context_press_keycode (EekboardContext *context, + guint keycode, + GCancellable *cancellable) { EekboardContextPrivate *priv; @@ -584,7 +584,7 @@ eekboard_context_press_key (EekboardContext *context, return; g_dbus_proxy_call (G_DBUS_PROXY(context), - "PressKey", + "PressKeycode", g_variant_new ("(u)", keycode), G_DBUS_CALL_FLAGS_NONE, -1, @@ -594,15 +594,15 @@ eekboard_context_press_key (EekboardContext *context, } /** - * eekboard_context_release_key: - * @context: an #EekboardContext + * eekboard_context_release_keycode: + * @Context: an #EekboardContext * @keycode: keycode number * @cancellable: a #GCancellable * * Tell eekboard-server that a key identified by @keycode is released. */ void -eekboard_context_release_key (EekboardContext *context, +eekboard_context_release_keycode (EekboardContext *context, guint keycode, GCancellable *cancellable) { @@ -615,7 +615,7 @@ eekboard_context_release_key (EekboardContext *context, return; g_dbus_proxy_call (G_DBUS_PROXY(context), - "ReleaseKey", + "ReleaseKeycode", g_variant_new ("(u)", keycode), G_DBUS_CALL_FLAGS_NONE, -1, @@ -625,20 +625,20 @@ eekboard_context_release_key (EekboardContext *context, } /** - * eekboard_context_is_keyboard_visible: + * eekboard_context_is_visible: * @context: an #EekboardContext * * Check if keyboard is visible. */ gboolean -eekboard_context_is_keyboard_visible (EekboardContext *context) +eekboard_context_is_visible (EekboardContext *context) { EekboardContextPrivate *priv; g_assert (EEKBOARD_IS_CONTEXT(context)); priv = EEKBOARD_CONTEXT_GET_PRIVATE (context); - return priv->enabled && priv->keyboard_visible; + return priv->enabled && priv->visible; } /** diff --git a/eekboard/eekboard-context.h b/eekboard/eekboard-context.h index 934718a9..42788608 100644 --- a/eekboard/eekboard-context.h +++ b/eekboard/eekboard-context.h @@ -15,9 +15,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -#if !defined(__EEKBOARD_H_INSIDE__) && !defined(EEKBOARD_COMPILATION) -#error "Only can be included directly." +#if !defined(__EEKBOARD_CLIENT_H_INSIDE__) && !defined(EEKBOARD_COMPILATION) +#error "Only can be included directly." #endif #ifndef EEKBOARD_CONTEXT_H @@ -100,12 +99,12 @@ void eekboard_context_set_group (EekboardContext *context, GCancellable *cancellable); gint eekboard_context_get_group (EekboardContext *context, GCancellable *cancellable); -void eekboard_context_press_key (EekboardContext *context, - guint keycode, - GCancellable *cancellable); -void eekboard_context_release_key (EekboardContext *context, +void eekboard_context_press_keycode (EekboardContext *context, guint keycode, GCancellable *cancellable); +void eekboard_context_release_keycode (EekboardContext *context, + guint keycode, + GCancellable *cancellable); gboolean eekboard_context_is_keyboard_visible (EekboardContext *context); void eekboard_context_set_enabled (EekboardContext *context, diff --git a/eekboard/eekboard-eekboard.h b/eekboard/eekboard-eekboard.h deleted file mode 100644 index c0e06270..00000000 --- a/eekboard/eekboard-eekboard.h +++ /dev/null @@ -1,81 +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 . - */ - -#if !defined(__EEKBOARD_H_INSIDE__) && !defined(EEKBOARD_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef EEKBOARD_EEKBOARD_H -#define EEKBOARD_EEKBOARD_H 1 - -#include -#include "eekboard/eekboard-context.h" - -G_BEGIN_DECLS - -#define EEKBOARD_TYPE_EEKBOARD (eekboard_eekboard_get_type()) -#define EEKBOARD_EEKBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_EEKBOARD, EekboardEekboard)) -#define EEKBOARD_EEKBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_EEKBOARD, EekboardEekboardClass)) -#define EEKBOARD_IS_EEKBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_EEKBOARD)) -#define EEKBOARD_IS_EEKBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_EEKBOARD)) -#define EEKBOARD_EEKBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_EEKBOARD, EekboardEekboardClass)) - -typedef struct _EekboardEekboard EekboardEekboard; -typedef struct _EekboardEekboardClass EekboardEekboardClass; -typedef struct _EekboardEekboardPrivate EekboardEekboardPrivate; - -struct _EekboardEekboard { - /*< private >*/ - GDBusProxy parent; - - EekboardEekboardPrivate *priv; -}; - -struct _EekboardEekboardClass { - /*< private >*/ - GDBusProxyClass parent_class; - - /* signals */ - void (* destroyed) (EekboardEekboard *self); - - /*< private >*/ - /* padding */ - gpointer pdummy[23]; -}; - -GType eekboard_eekboard_get_type (void) G_GNUC_CONST; - -EekboardEekboard *eekboard_eekboard_new (GDBusConnection *connection, - GCancellable *cancellable); -EekboardContext *eekboard_eekboard_create_context - (EekboardEekboard *eekboard, - const gchar *client_name, - GCancellable *cancellable); -void eekboard_eekboard_push_context - (EekboardEekboard *eekboard, - EekboardContext *context, - GCancellable *cancellable); -void eekboard_eekboard_pop_context (EekboardEekboard *eekboard, - GCancellable *cancellable); -void eekboard_eekboard_destroy_context - (EekboardEekboard *eekboard, - EekboardContext *context, - GCancellable *cancellable); - -G_END_DECLS -#endif /* EEKBOARD_EEKBOARD_H */ diff --git a/src/server-server.c b/eekboard/eekboard-service.c similarity index 50% rename from src/server-server.c rename to eekboard/eekboard-service.c index 279ec2a6..d891d093 100644 --- a/src/server-server.c +++ b/eekboard/eekboard-service.c @@ -19,10 +19,7 @@ #include "config.h" #endif /* HAVE_CONFIG_H */ -#include "server-server.h" -#include "server-context.h" - -#define I_(string) g_intern_static_string (string) +#include "eekboard/eekboard-service.h" enum { PROP_0, @@ -38,9 +35,24 @@ enum { static guint signals[LAST_SIGNAL] = { 0, }; +#define EEKBOARD_SERVICE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_SERVICE, EekboardServicePrivate)) + +struct _EekboardServicePrivate { + GDBusConnection *connection; + GDBusNodeInfo *introspection_data; + guint registration_id; + char *object_path; + + GHashTable *context_hash; + GSList *context_stack; +}; + +G_DEFINE_TYPE (EekboardService, eekboard_service, G_TYPE_OBJECT); + static const gchar introspection_xml[] = "" - " " + " " " " " " " " @@ -57,25 +69,6 @@ static const gchar introspection_xml[] = " " ""; -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, @@ -93,25 +86,26 @@ static const GDBusInterfaceVTable interface_vtable = }; static void -server_server_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +eekboard_service_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - ServerServer *server = SERVER_SERVER(object); + EekboardService *service = EEKBOARD_SERVICE(object); + EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service); 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)); + if (priv->object_path) + g_free (priv->object_path); + priv->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); + if (priv->connection) + g_object_unref (priv->connection); + priv->connection = g_object_ref (connection); break; default: g_object_set_property (object, @@ -122,79 +116,110 @@ server_server_set_property (GObject *object, } static void -server_server_dispose (GObject *object) +eekboard_service_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - ServerServer *server = SERVER_SERVER(object); + EekboardService *service = EEKBOARD_SERVICE(object); + EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service); + + switch (prop_id) { + case PROP_OBJECT_PATH: + g_value_set_string (value, priv->object_path); + break; + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); + break; + default: + g_object_set_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +eekboard_service_dispose (GObject *object) +{ + EekboardService *service = EEKBOARD_SERVICE(object); + EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service); GSList *head; - if (server->context_hash) { - g_hash_table_destroy (server->context_hash); - server->context_hash = NULL; + if (priv->context_hash) { + g_hash_table_destroy (priv->context_hash); + priv->context_hash = NULL; } - for (head = server->context_stack; head; head = server->context_stack) { + for (head = priv->context_stack; head; head = priv->context_stack) { g_object_unref (head->data); - server->context_stack = g_slist_next (head); + priv->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; + if (priv->connection) { + if (priv->registration_id > 0) { + g_dbus_connection_unregister_object (priv->connection, + priv->registration_id); + priv->registration_id = 0; } - g_object_unref (server->connection); - server->connection = NULL; + g_object_unref (priv->connection); + priv->connection = NULL; } - if (server->introspection_data) { - g_dbus_node_info_unref (server->introspection_data); - server->introspection_data = NULL; + if (priv->introspection_data) { + g_dbus_node_info_unref (priv->introspection_data); + priv->introspection_data = NULL; } - G_OBJECT_CLASS (server_server_parent_class)->dispose (object); + G_OBJECT_CLASS (eekboard_service_parent_class)->dispose (object); } static void -server_server_finalize (GObject *object) +eekboard_service_finalize (GObject *object) { - ServerServer *server = SERVER_SERVER(object); + EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(object); - g_free (server->object_path); + g_free (priv->object_path); - G_OBJECT_CLASS (server_server_parent_class)->dispose (object); + G_OBJECT_CLASS (eekboard_service_parent_class)->finalize (object); } static void -server_server_constructed (GObject *object) +eekboard_service_constructed (GObject *object) { - ServerServer *server = SERVER_SERVER (object); - if (server->connection && server->object_path) { + EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(object); + if (priv->connection && priv->object_path) { GError *error = NULL; - server->registration_id = g_dbus_connection_register_object - (server->connection, - server->object_path, - server->introspection_data->interfaces[0], + priv->registration_id = g_dbus_connection_register_object + (priv->connection, + priv->object_path, + priv->introspection_data->interfaces[0], &interface_vtable, - server, + object, NULL, &error); } } static void -server_server_class_init (ServerServerClass *klass) +eekboard_service_class_init (EekboardServiceClass *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; - gobject_class->finalize = server_server_finalize; + g_type_class_add_private (gobject_class, + sizeof (EekboardServicePrivate)); + + klass->create_context = NULL; + + gobject_class->constructed = eekboard_service_constructed; + gobject_class->set_property = eekboard_service_set_property; + gobject_class->get_property = eekboard_service_get_property; + gobject_class->dispose = eekboard_service_dispose; + gobject_class->finalize = eekboard_service_finalize; signals[DESTROYED] = g_signal_new (I_("destroyed"), @@ -211,7 +236,7 @@ server_server_class_init (ServerServerClass *klass) "Object-path", "Object-path", NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_OBJECT_PATH, pspec); @@ -220,23 +245,26 @@ server_server_class_init (ServerServerClass *klass) "Connection", "Connection", G_TYPE_DBUS_CONNECTION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CONNECTION, pspec); } static void -server_server_init (ServerServer *server) +eekboard_service_init (EekboardService *service) { + EekboardServicePrivate *priv; GError *error; - error = NULL; - server->introspection_data = - g_dbus_node_info_new_for_xml (introspection_xml, &error); - g_assert (server->introspection_data != NULL); + priv = service->priv = EEKBOARD_SERVICE_GET_PRIVATE(service); - server->context_hash = + error = NULL; + priv->introspection_data = + g_dbus_node_info_new_for_xml (introspection_xml, &error); + g_assert (priv->introspection_data != NULL); + + priv->context_hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, @@ -244,47 +272,47 @@ server_server_init (ServerServer *server) } static void -remove_context_from_stack (ServerServer *server, ServerContext *context) +remove_context_from_stack (EekboardService *service, + EekboardContextService *context) { + EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service); GSList *head; - head = g_slist_find (server->context_stack, context); + head = g_slist_find (priv->context_stack, context); if (head) { - server->context_stack = g_slist_remove_link (server->context_stack, - head); + priv->context_stack = g_slist_remove_link (priv->context_stack, head); g_object_unref (head->data); g_slist_free1 (head); } - if (server->context_stack) - server_context_set_enabled (server->context_stack->data, TRUE); + if (priv->context_stack) + eekboard_context_service_enable (priv->context_stack->data); } static void -server_name_vanished_callback (GDBusConnection *connection, - const gchar *name, - gpointer user_data) +service_name_vanished_callback (GDBusConnection *connection, + const gchar *name, + gpointer user_data) { - ServerServer *server = user_data; + EekboardService *service = user_data; + EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service); GSList *head; GHashTableIter iter; gpointer k, v; - g_hash_table_iter_init (&iter, server->context_hash); + g_hash_table_iter_init (&iter, priv->context_hash); while (g_hash_table_iter_next (&iter, &k, &v)) { - const gchar *client_connection = - server_context_get_client_connection (v); - if (g_strcmp0 (client_connection, name) == 0) + const gchar *owner = g_object_get_data (G_OBJECT(v), "owner"); + if (g_strcmp0 (owner, name) == 0) g_hash_table_iter_remove (&iter); } - for (head = server->context_stack; head; ) { - const gchar *client_connection = - server_context_get_client_connection (head->data); + for (head = priv->context_stack; head; ) { + const gchar *owner = g_object_get_data (G_OBJECT(head->data), "owner"); GSList *next = g_slist_next (head); - if (g_strcmp0 (client_connection, name) == 0) { - server->context_stack = g_slist_remove_link (server->context_stack, - head); + if (g_strcmp0 (owner, name) == 0) { + priv->context_stack = + g_slist_remove_link (priv->context_stack, head); g_object_unref (head->data); g_slist_free1 (head); } @@ -292,8 +320,8 @@ server_name_vanished_callback (GDBusConnection *connection, head = next; } - if (server->context_stack) - server_context_set_enabled (server->context_stack->data, TRUE); + if (priv->context_stack) + eekboard_context_service_enable (priv->context_stack->data); } static void @@ -306,30 +334,32 @@ handle_method_call (GDBusConnection *connection, GDBusMethodInvocation *invocation, gpointer user_data) { - ServerServer *server = user_data; + EekboardService *service = user_data; + EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service); + EekboardServiceClass *klass = EEKBOARD_SERVICE_GET_CLASS(service); if (g_strcmp0 (method_name, "CreateContext") == 0) { const gchar *client_name; gchar *object_path; static gint context_id = 0; - ServerContext *context; + EekboardContextService *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); - server_context_set_client_connection (context, sender); - server_context_set_client_name (context, client_name); - g_hash_table_insert (server->context_hash, + object_path = g_strdup_printf (EEKBOARD_CONTEXT_SERVICE_PATH, context_id++); + g_assert (klass->create_context); + context = klass->create_context (service, client_name, object_path); + g_object_set_data (G_OBJECT(context), "owner", g_strdup (sender)); + g_hash_table_insert (priv->context_hash, object_path, context); /* the vanished callback is called when clients are disconnected */ - g_bus_watch_name_on_connection (server->connection, + g_bus_watch_name_on_connection (priv->connection, sender, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, - server_name_vanished_callback, - server, + service_name_vanished_callback, + service, NULL); g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", @@ -339,10 +369,10 @@ handle_method_call (GDBusConnection *connection, if (g_strcmp0 (method_name, "PushContext") == 0) { const gchar *object_path; - ServerContext *context; + EekboardContextService *context; g_variant_get (parameters, "(&s)", &object_path); - context = g_hash_table_lookup (server->context_hash, object_path); + context = g_hash_table_lookup (priv->context_hash, object_path); if (!context) { g_dbus_method_invocation_return_error (invocation, G_IO_ERROR, @@ -350,37 +380,39 @@ handle_method_call (GDBusConnection *connection, "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); + if (priv->context_stack) + eekboard_context_service_disable (priv->context_stack->data); + priv->context_stack = g_slist_prepend (priv->context_stack, + g_object_ref (context)); + eekboard_context_service_enable (context); 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; + if (priv->context_stack) { + EekboardContextService *context = priv->context_stack->data; + gchar *object_path; + const gchar *owner; - if (g_strcmp0 (server_context_get_client_connection (context), - sender) != 0) { + g_object_get (G_OBJECT(context), "object-path", &object_path, NULL); + owner = g_object_get_data (G_OBJECT(context), "owner"); + if (g_strcmp0 (owner, sender) != 0) { g_dbus_method_invocation_return_error (invocation, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED, - "the current context not owned by %s", - sender); + "context at %s not owned by %s", + object_path, sender); return; } + g_free (object_path); - 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); + eekboard_context_service_disable (context); + priv->context_stack = g_slist_next (priv->context_stack); + if (priv->context_stack) + eekboard_context_service_enable (priv->context_stack->data); } g_dbus_method_invocation_return_value (invocation, NULL); @@ -388,11 +420,12 @@ handle_method_call (GDBusConnection *connection, } if (g_strcmp0 (method_name, "DestroyContext") == 0) { + EekboardContextService *context; const gchar *object_path; - ServerContext *context; + const gchar *owner; g_variant_get (parameters, "(&s)", &object_path); - context = g_hash_table_lookup (server->context_hash, object_path); + context = g_hash_table_lookup (priv->context_hash, object_path); if (!context) { g_dbus_method_invocation_return_error (invocation, G_IO_ERROR, @@ -400,14 +433,26 @@ handle_method_call (GDBusConnection *connection, "context not found"); return; } - remove_context_from_stack (server, context); - g_hash_table_remove (server->context_hash, object_path); + + owner = g_object_get_data (G_OBJECT(context), "owner"); + if (g_strcmp0 (owner, sender) != 0) { + g_dbus_method_invocation_return_error + (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED, + "the context at %s not owned by %s", + object_path, sender); + return; + } + + remove_context_from_stack (service, context); + g_hash_table_remove (priv->context_hash, object_path); g_dbus_method_invocation_return_value (invocation, NULL); return; } if (g_strcmp0 (method_name, "Destroy") == 0) { - g_signal_emit_by_name (server, "destroyed", NULL); + g_signal_emit_by_name (service, "destroyed", NULL); g_dbus_method_invocation_return_value (invocation, NULL); return; } @@ -415,11 +460,11 @@ handle_method_call (GDBusConnection *connection, g_return_if_reached (); } -ServerServer * -server_server_new (const gchar *object_path, - GDBusConnection *connection) +EekboardService * +eekboard_service_new (const gchar *object_path, + GDBusConnection *connection) { - return g_object_new (SERVER_TYPE_SERVER, + return g_object_new (EEKBOARD_TYPE_SERVICE, "object-path", object_path, "connection", connection, NULL); diff --git a/eekboard/eekboard-service.h b/eekboard/eekboard-service.h new file mode 100644 index 00000000..1e185067 --- /dev/null +++ b/eekboard/eekboard-service.h @@ -0,0 +1,66 @@ +/* + * 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_SERVICE_H +#define EEKBOARD_SERVICE_H 1 + +#define __EEKBOARD_SERVICE_H_INSIDE__ 1 + +#include "eekboard/eekboard-context-service.h" + +G_BEGIN_DECLS + +#define EEKBOARD_SERVICE_PATH "/org/fedorahosted/Eekboard" +#define EEKBOARD_SERVICE_INTERFACE "org.fedorahosted.Eekboard" + +#define EEKBOARD_TYPE_SERVICE (eekboard_service_get_type()) +#define EEKBOARD_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_SERVICE, EekboardService)) +#define EEKBOARD_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_SERVICE, EekboardServiceClass)) +#define EEKBOARD_IS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_SERVICE)) +#define EEKBOARD_IS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_SERVICE)) +#define EEKBOARD_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_SERVICE, EekboardServiceClass)) + +typedef struct _EekboardService EekboardService; +typedef struct _EekboardServiceClass EekboardServiceClass; +typedef struct _EekboardServicePrivate EekboardServicePrivate; + +struct _EekboardService { + GObject parent; + + EekboardServicePrivate *priv; +}; + +struct _EekboardServiceClass { + /*< private >*/ + GObjectClass parent_class; + + /*< public >*/ + EekboardContextService *(*create_context) (EekboardService *self, + const gchar *client_name, + const gchar *object_path); + + /*< private >*/ + /* padding */ + gpointer pdummy[24]; +}; + +GType eekboard_service_get_type (void) G_GNUC_CONST; +EekboardService * eekboard_service_new (const gchar *object_path, + GDBusConnection *connection); + +G_END_DECLS +#endif /* EEKBOARD_SERVICE_H */ diff --git a/src/xklutil.c b/eekboard/eekboard-xklutil.c similarity index 99% rename from src/xklutil.c rename to eekboard/eekboard-xklutil.c index 86a52915..ca7cfe89 100644 --- a/src/xklutil.c +++ b/eekboard/eekboard-xklutil.c @@ -18,7 +18,7 @@ * 02110-1301 USA */ #include -#include "xklutil.h" +#include "eekboard/eekboard-xklutil.h" XklConfigRec * eekboard_xkl_config_rec_from_string (const gchar *layouts) diff --git a/src/xklutil.h b/eekboard/eekboard-xklutil.h similarity index 100% rename from src/xklutil.h rename to eekboard/eekboard-xklutil.h diff --git a/eekboard/eekboard.h b/eekboard/eekboard.h deleted file mode 100644 index cb6a8498..00000000 --- a/eekboard/eekboard.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 . - */ -#ifndef EEKBOARD_H -#define EEKBOARD_H 1 - -#define __EEKBOARD_H_INSIDE__ 1 - -#include "eekboard/eekboard-eekboard.h" -#include "eekboard/eekboard-context.h" - -#endif /* EEKBOARD_H */ diff --git a/examples/simple-client/main.c b/examples/simple-client/main.c index c8263d9e..d73539bb 100644 --- a/examples/simple-client/main.c +++ b/examples/simple-client/main.c @@ -22,7 +22,7 @@ #include #include -#include "eekboard/eekboard.h" +#include "eekboard/eekboard-client.h" static gboolean opt_system = FALSE; static gboolean opt_session = FALSE; @@ -61,21 +61,19 @@ static const GOptionEntry options[] = { }; static void -on_key_pressed (guint keycode, gpointer user_data) +on_key_pressed (EekboardContext *context, + const gchar *keyname, + EekSymbol *symbol, + guint modifiers, + gpointer user_data) { - g_print ("KeyPressed %u\n", keycode); -} - -static void -on_key_released (guint keycode, gpointer user_data) -{ - g_print ("KeyReleased %u\n", keycode); + g_print ("KeyPressed %s %s\n", keyname, eek_symbol_get_name (symbol)); } int main (int argc, char **argv) { - EekboardEekboard *eekboard = NULL; + EekboardClient *eekboard = NULL; EekboardContext *context = NULL; GBusType bus_type; GDBusConnection *connection = NULL; @@ -84,7 +82,7 @@ main (int argc, char **argv) GMainLoop *loop = NULL; gint retval = 0; - g_type_init (); + eek_init (); g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL); option_context = g_option_context_new ("eekboard-client"); @@ -128,14 +126,14 @@ main (int argc, char **argv) break; } - eekboard = eekboard_eekboard_new (connection, NULL); + eekboard = eekboard_client_new (connection, NULL); if (eekboard == NULL) { g_printerr ("Can't create eekboard proxy\n"); retval = 1; goto out; } - context = eekboard_eekboard_create_context (eekboard, + context = eekboard_client_create_context (eekboard, "eekboard-client", NULL); if (context == NULL) { @@ -144,7 +142,7 @@ main (int argc, char **argv) goto out; } - eekboard_eekboard_push_context (eekboard, context, NULL); + eekboard_client_push_context (eekboard, context, NULL); if (opt_set_keyboard) { guint keyboard_id; @@ -173,18 +171,16 @@ main (int argc, char **argv) } if (opt_press_key >= 0) { - eekboard_context_press_key (context, opt_press_key, NULL); + eekboard_context_press_keycode (context, opt_press_key, NULL); } if (opt_release_key >= 0) { - eekboard_context_release_key (context, opt_release_key, NULL); + eekboard_context_release_keycode (context, opt_release_key, NULL); } if (opt_listen) { g_signal_connect (context, "key-pressed", G_CALLBACK(on_key_pressed), NULL); - g_signal_connect (context, "key-released", - G_CALLBACK(on_key_released), NULL); loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); } diff --git a/src/Makefile.am b/src/Makefile.am index 70baa637..52fd4065 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,8 +21,6 @@ bin_PROGRAMS = \ eekboard-server \ eekboard-xml -noinst_LTLIBRARIES = libxklutil.la - eekboard_CFLAGS = \ -I$(top_srcdir) \ $(GIO2_CFLAGS) \ @@ -32,7 +30,6 @@ eekboard_CFLAGS = \ -DKEYBOARDDIR=\"$(pkgdatadir)/keyboards\" eekboard_LDADD = \ - $(builddir)/libxklutil.la \ $(top_builddir)/eekboard/libeekboard.la \ $(top_builddir)/eek/libeek.la \ $(top_builddir)/eek/libeek-xkl.la \ @@ -74,7 +71,6 @@ eekboard_server_CFLAGS = \ -DKEYBOARDDIR=\"$(pkgdatadir)/keyboards\" eekboard_server_LDADD = \ - $(builddir)/libxklutil.la \ $(top_builddir)/eekboard/libeekboard.la \ $(top_builddir)/eek/libeek.la \ $(top_builddir)/eek/libeek-gtk.la \ @@ -93,8 +89,8 @@ eekboard_server_CFLAGS += $(XDOCK_CFLAGS) eekboard_server_LDADD += $(XDOCK_LIBS) endif -eekboard_server_headers = server-server.h server-context.h -eekboard_server_SOURCES = server-server.c server-context.c server-main.c +eekboard_server_headers = server-service.h server-context-service.h +eekboard_server_SOURCES = server-service.c server-context-service.c server-main.c eekboard_xml_CFLAGS = \ -I$(top_srcdir) \ @@ -103,7 +99,7 @@ eekboard_xml_CFLAGS = \ $(LIBXKLAVIER_CFLAGS) eekboard_xml_LDADD = \ - $(builddir)/libxklutil.la \ + $(top_builddir)/eekboard/libeekboard.la \ $(top_builddir)/eek/libeek.la \ $(top_builddir)/eek/libeek-xkl.la \ $(top_builddir)/eek/libeek-gtk.la \ @@ -118,11 +114,6 @@ endif eekboard_xml_SOURCES = xml-main.c -libxklutil_la_headers = xklutil.h -libxklutil_la_SOURCES = xklutil.c -libxklutil_la_CFLAGS = $(LIBXKLAVIER_CFLAGS) -libxklutil_la_LIBADD = $(LIBXKLAVIER_LIBS) - eekboarddir = $(includedir)/eekboard-$(EEK_API_VERSION)/eekboard eekboard_HEADERS = \ $(libeekboard_headers) @@ -130,5 +121,4 @@ eekboard_HEADERS = \ noinst_HEADERS = \ $(eekboard_headers) \ $(eekboard_server_headers) \ - $(eekboard_xml_headers) \ - $(libxklutil_la_headers) + $(eekboard_xml_headers) diff --git a/src/client-main.c b/src/client-main.c index 4398ff35..20dc42ff 100644 --- a/src/client-main.c +++ b/src/client-main.c @@ -29,7 +29,7 @@ #endif /* HAVE_IBUS */ #include #include -#include "eekboard/eekboard.h" +#include "eekboard/eekboard-client.h" #include "client.h" #define DEFAULT_KEYBOARD "us" @@ -64,14 +64,14 @@ static const GOptionEntry options[] = { }; static void -on_notify_keyboard_visible (GObject *object, - GParamSpec *spec, - gpointer user_data) +on_notify_visible (GObject *object, + GParamSpec *spec, + gpointer user_data) { GMainLoop *loop = user_data; gboolean visible; - g_object_get (object, "keyboard-visible", &visible, NULL); + g_object_get (object, "visible", &visible, NULL); /* user explicitly closed the window */ if (!visible && eekboard_context_is_enabled (EEKBOARD_CONTEXT(object))) @@ -88,7 +88,7 @@ on_context_destroyed (EekboardContext *context, } static void -on_destroyed (EekboardEekboard *eekboard, +on_destroyed (EekboardClient *eekboard, gpointer user_data) { GMainLoop *loop = user_data; @@ -96,23 +96,23 @@ on_destroyed (EekboardEekboard *eekboard, g_main_loop_quit (loop); } -enum { +enum FocusListenerType { FOCUS_NONE, FOCUS_ATSPI, FOCUS_IBUS }; static gboolean -set_keyboard (EekboardClient *client, +set_keyboard (Client *client, const gchar *keyboard) { if (g_strcmp0 (keyboard, "system") == 0) { - if (!eekboard_client_enable_xkl (client)) { + if (!client_enable_xkl (client)) { g_printerr ("Can't register xklavier event listeners\n"); return FALSE; } } else { - if (!eekboard_client_set_keyboard (client, keyboard)) { + if (!client_set_keyboard (client, keyboard)) { g_printerr ("Can't set keyboard \"%s\"\n", keyboard); return FALSE; } @@ -123,8 +123,8 @@ set_keyboard (EekboardClient *client, int main (int argc, char **argv) { - EekboardClient *client = NULL; - EekboardEekboard *eekboard; + Client *client = NULL; + EekboardClient *eekboard; EekboardContext *context; GBusType bus_type; GDBusConnection *connection; @@ -184,7 +184,7 @@ main (int argc, char **argv) break; } - client = eekboard_client_new (connection); + client = client_new (connection); g_object_unref (connection); if (client == NULL) { @@ -197,12 +197,26 @@ main (int argc, char **argv) if (opt_focus) { gchar *focus_listener = g_settings_get_string (settings, "focus-listener"); + const struct { + const gchar *name; + enum FocusListenerType type; + } focus_listeners[] = { +#ifdef HAVE_ATSPI + { "atspi", FOCUS_ATSPI }, +#endif +#ifdef HAVE_IBUS + { "ibus", FOCUS_IBUS }, +#endif + { NULL } + }; + gint i; - if (g_strcmp0 (focus_listener, "atspi") == 0) - focus = FOCUS_ATSPI; - else if (g_strcmp0 (focus_listener, "ibus") == 0) - focus = FOCUS_IBUS; - else { + focus = FOCUS_NONE; + for (i = 0; focus_listeners[i].name; i++) { + if (g_strcmp0 (focus_listener, focus_listeners[i].name) == 0) + focus = focus_listeners[i].type; + } + if (focus == FOCUS_NONE) { g_printerr ("Unknown focus listener \"%s\". " "Try \"atspi\" or \"ibus\"\n", focus_listener); retval = 1; @@ -215,7 +229,7 @@ main (int argc, char **argv) GSettings *desktop_settings = g_settings_new ("org.gnome.desktop.interface"); gboolean accessibility_enabled = - g_settings_get_boolean (settings, "toolkit-accessibility"); + g_settings_get_boolean (desktop_settings, "toolkit-accessibility"); g_object_unref (desktop_settings); if (accessibility_enabled) { @@ -226,14 +240,14 @@ main (int argc, char **argv) } if (focus == FOCUS_ATSPI && - !eekboard_client_enable_atspi_focus (client)) { + !client_enable_atspi_focus (client)) { g_printerr ("Can't register AT-SPI focus change event listeners\n"); retval = 1; goto out; } if (opt_keystroke && - !eekboard_client_enable_atspi_keystroke (client)) { + !client_enable_atspi_keystroke (client)) { g_printerr ("Can't register AT-SPI keystroke event listeners\n"); retval = 1; goto out; @@ -250,7 +264,7 @@ main (int argc, char **argv) if (focus == FOCUS_IBUS) { ibus_init (); - if (!eekboard_client_enable_ibus_focus (client)) { + if (!client_enable_ibus_focus (client)) { g_printerr ("Can't register IBus focus change event listeners\n"); retval = 1; goto out; @@ -259,7 +273,7 @@ main (int argc, char **argv) #endif /* HAVE_IBUS */ #ifdef HAVE_XTEST - if (!eekboard_client_enable_xtest (client)) { + if (!client_enable_xtest (client)) { g_printerr ("Can't init xtest\n"); g_object_unref (client); exit (1); @@ -270,8 +284,8 @@ main (int argc, char **argv) if (!opt_focus) { g_object_get (client, "context", &context, NULL); - g_signal_connect (context, "notify::keyboard-visible", - G_CALLBACK(on_notify_keyboard_visible), loop); + g_signal_connect (context, "notify::visible", + G_CALLBACK(on_notify_visible), loop); g_signal_connect (context, "destroyed", G_CALLBACK(on_context_destroyed), loop); g_object_unref (context); diff --git a/src/client.c b/src/client.c index 2869aa7d..2f9264db 100644 --- a/src/client.c +++ b/src/client.c @@ -39,9 +39,9 @@ #include "eek/eek.h" #include "eek/eek-xkl.h" -#include "eekboard/eekboard.h" +#include "eekboard/eekboard-client.h" +#include "eekboard/eekboard-xklutil.h" #include "client.h" -#include "xklutil.h" #include @@ -56,12 +56,12 @@ enum { PROP_LAST }; -typedef struct _EekboardClientClass EekboardClientClass; +typedef struct _ClientClass ClientClass; -struct _EekboardClient { +struct _Client { GObject parent; - EekboardEekboard *eekboard; + EekboardClient *eekboard; EekboardContext *context; GSList *keyboards; @@ -95,11 +95,11 @@ struct _EekboardClient { GSettings *settings; }; -struct _EekboardClientClass { +struct _ClientClass { GObjectClass parent_class; }; -G_DEFINE_TYPE (EekboardClient, eekboard_client, G_TYPE_OBJECT); +G_DEFINE_TYPE (Client, client, G_TYPE_OBJECT); #if ENABLE_FOCUS_LISTENER #define IS_KEYBOARD_VISIBLE(client) (!client->follows_focus) @@ -126,40 +126,40 @@ static void focus_listener_cb (const AtspiEvent *event, static gboolean keystroke_listener_cb (const AtspiDeviceEvent *stroke, void *user_data); #endif /* HAVE_ATSPI */ -static gboolean set_keyboard (EekboardClient *client, +static gboolean set_keyboard (Client *client, const gchar *keyboard); -static gboolean set_keyboard_from_xkl (EekboardClient *client); +static gboolean set_keyboard_from_xkl (Client *client); #ifdef HAVE_XTEST static void update_modifier_keycodes - (EekboardClient *client); +(Client *client); #endif /* HAVE_XTEST */ static void -eekboard_client_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +client_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - EekboardClient *client = EEKBOARD_CLIENT(object); + Client *client = CLIENT(object); GDBusConnection *connection; switch (prop_id) { case PROP_CONNECTION: connection = g_value_get_object (value); - client->eekboard = eekboard_eekboard_new (connection, NULL); + client->eekboard = eekboard_client_new (connection, NULL); if (client->eekboard != NULL) { client->context = - eekboard_eekboard_create_context (client->eekboard, - "eekboard", - NULL); + eekboard_client_create_context (client->eekboard, + "eekboard", + NULL); if (client->context == NULL) { g_object_unref (client->eekboard); client->eekboard = NULL; } else - eekboard_eekboard_push_context (client->eekboard, - client->context, - NULL); + eekboard_client_push_context (client->eekboard, + client->context, + NULL); } break; default: @@ -171,12 +171,12 @@ eekboard_client_set_property (GObject *object, } static void -eekboard_client_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +client_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - EekboardClient *client = EEKBOARD_CLIENT(object); + Client *client = CLIENT(object); switch (prop_id) { case PROP_EEKBOARD: @@ -194,19 +194,19 @@ eekboard_client_get_property (GObject *object, } static void -eekboard_client_dispose (GObject *object) +client_dispose (GObject *object) { - EekboardClient *client = EEKBOARD_CLIENT(object); + Client *client = CLIENT(object); - eekboard_client_disable_xkl (client); + client_disable_xkl (client); #ifdef HAVE_ATSPI - eekboard_client_disable_atspi_focus (client); - eekboard_client_disable_atspi_keystroke (client); + client_disable_atspi_focus (client); + client_disable_atspi_keystroke (client); #endif /* HAVE_ATSPI */ #ifdef HAVE_IBUS - eekboard_client_disable_ibus_focus (client); + client_disable_ibus_focus (client); if (client->ibus_bus) { g_object_unref (client->ibus_bus); client->ibus_bus = NULL; @@ -214,12 +214,12 @@ eekboard_client_dispose (GObject *object) #endif /* HAVE_IBUS */ #ifdef HAVE_XTEST - eekboard_client_disable_xtest (client); + client_disable_xtest (client); #endif /* HAVE_XTEST */ if (client->context) { if (client->eekboard) { - eekboard_eekboard_pop_context (client->eekboard, NULL); + eekboard_client_pop_context (client->eekboard, NULL); } g_object_unref (client->context); @@ -236,18 +236,18 @@ eekboard_client_dispose (GObject *object) client->settings = NULL; } - G_OBJECT_CLASS (eekboard_client_parent_class)->dispose (object); + G_OBJECT_CLASS (client_parent_class)->dispose (object); } static void -eekboard_client_class_init (EekboardClientClass *klass) +client_class_init (ClientClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; - gobject_class->set_property = eekboard_client_set_property; - gobject_class->get_property = eekboard_client_get_property; - gobject_class->dispose = eekboard_client_dispose; + gobject_class->set_property = client_set_property; + gobject_class->get_property = client_get_property; + gobject_class->dispose = client_dispose; pspec = g_param_spec_object ("connection", "Connection", @@ -261,7 +261,7 @@ eekboard_client_class_init (EekboardClientClass *klass) pspec = g_param_spec_object ("eekboard", "Eekboard", "Eekboard", - EEKBOARD_TYPE_EEKBOARD, + EEKBOARD_TYPE_CLIENT, G_PARAM_READABLE); g_object_class_install_property (gobject_class, PROP_EEKBOARD, @@ -278,14 +278,14 @@ eekboard_client_class_init (EekboardClientClass *klass) } static void -eekboard_client_init (EekboardClient *client) +client_init (Client *client) { client->settings = g_settings_new ("org.fedorahosted.eekboard"); } gboolean -eekboard_client_set_keyboard (EekboardClient *client, - const gchar *keyboard) +client_set_keyboard (Client *client, + const gchar *keyboard) { gboolean retval; retval = set_keyboard (client, keyboard); @@ -295,7 +295,7 @@ eekboard_client_set_keyboard (EekboardClient *client, } gboolean -eekboard_client_enable_xkl (EekboardClient *client) +client_enable_xkl (Client *client) { GdkDisplay *display = gdk_display_get_default (); gboolean retval; @@ -338,7 +338,7 @@ eekboard_client_enable_xkl (EekboardClient *client) } void -eekboard_client_disable_xkl (EekboardClient *client) +client_disable_xkl (Client *client) { if (client->xkl_engine) { xkl_engine_stop_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE); @@ -357,7 +357,7 @@ eekboard_client_disable_xkl (EekboardClient *client) #ifdef HAVE_ATSPI gboolean -eekboard_client_enable_atspi_focus (EekboardClient *client) +client_enable_atspi_focus (Client *client) { GError *error; @@ -384,7 +384,7 @@ eekboard_client_enable_atspi_focus (EekboardClient *client) } void -eekboard_client_disable_atspi_focus (EekboardClient *client) +client_disable_atspi_focus (Client *client) { GError *error; @@ -406,7 +406,7 @@ eekboard_client_disable_atspi_focus (EekboardClient *client) } gboolean -eekboard_client_enable_atspi_keystroke (EekboardClient *client) +client_enable_atspi_keystroke (Client *client) { GError *error; @@ -438,7 +438,7 @@ eekboard_client_enable_atspi_keystroke (EekboardClient *client) } void -eekboard_client_disable_atspi_keystroke (EekboardClient *client) +client_disable_atspi_keystroke (Client *client) { if (client->keystroke_listener) { GError *error; @@ -466,7 +466,7 @@ static void focus_listener_cb (const AtspiEvent *event, void *user_data) { - EekboardClient *client = user_data; + Client *client = user_data; AtspiAccessible *accessible = event->source; AtspiStateSet *state_set = atspi_accessible_get_state_set (accessible); AtspiRole role; @@ -516,14 +516,14 @@ static gboolean keystroke_listener_cb (const AtspiDeviceEvent *stroke, void *user_data) { - EekboardClient *client = user_data; + Client *client = user_data; switch (stroke->type) { case ATSPI_KEY_PRESSED: - eekboard_context_press_key (client->context, stroke->hw_code, NULL); + eekboard_context_press_keycode (client->context, stroke->hw_code, NULL); break; case ATSPI_KEY_RELEASED: - eekboard_context_release_key (client->context, stroke->hw_code, NULL); + eekboard_context_release_keycode (client->context, stroke->hw_code, NULL); break; default: g_return_val_if_reached (FALSE); @@ -537,25 +537,25 @@ static void add_match_rule (GDBusConnection *connection, const gchar *match_rule) { - GError *error; - GDBusMessage *message; + GError *error; + GDBusMessage *message; - message = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */ - "/org/freedesktop/DBus", /* path */ - "org.freedesktop.DBus", /* interface */ - "AddMatch"); - g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule)); - error = NULL; - g_dbus_connection_send_message (connection, - message, - G_DBUS_SEND_MESSAGE_FLAGS_NONE, - NULL, - &error); - g_object_unref (message); + message = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */ + "/org/freedesktop/DBus", /* path */ + "org.freedesktop.DBus", /* interface */ + "AddMatch"); + g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule)); + error = NULL; + g_dbus_connection_send_message (connection, + message, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + NULL, + &error); + g_object_unref (message); } static gboolean -on_hide_keyboard_timeout (EekboardClient *client) +on_hide_keyboard_timeout (Client *client) { eekboard_context_hide_keyboard (client->context, NULL); client->hide_keyboard_timeout_id = 0; @@ -568,7 +568,7 @@ focus_message_filter (GDBusConnection *connection, gboolean incoming, gpointer user_data) { - EekboardClient *client = user_data; + Client *client = user_data; if (incoming && g_strcmp0 (g_dbus_message_get_interface (message), @@ -598,7 +598,7 @@ focus_message_filter (GDBusConnection *connection, static void _ibus_connect_focus_handlers (IBusBus *bus, gpointer user_data) { - EekboardClient *client = user_data; + Client *client = user_data; GDBusConnection *connection; connection = ibus_bus_get_connection (bus); @@ -618,7 +618,7 @@ _ibus_connect_focus_handlers (IBusBus *bus, gpointer user_data) } gboolean -eekboard_client_enable_ibus_focus (EekboardClient *client) +client_enable_ibus_focus (Client *client) { if (!client->ibus_bus) { client->ibus_bus = ibus_bus_new (); @@ -636,7 +636,7 @@ eekboard_client_enable_ibus_focus (EekboardClient *client) } void -eekboard_client_disable_ibus_focus (EekboardClient *client) +client_disable_ibus_focus (Client *client) { GDBusConnection *connection; @@ -654,12 +654,12 @@ eekboard_client_disable_ibus_focus (EekboardClient *client) } #endif /* HAVE_ATSPI */ -EekboardClient * -eekboard_client_new (GDBusConnection *connection) +Client * +client_new (GDBusConnection *connection) { - EekboardClient *client = g_object_new (EEKBOARD_TYPE_CLIENT, - "connection", connection, - NULL); + Client *client = g_object_new (TYPE_CLIENT, + "connection", connection, + NULL); if (client->context) return client; return NULL; @@ -670,7 +670,7 @@ filter_xkl_event (GdkXEvent *xev, GdkEvent *event, gpointer user_data) { - EekboardClient *client = user_data; + Client *client = user_data; XEvent *xevent = (XEvent *)xev; xkl_engine_filter_events (client->xkl_engine, xevent); @@ -681,7 +681,7 @@ static void on_xkl_config_changed (XklEngine *xklengine, gpointer user_data) { - EekboardClient *client = user_data; + Client *client = user_data; gboolean retval; retval = set_keyboard_from_xkl (client); @@ -693,7 +693,7 @@ on_xkl_config_changed (XklEngine *xklengine, } static gboolean -set_keyboard (EekboardClient *client, +set_keyboard (Client *client, const gchar *keyboard) { GSList *keyboards = NULL; @@ -729,7 +729,7 @@ set_keyboard (EekboardClient *client, } static gboolean -set_keyboard_from_xkl (EekboardClient *client) +set_keyboard_from_xkl (Client *client) { XklConfigRec *rec; gchar *layout, *keyboard; @@ -761,7 +761,7 @@ on_xkl_state_changed (XklEngine *xklengine, gboolean restore, gpointer user_data) { - EekboardClient *client = user_data; + Client *client = user_data; if (type == GROUP_CHANGED) eekboard_context_set_group (client->context, value, NULL); @@ -776,7 +776,7 @@ on_xkl_state_changed (XklEngine *xklengine, - get_keycode_from_gdk_keymap (Caribou: best_keycode_keyval_match) */ static guint -get_replaced_keycode (EekboardClient *client) +get_replaced_keycode (Client *client) { GdkDisplay *display = gdk_display_get_default (); Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); @@ -798,7 +798,7 @@ get_replaced_keycode (EekboardClient *client) non-zero keycode), it simply changes the current map with the specified KEYCODE and KEYSYM. */ static gboolean -replace_keycode (EekboardClient *client, +replace_keycode (Client *client, guint *keycode, guint *keysym) { @@ -834,7 +834,7 @@ replace_keycode (EekboardClient *client, } static gboolean -get_keycode_from_gdk_keymap (EekboardClient *client, +get_keycode_from_gdk_keymap (Client *client, guint keysym, guint *keycode, guint *modifiers) @@ -859,7 +859,7 @@ get_keycode_from_gdk_keymap (EekboardClient *client, } static void -send_fake_modifier_key_event (EekboardClient *client, +send_fake_modifier_key_event (Client *client, EekModifierType modifiers, gboolean is_pressed) { @@ -881,7 +881,7 @@ send_fake_modifier_key_event (EekboardClient *client, } static void -send_fake_key_event (EekboardClient *client, +send_fake_key_event (Client *client, EekSymbol *symbol, guint keyboard_modifiers, gboolean is_pressed) @@ -939,7 +939,7 @@ on_key_pressed (EekboardContext *context, guint modifiers, gpointer user_data) { - EekboardClient *client = user_data; + Client *client = user_data; if (g_strcmp0 (eek_symbol_get_name (symbol), "cycle-keyboard") == 0) { client->keyboards = g_slist_next (client->keyboards); @@ -953,7 +953,7 @@ on_key_pressed (EekboardContext *context, } static void -update_modifier_keycodes (EekboardClient *client) +update_modifier_keycodes (Client *client) { GdkDisplay *display = gdk_display_get_default (); XModifierKeymap *mods; @@ -974,7 +974,7 @@ update_modifier_keycodes (EekboardClient *client) } gboolean -eekboard_client_enable_xtest (EekboardClient *client) +client_enable_xtest (Client *client) { GdkDisplay *display = gdk_display_get_default (); int opcode, event_base, error_base, major_version, minor_version; @@ -1011,7 +1011,7 @@ eekboard_client_enable_xtest (EekboardClient *client) } void -eekboard_client_disable_xtest (EekboardClient *client) +client_disable_xtest (Client *client) { if (client->xkb) { XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */ diff --git a/src/client.h b/src/client.h index 670730b2..048a94f7 100644 --- a/src/client.h +++ b/src/client.h @@ -15,48 +15,41 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef EEKBOARD_CLIENT_H -#define EEKBOARD_CLIENT_H 1 +#ifndef CLIENT_H +#define CLIENT_H 1 #include G_BEGIN_DECLS -#define EEKBOARD_TYPE_CLIENT (eekboard_client_get_type()) -#define EEKBOARD_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_CLIENT, EekboardClient)) -#define EEKBOARD_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_CLIENT, EekboardClientClass)) -#define EEKBOARD_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_CLIENT)) -#define EEKBOARD_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CLIENT)) -#define EEKBOARD_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CLIENT, EekboardClientClass)) +#define TYPE_CLIENT (client_get_type()) +#define CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CLIENT, Client)) +#define CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CLIENT, ClientClass)) +#define IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CLIENT)) +#define IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLIENT)) +#define CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CLIENT, ClientClass)) -typedef struct _EekboardClient EekboardClient; +typedef struct _Client Client; -EekboardClient * eekboard_client_new (GDBusConnection *connection); +Client *client_new (GDBusConnection *connection); -gboolean eekboard_client_set_keyboard - (EekboardClient *client, - const gchar *keyboard); +gboolean client_set_keyboard (Client *client, + const gchar *keyboard); -gboolean eekboard_client_enable_xkl (EekboardClient *client); -void eekboard_client_disable_xkl (EekboardClient *client); +gboolean client_enable_xkl (Client *client); +void client_disable_xkl (Client *client); -gboolean eekboard_client_enable_atspi_focus - (EekboardClient *client); -void eekboard_client_disable_atspi_focus - (EekboardClient *client); +gboolean client_enable_atspi_focus (Client *client); +void client_disable_atspi_focus (Client *client); -gboolean eekboard_client_enable_atspi_keystroke - (EekboardClient *client); -void eekboard_client_disable_atspi_keystroke - (EekboardClient *client); +gboolean client_enable_atspi_keystroke (Client *client); +void client_disable_atspi_keystroke (Client *client); -gboolean eekboard_client_enable_xtest (EekboardClient *client); -void eekboard_client_disable_xtest (EekboardClient *client); +gboolean client_enable_xtest (Client *client); +void client_disable_xtest (Client *client); -gboolean eekboard_client_enable_ibus_focus - (EekboardClient *client); -void eekboard_client_disable_ibus_focus - (EekboardClient *client); +gboolean client_enable_ibus_focus (Client *client); +void client_disable_ibus_focus (Client *client); G_END_DECLS -#endif /* EEKBOARD_CLIENT_H */ +#endif /* CLIENT_H */ diff --git a/src/server-context-service.c b/src/server-context-service.c new file mode 100644 index 00000000..11d2d55a --- /dev/null +++ b/src/server-context-service.c @@ -0,0 +1,473 @@ +/* + * 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 +#include + +#include +#include + +#if HAVE_CLUTTER_GTK +#include +#include "eek/eek-clutter.h" +#endif +#include "eek/eek-gtk.h" + +#include "server-context-service.h" + +#define DEFAULT_THEME (THEMEDIR "/default.css") + +enum { + PROP_0, + PROP_UI_TOOLKIT, + PROP_LAST +}; + +typedef enum { + UI_TOOLKIT_GTK, + UI_TOOLKIT_CLUTTER, + UI_TOOLKIT_DEFAULT = UI_TOOLKIT_GTK +} UIToolkitType; + +typedef struct _ServerContextServiceClass ServerContextServiceClass; + +struct _ServerContextService { + EekboardContextService parent; + + gboolean was_visible; + + GtkWidget *window; + GtkWidget *widget; + + gulong notify_visible_handler; + + GSettings *settings; + UIToolkitType ui_toolkit; +}; + +struct _ServerContextServiceClass { + EekboardContextServiceClass parent_class; +}; + +G_DEFINE_TYPE (ServerContextService, server_context_service, EEKBOARD_TYPE_CONTEXT_SERVICE); + +static void update_widget (ServerContextService *context); +static void set_geometry (ServerContextService *context); + +static void +on_monitors_changed (GdkScreen *screen, + gpointer user_data) +{ + ServerContextService *context = user_data; + if (context->window) + set_geometry (context); +} + +static void +on_destroy (GtkWidget *widget, gpointer user_data) +{ + ServerContextService *context = user_data; + + g_assert (widget == context->window); + context->window = NULL; + context->widget = NULL; +} + +static void +on_notify_keyboard (GObject *object, + GParamSpec *spec, + gpointer user_data) +{ + ServerContextService *context = user_data; + const EekKeyboard *keyboard; + + keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context)); + if (context->window) { + if (keyboard == NULL) { + gtk_widget_hide (context->window); + gtk_widget_destroy (context->widget); + } else { + gboolean was_visible = gtk_widget_get_visible (context->window); + /* avoid to send KeyboardVisibilityChanged */ + g_signal_handler_block (context->window, + context->notify_visible_handler); + update_widget (context); + if (was_visible) + gtk_widget_show_all (context->window); + g_signal_handler_unblock (context->window, + context->notify_visible_handler); + } + } +} + +static void +on_notify_fullscreen (GObject *object, + GParamSpec *spec, + gpointer user_data) +{ + ServerContextService *context = user_data; + set_geometry (context); +} + +static void +on_notify_visible (GObject *object, GParamSpec *spec, gpointer user_data) +{ + ServerContextService *context = user_data; + gboolean visible; + + g_object_get (object, "visible", &visible, NULL); + g_object_set (context, "visible", visible, NULL); +} + +static void +on_realize_set_dock (GtkWidget *widget, + gpointer user_data) +{ +#ifdef HAVE_XDOCK + GdkWindow *window = gtk_widget_get_window (widget); + gint x, y, width, height, depth; + long vals[12]; + + /* set window type to dock */ + gdk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_DOCK); + + /* set bottom strut */ +#if GTK_CHECK_VERSION(3,0,0) + gdk_window_get_geometry (window, &x, &y, &width, &height); +#else + gdk_window_get_geometry (window, &x, &y, &width, &height, &depth); +#endif /* GTK_CHECK_VERSION(3,0,0) */ + + vals[0] = 0; + vals[1] = 0; + vals[2] = 0; + vals[3] = height; + vals[4] = 0; + vals[5] = 0; + vals[6] = 0; + vals[7] = 0; + vals[8] = 0; + vals[9] = 0; + vals[10] = x; + vals[11] = x + width; + + XChangeProperty (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + XInternAtom (GDK_WINDOW_XDISPLAY (window), + "_NET_WM_STRUT_PARTIAL", False), + XA_CARDINAL, 32, PropModeReplace, + (guchar *)vals, 12); +#endif /* HAVE_XDOCK */ +} + +static void +on_realize_set_non_maximizable (GtkWidget *widget, + gpointer user_data) +{ + ServerContextService *context = user_data; + + g_assert (context && context->window == widget); + + /* make the window not maximizable */ + gdk_window_set_functions (gtk_widget_get_window (widget), + GDK_FUNC_RESIZE | + GDK_FUNC_MOVE | + GDK_FUNC_MINIMIZE | + GDK_FUNC_CLOSE); +} + +static void +set_geometry (ServerContextService *context) +{ + GdkScreen *screen; + GdkWindow *root; + gint monitor; + GdkRectangle rect; + const EekKeyboard *keyboard; + EekBounds bounds; + + 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); + keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context)); + eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds); + + g_signal_handlers_disconnect_by_func (context->window, + on_realize_set_dock, + context); + g_signal_handlers_disconnect_by_func (context->window, + on_realize_set_non_maximizable, + context); + + if (eekboard_context_service_get_fullscreen (EEKBOARD_CONTEXT_SERVICE(context))) { + gint width = rect.width, height = rect.height / 2; + + if (width * bounds.height > height * bounds.width) + width = (height / bounds.height) * bounds.width; + else + height = (width / bounds.width) * bounds.height; + + gtk_widget_set_size_request (context->widget, width, height); + + gtk_window_move (GTK_WINDOW(context->window), + (rect.width - width) / 2, + rect.height - height); + + gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE); + gtk_window_set_resizable (GTK_WINDOW(context->window), FALSE); + gtk_window_set_opacity (GTK_WINDOW(context->window), 0.8); + + g_signal_connect_after (context->window, "realize", + G_CALLBACK(on_realize_set_dock), + context); + } else { + if (context->ui_toolkit == UI_TOOLKIT_CLUTTER) { +#if HAVE_CLUTTER_GTK + ClutterActor *stage = + gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(context->widget)); + 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), + NULL); +#else + g_return_if_reached (); +#endif + } + gtk_widget_set_size_request (context->widget, + bounds.width, + bounds.height); + gtk_window_move (GTK_WINDOW(context->window), + MAX(rect.width - 20 - bounds.width, 0), + MAX(rect.height - 40 - bounds.height, 0)); + g_signal_connect_after (context->window, "realize", + G_CALLBACK(on_realize_set_non_maximizable), + context); + } +} + +static void +update_widget (ServerContextService *context) +{ + const EekKeyboard *keyboard; + const gchar *client_name; + EekBounds bounds; + EekTheme *theme; +#if HAVE_CLUTTER_GTK + ClutterActor *stage, *actor; + ClutterColor stage_color = { 0xff, 0xff, 0xff, 0xff }; +#endif + + if (context->widget) + gtk_widget_destroy (context->widget); + + theme = eek_theme_new (DEFAULT_THEME, NULL, NULL); + keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context)); + eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds); + if (context->ui_toolkit == UI_TOOLKIT_CLUTTER) { +#if HAVE_CLUTTER_GTK + context->widget = gtk_clutter_embed_new (); + stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(context->widget)); + actor = eek_clutter_keyboard_new (context->keyboard); + clutter_actor_set_name (actor, "keyboard"); + if (theme) + eek_clutter_keyboard_set_theme (EEK_CLUTTER_KEYBOARD(actor), theme); + clutter_container_add_actor (CLUTTER_CONTAINER(stage), actor); + + clutter_stage_set_color (CLUTTER_STAGE(stage), &stage_color); +#else + g_return_if_reached (); +#endif + } else { + context->widget = eek_gtk_keyboard_new (keyboard); + if (theme) + eek_gtk_keyboard_set_theme (EEK_GTK_KEYBOARD(context->widget), + theme); + } + + if (!context->window) { + context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (context->window, "destroy", + G_CALLBACK(on_destroy), context); + context->notify_visible_handler = + g_signal_connect (context->window, "notify::visible", + G_CALLBACK(on_notify_visible), context); + + gtk_widget_set_can_focus (context->window, FALSE); + g_object_set (G_OBJECT(context->window), "accept_focus", FALSE, NULL); + client_name = eekboard_context_service_get_client_name (EEKBOARD_CONTEXT_SERVICE(context)); + gtk_window_set_title (GTK_WINDOW(context->window), + client_name ? client_name : _("Keyboard")); + gtk_window_set_icon_name (GTK_WINDOW(context->window), "eekboard"); + gtk_window_set_keep_above (GTK_WINDOW(context->window), TRUE); + } + gtk_container_add (GTK_CONTAINER(context->window), context->widget); + set_geometry (context); +} + +static void +server_context_service_real_show_keyboard (EekboardContextService *_context) +{ + ServerContextService *context = SERVER_CONTEXT_SERVICE(_context); + + if (!context->window) + update_widget (context); + g_assert (context->window); + gtk_widget_show_all (context->window); +} + +static void +server_context_service_real_hide_keyboard (EekboardContextService *_context) +{ + ServerContextService *context = SERVER_CONTEXT_SERVICE(_context); + + if (context->window) + gtk_widget_hide (context->window); +} + +static void +server_context_service_real_enabled (EekboardContextService *_context) +{ + ServerContextService *context = SERVER_CONTEXT_SERVICE(_context); + + if (context->was_visible && context->window) + gtk_widget_show_all (context->window); +} + +static void +server_context_service_real_disabled (EekboardContextService *_context) +{ + ServerContextService *context = SERVER_CONTEXT_SERVICE(_context); + + if (context->window) { + context->was_visible = + gtk_widget_get_visible (context->window); + gtk_widget_hide (context->window); + } +} + +static void +server_context_service_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ServerContextService *context = SERVER_CONTEXT_SERVICE(object); + const gchar *ui_toolkit; + + switch (prop_id) { + case PROP_UI_TOOLKIT: + ui_toolkit = g_value_get_string (value); + if (g_strcmp0 (ui_toolkit, "gtk") == 0) + context->ui_toolkit = UI_TOOLKIT_GTK; +#if HAVE_CLUTTER_GTK + else if (g_strcmp0 (ui_toolkit, "clutter") == 0) + context->ui_toolkit = UI_TOOLKIT_CLUTTER; +#endif /* HAVE_CLUTTER_GTK */ + else + g_warning ("unknown UI toolkit %s", ui_toolkit); + break; + default: + g_object_set_property (object, + g_param_spec_get_name (pspec), + value); + break; + } +} + +static void +server_context_service_dispose (GObject *object) +{ + ServerContextService *context = SERVER_CONTEXT_SERVICE(object); + + if (context->window) { + gtk_widget_destroy (context->window); + context->window = NULL; + } + + G_OBJECT_CLASS (server_context_service_parent_class)->dispose (object); +} + +static void +server_context_service_class_init (ServerContextServiceClass *klass) +{ + EekboardContextServiceClass *context_class = EEKBOARD_CONTEXT_SERVICE_CLASS(klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + context_class->show_keyboard = server_context_service_real_show_keyboard; + context_class->hide_keyboard = server_context_service_real_hide_keyboard; + context_class->enabled = server_context_service_real_enabled; + context_class->disabled = server_context_service_real_disabled; + + gobject_class->set_property = server_context_service_set_property; + gobject_class->dispose = server_context_service_dispose; + + pspec = g_param_spec_string ("ui-toolkit", + "UI toolkit", + "UI toolkit", + NULL, + G_PARAM_WRITABLE); + g_object_class_install_property (gobject_class, + PROP_UI_TOOLKIT, + pspec); +} + +static void +server_context_service_init (ServerContextService *context) +{ + GdkScreen *screen; + + screen = gdk_screen_get_default (); + g_signal_connect (screen, + "monitors-changed", + G_CALLBACK(on_monitors_changed), + context); + g_signal_connect (context, + "notify::keyboard", + G_CALLBACK(on_notify_keyboard), + context); + g_signal_connect (context, + "notify::fullscreen", + G_CALLBACK(on_notify_fullscreen), + context); + + context->settings = g_settings_new ("org.fedorahosted.eekboard"); + g_settings_bind (context->settings, "ui-toolkit", + context, "ui-toolkit", + G_SETTINGS_BIND_GET); +} + +ServerContextService * +server_context_service_new (const gchar *client_name, + const gchar *object_path, + GDBusConnection *connection) +{ + return g_object_new (SERVER_TYPE_CONTEXT_SERVICE, + "client-name", client_name, + "object-path", object_path, + "connection", connection, + NULL); +} diff --git a/src/server-context-service.h b/src/server-context-service.h new file mode 100644 index 00000000..34fc6004 --- /dev/null +++ b/src/server-context-service.h @@ -0,0 +1,40 @@ +/* + * 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_SERVICE_H +#define SERVER_CONTEXT_SERVICE_H 1 + +G_BEGIN_DECLS + +#include "eekboard/eekboard-service.h" + +#define SERVER_TYPE_CONTEXT_SERVICE (server_context_service_get_type()) +#define SERVER_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SERVER_TYPE_CONTEXT_SERVICE, ServerContextService)) +#define SERVER_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SERVER_TYPE_CONTEXT_SERVICE, ServerContextServiceClass)) +#define SERVER_IS_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SERVER_TYPE_CONTEXT_SERVICE)) +#define SERVER_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SERVER_TYPE_CONTEXT_SERVICE)) +#define SERVER_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SERVER_TYPE_CONTEXT_SERVICE, ServerContextServiceClass)) + +typedef struct _ServerContextService ServerContextService; + +ServerContextService *server_context_service_new (const gchar *client_name, + const gchar *object_path, + GDBusConnection *connection); + +G_END_DECLS +#endif /* SERVER_CONTEXT_SERVICE_H */ + diff --git a/src/server-context.c b/src/server-context.c deleted file mode 100644 index 6dcb9326..00000000 --- a/src/server-context.c +++ /dev/null @@ -1,1070 +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 -#include - -#include -#include - -#include "eek/eek.h" - -#if HAVE_CLUTTER_GTK -#include -#include "eek/eek-clutter.h" -#endif -#include "eek/eek-gtk.h" -#include "eek/eek-xkl.h" - -#include "server-context.h" -#include "xklutil.h" - -#define CSW 640 -#define CSH 480 -#define DEFAULT_THEME (THEMEDIR "/default.css") - -enum { - PROP_0, - PROP_OBJECT_PATH, - PROP_CONNECTION, - PROP_UI_TOOLKIT, - PROP_LAST -}; - -static const gchar introspection_xml[] = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - /* signals */ - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -typedef enum { - UI_TOOLKIT_GTK, - UI_TOOLKIT_CLUTTER, - UI_TOOLKIT_DEFAULT = UI_TOOLKIT_GTK -} ServerContextUIToolkitType; - -typedef struct _ServerContextClass ServerContextClass; - -struct _ServerContext { - GObject parent; - GDBusConnection *connection; - GDBusNodeInfo *introspection_data; - guint registration_id; - char *object_path; - char *client_connection; - char *client_name; - - gboolean enabled; - gboolean last_keyboard_visible; - gboolean fullscreen; - - GtkWidget *window; - GtkWidget *widget; - guint keyboard_id; - EekKeyboard *keyboard; - GHashTable *keyboard_hash; - - gulong key_pressed_handler; - gulong key_released_handler; - gulong notify_visible_handler; - - EekKey *repeat_key; - guint repeat_timeout_id; - gboolean repeat_triggered; - - GSettings *settings; - ServerContextUIToolkitType ui_toolkit; -}; - -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 = - clutter_container_find_child_by_name (CLUTTER_CONTAINER(stage), - "keyboard"); - - 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 -on_realize_set_dock (GtkWidget *widget, - gpointer user_data) -{ -#ifdef HAVE_XDOCK - GdkWindow *window = gtk_widget_get_window (widget); - gint x, y, width, height, depth; - long vals[12]; - - /* set window type to dock */ - gdk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_DOCK); - - /* set bottom strut */ -#if GTK_CHECK_VERSION(3,0,0) - gdk_window_get_geometry (window, &x, &y, &width, &height); -#else - gdk_window_get_geometry (window, &x, &y, &width, &height, &depth); -#endif /* GTK_CHECK_VERSION(3,0,0) */ - - vals[0] = 0; - vals[1] = 0; - vals[2] = 0; - vals[3] = height; - vals[4] = 0; - vals[5] = 0; - vals[6] = 0; - vals[7] = 0; - vals[8] = 0; - vals[9] = 0; - vals[10] = x; - vals[11] = x + width; - - XChangeProperty (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), - XInternAtom (GDK_WINDOW_XDISPLAY (window), - "_NET_WM_STRUT_PARTIAL", False), - XA_CARDINAL, 32, PropModeReplace, - (guchar *)vals, 12); -#endif /* HAVE_XDOCK */ -} - -static void -on_realize_set_non_maximizable (GtkWidget *widget, - gpointer user_data) -{ - ServerContext *context = user_data; - - g_assert (context && context->window == widget); - - /* make the window not maximizable */ - gdk_window_set_functions (gtk_widget_get_window (widget), - GDK_FUNC_RESIZE | - GDK_FUNC_MOVE | - GDK_FUNC_MINIMIZE | - GDK_FUNC_CLOSE); -} - -static void -set_geometry (ServerContext *context) -{ - GdkScreen *screen; - GdkWindow *root; - gint monitor; - GdkRectangle rect; - EekBounds bounds; - - 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); - eek_element_get_bounds (EEK_ELEMENT(context->keyboard), &bounds); - - g_signal_handlers_disconnect_by_func (context->window, - on_realize_set_dock, - context); - g_signal_handlers_disconnect_by_func (context->window, - on_realize_set_non_maximizable, - context); - - if (context->fullscreen) { - gint width = rect.width, height = rect.height / 2; - - if (width * bounds.height > height * bounds.width) - width = (height / bounds.height) * bounds.width; - else - height = (width / bounds.width) * bounds.height; - - gtk_widget_set_size_request (context->widget, width, height); - - gtk_window_move (GTK_WINDOW(context->window), - (rect.width - width) / 2, - rect.height - height); - - gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE); - gtk_window_set_resizable (GTK_WINDOW(context->window), FALSE); - gtk_window_set_opacity (GTK_WINDOW(context->window), 0.8); - - g_signal_connect_after (context->window, "realize", - G_CALLBACK(on_realize_set_dock), - context); - } else { - if (context->ui_toolkit == UI_TOOLKIT_CLUTTER) { -#if HAVE_CLUTTER_GTK - ClutterActor *stage = - gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(context->widget)); - 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), - NULL); -#else - g_return_if_reached (); -#endif - } - gtk_widget_set_size_request (context->widget, - bounds.width, - bounds.height); - gtk_window_move (GTK_WINDOW(context->window), - MAX(rect.width - 20 - bounds.width, 0), - MAX(rect.height - 40 - bounds.height, 0)); - g_signal_connect_after (context->window, "realize", - G_CALLBACK(on_realize_set_non_maximizable), - context); - } -} - -static void -update_widget (ServerContext *context) -{ - EekBounds bounds; - EekTheme *theme; -#if HAVE_CLUTTER_GTK - ClutterActor *stage, *actor; - ClutterColor stage_color = { 0xff, 0xff, 0xff, 0xff }; -#endif - - if (context->widget) - gtk_widget_destroy (context->widget); - - theme = eek_theme_new (DEFAULT_THEME, NULL, NULL); - eek_element_get_bounds (EEK_ELEMENT(context->keyboard), &bounds); - if (context->ui_toolkit == UI_TOOLKIT_CLUTTER) { -#if HAVE_CLUTTER_GTK - context->widget = gtk_clutter_embed_new (); - stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(context->widget)); - actor = eek_clutter_keyboard_new (context->keyboard); - clutter_actor_set_name (actor, "keyboard"); - if (theme) - eek_clutter_keyboard_set_theme (EEK_CLUTTER_KEYBOARD(actor), theme); - clutter_container_add_actor (CLUTTER_CONTAINER(stage), actor); - - clutter_stage_set_color (CLUTTER_STAGE(stage), &stage_color); -#else - g_return_if_reached (); -#endif - } else { - context->widget = eek_gtk_keyboard_new (context->keyboard); - if (theme) - eek_gtk_keyboard_set_theme (EEK_GTK_KEYBOARD(context->widget), - theme); - } - - if (!context->window) { - context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - g_signal_connect (context->window, "destroy", - G_CALLBACK(on_destroy), context); - context->notify_visible_handler = - g_signal_connect (context->window, "notify::visible", - G_CALLBACK(on_notify_visible), context); - - 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->client_name ? - context->client_name : - _("Keyboard")); - gtk_window_set_icon_name (GTK_WINDOW(context->window), "eekboard"); - gtk_window_set_keep_above (GTK_WINDOW(context->window), TRUE); - } - gtk_container_add (GTK_CONTAINER(context->window), context->widget); - set_geometry (context); -} - -static void -server_context_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ServerContext *context = SERVER_CONTEXT(object); - GDBusConnection *connection; - const gchar *ui_toolkit; - - 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; - case PROP_UI_TOOLKIT: - ui_toolkit = g_value_get_string (value); - if (g_strcmp0 (ui_toolkit, "gtk") == 0) - context->ui_toolkit = UI_TOOLKIT_GTK; -#if HAVE_CLUTTER_GTK - else if (g_strcmp0 (ui_toolkit, "clutter") == 0) - context->ui_toolkit = UI_TOOLKIT_CLUTTER; -#endif /* HAVE_CLUTTER_GTK */ - else - g_warning ("unknown UI toolkit %s", ui_toolkit); - 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); - context->keyboard = NULL; - } - - if (context->keyboard_hash) { - g_hash_table_destroy (context->keyboard_hash); - context->keyboard_hash = 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; - } - - if (context->settings) { - g_object_unref (context->settings); - context->settings = NULL; - } - - G_OBJECT_CLASS (server_context_parent_class)->dispose (object); -} - -static void -server_context_finalize (GObject *object) -{ - ServerContext *context = SERVER_CONTEXT(object); - - g_free (context->object_path); - g_free (context->client_connection); - g_free (context->client_name); - - G_OBJECT_CLASS (server_context_parent_class)->finalize (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; - gobject_class->finalize = server_context_finalize; - - 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); - - pspec = g_param_spec_string ("ui-toolkit", - "UI toolkit", - "UI toolkit", - NULL, - G_PARAM_WRITABLE); - g_object_class_install_property (gobject_class, - PROP_UI_TOOLKIT, - pspec); -} - -static void -on_monitors_changed (GdkScreen *screen, - gpointer user_data) -{ - ServerContext *context = user_data; - if (context->window) - set_geometry (context); -} - -static void -server_context_init (ServerContext *context) -{ - GdkScreen *screen; - GError *error; - - error = NULL; - context->introspection_data = - g_dbus_node_info_new_for_xml (introspection_xml, &error); - g_assert (context->introspection_data != NULL); - - context->keyboard_hash = - g_hash_table_new_full (g_direct_hash, - g_direct_equal, - NULL, - (GDestroyNotify)g_object_unref); - - context->ui_toolkit = UI_TOOLKIT_DEFAULT; - - context->settings = g_settings_new ("org.fedorahosted.eekboard"); - g_settings_bind (context->settings, "ui-toolkit", - context, "ui-toolkit", - G_SETTINGS_BIND_GET); - - screen = gdk_screen_get_default (); - g_signal_connect (screen, - "monitors-changed", - G_CALLBACK(on_monitors_changed), - context); -} - -static gboolean on_repeat_timeout (ServerContext *context); - -static void -emit_key_pressed_dbus_signal (ServerContext *context, EekKey *key) -{ - if (context->connection && context->enabled) { - const gchar *keyname = eek_element_get_name (EEK_ELEMENT(key)); - EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0); - guint modifiers = eek_keyboard_get_modifiers (context->keyboard); - GVariant *variant; - GError *error; - - variant = eek_serializable_serialize (EEK_SERIALIZABLE(symbol)); - - error = NULL; - g_dbus_connection_emit_signal (context->connection, - NULL, - context->object_path, - SERVER_CONTEXT_INTERFACE, - "KeyPressed", - g_variant_new ("(svu)", - keyname, - variant, - modifiers), - &error); - g_variant_unref (variant); - g_assert_no_error (error); - } -} - -static gboolean -on_repeat_timeout (ServerContext *context) -{ - gint delay = g_settings_get_int (context->settings, "repeat-interval"); - - emit_key_pressed_dbus_signal (context, context->repeat_key); - - context->repeat_timeout_id = - g_timeout_add (delay, - (GSourceFunc)on_repeat_timeout, - context); - - return FALSE; -} - -static gboolean -on_repeat_timeout_init (ServerContext *context) -{ - emit_key_pressed_dbus_signal (context, context->repeat_key); - - /* FIXME: clear modifiers for further key repeat; better not - depend on modifier behavior is LATCH */ - eek_keyboard_set_modifiers (context->keyboard, 0); - - /* reschedule repeat timeout only when "repeat" option is set */ - if (g_settings_get_boolean (context->settings, "repeat")) { - gint delay = g_settings_get_int (context->settings, "repeat-interval"); - context->repeat_timeout_id = - g_timeout_add (delay, - (GSourceFunc)on_repeat_timeout, - context); - } else - context->repeat_timeout_id = 0; - - return FALSE; -} - -static void -on_key_pressed (EekKeyboard *keyboard, - EekKey *key, - gpointer user_data) -{ - ServerContext *context = user_data; - gint delay = g_settings_get_int (context->settings, "repeat-delay"); - - if (context->repeat_timeout_id) { - g_source_remove (context->repeat_timeout_id); - context->repeat_timeout_id = 0; - } - - context->repeat_key = key; - context->repeat_timeout_id = - g_timeout_add (delay, - (GSourceFunc)on_repeat_timeout_init, - context); -} - -static void -on_key_released (EekKeyboard *keyboard, - EekKey *key, - gpointer user_data) -{ - ServerContext *context = user_data; - - if (context->repeat_timeout_id > 0) { - g_source_remove (context->repeat_timeout_id); - context->repeat_timeout_id = 0; - - /* KeyPressed signal has not been emitted in repeat handler */ - emit_key_pressed_dbus_signal (context, context->repeat_key); - } -} - -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 EekKeyboard * -create_keyboard_from_string (const gchar *string) -{ - EekKeyboard *keyboard; - EekLayout *layout; - - if (g_str_has_prefix (string, "xkb:")) { - XklConfigRec *rec = eekboard_xkl_config_rec_from_string (&string[4]); - - layout = eek_xkl_layout_new (); - if (!eek_xkl_layout_set_config (EEK_XKL_LAYOUT(layout), rec)) { - g_object_unref (layout); - return NULL; - } - } else { - gchar *path; - GFile *file; - GFileInputStream *input; - GError *error; - - path = g_strdup_printf ("%s/%s.xml", KEYBOARDDIR, string); - file = g_file_new_for_path (path); - g_free (path); - - error = NULL; - input = g_file_read (file, NULL, &error); - if (input == NULL) { - g_object_unref (file); - return NULL; - } - layout = eek_xml_layout_new (G_INPUT_STREAM(input)); - } - keyboard = eek_keyboard_new (layout, CSW, CSH); - g_object_unref (layout); - - return keyboard; -} - -static void -emit_group_changed_signal (ServerContext *context, int group) -{ - GError *error; - - error = NULL; - g_dbus_connection_emit_signal (context->connection, - NULL, - context->object_path, - SERVER_CONTEXT_INTERFACE, - "GroupChanged", - g_variant_new ("(i)", group), - &error); - g_assert_no_error (error); -} - -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, "AddKeyboard") == 0) { - const gchar *name; - static guint keyboard_id = 0; - EekKeyboard *keyboard; - - g_variant_get (parameters, "(&s)", &name); - keyboard = create_keyboard_from_string (name); - - if (keyboard == NULL) { - g_dbus_method_invocation_return_error (invocation, - G_IO_ERROR, - G_IO_ERROR_FAILED_HANDLED, - "can't create a keyboard"); - return; - } - - eek_keyboard_set_modifier_behavior (keyboard, - EEK_MODIFIER_BEHAVIOR_LATCH); - - g_hash_table_insert (context->keyboard_hash, - GUINT_TO_POINTER(++keyboard_id), - keyboard); - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(u)", - keyboard_id)); - return; - } - - if (g_strcmp0 (method_name, "RemoveKeyboard") == 0) { - guint keyboard_id; - - g_variant_get (parameters, "(u)", &keyboard_id); - - if (keyboard_id == context->keyboard_id) { - disconnect_keyboard_signals (context); - if (context->window) { - gtk_widget_hide (context->window); - gtk_widget_destroy (context->widget); - } - - context->keyboard = NULL; - } - - g_hash_table_remove (context->keyboard_hash, - GUINT_TO_POINTER(keyboard_id)); - g_dbus_method_invocation_return_value (invocation, NULL); - return; - } - - if (g_strcmp0 (method_name, "SetKeyboard") == 0) { - EekKeyboard *keyboard; - guint keyboard_id; - gint group; - - g_variant_get (parameters, "(u)", &keyboard_id); - - keyboard = g_hash_table_lookup (context->keyboard_hash, - GUINT_TO_POINTER(keyboard_id)); - if (!keyboard) { - g_dbus_method_invocation_return_error (invocation, - G_IO_ERROR, - G_IO_ERROR_FAILED_HANDLED, - "no such keyboard"); - return; - } - - if (keyboard == context->keyboard) { - g_dbus_method_invocation_return_value (invocation, NULL); - return; - } - - if (context->keyboard) - disconnect_keyboard_signals (context); - - context->keyboard = keyboard; - - 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); - - if (context->window) { - gboolean was_visible = gtk_widget_get_visible (context->window); - /* avoid to send KeyboardVisibilityChanged */ - g_signal_handler_block (context->window, - context->notify_visible_handler); - update_widget (context); - if (was_visible) - gtk_widget_show_all (context->window); - g_signal_handler_unblock (context->window, - context->notify_visible_handler); - } - - g_dbus_method_invocation_return_value (invocation, NULL); - - group = eek_element_get_group (EEK_ELEMENT(context->keyboard)); - emit_group_changed_signal (context, group); - - return; - } - - if (g_strcmp0 (method_name, "SetFullscreen") == 0) { - gboolean fullscreen; - - g_variant_get (parameters, "(b)", &fullscreen); - - if (context->fullscreen == fullscreen) { - g_dbus_method_invocation_return_value (invocation, NULL); - return; - } - context->fullscreen = fullscreen; - if (context->window) - set_geometry (context); - - g_dbus_method_invocation_return_value (invocation, NULL); - return; - } - - if (g_strcmp0 (method_name, "SetGroup") == 0) { - gint group; - - 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_element_set_group (EEK_ELEMENT(context->keyboard), group); - - if (context->window) { - gboolean was_visible = gtk_widget_get_visible (context->window); - - /* avoid to send KeyboardVisibilityChanged */ - g_signal_handler_block (context->window, - context->notify_visible_handler); - update_widget (context); - if (was_visible) - gtk_widget_show_all (context->window); - g_signal_handler_unblock (context->window, - context->notify_visible_handler); - } - - g_dbus_method_invocation_return_value (invocation, NULL); - - emit_group_changed_signal (context, group); - - 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->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; - - context->enabled = enabled; - 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); - if (context->last_keyboard_visible && context->window) - gtk_widget_show_all (context->window); - } 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); - if (context->window) { - context->last_keyboard_visible = - gtk_widget_get_visible (context->window); - gtk_widget_hide (context->window); - } - } -} - -void -server_context_set_client_connection (ServerContext *context, - const gchar *client_connection) -{ - g_free (context->client_connection); - context->client_connection = g_strdup (client_connection); -} - -const gchar * -server_context_get_client_connection (ServerContext *context) -{ - return context->client_connection; -} - -void -server_context_set_client_name (ServerContext *context, - const gchar *client_name) -{ - g_free (context->client_name); - context->client_name = g_strdup (client_name); -} diff --git a/src/server-main.c b/src/server-main.c index 387c0589..2aa238c3 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -28,7 +28,7 @@ #include #endif -#include "server-server.h" +#include "server-service.h" #include "eek/eek.h" static gboolean opt_system = FALSE; @@ -61,7 +61,7 @@ on_name_lost (GDBusConnection *connection, } static void -on_destroyed (ServerServer *server, +on_destroyed (ServerService *service, gpointer user_data) { GMainLoop *loop = user_data; @@ -72,7 +72,7 @@ on_destroyed (ServerServer *server, int main (int argc, char **argv) { - ServerServer *server; + ServerService *service; GBusType bus_type; GDBusConnection *connection; GError *error; @@ -131,15 +131,15 @@ main (int argc, char **argv) break; } - server = server_server_new (SERVER_SERVER_PATH, connection); + service = server_service_new (EEKBOARD_SERVICE_PATH, connection); - if (server == NULL) { + if (service == NULL) { g_printerr ("Can't create server\n"); exit (1); } owner_id = g_bus_own_name_on_connection (connection, - SERVER_SERVER_INTERFACE, + EEKBOARD_SERVICE_INTERFACE, G_BUS_NAME_OWNER_FLAGS_NONE, on_name_acquired, on_name_lost, @@ -152,12 +152,12 @@ main (int argc, char **argv) loop = g_main_loop_new (NULL, FALSE); - g_signal_connect (server, "destroyed", G_CALLBACK(on_destroyed), loop); + g_signal_connect (service, "destroyed", G_CALLBACK(on_destroyed), loop); g_main_loop_run (loop); g_bus_unown_name (owner_id); - g_object_unref (server); + g_object_unref (service); g_object_unref (connection); g_main_loop_unref (loop); diff --git a/src/server-server.h b/src/server-server.h deleted file mode 100644 index 80d6af2b..00000000 --- a/src/server-server.h +++ /dev/null @@ -1,41 +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 SERVER_KEYBOARD_H -#define SERVER_KEYBOARD_H 1 - -#include - -G_BEGIN_DECLS - -#define SERVER_SERVER_PATH "/org/fedorahosted/Eekboard/Server" -#define SERVER_SERVER_INTERFACE "org.fedorahosted.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-service.c b/src/server-service.c new file mode 100644 index 00000000..59ac3333 --- /dev/null +++ b/src/server-service.c @@ -0,0 +1,71 @@ +/* + * 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-service.h" +#include "server-context-service.h" + +typedef struct _ServerServiceClass ServerServiceClass; + +struct _ServerService { + EekboardService parent; +}; + +struct _ServerServiceClass { + EekboardServiceClass parent_class; +}; + +G_DEFINE_TYPE (ServerService, server_service, EEKBOARD_TYPE_SERVICE); + +static EekboardContextService * +server_service_real_create_context (EekboardService *self, + const gchar *client_name, + const gchar *object_path) +{ + GDBusConnection *connection; + ServerContextService *context; + + g_object_get (G_OBJECT(self), "connection", &connection, NULL); + context = server_context_service_new (client_name, object_path, connection); + g_object_unref (connection); + + return EEKBOARD_CONTEXT_SERVICE(context); +} + +static void +server_service_class_init (ServerServiceClass *klass) +{ + EekboardServiceClass *service_class = EEKBOARD_SERVICE_CLASS(klass); + service_class->create_context = server_service_real_create_context; +} + +static void +server_service_init (ServerService *self) +{ +} + +ServerService *server_service_new (const gchar *object_path, + GDBusConnection *connection) +{ + return g_object_new (SERVER_TYPE_SERVICE, + "object-path", object_path, + "connection", connection, + NULL); +} diff --git a/src/server-service.h b/src/server-service.h new file mode 100644 index 00000000..9e5e7dd3 --- /dev/null +++ b/src/server-service.h @@ -0,0 +1,38 @@ +/* + * 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_SERVICE_H +#define SERVER_SERVICE_H 1 + +#include "eekboard/eekboard-service.h" + +G_BEGIN_DECLS + +#define SERVER_TYPE_SERVICE (server_service_get_type()) +#define SERVER_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SERVER_TYPE_SERVICE, ServerService)) +#define SERVER_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SERVER_TYPE_SERVICE, ServerServiceClass)) +#define SERVER_IS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SERVER_TYPE_SERVICE)) +#define SERVER_IS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SERVER_TYPE_SERVICE)) +#define SERVER_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SERVER_TYPE_SERVICE, ServerServiceClass)) + +typedef struct _ServerService ServerService; + +ServerService *server_service_new (const gchar *object_path, + GDBusConnection *connection); + +G_END_DECLS +#endif /* SERVER_SERVICE_H */ diff --git a/src/xml-main.c b/src/xml-main.c index 11818dc5..70282bbb 100644 --- a/src/xml-main.c +++ b/src/xml-main.c @@ -36,7 +36,7 @@ #include "eek/eek-gtk.h" #endif /* !HAVE_CLUTTER_GTK */ -#include "xklutil.h" +#include "eekboard/eekboard-xklutil.h" #define BUFSIZE 8192