From e4f80b864bde333b250cd7da6b88e67e86717058 Mon Sep 17 00:00:00 2001 From: Moritz Lipp Date: Tue, 27 Apr 2010 16:07:49 +0200 Subject: [PATCH] Keyboard navigation for the index This patch provides the functionality to browse through the index via the keyboard hence the mouse is not needed anymore. The original author of this patch is int3 , in addition there has been introduced a fix solving problems with named destinations. --- config.def.h | 7 ++ zathura.c | 179 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 143 insertions(+), 43 deletions(-) diff --git a/config.def.h b/config.def.h index 14d97f7..3f9eb25 100644 --- a/config.def.h +++ b/config.def.h @@ -68,6 +68,7 @@ Shortcut shortcuts[] = { {GDK_SHIFT_MASK, GDK_slash, sc_focus_inputbar, NORMAL, { .data = "/" } }, {GDK_SHIFT_MASK, GDK_question, sc_focus_inputbar, NORMAL, { .data = "?" } }, {0, GDK_Tab, sc_toggle_index, NORMAL, {0} }, + {0, GDK_Tab, sc_toggle_index, INDEX, {0} }, {0, GDK_J, sc_navigate, NORMAL, { NEXT } }, {0, GDK_K, sc_navigate, NORMAL, { PREVIOUS } }, {GDK_MOD1_MASK, GDK_Right, sc_navigate, NORMAL, { NEXT } }, @@ -95,6 +96,12 @@ Shortcut shortcuts[] = { {0, GDK_a, sc_adjust_window, NORMAL, { ADJUST_BESTFIT } }, {0, GDK_s, sc_adjust_window, NORMAL, { ADJUST_WIDTH } }, {0, GDK_BackSpace, sc_change_buffer, -1, { DELETE_LAST } }, + {0, GDK_k, sc_navigate_index, INDEX, { UP } }, + {0, GDK_j, sc_navigate_index, INDEX, { DOWN } }, + {0, GDK_h, sc_navigate_index, INDEX, { COLLAPSE } }, + {0, GDK_l, sc_navigate_index, INDEX, { EXPAND } }, + {0, GDK_space, sc_navigate_index, INDEX, { SELECT } }, + {0, GDK_Return, sc_navigate_index, INDEX, { SELECT } }, }; /* inputbar shortcuts */ diff --git a/zathura.c b/zathura.c index 25b6d00..8465622 100644 --- a/zathura.c +++ b/zathura.c @@ -27,7 +27,7 @@ enum { NEXT, PREVIOUS, LEFT, RIGHT, UP, DOWN, ZOOM_IN, ZOOM_OUT, ZOOM_ORIGINAL, ZOOM_SPECIFIC, FORWARD, BACKWARD, ADJUST_BESTFIT, ADJUST_WIDTH, ADJUST_NONE, CONTINUOUS, DELETE_LAST, ADD_MARKER, - EVAL_MARKER }; + EVAL_MARKER, INDEX, EXPAND, COLLAPSE, SELECT }; /* typedefs */ struct CElement @@ -288,6 +288,7 @@ void sc_recolor(Argument*); void sc_rotate(Argument*); void sc_scroll(Argument*); void sc_search(Argument*); +void sc_navigate_index(Argument*); void sc_toggle_index(Argument*); void sc_toggle_inputbar(Argument*); void sc_toggle_statusbar(Argument*); @@ -333,7 +334,7 @@ gboolean scmd_search(char*, Argument*); /* callback declarations */ gboolean cb_destroy(GtkWidget*, gpointer); gboolean cb_draw(GtkWidget*, GdkEventExpose*, gpointer); -gboolean cb_index_selection_changed(GtkTreeSelection*, GtkWidget*); +gboolean cb_index_row_activated(GtkTreeView*, GtkTreePath*, GtkTreeViewColumn*, gpointer); gboolean cb_inputbar_kb_pressed(GtkWidget*, GdkEventKey*, gpointer); gboolean cb_inputbar_activate(GtkEntry*, gpointer); gboolean cb_inputbar_form_activate(GtkEntry*, gpointer); @@ -1089,10 +1090,10 @@ search(void* parameter) g_static_mutex_lock(&(Zathura.Lock.document_lock)); if(!Zathura.PDF.document || !search_item || !strlen(search_item)) { + g_static_mutex_lock(&(Zathura.Lock.document_lock)); g_static_mutex_lock(&(Zathura.Lock.search_lock)); Zathura.Thread.search_thread_running = FALSE; g_static_mutex_unlock(&(Zathura.Lock.search_lock)); - g_static_mutex_lock(&(Zathura.Lock.document_lock)); g_thread_exit(NULL); } g_static_mutex_unlock(&(Zathura.Lock.document_lock)); @@ -1101,6 +1102,9 @@ search(void* parameter) if(argument->n) direction = (argument->n == BACKWARD) ? -1 : 1; + int number_of_pages = Zathura.PDF.number_of_pages; + int page_number = Zathura.PDF.page_number; + for(page_counter = 1; page_counter <= Zathura.PDF.number_of_pages; page_counter++) { g_static_mutex_lock(&(Zathura.Lock.search_lock)); @@ -1111,9 +1115,8 @@ search(void* parameter) } g_static_mutex_unlock(&(Zathura.Lock.search_lock)); - // probably should wrap this in a mutex, but I'm lazy - next_page = (Zathura.PDF.number_of_pages + Zathura.PDF.page_number + - page_counter * direction) % Zathura.PDF.number_of_pages; + next_page = (number_of_pages + page_number + + page_counter * direction) % number_of_pages; g_static_mutex_lock(&(Zathura.Lock.pdflib_lock)); PopplerPage* page = poppler_document_get_page(Zathura.PDF.document, next_page); @@ -1152,7 +1155,7 @@ search(void* parameter) g_static_mutex_unlock(&(Zathura.Lock.search_lock)); g_thread_exit(NULL); - return NULL; // suppress GCC warnings about return value + return NULL; } void* @@ -1431,6 +1434,124 @@ sc_search(Argument* argument) g_static_mutex_unlock(&(Zathura.Lock.search_lock)); } +gboolean cb_index_row_activated(GtkTreeView* treeview, GtkTreePath* path, + GtkTreeViewColumn* column, gpointer user_data) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + g_object_get(treeview, "model", &model, NULL); + + if(gtk_tree_model_get_iter(model, &iter, path)) + { + PopplerAction* action; + PopplerDest* destination; + + gtk_tree_model_get(model, &iter, 1, &action, -1); + if(!action) + return TRUE; + + if(action->type == POPPLER_ACTION_GOTO_DEST) + { + destination = action->goto_dest.dest; + int page_number = destination->page_num; + + if(action->goto_dest.dest->type == POPPLER_DEST_NAMED) + { + PopplerDest* d = poppler_document_find_dest(Zathura.PDF.document, action->goto_dest.dest->named_dest); + if(d) + { + page_number = d->page_num; + poppler_dest_free(d); + } + } + + set_page(page_number - 1); + update_status(); + gtk_widget_grab_focus(GTK_WIDGET(Zathura.UI.view)); + } + } + + Zathura.Global.mode = NORMAL; + g_object_unref(model); + + return TRUE; +} + +void +sc_navigate_index(Argument* argument) +{ + GtkTreeView *treeview = gtk_container_get_children(GTK_CONTAINER(Zathura.UI.index))->data; + GtkTreePath *path; + + gtk_tree_view_get_cursor(treeview, &path, NULL); + if(!path) + return; + + GtkTreeModel *model = gtk_tree_view_get_model(treeview); + GtkTreeIter iter; + GtkTreeIter child_iter; + + gboolean is_valid_path = TRUE; + + switch(argument->n) + { + case UP: + if(!gtk_tree_path_prev(path)) + is_valid_path = gtk_tree_path_up(path); + else /* row above */ + { + while(gtk_tree_view_row_expanded(treeview, path)) { + gtk_tree_model_get_iter(model, &iter, path); + /* select last child */ + gtk_tree_model_iter_nth_child(model, &child_iter, &iter, + gtk_tree_model_iter_n_children(model, &iter)-1); + gtk_tree_path_free(path); + path = gtk_tree_model_get_path(model, &child_iter); + } + } + break; + case COLLAPSE: + if(!gtk_tree_view_collapse_row(treeview, path) + && gtk_tree_path_get_depth(path) > 1) + { + gtk_tree_path_up(path); + gtk_tree_view_collapse_row(treeview, path); + } + break; + case DOWN: + if(gtk_tree_view_row_expanded(treeview, path)) + gtk_tree_path_down(path); + else + { + do + { + gtk_tree_model_get_iter(model, &iter, path); + if (gtk_tree_model_iter_next(model, &iter)) + { + path = gtk_tree_model_get_path(model, &iter); + break; + } + } + while((is_valid_path = (gtk_tree_path_get_depth(path) > 1)) + && gtk_tree_path_up(path)); + } + break; + case EXPAND: + if(gtk_tree_view_expand_row(treeview, path, FALSE)) + gtk_tree_path_down(path); + break; + case SELECT: + cb_index_row_activated(treeview, path, NULL, NULL); + return; + } + + if (is_valid_path) + gtk_tree_view_set_cursor(treeview, path, NULL, FALSE); + + gtk_tree_path_free(path); +} + void sc_toggle_index(Argument* argument) { @@ -1440,7 +1561,6 @@ sc_toggle_index(Argument* argument) GtkWidget *treeview; GtkTreeModel *model; GtkCellRenderer *renderer; - GtkTreeSelection *selection; PopplerIndexIter *iter; if(!Zathura.UI.index) @@ -1473,9 +1593,8 @@ sc_toggle_index(Argument* argument) g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL); g_object_set(G_OBJECT(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 0)), "expand", TRUE, NULL); - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - gtk_tree_selection_select_path(selection, gtk_tree_path_new_first()); - g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(cb_index_selection_changed), NULL); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(treeview), gtk_tree_path_new_first(), NULL, FALSE); + g_signal_connect(G_OBJECT(treeview), "row-activated", G_CALLBACK(cb_index_row_activated), NULL); gtk_container_add (GTK_CONTAINER (Zathura.UI.index), treeview); gtk_widget_show (treeview); @@ -1484,9 +1603,15 @@ sc_toggle_index(Argument* argument) static gboolean show = FALSE; if(!show) + { switch_view(Zathura.UI.index); + Zathura.Global.mode = INDEX; + } else + { switch_view(Zathura.UI.drawing_area); + Zathura.Global.mode = NORMAL; + } show = !show; } @@ -2783,38 +2908,6 @@ gboolean cb_draw(GtkWidget* widget, GdkEventExpose* expose, gpointer data) return TRUE; } -gboolean -cb_index_selection_changed(GtkTreeSelection* treeselection, GtkWidget* action_view) -{ - GtkTreeModel *model; - GtkTreeIter iter; - - if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) - { - PopplerAction* action; - PopplerDest* destination; - - gtk_tree_model_get(model, &iter, 1, &action, -1); - if(!action) - return TRUE; - - if(action->type == POPPLER_ACTION_GOTO_DEST) - { - destination = action->goto_dest.dest; - int page_number = destination->page_num; - - if(page_number >= 0 && page_number <= Zathura.PDF.number_of_pages) - { - set_page(page_number - 1); - update_status(); - gtk_widget_grab_focus(GTK_WIDGET(Zathura.UI.view)); - } - } - } - - return TRUE; -} - gboolean cb_inputbar_kb_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data) {