diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index dd72ace9..5245eb8e 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -31,7 +31,6 @@ #include #include "eekboard/eekboard-context-service.h" -#include "eekboard/key-emitter.h" #include "keymap.h" #include "eek-keyboard.h" diff --git a/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c index 5b0e7add..94a6ae4c 100644 --- a/eekboard/eekboard-context-service.c +++ b/eekboard/eekboard-context-service.c @@ -37,7 +37,6 @@ #include -#include "eekboard/key-emitter.h" #include "wayland.h" #include "eek/eek-xml-layout.h" @@ -48,13 +47,10 @@ enum { PROP_0, // Magic: without this, keyboard is not useable in g_object_notify PROP_KEYBOARD, - PROP_VISIBLE, PROP_LAST }; enum { - ENABLED, - DISABLED, DESTROYED, LAST_SIGNAL }; @@ -65,17 +61,18 @@ static guint signals[LAST_SIGNAL] = { 0, }; (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServicePrivate)) struct _EekboardContextServicePrivate { - gboolean enabled; - gboolean visible; - LevelKeyboard *keyboard; // currently used keyboard GHashTable *keyboard_hash; // a table of available keyboards, per layout char *overlay; - GSettings *settings; + GSettings *settings; // Owned reference uint32_t hint; uint32_t purpose; + + // Maybe TODO: it's used only for fetching layout type. + // Maybe let UI push the type to this structure? + ServerContextService *ui; // unowned reference }; G_DEFINE_TYPE_WITH_PRIVATE (EekboardContextService, eekboard_context_service, G_TYPE_OBJECT); @@ -135,35 +132,14 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self, return keyboard; } -static void -eekboard_context_service_real_show_keyboard (EekboardContextService *self) -{ - self->priv->visible = TRUE; -} - -static void -eekboard_context_service_real_hide_keyboard (EekboardContextService *self) -{ - self->priv->visible = FALSE; -} - static void eekboard_context_service_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object); - + (void)value; switch (prop_id) { - case PROP_KEYBOARD: - if (context->priv->keyboard) - g_object_unref (context->priv->keyboard); - context->priv->keyboard = g_value_get_object (value); - break; - case PROP_VISIBLE: - context->priv->visible = g_value_get_boolean (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -182,9 +158,6 @@ eekboard_context_service_get_property (GObject *object, case PROP_KEYBOARD: g_value_set_object (value, context->priv->keyboard); break; - case PROP_VISIBLE: - g_value_set_boolean (value, context->priv->visible); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -249,6 +222,11 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ LevelKeyboard *previous_keyboard = context->priv->keyboard; context->priv->keyboard = keyboard; + // The keymap will get set even if the window is hidden. + // It's not perfect, + // but simpler than adding a check in the window showing procedure + eekboard_context_service_set_keymap(context, keyboard); + g_object_notify (G_OBJECT(context), "keyboard"); // replacing the keyboard above will cause the previous keyboard to get destroyed from the UI side (eek_gtk_keyboard_dispose) @@ -258,7 +236,12 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ } static void update_layout_and_type(EekboardContextService *context) { - eekboard_context_service_update_layout(context, server_context_service_get_layout_type(context)); + EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + enum squeek_arrangement_kind layout_kind = ARRANGEMENT_KIND_BASE; + if (priv->ui) { + layout_kind = server_context_service_get_layout_type(priv->ui); + } + eekboard_context_service_update_layout(context, layout_kind); } static gboolean @@ -294,48 +277,10 @@ eekboard_context_service_class_init (EekboardContextServiceClass *klass) GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; - klass->show_keyboard = eekboard_context_service_real_show_keyboard; - klass->hide_keyboard = eekboard_context_service_real_hide_keyboard; - 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; - - /** - * EekboardContextService::enabled: - * @context: an #EekboardContextService - * - * Emitted when @context is enabled. - */ - 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); - - /** - * EekboardContextService::disabled: - * @context: an #EekboardContextService - * - * Emitted when @context is enabled. - */ - 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); - /** * EekboardContextService::destroyed: * @context: an #EekboardContextService @@ -361,24 +306,10 @@ eekboard_context_service_class_init (EekboardContextServiceClass *klass) pspec = g_param_spec_pointer("keyboard", "Keyboard", "Keyboard", - G_PARAM_READWRITE); + G_PARAM_READABLE); g_object_class_install_property (gobject_class, PROP_KEYBOARD, pspec); - - /** - * EekboardContextService:visible: - * - * Flag to indicate if keyboard is visible or not. - */ - pspec = g_param_spec_boolean ("visible", - "Visible", - "Visible", - FALSE, - G_PARAM_READWRITE); - g_object_class_install_property (gobject_class, - PROP_VISIBLE, - pspec); } static void @@ -404,62 +335,6 @@ eekboard_context_service_init (EekboardContextService *self) self->priv->overlay = NULL; } -/** - * eekboard_context_service_enable: - * @context: an #EekboardContextService - * - * Enable @context. This function is called when @context is pushed - * by eekboard_service_push_context(). - */ -void -eekboard_context_service_enable (EekboardContextService *context) -{ - g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context)); - - if (!context->priv->enabled) { - context->priv->enabled = TRUE; - g_signal_emit (context, signals[ENABLED], 0); - } -} - -/** - * eekboard_context_service_disable: - * @context: an #EekboardContextService - * - * Disable @context. This function is called when @context is pushed - * by eekboard_service_pop_context(). - */ -void -eekboard_context_service_disable (EekboardContextService *context) -{ - g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context)); - - if (context->priv->enabled) { - context->priv->enabled = FALSE; - g_signal_emit (context, signals[DISABLED], 0); - } -} - -void -eekboard_context_service_show_keyboard (EekboardContextService *context) -{ - g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context)); - - if (!context->priv->visible) { - EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context)->show_keyboard (context); - } -} - -void -eekboard_context_service_hide_keyboard (EekboardContextService *context) -{ - g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context)); - - if (context->priv->visible) { - EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context)->hide_keyboard (context); - } -} - /** * eekboard_context_service_destroy: * @context: an #EekboardContextService @@ -471,9 +346,6 @@ eekboard_context_service_destroy (EekboardContextService *context) { g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context)); - if (context->priv->enabled) { - eekboard_context_service_disable (context); - } g_free(context->priv->overlay); g_signal_emit (context, signals[DESTROYED], 0); } @@ -521,3 +393,8 @@ const char* eekboard_context_service_get_overlay(EekboardContextService *context) { return context->priv->overlay; } + +EekboardContextService *eekboard_context_service_new() +{ + return g_object_new (EEKBOARD_TYPE_CONTEXT_SERVICE, NULL); +} diff --git a/eekboard/eekboard-context-service.h b/eekboard/eekboard-context-service.h index 38e4a9f2..dab830ce 100644 --- a/eekboard/eekboard-context-service.h +++ b/eekboard/eekboard-context-service.h @@ -46,6 +46,8 @@ typedef struct _EekboardContextServicePrivate EekboardContextServicePrivate; /** * EekboardContextService: * + * Handles layout state, gsettings, and virtual-keyboard. + * * TODO: Restrict to managing keyboard layouts, and maybe button repeats, * and the virtual keyboard protocol. * @@ -63,8 +65,6 @@ struct _EekboardContextService { /** * EekboardContextServiceClass: * @create_keyboard: virtual function for create a keyboard from string - * @show_keyboard: virtual function for show a keyboard - * @hide_keyboard: virtual function for hide a keyboard * @enabled: class handler for #EekboardContextService::enabled signal * @disabled: class handler for #EekboardContextService::disabled signal */ @@ -75,12 +75,8 @@ struct _EekboardContextServiceClass { /*< public >*/ struct squeek_view *(*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); void (*destroyed) (EekboardContextService *self); /*< private >*/ @@ -88,14 +84,10 @@ struct _EekboardContextServiceClass { gpointer pdummy[24]; }; +EekboardContextService *eekboard_context_service_new(); GType eekboard_context_service_get_type (void) G_GNUC_CONST; -void eekboard_context_service_enable (EekboardContextService *context); -void eekboard_context_service_disable (EekboardContextService *context); -void eekboard_context_service_show_keyboard - (EekboardContextService *context); -void eekboard_context_service_hide_keyboard - (EekboardContextService *context); +EekboardContextService *eekboard_context_service_new(void); void eekboard_context_service_destroy (EekboardContextService *context); LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context); diff --git a/eekboard/eekboard-service.c b/eekboard/eekboard-service.c deleted file mode 100644 index 3128789b..00000000 --- a/eekboard/eekboard-service.c +++ /dev/null @@ -1,310 +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 . - */ - -/** - * SECTION:eekboard-service - * @short_description: base implementation of eekboard service - * - * Provides a dbus object, and contains the context. - * - * The #EekboardService class provides a base server side - * implementation of eekboard service. - */ - -#include "config.h" - -#include "sm.puri.OSK0.h" - -#include - -#include - -#include "eekboard/eekboard-service.h" - -enum { - PROP_0, - PROP_OBJECT_PATH, - PROP_CONNECTION, - PROP_LAST -}; - -enum { - DESTROYED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0, }; - -typedef struct _EekboardServicePrivate -{ - GDBusConnection *connection; - SmPuriOSK0 *dbus_interface; - GDBusNodeInfo *introspection_data; - guint registration_id; - char *object_path; - - EekboardContextService *context; // unowned reference -} EekboardServicePrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (EekboardService, eekboard_service, G_TYPE_OBJECT) - -static void -eekboard_service_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - EekboardService *service = EEKBOARD_SERVICE(object); - EekboardServicePrivate *priv = eekboard_service_get_instance_private (service); - GDBusConnection *connection; - - switch (prop_id) { - case PROP_OBJECT_PATH: - if (priv->object_path) - g_free (priv->object_path); - priv->object_path = g_value_dup_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; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -eekboard_service_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - EekboardService *service = EEKBOARD_SERVICE(object); - EekboardServicePrivate *priv = eekboard_service_get_instance_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_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -eekboard_service_dispose (GObject *object) -{ - EekboardService *service = EEKBOARD_SERVICE(object); - EekboardServicePrivate *priv = eekboard_service_get_instance_private (service); - - 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; - } - - if (priv->context) { - g_signal_handlers_disconnect_by_data (priv->context, service); - priv->context = NULL; - } - - G_OBJECT_CLASS (eekboard_service_parent_class)->dispose (object); -} - -static void -eekboard_service_finalize (GObject *object) -{ - EekboardService *service = EEKBOARD_SERVICE(object); - EekboardServicePrivate *priv = eekboard_service_get_instance_private (service); - - g_free (priv->object_path); - - G_OBJECT_CLASS (eekboard_service_parent_class)->finalize (object); -} - -static gboolean -handle_set_visible(SmPuriOSK0 *object, GDBusMethodInvocation *invocation, - gboolean arg_visible, gpointer user_data) { - EekboardService *service = user_data; - EekboardServicePrivate *priv = eekboard_service_get_instance_private (service); - - if (priv->context) { - if (arg_visible) { - eekboard_context_service_show_keyboard (priv->context); - } else { - eekboard_context_service_hide_keyboard (priv->context); - } - } - sm_puri_osk0_complete_set_visible(object, invocation); - return TRUE; -} - -static void on_visible(EekboardService *service, - GParamSpec *pspec, - EekboardContextService *context) -{ - gboolean visible; - EekboardServicePrivate *priv; - - g_return_if_fail (EEKBOARD_IS_SERVICE (service)); - g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE (context)); - - priv = eekboard_service_get_instance_private (service); - g_object_get (context, "visible", &visible, NULL); - - sm_puri_osk0_set_visible(priv->dbus_interface, visible); -} - -static void -eekboard_service_constructed (GObject *object) -{ - EekboardService *service = EEKBOARD_SERVICE(object); - EekboardServicePrivate *priv = eekboard_service_get_instance_private (service); - - priv->dbus_interface = sm_puri_osk0_skeleton_new(); - g_signal_connect(priv->dbus_interface, "handle-set-visible", - G_CALLBACK(handle_set_visible), service); - - if (priv->connection && priv->object_path) { - GError *error = NULL; - - if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(priv->dbus_interface), - priv->connection, - priv->object_path, - &error)) { - g_warning("Error registering dbus object: %s\n", error->message); - g_clear_error(&error); - } - } -} - -static void -eekboard_service_class_init (EekboardServiceClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GParamSpec *pspec; - - 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; - - /** - * EekboardService::destroyed: - * @service: an #EekboardService - * - * The ::destroyed signal is emitted when the service is vanished. - */ - signals[DESTROYED] = - g_signal_new (I_("destroyed"), - G_TYPE_FROM_CLASS(gobject_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - /** - * EekboardService:object-path: - * - * D-Bus object path. - */ - 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); - - /** - * EekboardService:connection: - * - * D-Bus connection. - */ - 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); -} - -static void -eekboard_service_init (EekboardService *self) -{ - EekboardServicePrivate *priv = eekboard_service_get_instance_private (self); - - priv->context = NULL; -} - -/** - * eekboard_service_new: - * @connection: a #GDBusConnection - * @object_path: object path - */ -EekboardService * -eekboard_service_new (GDBusConnection *connection, - const gchar *object_path) -{ - return g_object_new (EEKBOARD_TYPE_SERVICE, - "object-path", object_path, - "connection", connection, - NULL); -} - -void -eekboard_service_set_context(EekboardService *service, - EekboardContextService *context) -{ - EekboardServicePrivate *priv = eekboard_service_get_instance_private (service); - - g_return_if_fail (!priv->context); - - priv->context = context; - - g_signal_connect_swapped (priv->context, - "notify::visible", - G_CALLBACK(on_visible), - service); -} diff --git a/eekboard/eekboard-service.h b/eekboard/eekboard-service.h deleted file mode 100644 index 58984bfb..00000000 --- a/eekboard/eekboard-service.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2010-2011 Daiki Ueno - * Copyright (C) 2010-2011 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef EEKBOARD_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 "/sm/puri/OSK0" -#define EEKBOARD_SERVICE_INTERFACE "sm.puri.OSK0" - -#define EEKBOARD_TYPE_SERVICE (eekboard_service_get_type()) -G_DECLARE_DERIVABLE_TYPE (EekboardService, eekboard_service, EEKBOARD, SERVICE, GObject) - -/** - * EekboardServiceClass: - * @create_context: virtual function for creating a context - */ -struct _EekboardServiceClass { - /*< private >*/ - GObjectClass parent_class; - - /*< public >*/ - EekboardContextService *(*create_context) (EekboardService *self); - - /*< private >*/ - /* padding */ - gpointer pdummy[24]; -}; - -GType eekboard_service_get_type (void) G_GNUC_CONST; -EekboardService * eekboard_service_new (GDBusConnection *connection, - const gchar *object_path); -void eekboard_service_set_context(EekboardService *service, - EekboardContextService *context); -G_END_DECLS -#endif /* EEKBOARD_SERVICE_H */ diff --git a/eekboard/key-emitter.c b/eekboard/key-emitter.c deleted file mode 100644 index b652441e..00000000 --- a/eekboard/key-emitter.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2011 Daiki Ueno - * Copyright (C) 2011 Red Hat, Inc. - * Copyright (C) 2019 Purism, SPC - * - * 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 . - */ - -/* This file is responsible for managing keycode data and emitting keycodes. */ - -#include "eekboard/key-emitter.h" - -#include -#include - -#include "eekboard/eekboard-context-service.h" - -// TODO: decide whether it's this struct that carries the keyboard around in key-emitter or if the whole manager should be dragged around -// if this is the carrier, then it should be made part of the manager -// hint: check which fields need to be persisted between keypresses; which between keyboards -typedef struct { - struct zwp_virtual_keyboard_v1 *virtual_keyboard; // unowned copy - struct xkb_keymap *keymap; // unowned copy - XkbDescRec *xkb; - guint modifier_keycodes[8]; - guint modifier_indices[MOD_IDX_LAST]; - guint group; -} SeatEmitter; - - -int send_virtual_keyboard_key( - struct zwp_virtual_keyboard_v1 *keyboard, - unsigned int keycode, - unsigned is_press, - uint32_t timestamp -) { - zwp_virtual_keyboard_v1_key(keyboard, timestamp, keycode, (unsigned)is_press); - return 0; -} - -/* Finds the first key code for each modifier and saves it in modifier_keycodes */ -static void -update_modifier_info (SeatEmitter *client) -{ - client->modifier_indices[MOD_IDX_SHIFT] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_SHIFT); - client->modifier_indices[MOD_IDX_CAPS] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_CAPS); - client->modifier_indices[MOD_IDX_CTRL] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_CTRL); - client->modifier_indices[MOD_IDX_ALT] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_ALT); - client->modifier_indices[MOD_IDX_NUM] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_NUM); - client->modifier_indices[MOD_IDX_MOD3] = xkb_keymap_mod_get_index(client->keymap, "Mod3"); - client->modifier_indices[MOD_IDX_LOGO] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_LOGO); - client->modifier_indices[MOD_IDX_ALTGR] = xkb_keymap_mod_get_index(client->keymap, "Mod5"); - client->modifier_indices[MOD_IDX_NUMLK] = xkb_keymap_mod_get_index(client->keymap, "NumLock"); - client->modifier_indices[MOD_IDX_ALSO_ALT] = xkb_keymap_mod_get_index(client->keymap, "Alt"); - client->modifier_indices[MOD_IDX_LVL3] = xkb_keymap_mod_get_index(client->keymap, "LevelThree"); - client->modifier_indices[MOD_IDX_LALT] = xkb_keymap_mod_get_index(client->keymap, "LAlt"); - client->modifier_indices[MOD_IDX_RALT] = xkb_keymap_mod_get_index(client->keymap, "RAlt"); - client->modifier_indices[MOD_IDX_RCONTROL] = xkb_keymap_mod_get_index(client->keymap, "RControl"); - client->modifier_indices[MOD_IDX_LCONTROL] = xkb_keymap_mod_get_index(client->keymap, "LControl"); - client->modifier_indices[MOD_IDX_SCROLLLK] = xkb_keymap_mod_get_index(client->keymap, "ScrollLock"); - client->modifier_indices[MOD_IDX_LVL5] = xkb_keymap_mod_get_index(client->keymap, "LevelFive"); - client->modifier_indices[MOD_IDX_ALSO_ALTGR] = xkb_keymap_mod_get_index(client->keymap, "AltGr"); - client->modifier_indices[MOD_IDX_META] = xkb_keymap_mod_get_index(client->keymap, "Meta"); - client->modifier_indices[MOD_IDX_SUPER] = xkb_keymap_mod_get_index(client->keymap, "Super"); - client->modifier_indices[MOD_IDX_HYPER] = xkb_keymap_mod_get_index(client->keymap, "Hyper"); - - /* - for (xkb_mod_index_t i = 0; - i < xkb_keymap_num_mods(client->keymap); - i++) { - g_log("squeek", G_LOG_LEVEL_DEBUG, "%s", xkb_keymap_mod_get_name(client->keymap, i)); - }*/ -} - -static void -send_fake_key (SeatEmitter *emitter, - LevelKeyboard *keyboard, - guint keycode, - gboolean pressed, - uint32_t timestamp) -{ - zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, 0); - send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp); - zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, 0); -} - -void -emit_key_activated (EekboardContextService *manager, - LevelKeyboard *keyboard, - guint keycode, - gboolean pressed, - uint32_t timestamp) -{ - /* FIXME: figure out how to deal with Client after key presses go through - if (g_strcmp0 (eek_symbol_get_name (symbol), "cycle-keyboard") == 0) { - client->keyboards_head = g_slist_next (client->keyboards_head); - if (client->keyboards_head == NULL) - client->keyboards_head = client->keyboards; - eekboard_context_set_keyboard (client->context, - GPOINTER_TO_UINT(client->keyboards_head->data), - NULL); - return; - } - - if (g_strcmp0 (eek_symbol_get_name (symbol), "preferences") == 0) { - gchar *argv[2]; - GError *error; - - argv[0] = g_build_filename (LIBEXECDIR, "eekboard-setup", NULL); - argv[1] = NULL; - - error = NULL; - if (!g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error)) { - g_warning ("can't spawn %s: %s", argv[0], error->message); - g_error_free (error); - } - g_free (argv[0]); - return; - } -*/ - SeatEmitter emitter = {0}; - emitter.virtual_keyboard = manager->virtual_keyboard; - update_modifier_info (&emitter); - send_fake_key (&emitter, keyboard, keycode, pressed, timestamp); -} diff --git a/eekboard/key-emitter.h b/eekboard/key-emitter.h deleted file mode 100644 index 337e925c..00000000 --- a/eekboard/key-emitter.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef KEYEMITTER_H -#define KEYEMITTER_H - -#include -#include - -#include "eek/eek.h" - -#include "virtual-keyboard-unstable-v1-client-protocol.h" - -/// Indices obtained by xkb_keymap_mod_get_name -enum mod_indices { - MOD_IDX_SHIFT, - MOD_IDX_CAPS, - MOD_IDX_CTRL, - MOD_IDX_ALT, - MOD_IDX_NUM, - MOD_IDX_MOD3, - MOD_IDX_LOGO, - MOD_IDX_ALTGR, - MOD_IDX_NUMLK, // Caution, not sure which is the right one - MOD_IDX_ALSO_ALT, // Not sure why, alt emits the first alt on my setup - MOD_IDX_LVL3, - - // Not sure if the next 4 are used at all - MOD_IDX_LALT, - MOD_IDX_RALT, - MOD_IDX_RCONTROL, - MOD_IDX_LCONTROL, - - MOD_IDX_SCROLLLK, - MOD_IDX_LVL5, - MOD_IDX_ALSO_ALTGR, // Not used on my layout - MOD_IDX_META, - MOD_IDX_SUPER, - MOD_IDX_HYPER, - - MOD_IDX_LAST, -}; - -void -emit_key_activated (EekboardContextService *manager, LevelKeyboard *keyboard, - guint keycode, - gboolean pressed, uint32_t timestamp); -#endif // KEYEMITTER_H diff --git a/src/dbus.c b/src/dbus.c new file mode 100644 index 00000000..046b6bd8 --- /dev/null +++ b/src/dbus.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include "dbus.h" + +#include +#include + +void +dbus_handler_destroy(DBusHandler *service) +{ + g_free (service->object_path); + + if (service->connection) { + if (service->registration_id > 0) { + g_dbus_connection_unregister_object (service->connection, + service->registration_id); + service->registration_id = 0; + } + + g_object_unref (service->connection); + service->connection = NULL; + } + + if (service->introspection_data) { + g_dbus_node_info_unref (service->introspection_data); + service->introspection_data = NULL; + } + + if (service->context) { + g_signal_handlers_disconnect_by_data (service->context, service); + service->context = NULL; + } + + free(service); +} + +static gboolean +handle_set_visible(SmPuriOSK0 *object, GDBusMethodInvocation *invocation, + gboolean arg_visible, gpointer user_data) { + DBusHandler *service = user_data; + + if (service->context) { + if (arg_visible) { + server_context_service_show_keyboard (service->context); + } else { + server_context_service_hide_keyboard (service->context); + } + } + sm_puri_osk0_complete_set_visible(object, invocation); + return TRUE; +} + +static void on_visible(DBusHandler *service, + GParamSpec *pspec, + ServerContextService *context) +{ + (void)pspec; + gboolean visible; + + g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (context)); + + g_object_get (context, "visible", &visible, NULL); + + sm_puri_osk0_set_visible(service->dbus_interface, visible); +} + +DBusHandler * +dbus_handler_new (GDBusConnection *connection, + const gchar *object_path) +{ + DBusHandler *self = calloc(1, sizeof(DBusHandler)); + self->object_path = g_strdup(object_path); + self->connection = connection; + + self->dbus_interface = sm_puri_osk0_skeleton_new(); + g_signal_connect(self->dbus_interface, "handle-set-visible", + G_CALLBACK(handle_set_visible), self); + + if (self->connection && self->object_path) { + GError *error = NULL; + + if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(self->dbus_interface), + self->connection, + self->object_path, + &error)) { + g_warning("Error registering dbus object: %s\n", error->message); + g_clear_error(&error); + // TODO: return an error + } + } + return self; +} + +void +dbus_handler_set_ui_context(DBusHandler *service, + ServerContextService *context) +{ + g_return_if_fail (!service->context); + + service->context = context; + + g_signal_connect_swapped (service->context, + "notify::visible", + G_CALLBACK(on_visible), + service); +} diff --git a/src/dbus.h b/src/dbus.h new file mode 100644 index 00000000..f719e274 --- /dev/null +++ b/src/dbus.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010-2011 Daiki Ueno + * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2019-2020 Purism, SPC + * + * 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 DBUS_H_ +#define DBUS_H_ 1 + +#include "server-context-service.h" + +#include "sm.puri.OSK0.h" + +G_BEGIN_DECLS + +#define DBUS_SERVICE_PATH "/sm/puri/OSK0" +#define DBUS_SERVICE_INTERFACE "sm.puri.OSK0" + +typedef struct _DBusHandler +{ + GDBusConnection *connection; + SmPuriOSK0 *dbus_interface; + GDBusNodeInfo *introspection_data; + guint registration_id; + char *object_path; + + ServerContextService *context; // unowned reference +} DBusHandler; + +DBusHandler * dbus_handler_new (GDBusConnection *connection, + const gchar *object_path); +void dbus_handler_set_ui_context(DBusHandler *service, + ServerContextService *context); +void dbus_handler_destroy(DBusHandler*); +G_END_DECLS +#endif /* DBUS_H_ */ diff --git a/src/imservice.c b/src/imservice.c index efa6208a..595a3546 100644 --- a/src/imservice.c +++ b/src/imservice.c @@ -2,9 +2,6 @@ #include -#include "eekboard/eekboard-context-service.h" - - static const struct zwp_input_method_v2_listener input_method_listener = { .activate = imservice_handle_input_method_activate, .deactivate = imservice_handle_input_method_deactivate, @@ -15,11 +12,11 @@ static const struct zwp_input_method_v2_listener input_method_listener = { .unavailable = imservice_handle_unavailable, }; -struct imservice* get_imservice(EekboardContextService *context, - struct zwp_input_method_manager_v2 *manager, - struct wl_seat *seat) { +struct imservice* get_imservice(struct zwp_input_method_manager_v2 *manager, + struct wl_seat *seat, + EekboardContextService *state) { struct zwp_input_method_v2 *im = zwp_input_method_manager_v2_get_input_method(manager, seat); - struct imservice *imservice = imservice_new(im, context); + struct imservice *imservice = imservice_new(im, state); /* Add a listener, passing the imservice instance to make it available to callbacks. */ @@ -28,14 +25,6 @@ struct imservice* get_imservice(EekboardContextService *context, return imservice; } -void imservice_make_visible(EekboardContextService *context) { - eekboard_context_service_show_keyboard (context); -} - -void imservice_try_hide(EekboardContextService *context) { - eekboard_context_service_hide_keyboard (context); -} - /// Declared explicitly because _destroy is inline, /// making it unavailable in Rust void imservice_destroy_im(struct zwp_input_method_v2 *im) { diff --git a/src/imservice.h b/src/imservice.h index 71c59275..5b879bfb 100644 --- a/src/imservice.h +++ b/src/imservice.h @@ -3,16 +3,18 @@ #include "input-method-unstable-v2-client-protocol.h" #include "eek/eek-types.h" +#include "src/server-context-service.h" struct imservice; -struct imservice* get_imservice(EekboardContextService *context, - struct zwp_input_method_manager_v2 *manager, - struct wl_seat *seat); +struct imservice* get_imservice(struct zwp_input_method_manager_v2 *manager, + struct wl_seat *seat, + EekboardContextService *state); // Defined in Rust -struct imservice* imservice_new(struct zwp_input_method_v2 *im, - EekboardContextService *context); +struct imservice* imservice_new(struct zwp_input_method_v2 *im, EekboardContextService *state); +void imservice_set_ui(struct imservice *self, ServerContextService *ui_context); + void imservice_handle_input_method_activate(void *data, struct zwp_input_method_v2 *input_method); void imservice_handle_input_method_deactivate(void *data, struct zwp_input_method_v2 *input_method); void imservice_handle_surrounding_text(void *data, struct zwp_input_method_v2 *input_method, diff --git a/src/imservice.rs b/src/imservice.rs index d3e4c5d0..cc30b01a 100644 --- a/src/imservice.rs +++ b/src/imservice.rs @@ -21,27 +21,35 @@ pub mod c { #[repr(transparent)] pub struct InputMethod(*const c_void); - /// EekboardContextService* + /// ServerContextService* #[repr(transparent)] pub struct UIManager(*const c_void); - + + /// EekboardContextService* + #[repr(transparent)] + pub struct StateManager(*const c_void); + #[no_mangle] extern "C" { fn imservice_destroy_im(im: *mut c::InputMethod); - fn eekboard_context_service_set_hint_purpose(imservice: *const UIManager, hint: u32, purpose: u32); - fn eekboard_context_service_show_keyboard(imservice: *const UIManager); - fn eekboard_context_service_hide_keyboard(imservice: *const UIManager); + fn eekboard_context_service_set_hint_purpose(state: *const StateManager, hint: u32, purpose: u32); + fn server_context_service_show_keyboard(imservice: *const UIManager); + fn server_context_service_hide_keyboard(imservice: *const UIManager); } // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers #[no_mangle] - pub unsafe extern "C" - fn imservice_new(im: *const InputMethod, ui_manager: *const UIManager) -> *mut IMService { + pub extern "C" + fn imservice_new( + im: *const InputMethod, + state_manager: *const StateManager + ) -> *mut IMService { Box::::into_raw(Box::new( IMService { im: im, - ui_manager: ui_manager, + state_manager: state_manager, + ui_manager: None, pending: IMProtocolState::default(), current: IMProtocolState::default(), preedit_string: String::new(), @@ -49,6 +57,20 @@ pub mod c { } )) } + + #[no_mangle] + pub extern "C" + fn imservice_set_ui(imservice: *mut IMService, ui_manager: *const UIManager) { + if imservice.is_null() { + panic!("Null imservice pointer"); + } + let imservice: &mut IMService = unsafe { &mut *imservice }; + imservice.ui_manager = if ui_manager.is_null() { + None + } else { + Some(ui_manager) + }; + } // TODO: is unsafe needed here? #[no_mangle] @@ -148,15 +170,20 @@ pub mod c { active: imservice.current.active, ..IMProtocolState::default() }; + if active_changed { if imservice.current.active { - eekboard_context_service_show_keyboard(imservice.ui_manager); + if let Some(ui) = imservice.ui_manager { + server_context_service_show_keyboard(ui); + } eekboard_context_service_set_hint_purpose( - imservice.ui_manager, + imservice.state_manager, imservice.current.content_hint.bits(), imservice.current.content_purpose.clone() as u32); } else { - eekboard_context_service_hide_keyboard(imservice.ui_manager); + if let Some(ui) = imservice.ui_manager { + server_context_service_hide_keyboard(ui); + } } } } @@ -173,7 +200,9 @@ pub mod c { // the keyboard is already decommissioned imservice.current.active = false; - eekboard_context_service_hide_keyboard(imservice.ui_manager); + if let Some(ui) = imservice.ui_manager { + server_context_service_hide_keyboard(ui); + } } // FIXME: destroy and deallocate @@ -320,7 +349,9 @@ pub struct IMService { /// Owned reference (still created and destroyed in C) pub im: *const c::InputMethod, /// Unowned reference. Be careful, it's shared with C at large - ui_manager: *const c::UIManager, + ui_manager: Option<*const c::UIManager>, + /// Unowned reference. Be careful, it's shared with C at large + state_manager: *const c::StateManager, pending: IMProtocolState, current: IMProtocolState, // turn current into an idiomatic representation? diff --git a/src/layout.rs b/src/layout.rs index 76f830c1..c01226d5 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -332,11 +332,12 @@ pub mod c { .map(|place| place.button.state.clone()) }; - if let Some(mut state) = state { - layout.press_key( + if let Some(state) = state { + seat::handle_press_key( + layout, &VirtualKeyboard(virtual_keyboard), - &mut state, Timestamp(time), + &state, ); // maybe TODO: draw on the display buffer here drawing::queue_redraw(ui_keyboard); @@ -379,7 +380,7 @@ pub mod c { )}) }; - if let Some((mut state, _button, _view_position)) = button_info { + if let Some((state, _button, _view_position)) = button_info { let mut found = false; for wrapped_key in pressed { let key: &Rc> = wrapped_key.borrow(); @@ -397,7 +398,12 @@ pub mod c { } } if !found { - layout.press_key(&virtual_keyboard, &mut state, time); + seat::handle_press_key( + layout, + &virtual_keyboard, + time, + &state, + ); // maybe TODO: draw on the display buffer here } } else { @@ -653,24 +659,6 @@ impl Layout { } } - fn press_key( - &mut self, - virtual_keyboard: &VirtualKeyboard, - rckey: &mut Rc>, - time: Timestamp, - ) { - if !self.pressed_keys.insert(::util::Pointer(rckey.clone())) { - eprintln!("Warning: key {:?} was already pressed", rckey); - } - let mut key = rckey.borrow_mut(); - virtual_keyboard.switch( - &key.keycodes, - PressType::Pressed, - time, - ); - key.pressed = PressType::Pressed; - } - /// Calculates size without margins fn calculate_inner_size(&self) -> Size { Size { @@ -864,6 +852,24 @@ mod seat { } } + pub fn handle_press_key( + layout: &mut Layout, + virtual_keyboard: &VirtualKeyboard, + time: Timestamp, + rckey: &Rc>, + ) { + if !layout.pressed_keys.insert(::util::Pointer(rckey.clone())) { + eprintln!("Warning: key {:?} was already pressed", rckey); + } + let mut key = rckey.borrow_mut(); + virtual_keyboard.switch( + &key.keycodes, + PressType::Pressed, + time, + ); + key.pressed = PressType::Pressed; + } + pub fn handle_release_key( layout: &mut Layout, virtual_keyboard: &VirtualKeyboard, diff --git a/src/meson.build b/src/meson.build index ef317d37..e43974a6 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,6 +12,7 @@ config_h = configure_file( sources = [ config_h, + 'dbus.c', 'imservice.c', 'server-context-service.c', 'wayland.c', @@ -24,9 +25,7 @@ sources = [ '../eek/eek-xml-layout.c', '../eek/layersurface.c', dbus_src, - '../eekboard/key-emitter.c', '../eekboard/eekboard-context-service.c', - '../eekboard/eekboard-service.c', # '../eekboard/eekboard-xklutil.c', squeekboard_resources, wl_proto_sources, diff --git a/src/server-context-service.c b/src/server-context-service.c index 137ae0cf..ce2052da 100644 --- a/src/server-context-service.c +++ b/src/server-context-service.c @@ -23,22 +23,26 @@ #include "eek/eek.h" #include "eek/eek-gtk-keyboard.h" #include "eek/layersurface.h" +#include "eekboard/eekboard-context-service.h" #include "wayland.h" - #include "server-context-service.h" enum { PROP_0, PROP_SIZE_CONSTRAINT_LANDSCAPE, PROP_SIZE_CONSTRAINT_PORTRAIT, + PROP_VISIBLE, PROP_LAST }; typedef struct _ServerContextServiceClass ServerContextServiceClass; struct _ServerContextService { - EekboardContextService parent; + GObject parent; + EekboardContextService *state; // unowned + + gboolean visible; PhoshLayerSurface *window; GtkWidget *widget; guint hiding; @@ -50,10 +54,10 @@ struct _ServerContextService { }; struct _ServerContextServiceClass { - EekboardContextServiceClass parent_class; + GObjectClass parent_class; }; -G_DEFINE_TYPE (ServerContextService, server_context_service, EEKBOARD_TYPE_CONTEXT_SERVICE); +G_DEFINE_TYPE(ServerContextService, server_context_service, G_TYPE_OBJECT); static void on_destroy (GtkWidget *widget, gpointer user_data) @@ -65,7 +69,7 @@ on_destroy (GtkWidget *widget, gpointer user_data) context->window = NULL; context->widget = NULL; - eekboard_context_service_destroy (EEKBOARD_CONTEXT_SERVICE (context)); + //eekboard_context_service_destroy (EEKBOARD_CONTEXT_SERVICE (context)); } static void @@ -76,17 +80,6 @@ on_notify_keyboard (GObject *object, GParamSpec *spec, ServerContextService *context) { - const LevelKeyboard *keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context)); - - if (!keyboard) - g_error("Programmer error: keyboard layout was unset!"); - - // The keymap will get set even if the window is hidden. - // It's not perfect, - // but simpler than adding a check in the window showing procedure - eekboard_context_service_set_keymap(EEKBOARD_CONTEXT_SERVICE(context), - keyboard); - /* Recreate the keyboard widget to keep in sync with the keymap. */ if (context->window) make_widget(context); @@ -95,8 +88,8 @@ on_notify_keyboard (GObject *object, g_object_get (context, "visible", &visible, NULL); if (visible) { - eekboard_context_service_hide_keyboard(EEKBOARD_CONTEXT_SERVICE(context)); - eekboard_context_service_show_keyboard(EEKBOARD_CONTEXT_SERVICE(context)); + server_context_service_hide_keyboard(context); + server_context_service_show_keyboard(context); } } @@ -229,7 +222,7 @@ make_widget (ServerContextService *context) context->widget = NULL; } - LevelKeyboard *keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context)); + LevelKeyboard *keyboard = eekboard_context_service_get_keyboard (context->state); context->widget = eek_gtk_keyboard_new (keyboard); @@ -238,26 +231,6 @@ make_widget (ServerContextService *context) gtk_widget_show (context->widget); } -static void -server_context_service_real_show_keyboard (EekboardContextService *_context) -{ - ServerContextService *context = SERVER_CONTEXT_SERVICE(_context); - - if (context->hiding) { - g_source_remove (context->hiding); - context->hiding = 0; - } - - if (!context->window) - make_window (context); - if (!context->widget) - make_widget (context); - - EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)-> - show_keyboard (_context); - gtk_widget_show (GTK_WIDGET(context->window)); -} - static gboolean on_hide (ServerContextService *context) { @@ -268,20 +241,49 @@ on_hide (ServerContextService *context) } static void -server_context_service_real_hide_keyboard (EekboardContextService *_context) +server_context_service_real_show_keyboard (ServerContextService *context) { - ServerContextService *context = SERVER_CONTEXT_SERVICE(_context); + if (context->hiding) { + g_source_remove (context->hiding); + context->hiding = 0; + } - if (!context->hiding) - context->hiding = g_timeout_add (200, (GSourceFunc) on_hide, context); + if (!context->window) + make_window (context); + if (!context->widget) + make_widget (context); - EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)-> - hide_keyboard (_context); + context->visible = TRUE; + gtk_widget_show (GTK_WIDGET(context->window)); } static void -server_context_service_real_destroyed (EekboardContextService *_context) +server_context_service_real_hide_keyboard (ServerContextService *context) { + if (!context->hiding) + context->hiding = g_timeout_add (200, (GSourceFunc) on_hide, context); + + context->visible = FALSE; +} + +void +server_context_service_show_keyboard (ServerContextService *context) +{ + g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(context)); + + if (!context->visible) { + server_context_service_real_show_keyboard (context); + } +} + +void +server_context_service_hide_keyboard (ServerContextService *context) +{ + g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(context)); + + if (context->visible) { + server_context_service_real_hide_keyboard (context); + } } static void @@ -306,6 +308,9 @@ server_context_service_set_property (GObject *object, &context->size_constraint_portrait[0], &context->size_constraint_portrait[1]); break; + case PROP_VISIBLE: + context->visible = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -313,6 +318,23 @@ server_context_service_set_property (GObject *object, } } +static void +server_context_service_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ServerContextService *context = SERVER_CONTEXT_SERVICE(object); + switch (prop_id) { + case PROP_VISIBLE: + g_value_set_boolean (value, context->visible); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void server_context_service_dispose (GObject *object) { @@ -327,15 +349,11 @@ server_context_service_dispose (GObject *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->destroyed = server_context_service_real_destroyed; - gobject_class->set_property = server_context_service_set_property; + gobject_class->get_property = server_context_service_get_property; gobject_class->dispose = server_context_service_dispose; pspec = g_param_spec_variant ("size-constraint-landscape", @@ -357,24 +375,38 @@ server_context_service_class_init (ServerContextServiceClass *klass) g_object_class_install_property (gobject_class, PROP_SIZE_CONSTRAINT_PORTRAIT, pspec); + + /** + * Flag to indicate if keyboard is visible or not. + */ + pspec = g_param_spec_boolean ("visible", + "Visible", + "Visible", + FALSE, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_VISIBLE, + pspec); } static void -server_context_service_init (ServerContextService *context) +server_context_service_init (ServerContextService *state) { + (void)state; +} + +ServerContextService * +server_context_service_new (EekboardContextService *state) { - g_signal_connect (context, + ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL); + ui->state = state; + g_signal_connect (state, "notify::keyboard", G_CALLBACK(on_notify_keyboard), - context); + ui); + return ui; } -EekboardContextService * -server_context_service_new () +enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *service) { - return EEKBOARD_CONTEXT_SERVICE(g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL)); -} - -enum squeek_arrangement_kind server_context_service_get_layout_type(EekboardContextService *service) -{ - return SERVER_CONTEXT_SERVICE(service)->last_type; + return service->last_type; } diff --git a/src/server-context-service.h b/src/server-context-service.h index 2929640a..c316f6b7 100644 --- a/src/server-context-service.h +++ b/src/server-context-service.h @@ -18,7 +18,6 @@ #ifndef SERVER_CONTEXT_SERVICE_H #define SERVER_CONTEXT_SERVICE_H 1 -#include "eekboard/eekboard-service.h" #include "src/layout.h" G_BEGIN_DECLS @@ -30,12 +29,16 @@ G_BEGIN_DECLS #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)) -/** Manages the liecycle of the window displaying layouts. */ +/** Manages the lifecycle of the window displaying layouts. */ typedef struct _ServerContextService ServerContextService; -EekboardContextService *server_context_service_new (); -enum squeek_arrangement_kind server_context_service_get_layout_type(EekboardContextService*); +GType server_context_service_get_type + (void) G_GNUC_CONST; +ServerContextService *server_context_service_new(EekboardContextService *state); +enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *); +void server_context_service_show_keyboard (ServerContextService *context); +void server_context_service_hide_keyboard (ServerContextService *context); G_END_DECLS #endif /* SERVER_CONTEXT_SERVICE_H */ diff --git a/src/server-main.c b/src/server-main.c index 35377e17..0fe5299f 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -25,8 +25,9 @@ #include "config.h" -#include "eekboard/eekboard-service.h" #include "eek/eek.h" +#include "eekboard/eekboard-context-service.h" +#include "dbus.h" #include "imservice.h" #include "outputs.h" #include "server-context-service.h" @@ -38,7 +39,9 @@ /// Global application state struct squeekboard { struct squeek_wayland wayland; - EekboardContextService *context; + DBusHandler *dbus_handler; + EekboardContextService *settings_context; + ServerContextService *ui_context; struct imservice *imservice; }; @@ -72,25 +75,6 @@ on_name_lost (GDBusConnection *connection, exit (1); } -static void -on_destroyed (EekboardService *service, - gpointer user_data) -{ - (void)service; - GMainLoop *loop = user_data; - - g_main_loop_quit (loop); -} - -static EekboardContextService *create_context() { - EekboardContextService *context = server_context_service_new (); - g_object_set_data_full (G_OBJECT(context), - "owner", g_strdup ("sender"), - (GDestroyNotify)g_free); - eekboard_context_service_enable (context); - return context; -} - // Wayland static void @@ -211,7 +195,7 @@ main (int argc, char **argv) exit(1); } - instance.context = create_context(); + instance.settings_context = eekboard_context_service_new(); // set up dbus @@ -259,17 +243,16 @@ main (int argc, char **argv) break; } - EekboardService *service = eekboard_service_new (connection, EEKBOARD_SERVICE_PATH); + DBusHandler *service = dbus_handler_new(connection, DBUS_SERVICE_PATH); if (service == NULL) { g_printerr ("Can't create dbus server\n"); exit (1); - } else { - eekboard_service_set_context(service, instance.context); } + instance.dbus_handler = service; guint owner_id = g_bus_own_name_on_connection (connection, - EEKBOARD_SERVICE_INTERFACE, + DBUS_SERVICE_INTERFACE, G_BUS_NAME_OWNER_FLAGS_NONE, on_name_acquired, on_name_lost, @@ -282,9 +265,9 @@ main (int argc, char **argv) struct imservice *imservice = NULL; if (instance.wayland.input_method_manager) { - imservice = get_imservice(instance.context, - instance.wayland.input_method_manager, - instance.wayland.seat); + imservice = get_imservice(instance.wayland.input_method_manager, + instance.wayland.seat, + instance.settings_context); if (imservice) { instance.imservice = imservice; } else { @@ -292,12 +275,23 @@ main (int argc, char **argv) } } + ServerContextService *ui_context = server_context_service_new(instance.settings_context); + if (!ui_context) { + g_error("Could not initialize GUI"); + exit(1); + } + instance.ui_context = ui_context; + if (instance.imservice) { + imservice_set_ui(instance.imservice, instance.ui_context); + } + if (instance.dbus_handler) { + dbus_handler_set_ui_context(instance.dbus_handler, instance.ui_context); + } + session_register(); GMainLoop *loop = g_main_loop_new (NULL, FALSE); - g_signal_connect (service, "destroyed", G_CALLBACK(on_destroyed), loop); - g_main_loop_run (loop); g_bus_unown_name (owner_id);