From 5447de8a4701aec496638486e02ebf6acae7bb45 Mon Sep 17 00:00:00 2001 From: Colin Geniet Date: Wed, 24 Apr 2024 10:15:01 +0200 Subject: [PATCH 1/2] utils: Add parser/writer for 'first-page-column' The 'first-page-column' setting is a string representing a list of integers. This is annoying to manipulate. Currently, it has a single accessor, 'find_first_page_column', which looks up the nth value. The next commit will add a function to change it. To avoid this turning into a horrible buggy mess of string manipulation, add functions to convert the settings string to and from integer arrays. Rewrite 'find_first_page_column' using these functions. Efficiency: the new functions are slower than 'find_first_page_column' because they parse all values in the string. This is irrelevant since the string is supposed to be tiny, and is only used when opening a document or when the page layout is modified by the user. --- zathura/utils.c | 65 ++++++++++++++++++++++++++++++++++++++++--------- zathura/utils.h | 24 ++++++++++++++++++ 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/zathura/utils.c b/zathura/utils.c index 32d1e5f..b064071 100644 --- a/zathura/utils.c +++ b/zathura/utils.c @@ -244,6 +244,52 @@ get_selection(zathura_t* zathura) return selection; } +char* +write_first_page_column_list(unsigned int* first_page_columns, unsigned int size) +{ + if (first_page_columns == NULL) + return NULL; + + char** tokens = g_malloc_n(size+1, sizeof(char*)); + tokens[size] = NULL; + + for (unsigned int i=0; i 0, first_page_column); - /* split settings list */ - char** settings = g_strsplit(first_page_column_list, ":", pages_per_row + 1); - const size_t settings_size = g_strv_length(settings); + unsigned int size = 0; + unsigned int* settings = parse_first_page_column_list(first_page_column_list, &size); - /* read setting value corresponding to the specified pages per row */ - unsigned int index = pages_per_row - 1; - if (index < settings_size && *settings[index] != '\0') { - first_page_column = atoi(settings[index]); - } else if (*settings[settings_size - 1] != '\0') { - first_page_column = atoi(settings[settings_size - 1]); + if (pages_per_row <= size) { + first_page_column = settings[pages_per_row - 1]; + } else if (size > 0) { + first_page_column = settings[size - 1]; } - /* free buffers */ - g_strfreev(settings); + g_free(settings); return first_page_column; } diff --git a/zathura/utils.h b/zathura/utils.h index e1da74b..5e4a1f0 100644 --- a/zathura/utils.h +++ b/zathura/utils.h @@ -107,6 +107,30 @@ GdkAtom* get_selection(zathura_t* zathura); double zathura_correct_zoom_value(girara_session_t* session, const double zoom); +/** + * Write a list of 'pages per row to first column' values as a colon separated string. + * + * For valid settings list, this is the inverse of parse_first_page_column_list. + * + * @param[in] first_page_columns The settings vector + * @param[in] size The size of the settings vector + * + * @return The new settings string + */ +char* write_first_page_column(unsigned int* first_page_columns, unsigned int size); + +/** + * Parse a 'pages per row to first column' settings list. + * + * For valid settings list, this is the inverse of write_first_page_column_list. + * + * @param[in] first_page_column_list The settings list + * @param[in] size A cell to return the size of the result, mandatory + * + * @return The values from the settings list as a new vector + */ +unsigned int* parse_first_page_column(const char* first_page_column_list, unsigned int* size); + /** * Extracts the column the first page should be rendered in from the specified * list of settings corresponding to the specified pages per row From d5cb3777c111f5c02c1c340ae9c9856323e0a499 Mon Sep 17 00:00:00 2001 From: Colin Geniet Date: Wed, 24 Apr 2024 11:54:24 +0200 Subject: [PATCH 2/2] input: Add shortcut to cycle first page column Add mapping cycle_first_column (default 'D') to cycle the column in which to display the first page. --- doc/man/zathura.1.rst | 2 ++ doc/man/zathurarc.5.rst | 4 ++++ zathura/config.c | 2 ++ zathura/shortcuts.c | 28 ++++++++++++++++++++++++ zathura/shortcuts.h | 11 ++++++++++ zathura/utils.c | 48 +++++++++++++++++++++++++++++++++++++++++ zathura/utils.h | 12 +++++++++++ 7 files changed, 107 insertions(+) diff --git a/doc/man/zathura.1.rst b/doc/man/zathura.1.rst index 4550015..eda32bb 100644 --- a/doc/man/zathura.1.rst +++ b/doc/man/zathura.1.rst @@ -127,6 +127,8 @@ General Show index and switch to **Index mode** d Toggle dual page view + D + Cycle opening column in dual page view F5 Switch to presentation mode F11 diff --git a/doc/man/zathurarc.5.rst b/doc/man/zathurarc.5.rst index 92a0c6f..2fb4c32 100644 --- a/doc/man/zathurarc.5.rst +++ b/doc/man/zathurarc.5.rst @@ -225,6 +225,10 @@ They can also be combined with modifiers: Change current mode. Pass the desired mode as argument. + * ``cycle_first_page`` + + In multiple page layout, cycle the column in which the first page is displayed. + * ``display_link``: Display link target. diff --git a/zathura/config.c b/zathura/config.c index 545bc44..755f979 100644 --- a/zathura/config.c +++ b/zathura/config.c @@ -443,6 +443,7 @@ void config_load_default(zathura_t* zathura) { girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_KEY_n, NULL, girara_sc_toggle_statusbar, (mode), 0, NULL); \ girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_KEY_m, NULL, girara_sc_toggle_inputbar, (mode), 0, NULL); \ girara_shortcut_add(gsession, 0, GDK_KEY_d, NULL, sc_toggle_page_mode, (mode), 0, NULL); \ + girara_shortcut_add(gsession, 0, GDK_KEY_D, NULL, sc_cycle_first_column, (mode), 0, NULL); \ \ girara_shortcut_add(gsession, 0, GDK_KEY_q, NULL, sc_quit, (mode), 0, NULL); \ \ @@ -596,6 +597,7 @@ void config_load_default(zathura_t* zathura) { girara_shortcut_mapping_add(gsession, "adjust_window", sc_adjust_window); girara_shortcut_mapping_add(gsession, "bisect", sc_bisect); girara_shortcut_mapping_add(gsession, "change_mode", sc_change_mode); + girara_shortcut_mapping_add(gsession, "cycle_first_column", sc_cycle_first_column); girara_shortcut_mapping_add(gsession, "display_link", sc_display_link); girara_shortcut_mapping_add(gsession, "copy_link", sc_copy_link); girara_shortcut_mapping_add(gsession, "copy_filepath", sc_copy_filepath); diff --git a/zathura/shortcuts.c b/zathura/shortcuts.c index cd5be3c..1457e01 100644 --- a/zathura/shortcuts.c +++ b/zathura/shortcuts.c @@ -150,6 +150,34 @@ sc_change_mode(girara_session_t* session, girara_argument_t* argument, return false; } +bool +sc_cycle_first_column(girara_session_t* session, girara_argument_t* UNUSED(argument), + girara_event_t* UNUSED(event), unsigned int 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; + + if (zathura->document == NULL) { + girara_notify(session, GIRARA_WARNING, _("No document opened.")); + return false; + } + + int pages_per_row = 1; + girara_setting_get(session, "pages-per-row", &pages_per_row); + char* first_page_column_list = NULL; + girara_setting_get(session, "first-page-column", &first_page_column_list); + + if (t == 0) t = 1; + char* new_column_list = increment_first_page_column(first_page_column_list, pages_per_row, t); + g_free(first_page_column_list); + + girara_setting_set(session, "first-page-column", new_column_list); + g_free(new_column_list); + + return true; +} + bool sc_display_link(girara_session_t* session, girara_argument_t* UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t)) diff --git a/zathura/shortcuts.h b/zathura/shortcuts.h index ae0fe00..a7c3999 100644 --- a/zathura/shortcuts.h +++ b/zathura/shortcuts.h @@ -38,6 +38,17 @@ bool sc_adjust_window(girara_session_t* session, girara_argument_t* argument, gi */ bool sc_change_mode(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t); +/** + * Cycle the column the first page is displayed in + * + * @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 occurred otherwise false + */ +bool sc_cycle_first_column(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t); + /** * Display a link * diff --git a/zathura/utils.c b/zathura/utils.c index b064071..3663ff6 100644 --- a/zathura/utils.c +++ b/zathura/utils.c @@ -313,6 +313,54 @@ find_first_page_column(const char* first_page_column_list, return first_page_column; } +char* +increment_first_page_column(const char* first_page_column_list, + const unsigned int pages_per_row, int incr) +{ + /* sanity checks */ + if (first_page_column_list == NULL) + first_page_column_list = ""; + /* This function is a no-op for 1 column layout */ + if (pages_per_row <= 1) + return g_strdup(first_page_column_list); + + unsigned int size = 0; + unsigned int* settings = parse_first_page_column_list(first_page_column_list, &size); + + /* Lookup current setting. Signed value to avoid negative overflow when modifying it later. */ + int column = 1; + if (pages_per_row <= size) { + column = settings[pages_per_row - 1]; + } else if (size > 0) { + column = settings[size - 1]; + } + + /* increment and normalise to [1,pages_per_row]. */ + column += incr; + column %= pages_per_row; /* range [-pages_per_row+1, pages_per_row-1] */ + if (column <= 0) + column += pages_per_row; /* range [1, pages_per_row] */ + + /* Write back, creating the new cell if necessary. */ + if (pages_per_row <= size) { + settings[pages_per_row - 1] = column; + } else { + /* extend settings array */ + settings = g_realloc_n(settings, pages_per_row, sizeof(*settings)); + for (unsigned int i=size; i