diff --git a/callbacks.c b/callbacks.c index 9e7d208..b0021ba 100644 --- a/callbacks.c +++ b/callbacks.c @@ -177,7 +177,10 @@ cb_index_row_activated(GtkTreeView* tree_view, GtkTreePath* path, } sc_toggle_index(zathura->ui.session, NULL, NULL, 0); + + /* zathura_jumplist_save is called when entering index mode */ zathura_link_evaluate(zathura, index_element->link); + zathura_jumplist_add(zathura); } g_object_unref(model); @@ -221,9 +224,12 @@ cb_sc_follow(GtkEntry* entry, girara_session_t* session) if (eval == true) { zathura_link_t* link = zathura_page_widget_link_get(ZATHURA_PAGE(page_widget), index); + if (link != NULL) { + zathura_jumplist_save(zathura); zathura_link_evaluate(zathura, link); invalid_index = false; + zathura_jumplist_add(zathura); } } } @@ -404,7 +410,9 @@ cb_unknown_command(girara_session_t* session, const char* input) } } + zathura_jumplist_save(zathura); page_set(zathura, atoi(input) - 1); + zathura_jumplist_add(zathura); return true; } diff --git a/config.c b/config.c index 84cf3d7..6d955ce 100644 --- a/config.c +++ b/config.c @@ -18,6 +18,21 @@ #include #include +static void +cb_jumplist_change(girara_session_t* session, const char* name, + girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) +{ + g_return_if_fail(value != NULL); + g_return_if_fail(session != NULL); + g_return_if_fail(session->global.data != NULL); + g_return_if_fail(name != NULL); + zathura_t* zathura = session->global.data; + if (g_strcmp0(name, "jumplist-size") == 0) { + size_t *max_size = (size_t*) value; + zathura->jumplist.max_size = *max_size; + } +} + static void cb_color_change(girara_session_t* session, const char* name, girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) @@ -122,6 +137,8 @@ config_load_default(zathura_t* zathura) int_value = 20; girara_setting_add(gsession, "page-store-threshold", &int_value, INT, false, _("Life time (in seconds) of a hidden page"), NULL, NULL); girara_setting_add(gsession, "page-store-interval", &int_value, INT, true, _("Amount of seconds between each cache purge"), NULL, NULL); + int_value = 20; + girara_setting_add(gsession, "jumplist-size", &int_value, INT, false, _("Number of positions to remember in the jumplist"), cb_jumplist_change, NULL); girara_setting_add(gsession, "recolor-darkcolor", NULL, STRING, false, _("Recoloring (dark color)"), cb_color_change, NULL); girara_setting_set(gsession, "recolor-darkcolor", "#FFFFFF"); @@ -242,6 +259,8 @@ config_load_default(zathura_t* zathura) girara_shortcut_add(gsession, 0, GDK_KEY_y, NULL, sc_scroll, NORMAL, FULL_RIGHT, NULL); girara_shortcut_add(gsession, 0, GDK_KEY_space, NULL, sc_scroll, NORMAL, FULL_DOWN, NULL); girara_shortcut_add(gsession, GDK_SHIFT_MASK, GDK_KEY_space, NULL, sc_scroll, NORMAL, FULL_UP, NULL); + girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_KEY_o, NULL, sc_jumplist, NORMAL, BACKWARD, NULL); + girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_KEY_i, NULL, sc_jumplist, NORMAL, FORWARD, NULL); girara_shortcut_add(gsession, 0, GDK_KEY_n, NULL, sc_search, NORMAL, FORWARD, NULL); girara_shortcut_add(gsession, 0, GDK_KEY_N, NULL, sc_search, NORMAL, BACKWARD, NULL); diff --git a/document.h b/document.h index b72e4ac..712fd5b 100644 --- a/document.h +++ b/document.h @@ -93,7 +93,7 @@ void zathura_document_set_current_page_number(zathura_document_t* document, unsi * Returns the current scale value of the document * * @param document The document - * @return The current scale value + * @return The current scale value */ double zathura_document_get_scale(zathura_document_t* document); @@ -125,7 +125,7 @@ void zathura_document_set_rotation(zathura_document_t* document, unsigned int ro * Returns the adjust mode of the document * * @param document The document - * @return The adjust mode + * @return The adjust mode */ zathura_adjust_mode_t zathura_document_get_adjust_mode(zathura_document_t* document); diff --git a/shortcuts.c b/shortcuts.c index ecd72c5..519c0e6 100644 --- a/shortcuts.c +++ b/shortcuts.c @@ -293,6 +293,7 @@ sc_goto(girara_session_t* session, girara_argument_t* argument, girara_event_t* g_return_val_if_fail(argument != NULL, false); g_return_val_if_fail(zathura->document != NULL, false); + zathura_jumplist_save(zathura); if (t != 0) { /* add offset */ unsigned int page_offset = zathura_document_get_page_offset(zathura->document); @@ -300,13 +301,15 @@ sc_goto(girara_session_t* session, girara_argument_t* argument, girara_event_t* t += page_offset; } - page_set(zathura, t - 1); + page_set(zathura, t-1); } else if (argument->n == TOP) { page_set(zathura, 0); } else if (argument->n == BOTTOM) { page_set(zathura, zathura_document_get_number_of_pages(zathura->document) - 1); } + zathura_jumplist_add(zathura); + return false; } @@ -609,6 +612,38 @@ sc_scroll(girara_session_t* session, girara_argument_t* argument, return false; } + +bool +sc_jumplist(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t)) +{ + g_return_val_if_fail(session != NULL, false); + g_return_val_if_fail(session->global.data != NULL, false); + zathura_t* zathura = session->global.data; + g_return_val_if_fail(argument != NULL, false); + g_return_val_if_fail(zathura->document != NULL, false); + + zathura_jump_t* jump = NULL; + switch(argument->n) { + case FORWARD: + zathura_jumplist_save(zathura); + zathura_jumplist_forward(zathura); + jump = zathura_jumplist_current(zathura); + break; + + case BACKWARD: + zathura_jumplist_save(zathura); + zathura_jumplist_backward(zathura); + jump = zathura_jumplist_current(zathura); + break; + } + + page_set(zathura, jump->page); + position_set_delayed(zathura, jump->x, jump->y); + + return false; +} + + bool sc_search(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t)) @@ -651,6 +686,8 @@ sc_search(girara_session_t* session, girara_argument_t* argument, target_idx = current - 1; } else { /* the next result is on a different page */ + zathura_jumplist_save(zathura); + g_object_set(page_widget, "search-current", -1, NULL); for (int npage_id = 1; page_id < num_pages; ++npage_id) { @@ -665,6 +702,8 @@ sc_search(girara_session_t* session, girara_argument_t* argument, break; } } + + zathura_jumplist_add(zathura); } break; @@ -779,6 +818,7 @@ sc_navigate_index(girara_session_t* session, girara_argument_t* argument, break; case SELECT: cb_index_row_activated(tree_view, path, NULL, zathura); + return false; } @@ -884,6 +924,9 @@ sc_toggle_index(girara_session_t* session, girara_argument_t* UNUSED(argument), vvalue = gtk_adjustment_get_value(vadjustment); hvalue = gtk_adjustment_get_value(hadjustment); + /* save current position to the jumplist */ + zathura_jumplist_save(zathura); + girara_set_view(session, zathura->ui.index); gtk_widget_show(GTK_WIDGET(zathura->ui.index)); girara_mode_set(zathura->ui.session, zathura->modes.index); diff --git a/shortcuts.h b/shortcuts.h index 191c1af..362c243 100644 --- a/shortcuts.h +++ b/shortcuts.h @@ -160,6 +160,17 @@ bool sc_rotate(girara_session_t* session, girara_argument_t* argument, girara_ev */ bool sc_scroll(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t); +/** + * Scroll through the pages + * + * @param session The used girara session + * @param argument The used argument + * @param event Girara event + * @param t Number of executions + * @return true if no error occured otherwise false + */ +bool sc_jumplist(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t); + /** * Search through the document for the latest search item * diff --git a/types.h b/types.h index 8aade9a..94240d2 100644 --- a/types.h +++ b/types.h @@ -19,6 +19,15 @@ typedef struct zathura_page_s zathura_page_t; * Zathura */ typedef struct zathura_s zathura_t; +/** + * Jump + */ +typedef struct zathura_jump_s +{ + unsigned int page; + double x; + double y; +} zathura_jump_t; /** * Plugin manager diff --git a/zathura.1.rst b/zathura.1.rst index 2f8322f..e5faf96 100644 --- a/zathura.1.rst +++ b/zathura.1.rst @@ -68,6 +68,8 @@ t, ^f, ^b, space, , y Scroll a full page left, down, up or right gg, G, nG Goto to the first, the last or to the nth page +^o, ^i + Move backward and forward through the jump list ^c, Escape Abort a, s @@ -84,7 +86,7 @@ f Enter command r Rotate by 90 degrees -^i +^r Recolor R Reload document diff --git a/zathura.c b/zathura.c index 191f4a8..38454b0 100644 --- a/zathura.c +++ b/zathura.c @@ -235,6 +235,16 @@ zathura_init(zathura_t* zathura) girara_setting_get(zathura->ui.session, "page-store-interval", &interval); g_timeout_add_seconds(interval, purge_pages, zathura); + /* jumplist */ + + zathura->jumplist.max_size = 20; + girara_setting_get(zathura->ui.session, "jumplist-size", &(zathura->jumplist.max_size)); + + zathura->jumplist.list = girara_list_new2(g_free); + zathura->jumplist.size = 0; + zathura->jumplist.cur = NULL; + zathura_jumplist_append_jump(zathura); + zathura->jumplist.cur = girara_list_iterator(zathura->jumplist.list); return true; error_free: @@ -291,6 +301,15 @@ zathura_free(zathura_t* zathura) g_free(zathura->config.config_dir); g_free(zathura->config.data_dir); + /* free jumplist */ + if (zathura->jumplist.list != NULL) { + girara_list_free(zathura->jumplist.list); + } + + if (zathura->jumplist.cur != NULL) { + girara_list_iterator_free(zathura->jumplist.cur); + } + g_free(zathura); } @@ -1026,3 +1045,92 @@ position_set_delayed(zathura_t* zathura, double position_x, double position_y) return FALSE; } + + +zathura_jump_t* +zathura_jumplist_current(zathura_t* zathura) { + if (zathura->jumplist.cur != NULL) { + return girara_list_iterator_data(zathura->jumplist.cur); + } else { + return NULL; + } +} + +void +zathura_jumplist_forward(zathura_t* zathura) { + if (girara_list_iterator_has_next(zathura->jumplist.cur)) { + girara_list_iterator_next(zathura->jumplist.cur); + } +} + +void +zathura_jumplist_backward(zathura_t* zathura) { + if (girara_list_iterator_has_previous(zathura->jumplist.cur)) { + girara_list_iterator_previous(zathura->jumplist.cur); + } +} + +void +zathura_jumplist_append_jump(zathura_t* zathura) { + zathura_jump_t *jump = g_malloc(sizeof(zathura_jump_t)); + if (jump != NULL) { + jump->page = 0; + jump->x = 0; + jump->y = 0; + + /* remove right tail after current */ + if (zathura->jumplist.cur != NULL) { + girara_list_iterator_t *it = girara_list_iterator_copy(zathura->jumplist.cur); + girara_list_iterator_next(it); + while (girara_list_iterator_is_valid(it)) { + girara_list_iterator_remove(it); + zathura->jumplist.size = zathura->jumplist.size - 1; + } + g_free(it); + } + + /* trim from beginning until max_size */ + girara_list_iterator_t *it = girara_list_iterator(zathura->jumplist.list); + while (zathura->jumplist.size >= zathura->jumplist.max_size && girara_list_iterator_is_valid(it)) { + girara_list_iterator_remove(it); + zathura->jumplist.size = zathura->jumplist.size - 1; + } + g_free(it); + + girara_list_append(zathura->jumplist.list, jump); + zathura->jumplist.size = zathura->jumplist.size + 1; + } +} + +void +zathura_jumplist_add(zathura_t* zathura) { + if (zathura->jumplist.list != NULL) { + unsigned int pagenum = zathura_document_get_current_page_number(zathura->document); + zathura_jump_t* cur = zathura_jumplist_current(zathura); + if (cur && cur->page == pagenum) { + return; + } + + zathura_jumplist_append_jump(zathura); + girara_list_iterator_next(zathura->jumplist.cur); + zathura_jumplist_save(zathura); + } +} + + +void +zathura_jumplist_save(zathura_t* zathura) { + zathura_jump_t* cur = zathura_jumplist_current(zathura); + + unsigned int pagenum = zathura_document_get_current_page_number(zathura->document); + + if (cur) { + /* get position */ + GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); + GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); + + cur->page = pagenum; + cur->x = gtk_adjustment_get_value(view_hadjustment); + cur->y = gtk_adjustment_get_value(view_vadjustment); + } +} diff --git a/zathura.h b/zathura.h index 9aa807c..0e16768 100644 --- a/zathura.h +++ b/zathura.h @@ -105,6 +105,14 @@ struct zathura_s girara_list_t* bookmarks; /**< bookmarks */ } bookmarks; + struct + { + girara_list_t* list; + girara_list_iterator_t *cur; + unsigned int size; + unsigned int max_size; + } jumplist; + struct { gchar* file; @@ -292,4 +300,48 @@ void page_widget_set_mode(zathura_t* zathura, unsigned int pages_per_row, unsign */ void statusbar_page_number_update(zathura_t* zathura); +/** + * Return current jump in the jumplist + * + * @param zathura The zathura session + * @return current jump + */ +zathura_jump_t* zathura_jumplist_current(zathura_t* zathura); + +/** + * Move forward in the jumplist + * + * @param zathura The zathura session + */ +void zathura_jumplist_forward(zathura_t* zathura); + +/** + * Move backward in the jumplist + * + * @param zathura The zathura session + */ +void zathura_jumplist_backward(zathura_t* zathura); + +/** + * Save current page to the jumplist at current position + * + * @param zathura The zathura session + */ +void zathura_jumplist_save(zathura_t* zathura); + +/** + * Add current page as a new item to the jumplist after current position + * + * @param zathura The zathura session + */ +void zathura_jumplist_add(zathura_t* zathura); + +/** + * Add a page to the jumplist after current position + * + * @param zathura The zathura session + */ +void zathura_jumplist_append_jump(zathura_t* zathura); + + #endif // ZATHURA_H