diff --git a/adjustment.c b/adjustment.c new file mode 100644 index 0000000..f61ea8f --- /dev/null +++ b/adjustment.c @@ -0,0 +1,55 @@ +/* See LICENSE file for license and copyright information */ + +#include "adjustment.h" +#include "utils.h" + +GtkAdjustment* +zathura_adjustment_clone(GtkAdjustment* adjustment) +{ + gdouble value = gtk_adjustment_get_value(adjustment); + gdouble lower = gtk_adjustment_get_lower(adjustment); + gdouble upper = gtk_adjustment_get_upper(adjustment); + gdouble step_increment = gtk_adjustment_get_step_increment(adjustment); + gdouble page_increment = gtk_adjustment_get_page_increment(adjustment); + gdouble page_size = gtk_adjustment_get_page_size(adjustment); + + return GTK_ADJUSTMENT(gtk_adjustment_new(value, lower, upper, step_increment, + page_increment, page_size)); +} + +void +zathura_adjustment_set_value(GtkAdjustment* adjustment, gdouble value) +{ + gtk_adjustment_set_value(adjustment, + MAX(gtk_adjustment_get_lower(adjustment), + MIN(gtk_adjustment_get_upper(adjustment) - + gtk_adjustment_get_page_size(adjustment), + value))); +} + +gdouble +zathura_adjustment_get_ratio(GtkAdjustment* adjustment) +{ + gdouble lower = gtk_adjustment_get_lower(adjustment); + gdouble upper = gtk_adjustment_get_upper(adjustment); + gdouble page_size = gtk_adjustment_get_page_size(adjustment); + gdouble value = gtk_adjustment_get_value(adjustment); + + return (value - lower + page_size / 2.0) / (upper - lower); +} + +void +zathura_adjustment_set_value_from_ratio(GtkAdjustment* adjustment, + gdouble ratio) +{ + if (ratio == 0.0) + return; + + gdouble lower = gtk_adjustment_get_lower(adjustment); + gdouble upper = gtk_adjustment_get_upper(adjustment); + gdouble page_size = gtk_adjustment_get_page_size(adjustment); + + gdouble value = (upper - lower) * ratio + lower - page_size / 2.0; + + zathura_adjustment_set_value(adjustment, value); +} diff --git a/adjustment.h b/adjustment.h new file mode 100644 index 0000000..63b4f88 --- /dev/null +++ b/adjustment.h @@ -0,0 +1,49 @@ +/* See LICENSE file for license and copyright information */ + +#ifndef ZATHURA_ADJUSTMENT_H +#define ZATHURA_ADJUSTMENT_H + +#include + +/* Clone a GtkAdjustment + * + * Creates a new adjustment with the same value, lower and upper bounds, step + * and page increments and page_size as the original adjustment. + * + * @param adjustment Adjustment instance to be cloned + * @return Pointer to the new adjustment + */ +GtkAdjustment* zathura_adjustment_clone(GtkAdjustment* adjustment); + +/** + * Set the adjustment value while enforcing its limits + * + * @param adjustment Adjustment instance + * @param value Adjustment value + */ +void zathura_adjustment_set_value(GtkAdjustment* adjustment, gdouble value); + +/** + * Compute the adjustment ratio + * + * That is, the ratio between the length from the lower bound to the middle of + * the slider, and the total length of the scrollbar. + * + * @param adjustment Scrollbar adjustment + * @return Adjustment ratio + */ +gdouble zathura_adjustment_get_ratio(GtkAdjustment* adjustment); + +/** + * Set the adjustment value from ratio + * + * The ratio is usually obtained from a previous call to + * zathura_adjustment_get_ratio(). + * + * @param adjustment Adjustment instance + * @param ratio Ratio from which the adjustment value will be set + */ +void zathura_adjustment_set_value_from_ratio(GtkAdjustment* adjustment, + gdouble ratio); + +#endif /* ZATHURA_ADJUSTMENT_H */ diff --git a/callbacks.c b/callbacks.c index b72ebad..9bd4806 100644 --- a/callbacks.c +++ b/callbacks.c @@ -18,6 +18,7 @@ #include "shortcuts.h" #include "page-widget.h" #include "page.h" +#include "adjustment.h" gboolean cb_destroy(GtkWidget* UNUSED(widget), zathura_t* zathura) @@ -108,6 +109,78 @@ cb_view_vadjustment_value_changed(GtkAdjustment* GIRARA_UNUSED(adjustment), gpoi statusbar_page_number_update(zathura); } +void +cb_view_hadjustment_changed(GtkAdjustment* adjustment, gpointer data) +{ + zathura_t* zathura = data; + g_return_if_fail(zathura != NULL); + + zathura_adjust_mode_t adjust_mode = + zathura_document_get_adjust_mode(zathura->document); + + gdouble lower, upper, page_size, value, ratio; + bool zoom_center = false; + + switch (adjust_mode) { + center: + case ZATHURA_ADJUST_BESTFIT: + case ZATHURA_ADJUST_WIDTH: + lower = gtk_adjustment_get_lower(adjustment); + upper = gtk_adjustment_get_upper(adjustment); + page_size = gtk_adjustment_get_page_size(adjustment); + value = ((upper - lower) - page_size) / 2.0; + zathura_adjustment_set_value(adjustment, value); + break; + default: + girara_setting_get(zathura->ui.session, "zoom-center", &zoom_center); + if (zoom_center) + goto center; + + ratio = zathura_adjustment_get_ratio(zathura->ui.hadjustment); + zathura_adjustment_set_value_from_ratio(adjustment, ratio); + break; + } +} + +void +cb_view_vadjustment_changed(GtkAdjustment* adjustment, gpointer data) +{ + zathura_t* zathura = data; + g_return_if_fail(zathura != NULL); + + double ratio = zathura_adjustment_get_ratio(zathura->ui.vadjustment); + zathura_adjustment_set_value_from_ratio(adjustment, ratio); +} + +void +cb_adjustment_track_value(GtkAdjustment* adjustment, gpointer data) +{ + GtkAdjustment* tracker = data; + + gdouble lower = gtk_adjustment_get_lower(adjustment); + gdouble upper = gtk_adjustment_get_upper(adjustment); + if (lower != gtk_adjustment_get_lower(tracker) || + upper != gtk_adjustment_get_upper(tracker)) + return; + + gdouble value = gtk_adjustment_get_value(adjustment); + gtk_adjustment_set_value(tracker, value); +} + +void +cb_adjustment_track_bounds(GtkAdjustment* adjustment, gpointer data) +{ + GtkAdjustment* tracker = data; + gdouble value = gtk_adjustment_get_value(adjustment); + gdouble lower = gtk_adjustment_get_lower(adjustment); + gdouble upper = gtk_adjustment_get_upper(adjustment); + gdouble page_size = gtk_adjustment_get_page_size(adjustment); + gtk_adjustment_set_value(tracker, value); + gtk_adjustment_set_lower(tracker, lower); + gtk_adjustment_set_upper(tracker, upper); + gtk_adjustment_set_page_size(tracker, page_size); +} + void cb_pages_per_row_value_changed(girara_session_t* session, const char* UNUSED(name), girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) { diff --git a/callbacks.h b/callbacks.h index 4ce2e2e..d879732 100644 --- a/callbacks.h +++ b/callbacks.h @@ -35,6 +35,53 @@ void cb_buffer_changed(girara_session_t* session); * @param data NULL */ void cb_view_vadjustment_value_changed(GtkAdjustment *adjustment, gpointer data); + +/** + * This function gets called when the bounds or the page_size of the horizontal + * scrollbar change (e.g. when the zoom level is changed). + * + * It adjusts the value of the horizontal scrollbar, possibly based on its + * previous adjustment, stored in the tracking adjustment + * zathura->ui.hadjustment. + * + * @param adjustment The horizontal adjustment of a gtkScrolledWindow + * @param data The zathura instance + */ +void cb_view_hadjustment_changed(GtkAdjustment *adjustment, gpointer data); + +/** + * This function gets called when the bounds or the page_size of the vertical + * scrollbar change (e.g. when the zoom level is changed). + * + * It adjusts the value of the vertical scrollbar based on its previous + * adjustment, stored in the tracking adjustment zathura->ui.hadjustment. + * + * @param adjustment The vertical adjustment of a gtkScrolledWindow + * @param data The zathura instance + */ +void cb_view_vadjustment_changed(GtkAdjustment *adjustment, gpointer data); + +/* This function gets called when the value of the adjustment changes. + * + * It updates the value of the tracking adjustment, only if the bounds of the + * adjustment have not changed (if they did change, + * cb_adjustment_track_bounds() will take care of updating everything). + * + * @param adjustment The adjustment instance + * @param data The tracking adjustment instance + */ +void cb_adjustment_track_value(GtkAdjustment* adjustment, gpointer data); + +/* This function gets called when the bounds or the page_size of the adjustment + * change. + * + * It updates the value, bounds and page_size of the tracking adjustment. + * + * @param adjustment The adjustment instance + * @param data The tracking adjustment instance + */ +void cb_adjustment_track_bounds(GtkAdjustment* adjustment, gpointer data); + /** * This function gets called when the value of the "pages-per-row" * variable changes diff --git a/marks.c b/marks.c index d5e4d47..0fac33d 100644 --- a/marks.c +++ b/marks.c @@ -235,9 +235,7 @@ mark_evaluate(zathura_t* zathura, int key) /* search for existing mark */ GIRARA_LIST_FOREACH(zathura->global.marks, zathura_mark_t*, iter, mark) if (mark != NULL && mark->key == key) { - double old_scale = zathura_document_get_scale(zathura->document); zathura_document_set_scale(zathura->document, mark->scale); - readjust_view_after_zooming(zathura, old_scale, true); render_all(zathura); position_set_delayed(zathura, mark->position_x, mark->position_y); diff --git a/shortcuts.c b/shortcuts.c index 6974d48..2e4d138 100644 --- a/shortcuts.c +++ b/shortcuts.c @@ -17,6 +17,7 @@ #include "page.h" #include "print.h" #include "page-widget.h" +#include "adjustment.h" /* Helper function; see sc_display_link and sc_follow. */ static bool @@ -105,7 +106,6 @@ sc_adjust_window(girara_session_t* session, girara_argument_t* argument, goto error_ret; } - float old_zoom = zathura_document_get_scale(zathura->document); zathura_document_set_adjust_mode(zathura->document, argument->n); if (argument->n == ZATHURA_ADJUST_NONE) { /* there is nothing todo */ @@ -180,9 +180,6 @@ sc_adjust_window(girara_session_t* session, girara_argument_t* argument, goto error_ret; } - /* keep position */ - readjust_view_after_zooming(zathura, old_zoom, false); - /* re-render all pages */ render_all(zathura); @@ -375,8 +372,10 @@ sc_mouse_scroll(girara_session_t* session, girara_argument_t* argument, girara_e return false; } - set_adjustment(x_adj, gtk_adjustment_get_value(x_adj) - (event->x - x)); - set_adjustment(y_adj, gtk_adjustment_get_value(y_adj) - (event->y - y)); + zathura_adjustment_set_value(x_adj, + gtk_adjustment_get_value(x_adj) - (event->x - x)); + zathura_adjustment_set_value(y_adj, + gtk_adjustment_get_value(y_adj) - (event->y - y)); break; /* unhandled events */ @@ -698,7 +697,7 @@ sc_scroll(girara_session_t* session, girara_argument_t* argument, } } - set_adjustment(adjustment, new_value); + zathura_adjustment_set_value(adjustment, new_value); return false; } @@ -818,14 +817,14 @@ sc_search(girara_session_t* session, girara_argument_t* argument, GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); int y = offset.y - gtk_adjustment_get_page_size(view_vadjustment) / 2 + rectangle.y1; - set_adjustment(view_vadjustment, y); + zathura_adjustment_set_value(view_vadjustment, y); bool search_hadjust = true; girara_setting_get(session, "search-hadjust", &search_hadjust); if (search_hadjust == true) { GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); int x = offset.x - gtk_adjustment_get_page_size(view_hadjustment) / 2 + rectangle.x1; - set_adjustment(view_hadjustment, x); + zathura_adjustment_set_value(view_hadjustment, x); } } @@ -1214,9 +1213,6 @@ sc_zoom(girara_session_t* session, girara_argument_t* argument, girara_event_t* zathura_document_set_scale(zathura->document, zoom_max); } - /* keep position */ - readjust_view_after_zooming(zathura, old_zoom, true); - render_all(zathura); return false; diff --git a/utils.c b/utils.c index fd052e5..26a07cd 100644 --- a/utils.c +++ b/utils.c @@ -248,13 +248,6 @@ error_ret: return rectangle; } -void -set_adjustment(GtkAdjustment* adjustment, gdouble value) -{ - gtk_adjustment_set_value(adjustment, MAX(gtk_adjustment_get_lower(adjustment), - MIN(gtk_adjustment_get_upper(adjustment) - gtk_adjustment_get_page_size(adjustment), value))); -} - double page_calc_height_width(zathura_page_t* page, unsigned int* page_height, unsigned int* page_width, bool rotate) { @@ -332,35 +325,6 @@ zathura_page_get_widget(zathura_t* zathura, zathura_page_t* page) return zathura->pages[page_number]; } -void -readjust_view_after_zooming(zathura_t *zathura, float old_zoom, bool delay) -{ - if (zathura == NULL || zathura->document == NULL) { - return; - } - - GtkScrolledWindow *window = GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view); - GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(window); - GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment(window); - - double scale = zathura_document_get_scale(zathura->document); - gdouble valx = gtk_adjustment_get_value(hadjustment) / old_zoom * scale; - gdouble valy = gtk_adjustment_get_value(vadjustment) / old_zoom * scale; - - bool zoom_center = false; - girara_setting_get(zathura->ui.session, "zoom-center", &zoom_center); - if (zoom_center) { - valx += gtk_adjustment_get_page_size(hadjustment) * (scale / old_zoom - 1) / 2; - } - - if (delay == true) { - position_set_delayed(zathura, valx, valy); - } else { - set_adjustment(hadjustment, valx); - set_adjustment(vadjustment, valy); - } -} - void document_draw_search_results(zathura_t* zathura, bool value) { diff --git a/utils.h b/utils.h index b480ab8..ce6baf6 100644 --- a/utils.h +++ b/utils.h @@ -86,13 +86,6 @@ zathura_rectangle_t rotate_rectangle(zathura_rectangle_t rectangle, unsigned int */ zathura_rectangle_t recalc_rectangle(zathura_page_t* page, zathura_rectangle_t rectangle); -/** - * Set adjustment of a GtkAdjustment respecting its limits. - * @param adjust the GtkAdkustment instance - * @param value the new adjustment - */ -void set_adjustment(GtkAdjustment* adjust, gdouble value); - /** * Calculate the page size according to the corrent scaling and rotation if * desired. @@ -132,15 +125,6 @@ void zathura_get_document_size(zathura_t* zathura, */ GtkWidget* zathura_page_get_widget(zathura_t* zathura, zathura_page_t* page); -/** - * Re-adjust view - * - * @param zathura Zathura instance - * @param old_zoom Old zoom value - * @param delay true if action should be delayed - */ -void readjust_view_after_zooming(zathura_t* zathura, float old_zoom, bool delay); - /** * Set if the search results should be drawn or not * diff --git a/zathura.c b/zathura.c index 7485530..8e8c4da 100644 --- a/zathura.c +++ b/zathura.c @@ -32,6 +32,7 @@ #include "page.h" #include "page-widget.h" #include "plugin.h" +#include "adjustment.h" typedef struct zathura_document_info_s { zathura_t* zathura; @@ -152,11 +153,37 @@ zathura_init(zathura_t* zathura) g_signal_connect(G_OBJECT(zathura->ui.session->gtk.window), "size-allocate", G_CALLBACK(cb_view_resized), zathura); - /* callbacks */ - GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); - g_signal_connect(G_OBJECT(view_vadjustment), "value-changed", G_CALLBACK(cb_view_vadjustment_value_changed), zathura); - GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); - g_signal_connect(G_OBJECT(view_hadjustment), "value-changed", G_CALLBACK(cb_view_vadjustment_value_changed), zathura); + /* Setup hadjustment tracker */ + GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment( + GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); + zathura->ui.hadjustment = zathura_adjustment_clone(hadjustment); + g_object_ref_sink(zathura->ui.hadjustment); + + /* Connect hadjustment signals */ + g_signal_connect(G_OBJECT(hadjustment), "value-changed", + G_CALLBACK(cb_view_vadjustment_value_changed), zathura); + g_signal_connect(G_OBJECT(hadjustment), "value-changed", + G_CALLBACK(cb_adjustment_track_value), zathura->ui.hadjustment); + g_signal_connect(G_OBJECT(hadjustment), "changed", + G_CALLBACK(cb_view_hadjustment_changed), zathura); + g_signal_connect(G_OBJECT(hadjustment), "changed", + G_CALLBACK(cb_adjustment_track_bounds), zathura->ui.hadjustment); + + /* Setup vadjustment tracker */ + GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment( + GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); + zathura->ui.vadjustment = zathura_adjustment_clone(vadjustment); + g_object_ref_sink(zathura->ui.vadjustment); + + /* Connect vadjustment signals */ + g_signal_connect(G_OBJECT(vadjustment), "value-changed", + G_CALLBACK(cb_view_vadjustment_value_changed), zathura); + g_signal_connect(G_OBJECT(vadjustment), "value-changed", + G_CALLBACK(cb_adjustment_track_value), zathura->ui.vadjustment); + g_signal_connect(G_OBJECT(vadjustment), "changed", + G_CALLBACK(cb_view_vadjustment_changed), zathura); + g_signal_connect(G_OBJECT(vadjustment), "changed", + G_CALLBACK(cb_adjustment_track_bounds), zathura->ui.vadjustment); /* page view alignment */ zathura->ui.page_widget_alignment = gtk_alignment_new(0.5, 0.5, 0, 0); @@ -280,6 +307,13 @@ zathura_free(zathura_t* zathura) girara_session_destroy(zathura->ui.session); } + if (zathura->ui.hadjustment != NULL) { + g_object_unref(G_OBJECT(zathura->ui.hadjustment)); + } + if (zathura->ui.vadjustment != NULL) { + g_object_unref(G_OBJECT(zathura->ui.vadjustment)); + } + /* stdin support */ if (zathura->stdin_support.file != NULL) { g_unlink(zathura->stdin_support.file); @@ -956,8 +990,8 @@ page_set(zathura_t* zathura, unsigned int page_id) 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)); - set_adjustment(view_hadjustment, offset.x); - set_adjustment(view_vadjustment, offset.y); + zathura_adjustment_set_value(view_hadjustment, offset.x); + zathura_adjustment_set_value(view_vadjustment, offset.y); statusbar_page_number_update(zathura); @@ -1065,8 +1099,8 @@ position_set_delayed_impl(gpointer data) GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(window); GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment(window); - set_adjustment(hadjustment, p->position_x); - set_adjustment(vadjustment, p->position_y); + zathura_adjustment_set_value(hadjustment, p->position_x); + zathura_adjustment_set_value(vadjustment, p->position_y); g_free(p); diff --git a/zathura.h b/zathura.h index 96d9610..1520d78 100644 --- a/zathura.h +++ b/zathura.h @@ -69,6 +69,9 @@ struct zathura_s GtkWidget *page_widget_alignment; GtkWidget *page_widget; /**< Widget that contains all rendered pages */ GtkWidget *index; /**< Widget to show the index of the document */ + + GtkAdjustment *hadjustment; /**< Tracking hadjustment */ + GtkAdjustment *vadjustment; /**< Tracking vadjustment */ } ui; struct