diff --git a/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c index a8922b8f..94a6ae4c 100644 --- a/eekboard/eekboard-context-service.c +++ b/eekboard/eekboard-context-service.c @@ -69,6 +69,10 @@ struct _EekboardContextServicePrivate { 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); @@ -218,13 +222,13 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ LevelKeyboard *previous_keyboard = context->priv->keyboard; context->priv->keyboard = keyboard; - g_object_notify (G_OBJECT(context), "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) if (previous_keyboard) { level_keyboard_free(previous_keyboard); @@ -232,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 @@ -384,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 9333586e..dab830ce 100644 --- a/eekboard/eekboard-context-service.h +++ b/eekboard/eekboard-context-service.h @@ -77,8 +77,6 @@ struct _EekboardContextServiceClass { const gchar *keyboard_type); /* signals */ - void (*enabled) (EekboardContextService *self); - void (*disabled) (EekboardContextService *self); void (*destroyed) (EekboardContextService *self); /*< private >*/ @@ -86,8 +84,10 @@ struct _EekboardContextServiceClass { gpointer pdummy[24]; }; +EekboardContextService *eekboard_context_service_new(); GType eekboard_context_service_get_type (void) G_GNUC_CONST; +EekboardContextService *eekboard_context_service_new(void); void eekboard_context_service_destroy (EekboardContextService *context); LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context); diff --git a/src/dbus.c b/src/dbus.c index 29783090..046b6bd8 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -110,7 +110,7 @@ dbus_handler_new (GDBusConnection *connection, } void -dbus_handler_set_context(DBusHandler *service, +dbus_handler_set_ui_context(DBusHandler *service, ServerContextService *context) { g_return_if_fail (!service->context); diff --git a/src/dbus.h b/src/dbus.h index c77ad850..f719e274 100644 --- a/src/dbus.h +++ b/src/dbus.h @@ -41,7 +41,7 @@ typedef struct _DBusHandler DBusHandler * dbus_handler_new (GDBusConnection *connection, const gchar *object_path); -void dbus_handler_set_context(DBusHandler *service, +void dbus_handler_set_ui_context(DBusHandler *service, ServerContextService *context); void dbus_handler_destroy(DBusHandler*); G_END_DECLS diff --git a/src/imservice.c b/src/imservice.c index d33f11db..595a3546 100644 --- a/src/imservice.c +++ b/src/imservice.c @@ -12,11 +12,11 @@ static const struct zwp_input_method_v2_listener input_method_listener = { .unavailable = imservice_handle_unavailable, }; -struct imservice* get_imservice(ServerContextService *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. */ diff --git a/src/imservice.h b/src/imservice.h index 0f7b1c75..5b879bfb 100644 --- a/src/imservice.h +++ b/src/imservice.h @@ -7,13 +7,14 @@ struct imservice; -struct imservice* get_imservice(ServerContextService *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, - ServerContextService *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 df4019b7..cc30b01a 100644 --- a/src/imservice.rs +++ b/src/imservice.rs @@ -21,14 +21,18 @@ 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_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); } @@ -36,12 +40,16 @@ pub mod c { // 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 { - server_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 { - server_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; - server_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/server-context-service.c b/src/server-context-service.c index 1cacb37d..ce2052da 100644 --- a/src/server-context-service.c +++ b/src/server-context-service.c @@ -38,7 +38,9 @@ enum { typedef struct _ServerContextServiceClass ServerContextServiceClass; struct _ServerContextService { - EekboardContextService parent; + GObject parent; + + EekboardContextService *state; // unowned gboolean visible; PhoshLayerSurface *window; @@ -52,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) @@ -67,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 @@ -220,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); @@ -284,11 +286,6 @@ server_context_service_hide_keyboard (ServerContextService *context) } } -static void -server_context_service_real_destroyed (EekboardContextService *_context) -{ -} - static void server_context_service_set_property (GObject *object, guint prop_id, @@ -352,12 +349,9 @@ 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->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; @@ -396,21 +390,23 @@ server_context_service_class_init (ServerContextServiceClass *klass) } static void -server_context_service_init (ServerContextService *context) -{ - g_signal_connect (context, - "notify::keyboard", - G_CALLBACK(on_notify_keyboard), - context); +server_context_service_init (ServerContextService *state) { + (void)state; } ServerContextService * -server_context_service_new () +server_context_service_new (EekboardContextService *state) { - return g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL); + ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL); + ui->state = state; + g_signal_connect (state, + "notify::keyboard", + G_CALLBACK(on_notify_keyboard), + ui); + return ui; } -enum squeek_arrangement_kind server_context_service_get_layout_type(EekboardContextService *service) +enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *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 c7f7412a..c316f6b7 100644 --- a/src/server-context-service.h +++ b/src/server-context-service.h @@ -29,14 +29,14 @@ 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; GType server_context_service_get_type (void) G_GNUC_CONST; -ServerContextService *server_context_service_new(); -enum squeek_arrangement_kind server_context_service_get_layout_type(EekboardContextService*); +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 diff --git a/src/server-main.c b/src/server-main.c index fa919f02..b9592eaa 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -39,7 +39,9 @@ /// Global application state struct squeekboard { struct squeek_wayland wayland; - ServerContextService *context; + DBusHandler *dbus_handler; + EekboardContextService *settings_context; + ServerContextService *ui_context; struct imservice *imservice; }; @@ -71,14 +73,6 @@ on_name_lost (GDBusConnection *connection, exit (1); } -static ServerContextService *create_context() { - ServerContextService *context = server_context_service_new (); - g_object_set_data_full (G_OBJECT(context), - "owner", g_strdup ("sender"), - (GDestroyNotify)g_free); - return context; -} - // Wayland static void @@ -199,7 +193,7 @@ main (int argc, char **argv) exit(1); } - instance.context = create_context(); + instance.settings_context = eekboard_context_service_new(); // set up dbus @@ -252,9 +246,8 @@ main (int argc, char **argv) if (service == NULL) { g_printerr ("Can't create dbus server\n"); exit (1); - } else { - dbus_handler_set_context(service, instance.context); } + instance.dbus_handler = service; guint owner_id = g_bus_own_name_on_connection (connection, DBUS_SERVICE_INTERFACE, @@ -270,9 +263,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 { @@ -280,6 +273,19 @@ 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);