diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index 51ded953..bd075647 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -47,7 +47,9 @@ typedef struct _EekGtkKeyboardPrivate EekRenderer *renderer; EekboardContextService *eekboard_context; // unowned reference struct submission *submission; // unowned reference - LevelKeyboard *keyboard; // unowned reference; it's kept in server-context (FIXME) + + struct squeek_layout_state *layout; + LevelKeyboard *keyboard; // unowned reference; it's kept in server-context GdkEventSequence *sequence; // unowned reference } EekGtkKeyboardPrivate; @@ -78,10 +80,16 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, GtkAllocation allocation; gtk_widget_get_allocation (self, &allocation); + if (!priv->keyboard) { + return FALSE; + } + if (!priv->renderer) { PangoContext *pcontext = gtk_widget_get_pango_context (self); - priv->renderer = eek_renderer_new (priv->keyboard, pcontext); + priv->renderer = eek_renderer_new ( + priv->keyboard, + pcontext); eek_renderer_set_allocation_size (priv->renderer, allocation.width, @@ -94,6 +102,14 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, return FALSE; } +static enum squeek_arrangement_kind get_type(uint32_t width, uint32_t height) { + (void)height; + if (width < 540) { + return ARRANGEMENT_KIND_BASE; + } + return ARRANGEMENT_KIND_WIDE; +} + static void eek_gtk_keyboard_real_size_allocate (GtkWidget *self, GtkAllocation *allocation) @@ -101,6 +117,16 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self, EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); + // check if the change would switch types + enum squeek_arrangement_kind new_type = get_type( + (uint32_t)(allocation->width - allocation->x), + (uint32_t)(allocation->height - allocation->y)); + if (priv->layout->arrangement != new_type) { + priv->layout->arrangement = new_type; + + eekboard_context_service_use_layout(priv->eekboard_context, priv->layout); + } + if (priv->renderer) eek_renderer_set_allocation_size (priv->renderer, allocation->width, @@ -114,7 +140,9 @@ static void depress(EekGtkKeyboard *self, gdouble x, gdouble y, guint32 time) { EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - + if (!priv->keyboard) { + return; + } squeek_layout_depress(priv->keyboard->layout, priv->submission, x, y, eek_renderer_get_transformation(priv->renderer), time, self); @@ -124,7 +152,10 @@ static void drag(EekGtkKeyboard *self, gdouble x, gdouble y, guint32 time) { EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - squeek_layout_drag(priv->keyboard->layout, + if (!priv->keyboard) { + return; + } + squeek_layout_drag(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout, priv->submission, x, y, eek_renderer_get_transformation(priv->renderer), time, priv->eekboard_context, self); @@ -133,8 +164,10 @@ static void drag(EekGtkKeyboard *self, static void release(EekGtkKeyboard *self, guint32 time) { EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - - squeek_layout_release(priv->keyboard->layout, + if (!priv->keyboard) { + return; + } + squeek_layout_release(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout, priv->submission, eek_renderer_get_transformation(priv->renderer), time, priv->eekboard_context, self); @@ -301,21 +334,46 @@ eek_gtk_keyboard_init (EekGtkKeyboard *self) (void)self; } +static void +on_notify_keyboard (GObject *object, + GParamSpec *spec, + EekGtkKeyboard *self) { + (void)spec; + EekGtkKeyboardPrivate *priv = (EekGtkKeyboardPrivate*)eek_gtk_keyboard_get_instance_private (self); + priv->keyboard = eekboard_context_service_get_keyboard(EEKBOARD_CONTEXT_SERVICE(object)); + if (priv->renderer) { + g_object_unref(priv->renderer); + } + priv->renderer = NULL; + gtk_widget_queue_draw(GTK_WIDGET(self)); +} + /** - * eek_gtk_keyboard_new: - * @keyboard: an #EekKeyboard - * * Create a new #GtkWidget displaying @keyboard. * Returns: a #GtkWidget */ GtkWidget * -eek_gtk_keyboard_new (LevelKeyboard *keyboard, EekboardContextService *eekservice, - struct submission *submission) +eek_gtk_keyboard_new (EekboardContextService *eekservice, + struct submission *submission, + struct squeek_layout_state *layout) { EekGtkKeyboard *ret = EEK_GTK_KEYBOARD(g_object_new (EEK_TYPE_GTK_KEYBOARD, NULL)); EekGtkKeyboardPrivate *priv = (EekGtkKeyboardPrivate*)eek_gtk_keyboard_get_instance_private (ret); - priv->keyboard = keyboard; priv->eekboard_context = eekservice; priv->submission = submission; + priv->layout = layout; + priv->renderer = NULL; + g_signal_connect (eekservice, + "notify::keyboard", + G_CALLBACK(on_notify_keyboard), + ret); + on_notify_keyboard(G_OBJECT(eekservice), NULL, ret); + /* TODO: this is how a compound keyboard + * made out of a layout and a suggestion bar could start. + * GtkBox *box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)); + GtkEntry *fill = GTK_ENTRY(gtk_entry_new()); + gtk_box_pack_start(box, GTK_WIDGET(fill), FALSE, FALSE, 0); + gtk_box_pack_start(box, GTK_WIDGET(ret), TRUE, TRUE, 0); + return GTK_WIDGET(box);*/ return GTK_WIDGET(ret); } diff --git a/eek/eek-gtk-keyboard.h b/eek/eek-gtk-keyboard.h index 95647220..ca127011 100644 --- a/eek/eek-gtk-keyboard.h +++ b/eek/eek-gtk-keyboard.h @@ -31,6 +31,7 @@ #include "eek/eek-types.h" struct submission; +struct squeek_layout_state; typedef struct _LevelKeyboard LevelKeyboard; // including causes weird bugs G_BEGIN_DECLS @@ -48,7 +49,7 @@ struct _EekGtkKeyboardClass }; GType eek_gtk_keyboard_get_type (void) G_GNUC_CONST; -GtkWidget *eek_gtk_keyboard_new (LevelKeyboard *keyboard, EekboardContextService *eekservice, struct submission *submission); +GtkWidget *eek_gtk_keyboard_new (EekboardContextService *eekservice, struct submission *submission, struct squeek_layout_state *layout); G_END_DECLS #endif /* EEK_GTK_KEYBOARD_H */ diff --git a/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c index cf5e7e4d..46ef548a 100644 --- a/eekboard/eekboard-context-service.c +++ b/eekboard/eekboard-context-service.c @@ -48,12 +48,7 @@ static guint signals[LAST_SIGNAL] = { 0, }; struct _EekboardContextServicePrivate { LevelKeyboard *keyboard; // currently used keyboard GHashTable *keyboard_hash; // a table of available keyboards, per layout - - char *overlay; - 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? @@ -120,39 +115,31 @@ settings_get_layout(GSettings *settings, char **type, char **layout) } void -eekboard_context_service_update_layout(EekboardContextService *context, enum squeek_arrangement_kind t) -{ - g_autofree gchar *keyboard_layout = NULL; - if (context->priv->overlay) { - keyboard_layout = g_strdup(context->priv->overlay); - } else { - g_autofree gchar *keyboard_type = NULL; - settings_get_layout(context->priv->settings, - &keyboard_type, &keyboard_layout); - } +eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *state) { + gchar *layout_name = state->overlay_name; - if (!keyboard_layout) { - keyboard_layout = g_strdup("us"); - } + if (layout_name == NULL) { + layout_name = state->layout_name; - EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); + switch (state->purpose) { + case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER: + case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE: + layout_name = "number"; + break; + case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL: + layout_name = "terminal"; + break; + default: + ; + } - switch (priv->purpose) { - case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER: - case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE: - g_free(keyboard_layout); - keyboard_layout = g_strdup("number"); - break; - case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL: - g_free(keyboard_layout); - keyboard_layout = g_strdup("terminal"); - break; - default: - ; + if (layout_name == NULL) { + layout_name = "us"; + } } // generic part follows - LevelKeyboard *keyboard = level_keyboard_new(keyboard_layout, t); + LevelKeyboard *keyboard = level_keyboard_new(layout_name, state->arrangement); // set as current LevelKeyboard *previous_keyboard = context->priv->keyboard; context->priv->keyboard = keyboard; @@ -162,6 +149,7 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ submission_set_keyboard(context->priv->submission, keyboard); } + // Update UI 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) @@ -170,13 +158,22 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ } } -static void update_layout_and_type(EekboardContextService *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); +static void eekboard_context_service_update_settings_layout(EekboardContextService *context) { + g_autofree gchar *keyboard_layout = NULL; + g_autofree gchar *keyboard_type = NULL; + settings_get_layout(context->priv->settings, + &keyboard_type, &keyboard_layout); + + if (g_strcmp0(context->layout->layout_name, keyboard_layout) != 0 || context->layout->overlay_name) { + g_free(context->layout->overlay_name); + context->layout->overlay_name = NULL; + if (keyboard_layout) { + g_free(context->layout->layout_name); + context->layout->layout_name = g_strdup(keyboard_layout); + } + // This must actually update the UI. + eekboard_context_service_use_layout(context, context->layout); } - eekboard_context_service_update_layout(context, layout_kind); } static gboolean @@ -187,17 +184,14 @@ settings_handle_layout_changed(GSettings *s, (void)keys; (void)n_keys; EekboardContextService *context = user_data; - g_free(context->priv->overlay); - context->priv->overlay = NULL; - update_layout_and_type(context); + eekboard_context_service_update_settings_layout(context); return TRUE; } static void eekboard_context_service_constructed (GObject *object) { - EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE (object); - update_layout_and_type(context); + (void)object; } static void @@ -260,8 +254,6 @@ eekboard_context_service_init (EekboardContextService *self) g_warning ("Could not connect to gsettings updates, layout" " changing unavailable"); } - - self->priv->overlay = NULL; } /** @@ -274,8 +266,6 @@ void eekboard_context_service_destroy (EekboardContextService *context) { g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context)); - - g_free(context->priv->overlay); g_signal_emit (context, signals[DESTROYED], 0); } @@ -295,29 +285,34 @@ eekboard_context_service_get_keyboard (EekboardContextService *context) void eekboard_context_service_set_hint_purpose(EekboardContextService *context, uint32_t hint, uint32_t purpose) { - EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context); - - if (priv->hint != hint || priv->purpose != purpose) { - priv->hint = hint; - priv->purpose = purpose; - update_layout_and_type(context); + if (context->layout->hint != hint || context->layout->purpose != purpose) { + context->layout->hint = hint; + context->layout->purpose = purpose; + eekboard_context_service_use_layout(context, context->layout); } } void eekboard_context_service_set_overlay(EekboardContextService *context, const char* name) { - context->priv->overlay = g_strdup(name); - update_layout_and_type(context); + if (g_strcmp0(context->layout->overlay_name, name)) { + g_free(context->layout->overlay_name); + context->layout->overlay_name = g_strdup(name); + eekboard_context_service_use_layout(context, context->layout); + } } const char* eekboard_context_service_get_overlay(EekboardContextService *context) { - return context->priv->overlay; + return context->layout->overlay_name; } -EekboardContextService *eekboard_context_service_new(void) +EekboardContextService *eekboard_context_service_new(struct squeek_layout_state *state) { - return g_object_new (EEKBOARD_TYPE_CONTEXT_SERVICE, NULL); + EekboardContextService *context = g_object_new (EEKBOARD_TYPE_CONTEXT_SERVICE, NULL); + context->layout = state; + eekboard_context_service_update_settings_layout(context); + eekboard_context_service_use_layout(context, context->layout); + return context; } void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission) { diff --git a/eekboard/eekboard-context-service.h b/eekboard/eekboard-context-service.h index 9cb53345..b5f17988 100644 --- a/eekboard/eekboard-context-service.h +++ b/eekboard/eekboard-context-service.h @@ -57,8 +57,8 @@ typedef struct _EekboardContextServicePrivate EekboardContextServicePrivate; */ struct _EekboardContextService { GObject parent; - EekboardContextServicePrivate *priv; + struct squeek_layout_state *layout; // Unowned }; /** @@ -85,7 +85,7 @@ struct _EekboardContextServiceClass { GType eekboard_context_service_get_type (void) G_GNUC_CONST; -EekboardContextService *eekboard_context_service_new(void); +EekboardContextService *eekboard_context_service_new(struct squeek_layout_state *state); void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission); void eekboard_context_service_set_ui(EekboardContextService *context, ServerContextService *ui); void eekboard_context_service_destroy (EekboardContextService *context); @@ -98,6 +98,6 @@ void eekboard_context_service_set_hint_purpose(EekboardContextService *context, uint32_t hint, uint32_t purpose); void -eekboard_context_service_update_layout(EekboardContextService *context, enum squeek_arrangement_kind t); +eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *layout); G_END_DECLS #endif /* EEKBOARD_CONTEXT_SERVICE_H */ diff --git a/src/layout.h b/src/layout.h index eefcce36..3522b3db 100644 --- a/src/layout.h +++ b/src/layout.h @@ -8,12 +8,21 @@ #include "eek/eek-renderer.h" #include "eek/eek-types.h" #include "virtual-keyboard-unstable-v1-client-protocol.h" +#include "text-input-unstable-v3-client-protocol.h" enum squeek_arrangement_kind { ARRANGEMENT_KIND_BASE = 0, ARRANGEMENT_KIND_WIDE = 1, }; +struct squeek_layout_state { + enum squeek_arrangement_kind arrangement; + enum zwp_text_input_v3_content_purpose purpose; + enum zwp_text_input_v3_content_hint hint; + char *layout_name; + char *overlay_name; +}; + struct squeek_layout; EekBounds squeek_button_get_bounds(const struct squeek_button*); diff --git a/src/server-context-service.c b/src/server-context-service.c index cd25dc0e..3e1e7f11 100644 --- a/src/server-context-service.c +++ b/src/server-context-service.c @@ -42,13 +42,13 @@ struct _ServerContextService { EekboardContextService *state; // unowned /// Needed for instantiating the widget struct submission *submission; // unowned + struct squeek_layout_state *layout; gboolean visible; PhoshLayerSurface *window; GtkWidget *widget; // nullable guint hiding; guint last_requested_height; - enum squeek_arrangement_kind last_type; }; struct _ServerContextServiceClass { @@ -70,27 +70,6 @@ on_destroy (GtkWidget *widget, gpointer user_data) //eekboard_context_service_destroy (EEKBOARD_CONTEXT_SERVICE (context)); } -static void -make_widget (ServerContextService *context); - -static void -on_notify_keyboard (GObject *object, - GParamSpec *spec, - ServerContextService *context) -{ - /* Recreate the keyboard widget to keep in sync with the keymap. */ - if (context->window) - make_widget(context); - - gboolean visible; - g_object_get (context, "visible", &visible, NULL); - - if (visible) { - server_context_service_hide_keyboard(context); - server_context_service_show_keyboard(context); - } -} - static void on_notify_map (GObject *object, ServerContextService *context) @@ -119,14 +98,6 @@ calculate_height(int32_t width) return height; } -enum squeek_arrangement_kind get_type(uint32_t width, uint32_t height) { - (void)height; - if (width < 540) { - return ARRANGEMENT_KIND_BASE; - } - return ARRANGEMENT_KIND_WIDE; -} - static void on_surface_configure(PhoshLayerSurface *surface, ServerContextService *context) { @@ -136,12 +107,6 @@ on_surface_configure(PhoshLayerSurface *surface, ServerContextService *context) "configured-width", &width, "configured-height", &height, NULL); - // check if the change would switch types - enum squeek_arrangement_kind new_type = get_type((uint32_t)width, (uint32_t)height); - if (context->last_type != new_type) { - context->last_type = new_type; - eekboard_context_service_update_layout(context->state, context->last_type); - } guint desired_height = calculate_height(width); guint configured_height = (guint)height; @@ -219,14 +184,11 @@ make_widget (ServerContextService *context) gtk_widget_destroy(context->widget); context->widget = NULL; } - - LevelKeyboard *keyboard = eekboard_context_service_get_keyboard (context->state); - - context->widget = eek_gtk_keyboard_new (keyboard, context->state, context->submission); + context->widget = eek_gtk_keyboard_new (context->state, context->submission, context->layout); gtk_widget_set_has_tooltip (context->widget, TRUE); gtk_container_add (GTK_CONTAINER(context->window), context->widget); - gtk_widget_show (context->widget); + gtk_widget_show_all(context->widget); } static gboolean @@ -360,19 +322,11 @@ server_context_service_init (ServerContextService *state) { } ServerContextService * -server_context_service_new (EekboardContextService *state, struct submission *submission) +server_context_service_new (EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout) { ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL); ui->submission = submission; ui->state = state; - g_signal_connect (state, - "notify::keyboard", - G_CALLBACK(on_notify_keyboard), - ui); + ui->layout = layout; return ui; } - -enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *service) -{ - return service->last_type; -} diff --git a/src/server-context-service.h b/src/server-context-service.h index b6806e2b..2c88a8bc 100644 --- a/src/server-context-service.h +++ b/src/server-context-service.h @@ -36,7 +36,7 @@ typedef struct _ServerContextService ServerContextService; GType server_context_service_get_type (void) G_GNUC_CONST; -ServerContextService *server_context_service_new(EekboardContextService *state, struct submission *submission); +ServerContextService *server_context_service_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout); 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); diff --git a/src/server-main.c b/src/server-main.c index 68a5f06a..513def37 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -28,6 +28,7 @@ #include "eek/eek.h" #include "eekboard/eekboard-context-service.h" #include "dbus.h" +#include "layout.h" #include "outputs.h" #include "submission.h" #include "server-context-service.h" @@ -38,11 +39,12 @@ /// Global application state struct squeekboard { - struct squeek_wayland wayland; - DBusHandler *dbus_handler; - EekboardContextService *settings_context; - ServerContextService *ui_context; - struct submission *submission; + struct squeek_wayland wayland; // Just hooks. + DBusHandler *dbus_handler; // Controls visibility of the OSK. + EekboardContextService *settings_context; // Gsettings hooks. + ServerContextService *ui_context; // mess, includes the entire UI + struct submission *submission; // Wayland text input handling. + struct squeek_layout_state layout_choice; // Currently wanted layout. }; @@ -199,7 +201,7 @@ main (int argc, char **argv) g_warning("Wayland input method interface not available"); } - instance.settings_context = eekboard_context_service_new(); + instance.settings_context = eekboard_context_service_new(&instance.layout_choice); // set up dbus @@ -276,7 +278,8 @@ main (int argc, char **argv) ServerContextService *ui_context = server_context_service_new( instance.settings_context, - instance.submission); + instance.submission, + &instance.layout_choice); if (!ui_context) { g_error("Could not initialize GUI"); exit(1);