diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index f967c530..58badc2e 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -77,6 +77,8 @@ static void on_symbol_index_changed (EekKeyboard *keyboard, gpointer user_data); static void render_pressed_key (GtkWidget *widget, EekKey *key); +static void render_released_key (GtkWidget *widget, + EekKey *key); static void eek_gtk_keyboard_real_realize (GtkWidget *self) @@ -181,19 +183,6 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self, size_allocate (self, allocation); } -static void -set_dragged_key (EekGtkKeyboard *keyboard, EekKey *key) -{ - EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard); - - if (priv->dragged_key && priv->dragged_key != key) - g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard); - if (key && !eek_key_is_pressed (key)) { - priv->dragged_key = key; - g_signal_emit_by_name (key, "pressed", priv->keyboard); - } -} - static gboolean eek_gtk_keyboard_real_button_press_event (GtkWidget *self, GdkEventButton *event) @@ -204,27 +193,23 @@ eek_gtk_keyboard_real_button_press_event (GtkWidget *self, key = eek_renderer_find_key_by_position (priv->renderer, (gdouble)event->x, (gdouble)event->y); - - set_dragged_key (EEK_GTK_KEYBOARD(self), key); - return TRUE; -} - -static void -clear_dragged_key (EekGtkKeyboard *keyboard) -{ - EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard); - - if (priv->dragged_key) { - g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard); - priv->dragged_key = NULL; + if (key && key != priv->dragged_key) { + priv->dragged_key = key; + g_signal_emit_by_name (key, "pressed", priv->keyboard); } + return TRUE; } static gboolean eek_gtk_keyboard_real_button_release_event (GtkWidget *self, GdkEventButton *event) { - clear_dragged_key (EEK_GTK_KEYBOARD(self)); + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); + + if (priv->dragged_key) { + g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard); + priv->dragged_key = NULL; + } return TRUE; } @@ -238,14 +223,24 @@ eek_gtk_keyboard_real_motion_notify_event (GtkWidget *self, key = eek_renderer_find_key_by_position (priv->renderer, (gdouble)event->x, (gdouble)event->y); - set_dragged_key (EEK_GTK_KEYBOARD(self), key); + if (key && key != priv->dragged_key) { + if (priv->dragged_key) + render_released_key (GTK_WIDGET(self), priv->dragged_key); + priv->dragged_key = key; + g_signal_emit_by_name (key, "pressed", priv->keyboard); + } return TRUE; } static void eek_gtk_keyboard_real_unmap (GtkWidget *self) { - clear_dragged_key (EEK_GTK_KEYBOARD(self)); + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); + + if (priv->dragged_key) { + g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard); + priv->dragged_key = NULL; + } GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->unmap (self); } @@ -451,6 +446,34 @@ render_pressed_key (GtkWidget *widget, cairo_destroy (cr); } +static void +render_released_key (GtkWidget *widget, + EekKey *key) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); + EekBounds bounds, large_bounds; + cairo_t *cr; + + cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget))); + + eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE); + magnify_bounds (widget, &bounds, &large_bounds, 2.0); + cairo_rectangle (cr, + large_bounds.x, + large_bounds.y, + large_bounds.width, + large_bounds.height); + cairo_rectangle (cr, + bounds.x, + bounds.y, + bounds.width, + bounds.height); + cairo_clip (cr); + + eek_renderer_render_keyboard (priv->renderer, cr); + cairo_destroy (cr); +} + static void on_key_pressed (EekKeyboard *keyboard, EekKey *key, @@ -473,32 +496,12 @@ on_key_released (EekKeyboard *keyboard, { GtkWidget *widget = user_data; EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); - cairo_t *cr; - EekBounds bounds, large_bounds; /* renderer may have not been set yet if the widget is a popup */ if (!priv->renderer) return; - cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget))); - - eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE); - magnify_bounds (widget, &bounds, &large_bounds, 2.0); - cairo_rectangle (cr, - large_bounds.x, - large_bounds.y, - large_bounds.width, - large_bounds.height); - cairo_rectangle (cr, - bounds.x, - bounds.y, - bounds.width, - bounds.height); - cairo_clip (cr); - - eek_renderer_render_keyboard (priv->renderer, cr); - cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); - cairo_destroy (cr); + render_released_key (widget, key); } static void diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index 422ce75d..0d4b4164 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -748,6 +748,21 @@ eek_keyboard_get_modifier_behavior (EekKeyboard *keyboard) return priv->modifier_behavior; } +void +eek_keyboard_set_modifiers (EekKeyboard *keyboard, + EekModifierType modifiers) +{ + EekKeyboardPrivate *priv; + + g_assert (EEK_IS_KEYBOARD(keyboard)); + priv = EEK_KEYBOARD_GET_PRIVATE(keyboard); + + priv->modifiers = modifiers; + set_level_from_modifiers (keyboard); + + return priv->modifiers; +} + /** * eek_keyboard_get_modifiers: * @keyboard: an #EekKeyboard diff --git a/eek/eek-keyboard.h b/eek/eek-keyboard.h index 265f9666..3c521730 100644 --- a/eek/eek-keyboard.h +++ b/eek/eek-keyboard.h @@ -135,6 +135,9 @@ void eek_keyboard_set_modifier_behavior EekModifierBehavior modifier_behavior); EekModifierBehavior eek_keyboard_get_modifier_behavior (EekKeyboard *keyboard); +void eek_keyboard_set_modifiers + (EekKeyboard *keyboard, + EekModifierType modifiers); EekModifierType eek_keyboard_get_modifiers (EekKeyboard *keyboard); diff --git a/eek/eek-renderer.c b/eek/eek-renderer.c index 187f39c3..942376bc 100644 --- a/eek/eek-renderer.c +++ b/eek/eek-renderer.c @@ -87,7 +87,8 @@ static void eek_renderer_real_render_key_label (EekRenderer *self, static void invalidate (EekRenderer *renderer); static void render_key (EekRenderer *self, cairo_t *cr, - EekKey *key); + EekKey *key, + gboolean active); static void on_symbol_index_changed (EekKeyboard *keyboard, gint group, gint level, @@ -117,7 +118,7 @@ create_keyboard_surface_key_callback (EekElement *element, bounds.width * priv->scale, bounds.height * priv->scale); cairo_clip (data->cr); - render_key (data->renderer, data->cr, EEK_KEY(element)); + render_key (data->renderer, data->cr, EEK_KEY(element), FALSE); cairo_restore (data->cr); } @@ -197,7 +198,8 @@ create_keyboard_surface (EekRenderer *renderer) static void render_key_outline (EekRenderer *renderer, cairo_t *cr, - EekKey *key) + EekKey *key, + gboolean active) { EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(renderer); EekOutline *outline; @@ -215,10 +217,10 @@ render_key_outline (EekRenderer *renderer, if (oref == 0) return; - if (eek_key_is_pressed (key)) - theme_node = g_object_get_data (G_OBJECT(key), "theme-node-pressed"); - else - theme_node = g_object_get_data (G_OBJECT(key), "theme-node"); + theme_node = g_object_get_data (G_OBJECT(key), + active ? + "theme-node-pressed" : + "theme-node"); if (theme_node) { eek_theme_node_get_foreground_color (theme_node, &foreground); eek_theme_node_get_background_color (theme_node, &background); @@ -428,7 +430,8 @@ calculate_font_size (EekRenderer *renderer, static void render_key (EekRenderer *self, cairo_t *cr, - EekKey *key) + EekKey *key, + gboolean active) { EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(self); EekOutline *outline; @@ -443,7 +446,7 @@ render_key (EekRenderer *self, if (oref == 0) return; - if (eek_key_is_pressed (key)) + if (active) outline_surface_cache = priv->active_outline_surface_cache; else outline_surface_cache = priv->outline_surface_cache; @@ -463,7 +466,11 @@ render_key (EekRenderer *self, cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0); cairo_paint (cr); - eek_renderer_render_key_outline (self, cr, key, 1.0, 0); + cairo_save (cr); + eek_renderer_apply_transformation_for_key (self, cr, key, 1.0, FALSE); + render_key_outline (self, cr, key, active); + cairo_restore (cr); + cairo_destroy (cr); g_hash_table_insert (outline_surface_cache, @@ -625,7 +632,7 @@ eek_renderer_real_render_key_outline (EekRenderer *self, { cairo_save (cr); eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate); - render_key_outline (self, cr, key); + render_key_outline (self, cr, key, eek_key_is_pressed (key)); cairo_restore (cr); } @@ -638,7 +645,7 @@ eek_renderer_real_render_key (EekRenderer *self, { cairo_save (cr); eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate); - render_key (self, cr, key); + render_key (self, cr, key, eek_key_is_pressed (key)); cairo_restore (cr); } diff --git a/src/server-context.c b/src/server-context.c index 75d7c9f9..30c83703 100644 --- a/src/server-context.c +++ b/src/server-context.c @@ -122,6 +122,7 @@ struct _ServerContext { EekKey *repeat_key; guint repeat_timeout_id; + gboolean repeat_triggered; GSettings *settings; ServerContextUIToolkitType ui_toolkit; @@ -606,8 +607,8 @@ server_context_init (ServerContext *context) static gboolean on_repeat_timeout (ServerContext *context); -static gboolean -on_repeat_timeout (ServerContext *context) +static void +emit_press_release_dbus_signal (ServerContext *context) { if (context->connection && context->enabled) { guint keycode = eek_key_get_keycode (context->repeat_key); @@ -632,13 +633,42 @@ on_repeat_timeout (ServerContext *context) g_variant_new ("(u)", keycode), &error); g_assert_no_error (error); + } +} +static gboolean +on_repeat_timeout (ServerContext *context) +{ + gint delay = g_settings_get_int (context->settings, "repeat-interval"); + + emit_press_release_dbus_signal (context); + + context->repeat_timeout_id = + g_timeout_add (delay, + (GSourceFunc)on_repeat_timeout, + context); + + return FALSE; +} + +static gboolean +on_repeat_timeout_init (ServerContext *context) +{ + emit_press_release_dbus_signal (context); + + /* FIXME: clear modifiers for further key repeat; better not + depend on modifier behavior is LATCH */ + eek_keyboard_set_modifiers (context->keyboard, 0); + + /* reschedule repeat timeout only when "repeat" option is set */ + if (g_settings_get_boolean (context->settings, "repeat")) { gint delay = g_settings_get_int (context->settings, "repeat-interval"); context->repeat_timeout_id = g_timeout_add (delay, (GSourceFunc)on_repeat_timeout, context); - } + } else + context->repeat_timeout_id = 0; return FALSE; } @@ -649,35 +679,18 @@ on_key_pressed (EekKeyboard *keyboard, gpointer user_data) { ServerContext *context = user_data; + gint delay = g_settings_get_int (context->settings, "repeat-delay"); if (context->repeat_timeout_id) { g_source_remove (context->repeat_timeout_id); context->repeat_timeout_id = 0; } - if (context->connection && context->enabled) { - guint keycode = eek_key_get_keycode (key); - GError *error; - - error = NULL; - g_dbus_connection_emit_signal (context->connection, - NULL, - context->object_path, - SERVER_CONTEXT_INTERFACE, - "KeyPressed", - g_variant_new ("(u)", keycode), - &error); - g_assert_no_error (error); - - if (g_settings_get_boolean (context->settings, "repeat")) { - gint delay = g_settings_get_int (context->settings, "repeat-delay"); - context->repeat_key = key; - context->repeat_timeout_id = - g_timeout_add (delay, - (GSourceFunc)on_repeat_timeout, - context); - } - } + context->repeat_key = key; + context->repeat_timeout_id = + g_timeout_add (delay, + (GSourceFunc)on_repeat_timeout_init, + context); } static void @@ -686,16 +699,30 @@ on_key_released (EekKeyboard *keyboard, gpointer user_data) { ServerContext *context = user_data; + gboolean need_key_press = FALSE; - if (context->repeat_timeout_id) { + if (context->repeat_timeout_id > 0) { g_source_remove (context->repeat_timeout_id); context->repeat_timeout_id = 0; + need_key_press = TRUE; } if (context->connection && context->enabled) { guint keycode = eek_key_get_keycode (key); GError *error; + if (need_key_press) { + error = NULL; + g_dbus_connection_emit_signal (context->connection, + NULL, + context->object_path, + SERVER_CONTEXT_INTERFACE, + "KeyPressed", + g_variant_new ("(u)", keycode), + &error); + g_assert_no_error (error); + } + error = NULL; g_dbus_connection_emit_signal (context->connection, NULL,