Instead of guesstimating the values of the scrollbars adjustments after
a change in zoom level, connect callbacks to the "changed" GtkAdjustment
event (which is emitted when the bounds or page_size of the adjustment
change, e.g. when the zoom level changes), and compute the new values
from there.

The previous adjustment values are tracked in zathura->ui.hadjustment
and zathura->ui.vadjustment (and updated by signal handlers as well), so
that the view's position can be maintained while zooming.

cb_view_hadjustment_changed() centers the page horizontally if a
"best-fit" or "width" zoom is being performed, or if "zoom-center" is
true; otherwise, it keeps the view horizontally centered around the same
area of the page.

cb_view_vadjustment_changed() always keeps the view vertically centered
around the same area of the page.
---
Thanks to Marwan's review of my previous patch, this should now work much
better. But further review and testing would be much appreciated (the more the
merrier :) ).
---
 callbacks.c |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 callbacks.h |   22 ++++++++++++++++++
 marks.c     |    2 --
 shortcuts.c |    7 ------
 utils.c     |   48 ++++++++++++++++++---------------------
 utils.h     |   23 ++++++++++++++-----
 zathura.c   |   33 +++++++++++++++++++++++++++
 zathura.h   |    3 +++
 8 files changed, 170 insertions(+), 40 deletions(-)

diff --git a/callbacks.c b/callbacks.c
index b72ebad..974893d 100644
--- a/callbacks.c
+++ b/callbacks.c
@@ -109,6 +109,49 @@ cb_view_vadjustment_value_changed(GtkAdjustment* 
GIRARA_UNUSED(adjustment), gpoi
 }
 
 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;
+      set_adjustment(adjustment, value);
+      break;
+    default:
+      girara_setting_get(zathura->ui.session, "zoom-center", &zoom_center);
+      if (zoom_center)
+        goto center;
+
+      ratio = compute_adjustment_ratio(zathura->ui.hadjustment);
+      set_adjustment_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 = compute_adjustment_ratio(zathura->ui.vadjustment);
+  set_adjustment_from_ratio(adjustment, ratio);
+}
+
+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))
 {
   g_return_if_fail(value != NULL);
@@ -447,3 +490,32 @@ cb_unknown_command(girara_session_t* session, const char* 
input)
 
   return true;
 }
+
+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);
+}
diff --git a/callbacks.h b/callbacks.h
index 4ce2e2e..7fbb49e 100644
--- a/callbacks.h
+++ b/callbacks.h
@@ -35,6 +35,25 @@ 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 changes (e.g. when the zoom level is changed).
+ *
+ * @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 changes (e.g. when the zoom level is changed).
+ *
+ * @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 "pages-per-row"
  * variable changes
@@ -155,4 +174,7 @@ void cb_setting_recolor_keep_hue_change(girara_session_t* 
session, const char* n
  */
 bool cb_unknown_command(girara_session_t* session, const char* input);
 
+void cb_adjustment_track_value(GtkAdjustment* adjustment, gpointer data);
+void cb_adjustment_track_bounds(GtkAdjustment* adjustment, gpointer data);
+
 #endif // CALLBACKS_H
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 a3348af..dac4637 100644
--- a/shortcuts.c
+++ b/shortcuts.c
@@ -105,7 +105,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 +179,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);
 
@@ -1214,9 +1210,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..bf1a74f 100644
--- a/utils.c
+++ b/utils.c
@@ -255,6 +255,21 @@ set_adjustment(GtkAdjustment* adjustment, gdouble value)
                            MIN(gtk_adjustment_get_upper(adjustment) - 
gtk_adjustment_get_page_size(adjustment), value)));
 }
 
