Index: ev-dualscreen.txt
===================================================================
--- ev-dualscreen.txt	(revision 0)
+++ ev-dualscreen.txt	(revision 0)
@@ -0,0 +1,53 @@
+This file should give you the general idea to ev-dualscreen.c
+
+
+  Dual-screen presentation feature for evince
+  ___________________________________________
+
+ Monitor 1 (Your screen):                  Monitor 2 (Beamer / Projector)
+  
+   ev_view of the presentation pdf
+   width = 1/3*presentationwidth.
+    |
+    |
+    |        ev_view of another file,
+    |        Notes.pdf. contains same       ev_view presentation mode of 
+    |        number of pages                the presentation file
+    |         |                               |
+    v         v                               v
+  +-------++----------------+              +-------------------------+
+  |       ||                |              |                         |
+  | Prev  || Notes.pdf      |              |                         |
+  | Slide ||                |              |                         |
+  +-------+|                |              |                         |
+  |       ||                |              |                         |
+  |Current||                |              |       Current Slide     |
+  | Slide ||                |              |      of presentation    |
+  +-------+|                |              |                         |
+  |       ||                |              |                         |
+  | Next  ||                |              |                         |
+  | Slide ||                |              |                         |
+  +-------++----------------+              +-------------------------+
+
+Features:
+  - clicking anywhere => next slide; right-clicking anywhere => prev slide
+    The page number is the same on all three views. 
+
+Possible way of integration:
+
+  <del>a) Own application "evince-presentation" shipped with evince</del>
+
+  b) Menu item "Dual-Screen presentation"
+     => opens the control window with the current file as presentation file
+     => allows to select a notes file
+
+The general idea for window placement is that the user does it (move, set the 
+first window to presentation mode).
+I didn't look at it, but detecting which part of the screen is on the beamer 
+would be quite rough. Also, there is no setup of dualscreen mode what so ever, 
+the user has to do this before (add second monitor in xorg.conf). 
+
+
+Maybe later features: 
+  - clock (without seconds, these distract IMHO)
+  - timer
Index: ev-dualscreen.c
===================================================================
--- ev-dualscreen.c	(revision 0)
+++ ev-dualscreen.c	(revision 0)
@@ -0,0 +1,207 @@
+/**
+ * Licence: whatever ...
+ * Author: Johannes Buchner
+ *
+ ****
+ *
+ * TODO: g_signal_connect (ev_window->priv->page_cache, "page-changed",
+			  G_CALLBACK (page_changed_cb), ev_window);
+         Connect the page change between the views.
+		 It seems to work for 1 document, but it also should when loading a 
+		 notes pdf into notesview.
+ * TODO: Check for memory leaks (maybe use unref?). Especially after window destroy.
+ * TODO: It is quite slow atm. Can we load the whole document in memory?
+         (just during the presentation)
+ * TODO: Allow loading of a notes files at the right view. Shall we make a 
+         button (bar), a right click menu, double clicking?
+ ***/
+
+#include "ev-dualscreen.h"
+
+#define EV_DSCWINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EV_TYPE_DSCWINDOW, EvDSCWindowPrivate))
+
+typedef struct _EvDSCWindowPrivate {
+	GtkWidget *main_box;
+	GtkWidget *menubar;
+	GtkWidget *overview;
+	GtkWidget *notesview;
+	
+	GtkWidget *overview_scrolled_window;
+	GtkWidget *notesview_scrolled_window;
+	
+	EvWindow *presentation_window; 
+	EvDocument *presentation_document;
+} EvDSCWindowPrivate;
+
+G_DEFINE_TYPE (EvDSCWindow, ev_dscwindow, GTK_TYPE_WINDOW)
+
+static gdouble ev_dscwindow_get_screen_dpi (EvDSCWindow *ev_window);
+static void update_view_size (EvView *view, GtkWidget * scrolled_window);
+
+static void
+ev_dscwindow_handle_position_change_cb (GObject *object, GParamSpec *pspec,
+				      EvDSCWindow *ev_dscwindow)
+{
+	g_message("ev_dscwindow_handle_position_change_cb");
+	EvDSCWindowPrivate *priv = EV_DSCWINDOW_GET_PRIVATE(ev_dscwindow);
+
+	update_view_size(EV_VIEW(priv->overview),  GTK_WIDGET(priv->overview_scrolled_window ));
+	update_view_size(EV_VIEW(priv->notesview), GTK_WIDGET(priv->notesview_scrolled_window));
+}
+static void 
+ev_dscwindow_handle_resized(GtkContainer *container, gpointer user_data){
+	g_message("ev_dscwindow_handle_resized");
+}
+
+static void 
+ev_dscwindow_init(EvDSCWindow * self){
+	EvDSCWindowPrivate *priv = EV_DSCWINDOW_GET_PRIVATE(self);
+	gtk_window_set_title (GTK_WINDOW (self), _("Presentation Control"));
+	GtkWidget* h = gtk_hpaned_new ();
+	
+	// Left side:
+	/* Wanted setup: 
+	   2 pages high, continous, not dual. fit page width (or best fit).
+	 */ 
+	priv->overview_scrolled_window = GTK_WIDGET (g_object_new (
+		GTK_TYPE_SCROLLED_WINDOW, "shadow-type", GTK_SHADOW_IN, NULL));
+	gtk_widget_show (priv->overview_scrolled_window);
+	gtk_paned_add1(GTK_PANED(h), priv->overview_scrolled_window);
+	
+	priv->overview  = ev_view_new();
+	ev_view_set_screen_dpi (EV_VIEW (priv->overview),
+				ev_dscwindow_get_screen_dpi (self));
+	gtk_container_add (GTK_CONTAINER (priv->overview_scrolled_window),
+			   priv->overview);
+	gtk_widget_show (priv->overview);
+	
+	ev_view_set_continuous  (EV_VIEW (priv->overview), TRUE);
+	ev_view_set_dual_page   (EV_VIEW (priv->overview), FALSE); 
+	ev_view_set_sizing_mode (EV_VIEW (priv->overview), EV_SIZING_BEST_FIT);
+	
+	// Right side:
+	/* Wanted setup: 
+	   Just one page. best fit. not dual.
+	 */ 
+	priv->notesview_scrolled_window = GTK_WIDGET (g_object_new (
+		GTK_TYPE_SCROLLED_WINDOW, "shadow-type", GTK_SHADOW_IN, NULL));
+	gtk_widget_show (priv->notesview_scrolled_window);
+	gtk_paned_add2(GTK_PANED(h), priv->notesview_scrolled_window);
+	
+	priv->notesview = ev_view_new();
+	ev_view_set_screen_dpi (EV_VIEW (priv->notesview),
+				ev_dscwindow_get_screen_dpi (self));
+	gtk_container_add (GTK_CONTAINER (priv->notesview_scrolled_window),
+			   priv->notesview);
+	gtk_widget_show (priv->notesview);
+	
+	ev_view_set_continuous(EV_VIEW (priv->notesview), FALSE);
+	ev_view_set_dual_page(EV_VIEW (priv->notesview), FALSE); 
+	ev_view_set_sizing_mode (EV_VIEW (priv->notesview), EV_SIZING_BEST_FIT);
+	
+	/* ok, done */
+	// TODO: set width of left thing to: (height/[3 or 2?])*doc_width/doc_height
+	gtk_paned_set_position(GTK_PANED(h), 300);
+	gtk_widget_show (h);
+	gtk_container_add (GTK_CONTAINER (self), h);
+	
+	// TODO: Should we maximize the window? 
+	gtk_window_set_default_size (GTK_WINDOW (self), 600, 600);
+	
+	// get the views loaded right in the first place:
+	ev_dscwindow_handle_position_change_cb(NULL, NULL, self);
+	g_signal_connect (h, "notify::position", 
+		G_CALLBACK (ev_dscwindow_handle_position_change_cb), self);
+	
+	g_signal_connect (self, "notify::check-resize", 
+		G_CALLBACK (ev_dscwindow_handle_resized), self);
+	
+}
+
+static void 
+ev_dscwindow_dispose(GObject *obj){
+	EvDSCWindowPrivate *priv = EV_DSCWINDOW_GET_PRIVATE(EV_DSCWINDOW(obj));
+	// unload the documents from the views
+	ev_view_set_document(EV_VIEW (priv->overview),  NULL);
+	ev_view_set_document(EV_VIEW (priv->notesview), NULL);
+
+	// Remove the window, but this crashes:
+	//GtkWindow * win = GTK_WINDOW(obj);
+	//G_OBJECT_CLASS (win)->dispose (obj);
+}
+
+static void 
+ev_dscwindow_class_init(EvDSCWindowClass * klass){
+	GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
+	g_type_class_add_private (klass, sizeof (EvDSCWindowPrivate));
+	g_object_class->dispose  = ev_dscwindow_dispose;
+}
+
+GtkWidget *
+ev_dscwindow_new (void)
+{
+	return GTK_WIDGET (g_object_new (EV_TYPE_DSCWINDOW, 
+		"type", GTK_WINDOW_TOPLEVEL, NULL));
+}
+
+void
+ev_dscwindow_set_presentation (EvDSCWindow * self, 
+	EvWindow *presentation_window, EvDocument *document)
+{
+	if(EV_IS_WINDOW(presentation_window)){
+		EvDSCWindowPrivate *priv = EV_DSCWINDOW_GET_PRIVATE(self);
+		priv->presentation_window = presentation_window;
+		priv->presentation_document = document;
+		
+		ev_view_set_document(EV_VIEW (priv->overview),  priv->presentation_document);
+		ev_view_set_document(EV_VIEW (priv->notesview), priv->presentation_document);
+	}
+}
+
+/* cut'n'pasted: */
+
+static gdouble
+ev_dscwindow_get_screen_dpi (EvDSCWindow *ev_window)
+{
+	GdkScreen *screen;
+	gdouble    xdpi, ydpi;
+
+	screen = gtk_window_get_screen (GTK_WINDOW (ev_window));
+
+	xdpi = 25.4 * gdk_screen_get_width (screen) / gdk_screen_get_width_mm (screen);
+	ydpi = 25.4 * gdk_screen_get_height (screen) / gdk_screen_get_height_mm (screen);
+	
+	return (xdpi + ydpi) / 2.0;
+}
+
+static void
+update_view_size (EvView *view, GtkWidget * scrolled_window)
+{
+	int width, height;
+	GtkRequisition vsb_requisition;
+	GtkRequisition hsb_requisition;
+	int scrollbar_spacing;
+		
+	/* Calculate the width available for the */
+	width = scrolled_window->allocation.width;
+	height = scrolled_window->allocation.height;
+
+	if (gtk_scrolled_window_get_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window)) == GTK_SHADOW_IN) {
+		width -= 2 * GTK_WIDGET(view)->style->xthickness;
+		height -= 2 * GTK_WIDGET(view)->style->ythickness;
+	}
+
+	gtk_widget_size_request (GTK_SCROLLED_WINDOW (scrolled_window)->vscrollbar,
+				 &vsb_requisition);
+	gtk_widget_size_request (GTK_SCROLLED_WINDOW (scrolled_window)->hscrollbar,
+				 &hsb_requisition);
+	gtk_widget_style_get (scrolled_window,
+			      "scrollbar_spacing", &scrollbar_spacing,
+			      NULL);
+
+	ev_view_set_zoom_for_size (EV_VIEW (view),
+				   MAX (1, width),
+				   MAX (1, height),
+				   vsb_requisition.width + scrollbar_spacing,
+				   hsb_requisition.height + scrollbar_spacing);
+}
Index: ev-dualscreen.h
===================================================================
--- ev-dualscreen.h	(revision 0)
+++ ev-dualscreen.h	(revision 0)
@@ -0,0 +1,37 @@
+/**
+ * Licence: whatever ...
+ * Author: Johannes Buchner
+ * See ev-dualscreen.txt
+ */
+
+#ifndef EV_DUALSCREEN_H
+#define EV_DUALSCREEN_H
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include "ev-window.h"
+#include "ev-view.h"
+
+G_BEGIN_DECLS
+typedef struct _EvDSCWindow {
+	GtkWindow		base_instance;
+} EvDSCWindow;
+typedef struct _EvDSCWindowClass {
+	GtkWindowClass base_class;
+} EvDSCWindowClass;
+
+#define EV_TYPE_DSCWINDOW			(ev_dscwindow_get_type())
+#define EV_DSCWINDOW(object)		(G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_DSCWINDOW, EvDSCWindow))
+#define EV_DSCWINDOW_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_DSCWINDOW, EvDSCWindowClass))
+#define EV_IS_DSCWINDOW(object)		(G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_DSCWINDOW))
+#define EV_IS_DSCWINDOW_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_DSCWINDOW))
+#define EV_DSCWINDOW_GET_CLASS(object)	(G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_DSCWINDOW, EvDSCWindowClass))
+
+GType		ev_dscwindow_get_type	  (void);
+GtkWidget * ev_dscwindow_new (void);
+void ev_dscwindow_set_presentation (EvDSCWindow * self, 
+	EvWindow *presentation_window, EvDocument *document);
+G_END_DECLS
+
+#endif /* EV_DUALSCREEN_H */
Index: ev-window.c
===================================================================
--- ev-window.c	(revision 2510)
+++ ev-window.c	(working copy)
@@ -47,6 +47,7 @@
 #include "ev-document-find.h"
 #include "ev-document-security.h"
 #include "ev-document-factory.h"
