diff --git a/Cargo.lock b/Cargo.lock index bb1d07ef..cb1be684 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -324,6 +324,9 @@ name = "rs" version = "0.1.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cairo-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 44e02b37..0e04f0ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,15 @@ serde = { version = "1.0.*", features = ["derive"] } serde_yaml = "0.8.*" xkbcommon = { version = "0.4.*", features = ["wayland"] } +[dependencies.cairo-rs] +version = "0.5.*" + +[dependencies.cairo-sys-rs] +version = "" + +[dependencies.gdk] +version = "" + [dependencies.gio] version = "" features = ["v2_44"] @@ -23,7 +32,6 @@ features = ["v2_44"] version = "" features = ["v2_44"] - [dependencies.gtk] version = "0.5.*" features = ["v3_22"] diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index 67f354df..96d899b6 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -61,10 +61,6 @@ typedef struct _EekGtkKeyboardPrivate G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA) -static void render_pressed_button (GtkWidget *widget, struct button_place *place); -static void render_released_button (GtkWidget *widget, - const struct squeek_button *button); - static void eek_gtk_keyboard_real_realize (GtkWidget *self) { @@ -85,7 +81,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, cairo_t *cr) { EekGtkKeyboardPrivate *priv = - eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); + eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); GtkAllocation allocation; gtk_widget_get_allocation (self, &allocation); @@ -101,10 +97,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, gtk_widget_get_scale_factor (self)); } - // render the keyboard without any key activity (TODO: from a cached buffer) eek_renderer_render_keyboard (priv->renderer, cr); - // render only a few remaining changes - squeek_layout_draw_all_changed(priv->keyboard->layout, EEK_GTK_KEYBOARD(self)); return FALSE; } @@ -113,7 +106,7 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self, GtkAllocation *allocation) { EekGtkKeyboardPrivate *priv = - eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); + eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); if (priv->renderer) eek_renderer_set_allocation_size (priv->renderer, @@ -158,8 +151,6 @@ eek_gtk_keyboard_real_button_press_event (GtkWidget *self, return TRUE; } - - // TODO: this belongs more in gtk_keyboard, with a way to find out which key to re-render static gboolean eek_gtk_keyboard_real_button_release_event (GtkWidget *self, @@ -231,7 +222,7 @@ static void eek_gtk_keyboard_real_unmap (GtkWidget *self) { EekGtkKeyboardPrivate *priv = - eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); + eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); if (priv->keyboard) { squeek_layout_release_all_only( @@ -248,6 +239,7 @@ eek_gtk_keyboard_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { + (void)value; switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -304,7 +296,9 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass) static void eek_gtk_keyboard_init (EekGtkKeyboard *self) -{} +{ + (void)self; +} /** * eek_gtk_keyboard_new: @@ -322,110 +316,7 @@ eek_gtk_keyboard_new (LevelKeyboard *keyboard) return GTK_WIDGET(ret); } -static void -render_pressed_button (GtkWidget *widget, - struct button_place *place) -{ - EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget); +EekRenderer *eek_gtk_keyboard_get_renderer(EekGtkKeyboard *self) { EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - - GdkWindow *window = gtk_widget_get_window (widget); - cairo_region_t *region = gdk_window_get_clip_region (window); - GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region); - cairo_t *cr = gdk_drawing_context_get_cairo_context (context); - - eek_renderer_render_button (priv->renderer, cr, place, 1.0, TRUE); -/* - eek_renderer_render_key (priv->renderer, cr, key, 1.5, TRUE); -*/ - gdk_window_end_draw_frame (window, context); - - cairo_region_destroy (region); -} - -void -eek_gtk_render_locked_button (EekGtkKeyboard *self, struct button_place place) -{ - EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - - GdkWindow *window = gtk_widget_get_window (GTK_WIDGET(self)); - cairo_region_t *region = gdk_window_get_clip_region (window); - GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region); - cairo_t *cr = gdk_drawing_context_get_cairo_context (context); - - eek_renderer_render_button (priv->renderer, cr, &place, 1.0, TRUE); - - gdk_window_end_draw_frame (window, context); - - cairo_region_destroy (region); -} - -// TODO: does it really redraw the entire keyboard? -static void -render_released_button (GtkWidget *widget, - const struct squeek_button *button) -{ - (void)button; - EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget); - EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - - GdkWindow *window = gtk_widget_get_window (widget); - cairo_region_t *region = gdk_window_get_clip_region (window); - GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region); - cairo_t *cr = gdk_drawing_context_get_cairo_context (context); - - eek_renderer_render_keyboard (priv->renderer, cr); - - gdk_window_end_draw_frame (window, context); - - cairo_region_destroy (region); -} - -void -eek_gtk_on_button_pressed (struct button_place place, - EekGtkKeyboard *self) -{ - EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - - /* renderer may have not been set yet if the widget is a popup */ - if (!priv->renderer) - return; - - if (!place.row) { - return; - } - render_pressed_button (GTK_WIDGET(self), &place); - gtk_widget_queue_draw (GTK_WIDGET(self)); - -#if HAVE_LIBCANBERRA - ca_gtk_play_for_widget (widget, 0, - CA_PROP_EVENT_ID, "button-pressed", - CA_PROP_EVENT_DESCRIPTION, "virtual key pressed", - CA_PROP_APPLICATION_ID, "org.fedorahosted.Eekboard", - NULL); -#endif -} - -void -eek_gtk_on_button_released (const struct squeek_button *button, - struct squeek_view *view, - EekGtkKeyboard *self) -{ - (void)view; - EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - - /* renderer may have not been set yet if the widget is a popup */ - if (!priv->renderer) - return; - - render_released_button (GTK_WIDGET(self), button); - gtk_widget_queue_draw (GTK_WIDGET(self)); - -#if HAVE_LIBCANBERRA - ca_gtk_play_for_widget (widget, 0, - CA_PROP_EVENT_ID, "button-released", - CA_PROP_EVENT_DESCRIPTION, "virtual key pressed", - CA_PROP_APPLICATION_ID, "org.fedorahosted.Eekboard", - NULL); -#endif + return priv->renderer; } diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index ee750abb..07790245 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -34,8 +34,6 @@ #include "eekboard/eekboard-context-service.h" #include "eekboard/key-emitter.h" #include "keymap.h" -#include "src/keyboard.h" - #include "eek-keyboard.h" void level_keyboard_deinit(LevelKeyboard *self) { @@ -59,8 +57,3 @@ LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek keyboard->manager = manager; return keyboard; } - -struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard) -{ - return squeek_layout_get_current_view(keyboard->layout); -} diff --git a/eek/eek-keyboard.h b/eek/eek-keyboard.h index 05bf5330..ebf63351 100644 --- a/eek/eek-keyboard.h +++ b/eek/eek-keyboard.h @@ -49,7 +49,6 @@ typedef struct _LevelKeyboard LevelKeyboard; gchar * eek_keyboard_get_keymap (LevelKeyboard *keyboard); -struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard); LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout); void level_keyboard_deinit(LevelKeyboard *self); void level_keyboard_free(LevelKeyboard *self); diff --git a/eek/eek-renderer.c b/eek/eek-renderer.c index 1bfaf672..2c30a062 100644 --- a/eek/eek-renderer.c +++ b/eek/eek-renderer.c @@ -42,17 +42,14 @@ typedef struct _EekRendererPrivate GtkStyleContext *view_context; // owned GtkStyleContext *button_context; // TODO: maybe move a copy to each button - gdouble border_width; + gdouble border_width; // FIXME: border of what? gdouble allocation_width; gdouble allocation_height; - gdouble scale; gint scale_factor; /* the outputs scale factor */ - gint origin_x; - gint origin_y; + struct transformation widget_to_layout; PangoFontDescription *font; // owned reference - cairo_surface_t *keyboard_surface; } EekRendererPrivate; @@ -62,110 +59,10 @@ G_DEFINE_TYPE_WITH_PRIVATE (EekRenderer, eek_renderer, G_TYPE_OBJECT) static void eek_renderer_render_button_label (EekRenderer *self, cairo_t *cr, GtkStyleContext *ctx, const struct squeek_button *button); -static void invalidate (EekRenderer *renderer); -static void render_button (EekRenderer *self, - cairo_t *cr, EekBounds view_bounds, struct button_place *place, +void eek_render_button (EekRenderer *self, + cairo_t *cr, const struct squeek_button *button, gboolean pressed, gboolean locked); -struct _CreateKeyboardSurfaceCallbackData { - cairo_t *cr; - EekRenderer *renderer; - struct squeek_view *view; - struct squeek_row *row; -}; -typedef struct _CreateKeyboardSurfaceCallbackData CreateKeyboardSurfaceCallbackData; - -static void -create_keyboard_surface_button_callback (struct squeek_button *button, - gpointer user_data) -{ - CreateKeyboardSurfaceCallbackData *data = user_data; - EekBounds bounds = squeek_button_get_bounds(button); - - cairo_save (data->cr); - - cairo_translate (data->cr, bounds.x, bounds.y); - cairo_rectangle (data->cr, - 0.0, - 0.0, - bounds.width + 100, - bounds.height + 100); - cairo_clip (data->cr); - struct button_place place = { - .row = data->row, - .button = button, - }; - render_button (data->renderer, data->cr, squeek_view_get_bounds(data->view), &place, FALSE, FALSE); - - cairo_restore (data->cr); -} - -static void -create_keyboard_surface_row_callback (struct squeek_row *row, - gpointer user_data) -{ - CreateKeyboardSurfaceCallbackData *data = user_data; - - EekBounds bounds = squeek_row_get_bounds(row); - - cairo_save (data->cr); - cairo_translate (data->cr, bounds.x, bounds.y); - - gint angle = squeek_row_get_angle (row); - cairo_rotate (data->cr, angle * G_PI / 180); - - data->row = row; - squeek_row_foreach(row, create_keyboard_surface_button_callback, data); - - cairo_restore (data->cr); -} - -static void -render_keyboard_surface (EekRenderer *renderer, struct squeek_view *view) -{ - EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); - - GdkRGBA color = {0}; - gtk_style_context_get_color (priv->view_context, GTK_STATE_FLAG_NORMAL, &color); - - EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard)); - - CreateKeyboardSurfaceCallbackData data = { - .cr = cairo_create (priv->keyboard_surface), - .renderer = renderer, - .view = view, - }; - - /* Paint the background covering the entire widget area */ - gtk_render_background (priv->view_context, - data.cr, - 0, 0, - priv->allocation_width, priv->allocation_height); - gtk_render_frame (priv->view_context, - data.cr, - 0, 0, - priv->allocation_width, priv->allocation_height); - - cairo_save (data.cr); - cairo_scale (data.cr, priv->scale, priv->scale); - cairo_translate (data.cr, bounds.x, bounds.y); - - cairo_set_source_rgba (data.cr, - color.red, - color.green, - color.blue, - color.alpha); - - /* draw rows */ - squeek_view_foreach(level_keyboard_current(priv->keyboard), - create_keyboard_surface_row_callback, - &data); - - cairo_restore (data.cr); - - cairo_destroy (data.cr); -} - static void render_outline (cairo_t *cr, GtkStyleContext *ctx, @@ -190,46 +87,20 @@ render_outline (cairo_t *cr, } static void render_button_in_context(EekRenderer *self, - gdouble scale, gint scale_factor, cairo_t *cr, GtkStyleContext *ctx, - EekBounds view_bounds, - struct button_place *place, - gboolean active) { - cairo_surface_t *outline_surface = NULL; + const struct squeek_button *button) { + /* blank background */ + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0); + cairo_paint (cr); - /* render outline */ - EekBounds bounds = squeek_button_get_bounds(place->button); - - { - cairo_t *cr; - - // Outline will be drawn on the outside of the button, so the - // surface needs to be bigger than the button - outline_surface = - cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - (int)ceil(bounds.width) + 10, - (int)ceil(bounds.height) + 10); - cr = cairo_create (outline_surface); - - /* blank background */ - cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0); - cairo_paint (cr); - - cairo_save (cr); - eek_renderer_apply_transformation_for_button (cr, view_bounds, place, 1.0, FALSE); - render_outline (cr, ctx, bounds); - cairo_restore (cr); - - cairo_destroy (cr); - } - cairo_set_source_surface (cr, outline_surface, 0.0, 0.0); - cairo_surface_destroy(outline_surface); + EekBounds bounds = squeek_button_get_bounds(button); + render_outline (cr, ctx, bounds); cairo_paint (cr); /* render icon (if any) */ - const char *icon_name = squeek_button_get_icon_name(place->button); + const char *icon_name = squeek_button_get_icon_name(button); if (icon_name) { cairo_surface_t *icon_surface = @@ -259,14 +130,13 @@ static void render_button_in_context(EekRenderer *self, return; } } - eek_renderer_render_button_label (self, cr, ctx, place->button); + eek_renderer_render_button_label (self, cr, ctx, button); } -static void -render_button (EekRenderer *self, +void +eek_render_button (EekRenderer *self, cairo_t *cr, - EekBounds view_bounds, - struct button_place *place, + const struct squeek_button *button, gboolean pressed, gboolean locked) { @@ -277,7 +147,7 @@ render_button (EekRenderer *self, from the button's symbol. */ g_autoptr (GtkWidgetPath) path = NULL; path = gtk_widget_path_copy (gtk_style_context_get_path (ctx)); - const char *name = squeek_button_get_name(place->button); + const char *name = squeek_button_get_name(button); gtk_widget_path_iter_set_name (path, -1, name); /* Update the style context with the updated widget path. */ @@ -286,13 +156,13 @@ render_button (EekRenderer *self, (pressed) or normal. */ gtk_style_context_set_state(ctx, pressed ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL); - const char *outline_name = squeek_button_get_outline_name(place->button); + const char *outline_name = squeek_button_get_outline_name(button); if (locked) { gtk_style_context_add_class(ctx, "locked"); } gtk_style_context_add_class(ctx, outline_name); - render_button_in_context(self, priv->scale, priv->scale_factor, cr, ctx, view_bounds, place, pressed); + render_button_in_context(self, priv->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); @@ -302,47 +172,6 @@ render_button (EekRenderer *self, } } -/** - * eek_renderer_apply_transformation_for_key: - * @self: The renderer used to render the key - * @cr: The Cairo rendering context used for rendering - * @key: The key to be transformed - * @scale: The factor used to scale the key bounds before rendering - * @rotate: Whether to rotate the key by the angle defined for the key's - * in its section definition - * - * Applies a transformation, consisting of scaling and rotation, to the - * current rendering context using the bounds for the given key. The scale - * factor is separate to the normal scale factor for the keyboard as a whole - * and is applied cumulatively. It is typically used to render larger than - * normal keys for popups. -*/ -void -eek_renderer_apply_transformation_for_button (cairo_t *cr, - EekBounds view_bounds, - struct button_place *place, - gdouble scale, - gboolean rotate) -{ - EekBounds bounds, rotated_bounds; - gdouble s; - - eek_renderer_get_button_bounds (view_bounds, place, &bounds, FALSE); - eek_renderer_get_button_bounds (view_bounds, place, &rotated_bounds, TRUE); - - gint angle = squeek_row_get_angle (place->row); - - cairo_scale (cr, scale, scale); - if (rotate) { - s = sin (angle * G_PI / 180); - if (s < 0) - cairo_translate (cr, 0, - bounds.width * s); - else - cairo_translate (cr, bounds.height * s, 0); - cairo_rotate (cr, angle * G_PI / 180); - } -} - static void eek_renderer_render_button_label (EekRenderer *self, cairo_t *cr, @@ -415,76 +244,28 @@ eek_renderer_render_button_label (EekRenderer *self, g_object_unref (layout); } -/* - * eek_renderer_real_render_key: - * @self: The renderer used to render the key - * @cr: The Cairo rendering context used for rendering - * @key: The key to be transformed - * @scale: The factor used to scale the key bounds before rendering - * @rotate: Whether to rotate the key by the angle defined for the key's - * in its section definition - * - * Renders a key separately from the normal keyboard rendering. -*/ -static void -eek_renderer_real_render_button (EekRenderer *self, - cairo_t *cr, - struct button_place *place, - gdouble scale, - gboolean rotate) -{ - EekRendererPrivate *priv = eek_renderer_get_instance_private (self); - EekBounds bounds; - - EekBounds view_bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard)); - eek_renderer_get_button_bounds (view_bounds, place, &bounds, rotate); - - cairo_save (cr); - /* Because this function is called separately from the keyboard rendering - function, the transformation for the context needs to be set up */ - cairo_translate (cr, priv->origin_x, priv->origin_y); - cairo_scale (cr, priv->scale, priv->scale); - cairo_translate (cr, bounds.x, bounds.y); - - eek_renderer_apply_transformation_for_button (cr, view_bounds, place, scale, rotate); - struct squeek_key *key = squeek_button_get_key(place->button); - render_button ( - self, cr, view_bounds, place, - squeek_key_is_pressed(key) != 0, - squeek_key_is_locked (key) != 0 - ); - cairo_restore (cr); -} - -static void -eek_renderer_real_render_keyboard (EekRenderer *self, +void +eek_renderer_render_keyboard (EekRenderer *self, cairo_t *cr) { EekRendererPrivate *priv = eek_renderer_get_instance_private (self); - cairo_pattern_t *source; g_return_if_fail (priv->keyboard); g_return_if_fail (priv->allocation_width > 0.0); g_return_if_fail (priv->allocation_height > 0.0); - cairo_save (cr); + /* Paint the background covering the entire widget area */ + gtk_render_background (priv->view_context, + cr, + 0, 0, + priv->allocation_width, priv->allocation_height); - cairo_translate (cr, priv->origin_x, priv->origin_y); - - if (priv->keyboard_surface) - cairo_surface_destroy (priv->keyboard_surface); - - priv->keyboard_surface = cairo_surface_create_for_rectangle ( - cairo_get_target (cr), 0, 0, - priv->allocation_width, priv->allocation_height); - - render_keyboard_surface (self, squeek_layout_get_current_view(priv->keyboard->layout)); - - cairo_set_source_surface (cr, priv->keyboard_surface, 0.0, 0.0); - source = cairo_get_source (cr); - cairo_pattern_set_extend (source, CAIRO_EXTEND_PAD); - cairo_paint (cr); + 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); + squeek_draw_layout_base_view(priv->keyboard->layout, self, cr); + squeek_layout_draw_all_changed(priv->keyboard->layout, self, cr); cairo_restore (cr); } @@ -514,6 +295,7 @@ eek_renderer_get_property (GObject *object, GValue *value, GParamSpec *pspec) { + (void)value; switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -535,8 +317,7 @@ eek_renderer_dispose (GObject *object) priv->pcontext = NULL; } - /* this will release all allocated surfaces and font if any */ - invalidate (EEK_RENDERER(object)); + // this is where renderer-specific surfaces would be released G_OBJECT_CLASS (eek_renderer_parent_class)->dispose (object); } @@ -560,9 +341,6 @@ eek_renderer_class_init (EekRendererClass *klass) GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; - klass->render_button = eek_renderer_real_render_button; - klass->render_keyboard = eek_renderer_real_render_keyboard; - gobject_class->set_property = eek_renderer_set_property; gobject_class->get_property = eek_renderer_get_property; gobject_class->dispose = eek_renderer_dispose; @@ -615,10 +393,8 @@ eek_renderer_init (EekRenderer *self) priv->border_width = 1.0; priv->allocation_width = 0.0; priv->allocation_height = 0.0; - priv->scale = 1.0; priv->scale_factor = 1; priv->font = NULL; - priv->keyboard_surface = NULL; GtkIconTheme *theme = gtk_icon_theme_get_default (); @@ -627,17 +403,6 @@ eek_renderer_init (EekRenderer *self) priv->css_provider = squeek_load_style(); } -static void -invalidate (EekRenderer *renderer) -{ - EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); - - if (priv->keyboard_surface) { - cairo_surface_destroy (priv->keyboard_surface); - priv->keyboard_surface = NULL; - } -} - EekRenderer * eek_renderer_new (LevelKeyboard *keyboard, PangoContext *pcontext) @@ -685,8 +450,6 @@ eek_renderer_set_allocation_size (EekRenderer *renderer, gdouble width, gdouble height) { - gdouble scale; - g_return_if_fail (EEK_IS_RENDERER(renderer)); g_return_if_fail (width > 0.0 && height > 0.0); @@ -695,99 +458,11 @@ eek_renderer_set_allocation_size (EekRenderer *renderer, priv->allocation_width = width; priv->allocation_height = height; - /* Calculate a scale factor to use when rendering the keyboard into the - available space. */ - EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard)); + priv->widget_to_layout = squeek_layout_calculate_transformation( + priv->keyboard->layout, + priv->allocation_width, priv->allocation_height); - gdouble w = (bounds.x * 2) + bounds.width; - gdouble h = (bounds.y * 2) + bounds.height; - - scale = MIN(width / w, height / h); - - priv->scale = scale; - /* Set the rendering offset in widget coordinates to center the keyboard */ - priv->origin_x = (gint)floor((width - (scale * w)) / 2); - priv->origin_y = (gint)floor((height - (scale * h)) / 2); - invalidate (renderer); -} - -void -eek_renderer_get_size (EekRenderer *renderer, - gdouble *width, - gdouble *height) -{ - g_return_if_fail (EEK_IS_RENDERER(renderer)); - - EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); - - EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard)); - if (width) - *width = bounds.width; - if (height) - *height = bounds.height; -} - -void -eek_renderer_get_button_bounds (EekBounds view_bounds, - struct button_place *place, - EekBounds *bounds, - gboolean rotate) -{ - gint angle = 0; - EekPoint points[4], min, max; - - g_return_if_fail (place); - g_return_if_fail (bounds != NULL); - - EekBounds button_bounds = squeek_button_get_bounds(place->button); - EekBounds row_bounds = squeek_row_get_bounds (place->row); - - if (!rotate) { - button_bounds.x += view_bounds.x + row_bounds.x; - button_bounds.y += view_bounds.y + row_bounds.y; - *bounds = button_bounds; - return; - } - points[0].x = button_bounds.x; - points[0].y = button_bounds.y; - points[1].x = points[0].x + button_bounds.width; - points[1].y = points[0].y; - points[2].x = points[1].x; - points[2].y = points[1].y + button_bounds.height; - points[3].x = points[0].x; - points[3].y = points[2].y; - - if (rotate) { - angle = squeek_row_get_angle (place->row); - } - - min = points[2]; - max = points[0]; - for (unsigned i = 0; i < G_N_ELEMENTS(points); i++) { - eek_point_rotate (&points[i], angle); - if (points[i].x < min.x) - min.x = points[i].x; - if (points[i].x > max.x) - max.x = points[i].x; - if (points[i].y < min.y) - min.y = points[i].y; - if (points[i].y > max.y) - max.y = points[i].y; - } - bounds->x = view_bounds.x + row_bounds.x + min.x; - bounds->y = view_bounds.y + row_bounds.y + min.y; - bounds->width = (max.x - min.x); - bounds->height = (max.y - min.y); -} - -gdouble -eek_renderer_get_scale (EekRenderer *renderer) -{ - g_return_val_if_fail (EEK_IS_RENDERER(renderer), 0); - - EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); - - return priv->scale; + // This is where size-dependent surfaces would be released } void @@ -823,29 +498,6 @@ eek_renderer_get_icon_surface (const gchar *icon_name, return surface; } -void -eek_renderer_render_button (EekRenderer *renderer, - cairo_t *cr, - struct button_place *place, - gdouble scale, - gboolean rotate) -{ - g_return_if_fail (EEK_IS_RENDERER(renderer)); - g_return_if_fail (place); - g_return_if_fail (scale >= 0.0); - - EEK_RENDERER_GET_CLASS(renderer)-> - render_button (renderer, cr, place, scale, rotate); -} - -void -eek_renderer_render_keyboard (EekRenderer *renderer, - cairo_t *cr) -{ - g_return_if_fail (EEK_IS_RENDERER(renderer)); - EEK_RENDERER_GET_CLASS(renderer)->render_keyboard (renderer, cr); -} - static gboolean sign (EekPoint *p1, EekPoint *p2, EekPoint *p3) { @@ -899,10 +551,5 @@ eek_renderer_get_transformation (EekRenderer *renderer) { g_return_val_if_fail (EEK_IS_RENDERER(renderer), failed); EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); - struct transformation ret = { - .origin_x = priv->origin_x, - .origin_y = priv->origin_y, - .scale = priv->scale, - }; - return ret; + return priv->widget_to_layout; } diff --git a/eek/eek-renderer.h b/eek/eek-renderer.h index ced11c15..0d46237e 100644 --- a/eek/eek-renderer.h +++ b/eek/eek-renderer.h @@ -25,7 +25,6 @@ #include #include "eek-types.h" -#include "src/layout.h" G_BEGIN_DECLS @@ -36,15 +35,6 @@ struct _EekRendererClass { GObjectClass parent_class; - void (* render_button) (EekRenderer *self, - cairo_t *cr, - struct button_place *place, - gdouble scale, - gboolean rotate); - - void (* render_keyboard) (EekRenderer *self, - cairo_t *cr); - cairo_surface_t *(* get_icon_surface) (EekRenderer *self, const gchar *icon_name, gint size, @@ -62,38 +52,15 @@ void eek_renderer_set_allocation_size (EekRenderer *renderer, gdouble width, gdouble height); -void eek_renderer_get_size (EekRenderer *renderer, - gdouble *width, - gdouble *height); -void eek_renderer_get_button_bounds (EekBounds view_bounds, - struct button_place *button, - EekBounds *bounds, - gboolean rotate); - -gdouble eek_renderer_get_scale (EekRenderer *renderer); void eek_renderer_set_scale_factor (EekRenderer *renderer, gint scale); -void eek_renderer_render_button (EekRenderer *renderer, - cairo_t *cr, - struct button_place *place, - gdouble scale, - gboolean rotate); - cairo_surface_t *eek_renderer_get_icon_surface(const gchar *icon_name, gint size, gint scale); void eek_renderer_render_keyboard (EekRenderer *renderer, cairo_t *cr); -void eek_renderer_set_border_width (EekRenderer *renderer, - gdouble border_width); -void eek_renderer_apply_transformation_for_button - (cairo_t *cr, - EekBounds view_bounds, - struct button_place *place, - gdouble scale, - gboolean rotate); struct transformation eek_renderer_get_transformation (EekRenderer *renderer); diff --git a/eek/eek-types.h b/eek/eek-types.h index db187250..6324094b 100644 --- a/eek/eek-types.h +++ b/eek/eek-types.h @@ -88,5 +88,14 @@ struct transformation { gdouble origin_y; gdouble scale; }; + +struct squeek_button; +struct squeek_row; + +/// Represents the path to the button within a view +struct button_place { + const struct squeek_row *row; + const struct squeek_button *button; +}; G_END_DECLS #endif /* EEK_TYPES_H */ diff --git a/eek/eek-xml-layout.c b/eek/eek-xml-layout.c index fe95e10c..300d463b 100644 --- a/eek/eek-xml-layout.c +++ b/eek/eek-xml-layout.c @@ -24,7 +24,6 @@ #include "config.h" #include "eek-keyboard.h" -#include "src/keyboard.h" #include "src/layout.h" #include "eek-xml-layout.h" diff --git a/src/data.rs b/src/data.rs index 503716ca..cc02948d 100644 --- a/src/data.rs +++ b/src/data.rs @@ -405,7 +405,7 @@ impl Layout { let views = HashMap::from_iter( self.views.iter().map(|(name, view)| {( name.clone(), - Box::new(::layout::View { + ::layout::View { bounds: ::layout::c::Bounds { x: self.bounds.x, y: self.bounds.y, @@ -413,7 +413,7 @@ impl Layout { height: self.bounds.height, }, rows: view.iter().map(|row| { - Box::new(::layout::Row { + ::layout::Row { angle: 0, bounds: None, buttons: row.split_ascii_whitespace().map(|name| { @@ -427,9 +427,9 @@ impl Layout { &mut warning_handler, )) }).collect(), - }) + } }).collect(), - }) + } )}) ); diff --git a/src/drawing.rs b/src/drawing.rs new file mode 100644 index 00000000..dfe19702 --- /dev/null +++ b/src/drawing.rs @@ -0,0 +1,126 @@ +/*! Drawing the UI */ + +use cairo; +use std::cell::RefCell; + +use ::keyboard; +use ::layout::{ Button, Layout }; +use ::layout::c::{ EekGtkKeyboard, Point }; + +use glib::translate::FromGlibPtrNone; +use gtk::WidgetExt; + +mod c { + use super::*; + + use cairo_sys; + use std::os::raw::c_void; + + // This is constructed only in C, no need for warnings + #[allow(dead_code)] + #[repr(transparent)] + #[derive(Clone, Copy)] + pub struct EekRenderer(*const c_void); + + #[no_mangle] + extern "C" { + // Button and View inside CButtonPlace are safe to pass to C + // as long as they don't outlive the call + // and nothing dereferences them + #[allow(improper_ctypes)] + pub fn eek_render_button( + renderer: EekRenderer, + cr: *mut cairo_sys::cairo_t, + button: *const Button, + pressed: u64, + locked: u64, + ); + } + + #[no_mangle] + pub extern "C" + fn squeek_layout_draw_all_changed( + layout: *mut Layout, + renderer: EekRenderer, + cr: *mut cairo_sys::cairo_t, + ) { + let layout = unsafe { &mut *layout }; + let cr = unsafe { cairo::Context::from_raw_none(cr) }; + + let view = layout.get_current_view(); + let view_position = view.bounds.get_position(); + for row in &view.rows { + for button in &row.buttons { + let state = RefCell::borrow(&button.state).clone(); + if state.pressed == keyboard::PressType::Pressed || state.locked { + let position = &view_position + + row.bounds.clone().unwrap().get_position() + + button.bounds.get_position(); + render_button_at_position( + renderer, &cr, + position, button.as_ref(), + state.pressed, state.locked, + ); + } + } + } + } + + #[no_mangle] + pub extern "C" + fn squeek_draw_layout_base_view( + layout: *mut Layout, + renderer: EekRenderer, + cr: *mut cairo_sys::cairo_t, + ) { + let layout = unsafe { &mut *layout }; + let cr = unsafe { cairo::Context::from_raw_none(cr) }; + let view = layout.get_current_view(); + let view_position = view.bounds.get_position(); + for row in &view.rows { + for button in &row.buttons { + let position = &view_position + + row.bounds.clone().unwrap().get_position() + + button.bounds.get_position(); + render_button_at_position( + renderer, &cr, + position, button.as_ref(), + keyboard::PressType::Released, false, + ); + } + } + } +} + +/// Renders a button at a position (button's own bounds ignored) +pub fn render_button_at_position( + renderer: c::EekRenderer, + cr: &cairo::Context, + position: Point, + button: &Button, + pressed: keyboard::PressType, + locked: bool, +) { + cr.save(); + cr.translate(position.x, position.y); + cr.rectangle( + 0.0, 0.0, + button.bounds.width, button.bounds.height + ); + cr.clip(); + unsafe { + c::eek_render_button( + renderer, + cairo::Context::to_raw_none(&cr), + button as *const Button, + pressed as u64, + locked as u64, + ) + }; + cr.restore(); +} + +pub fn queue_redraw(keyboard: EekGtkKeyboard) { + let widget = unsafe { gtk::Widget::from_glib_none(keyboard.0) }; + widget.queue_draw(); +} diff --git a/src/keyboard.h b/src/keyboard.h deleted file mode 100644 index 554fb382..00000000 --- a/src/keyboard.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __KEYBOARD_H -#define __KEYBOARD_H - -#include "inttypes.h" -#include "stdbool.h" -#include "virtual-keyboard-unstable-v1-client-protocol.h" - -struct squeek_key; - -uint32_t squeek_key_is_pressed(struct squeek_key *key); -uint32_t squeek_key_is_locked(struct squeek_key *key); -#endif diff --git a/src/keyboard.rs b/src/keyboard.rs index fdd14078..b64038bb 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -10,32 +10,8 @@ use ::action::Action; use std::io::Write; use std::iter::{ FromIterator, IntoIterator }; -use ::util::CloneOwned; -/// Gathers stuff defined in C or called by C -pub mod c { - use super::*; - use ::util::c; - - pub type CKeyState = c::Wrapped; - - // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers - - #[no_mangle] - pub extern "C" - fn squeek_key_is_pressed(key: CKeyState) -> u32 { - //let key = unsafe { Rc::from_raw(key.0) }; - return key.clone_owned().pressed as u32; - } - - #[no_mangle] - pub extern "C" - fn squeek_key_is_locked(key: CKeyState) -> u32 { - return key.clone_owned().locked as u32; - } -} - -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum PressType { Released = 0, Pressed = 1, diff --git a/src/layout.h b/src/layout.h index c88bea30..45748ecc 100644 --- a/src/layout.h +++ b/src/layout.h @@ -5,8 +5,8 @@ #include #include "eek/eek-element.h" #include "eek/eek-gtk-keyboard.h" +#include "eek/eek-renderer.h" #include "eek/eek-types.h" -#include "src/keyboard.h" #include "virtual-keyboard-unstable-v1-client-protocol.h" enum squeek_arrangement_kind { @@ -14,48 +14,22 @@ enum squeek_arrangement_kind { ARRANGEMENT_KIND_WIDE = 1, }; -struct squeek_button; -struct squeek_row; -struct squeek_view; struct squeek_layout; -/// Represents the path to the button within a view -struct button_place { - const struct squeek_row *row; - const struct squeek_button *button; -}; - -int32_t squeek_row_get_angle(const struct squeek_row*); - -EekBounds squeek_row_get_bounds(const struct squeek_row*); - -typedef void (*ButtonCallback) (struct squeek_button *button, gpointer user_data); -void squeek_row_foreach(struct squeek_row*, - ButtonCallback callback, - gpointer user_data); - EekBounds squeek_button_get_bounds(const struct squeek_button*); const char *squeek_button_get_label(const struct squeek_button*); const char *squeek_button_get_icon_name(const struct squeek_button*); const char *squeek_button_get_name(const struct squeek_button*); const char *squeek_button_get_outline_name(const struct squeek_button*); -struct squeek_key *squeek_button_get_key(const struct squeek_button*); -uint32_t *squeek_button_has_key(const struct squeek_button* button, - const struct squeek_key *key); void squeek_button_print(const struct squeek_button* button); - -EekBounds squeek_view_get_bounds(const struct squeek_view*); - -typedef void (*RowCallback) (struct squeek_row *row, gpointer user_data); -void squeek_view_foreach(struct squeek_view*, - RowCallback callback, - gpointer user_data); +struct transformation squeek_layout_calculate_transformation( + const struct squeek_layout *layout, + double allocation_width, double allocation_size); void squeek_layout_place_contents(struct squeek_layout*); -struct squeek_view *squeek_layout_get_current_view(struct squeek_layout*); struct squeek_layout *squeek_load_layout(const char *name, uint32_t type); const char *squeek_layout_get_keymap(const struct squeek_layout*); @@ -75,5 +49,6 @@ void squeek_layout_drag(struct squeek_layout *layout, struct zwp_virtual_keyboar double x_widget, double y_widget, struct transformation widget_to_layout, uint32_t timestamp, EekGtkKeyboard *ui_keyboard); -void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekGtkKeyboard *ui_keyboard); +void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekRenderer* renderer, cairo_t *cr); +void squeek_draw_layout_base_view(struct squeek_layout *layout, EekRenderer* renderer, cairo_t *cr); #endif diff --git a/src/layout.rs b/src/layout.rs index 27e32cd5..80dcb52c 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -24,6 +24,7 @@ use std::rc::Rc; use std::vec::Vec; use ::action::Action; +use ::drawing; use ::float_ord::FloatOrd; use ::keyboard::{ KeyState, PressType }; use ::submission::{ Timestamp, VirtualKeyboard }; @@ -34,16 +35,14 @@ use std::borrow::Borrow; pub mod c { use super::*; + use gtk_sys; use std::ffi::CStr; use std::os::raw::{ c_char, c_void }; use std::ptr; - use gtk_sys; + + use std::ops::Add; // The following defined in C - - #[repr(transparent)] - pub struct UserData(*const c_void); - #[repr(transparent)] #[derive(Copy, Clone)] pub struct EekGtkKeyboard(pub *const gtk_sys::GtkWidget); @@ -55,10 +54,27 @@ pub mod c { pub x: f64, pub y: f64, } + + impl Add for Point { + type Output = Self; + fn add(self, other: Self) -> Self { + &self + other + } + } + + impl Add for &Point { + type Output = Point; + fn add(self, other: Point) -> Point { + Point { + x: self.x + other.x, + y: self.y + other.y, + } + } + } /// Defined in eek-types.h #[repr(C)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq)] pub struct Bounds { pub x: f64, pub y: f64, @@ -66,62 +82,53 @@ pub mod c { pub height: f64 } - type ButtonCallback = unsafe extern "C" fn(button: *mut ::layout::Button, data: *mut UserData); - type RowCallback = unsafe extern "C" fn(row: *mut ::layout::Row, data: *mut UserData); + impl Bounds { + pub fn get_position(&self) -> Point { + Point { + x: self.x, + y: self.y, + } + } + } + + /// Scale + translate + #[repr(C)] + pub struct Transformation { + pub origin_x: f64, + pub origin_y: f64, + pub scale: f64, + } + + impl Transformation { + fn forward(&self, p: Point) -> Point { + Point { + x: (p.x - self.origin_x) / self.scale, + y: (p.y - self.origin_y) / self.scale, + } + } + fn reverse(&self, p: Point) -> Point { + Point { + x: p.x * self.scale + self.origin_x, + y: p.y * self.scale + self.origin_y, + } + } + pub fn reverse_bounds(&self, b: Bounds) -> Bounds { + let start = self.reverse(Point { x: b.x, y: b.y }); + let end = self.reverse(Point { + x: b.x + b.width, + y: b.y + b.height, + }); + Bounds { + x: start.x, + y: start.y, + width: end.x - start.x, + height: end.y - start.y, + } + } + } // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers - #[no_mangle] - pub extern "C" - fn squeek_view_get_bounds(view: *const ::layout::View) -> Bounds { - unsafe { &*view }.bounds.clone() - } - - #[no_mangle] - pub extern "C" - fn squeek_view_foreach( - view: *mut ::layout::View, - callback: RowCallback, - data: *mut UserData, - ) { - let view = unsafe { &mut *view }; - for row in view.rows.iter_mut() { - let row = row.as_mut() as *mut ::layout::Row; - unsafe { callback(row, data) }; - } - } - - #[no_mangle] - pub extern "C" - fn squeek_row_get_angle(row: *const ::layout::Row) -> i32 { - let row = unsafe { &*row }; - row.angle - } - - #[no_mangle] - pub extern "C" - fn squeek_row_get_bounds(row: *const ::layout::Row) -> Bounds { - let row = unsafe { &*row }; - match &row.bounds { - Some(bounds) => bounds.clone(), - None => panic!("Row doesn't have any bounds yet"), - } - } - - #[no_mangle] - pub extern "C" - fn squeek_row_foreach( - row: *mut ::layout::Row, - callback: ButtonCallback, - data: *mut UserData, - ) { - let row = unsafe { &mut *row }; - for button in row.buttons.iter_mut() { - let button = button.as_mut() as *mut ::layout::Button; - unsafe { callback(button, data) }; - } - } - #[no_mangle] pub extern "C" fn squeek_button_get_bounds(button: *const ::layout::Button) -> Bounds { @@ -129,16 +136,6 @@ pub mod c { button.bounds.clone() } - /// Borrow a new reference to key state. Doesn't need freeing - #[no_mangle] - pub extern "C" - fn squeek_button_get_key( - button: *const ::layout::Button - ) -> ::keyboard::c::CKeyState { - let button = unsafe { &*button }; - ::keyboard::c::CKeyState::wrap(button.state.clone()) - } - #[no_mangle] pub extern "C" fn squeek_button_get_label( @@ -187,16 +184,26 @@ pub mod c { println!("{:?}", button); } + /// Positions the layout within the available space #[no_mangle] pub extern "C" - fn squeek_layout_get_current_view(layout: *const Layout) -> *const View { + fn squeek_layout_calculate_transformation( + layout: *const Layout, + allocation_width: f64, + allocation_height: f64, + ) -> Transformation { let layout = unsafe { &*layout }; - let view_name = layout.current_view.clone(); - layout.views.get(&view_name) - .expect("Current view doesn't exist") - .as_ref() as *const View + let bounds = &layout.get_current_view().bounds; + let h_scale = allocation_width / bounds.width; + let v_scale = allocation_height / bounds.height; + let scale = if h_scale > v_scale { h_scale } else { v_scale }; + Transformation { + origin_x: allocation_width - (scale * bounds.width) / 2.0, + origin_y: allocation_height - (scale * bounds.height) / 2.0, + scale: scale, + } } - + #[no_mangle] pub extern "C" fn squeek_layout_get_keymap(layout: *const Layout) -> *const c_char { @@ -222,7 +229,7 @@ pub mod c { use super::*; use ::submission::c::ZwpVirtualKeyboardV1; - + #[repr(C)] #[derive(PartialEq, Debug)] pub struct CButtonPlace { @@ -238,42 +245,6 @@ pub mod c { } } } - - /// Scale + translate - #[repr(C)] - pub struct Transformation { - origin_x: f64, - origin_y: f64, - scale: f64, - } - - impl Transformation { - fn forward(&self, p: Point) -> Point { - Point { - x: (p.x - self.origin_x) / self.scale, - y: (p.y - self.origin_y) / self.scale, - } - } - fn reverse(&self, p: Point) -> Point { - Point { - x: p.x * self.scale + self.origin_x, - y: p.y * self.scale + self.origin_y, - } - } - pub fn reverse_bounds(&self, b: Bounds) -> Bounds { - let start = self.reverse(Point { x: b.x, y: b.y }); - let end = self.reverse(Point { - x: b.x + b.width, - y: b.y + b.height, - }); - Bounds { - x: start.x, - y: start.y, - width: end.x - start.x, - height: end.y - start.y, - } - } - } // This is constructed only in C, no need for warnings #[allow(dead_code)] @@ -289,34 +260,6 @@ pub mod c { origin: Point, angle: i32 ) -> u32; - - // Button and View are safe to pass to C - // as long as they don't outlive the call - // and nothing dereferences them - #[allow(improper_ctypes)] - pub fn eek_gtk_on_button_released( - button: *const Button, - view: *const View, - keyboard: EekGtkKeyboard, - ); - - // Button and View inside CButtonPlace are safe to pass to C - // as long as they don't outlive the call - // and nothing dereferences them - #[allow(improper_ctypes)] - pub fn eek_gtk_on_button_pressed( - place: CButtonPlace, - keyboard: EekGtkKeyboard, - ); - - // Button and View inside CButtonPlace are safe to pass to C - // as long as they don't outlive the call - // and nothing dereferences them - #[allow(improper_ctypes)] - pub fn eek_gtk_render_locked_button( - keyboard: EekGtkKeyboard, - place: CButtonPlace, - ); } /// Places each button in order, starting from 0 on the left, @@ -356,15 +299,16 @@ pub mod c { // because it will be mutated in the loop for key in layout.pressed_keys.clone() { let key: &Rc> = key.borrow(); - ui::release_key( + seat::handle_release_key( layout, &virtual_keyboard, &widget_to_layout, time, ui_keyboard, - key + key, ); } + drawing::queue_redraw(ui_keyboard); } /// Release all buittons but don't redraw @@ -403,27 +347,16 @@ pub mod c { let point = widget_to_layout.forward( Point { x: x_widget, y: y_widget } ); - - // the immutable reference to `layout` through `view` - // must be dropped - // before `layout.press_key` borrows it mutably again - let state_place = { - let view = layout.get_current_view(); - let place = view.find_button_by_position(point); - place.map(|place| {( - place.button.state.clone(), - place.into(), - )}) - }; - - if let Some((mut state, c_place)) = state_place { + + if let Some(position) = layout.get_button_at_point(point) { + let mut state = position.button.state.clone(); layout.press_key( &VirtualKeyboard(virtual_keyboard), &mut state, Timestamp(time), ); - - unsafe { eek_gtk_on_button_pressed(c_place, ui_keyboard) }; + // maybe TODO: draw on the display buffer here + drawing::queue_redraw(ui_keyboard); } } @@ -449,23 +382,26 @@ pub mod c { ); let pressed = layout.pressed_keys.clone(); - let state_place = { + let button_info = { let view = layout.get_current_view(); let place = view.find_button_by_position(point); place.map(|place| {( place.button.state.clone(), - place.into(), + place.button.clone(), + view.bounds.get_position() + + place.row.bounds.clone().unwrap().get_position() + + place.button.bounds.get_position(), )}) }; - if let Some((mut state, c_place)) = state_place { + if let Some((mut state, _button, _view_position)) = button_info { let mut found = false; for wrapped_key in pressed { let key: &Rc> = wrapped_key.borrow(); if Rc::ptr_eq(&state, &wrapped_key.0) { found = true; } else { - ui::release_key( + seat::handle_release_key( layout, &virtual_keyboard, &widget_to_layout, @@ -477,12 +413,12 @@ pub mod c { } if !found { layout.press_key(&virtual_keyboard, &mut state, time); - unsafe { eek_gtk_on_button_pressed(c_place, ui_keyboard) }; + // maybe TODO: draw on the display buffer here } } else { for wrapped_key in pressed { let key: &Rc> = wrapped_key.borrow(); - ui::release_key( + seat::handle_release_key( layout, &virtual_keyboard, &widget_to_layout, @@ -492,33 +428,7 @@ pub mod c { ); } } - } - - #[no_mangle] - pub extern "C" - fn squeek_layout_draw_all_changed( - layout: *mut Layout, - ui_keyboard: EekGtkKeyboard, - ) { - let layout = unsafe { &mut *layout }; - - for row in &layout.get_current_view().rows { - for button in &row.buttons { - let c_place = CButtonPlace::from( - ButtonPlace { row, button } - ); - let state = RefCell::borrow(&button.state); - match (state.pressed, state.locked) { - (PressType::Released, false) => {} - (PressType::Pressed, _) => unsafe { - eek_gtk_on_button_pressed(c_place, ui_keyboard) - }, - (_, true) => unsafe { - eek_gtk_render_locked_button(ui_keyboard, c_place) - }, - } - } - } + drawing::queue_redraw(ui_keyboard); } #[cfg(test)] @@ -545,6 +455,12 @@ pub mod c { } } +/// Relative to `View` +struct ButtonPosition { + view_position: c::Point, + button: Button, +} + pub struct ButtonPlace<'a> { button: &'a Button, row: &'a Row, @@ -654,7 +570,7 @@ pub struct Spacing { pub struct View { /// Position relative to keyboard origin pub bounds: c::Bounds, - pub rows: Vec>, + pub rows: Vec, } impl View { @@ -749,7 +665,7 @@ pub struct Layout { // Views own the actual buttons which have state // Maybe they should own UI only, // and keys should be owned by a dedicated non-UI-State? - pub views: HashMap>, + pub views: HashMap, // Non-UI stuff /// xkb keymap applicable to the contained keys. Unchangeable @@ -768,7 +684,7 @@ pub struct Layout { /// A builder structure for picking up layout data from storage pub struct LayoutData { - pub views: HashMap>, + pub views: HashMap, pub keymap_str: CString, } @@ -789,7 +705,8 @@ impl Layout { locked_keys: HashSet::new(), } } - fn get_current_view(&self) -> &Box { + + pub fn get_current_view(&self) -> &View { self.views.get(&self.current_view).expect("Selected nonexistent view") } @@ -881,12 +798,24 @@ impl Layout { }; }; } + + fn get_button_at_point(&self, point: c::Point) -> Option { + let view = self.get_current_view(); + let place = view.find_button_by_position(point); + place.map(|place| ButtonPosition { + button: place.button.clone(), + // Rows have no business being inside a view + // if they have no valid bounds. + view_position: place.row.bounds.clone().unwrap().get_position() + + place.button.bounds.get_position(), + }) + } } mod procedures { use super::*; - type Path<'v> = (&'v Box, &'v Box