Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ev-previewer-window.c
Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 
33  GtkApplicationWindow base_instance;
34 
37 
38  GtkActionGroup *action_group;
39  GtkActionGroup *accels_group;
40  GtkUIManager *ui_manager;
41 
42  GtkWidget *swindow;
44  gdouble dpi;
45 
46  /* Printing */
47  GtkPrintSettings *print_settings;
48  GtkPageSetup *print_page_setup;
49 #if GTKUNIXPRINT_ENABLED
50  GtkPrinter *printer;
51 #endif
53  gchar *source_file;
54 };
55 
57  GtkApplicationWindowClass base_class;
58 };
59 
60 enum {
63 };
64 
65 #define MIN_SCALE 0.05409
66 #define MAX_SCALE 4.0
67 
68 G_DEFINE_TYPE (EvPreviewerWindow, ev_previewer_window, GTK_TYPE_APPLICATION_WINDOW)
69 
70 static gdouble
72 {
73  GdkScreen *screen;
74 
75  screen = gtk_window_get_screen (GTK_WINDOW (window));
76  return ev_document_misc_get_screen_dpi (screen);
77 }
78 
79 #if GTKUNIXPRINT_ENABLED
80 static void
81 ev_previewer_window_error_dialog_run (EvPreviewerWindow *window,
82  GError *error)
83 {
84  GtkWidget *dialog;
85 
86  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
87  GTK_DIALOG_MODAL |
88  GTK_DIALOG_DESTROY_WITH_PARENT,
89  GTK_MESSAGE_ERROR,
90  GTK_BUTTONS_CLOSE,
91  "%s", _("Failed to print document"));
92  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
93  "%s", error->message);
94  gtk_dialog_run (GTK_DIALOG (dialog));
95  gtk_widget_destroy (dialog);
96 }
97 #endif
98 
99 static void
100 ev_previewer_window_close (GtkAction *action,
101  EvPreviewerWindow *window)
102 {
103  gtk_widget_destroy (GTK_WIDGET (window));
104 }
105 
106 static void
108  EvPreviewerWindow *window)
109 {
110  ev_view_previous_page (window->view);
111 }
112 
113 static void
114 ev_previewer_window_next_page (GtkAction *action,
115  EvPreviewerWindow *window)
116 {
117  ev_view_next_page (window->view);
118 }
119 
120 static void
121 ev_previewer_window_zoom_in (GtkAction *action,
122  EvPreviewerWindow *window)
123 {
125  ev_view_zoom_in (window->view);
126 }
127 
128 static void
129 ev_previewer_window_zoom_out (GtkAction *action,
130  EvPreviewerWindow *window)
131 {
133  ev_view_zoom_out (window->view);
134 }
135 
136 static void
137 ev_previewer_window_zoom_fit_page (GtkToggleAction *action,
138  EvPreviewerWindow *window)
139 {
141  gtk_toggle_action_get_active (action) ?
143 }
144 
145 static void
146 ev_previewer_window_zoom_fit_width (GtkToggleAction *action,
147  EvPreviewerWindow *window)
148 {
150  gtk_toggle_action_get_active (action) ?
152 }
153 
154 static void
156  EvLink *link,
157  EvPreviewerWindow *window)
158 {
159  ev_view_handle_link (window->view, link);
160  gtk_widget_grab_focus (GTK_WIDGET (window->view));
161 }
162 
163 static void
165  EvPreviewerWindow *window)
166 {
167  GtkAction *page_action;
168 
169  page_action = gtk_action_group_get_action (window->action_group,
170  "PageSelector");
172 }
173 
174 #if GTKUNIXPRINT_ENABLED
175 static void
176 ev_previewer_window_print_finished (GtkPrintJob *print_job,
177  EvPreviewerWindow *window,
178  GError *error)
179 {
180  if (error) {
181  ev_previewer_window_error_dialog_run (window, error);
182  }
183 
184  g_object_unref (print_job);
185  gtk_widget_destroy (GTK_WIDGET (window));
186 }
187 
188 static void
189 ev_previewer_window_do_print (EvPreviewerWindow *window)
190 {
191  GtkPrintJob *job;
192  GError *error = NULL;
193 
194  job = gtk_print_job_new (window->print_job_title ?
195  window->print_job_title :
196  window->source_file,
197  window->printer,
198  window->print_settings,
199  window->print_page_setup);
200  if (gtk_print_job_set_source_file (job, window->source_file, &error)) {
201  gtk_print_job_send (job,
202  (GtkPrintJobCompleteFunc)ev_previewer_window_print_finished,
203  window, NULL);
204  } else {
205  ev_previewer_window_error_dialog_run (window, error);
206  g_error_free (error);
207  }
208 
209  gtk_widget_hide (GTK_WIDGET (window));
210 }
211 
212 static void
213 ev_previewer_window_enumerate_finished (EvPreviewerWindow *window)
214 {
215  if (window->printer) {
216  ev_previewer_window_do_print (window);
217  } else {
218  GError *error = NULL;
219 
220  g_set_error (&error,
221  GTK_PRINT_ERROR,
222  GTK_PRINT_ERROR_GENERAL,
223  _("The selected printer ā€œ%sā€ could not be found"),
224  gtk_print_settings_get_printer (window->print_settings));
225 
226  ev_previewer_window_error_dialog_run (window, error);
227  g_error_free (error);
228  }
229 }
230 
231 static gboolean
232 ev_previewer_window_enumerate_printers (GtkPrinter *printer,
233  EvPreviewerWindow *window)
234 {
235  const gchar *printer_name;
236 
237  printer_name = gtk_print_settings_get_printer (window->print_settings);
238  if ((printer_name
239  && strcmp (printer_name, gtk_printer_get_name (printer)) == 0) ||
240  (!printer_name && gtk_printer_is_default (printer))) {
241  if (window->printer)
242  g_object_unref (window->printer);
243  window->printer = g_object_ref (printer);
244 
245  return TRUE; /* we're done */
246  }
247 
248  return FALSE; /* continue the enumeration */
249 }
250 
251 static void
252 ev_previewer_window_print (GtkAction *action,
253  EvPreviewerWindow *window)
254 {
255  if (!window->print_settings)
256  window->print_settings = gtk_print_settings_new ();
257  if (!window->print_page_setup)
258  window->print_page_setup = gtk_page_setup_new ();
259  gtk_enumerate_printers ((GtkPrinterFunc)ev_previewer_window_enumerate_printers,
260  window,
261  (GDestroyNotify)ev_previewer_window_enumerate_finished,
262  FALSE);
263 }
264 #endif
265 
266 static const GtkActionEntry action_entries[] = {
267  { "FileCloseWindow", GTK_STOCK_CLOSE, NULL, "<control>W",
268  NULL,
269  G_CALLBACK (ev_previewer_window_close) },
270  { "GoPreviousPage", GTK_STOCK_GO_UP, N_("_Previous Page"), "<control>Page_Up",
271  N_("Go to the previous page"),
272  G_CALLBACK (ev_previewer_window_previous_page) },
273  { "GoNextPage", GTK_STOCK_GO_DOWN, N_("_Next Page"), "<control>Page_Down",
274  N_("Go to the next page"),
275  G_CALLBACK (ev_previewer_window_next_page) },
276  { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "<control>plus",
277  N_("Enlarge the document"),
278  G_CALLBACK (ev_previewer_window_zoom_in) },
279  { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "<control>minus",
280  N_("Shrink the document"),
281  G_CALLBACK (ev_previewer_window_zoom_out) },
282 #if GTKUNIXPRINT_ENABLED
283  /* translators: Print document currently shown in the Print Preview window */
284  { "PreviewPrint", GTK_STOCK_PRINT, N_("Print"), NULL,
285  N_("Print this document"),
286  G_CALLBACK (ev_previewer_window_print) }
287 #endif
288 };
289 
290 static const GtkActionEntry accel_entries[] = {
291  { "p", GTK_STOCK_GO_UP, "", "p", NULL,
292  G_CALLBACK (ev_previewer_window_previous_page) },
293  { "n", GTK_STOCK_GO_DOWN, "", "n", NULL,
294  G_CALLBACK (ev_previewer_window_next_page) },
295  { "Plus", GTK_STOCK_ZOOM_IN, NULL, "plus", NULL,
296  G_CALLBACK (ev_previewer_window_zoom_in) },
297  { "CtrlEqual", GTK_STOCK_ZOOM_IN, NULL, "<control>equal", NULL,
298  G_CALLBACK (ev_previewer_window_zoom_in) },
299  { "Equal", GTK_STOCK_ZOOM_IN, NULL, "equal", NULL,
300  G_CALLBACK (ev_previewer_window_zoom_in) },
301  { "Minus", GTK_STOCK_ZOOM_OUT, NULL, "minus", NULL,
302  G_CALLBACK (ev_previewer_window_zoom_out) },
303  { "KpPlus", GTK_STOCK_ZOOM_IN, NULL, "KP_Add", NULL,
304  G_CALLBACK (ev_previewer_window_zoom_in) },
305  { "KpMinus", GTK_STOCK_ZOOM_OUT, NULL, "KP_Subtract", NULL,
306  G_CALLBACK (ev_previewer_window_zoom_out) },
307  { "CtrlKpPlus", GTK_STOCK_ZOOM_IN, NULL, "<control>KP_Add", NULL,
308  G_CALLBACK (ev_previewer_window_zoom_in) },
309  { "CtrlKpMinus", GTK_STOCK_ZOOM_OUT, NULL, "<control>KP_Subtract", NULL,
310  G_CALLBACK (ev_previewer_window_zoom_out) },
311  { "FocusPageSelector", NULL, "", "<control>l", NULL,
313 
314 };
315 
316 static const GtkToggleActionEntry toggle_action_entries[] = {
317  { "ViewFitPage", EV_STOCK_ZOOM_PAGE, N_("Fit Pa_ge"), NULL,
318  N_("Make the current document fill the window"),
319  G_CALLBACK (ev_previewer_window_zoom_fit_page) },
320  { "ViewFitWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit _Width"), NULL,
321  N_("Make the current document fill the window width"),
323 };
324 
325 static gboolean
326 view_focus_changed (GtkWidget *widget,
327  GdkEventFocus *event,
328  EvPreviewerWindow *window)
329 {
330  if (window->accels_group)
331  gtk_action_group_set_sensitive (window->accels_group, event->in);
332 
333  return FALSE;
334 }
335 
336 static void
338  gint old_page,
339  gint new_page,
340  EvPreviewerWindow *window)
341 {
342  GtkAction *action;
344 
345  action = gtk_action_group_get_action (window->action_group, "GoPreviousPage");
346  gtk_action_set_sensitive (GTK_ACTION (action), new_page > 0 );
347 
348  action = gtk_action_group_get_action (window->action_group, "GoNextPage");
349  gtk_action_set_sensitive (GTK_ACTION (action), new_page < n_pages - 1);
350 }
351 
352 static void
354  GParamSpec *pspec,
355  EvPreviewerWindow *window)
356 {
357  EvSizingMode sizing_mode = ev_document_model_get_sizing_mode (model);
358  GtkAction *action;
359 
360  action = gtk_action_group_get_action (window->action_group, "ViewFitPage");
361  g_signal_handlers_block_by_func (action,
363  window);
364  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
365  sizing_mode == EV_SIZING_FIT_PAGE);
366  g_signal_handlers_unblock_by_func (action,
368  window);
369 
370  action = gtk_action_group_get_action (window->action_group, "ViewFitWidth");
371  g_signal_handlers_block_by_func (action,
373  window);
374  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
375  sizing_mode == EV_SIZING_FIT_WIDTH);
376  g_signal_handlers_unblock_by_func (action,
378  window);
379 }
380 
381 static void
383  GParamSpec *pspec,
384  EvDocumentModel *model)
385 {
386  EvDocument *document = ev_document_model_get_document (model);
387 
388  window->document = g_object_ref (document);
389 
390  g_signal_connect (model, "notify::sizing-mode",
391  G_CALLBACK (view_sizing_mode_changed),
392  window);
393  gtk_action_group_set_sensitive (window->action_group, TRUE);
394  gtk_action_group_set_sensitive (window->accels_group, TRUE);
395 }
396 
397 static void
399 {
400  GList *actions;
401 
402  gtk_ui_manager_ensure_update (window->ui_manager);
403 
404  actions = gtk_action_group_list_actions (window->action_group);
405  g_list_foreach (actions, (GFunc)gtk_action_connect_accelerator, NULL);
406  g_list_free (actions);
407 }
408 
409 static void
411 {
412  EvPreviewerWindow *window = EV_PREVIEWER_WINDOW (object);
413 
414  if (window->model) {
415  g_object_unref (window->model);
416  window->model = NULL;
417  }
418 
419  if (window->document) {
420  g_object_unref (window->document);
421  window->document = NULL;
422  }
423 
424  if (window->action_group) {
425  g_object_unref (window->action_group);
426  window->action_group = NULL;
427  }
428 
429  if (window->accels_group) {
430  g_object_unref (window->accels_group);
431  window->accels_group = NULL;
432  }
433 
434  if (window->ui_manager) {
435  g_object_unref (window->ui_manager);
436  window->ui_manager = NULL;
437  }
438 
439  if (window->print_settings) {
440  g_object_unref (window->print_settings);
441  window->print_settings = NULL;
442  }
443 
444  if (window->print_page_setup) {
445  g_object_unref (window->print_page_setup);
446  window->print_page_setup = NULL;
447  }
448 
449 #if GTKUNIXPRINT_ENABLED
450  if (window->printer) {
451  g_object_unref (window->printer);
452  window->printer = NULL;
453  }
454 #endif
455 
456  if (window->print_job_title) {
457  g_free (window->print_job_title);
458  window->print_job_title = NULL;
459  }
460 
461  if (window->source_file) {
462  g_free (window->source_file);
463  window->source_file = NULL;
464  }
465 
466  G_OBJECT_CLASS (ev_previewer_window_parent_class)->dispose (object);
467 }
468 
469 static void
471 {
472  gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);
473 }
474 
475 static void
477  guint prop_id,
478  const GValue *value,
479  GParamSpec *pspec)
480 {
481  EvPreviewerWindow *window = EV_PREVIEWER_WINDOW (object);
482 
483  switch (prop_id) {
484  case PROP_MODEL:
485  window->model = g_value_dup_object (value);
486  break;
487  default:
488  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
489  }
490 }
491 
492 static gboolean
493 _gtk_css_provider_load_from_resource (GtkCssProvider *provider,
494  const char *resource_path,
495  GError **error)
496 {
497  GBytes *data;
498  gboolean retval;
499 
500  data = g_resources_lookup_data (resource_path, 0, error);
501  if (!data)
502  return FALSE;
503 
504  retval = gtk_css_provider_load_from_data (provider,
505  g_bytes_get_data (data, NULL),
506  g_bytes_get_size (data),
507  error);
508  g_bytes_unref (data);
509 
510  return retval;
511 }
512 
513 static GObject *
515  guint n_construct_properties,
516  GObjectConstructParam *construct_params)
517 {
518  GObject *object;
520  GtkWidget *vbox;
521  GtkWidget *toolbar;
522  GtkAction *action;
523  GError *error = NULL;
524  gdouble dpi;
525  GtkCssProvider *css_provider;
526 
527  object = G_OBJECT_CLASS (ev_previewer_window_parent_class)->constructor (type,
528  n_construct_properties,
529  construct_params);
530  window = EV_PREVIEWER_WINDOW (object);
531 
532  dpi = get_screen_dpi (window);
533  ev_document_model_set_min_scale (window->model, MIN_SCALE * dpi / 72.0);
534  ev_document_model_set_max_scale (window->model, MAX_SCALE * dpi / 72.0);
536  g_signal_connect_swapped (window->model, "notify::document",
538  window);
539 
540  window->action_group = gtk_action_group_new ("PreviewerActions");
541  gtk_action_group_set_translation_domain (window->action_group, NULL);
542  gtk_action_group_add_actions (window->action_group, action_entries,
543  G_N_ELEMENTS (action_entries),
544  window);
545  gtk_action_group_add_toggle_actions (window->action_group, toggle_action_entries,
546  G_N_ELEMENTS (toggle_action_entries),
547  window);
548  gtk_action_group_set_sensitive (window->action_group, FALSE);
549 
550  action = g_object_new (EV_TYPE_PAGE_ACTION,
551  "name", "PageSelector",
552  "label", _("Page"),
553  "tooltip", _("Select Page"),
554  "icon_name", "text-x-generic",
555  "visible_overflown", FALSE,
556  NULL);
557  ev_page_action_set_model (EV_PAGE_ACTION (action), window->model);
558  g_signal_connect (action, "activate_link",
560  window);
561  gtk_action_group_add_action (window->action_group, action);
562  g_object_unref (action);
563 
564  window->accels_group = gtk_action_group_new ("PreviewerAccelerators");
565  gtk_action_group_add_actions (window->accels_group, accel_entries,
566  G_N_ELEMENTS (accel_entries),
567  window);
568  gtk_action_group_set_sensitive (window->accels_group, FALSE);
569 
570  css_provider = gtk_css_provider_new ();
572  "/org/gnome/evince/previewer/ui/evince-previewer.css",
573  &error);
574  g_assert_no_error (error);
575  gtk_style_context_add_provider_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)),
576  GTK_STYLE_PROVIDER (css_provider),
577  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
578  g_object_unref (css_provider);
579 
580  window->ui_manager = gtk_ui_manager_new ();
581  gtk_ui_manager_insert_action_group (window->ui_manager,
582  window->action_group, 0);
583  gtk_ui_manager_insert_action_group (window->ui_manager,
584  window->accels_group, 1);
585  gtk_window_add_accel_group (GTK_WINDOW (window),
586  gtk_ui_manager_get_accel_group (window->ui_manager));
587 
588  gtk_ui_manager_add_ui_from_resource (window->ui_manager, "/org/gnome/evince/previewer/ui/previewer.xml", &error);
589  g_assert_no_error (error);
590 
591  /* GTKUIManager connects actions accels only for menu items,
592  * but not for tool items. See bug #612972.
593  */
595 
596  view_sizing_mode_changed (window->model, NULL, window);
597 
598  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
599 
600  toolbar = gtk_ui_manager_get_widget (window->ui_manager, "/PreviewToolbar");
601  gtk_style_context_add_class (gtk_widget_get_style_context (toolbar),
602  GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
603  gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
604  gtk_widget_show (toolbar);
605 
606  window->swindow = gtk_scrolled_window_new (NULL, NULL);
607 
608  window->view = EV_VIEW (ev_view_new ());
609  g_signal_connect_object (window->view, "focus_in_event",
610  G_CALLBACK (view_focus_changed),
611  window, 0);
612  g_signal_connect_object (window->view, "focus_out_event",
613  G_CALLBACK (view_focus_changed),
614  window, 0);
615  ev_view_set_model (window->view, window->model);
617 
618  g_signal_connect_object (window->model, "page-changed",
619  G_CALLBACK (model_page_changed),
620  window, 0);
621 
622  gtk_container_add (GTK_CONTAINER (window->swindow), GTK_WIDGET (window->view));
623  gtk_widget_show (GTK_WIDGET (window->view));
624 
625  gtk_box_pack_start (GTK_BOX (vbox), window->swindow, TRUE, TRUE, 0);
626  gtk_widget_show (window->swindow);
627 
628  gtk_container_add (GTK_CONTAINER (window), vbox);
629  gtk_widget_show (vbox);
630 
631  return object;
632 }
633 
634 
635 static void
637 {
638  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
639 
640  gobject_class->constructor = ev_previewer_window_constructor;
641  gobject_class->set_property = ev_previewer_window_set_property;
642  gobject_class->dispose = ev_previewer_window_dispose;
643 
644  g_object_class_install_property (gobject_class,
645  PROP_MODEL,
646  g_param_spec_object ("model",
647  "Model",
648  "The document model",
650  G_PARAM_WRITABLE |
651  G_PARAM_CONSTRUCT_ONLY));
652 }
653 
654 /* Public methods */
657 {
658  return g_object_new (EV_TYPE_PREVIEWER_WINDOW,
659  "application", g_application_get_default (),
660  "model", model,
661  NULL);
662 }
663 
664 void
666  const gchar *print_settings)
667 {
668  if (window->print_settings)
669  g_object_unref (window->print_settings);
670  if (window->print_page_setup)
671  g_object_unref (window->print_page_setup);
672  if (window->print_job_title)
673  g_free (window->print_job_title);
674 
675  if (print_settings && g_file_test (print_settings, G_FILE_TEST_IS_REGULAR)) {
676  GKeyFile *key_file;
677  GError *error = NULL;
678 
679  key_file = g_key_file_new ();
680  g_key_file_load_from_file (key_file,
681  print_settings,
682  G_KEY_FILE_KEEP_COMMENTS |
683  G_KEY_FILE_KEEP_TRANSLATIONS,
684  &error);
685  if (!error) {
686  GtkPrintSettings *psettings;
687  GtkPageSetup *psetup;
688  gchar *job_name;
689 
690  psettings = gtk_print_settings_new_from_key_file (key_file,
691  "Print Settings",
692  NULL);
693  window->print_settings = psettings ? psettings : gtk_print_settings_new ();
694 
695  psetup = gtk_page_setup_new_from_key_file (key_file,
696  "Page Setup",
697  NULL);
698  window->print_page_setup = psetup ? psetup : gtk_page_setup_new ();
699 
700  job_name = g_key_file_get_string (key_file,
701  "Print Job", "title",
702  NULL);
703  if (job_name) {
704  window->print_job_title = job_name;
705  gtk_window_set_title (GTK_WINDOW (window), job_name);
706  }
707  } else {
708  window->print_settings = gtk_print_settings_new ();
709  window->print_page_setup = gtk_page_setup_new ();
710  g_error_free (error);
711  }
712 
713  g_key_file_free (key_file);
714  } else {
715  window->print_settings = gtk_print_settings_new ();
716  window->print_page_setup = gtk_page_setup_new ();
717  }
718 }
719 
720 void
722  const gchar *source_file)
723 {
724  if (window->source_file)
725  g_free (window->source_file);
726  window->source_file = g_strdup (source_file);
727 }