diff --git a/src/canvas.cpp b/src/canvas.cpp
index 38992ba149434a76203ab667d125bf036e33193e..f940da64c408eb86418677a8c3ce934fde7bee48 100644
--- a/src/canvas.cpp
+++ b/src/canvas.cpp
@@ -387,6 +387,7 @@ void Canvas::page_rendered(int page) {
 void Canvas::goto_page() {
 	int page = goto_line->text().toInt() - 1;
 	goto_line->hide();
-	cur_layout->scroll_page_jump(page, false);
+	setFocus(Qt::OtherFocusReason);
+	cur_layout->scroll_page_top_jump(page, false);
 }
 
diff --git a/src/layout/gridlayout.cpp b/src/layout/gridlayout.cpp
index ba10dd89cebe9ee1f3a41d281162d1ca4a2de5be..9b6136b1171064785a578794432c1c541ac03370 100644
--- a/src/layout/gridlayout.cpp
+++ b/src/layout/gridlayout.cpp
@@ -142,7 +142,7 @@ void GridLayout::resize(int w, int h) {
 
 void GridLayout::set_zoom(int new_zoom, bool relative) {
 	float old_factor = 1 + zoom * zoom_factor;
-	int old_page = page;
+	int old_page = get_page();
 	if (relative) {
 		zoom += new_zoom;
 	} else {
@@ -163,7 +163,7 @@ void GridLayout::set_zoom(int new_zoom, bool relative) {
 	off_y = (off_y - height / 2) * new_factor / old_factor + height / 2;
 
 	set_constants();
-	viewer->layout_updated(page, page != old_page);
+	viewer->layout_updated(get_page(), get_page() != old_page);
 }
 
 bool GridLayout::set_columns_noupdate(int new_columns, bool relative) {
@@ -179,28 +179,28 @@ bool GridLayout::set_columns_noupdate(int new_columns, bool relative) {
 }
 
 void GridLayout::set_columns(int new_columns, bool relative) {
-	int old_page = page;
+	int old_page = get_page();
 	if (set_columns_noupdate(new_columns, relative)) {
-		viewer->layout_updated(page, page != old_page);
+		viewer->layout_updated(get_page(), get_page() != old_page);
 	}
 }
 
 void GridLayout::set_offset(int new_offset, bool relative) {
-	int old_page = page;
+	int old_page = get_page();
 	if (relative) {
 		new_offset += grid->get_offset();
 	}
 
 	if (grid->set_offset(new_offset)) {
 		set_constants();
-		viewer->layout_updated(page, page != old_page);
+		viewer->layout_updated(get_page(), get_page() != old_page);
 	}
 }
 
 bool GridLayout::scroll_smooth_noupdate(int dx, int dy) {
 	int old_off_x = off_x;
 	int old_off_y = off_y;
-	int old_page = page;
+	int old_page = get_page();
 	off_x += dx;
 	off_y += dy;
 
@@ -262,18 +262,18 @@ bool GridLayout::scroll_smooth_noupdate(int dx, int dy) {
 			off_x = border_off_w;
 		}
 	}
-	return off_x != old_off_x || off_y != old_off_y || page != old_page;
+	return off_x != old_off_x || off_y != old_off_y || get_page() != old_page;
 }
 
 void GridLayout::scroll_smooth(int dx, int dy) {
-	int old_page = page;
+	int old_page = get_page();
 	if (scroll_smooth_noupdate(dx, dy)) {
-		viewer->layout_updated(page, page != old_page);
+		viewer->layout_updated(get_page(), get_page() != old_page);
 	}
 }
 
 bool GridLayout::scroll_page_noupdate(int new_page, bool relative) {
-	int old_page = page;
+	int old_page = get_page();
 	int old_off_y = off_y;
 
 	// negative has to stay negative, absolute movement has to account for grid offset
@@ -299,13 +299,50 @@ bool GridLayout::scroll_page_noupdate(int new_page, bool relative) {
 			off_y = border_off_h;
 		}
 	}
-	return page != old_page || off_y != old_off_y;
+	return get_page() != old_page || off_y != old_off_y;
 }
 
 void GridLayout::scroll_page(int new_page, bool relative) {
-	int old_page = page;
+	int old_page = get_page();
 	if (scroll_page_noupdate(new_page, relative)) {
-		viewer->layout_updated(page, page != old_page);
+		viewer->layout_updated(get_page(), get_page() != old_page);
+	}
+}
+
+void GridLayout::scroll_page_top_jump(int new_page, bool relative) {
+	res->store_jump(get_page());
+	int old_page = get_page();
+	bool change = false;
+
+	// calculate column index
+	if (relative) {
+		new_page += page;
+	}
+	if (new_page < 0) {
+		new_page = 0;
+	} else if (new_page >= res->get_page_count()) {
+		new_page = res->get_page_count() - 1;
+	}
+	int column_index = (new_page + grid->get_offset()) % grid->get_column_count();
+
+	// calculate pixel offset
+	int offset = 0;
+//	horizontal_page = 0;
+	if (column_index >= horizontal_page) {
+		for (int i = horizontal_page; i < column_index; i++) {
+			offset += grid->get_width(i) * size + useless_gap;
+		}
+	} else {
+		for (int i = horizontal_page; i >= column_index; i--) {
+			offset -= grid->get_width(i) * size + useless_gap;
+		}
+	}
+
+	// move viewport
+	change |= scroll_smooth_noupdate(-off_x - offset, -off_y);
+	change |= scroll_page_noupdate(new_page, relative);
+	if (change) {
+		viewer->layout_updated(get_page(), get_page() != old_page);
 	}
 }
 
@@ -427,7 +464,7 @@ void GridLayout::view_hit() {
 }
 
 void GridLayout::view_rect(const QRect &r) {
-	int old_page = page;
+	int old_page = get_page();
 
 	// move view horizontally
 	if (r.width() <= width * (1 - 2 * search_padding)) {
@@ -458,10 +495,11 @@ void GridLayout::view_rect(const QRect &r) {
 		scroll_smooth_noupdate(0, center - r.y());
 	}
 	// needs to redraw regardless of change
-	viewer->layout_updated(page, page != old_page);
+	viewer->layout_updated(get_page(), get_page() != old_page);
 }
 
 void GridLayout::view_point(const QPoint &p) {
+	res->store_jump(get_page());
 	scroll_smooth(-p.x(), -p.y());
 }
 
diff --git a/src/layout/gridlayout.h b/src/layout/gridlayout.h
index 60b0afab6bce1fb842f731b9a4ba8816d5401346..c88c44d7fdb71e87b773a4abc0e1d8432d651ce8 100644
--- a/src/layout/gridlayout.h
+++ b/src/layout/gridlayout.h
@@ -23,6 +23,7 @@ public:
 
 	void scroll_smooth(int dx, int dy);
 	void scroll_page(int new_page, bool relative = true);
+	void scroll_page_top_jump(int new_page, bool relative = true);
 	void render(QPainter *painter);
 
 	void advance_invisible_hit(bool forward = true);
diff --git a/src/layout/layout.cpp b/src/layout/layout.cpp
index 7af0b6ac2494ed28421b4ef481c071080992263a..3d5db10248e381870167097c56ea749d5aec9e56 100644
--- a/src/layout/layout.cpp
+++ b/src/layout/layout.cpp
@@ -102,6 +102,11 @@ void Layout::scroll_page_jump(int new_page, bool relative) {
 	scroll_page(new_page, relative);
 }
 
+void Layout::scroll_page_top_jump(int new_page, bool relative) {
+	// override if layout supports smooth scrolling
+	scroll_page_jump(new_page, relative);
+}
+
 void Layout::update_search() {
 	const map<int,QList<QRectF> *> *hits = viewer->get_search_bar()->get_hits();
 	if (hits->empty()) {
diff --git a/src/layout/layout.h b/src/layout/layout.h
index 7ae492e8451881f4413d1bb3fbd0332da5980692..48dad222459a75ce75ee8a2daa800f380e7dad52 100644
--- a/src/layout/layout.h
+++ b/src/layout/layout.h
@@ -30,8 +30,11 @@ public:
 	virtual void scroll_smooth(int dx, int dy);
 	virtual void scroll_page(int new_page, bool relative = true);
 
+	virtual void goto_page_at(int mx, int my);
+
 	// jump movement
 	virtual void scroll_page_jump(int new_page, bool relative = true);
+	virtual void scroll_page_top_jump(int new_page, bool relative = true);
 
 	virtual void update_search();
 	virtual void advance_hit(bool forward = true);
@@ -40,7 +43,6 @@ public:
 	virtual void activate_link(int page, float x, float y);
 	virtual void goto_link_destination(const Poppler::LinkDestination &link);
 	virtual void goto_position(int page, QPointF pos);
-	virtual void goto_page_at(int mx, int my);
 
 	// misc actions
 	virtual void render(QPainter *painter) = 0;