From 4ff9cf087b8c7139f6c9b988c949ee471bf3dc58 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Tue, 25 Feb 2020 14:37:46 +0000 Subject: [PATCH 1/6] renderer: Simplify by dropping gobjectness --- eek/eek-gtk-keyboard.c | 4 +- eek/eek-renderer.c | 214 +++++++++++------------------------------ eek/eek-renderer.h | 28 +++--- 3 files changed, 69 insertions(+), 177 deletions(-) diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index bd075647..d1d76fb6 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -287,7 +287,7 @@ eek_gtk_keyboard_dispose (GObject *object) EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); if (priv->renderer) { - g_object_unref (priv->renderer); + eek_renderer_free(priv->renderer); priv->renderer = NULL; priv->renderer = NULL; } @@ -342,7 +342,7 @@ on_notify_keyboard (GObject *object, 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); + eek_renderer_free(priv->renderer); } priv->renderer = NULL; gtk_widget_queue_draw(GTK_WIDGET(self)); diff --git a/eek/eek-renderer.c b/eek/eek-renderer.c index 45ff5cd5..0db5f813 100644 --- a/eek/eek-renderer.c +++ b/eek/eek-renderer.c @@ -28,27 +28,6 @@ #include "eek-renderer.h" #include "src/style.h" -enum { - PROP_0, - PROP_PCONTEXT, - PROP_LAST -}; - -typedef struct _EekRendererPrivate -{ - LevelKeyboard *keyboard; // unowned - PangoContext *pcontext; // owned - GtkCssProvider *css_provider; // owned - GtkStyleContext *view_context; // owned - GtkStyleContext *button_context; // TODO: maybe move a copy to each button - - gdouble allocation_width; - gdouble allocation_height; - gint scale_factor; /* the outputs scale factor */ - struct transformation widget_to_layout; -} EekRendererPrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (EekRenderer, eek_renderer, G_TYPE_OBJECT) /* eek-keyboard-drawing.c */ static void render_button_label (cairo_t *cr, GtkStyleContext *ctx, @@ -138,9 +117,7 @@ eek_render_button (EekRenderer *self, gboolean pressed, gboolean locked) { - EekRendererPrivate *priv = eek_renderer_get_instance_private (self); - - GtkStyleContext *ctx = priv->button_context; + GtkStyleContext *ctx = self->button_context; /* Set the name of the button on the widget path, using the name obtained from the button's symbol. */ g_autoptr (GtkWidgetPath) path = NULL; @@ -160,7 +137,7 @@ eek_render_button (EekRenderer *self, } gtk_style_context_add_class(ctx, outline_name); - render_button_in_context(priv->scale_factor, cr, ctx, button); + render_button_in_context(self->scale_factor, cr, ctx, button); // Save and restore functions don't work if gtk_render_* was used in between gtk_style_context_set_state(ctx, GTK_STATE_FLAG_NORMAL); @@ -218,114 +195,43 @@ void eek_renderer_render_keyboard (EekRenderer *self, cairo_t *cr) { - EekRendererPrivate *priv = eek_renderer_get_instance_private (self); - - g_return_if_fail (priv->keyboard); - g_return_if_fail (priv->allocation_width > 0.0); - g_return_if_fail (priv->allocation_height > 0.0); + g_return_if_fail (self->keyboard); + g_return_if_fail (self->allocation_width > 0.0); + g_return_if_fail (self->allocation_height > 0.0); /* Paint the background covering the entire widget area */ - gtk_render_background (priv->view_context, + gtk_render_background (self->view_context, cr, 0, 0, - priv->allocation_width, priv->allocation_height); + self->allocation_width, self->allocation_height); cairo_save(cr); - cairo_translate (cr, priv->widget_to_layout.origin_x, priv->widget_to_layout.origin_y); - cairo_scale (cr, priv->widget_to_layout.scale, priv->widget_to_layout.scale); + cairo_translate (cr, self->widget_to_layout.origin_x, self->widget_to_layout.origin_y); + cairo_scale (cr, self->widget_to_layout.scale, self->widget_to_layout.scale); - squeek_draw_layout_base_view(priv->keyboard->layout, self, cr); - squeek_layout_draw_all_changed(priv->keyboard->layout, self, cr); + squeek_draw_layout_base_view(self->keyboard->layout, self, cr); + squeek_layout_draw_all_changed(self->keyboard->layout, self, cr); cairo_restore (cr); } -static void -eek_renderer_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +void +eek_renderer_free (EekRenderer *self) { - EekRendererPrivate *priv = eek_renderer_get_instance_private ( - EEK_RENDERER(object)); - - switch (prop_id) { - case PROP_PCONTEXT: - priv->pcontext = g_value_get_object (value); - g_object_ref (priv->pcontext); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + if (self->keyboard) { + self->keyboard = NULL; } -} - -static void -eek_renderer_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - (void)value; - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + if (self->pcontext) { + g_object_unref (self->pcontext); + self->pcontext = NULL; } -} - -static void -eek_renderer_dispose (GObject *object) -{ - EekRenderer *self = EEK_RENDERER (object); - EekRendererPrivate *priv = eek_renderer_get_instance_private (self); - - if (priv->keyboard) { - priv->keyboard = NULL; - } - if (priv->pcontext) { - g_object_unref (priv->pcontext); - priv->pcontext = NULL; - } - + g_object_unref(self->css_provider); + g_object_unref(self->view_context); + g_object_unref(self->button_context); // this is where renderer-specific surfaces would be released - G_OBJECT_CLASS (eek_renderer_parent_class)->dispose (object); + free(self); } -static void -eek_renderer_finalize (GObject *object) -{ - EekRenderer *self = EEK_RENDERER(object); - EekRendererPrivate *priv = eek_renderer_get_instance_private (self); - - g_object_unref(priv->css_provider); - g_object_unref(priv->view_context); - g_object_unref(priv->button_context); - G_OBJECT_CLASS (eek_renderer_parent_class)->finalize (object); -} - -static void -eek_renderer_class_init (EekRendererClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GParamSpec *pspec; - - gobject_class->set_property = eek_renderer_set_property; - gobject_class->get_property = eek_renderer_get_property; - gobject_class->dispose = eek_renderer_dispose; - gobject_class->finalize = eek_renderer_finalize; - - pspec = g_param_spec_object ("pango-context", - "Pango Context", - "Pango Context", - PANGO_TYPE_CONTEXT, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); - g_object_class_install_property (gobject_class, - PROP_PCONTEXT, - pspec); -} - - static GType new_type(char *name) { GTypeInfo info = {0}; info.class_size = sizeof(GtkWidgetClass); @@ -353,61 +259,59 @@ static GType button_type() { } static void -eek_renderer_init (EekRenderer *self) +renderer_init (EekRenderer *self) { - EekRendererPrivate *priv = eek_renderer_get_instance_private (self); - - priv->keyboard = NULL; - priv->pcontext = NULL; - priv->allocation_width = 0.0; - priv->allocation_height = 0.0; - priv->scale_factor = 1; + self->keyboard = NULL; + self->pcontext = NULL; + self->allocation_width = 0.0; + self->allocation_height = 0.0; + self->scale_factor = 1; GtkIconTheme *theme = gtk_icon_theme_get_default (); gtk_icon_theme_add_resource_path (theme, "/sm/puri/squeekboard/icons"); - priv->css_provider = squeek_load_style(); + self->css_provider = squeek_load_style(); } EekRenderer * eek_renderer_new (LevelKeyboard *keyboard, PangoContext *pcontext) { - EekRenderer *renderer = g_object_new (EEK_TYPE_RENDERER, - "pango-context", pcontext, - NULL); - EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); - priv->keyboard = keyboard; + EekRenderer *renderer = calloc(1, sizeof(EekRenderer)); + renderer_init(renderer); + renderer->pcontext = pcontext; + g_object_ref (renderer->pcontext); + renderer->keyboard = keyboard; /* Create a style context for the layout */ GtkWidgetPath *path = gtk_widget_path_new(); gtk_widget_path_append_type(path, view_type()); - priv->view_context = gtk_style_context_new(); - gtk_style_context_set_path(priv->view_context, path); + renderer->view_context = gtk_style_context_new(); + gtk_style_context_set_path(renderer->view_context, path); gtk_widget_path_unref(path); - if (squeek_layout_get_kind(priv->keyboard->layout) == ARRANGEMENT_KIND_WIDE) { - gtk_style_context_add_class(priv->view_context, "wide"); + if (squeek_layout_get_kind(renderer->keyboard->layout) == ARRANGEMENT_KIND_WIDE) { + gtk_style_context_add_class(renderer->view_context, "wide"); } - gtk_style_context_add_provider (priv->view_context, - GTK_STYLE_PROVIDER(priv->css_provider), + gtk_style_context_add_provider (renderer->view_context, + GTK_STYLE_PROVIDER(renderer->css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER); /* Create a style context for the buttons */ path = gtk_widget_path_new(); gtk_widget_path_append_type(path, view_type()); - if (squeek_layout_get_kind(priv->keyboard->layout) == ARRANGEMENT_KIND_WIDE) { + if (squeek_layout_get_kind(renderer->keyboard->layout) == ARRANGEMENT_KIND_WIDE) { gtk_widget_path_iter_add_class(path, -1, "wide"); } gtk_widget_path_append_type(path, button_type()); - priv->button_context = gtk_style_context_new (); - gtk_style_context_set_path(priv->button_context, path); + renderer->button_context = gtk_style_context_new (); + gtk_style_context_set_path(renderer->button_context, path); gtk_widget_path_unref(path); - gtk_style_context_set_parent(priv->button_context, priv->view_context); - gtk_style_context_set_state (priv->button_context, GTK_STATE_FLAG_NORMAL); - gtk_style_context_add_provider (priv->button_context, - GTK_STYLE_PROVIDER(priv->css_provider), + gtk_style_context_set_parent(renderer->button_context, renderer->view_context); + gtk_style_context_set_state (renderer->button_context, GTK_STATE_FLAG_NORMAL); + gtk_style_context_add_provider (renderer->button_context, + GTK_STYLE_PROVIDER(renderer->css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER); return renderer; } @@ -417,17 +321,14 @@ eek_renderer_set_allocation_size (EekRenderer *renderer, gdouble width, gdouble height) { - g_return_if_fail (EEK_IS_RENDERER(renderer)); g_return_if_fail (width > 0.0 && height > 0.0); - EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); + renderer->allocation_width = width; + renderer->allocation_height = height; - priv->allocation_width = width; - priv->allocation_height = height; - - priv->widget_to_layout = squeek_layout_calculate_transformation( - priv->keyboard->layout, - priv->allocation_width, priv->allocation_height); + renderer->widget_to_layout = squeek_layout_calculate_transformation( + renderer->keyboard->layout, + renderer->allocation_width, renderer->allocation_height); // This is where size-dependent surfaces would be released } @@ -435,10 +336,7 @@ eek_renderer_set_allocation_size (EekRenderer *renderer, void eek_renderer_set_scale_factor (EekRenderer *renderer, gint scale) { - g_return_if_fail (EEK_IS_RENDERER(renderer)); - - EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); - priv->scale_factor = scale; + renderer->scale_factor = scale; } cairo_surface_t * @@ -467,9 +365,5 @@ eek_renderer_get_icon_surface (const gchar *icon_name, struct transformation eek_renderer_get_transformation (EekRenderer *renderer) { - struct transformation failed = {0}; - g_return_val_if_fail (EEK_IS_RENDERER(renderer), failed); - - EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); - return priv->widget_to_layout; + return renderer->widget_to_layout; } diff --git a/eek/eek-renderer.h b/eek/eek-renderer.h index 0d46237e..4e7284d7 100644 --- a/eek/eek-renderer.h +++ b/eek/eek-renderer.h @@ -26,24 +26,20 @@ #include "eek-types.h" -G_BEGIN_DECLS - -#define EEK_TYPE_RENDERER (eek_renderer_get_type()) -G_DECLARE_DERIVABLE_TYPE (EekRenderer, eek_renderer, EEK, RENDERER, GObject) - -struct _EekRendererClass +typedef struct EekRenderer { - GObjectClass parent_class; + LevelKeyboard *keyboard; // unowned + PangoContext *pcontext; // owned + GtkCssProvider *css_provider; // owned + GtkStyleContext *view_context; // owned + GtkStyleContext *button_context; // TODO: maybe move a copy to each button - cairo_surface_t *(* get_icon_surface) (EekRenderer *self, - const gchar *icon_name, - gint size, - gint scale); + gdouble allocation_width; + gdouble allocation_height; + gint scale_factor; /* the outputs scale factor */ + struct transformation widget_to_layout; +} EekRenderer; - /*< private >*/ - /* padding */ - gpointer pdummy[23]; -}; GType eek_renderer_get_type (void) G_GNUC_CONST; EekRenderer *eek_renderer_new (LevelKeyboard *keyboard, @@ -61,6 +57,8 @@ cairo_surface_t *eek_renderer_get_icon_surface(const gchar *icon_name, void eek_renderer_render_keyboard (EekRenderer *renderer, cairo_t *cr); +void +eek_renderer_free (EekRenderer *self); struct transformation eek_renderer_get_transformation (EekRenderer *renderer); From 22daefba3a3f7ffe6956d1126bcffbcfdaf6d49e Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Tue, 25 Feb 2020 15:46:58 +0000 Subject: [PATCH 2/6] levelkeyboard: Rearrange to make future conversion easier --- eek/eek-keyboard.c | 4 +--- eek/eek-keyboard.h | 3 +-- eekboard/eekboard-context-service.c | 3 ++- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index 24ef537b..292a0879 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -38,10 +38,8 @@ void level_keyboard_free(LevelKeyboard *self) { } LevelKeyboard* -level_keyboard_new (const gchar *keyboard_type, - enum squeek_arrangement_kind t) +level_keyboard_new (struct squeek_layout *layout) { - struct squeek_layout *layout = squeek_load_layout(keyboard_type, t); LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1); if (!keyboard) { diff --git a/eek/eek-keyboard.h b/eek/eek-keyboard.h index fab549e1..b1377c47 100644 --- a/eek/eek-keyboard.h +++ b/eek/eek-keyboard.h @@ -47,8 +47,7 @@ gchar * eek_keyboard_get_keymap (LevelKeyboard *keyboard); LevelKeyboard* -level_keyboard_new (const gchar *keyboard_type, - enum squeek_arrangement_kind t); +level_keyboard_new (struct squeek_layout *layout); void level_keyboard_free(LevelKeyboard *self); G_END_DECLS diff --git a/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c index 46ef548a..4a91be0e 100644 --- a/eekboard/eekboard-context-service.c +++ b/eekboard/eekboard-context-service.c @@ -139,7 +139,8 @@ eekboard_context_service_use_layout(EekboardContextService *context, struct sque } // generic part follows - LevelKeyboard *keyboard = level_keyboard_new(layout_name, state->arrangement); + struct squeek_layout *layout = squeek_load_layout(layout_name, state->arrangement); + LevelKeyboard *keyboard = level_keyboard_new(layout); // set as current LevelKeyboard *previous_keyboard = context->priv->keyboard; context->priv->keyboard = keyboard; From 784f9127fa04da3d8d29ea310a62672ab11a8dcf Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Wed, 26 Feb 2020 07:59:29 +0000 Subject: [PATCH 3/6] layout: Minor generalizations --- eek/eek-gtk-keyboard.c | 8 +++++--- eek/eek-gtk-keyboard.h | 1 - eek/eek-renderer.c | 20 ++++++++------------ eek/eek-renderer.h | 14 +++++++++++--- eekboard/eekboard-context-service.h | 3 --- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index d1d76fb6..ddcf09e1 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -44,11 +44,11 @@ typedef struct _EekGtkKeyboardPrivate { - EekRenderer *renderer; + EekRenderer *renderer; // owned, nullable EekboardContextService *eekboard_context; // unowned reference struct submission *submission; // unowned reference - struct squeek_layout_state *layout; + struct squeek_layout_state *layout; // unowned LevelKeyboard *keyboard; // unowned reference; it's kept in server-context GdkEventSequence *sequence; // unowned reference @@ -92,13 +92,14 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, pcontext); eek_renderer_set_allocation_size (priv->renderer, + priv->keyboard->layout, allocation.width, allocation.height); eek_renderer_set_scale_factor (priv->renderer, gtk_widget_get_scale_factor (self)); } - eek_renderer_render_keyboard (priv->renderer, cr); + eek_renderer_render_keyboard (priv->renderer, cr, priv->keyboard); return FALSE; } @@ -129,6 +130,7 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self, if (priv->renderer) eek_renderer_set_allocation_size (priv->renderer, + priv->keyboard->layout, allocation->width, allocation->height); diff --git a/eek/eek-gtk-keyboard.h b/eek/eek-gtk-keyboard.h index ca127011..7570ac05 100644 --- a/eek/eek-gtk-keyboard.h +++ b/eek/eek-gtk-keyboard.h @@ -32,7 +32,6 @@ struct submission; struct squeek_layout_state; -typedef struct _LevelKeyboard LevelKeyboard; // including causes weird bugs G_BEGIN_DECLS #define EEK_TYPE_GTK_KEYBOARD (eek_gtk_keyboard_get_type()) diff --git a/eek/eek-renderer.c b/eek/eek-renderer.c index 0db5f813..39c60951 100644 --- a/eek/eek-renderer.c +++ b/eek/eek-renderer.c @@ -193,9 +193,9 @@ render_button_label (cairo_t *cr, void eek_renderer_render_keyboard (EekRenderer *self, - cairo_t *cr) + cairo_t *cr, + LevelKeyboard *keyboard) { - g_return_if_fail (self->keyboard); g_return_if_fail (self->allocation_width > 0.0); g_return_if_fail (self->allocation_height > 0.0); @@ -209,17 +209,14 @@ eek_renderer_render_keyboard (EekRenderer *self, cairo_translate (cr, self->widget_to_layout.origin_x, self->widget_to_layout.origin_y); cairo_scale (cr, self->widget_to_layout.scale, self->widget_to_layout.scale); - squeek_draw_layout_base_view(self->keyboard->layout, self, cr); - squeek_layout_draw_all_changed(self->keyboard->layout, self, cr); + squeek_draw_layout_base_view(keyboard->layout, self, cr); + squeek_layout_draw_all_changed(keyboard->layout, self, cr); cairo_restore (cr); } void eek_renderer_free (EekRenderer *self) { - if (self->keyboard) { - self->keyboard = NULL; - } if (self->pcontext) { g_object_unref (self->pcontext); self->pcontext = NULL; @@ -261,7 +258,6 @@ static GType button_type() { static void renderer_init (EekRenderer *self) { - self->keyboard = NULL; self->pcontext = NULL; self->allocation_width = 0.0; self->allocation_height = 0.0; @@ -282,7 +278,6 @@ eek_renderer_new (LevelKeyboard *keyboard, renderer_init(renderer); renderer->pcontext = pcontext; g_object_ref (renderer->pcontext); - renderer->keyboard = keyboard; /* Create a style context for the layout */ GtkWidgetPath *path = gtk_widget_path_new(); @@ -291,7 +286,7 @@ eek_renderer_new (LevelKeyboard *keyboard, renderer->view_context = gtk_style_context_new(); gtk_style_context_set_path(renderer->view_context, path); gtk_widget_path_unref(path); - if (squeek_layout_get_kind(renderer->keyboard->layout) == ARRANGEMENT_KIND_WIDE) { + if (squeek_layout_get_kind(keyboard->layout) == ARRANGEMENT_KIND_WIDE) { gtk_style_context_add_class(renderer->view_context, "wide"); } gtk_style_context_add_provider (renderer->view_context, @@ -301,7 +296,7 @@ eek_renderer_new (LevelKeyboard *keyboard, /* Create a style context for the buttons */ path = gtk_widget_path_new(); gtk_widget_path_append_type(path, view_type()); - if (squeek_layout_get_kind(renderer->keyboard->layout) == ARRANGEMENT_KIND_WIDE) { + if (squeek_layout_get_kind(keyboard->layout) == ARRANGEMENT_KIND_WIDE) { gtk_widget_path_iter_add_class(path, -1, "wide"); } gtk_widget_path_append_type(path, button_type()); @@ -318,6 +313,7 @@ eek_renderer_new (LevelKeyboard *keyboard, void eek_renderer_set_allocation_size (EekRenderer *renderer, + struct squeek_layout *layout, gdouble width, gdouble height) { @@ -327,7 +323,7 @@ eek_renderer_set_allocation_size (EekRenderer *renderer, renderer->allocation_height = height; renderer->widget_to_layout = squeek_layout_calculate_transformation( - renderer->keyboard->layout, + layout, renderer->allocation_width, renderer->allocation_height); // This is where size-dependent surfaces would be released diff --git a/eek/eek-renderer.h b/eek/eek-renderer.h index 4e7284d7..a90deeb9 100644 --- a/eek/eek-renderer.h +++ b/eek/eek-renderer.h @@ -26,17 +26,25 @@ #include "eek-types.h" +struct squeek_layout; + +/// Renders LevelKayboards +/// It cannot adjust styles at runtime. typedef struct EekRenderer { - LevelKeyboard *keyboard; // unowned PangoContext *pcontext; // owned GtkCssProvider *css_provider; // owned GtkStyleContext *view_context; // owned GtkStyleContext *button_context; // TODO: maybe move a copy to each button + /// Style class for rendering the view and button CSS. + gchar *extra_style; // owned + // Mutable state + /// Background extents gdouble allocation_width; gdouble allocation_height; gint scale_factor; /* the outputs scale factor */ + /// Coords transformation struct transformation widget_to_layout; } EekRenderer; @@ -45,7 +53,7 @@ GType eek_renderer_get_type (void) G_GNUC_CONST; EekRenderer *eek_renderer_new (LevelKeyboard *keyboard, PangoContext *pcontext); void eek_renderer_set_allocation_size - (EekRenderer *renderer, + (EekRenderer *renderer, struct squeek_layout *layout, gdouble width, gdouble height); void eek_renderer_set_scale_factor (EekRenderer *renderer, @@ -56,7 +64,7 @@ cairo_surface_t *eek_renderer_get_icon_surface(const gchar *icon_name, gint scale); void eek_renderer_render_keyboard (EekRenderer *renderer, - cairo_t *cr); + cairo_t *cr, LevelKeyboard *keyboard); void eek_renderer_free (EekRenderer *self); diff --git a/eekboard/eekboard-context-service.h b/eekboard/eekboard-context-service.h index b5f17988..8547e3e7 100644 --- a/eekboard/eekboard-context-service.h +++ b/eekboard/eekboard-context-service.h @@ -72,9 +72,6 @@ struct _EekboardContextServiceClass { GObjectClass parent_class; /*< public >*/ - struct squeek_view *(*create_keyboard) (EekboardContextService *self, - const gchar *keyboard_type); - /* signals */ void (*destroyed) (EekboardContextService *self); From 24f709ab132483d2e1cc3b77300810cf11efac83 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Fri, 28 Feb 2020 18:09:34 +0000 Subject: [PATCH 4/6] Remove unused code --- eekboard/eekboard-context-service.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c index 4a91be0e..b69d3660 100644 --- a/eekboard/eekboard-context-service.c +++ b/eekboard/eekboard-context-service.c @@ -47,7 +47,6 @@ static guint signals[LAST_SIGNAL] = { 0, }; struct _EekboardContextServicePrivate { LevelKeyboard *keyboard; // currently used keyboard - GHashTable *keyboard_hash; // a table of available keyboards, per layout GSettings *settings; // Owned reference // Maybe TODO: it's used only for fetching layout type. @@ -94,13 +93,6 @@ eekboard_context_service_get_property (GObject *object, static void eekboard_context_service_dispose (GObject *object) { - EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object); - - if (context->priv->keyboard_hash) { - g_hash_table_destroy (context->priv->keyboard_hash); - context->priv->keyboard_hash = NULL; - } - G_OBJECT_CLASS (eekboard_context_service_parent_class)-> dispose (object); } @@ -241,12 +233,6 @@ eekboard_context_service_init (EekboardContextService *self) { self->priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(self); - self->priv->keyboard_hash = - g_hash_table_new_full (g_direct_hash, - g_direct_equal, - NULL, - (GDestroyNotify)g_object_unref); - self->priv->settings = g_settings_new ("org.gnome.desktop.input-sources"); gulong conn_id = g_signal_connect(self->priv->settings, "change-event", G_CALLBACK(settings_handle_layout_changed), From 3cd170acc3dd1834b39c817c1e009b5a8ae79731 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Sat, 29 Feb 2020 14:54:40 +0000 Subject: [PATCH 5/6] sizing: Create a standalone UI shape manager The manager is used for sizing the layer surface. It promises never to exceed half the output height. The selection of the current layout is not being done here, leading to worse behaviour in 1:1 scaling. In the future, it could be used for sizing the keyboard itself and the suggestion box, as well as decide which layout to use, because layouts should have some sizing hints. --- src/lib.rs | 1 + src/outputs.h | 6 +- src/outputs.rs | 103 ++++++++++++++++++++++------------- src/server-context-service.c | 26 +++------ src/server-context-service.h | 3 +- src/server-main.c | 7 ++- src/ui_manager.h | 14 +++++ src/ui_manager.rs | 81 +++++++++++++++++++++++++++ src/util.rs | 4 +- 9 files changed, 185 insertions(+), 60 deletions(-) create mode 100644 src/ui_manager.h create mode 100644 src/ui_manager.rs diff --git a/src/lib.rs b/src/lib.rs index ba71686b..287b5286 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,5 +35,6 @@ mod style; mod submission; pub mod tests; pub mod util; +mod ui_manager; mod vkeyboard; mod xdg; diff --git a/src/outputs.h b/src/outputs.h index 38a207f6..e018d037 100644 --- a/src/outputs.h +++ b/src/outputs.h @@ -4,10 +4,14 @@ #include "wayland-client-protocol.h" struct squeek_outputs; +struct squeek_output_handle { + struct wl_output *output; + struct squeek_outputs *outputs; +}; struct squeek_outputs *squeek_outputs_new(); void squeek_outputs_free(struct squeek_outputs*); void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output); -struct wl_output *squeek_outputs_get_current(struct squeek_outputs*); +struct squeek_output_handle squeek_outputs_get_current(struct squeek_outputs*); int32_t squeek_outputs_get_perceptual_width(struct squeek_outputs*, struct wl_output *output); #endif diff --git a/src/outputs.rs b/src/outputs.rs index 08ac590d..29f4e78c 100644 --- a/src/outputs.rs +++ b/src/outputs.rs @@ -17,7 +17,7 @@ pub mod c { // Defined in C #[repr(transparent)] - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, Copy)] pub struct WlOutput(*const c_void); #[repr(C)] @@ -105,6 +105,24 @@ pub mod c { type COutputs = ::util::c::Wrapped; + /// A stable reference to an output. + #[derive(Clone)] + #[repr(C)] + pub struct OutputHandle { + wl_output: WlOutput, + outputs: COutputs, + } + + impl OutputHandle { + // Cannot return an Output reference + // because COutputs is too deeply wrapped + pub fn get_state(&self) -> Option { + let outputs = self.outputs.clone_ref(); + let outputs = outputs.borrow(); + find_output(&outputs, self.wl_output.clone()).map(|o| o.current.clone()) + } + } + // Defined in Rust extern fn outputs_handle_geometry( @@ -240,46 +258,15 @@ pub mod c { #[no_mangle] pub extern "C" - fn squeek_outputs_get_current(raw_collection: COutputs) -> WlOutput { + fn squeek_outputs_get_current(raw_collection: COutputs) -> OutputHandle { let collection = raw_collection.clone_ref(); let collection = collection.borrow(); - collection.outputs[0].output.clone() - } - - #[no_mangle] - pub extern "C" - fn squeek_outputs_get_perceptual_width( - raw_collection: COutputs, - wl_output: WlOutput, - ) -> i32 { - let collection = raw_collection.clone_ref(); - let collection = collection.borrow(); - - let output_state = find_output(&collection, wl_output) - .map(|o| &o.current); - match output_state { - Some(OutputState { - current_mode: Some(super::Mode { width, height } ), - transform: Some(transform), - scale, - }) => { - match transform { - Transform::Normal - | Transform::Rotated180 - | Transform::Flipped - | Transform::FlippedRotated180 => width / scale, - _ => height / scale, - } - }, - _ => { - log_print!( - logging::Level::Surprise, - "Not enough info received on output", - ); - 0 - }, + OutputHandle { + wl_output: collection.outputs[0].output.clone(), + outputs: raw_collection.clone(), } } + // TODO: handle unregistration fn find_output( @@ -305,6 +292,14 @@ pub mod c { } } +/// Generic size +#[derive(Clone)] +pub struct Size { + pub width: u32, + pub height: u32, +} + +/// wl_output mode #[derive(Clone)] struct Mode { width: i32, @@ -315,10 +310,16 @@ struct Mode { pub struct OutputState { current_mode: Option, transform: Option, - scale: i32, + pub scale: i32, } impl OutputState { + // More properly, this would have been a builder kind of struct, + // with wl_output gradually adding properties to it + // before it reached a fully initialized state, + // when it would transform into a struct without all (some?) of the Options. + // However, it's not clear which state is fully initialized, + // and whether it would make things easier at all anyway. fn uninitialized() -> OutputState { OutputState { current_mode: None, @@ -326,6 +327,32 @@ impl OutputState { scale: 1, } } + + pub fn get_pixel_size(&self) -> Option { + use self::c::Transform; + match self { + OutputState { + current_mode: Some(Mode { width, height } ), + transform: Some(transform), + scale: _, + } => Some( + match transform { + Transform::Normal + | Transform::Rotated180 + | Transform::Flipped + | Transform::FlippedRotated180 => Size { + width: *width as u32, + height: *height as u32, + }, + _ => Size { + width: *height as u32, + height: *width as u32, + }, + } + ), + _ => None, + } + } } pub struct Output { diff --git a/src/server-context-service.c b/src/server-context-service.c index 3e1e7f11..46811ce4 100644 --- a/src/server-context-service.c +++ b/src/server-context-service.c @@ -43,6 +43,7 @@ struct _ServerContextService { /// Needed for instantiating the widget struct submission *submission; // unowned struct squeek_layout_state *layout; + struct ui_manager *manager; // unowned gboolean visible; PhoshLayerSurface *window; @@ -86,18 +87,6 @@ on_notify_unmap (GObject *object, g_object_set (context, "visible", FALSE, NULL); } -static uint32_t -calculate_height(int32_t width) -{ - uint32_t height = 180; - if (width < 360 && width > 0) { - height = ((unsigned)width * 7 / 12); // to match 360×210 - } else if (width < 540) { - height = 180 + (540 - (unsigned)width) * 30 / 180; // smooth transition - } - return height; -} - static void on_surface_configure(PhoshLayerSurface *surface, ServerContextService *context) { @@ -108,7 +97,7 @@ on_surface_configure(PhoshLayerSurface *surface, ServerContextService *context) "configured-height", &height, NULL); - guint desired_height = calculate_height(width); + guint desired_height = squeek_uiman_get_perceptual_height(context->manager); guint configured_height = (guint)height; // if height was already requested once but a different one was given // (for the same set of surrounding properties), @@ -131,14 +120,14 @@ make_window (ServerContextService *context) if (context->window) g_error("Window already present"); - struct wl_output *output = squeek_outputs_get_current(squeek_wayland->outputs); - int32_t width = squeek_outputs_get_perceptual_width(squeek_wayland->outputs, output); - uint32_t height = calculate_height(width); + struct squeek_output_handle output = squeek_outputs_get_current(squeek_wayland->outputs); + squeek_uiman_set_output(context->manager, output); + uint32_t height = squeek_uiman_get_perceptual_height(context->manager); context->window = g_object_new ( PHOSH_TYPE_LAYER_SURFACE, "layer-shell", squeek_wayland->layer_shell, - "wl-output", output, + "wl-output", output.output, "height", height, "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT @@ -322,11 +311,12 @@ server_context_service_init (ServerContextService *state) { } ServerContextService * -server_context_service_new (EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout) +server_context_service_new (EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman) { ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL); ui->submission = submission; ui->state = state; ui->layout = layout; + ui->manager = uiman; return ui; } diff --git a/src/server-context-service.h b/src/server-context-service.h index 2c88a8bc..a69f85ae 100644 --- a/src/server-context-service.h +++ b/src/server-context-service.h @@ -20,6 +20,7 @@ #include "src/layout.h" #include "src/submission.h" +#include "ui_manager.h" G_BEGIN_DECLS @@ -36,7 +37,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, struct squeek_layout_state *layout); +ServerContextService *server_context_service_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman); 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 513def37..0fae0245 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -32,6 +32,7 @@ #include "outputs.h" #include "submission.h" #include "server-context-service.h" +#include "ui_manager.h" #include "wayland.h" #include @@ -45,6 +46,7 @@ struct squeekboard { ServerContextService *ui_context; // mess, includes the entire UI struct submission *submission; // Wayland text input handling. struct squeek_layout_state layout_choice; // Currently wanted layout. + struct ui_manager *ui_manager; // UI shape tracker/chooser. TODO: merge with layuot choice }; @@ -201,6 +203,8 @@ main (int argc, char **argv) g_warning("Wayland input method interface not available"); } + instance.ui_manager = squeek_uiman_new(); + instance.settings_context = eekboard_context_service_new(&instance.layout_choice); // set up dbus @@ -279,7 +283,8 @@ main (int argc, char **argv) ServerContextService *ui_context = server_context_service_new( instance.settings_context, instance.submission, - &instance.layout_choice); + &instance.layout_choice, + instance.ui_manager); if (!ui_context) { g_error("Could not initialize GUI"); exit(1); diff --git a/src/ui_manager.h b/src/ui_manager.h new file mode 100644 index 00000000..57d3cc70 --- /dev/null +++ b/src/ui_manager.h @@ -0,0 +1,14 @@ +#ifndef UI_MANAGER__ +#define UI_MANAGER__ + +#include + +#include "outputs.h" + +struct ui_manager; + +struct ui_manager *squeek_uiman_new(); +void squeek_uiman_set_output(struct ui_manager *uiman, struct squeek_output_handle output); +uint32_t squeek_uiman_get_perceptual_height(struct ui_manager *uiman); + +#endif diff --git a/src/ui_manager.rs b/src/ui_manager.rs new file mode 100644 index 00000000..c7af6521 --- /dev/null +++ b/src/ui_manager.rs @@ -0,0 +1,81 @@ +/* Copyright (C) 2020 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + */ + +/*! Centrally manages the shape of the UI widgets, and the choice of layout. + * + * Coordinates this based on information collated from all possible sources. + */ + +use std::cmp::min; +use ::outputs::c::OutputHandle; + +mod c { + use super::*; + use ::util::c::Wrapped; + + #[no_mangle] + pub extern "C" + fn squeek_uiman_new() -> Wrapped { + Wrapped::new(Manager { output: None }) + } + + /// Used to size the layer surface containing all the OSK widgets. + #[no_mangle] + pub extern "C" + fn squeek_uiman_get_perceptual_height( + uiman: Wrapped, + ) -> u32 { + let uiman = uiman.clone_ref(); + let uiman = uiman.borrow(); + // TODO: what to do when there's no output? + uiman.get_perceptual_height().unwrap_or(0) + } + + #[no_mangle] + pub extern "C" + fn squeek_uiman_set_output( + uiman: Wrapped, + output: OutputHandle, + ) { + let uiman = uiman.clone_ref(); + let mut uiman = uiman.borrow_mut(); + uiman.output = Some(output); + } +} + +/// Stores current state of all things influencing what the UI should look like. +pub struct Manager { + /// Shared output handle, current state updated whenever it's needed. + // TODO: Stop assuming that the output never changes. + // (There's no way for the output manager to update the ui manager.) + // FIXME: Turn into an OutputState and apply relevant connections elsewhere. + // Otherwise testability and predictablity is low. + output: Option, + //// Pixel size of the surface. Needs explicit updating. + //surface_size: Option, +} + +impl Manager { + fn get_perceptual_height(&self) -> Option { + let output_info = (&self.output).as_ref() + .and_then(|o| o.get_state()) + .map(|os| (os.scale as u32, os.get_pixel_size())); + match output_info { + Some((scale, Some(px_size))) => Some({ + let height = if (px_size.width < 720) & (px_size.width > 0) { + px_size.width * 7 / 12 // to match 360×210 + } else if px_size.width < 1080 { + 360 + (1080 - px_size.width) * 60 / 360 // smooth transition + } else { + 360 + }; + + // Don't exceed half the display size + min(height, px_size.height / 2) / scale + }), + Some((scale, None)) => Some(360 / scale), + None => None, + } + } +} diff --git a/src/util.rs b/src/util.rs index d58a3e77..e87ffea6 100644 --- a/src/util.rs +++ b/src/util.rs @@ -98,7 +98,8 @@ pub mod c { Rc::from_raw(self.0) } - /// Creates a new Rc reference to the same data + /// Creates a new Rc reference to the same data. + /// Use for accessing the underlying data as a reference. pub fn clone_ref(&self) -> Rc> { // A bit dangerous: the Rc may be in use elsewhere let used_rc = unsafe { Rc::from_raw(self.0) }; @@ -130,6 +131,7 @@ pub mod c { impl COpaquePtr for Wrapped {} } +/// Clones the underlying data structure, like ToOwned. pub trait CloneOwned { type Owned; fn clone_owned(&self) -> Self::Owned; From 2770e1769c332f5c85aa1ce3dcab6d14a22b52b3 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Sat, 29 Feb 2020 15:06:27 +0000 Subject: [PATCH 6/6] sizing: Ignore scaling factor for layout selection --- eek/eek-gtk-keyboard.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index ddcf09e1..4da4024a 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -103,9 +103,10 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, return FALSE; } +// Units of pixel size static enum squeek_arrangement_kind get_type(uint32_t width, uint32_t height) { (void)height; - if (width < 540) { + if (width < 1080) { return ARRANGEMENT_KIND_BASE; } return ARRANGEMENT_KIND_WIDE; @@ -117,11 +118,11 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self, { EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); - + uint32_t scale = (uint32_t)gtk_widget_get_scale_factor(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)); + (uint32_t)(allocation->width - allocation->x) * scale, + (uint32_t)(allocation->height - allocation->y) * scale); if (priv->layout->arrangement != new_type) { priv->layout->arrangement = new_type;