]> www.fi.muni.cz Git - evince.git/blob - previewer/ev-previewer-window.c
[printing] Make use of gtk+-unix-print optional
[evince.git] / previewer / ev-previewer-window.c
1 /* ev-previewer-window.c: 
2  *  this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include <config.h>
22
23 #if GTKUNIXPRINT_ENABLED
24 #include <gtk/gtkunixprint.h>
25 #endif
26 #include <glib/gi18n.h>
27 #include <evince-view.h>
28 #include "ev-page-action.h"
29
30 #include "ev-previewer-window.h"
31
32 struct _EvPreviewerWindow {
33         GtkWindow         base_instance;
34
35         EvDocument       *document;
36
37         GtkActionGroup   *action_group;
38         GtkUIManager     *ui_manager;
39
40         GtkWidget        *swindow;
41         EvView           *view;
42         gdouble           dpi;
43
44         /* Printing */
45         GtkPrintSettings *print_settings;
46         GtkPageSetup     *print_page_setup;
47 #if GTKUNIXPRINT_ENABLED
48         GtkPrinter       *printer;
49 #endif
50         gchar            *print_job_title;
51         gchar            *source_file;
52 };
53
54 struct _EvPreviewerWindowClass {
55         GtkWindowClass base_class;
56 };
57
58 G_DEFINE_TYPE (EvPreviewerWindow, ev_previewer_window, GTK_TYPE_WINDOW)
59
60 static gdouble
61 get_screen_dpi (GtkWindow *window)
62 {
63         GdkScreen *screen;
64         gdouble    xdpi, ydpi;
65
66         screen = gtk_window_get_screen (window);
67
68         xdpi = 25.4 * gdk_screen_get_width (screen) / gdk_screen_get_width_mm (screen);
69         ydpi = 25.4 * gdk_screen_get_height (screen) / gdk_screen_get_height_mm (screen);
70
71         return (xdpi + ydpi) / 2.0;
72 }
73
74 static void
75 ev_previewer_window_set_view_size (EvPreviewerWindow *window)
76 {
77         gint width, height;
78         GtkRequisition vsb_requisition;
79         GtkRequisition hsb_requisition;
80         gint scrollbar_spacing;
81
82         if (!window->view)
83                 return;
84
85         /* Calculate the width available for the content */
86         width  = window->swindow->allocation.width;
87         height = window->swindow->allocation.height;
88
89         if (gtk_scrolled_window_get_shadow_type (GTK_SCROLLED_WINDOW (window->swindow)) == GTK_SHADOW_IN) {
90                 width -=  2 * GTK_WIDGET (window->view)->style->xthickness;
91                 height -= 2 * GTK_WIDGET (window->view)->style->ythickness;
92         }
93
94         gtk_widget_size_request (GTK_SCROLLED_WINDOW (window->swindow)->vscrollbar,
95                                  &vsb_requisition);
96         gtk_widget_size_request (GTK_SCROLLED_WINDOW (window->swindow)->hscrollbar,
97                                  &hsb_requisition);
98         gtk_widget_style_get (window->swindow,
99                               "scrollbar_spacing",
100                               &scrollbar_spacing,
101                               NULL);
102
103         ev_view_set_zoom_for_size (window->view,
104                                    MAX (1, width),
105                                    MAX (1, height),
106                                    vsb_requisition.width + scrollbar_spacing,
107                                    hsb_requisition.height + scrollbar_spacing);
108 }
109
110 #if GTKUNIXPRINT_ENABLED
111 static void
112 ev_previewer_window_error_dialog_run (EvPreviewerWindow *window,
113                                       GError            *error)
114 {
115         GtkWidget *dialog;
116
117         dialog = gtk_message_dialog_new (GTK_WINDOW (window),
118                                          GTK_DIALOG_MODAL |
119                                          GTK_DIALOG_DESTROY_WITH_PARENT,
120                                          GTK_MESSAGE_ERROR,
121                                          GTK_BUTTONS_CLOSE,
122                                          "%s", _("Failed to print document"));
123         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
124                                                   "%s", error->message);
125         gtk_dialog_run (GTK_DIALOG (dialog));
126         gtk_widget_destroy (dialog);
127 }
128 #endif
129
130 static void
131 ev_previewer_window_previous_page (GtkAction         *action,
132                                    EvPreviewerWindow *window)
133 {
134         ev_view_previous_page (window->view);
135 }
136
137 static void
138 ev_previewer_window_next_page (GtkAction         *action,
139                                EvPreviewerWindow *window)
140 {
141         ev_view_next_page (window->view);
142 }
143
144 static void
145 ev_previewer_window_zoom_in (GtkAction         *action,
146                              EvPreviewerWindow *window)
147 {
148         ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
149         ev_view_zoom_in (window->view);
150 }
151
152 static void
153 ev_previewer_window_zoom_out (GtkAction         *action,
154                               EvPreviewerWindow *window)
155 {
156         ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
157         ev_view_zoom_out (window->view);
158 }
159
160 static void
161 ev_previewer_window_zoom_best_fit (GtkToggleAction   *action,
162                                    EvPreviewerWindow *window)
163 {
164         if (gtk_toggle_action_get_active (action)) {
165                 ev_view_set_sizing_mode (window->view, EV_SIZING_BEST_FIT);
166                 ev_previewer_window_set_view_size (window);
167         } else {
168                 ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
169         }
170 }
171
172 static void
173 ev_previewer_window_zoom_page_width (GtkToggleAction   *action,
174                                      EvPreviewerWindow *window)
175 {
176         if (gtk_toggle_action_get_active (action)) {
177                 ev_view_set_sizing_mode (window->view, EV_SIZING_FIT_WIDTH);
178                 ev_previewer_window_set_view_size (window);
179         } else {
180                 ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
181         }
182 }
183
184 static void
185 ev_previewer_window_action_page_activated (GtkAction         *action,
186                                            EvLink            *link,
187                                            EvPreviewerWindow *window)
188 {
189         ev_view_handle_link (window->view, link);
190         gtk_widget_grab_focus (GTK_WIDGET (window->view));
191 }
192
193 #if GTKUNIXPRINT_ENABLED
194 static void
195 ev_previewer_window_print_finished (GtkPrintJob       *print_job,
196                                     EvPreviewerWindow *window,
197                                     GError            *error)
198 {
199         if (error) {
200                 ev_previewer_window_error_dialog_run (window, error);
201         }
202
203         g_object_unref (print_job);
204         gtk_widget_destroy (GTK_WIDGET (window));
205 }
206
207 static void
208 ev_previewer_window_do_print (EvPreviewerWindow *window)
209 {
210         GtkPrintJob *job;
211         GError      *error = NULL;
212
213         job = gtk_print_job_new (window->print_job_title ?
214                                  window->print_job_title :
215                                  window->source_file,
216                                  window->printer,
217                                  window->print_settings,
218                                  window->print_page_setup);
219         if (gtk_print_job_set_source_file (job, window->source_file, &error)) {
220                 gtk_print_job_send (job,
221                                     (GtkPrintJobCompleteFunc)ev_previewer_window_print_finished,
222                                     window, NULL);
223         } else {
224                 ev_previewer_window_error_dialog_run (window, error);
225                 g_error_free (error);
226         }
227
228         gtk_widget_hide (GTK_WIDGET (window));
229 }
230
231 static void
232 ev_previewer_window_enumerate_finished (EvPreviewerWindow *window)
233 {
234         if (window->printer) {
235                 ev_previewer_window_do_print (window);
236         } else {
237                 GError *error = NULL;
238
239                 g_set_error (&error,
240                              GTK_PRINT_ERROR,
241                              GTK_PRINT_ERROR_GENERAL,
242                              _("The selected printer '%s' could not be found"),
243                              gtk_print_settings_get_printer (window->print_settings));
244                                      
245                 ev_previewer_window_error_dialog_run (window, error);
246                 g_error_free (error);
247         }
248 }
249
250 static gboolean
251 ev_previewer_window_enumerate_printers (GtkPrinter        *printer,
252                                         EvPreviewerWindow *window)
253 {
254         const gchar *printer_name;
255
256         printer_name = gtk_print_settings_get_printer (window->print_settings);
257         if ((printer_name
258              && strcmp (printer_name, gtk_printer_get_name (printer)) == 0) ||
259             (!printer_name && gtk_printer_is_default (printer))) {
260                 if (window->printer)
261                         g_object_unref (window->printer);
262                 window->printer = g_object_ref (printer);
263
264                 return TRUE; /* we're done */
265         }
266
267         return FALSE; /* continue the enumeration */
268 }
269
270 static void
271 ev_previewer_window_print (GtkAction         *action,
272                            EvPreviewerWindow *window)
273 {
274         if (!window->print_settings)
275                 window->print_settings = gtk_print_settings_new ();
276         if (!window->print_page_setup)
277                 window->print_page_setup = gtk_page_setup_new ();
278         gtk_enumerate_printers ((GtkPrinterFunc)ev_previewer_window_enumerate_printers,
279                                 window,
280                                 (GDestroyNotify)ev_previewer_window_enumerate_finished,
281                                 FALSE);
282 }
283 #endif
284
285 static const GtkActionEntry action_entries[] = {
286         { "GoPreviousPage", GTK_STOCK_GO_UP, N_("_Previous Page"), "<control>Page_Up",
287           N_("Go to the previous page"),
288           G_CALLBACK (ev_previewer_window_previous_page) },
289         { "GoNextPage", GTK_STOCK_GO_DOWN, N_("_Next Page"), "<control>Page_Down",
290           N_("Go to the next page"),
291           G_CALLBACK (ev_previewer_window_next_page) },
292         { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "<control>plus",
293           N_("Enlarge the document"),
294           G_CALLBACK (ev_previewer_window_zoom_in) },
295         { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "<control>minus",
296           N_("Shrink the document"),
297           G_CALLBACK (ev_previewer_window_zoom_out) },
298 #if GTKUNIXPRINT_ENABLED
299         { "PreviewPrint", GTK_STOCK_PRINT, N_("Print"), NULL,
300           N_("Print this document"),
301           G_CALLBACK (ev_previewer_window_print) }
302 #endif
303 };
304
305 static const GtkToggleActionEntry toggle_action_entries[] = {
306         { "ViewBestFit", EV_STOCK_ZOOM_PAGE, N_("_Best Fit"), NULL,
307           N_("Make the current document fill the window"),
308           G_CALLBACK (ev_previewer_window_zoom_best_fit) },
309         { "ViewPageWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit Page _Width"), NULL,
310           N_("Make the current document fill the window width"),
311           G_CALLBACK (ev_previewer_window_zoom_page_width) }
312 };
313
314 /* EvView callbacks */
315 static void
316 view_sizing_mode_changed (EvView            *view,
317                           GParamSpec        *pspec,
318                           EvPreviewerWindow *window)
319 {
320         EvSizingMode sizing_mode;
321         GtkAction   *action;
322
323         if (!window->view)
324                 return;
325
326         g_object_get (window->view,
327                       "sizing_mode", &sizing_mode,
328                       NULL);
329
330         action = gtk_action_group_get_action (window->action_group, "ViewBestFit");
331         g_signal_handlers_block_by_func (action,
332                                          G_CALLBACK (ev_previewer_window_zoom_best_fit),
333                                          window);
334         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
335                                       sizing_mode == EV_SIZING_BEST_FIT);
336         g_signal_handlers_unblock_by_func (action,
337                                            G_CALLBACK (ev_previewer_window_zoom_best_fit),
338                                            window);
339
340         action = gtk_action_group_get_action (window->action_group, "ViewPageWidth");
341         g_signal_handlers_block_by_func (action,
342                                          G_CALLBACK (ev_previewer_window_zoom_page_width),
343                                          window);
344         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
345                                       sizing_mode == EV_SIZING_FIT_WIDTH);
346         g_signal_handlers_unblock_by_func (action,
347                                            G_CALLBACK (ev_previewer_window_zoom_page_width),
348                                            window);
349 }
350
351 static void
352 ev_previewer_window_dispose (GObject *object)
353 {
354         EvPreviewerWindow *window = EV_PREVIEWER_WINDOW (object);
355
356         if (window->document) {
357                 g_object_unref (window->document);
358                 window->document = NULL;
359         }
360
361         if (window->action_group) {
362                 g_object_unref (window->action_group);
363                 window->action_group = NULL;
364         }
365
366         if (window->ui_manager) {
367                 g_object_unref (window->ui_manager);
368                 window->ui_manager = NULL;
369         }
370
371         if (window->print_settings) {
372                 g_object_unref (window->print_settings);
373                 window->print_settings = NULL;
374         }
375
376         if (window->print_page_setup) {
377                 g_object_unref (window->print_page_setup);
378                 window->print_page_setup = NULL;
379         }
380
381 #if GTKUNIXPRINT_ENABLED
382         if (window->printer) {
383                 g_object_unref (window->printer);
384                 window->printer = NULL;
385         }
386 #endif
387
388         if (window->print_job_title) {
389                 g_free (window->print_job_title);
390                 window->print_job_title = NULL;
391         }
392
393         if (window->source_file) {
394                 g_free (window->source_file);
395                 window->source_file = NULL;
396         }
397
398         G_OBJECT_CLASS (ev_previewer_window_parent_class)->dispose (object);
399 }
400
401 static gchar*
402 data_dir (void)
403 {
404         gchar *datadir;
405 #ifdef G_OS_WIN32
406         gchar *dir;
407
408         dir = g_win32_get_package_installation_directory_of_module (NULL);
409         datadir = g_build_filename (dir, "share", "evince", NULL);
410         g_free (dir);
411 #else
412         datadir = g_strdup (DATADIR);
413 #endif
414
415        return datadir;
416 }
417
418 static void
419 ev_previewer_window_init (EvPreviewerWindow *window)
420 {
421         GtkWidget *vbox;
422         GtkWidget *toolbar;
423         GtkAction *action;
424         GError    *error = NULL;
425         gchar     *datadir, *ui_path;
426
427         gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);
428         
429         window->action_group = gtk_action_group_new ("PreviewerActions");
430         gtk_action_group_set_translation_domain (window->action_group, NULL);
431         gtk_action_group_add_actions (window->action_group, action_entries,
432                                       G_N_ELEMENTS (action_entries),
433                                       window);
434         gtk_action_group_add_toggle_actions (window->action_group, toggle_action_entries,
435                                              G_N_ELEMENTS (toggle_action_entries),
436                                              window);
437         gtk_action_group_set_sensitive (window->action_group, FALSE);
438
439         action = g_object_new (EV_TYPE_PAGE_ACTION,
440                                "name", "PageSelector",
441                                "label", _("Page"),
442                                "tooltip", _("Select Page"),
443                                "icon_name", "text-x-generic",
444                                "visible_overflown", FALSE,
445                                NULL);
446         g_signal_connect (action, "activate_link",
447                           G_CALLBACK (ev_previewer_window_action_page_activated),
448                           window);
449         gtk_action_group_add_action (window->action_group, action);
450         g_object_unref (action);
451
452         window->ui_manager = gtk_ui_manager_new ();
453         gtk_ui_manager_insert_action_group (window->ui_manager,
454                                             window->action_group, 0);
455         gtk_window_add_accel_group (GTK_WINDOW (window),
456                                     gtk_ui_manager_get_accel_group (window->ui_manager));
457         datadir = data_dir ();
458         ui_path = g_build_filename (datadir, "evince-previewer-ui.xml", NULL);
459         if (!gtk_ui_manager_add_ui_from_file (window->ui_manager, ui_path, &error)) {
460                 g_warning ("Failed to load ui from evince-previewer-ui.xml: %s", error->message);
461                 g_error_free (error);
462         }
463         g_free (ui_path);
464         g_free (datadir);
465
466         vbox = gtk_vbox_new (FALSE, 0);
467
468         toolbar = gtk_ui_manager_get_widget (window->ui_manager, "/PreviewToolbar");
469         gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
470         gtk_widget_show (toolbar);
471                 
472         window->swindow = gtk_scrolled_window_new (NULL, NULL);
473         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window->swindow),
474                                         GTK_POLICY_AUTOMATIC,
475                                         GTK_POLICY_AUTOMATIC);
476         
477         window->view = EV_VIEW (ev_view_new ());
478         g_signal_connect (window->view, "notify::sizing-mode",
479                           G_CALLBACK (view_sizing_mode_changed),
480                           window);
481         g_signal_connect_swapped (window->view, "zoom_invalid",
482                                   G_CALLBACK (ev_previewer_window_set_view_size),
483                                   window);
484         
485         ev_view_set_screen_dpi (window->view, get_screen_dpi (GTK_WINDOW (window)));
486         ev_view_set_continuous (window->view, FALSE);
487         ev_view_set_sizing_mode (window->view, EV_SIZING_FIT_WIDTH);
488         ev_view_set_loading (window->view, TRUE);
489         view_sizing_mode_changed (window->view, NULL, window);
490
491         gtk_container_add (GTK_CONTAINER (window->swindow), GTK_WIDGET (window->view));
492         gtk_widget_show (GTK_WIDGET (window->view));
493
494         gtk_box_pack_start (GTK_BOX (vbox), window->swindow, TRUE, TRUE, 0);
495         gtk_widget_show (window->swindow);
496         
497         gtk_container_add (GTK_CONTAINER (window), vbox);
498         gtk_widget_show (vbox);
499 }
500
501 static void
502 ev_previewer_window_class_init (EvPreviewerWindowClass *klass)
503 {
504         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
505
506         gobject_class->dispose = ev_previewer_window_dispose;
507 }
508
509 /* Public methods */
510 GtkWidget *
511 ev_previewer_window_new (void)
512 {
513         return GTK_WIDGET (g_object_new (EV_TYPE_PREVIEWER_WINDOW, NULL));
514 }
515
516 void
517 ev_previewer_window_set_document (EvPreviewerWindow *window,
518                                   EvDocument        *document)
519 {
520         GtkAction *action;
521         
522         g_return_if_fail (EV_IS_PREVIEWER_WINDOW (window));
523         g_return_if_fail (EV_IS_DOCUMENT (document));
524         
525         if (window->document)
526                 return;
527
528         action = gtk_action_group_get_action (window->action_group, "PageSelector");
529         ev_page_action_set_document (EV_PAGE_ACTION (action), document);
530         gtk_action_group_set_sensitive (window->action_group, TRUE);
531         
532         window->document = g_object_ref (document);
533         ev_view_set_document (window->view, document);
534         ev_view_set_zoom (window->view,
535                           get_screen_dpi (GTK_WINDOW (window)) / 72.0,
536                           FALSE);
537         ev_view_set_loading (window->view, FALSE);
538 }
539
540 void
541 ev_previewer_window_set_print_settings (EvPreviewerWindow *window,
542                                         const gchar       *print_settings)
543 {
544         if (window->print_settings)
545                 g_object_unref (window->print_settings);
546         if (window->print_page_setup)
547                 g_object_unref (window->print_page_setup);
548         if (window->print_job_title)
549                 g_free (window->print_job_title);
550
551         if (print_settings && g_file_test (print_settings, G_FILE_TEST_IS_REGULAR)) {
552                 GKeyFile *key_file;
553                 GError   *error = NULL;
554
555                 key_file = g_key_file_new ();
556                 g_key_file_load_from_file (key_file,
557                                            print_settings,
558                                            G_KEY_FILE_KEEP_COMMENTS |
559                                            G_KEY_FILE_KEEP_TRANSLATIONS,
560                                            &error);
561                 if (!error) {
562                         GtkPrintSettings *psettings;
563                         GtkPageSetup     *psetup;
564                         gchar            *job_name;
565
566                         psettings = gtk_print_settings_new_from_key_file (key_file,
567                                                                           "Print Settings",
568                                                                           NULL);
569                         window->print_settings = psettings ? psettings : gtk_print_settings_new ();
570
571                         psetup = gtk_page_setup_new_from_key_file (key_file,
572                                                                    "Page Setup",
573                                                                    NULL);
574                         window->print_page_setup = psetup ? psetup : gtk_page_setup_new ();
575
576                         job_name = g_key_file_get_string (key_file,
577                                                           "Print Job", "title",
578                                                           NULL);
579                         if (job_name) {
580                                 window->print_job_title = job_name;
581                                 gtk_window_set_title (GTK_WINDOW (window), job_name);
582                         }
583                 } else {
584                         window->print_settings = gtk_print_settings_new ();
585                         window->print_page_setup = gtk_page_setup_new ();
586                         g_error_free (error);
587                 }
588
589                 g_key_file_free (key_file);
590         } else {
591                 window->print_settings = gtk_print_settings_new ();
592                 window->print_page_setup = gtk_page_setup_new ();
593         }
594 }
595
596 void
597 ev_previewer_window_set_source_file (EvPreviewerWindow *window,
598                                      const gchar       *source_file)
599 {
600         if (window->source_file)
601                 g_free (window->source_file);
602         window->source_file = g_strdup (source_file);
603 }