]> www.fi.muni.cz Git - evince.git/blob - shell/ev-dualscreen.c
[dualscreen] cleanup
[evince.git] / shell / ev-dualscreen.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* this file is part of evince, a gnome document viewer
3  *
4  *  Copyright (C) 2007 Johannes Buchner
5  *
6  *  Author:
7  *    Johannes Buchner <buchner.johannes@gmx.at>
8  *    Lukas Bezdicka <255993@mail.muni.cz>
9  *
10  * Evince is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * Evince is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <glib/gi18n.h>
30 #include <gtk/gtk.h>
31
32 #include "ev-dualscreen.h"
33 #include "ev-window.h"
34 #include "ev-view.h"
35 #include "ev-view-presentation.h"
36 #include "ev-utils.h"
37 #include "ev-sidebar.h"
38 #include "ev-sidebar-thumbnails.h"
39
40 struct _EvDSCWindowPrivate {
41         GtkWidget *main_box;
42         GtkWidget *menubar;
43         GtkWidget *sidebar;
44         GtkWidget *notesview;
45         EvDocumentModel *model;
46         EvDocument * notesdocument;
47
48         GtkWidget *notesview_scrolled_window;
49         GtkWidget *presentation_window;
50
51         EvViewPresentation *presentation_view;
52         EvDocument * presentation_document;
53         gint moveback_monitor;
54 };
55
56 #define EV_DSCWINDOW_GET_PRIVATE(object) \
57         (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_DSCWINDOW, EvDSCWindowPrivate))
58 #define PAGE_CACHE_SIZE 52428800 /* 50MB */
59 #define SIDEBAR_DEFAULT_SIZE    132
60
61 /*static gpointer parent_class = NULL;*/
62
63 G_DEFINE_TYPE (EvDSCWindow, ev_dscwindow, GTK_TYPE_WINDOW)
64
65 /**
66  * ev_dscwindow_switch_monitors: Bring the presentation window and the control window each on the other monitor.
67  *
68  * @widget: Callback widget
69  * @self: EvDSCWindow
70  **/
71 static gboolean
72 ev_dscwindow_switch_monitors (GtkWidget *widget, EvDSCWindow *self)
73 {
74 /*
75 +       if (!EV_IS_DSCWINDOW (self))
76 +               return FALSE;
77 +
78 +       EvDSCWindowPrivate *priv = EV_DSCWINDOW_GET_PRIVATE (self);
79 +
80 +       gint num_monitors = get_num_monitors (GTK_WINDOW (self));
81 +
82 +       if (num_monitors == 2) {
83 +               GtkWindow * presentation_window = GTK_WINDOW (priv->presentation_window);
84 +               GdkScreen * screen = gtk_window_get_screen (presentation_window);
85 +
86 +               gint monitor_1 = gdk_screen_get_monitor_at_window (screen,
87 +                       GTK_WIDGET (presentation_window)->window);
88 +
89 +               gint monitor_2 = (monitor_1 + 1) % 2;
90 +
91 +               GdkRectangle coords;
92 +               gdk_screen_get_monitor_geometry (screen, monitor_2, &coords);
93 +               ev_window_stop_presentation (priv->presentation_window);
94 +               gtk_window_move (presentation_window, coords.x, coords.y);
95 +               ev_window_run_presentation (priv->presentation_window);
96 +               priv->moveback_monitor = monitor_1;
97 +
98 +               gdk_screen_get_monitor_geometry (screen, monitor_1, &coords);
99 +               gtk_window_unmaximize (GTK_WINDOW (self));
100 +               gtk_window_move (GTK_WINDOW (self), coords.x, coords.y);
101 +               gtk_window_maximize (GTK_WINDOW (self));
102 +       }*/
103         return TRUE;
104 }
105
106 /**
107  * ev_dscwindow_notes_interaction: User wants to load a different file as notes.
108  **/
109 static gboolean
110 ev_dscwindow_notes_interaction (GtkContainer *container, EvDSCWindow *self)
111 {
112 /*
113 +       EvDSCWindowPrivate *priv = EV_DSCWINDOW_GET_PRIVATE (self);
114 +       GtkWidget *dialog;
115 +
116 +       dialog = gtk_file_chooser_dialog_new (
117 +               _("Open Document"),
118 +               GTK_WINDOW (self),
119 +               GTK_FILE_CHOOSER_ACTION_OPEN,
120 +               GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
121 +               GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
122 +               NULL);
123 +
124 +       ev_document_factory_add_filters (dialog, NULL);
125 +       gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), FALSE);
126 +       gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE);
127 +
128 +       if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
129 +       {
130 +               char * uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
131 +               GError * error = NULL;
132 +               ev_view_set_loading (EV_VIEW (priv->notesview), TRUE);
133 +
134 +               if (priv->notesdocument) {
135 +                       ev_document_load (priv->notesdocument, uri, &error);
136 +               } else {
137 +                       priv->notesdocument = ev_document_factory_get_document (uri,
138 +                               &error);
139 +               }
140 +               g_free (uri);
141 +               if (error == NULL){
142 +                       ev_view_set_document (EV_VIEW (priv->notesview),
143 +                               priv->notesdocument);
144 +                       /* TODO: go to the same page that is open at the moment, or
145 +                        * move the presentation to the beginning. *//*
146 +               }
147 +       }
148 +       gtk_widget_destroy (dialog);
149 */
150         return TRUE;
151 }
152
153 /**
154  * ev_dscwindow_get_control: Get the control instance.
155  *
156  * If there is none, create one.
157  *
158  * Returns: control instance
159  **/
160 EvDSCWindow *
161 ev_dscwindow_get_control (void)
162 {
163         static EvDSCWindow * control = NULL;
164
165         if (!control || !EV_IS_DSCWINDOW (control)) {
166                 control = EV_DSCWINDOW (g_object_new (EV_TYPE_DSCWINDOW, NULL));
167         }
168
169         return control;
170 }
171
172 /*TODO: Fix me!*/
173 static void
174 ev_dscwindow_window_placement (EvDSCWindow *ev_dscwindow)
175 {
176         gint num_monitors = get_num_monitors (GTK_WINDOW (ev_dscwindow));
177         //if (num_monitors == 2) {
178                 GtkWindow * presentation_window = GTK_WINDOW (ev_dscwindow->priv->presentation_window);
179                 GdkScreen * screen = gtk_window_get_screen (presentation_window);
180                 gint work_monitor = gdk_screen_get_monitor_at_window (screen,
181                         gtk_widget_get_window (GTK_WIDGET (presentation_window)));
182                 gint presentation_monitor = (work_monitor + 1) % 2;
183                 GdkRectangle coords;
184                 gdk_screen_get_monitor_geometry (screen, presentation_monitor,
185                         &coords);
186
187                 gtk_window_move (presentation_window, coords.x, coords.y);
188                 //ev_window_run_presentation (ev_dscwindow->priv->presentation_window);
189                 ev_dscwindow->priv->moveback_monitor = work_monitor;
190                 gtk_window_maximize (GTK_WINDOW (ev_dscwindow));
191         //}
192 }
193 /**
194  * ev_dscwindow_page_changed_cb: Callback to change page on all views
195  *
196  **/
197 static void
198 ev_dscwindow_page_changed_cb (EvDocumentModel *model,
199                            GParamSpec      *pspec,
200                            EvDSCWindow     *ev_dscwindow)
201 {
202         gint page = ev_document_model_get_page (model);
203         if(page != ev_view_presentation_get_current_page (ev_dscwindow->priv->presentation_view))
204                 ev_view_presentation_set_page (EV_VIEW_PRESENTATION(ev_dscwindow->priv->presentation_view), page);
205 }
206 static void
207 ev_dscwindow_presentation_page_changed_cb (EvViewPresentation *pview,
208                            GParamSpec      *pspec,
209                            EvDSCWindow     *ev_dscwindow)
210 {
211         gint page = ev_view_presentation_get_current_page (pview);
212         ev_document_model_set_page (ev_dscwindow->priv->model, page);
213 }
214
215 static gboolean
216 ev_dscwindow_notes_clicked (GtkWidget *widget, GdkEvent *event,
217         EvDSCWindow *self)
218 {
219         if (!self || !EV_IS_DSCWINDOW (self) || !event)
220                 return FALSE;
221         gint page = ev_document_model_get_page (self->priv->model);
222
223         if (event->type == GDK_2BUTTON_PRESS && ((GdkEventButton *)event)->button == 1) {
224                 ev_dscwindow_notes_interaction (NULL, self);
225         } else if (event->type == GDK_BUTTON_PRESS && ((GdkEventButton *)event)->button == 1) {
226                 ev_document_model_set_page (self->priv->model, page+1);
227         } else if (event->type == GDK_BUTTON_PRESS && ((GdkEventButton *)event)->button == 3) {
228                 ev_document_model_set_page (self->priv->model, page-1);
229         }
230         return FALSE;
231 }
232
233 /**
234  * ev_dscwindow_set_presentation: Set presentation document
235  * @presentation_window: Main window we can reuse for presentation
236  **/
237 void
238 ev_dscwindow_set_presentation (EvDSCWindow *ev_dscwindow,
239         EvWindow *presentation_window, EvDocument *document, EvViewPresentation *pview)
240 {
241         if (!EV_IS_WINDOW (presentation_window))
242                 return;
243
244         ev_dscwindow->priv->presentation_window = GTK_WIDGET(presentation_window);
245         ev_dscwindow->priv->presentation_document = document;
246         ev_dscwindow->priv->presentation_view = EV_VIEW_PRESENTATION(pview);
247         ev_document_model_set_document(ev_dscwindow->priv->model,
248                 document);
249         g_signal_connect_swapped (ev_dscwindow->priv->presentation_view,
250                                   "destroy",
251                                   G_CALLBACK (gtk_widget_destroy),
252                                   ev_dscwindow);
253         g_signal_connect (G_OBJECT(ev_dscwindow->priv->presentation_view),
254                           "notify::page",
255                           G_CALLBACK (ev_dscwindow_presentation_page_changed_cb),
256                           ev_dscwindow);
257         ev_dscwindow_window_placement (ev_dscwindow);
258 }
259
260 /**
261  * ev_dscwindow_end: Destroy control window but keep presentation
262  */
263 static gboolean
264 ev_dscwindow_end (GtkWidget *widget, GdkEvent *event)
265 {
266         gtk_widget_destroy (GTK_WIDGET (ev_dscwindow_get_control ()));
267         return TRUE;
268 }
269
270 /**
271  * ev_dscwindow_init: Initialize multihead presentation
272 *
273 * @ev_dscwindow: EvDSCWindow.
274 *
275 * ev_dscwindow_set_presentation has to be called afterwards for loading in a document. TBD
276 **/
277 static void
278 ev_dscwindow_init (EvDSCWindow *ev_dscwindow)
279 {
280         ev_dscwindow->priv = EV_DSCWINDOW_GET_PRIVATE (ev_dscwindow);
281         ev_dscwindow->priv->moveback_monitor = -1;
282         ev_dscwindow->priv->notesdocument = NULL;
283
284         gtk_window_set_title (GTK_WINDOW (ev_dscwindow), _("Presentation Control"));
285
286         GtkWidget *h = gtk_hpaned_new ();
287         GtkWidget *v = gtk_vbox_new (FALSE, 0);
288
289         ev_dscwindow->priv->model = ev_document_model_new ();
290         g_signal_connect (G_OBJECT(ev_dscwindow->priv->model),
291                           "notify::page",
292                           G_CALLBACK (ev_dscwindow_page_changed_cb),
293                           ev_dscwindow);
294         ev_dscwindow->priv->sidebar = ev_sidebar_new ();
295         ev_sidebar_set_model (EV_SIDEBAR (ev_dscwindow->priv->sidebar),
296                               ev_dscwindow->priv->model);
297         gtk_box_pack_start (GTK_BOX (v), ev_dscwindow->priv->sidebar, TRUE , TRUE, 0);
298         gtk_widget_show (ev_dscwindow->priv->sidebar);
299
300         GtkWidget *sidebar_widget;
301         sidebar_widget = ev_sidebar_thumbnails_new ();
302         /*g_signal_connect (sidebar_widget,
303                           "notify::main-widget",
304                           G_CALLBACK (sidebar_page_main_widget_update_cb),
305                           ev_window);
306         sidebar_page_main_widget_update_cb (G_OBJECT (sidebar_widget), NULL, ev_window);*/
307         gtk_widget_show (sidebar_widget);
308         ev_sidebar_add_page (EV_SIDEBAR (ev_dscwindow->priv->sidebar),
309                              sidebar_widget);
310
311         ev_document_model_set_continuous (ev_dscwindow->priv->model, FALSE);
312         ev_document_model_set_dual_page (ev_dscwindow->priv->model, FALSE);
313         ev_document_model_set_sizing_mode (ev_dscwindow->priv->model, EV_SIZING_BEST_FIT);
314
315         GtkWidget *e = gtk_expander_new (_("Expensive features"));
316         gtk_expander_set_expanded (GTK_EXPANDER (e), TRUE);
317
318         GtkWidget *t = gtk_toolbar_new ();
319
320         GtkToolItem* b_switch = gtk_tool_button_new (NULL, _("Switch monitors"));
321         gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (b_switch), "object-flip-horizontal");
322         gtk_toolbar_insert (GTK_TOOLBAR (t), b_switch, -1);
323         g_signal_connect (b_switch, "clicked",
324                 G_CALLBACK (ev_dscwindow_switch_monitors), ev_dscwindow);
325
326         GtkToolItem* b_notes = gtk_tool_button_new (NULL, _("Load notes ..."));
327         gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (b_notes), "object-flip-horizontal");
328         gtk_toolbar_insert (GTK_TOOLBAR (t), b_notes, -1);
329         g_signal_connect (b_notes, "clicked",
330                 G_CALLBACK (ev_dscwindow_notes_interaction), ev_dscwindow);
331
332         GtkToolItem* b_close = gtk_tool_button_new (NULL, _("End presentation"));
333         gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (b_close), "view-restore");
334         gtk_toolbar_insert (GTK_TOOLBAR (t), b_close, -1);
335         /*TODO: rework close*/
336         g_signal_connect (b_close, "clicked",
337                 G_CALLBACK (ev_dscwindow_end), NULL);
338
339         gtk_container_add (GTK_CONTAINER (e), t);
340         gtk_box_pack_end (GTK_BOX (v), e, FALSE, TRUE, 0);
341         gtk_paned_add1 (GTK_PANED (h), v);
342
343         ev_dscwindow->priv->notesview_scrolled_window = GTK_WIDGET (g_object_new (
344                 GTK_TYPE_SCROLLED_WINDOW, "shadow-type", GTK_SHADOW_IN, NULL));
345         gtk_paned_add2 (GTK_PANED (h), ev_dscwindow->priv->notesview_scrolled_window);
346
347         ev_dscwindow->priv->notesview = ev_view_new ();
348         g_object_ref (ev_dscwindow->priv->notesview);
349         gtk_container_add (GTK_CONTAINER (ev_dscwindow->priv->notesview_scrolled_window),
350                 ev_dscwindow->priv->notesview);
351         ev_view_set_model (EV_VIEW (ev_dscwindow->priv->notesview), ev_dscwindow->priv->model);
352         gtk_widget_show_all (h);
353         gtk_container_add (GTK_CONTAINER (ev_dscwindow), h);
354
355         gtk_drag_dest_unset (GTK_WIDGET (ev_dscwindow->priv->notesview));
356         gtk_drag_dest_unset (GTK_WIDGET (ev_dscwindow->priv->sidebar));
357
358         gint click = GDK_BUTTON1_MOTION_MASK | GDK_KEY_PRESS_MASK;
359         gtk_widget_add_events (GTK_WIDGET (ev_dscwindow->priv->sidebar), click);
360         /* TODO: actions*/
361         g_signal_connect (ev_dscwindow->priv->notesview, "button-press-event",
362                           G_CALLBACK (ev_dscwindow_notes_clicked), ev_dscwindow);
363 }
364
365
366 static void
367 ev_dscwindow_dispose (GObject *obj)
368 {
369         EvDSCWindow * ev_dscwindow = EV_DSCWINDOW (obj);
370         EvDSCWindowPrivate *priv = ev_dscwindow->priv;
371
372         if (priv->moveback_monitor >= 0) {
373                 GtkWindow * presentation_window = GTK_WINDOW (priv->presentation_window);
374                 GdkRectangle coords;
375
376                 gdk_screen_get_monitor_geometry (
377                         gtk_window_get_screen (presentation_window),
378                         priv->moveback_monitor, &coords);
379
380                 gtk_window_move (presentation_window, coords.x, coords.y);
381         }
382         ev_window_stop_presentation (EV_WINDOW(priv->presentation_window), TRUE);
383         /*if (priv->overview) {
384                 g_object_unref (priv->overview);
385                 priv->overview = NULL;
386         }*/
387
388
389         G_OBJECT_CLASS (ev_dscwindow_parent_class)->dispose (obj);
390 }
391
392 static void
393 ev_dscwindow_class_init (EvDSCWindowClass *ev_dscwindow_class)
394 {
395         GObjectClass *g_object_class = G_OBJECT_CLASS (ev_dscwindow_class);
396         g_type_class_add_private (g_object_class, sizeof (EvDSCWindowPrivate));
397         g_object_class->dispose  = ev_dscwindow_dispose;
398 }
399
400 GtkWidget *
401 ev_dscwindow_new (void)
402 {
403         EvDSCWindow *ev_dscwindow;
404
405         ev_dscwindow = g_object_new (EV_TYPE_DSCWINDOW, "type", GTK_WINDOW_TOPLEVEL, NULL);
406         return GTK_WIDGET (ev_dscwindow);
407 }