+#include "ev-dualscreen.h"
 #include "ev-job-queue.h"
 #include "ev-jobs.h"
 #include "ev-sidebar-page.h"
@@ -270,6 +271,7 @@
 static void	view_handle_link_cb 			(EvView *view, 
 							 EvLink *link, 
 							 EvWindow *window);
+static void ev_window_cmd_dualscreen(GtkWidget *widget, gpointer user_data);
 
 G_DEFINE_TYPE (EvWindow, ev_window, GTK_TYPE_WINDOW)
 
@@ -390,6 +392,7 @@
 	ev_window_set_action_sensitive (ev_window, "ViewBestFit", has_pages);
 	ev_window_set_action_sensitive (ev_window, "ViewPageWidth", has_pages);
 	ev_window_set_action_sensitive (ev_window, "ViewReload", has_pages);
+	ev_window_set_action_sensitive (ev_window, "ViewDualScreenPresentation", has_pages);
 
 	/* Toolbar-specific actions: */
 	ev_window_set_action_sensitive (ev_window, PAGE_SELECTOR_ACTION, has_pages);
@@ -2719,6 +2722,15 @@
 	ev_window_update_actions (ev_window);
 }
 
+static void 
+ev_window_cmd_dualscreen(GtkWidget *widget, gpointer user_data)
+{
+	EvWindow *presentation_window = EV_WINDOW (user_data);
+	EvDSCWindow * new_control = EV_DSCWINDOW(g_object_new(EV_TYPE_DSCWINDOW, NULL));
+	ev_dscwindow_set_presentation (new_control, presentation_window, presentation_window->priv->document);
+	gtk_window_present(GTK_WINDOW(new_control));
+}
+
 static void
 ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
 {
@@ -4338,6 +4350,9 @@
         { "ViewReload", GTK_STOCK_REFRESH, N_("_Reload"), "<control>R",
           N_("Reload the document"),
           G_CALLBACK (ev_window_cmd_view_reload) },
+        { "ViewDualScreenPresentation", NULL, N_("Dualscreen Presentation Mode"), NULL /*Shortcut*/,
+          N_("Run document as a presentation for multihead screens"),
+          G_CALLBACK (ev_window_cmd_dualscreen) },
 
         /* Go menu */
         { "GoPreviousPage", GTK_STOCK_GO_BACK, N_("_Previous Page"), "<control>Page_Up",
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 2510)
+++ Makefile.am	(working copy)
@@ -27,6 +27,8 @@
 	eggfindbar.h			\
 	ev-application.c		\
 	ev-application.h		\
+	ev-dualscreen.c			\
+	ev-dualscreen.h			\
 	ev-job-queue.h			\
 	ev-job-queue.c			\
 	ev-jobs.h			\
