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.

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.
---
This is in preparation for addressing <http://bugs.pwmt.org/issue99>. A patch
will follow shortly.
---
 callbacks.c |   43 +++++++++++++++++++++++++++++++++++++++++++
 callbacks.h |   19 +++++++++++++++++++
 document.c  |   32 ++++++++++++++++++++++++++++++++
 document.h  |   38 ++++++++++++++++++++++++++++++++++++++
 marks.c     |    3 +--
 shortcuts.c |    5 ++---
 utils.c     |   49 +++++++++++++++++++++++++++++++------------------
 utils.h     |   24 +++++++++++++++++++++++-
 zathura.c   |    2 ++
 9 files changed, 191 insertions(+), 24 deletions(-)

diff --git a/callbacks.c b/callbacks.c
index b72ebad..59123f8 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 = zathura_document_get_hadjustment_ratio(zathura->document);
+      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 = zathura_document_get_vadjustment_ratio(zathura->document);
+  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);
diff --git a/callbacks.h b/callbacks.h
index 4ce2e2e..dcbce3e 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
diff --git a/document.c b/document.c
index 6b8d52b..b992010 100644
--- a/document.c
+++ b/document.c
@@ -48,6 +48,10 @@ struct zathura_document_s {
   void* data; /**< Custom data */
   zathura_adjust_mode_t adjust_mode; /**< Adjust mode (best-fit, width) */
   unsigned int page_offset; /**< Page offset */
+  struct {
+    double horizontal; /**< Horizontal adjustment ratio */
+    double vertical; /**< Vertical adjustment ratio */
+  } adjustment_ratio;
 
   /**
    * Document pages
@@ -391,6 +395,34 @@ zathura_document_set_page_offset(zathura_document_t* 
document, unsigned int page
   }
 }
 
+double
+zathura_document_get_hadjustment_ratio(zathura_document_t* document)
+{
+  if (document == NULL)
+    return 0.0;
+
+  return document->adjustment_ratio.horizontal;
+}
+
+double
+zathura_document_get_vadjustment_ratio(zathura_document_t* document)
+{
+  if (document == NULL)
+    return 0.0;
+
+  return document->adjustment_ratio.vertical;
+}
+
+void
+zathura_document_set_adjustment_ratios(zathura_document_t* document,
+                                       double hadjustment_ratio,
+                                       double vadjustment_ratio)
+{
+  g_return_if_fail(document != NULL);
+  document->adjustment_ratio.horizontal = hadjustment_ratio;
+  document->adjustment_ratio.vertical   = vadjustment_ratio;
+}
+
 void
 zathura_document_get_cell_size(zathura_document_t* document,
                                unsigned int* height, unsigned int* width)
diff --git a/document.h b/document.h
index 113344e..b8c3426 100644
--- a/document.h
+++ b/document.h
@@ -154,6 +154,44 @@ unsigned int 
zathura_document_get_page_offset(zathura_document_t* document);
 void zathura_document_set_page_offset(zathura_document_t* document, unsigned 
int page_offset);
 
 /**
+ * Returns the stored horizontal adjustment ratio
+ *
+ * It is the ratio between the the length from the lower bound to the middle of
+ * the slider, and the total length of the scrollbar. It is used to keep the
+ * view centered on the same area while zooming in or out.
+ *
+ * @param document The document instance
+ * @return The stored horizontal adjustment ratio
+ */
+double zathura_document_get_hadjustment_ratio(zathura_document_t* document);
+
+/**
+ * Returns the stored vertical adjustment ratio
+ *
+ * It is the ratio between the the length from the lower bound to the middle of
+ * the slider, and the total length of the scrollbar. It is used to keep the
+ * view centered on the same area while zooming in or out.
+ *
+ * @param document The document instance
+ * @return The stored vertical adjustment ratio
+ */
+double zathura_document_get_vadjustment_ratio(zathura_document_t* document);
+
+/**
+ * Stores the horizontal and vertical adjustment ratios
+ *
+ * The ratio is usually obtained from a call to compute_adjustment_ratio() from
+ * utils.h.
+ *
+ * @param document The document instance
+ * @param The horizontal adjustment ratio
+ * @param The vertical adjustment ratio
+ */
+void zathura_document_set_adjustment_ratios(zathura_document_t* document,
+                                            double hadjustment_ratio,
+                                            double vadjustment_ratio);
+
+/**
  * Returns the private data of the document
  *
  * @param document The document
diff --git a/marks.c b/marks.c
index d5e4d47..a60b63f 100644
--- a/marks.c
+++ b/marks.c
@@ -235,9 +235,8 @@ 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);
+    readjust_view_after_zooming(zathura);
     render_all(zathura);
 
     position_set_delayed(zathura, mark->position_x, mark->position_y);
diff --git a/shortcuts.c b/shortcuts.c
index a3348af..394239d 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 */
@@ -181,7 +180,7 @@ sc_adjust_window(girara_session_t* session, 
girara_argument_t* argument,
   }
 
   /* keep position */
-  readjust_view_after_zooming(zathura, old_zoom, false);
+  readjust_view_after_zooming(zathura);
 
   /* re-render all pages */
   render_all(zathura);
@@ -1215,7 +1214,7 @@ sc_zoom(girara_session_t* session, girara_argument_t* 
argument, girara_event_t*
   }
 
   /* keep position */
-  readjust_view_after_zooming(zathura, old_zoom, true);
+  readjust_view_after_zooming(zathura);
 
   render_all(zathura);
 
diff --git a/utils.c b/utils.c
index fd052e5..c402512 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,31 @@ zathura_page_get_widget(zathura_t* zathura, 
zathura_page_t* page)
   return zathura->pages[page_number];
 }
 
+double
+compute_adjustment_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
-readjust_view_after_zooming(zathura_t *zathura, float old_zoom, bool delay)
+readjust_view_after_zooming(zathura_t *zathura)
 {
   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;
-  }
+  GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment(window);
+  GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(window);
 
-  if (delay == true) {
-    position_set_delayed(zathura, valx, valy);
-  } else {
-    set_adjustment(hadjustment, valx);
-    set_adjustment(vadjustment, valy);
-  }
+  zathura_document_set_adjustment_ratios(zathura->document,
+      compute_adjustment_ratio(hadjustment),
+      compute_adjustment_ratio(vadjustment));
 }
 
 void
diff --git a/utils.h b/utils.h
index b480ab8..0f757d4 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,24 @@ void zathura_get_document_size(zathura_t* zathura,
 GtkWidget* zathura_page_get_widget(zathura_t* zathura, zathura_page_t* page);
 
 /**
+ * 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 Adjustment from a gtkScrolledWindow
+ * @return Adjustment ratio
+ */
+double compute_adjustment_ratio(GtkAdjustment* adjustment);
+
+/**
  * 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);
+void readjust_view_after_zooming(zathura_t* zathura);
 
 /**
  * Set if the search results should be drawn or not
diff --git a/zathura.c b/zathura.c
index 7485530..351ffed 100644
--- a/zathura.c
+++ b/zathura.c
@@ -155,8 +155,10 @@ 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);
 
   /* page view alignment */
   zathura->ui.page_widget_alignment = gtk_alignment_new(0.5, 0.5, 0, 0);
-- 
1.7.10.4

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

Reply via email to