+void
+set_adjustment_from_ratio(GtkAdjustment* adjustment, double 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;
+
+  set_adjustment(adjustment, value);
+}
+
 double
 page_calc_height_width(zathura_page_t* page, unsigned int* page_height, 
unsigned int* page_width, bool rotate)
 {
@@ -332,33 +347,14 @@ 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)
+double
+compute_adjustment_ratio(GtkAdjustment* adjustment)
 {
-  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);
-  }
+  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
diff --git a/utils.h b/utils.h
index b480ab8..d5af4c4 100644
--- a/utils.h
+++ b/utils.h
@@ -94,6 +94,17 @@ zathura_rectangle_t recalc_rectangle(zathura_page_t* page, 
zathura_rectangle_t r
 void set_adjustment(GtkAdjustment* adjust, gdouble value);
 
 /**
+ * Set the adjustment value from ratio
+ *
+ * The ratio is usually obtained from a previous call to
+ * compute_adjustment_ratio().
+ *
+ * @param adjustment Adjustment instance
+ * @param ratio The ratio from which the adjustment value will be computed
+ */
+void set_adjustment_from_ratio(GtkAdjustment* adjustment, double ratio);
+
+/**
  * Calculate the page size according to the corrent scaling and rotation if
  * desired.
  * @param page the page
@@ -133,13 +144,15 @@ void zathura_get_document_size(zathura_t* zathura,
 GtkWidget* zathura_page_get_widget(zathura_t* zathura, zathura_page_t* page);
 
 /**
- * Re-adjust view
+ * Compute the adjustment ratio
  *
- * @param zathura Zathura instance
- * @param old_zoom Old zoom value
- * @param delay true if action should be delayed
+ * 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 Adjustment from a gtkScrolledWindow
+ * @return Adjustment ratio
  */
-void readjust_view_after_zooming(zathura_t* zathura, float old_zoom, bool 
delay);
+double compute_adjustment_ratio(GtkAdjustment* adjustment);
 
 /**
  * Set if the search results should be drawn or not
diff --git a/zathura.c b/zathura.c
index 7485530..bbae922 100644
--- a/zathura.c
+++ b/zathura.c
@@ -155,8 +155,41 @@ zathura_init(zathura_t* 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);
+  g_signal_connect(G_OBJECT(view_vadjustment), "changed", 
G_CALLBACK(cb_view_vadjustment_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);
+  g_signal_connect(G_OBJECT(view_hadjustment), "changed", 
G_CALLBACK(cb_view_hadjustment_changed), zathura);
+
+  GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment(
+      GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
+  gdouble value = gtk_adjustment_get_value(hadjustment);
+  gdouble lower = gtk_adjustment_get_lower(hadjustment);
+  gdouble upper = gtk_adjustment_get_upper(hadjustment);
+  gdouble step_increment = gtk_adjustment_get_step_increment(hadjustment);
+  gdouble page_increment = gtk_adjustment_get_page_increment(hadjustment);
+  gdouble page_size = gtk_adjustment_get_page_size(hadjustment);
+  zathura->ui.hadjustment = GTK_ADJUSTMENT(gtk_adjustment_new(value, lower,
+        upper, step_increment, page_increment, page_size));
+
+  GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(
+      GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
+  value = gtk_adjustment_get_value(vadjustment);
+  lower = gtk_adjustment_get_lower(vadjustment);
+  upper = gtk_adjustment_get_upper(vadjustment);
+  step_increment = gtk_adjustment_get_step_increment(vadjustment);
+  page_increment = gtk_adjustment_get_page_increment(vadjustment);
+  page_size = gtk_adjustment_get_page_size(vadjustment);
+  zathura->ui.vadjustment = GTK_ADJUSTMENT(gtk_adjustment_new(value, lower,
+        upper, step_increment, page_increment, page_size));
+
+  g_signal_connect(G_OBJECT(hadjustment), "value-changed",
+      G_CALLBACK(cb_adjustment_track_value), zathura->ui.hadjustment);
+  g_signal_connect(G_OBJECT(vadjustment), "value-changed",
+      G_CALLBACK(cb_adjustment_track_value), zathura->ui.vadjustment);
+  g_signal_connect(G_OBJECT(hadjustment), "changed",
+      G_CALLBACK(cb_adjustment_track_bounds), zathura->ui.hadjustment);
+  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);
diff --git a/zathura.h b/zathura.h
index 96d9610..fca9c13 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;
+    GtkAdjustment *vadjustment;
   } ui;
 
   struct
-- 
1.7.10.4

_______________________________________________
zathura mailing list
zathura@lists.pwmt.org
http://lists.pwmt.org/mailman/listinfo/zathura

Reply via email to