From 6740baaa2eb9ee0b5dec91cded20f95ca88af3a9 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Wed, 19 Jun 2013 12:10:56 +0200 Subject: libview: Use GtkBindings for caret navigation This allows themes to override the key bindings and API users to move the caret cursor programmatically using g_signal_emit_by_name. origin commit: https://git.gnome.org/browse/evince/commit/?h=gnome-3-10&id=1206ff1 --- libview/ev-view-marshal.list | 1 + libview/ev-view-private.h | 40 +++++++++------ libview/ev-view.c | 120 ++++++++++++++++++++++++++++++++----------- 3 files changed, 114 insertions(+), 47 deletions(-) diff --git a/libview/ev-view-marshal.list b/libview/ev-view-marshal.list index fad49248..0ead4025 100644 --- a/libview/ev-view-marshal.list +++ b/libview/ev-view-marshal.list @@ -1,2 +1,3 @@ VOID:ENUM,ENUM VOID:INT,INT +BOOLEAN:ENUM,INT diff --git a/libview/ev-view-private.h b/libview/ev-view-private.h index 14221175..696a043f 100644 --- a/libview/ev-view-private.h +++ b/libview/ev-view-private.h @@ -178,6 +178,9 @@ struct _EvView { /* Common for button press handling */ int pressed_button; + /* Key bindings propagation */ + gboolean key_binding_handled; + /* Information for middle clicking and dragging around. */ DragInfo drag_info; @@ -236,23 +239,26 @@ struct _EvView { struct _EvViewClass { GtkContainerClass parent_class; - void (*scroll) (EvView *view, - GtkScrollType scroll, - GtkOrientation orientation); - void (*handle_link) (EvView *view, - EvLink *link); - void (*external_link) (EvView *view, - EvLinkAction *action); - void (*popup_menu) (EvView *view, - GList *items); - void (*selection_changed) (EvView *view); - void (*sync_source) (EvView *view, - EvSourceLink *link); - void (*annot_added) (EvView *view, - EvAnnotation *annot); - void (*annot_removed) (EvView *view, - EvAnnotation *annot); - void (*layers_changed) (EvView *view); + void (*scroll) (EvView *view, + GtkScrollType scroll, + GtkOrientation orientation); + void (*handle_link) (EvView *view, + EvLink *link); + void (*external_link) (EvView *view, + EvLinkAction *action); + void (*popup_menu) (EvView *view, + GList *items); + void (*selection_changed) (EvView *view); + void (*sync_source) (EvView *view, + EvSourceLink *link); + void (*annot_added) (EvView *view, + EvAnnotation *annot); + void (*annot_removed) (EvView *view, + EvAnnotation *annot); + void (*layers_changed) (EvView *view); + gboolean (*move_cursor) (EvView *view, + GtkMovementStep step, + gint count); }; void _get_page_size_for_scale_and_rotation (EvDocument *document, diff --git a/libview/ev-view.c b/libview/ev-view.c index 84ee1487..4f32136a 100644 --- a/libview/ev-view.c +++ b/libview/ev-view.c @@ -59,6 +59,7 @@ enum { SIGNAL_ANNOT_ADDED, SIGNAL_ANNOT_REMOVED, SIGNAL_LAYERS_CHANGED, + SIGNAL_MOVE_CURSOR, N_SIGNALS }; @@ -945,6 +946,9 @@ ev_view_scroll (EvView *view, gboolean first_page = FALSE; gboolean last_page = FALSE; + if (view->key_binding_handled) + return; + view->jump_to_find_result = FALSE; if ((!horizontal && ev_view_page_fits (view, GTK_ORIENTATION_VERTICAL)) || @@ -5187,48 +5191,61 @@ cursor_forward_line (EvView *view) } static gboolean -caret_key_press_event (EvView *view, - GdkEventKey *event) +ev_view_move_cursor (EvView *view, + GtkMovementStep step, + gint count) { gint prev_offset; gint prev_page; - /* Disable caret navigation on rotated pages */ - if (view->rotation != 0) + if (!view->caret_enabled || view->rotation != 0) return FALSE; + view->key_binding_handled = TRUE; view->cursor_blink_time = 0; prev_offset = view->cursor_offset; prev_page = view->cursor_page; - switch (event->keyval) { - case GDK_KEY_Left: - if (event->state & GDK_CONTROL_MASK) - cursor_backward_word_start (view); - else + switch (step) { + case GTK_MOVEMENT_VISUAL_POSITIONS: + while (count > 0) { + cursor_forward_char (view); + count--; + } + while (count < 0) { cursor_backward_char (view); + count++; + } break; - case GDK_KEY_Right: - if (event->state & GDK_CONTROL_MASK) + case GTK_MOVEMENT_WORDS: + while (count > 0) { cursor_forward_word_end (view); - else - cursor_forward_char (view); - break; - case GDK_KEY_Up: - cursor_backward_line (view); - break; - case GDK_KEY_Down: - cursor_forward_line (view); + count--; + } + while (count < 0) { + cursor_backward_word_start (view); + count++; + } break; - case GDK_KEY_Home: - cursor_go_to_line_start (view); + case GTK_MOVEMENT_DISPLAY_LINES: + while (count > 0) { + cursor_forward_line (view); + count--; + } + while (count < 0) { + cursor_backward_line (view); + count++; + } break; - case GDK_KEY_End: - cursor_go_to_line_end (view); + case GTK_MOVEMENT_DISPLAY_LINE_ENDS: + if (count > 0) + cursor_go_to_line_end (view); + else if (count < 0) + cursor_go_to_line_start (view); break; default: - return FALSE; + g_assert_not_reached (); } ev_view_pend_cursor_blink (view); @@ -5237,7 +5254,7 @@ caret_key_press_event (EvView *view, if (prev_offset != view->cursor_offset || prev_page != view->cursor_page) { GdkRectangle view_rect; - /* scroll to view the text caret */ + /* scroll to view the caret cursor */ if (!get_caret_cursor_rect_from_offset (view, view->cursor_offset, view->cursor_page, &view_rect)) return TRUE; @@ -5253,18 +5270,23 @@ static gboolean ev_view_key_press_event (GtkWidget *widget, GdkEventKey *event) { - EvView *view = EV_VIEW (widget); + EvView *view = EV_VIEW (widget); + gboolean retval; if (!view->document) return FALSE; - if (view->caret_enabled && caret_key_press_event (view, event)) - return TRUE; - if (!gtk_widget_has_focus (widget)) return ev_view_forward_key_event_to_focused_child (view, event); - return gtk_bindings_activate_event (G_OBJECT (widget), event); + /* I expected GTK+ do this for me, but it doesn't cancel + * the propagation of bindings handled for the same binding set + */ + view->key_binding_handled = FALSE; + retval = gtk_bindings_activate_event (G_OBJECT (widget), event); + view->key_binding_handled = FALSE; + + return retval; } static gint @@ -5942,6 +5964,25 @@ ev_view_parent_set (GtkWidget *widget, g_assert (!parent || GTK_IS_SCROLLED_WINDOW (parent)); } +static void +add_move_binding_keypad (GtkBindingSet *binding_set, + guint keyval, + GdkModifierType modifiers, + GtkMovementStep step, + gint count) +{ + guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left; + + gtk_binding_entry_add_signal (binding_set, keyval, modifiers, + "move-cursor", 2, + GTK_TYPE_MOVEMENT_STEP, step, + G_TYPE_INT, count); + gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers, + "move-cursor", 2, + GTK_TYPE_MOVEMENT_STEP, step, + G_TYPE_INT, count); +} + static void ev_view_class_init (EvViewClass *class) { @@ -5987,6 +6028,7 @@ ev_view_class_init (EvViewClass *class) container_class->forall = ev_view_forall; class->scroll = ev_view_scroll_internal; + class->move_cursor = ev_view_move_cursor; /* Scrollable interface */ g_object_class_override_property (object_class, PROP_HADJUSTMENT, "hadjustment"); @@ -6067,9 +6109,27 @@ ev_view_class_init (EvViewClass *class) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + signals[SIGNAL_MOVE_CURSOR] = g_signal_new ("move-cursor", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvViewClass, move_cursor), + NULL, NULL, + ev_view_marshal_BOOLEAN__ENUM_INT, + G_TYPE_BOOLEAN, 2, + GTK_TYPE_MOVEMENT_STEP, + G_TYPE_INT); binding_set = gtk_binding_set_by_class (class); + add_move_binding_keypad (binding_set, GDK_KEY_Left, 0, GTK_MOVEMENT_VISUAL_POSITIONS, -1); + add_move_binding_keypad (binding_set, GDK_KEY_Right, 0, GTK_MOVEMENT_VISUAL_POSITIONS, 1); + add_move_binding_keypad (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, -1); + add_move_binding_keypad (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, 1); + add_move_binding_keypad (binding_set, GDK_KEY_Up, 0, GTK_MOVEMENT_DISPLAY_LINES, -1); + add_move_binding_keypad (binding_set, GDK_KEY_Down, 0, GTK_MOVEMENT_DISPLAY_LINES, 1); + add_move_binding_keypad (binding_set, GDK_KEY_Home, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); + add_move_binding_keypad (binding_set, GDK_KEY_End, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); + add_scroll_binding_keypad (binding_set, GDK_KEY_Left, 0, GTK_SCROLL_STEP_BACKWARD, GTK_ORIENTATION_HORIZONTAL); add_scroll_binding_keypad (binding_set, GDK_KEY_Right, 0, GTK_SCROLL_STEP_FORWARD, GTK_ORIENTATION_HORIZONTAL); add_scroll_binding_keypad (binding_set, GDK_KEY_Left, GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, GTK_ORIENTATION_HORIZONTAL); -- cgit v1.2.1