1 /* ev-view-presentation.c
2 * this file is part of evince, a gnome document viewer
4 * Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
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.
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.
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.
24 #include <glib/gi18n-lib.h>
25 #include <gdk/gdkkeysyms.h>
27 #include "ev-view-presentation.h"
29 #include "ev-job-scheduler.h"
30 #include "ev-transition-animation.h"
31 #include "ev-view-cursor.h"
32 #include "ev-page-cache.h"
33 #include "ev-mapping.h"
49 EV_PRESENTATION_NORMAL,
50 EV_PRESENTATION_BLACK,
51 EV_PRESENTATION_WHITE,
53 } EvPresentationState;
55 struct _EvViewPresentation
60 cairo_surface_t *current_surface;
63 EvPresentationState state;
68 guint hide_cursor_timeout_id;
71 GtkWidget *goto_window;
72 GtkWidget *goto_entry;
75 guint trans_timeout_id;
78 gboolean enable_animations;
79 EvTransitionAnimation *animation;
82 EvPageCache *page_cache;
89 struct _EvViewPresentationClass
91 GtkWidgetClass base_class;
94 void (* change_page) (EvViewPresentation *pview,
95 GtkScrollType scroll);
96 void (* finished) (EvViewPresentation *pview);
99 static guint signals[N_SIGNALS] = { 0 };
101 static void ev_view_presentation_next_page (EvViewPresentation *pview);
102 static void ev_view_presentation_previous_page (EvViewPresentation *pview);
103 static void ev_view_presentation_set_cursor_for_location (EvViewPresentation *pview,
107 #define HIDE_CURSOR_TIMEOUT 5
109 G_DEFINE_TYPE (EvViewPresentation, ev_view_presentation, GTK_TYPE_WIDGET)
112 ev_view_presentation_set_normal (EvViewPresentation *pview)
114 GtkWidget *widget = GTK_WIDGET (pview);
116 if (pview->state == EV_PRESENTATION_NORMAL)
119 pview->state = EV_PRESENTATION_NORMAL;
120 gdk_window_set_background (widget->window, &widget->style->black);
121 gtk_widget_queue_draw (widget);
125 ev_view_presentation_set_black (EvViewPresentation *pview)
127 GtkWidget *widget = GTK_WIDGET (pview);
129 if (pview->state == EV_PRESENTATION_BLACK)
132 pview->state = EV_PRESENTATION_BLACK;
133 gdk_window_set_background (widget->window, &widget->style->black);
134 gtk_widget_queue_draw (widget);
138 ev_view_presentation_set_white (EvViewPresentation *pview)
140 GtkWidget *widget = GTK_WIDGET (pview);
142 if (pview->state == EV_PRESENTATION_WHITE)
145 pview->state = EV_PRESENTATION_WHITE;
146 gdk_window_set_background (widget->window, &widget->style->white);
147 gtk_widget_queue_draw (widget);
151 ev_view_presentation_set_end (EvViewPresentation *pview)
153 GtkWidget *widget = GTK_WIDGET (pview);
155 if (pview->state == EV_PRESENTATION_END)
158 pview->state = EV_PRESENTATION_END;
159 gtk_widget_queue_draw (widget);
163 ev_view_presentation_get_scale_for_page (EvViewPresentation *pview,
166 gdouble width, height;
168 ev_document_get_page_size (pview->document, page, &width, &height);
170 if (pview->rotation == 90 || pview->rotation == 270)
171 return GTK_WIDGET (pview)->allocation.height / width;
173 return GTK_WIDGET (pview)->allocation.height / height;
177 ev_view_presentation_update_scale (EvViewPresentation *pview)
179 if (ev_document_is_page_size_uniform (pview->document) && pview->scale != 0)
182 pview->scale = ev_view_presentation_get_scale_for_page (pview, pview->current_page);
186 ev_view_presentation_get_page_area (EvViewPresentation *pview,
189 GtkWidget *widget = GTK_WIDGET (pview);
190 gdouble doc_width, doc_height;
191 gint view_width, view_height;
193 ev_document_get_page_size (pview->document,
195 &doc_width, &doc_height);
197 if (pview->rotation == 90 || pview->rotation == 270) {
198 view_width = (gint)((doc_height * pview->scale) + 0.5);
199 view_height = (gint)((doc_width * pview->scale) + 0.5);
201 view_width = (gint)((doc_width * pview->scale) + 0.5);
202 view_height = (gint)((doc_height * pview->scale) + 0.5);
205 area->x = (MAX (0, widget->allocation.width - view_width)) / 2;
206 area->y = (MAX (0, widget->allocation.height - view_height)) / 2;
207 area->width = view_width;
208 area->height = view_height;
211 /* Page Transition */
213 transition_next_page (EvViewPresentation *pview)
215 ev_view_presentation_next_page (pview);
221 ev_view_presentation_transition_stop (EvViewPresentation *pview)
223 if (pview->trans_timeout_id > 0)
224 g_source_remove (pview->trans_timeout_id);
225 pview->trans_timeout_id = 0;
229 ev_view_presentation_transition_start (EvViewPresentation *pview)
233 if (!EV_IS_DOCUMENT_TRANSITION (pview->document))
236 ev_view_presentation_transition_stop (pview);
238 duration = ev_document_transition_get_page_duration (EV_DOCUMENT_TRANSITION (pview->document),
239 pview->current_page);
241 pview->trans_timeout_id =
242 g_timeout_add_seconds (duration,
243 (GSourceFunc) transition_next_page,
250 ev_view_presentation_animation_cancel (EvViewPresentation *pview)
252 if (pview->animation) {
253 g_object_unref (pview->animation);
254 pview->animation = NULL;
259 ev_view_presentation_transition_animation_finish (EvViewPresentation *pview)
261 ev_view_presentation_animation_cancel (pview);
262 ev_view_presentation_transition_start (pview);
263 gtk_widget_queue_draw (GTK_WIDGET (pview));
267 ev_view_presentation_transition_animation_frame (EvViewPresentation *pview,
270 gtk_widget_queue_draw (GTK_WIDGET (pview));
274 ev_view_presentation_animation_start (EvViewPresentation *pview,
277 EvTransitionEffect *effect = NULL;
278 cairo_surface_t *surface;
281 if (!pview->enable_animations)
284 if (pview->current_page == new_page)
287 effect = ev_document_transition_get_effect (EV_DOCUMENT_TRANSITION (pview->document),
292 pview->animation = ev_transition_animation_new (effect);
294 surface = EV_JOB_RENDER (pview->curr_job)->surface;
295 ev_transition_animation_set_origin_surface (pview->animation,
297 surface : pview->current_surface);
299 jump = new_page - pview->current_page;
301 surface = EV_JOB_RENDER (pview->prev_job)->surface;
303 surface = EV_JOB_RENDER (pview->next_job)->surface;
307 ev_transition_animation_set_dest_surface (pview->animation, surface);
309 g_signal_connect_swapped (pview->animation, "frame",
310 G_CALLBACK (ev_view_presentation_transition_animation_frame),
312 g_signal_connect_swapped (pview->animation, "finished",
313 G_CALLBACK (ev_view_presentation_transition_animation_finish),
317 /* Page Navigation */
319 job_finished_cb (EvJob *job,
320 EvViewPresentation *pview)
322 EvJobRender *job_render = EV_JOB_RENDER (job);
324 if (job != pview->curr_job)
327 if (pview->animation) {
328 ev_transition_animation_set_dest_surface (pview->animation,
329 job_render->surface);
331 ev_view_presentation_transition_start (pview);
332 gtk_widget_queue_draw (GTK_WIDGET (pview));
337 ev_view_presentation_schedule_new_job (EvViewPresentation *pview,
339 EvJobPriority priority)
344 if (page < 0 || page >= ev_document_get_n_pages (pview->document))
347 if (ev_document_is_page_size_uniform (pview->document))
348 scale = pview->scale;
350 scale = ev_view_presentation_get_scale_for_page (pview, page);
351 job = ev_job_render_new (pview->document, page, pview->rotation, pview->scale, 0, 0);
352 g_signal_connect (job, "finished",
353 G_CALLBACK (job_finished_cb),
355 ev_job_scheduler_push_job (job, priority);
361 ev_view_presentation_delete_job (EvViewPresentation *pview,
367 g_signal_handlers_disconnect_by_func (job, job_finished_cb, pview);
369 g_object_unref (job);
373 ev_view_presentation_update_current_page (EvViewPresentation *pview,
378 if (page < 0 || page >= ev_document_get_n_pages (pview->document))
381 ev_view_presentation_animation_cancel (pview);
382 ev_view_presentation_animation_start (pview, page);
384 jump = page - pview->current_page;
388 if (!pview->curr_job)
389 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
390 if (!pview->next_job)
391 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_HIGH);
392 if (!pview->prev_job)
393 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_LOW);
396 ev_view_presentation_delete_job (pview, pview->next_job);
397 pview->next_job = pview->curr_job;
398 pview->curr_job = pview->prev_job;
400 if (!pview->curr_job)
401 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
403 ev_job_scheduler_update_job (pview->curr_job, EV_JOB_PRIORITY_URGENT);
404 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_HIGH);
405 ev_job_scheduler_update_job (pview->next_job, EV_JOB_PRIORITY_LOW);
409 ev_view_presentation_delete_job (pview, pview->prev_job);
410 pview->prev_job = pview->curr_job;
411 pview->curr_job = pview->next_job;
413 if (!pview->curr_job)
414 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
416 ev_job_scheduler_update_job (pview->curr_job, EV_JOB_PRIORITY_URGENT);
417 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_HIGH);
418 ev_job_scheduler_update_job (pview->prev_job, EV_JOB_PRIORITY_LOW);
422 ev_view_presentation_delete_job (pview, pview->next_job);
423 ev_view_presentation_delete_job (pview, pview->curr_job);
424 pview->next_job = pview->prev_job;
426 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
427 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_HIGH);
428 if (!pview->next_job)
429 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_LOW);
431 ev_job_scheduler_update_job (pview->next_job, EV_JOB_PRIORITY_LOW);
434 ev_view_presentation_delete_job (pview, pview->prev_job);
435 ev_view_presentation_delete_job (pview, pview->curr_job);
436 pview->prev_job = pview->next_job;
438 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
439 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_HIGH);
440 if (!pview->prev_job)
441 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_LOW);
443 ev_job_scheduler_update_job (pview->prev_job, EV_JOB_PRIORITY_LOW);
446 ev_view_presentation_delete_job (pview, pview->prev_job);
447 ev_view_presentation_delete_job (pview, pview->curr_job);
448 ev_view_presentation_delete_job (pview, pview->next_job);
450 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
452 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_HIGH);
453 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_LOW);
455 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_HIGH);
456 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_LOW);
460 pview->current_page = page;
461 ev_view_presentation_update_scale (pview);
462 if (pview->page_cache)
463 ev_page_cache_set_page_range (pview->page_cache, page, page);
465 if (pview->cursor != EV_VIEW_CURSOR_HIDDEN) {
468 gtk_widget_get_pointer (GTK_WIDGET (pview), &x, &y);
469 ev_view_presentation_set_cursor_for_location (pview, x, y);
472 if (EV_JOB_RENDER (pview->curr_job)->surface)
473 gtk_widget_queue_draw (GTK_WIDGET (pview));
477 ev_view_presentation_next_page (EvViewPresentation *pview)
482 switch (pview->state) {
483 case EV_PRESENTATION_BLACK:
484 case EV_PRESENTATION_WHITE:
485 ev_view_presentation_set_normal (pview);
486 case EV_PRESENTATION_END:
488 case EV_PRESENTATION_NORMAL:
492 n_pages = ev_document_get_n_pages (pview->document);
493 new_page = pview->current_page + 1;
495 if (new_page == n_pages)
496 ev_view_presentation_set_end (pview);
498 ev_view_presentation_update_current_page (pview, new_page);
502 ev_view_presentation_previous_page (EvViewPresentation *pview)
506 switch (pview->state) {
507 case EV_PRESENTATION_BLACK:
508 case EV_PRESENTATION_WHITE:
509 ev_view_presentation_set_normal (pview);
511 case EV_PRESENTATION_END:
512 pview->state = EV_PRESENTATION_NORMAL;
513 new_page = pview->current_page;
515 case EV_PRESENTATION_NORMAL:
516 new_page = pview->current_page - 1;
520 ev_view_presentation_update_current_page (pview, new_page);
524 #define KEY_IS_NUMERIC(keyval) \
525 ((keyval >= GDK_0 && keyval <= GDK_9) || (keyval >= GDK_KP_0 && keyval <= GDK_KP_9))
527 /* Cut and paste from gtkwindow.c */
529 send_focus_change (GtkWidget *widget,
532 GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
534 g_object_ref (widget);
537 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
539 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
541 fevent->focus_change.type = GDK_FOCUS_CHANGE;
542 fevent->focus_change.window = g_object_ref (widget->window);
543 fevent->focus_change.in = in;
545 gtk_widget_event (widget, fevent);
547 g_object_notify (G_OBJECT (widget), "has-focus");
549 g_object_unref (widget);
550 gdk_event_free (fevent);
554 ev_view_presentation_goto_window_hide (EvViewPresentation *pview)
556 /* send focus-in event */
557 send_focus_change (pview->goto_entry, FALSE);
558 gtk_widget_hide (pview->goto_window);
559 gtk_entry_set_text (GTK_ENTRY (pview->goto_entry), "");
563 ev_view_presentation_goto_window_delete_event (GtkWidget *widget,
565 EvViewPresentation *pview)
567 ev_view_presentation_goto_window_hide (pview);
573 ev_view_presentation_goto_window_key_press_event (GtkWidget *widget,
575 EvViewPresentation *pview)
577 switch (event->keyval) {
581 case GDK_ISO_Left_Tab:
582 ev_view_presentation_goto_window_hide (pview);
591 if (!KEY_IS_NUMERIC (event->keyval))
599 ev_view_presentation_goto_window_button_press_event (GtkWidget *widget,
600 GdkEventButton *event,
601 EvViewPresentation *pview)
603 ev_view_presentation_goto_window_hide (pview);
609 ev_view_presentation_goto_entry_activate (GtkEntry *entry,
610 EvViewPresentation *pview)
615 text = gtk_entry_get_text (entry);
616 page = atoi (text) - 1;
618 ev_view_presentation_goto_window_hide (pview);
619 ev_view_presentation_update_current_page (pview, page);
623 ev_view_presentation_goto_window_create (EvViewPresentation *pview)
625 GtkWidget *frame, *hbox, *toplevel, *label;
627 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (pview));
629 if (pview->goto_window) {
630 if (GTK_WINDOW (toplevel)->group)
631 gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
632 GTK_WINDOW (pview->goto_window));
633 else if (GTK_WINDOW (pview->goto_window)->group)
634 gtk_window_group_remove_window (GTK_WINDOW (pview->goto_window)->group,
635 GTK_WINDOW (pview->goto_window));
639 pview->goto_window = gtk_window_new (GTK_WINDOW_POPUP);
640 gtk_window_set_screen (GTK_WINDOW (pview->goto_window),
641 gtk_widget_get_screen (GTK_WIDGET (pview)));
643 if (GTK_WINDOW (toplevel)->group)
644 gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
645 GTK_WINDOW (pview->goto_window));
647 gtk_window_set_modal (GTK_WINDOW (pview->goto_window), TRUE);
649 g_signal_connect (pview->goto_window, "delete_event",
650 G_CALLBACK (ev_view_presentation_goto_window_delete_event),
652 g_signal_connect (pview->goto_window, "key_press_event",
653 G_CALLBACK (ev_view_presentation_goto_window_key_press_event),
655 g_signal_connect (pview->goto_window, "button_press_event",
656 G_CALLBACK (ev_view_presentation_goto_window_button_press_event),
659 frame = gtk_frame_new (NULL);
660 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
661 gtk_container_add (GTK_CONTAINER (pview->goto_window), frame);
662 gtk_widget_show (frame);
664 hbox = gtk_hbox_new (FALSE, 0);
665 gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);
666 gtk_container_add (GTK_CONTAINER (frame), hbox);
667 gtk_widget_show (hbox);
669 label = gtk_label_new (_("Jump to page:"));
670 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 3);
671 gtk_widget_show (label);
672 gtk_widget_realize (label);
674 pview->goto_entry = gtk_entry_new ();
675 g_signal_connect (pview->goto_entry, "activate",
676 G_CALLBACK (ev_view_presentation_goto_entry_activate),
678 gtk_box_pack_start (GTK_BOX (hbox), pview->goto_entry, TRUE, TRUE, 0);
679 gtk_widget_show (pview->goto_entry);
680 gtk_widget_realize (pview->goto_entry);
684 ev_view_presentation_goto_entry_grab_focus (EvViewPresentation *pview)
686 GtkWidgetClass *entry_parent_class;
688 entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (pview->goto_entry));
689 (entry_parent_class->grab_focus) (pview->goto_entry);
691 send_focus_change (pview->goto_entry, TRUE);
695 ev_view_presentation_goto_window_send_key_event (EvViewPresentation *pview,
698 GdkEventKey *new_event;
701 /* Move goto window off screen */
702 screen = gtk_widget_get_screen (GTK_WIDGET (pview));
703 gtk_window_move (GTK_WINDOW (pview->goto_window),
704 gdk_screen_get_width (screen) + 1,
705 gdk_screen_get_height (screen) + 1);
706 gtk_widget_show (pview->goto_window);
708 new_event = (GdkEventKey *) gdk_event_copy (event);
709 g_object_unref (new_event->window);
710 new_event->window = g_object_ref (pview->goto_window->window);
711 gtk_widget_realize (pview->goto_window);
713 gtk_widget_event (pview->goto_window, (GdkEvent *)new_event);
714 gdk_event_free ((GdkEvent *)new_event);
715 gtk_widget_hide (pview->goto_window);
720 ev_view_presentation_link_is_supported (EvViewPresentation *pview,
723 EvLinkAction *action;
725 action = ev_link_get_action (link);
729 switch (ev_link_action_get_action_type (action)) {
730 case EV_LINK_ACTION_TYPE_GOTO_DEST:
731 return ev_link_action_get_dest (action) != NULL;
732 case EV_LINK_ACTION_TYPE_NAMED:
742 ev_view_presentation_get_link_at_location (EvViewPresentation *pview,
746 GdkRectangle page_area;
749 gdouble width, height;
750 gdouble new_x, new_y;
752 if (!pview->page_cache)
755 ev_document_get_page_size (pview->document, pview->current_page, &width, &height);
756 ev_view_presentation_get_page_area (pview, &page_area);
757 x = (x - page_area.x) / pview->scale;
758 y = (y - page_area.y) / pview->scale;
759 switch (pview->rotation) {
778 g_assert_not_reached ();
781 link_mapping = ev_page_cache_get_link_mapping (pview->page_cache, pview->current_page);
783 link = link_mapping ? ev_mapping_list_get_data (link_mapping, new_x, new_y) : NULL;
785 return link && ev_view_presentation_link_is_supported (pview, link) ? link : NULL;
789 ev_vew_presentation_goto_link_dest (EvViewPresentation *pview,
792 EvLinkAction *action;
794 action = ev_link_get_action (link);
796 if (ev_link_action_get_action_type (action) == EV_LINK_ACTION_TYPE_NAMED) {
797 const gchar *name = ev_link_action_get_name (action);
799 if (g_ascii_strcasecmp (name, "FirstPage") == 0) {
800 ev_view_presentation_update_current_page (pview, 0);
801 } else if (g_ascii_strcasecmp (name, "PrevPage") == 0) {
802 ev_view_presentation_update_current_page (pview, pview->current_page - 1);
803 } else if (g_ascii_strcasecmp (name, "NextPage") == 0) {
804 ev_view_presentation_update_current_page (pview, pview->current_page + 1);
805 } else if (g_ascii_strcasecmp (name, "LastPage") == 0) {
808 n_pages = ev_document_get_n_pages (pview->document);
809 ev_view_presentation_update_current_page (pview, n_pages - 1);
815 dest = ev_link_action_get_dest (action);
816 page = ev_document_links_get_dest_page (EV_DOCUMENT_LINKS (pview->document), dest);
817 ev_view_presentation_update_current_page (pview, page);
823 ev_view_presentation_set_cursor (EvViewPresentation *pview,
824 EvViewCursor view_cursor)
829 if (pview->cursor == view_cursor)
832 widget = GTK_WIDGET (pview);
833 if (!GTK_WIDGET_REALIZED (widget))
834 gtk_widget_realize (widget);
836 pview->cursor = view_cursor;
838 cursor = ev_view_cursor_new (gtk_widget_get_display (widget), view_cursor);
839 gdk_window_set_cursor (widget->window, cursor);
842 gdk_cursor_unref (cursor);
846 ev_view_presentation_set_cursor_for_location (EvViewPresentation *pview,
850 if (ev_view_presentation_get_link_at_location (pview, x, y))
851 ev_view_presentation_set_cursor (pview, EV_VIEW_CURSOR_LINK);
853 ev_view_presentation_set_cursor (pview, EV_VIEW_CURSOR_NORMAL);
857 hide_cursor_timeout_cb (EvViewPresentation *pview)
859 ev_view_presentation_set_cursor (pview, EV_VIEW_CURSOR_HIDDEN);
860 pview->hide_cursor_timeout_id = 0;
866 ev_view_presentation_hide_cursor_timeout_stop (EvViewPresentation *pview)
868 if (pview->hide_cursor_timeout_id > 0)
869 g_source_remove (pview->hide_cursor_timeout_id);
870 pview->hide_cursor_timeout_id = 0;
874 ev_view_presentation_hide_cursor_timeout_start (EvViewPresentation *pview)
876 ev_view_presentation_hide_cursor_timeout_stop (pview);
877 pview->hide_cursor_timeout_id =
878 g_timeout_add_seconds (HIDE_CURSOR_TIMEOUT,
879 (GSourceFunc)hide_cursor_timeout_cb,
884 ev_view_presentation_update_current_surface (EvViewPresentation *pview,
885 cairo_surface_t *surface)
887 if (!surface || pview->current_surface == surface)
890 cairo_surface_reference (surface);
891 if (pview->current_surface)
892 cairo_surface_destroy (pview->current_surface);
893 pview->current_surface = surface;
897 ev_view_presentation_destroy (GtkObject *object)
899 EvViewPresentation *pview = EV_VIEW_PRESENTATION (object);
901 if (pview->document) {
902 g_object_unref (pview->document);
903 pview->document = NULL;
906 ev_view_presentation_animation_cancel (pview);
907 ev_view_presentation_transition_stop (pview);
908 ev_view_presentation_hide_cursor_timeout_stop (pview);
910 if (pview->curr_job) {
911 ev_view_presentation_delete_job (pview, pview->curr_job);
912 pview->curr_job = NULL;
915 if (pview->prev_job) {
916 ev_view_presentation_delete_job (pview, pview->prev_job);
917 pview->prev_job = NULL;
920 if (pview->next_job) {
921 ev_view_presentation_delete_job (pview, pview->next_job);
922 pview->next_job = NULL;
925 if (pview->current_surface) {
926 cairo_surface_destroy (pview->current_surface);
927 pview->current_surface = NULL;
930 if (pview->page_cache) {
931 g_object_unref (pview->page_cache);
932 pview->page_cache = NULL;
935 if (pview->goto_window) {
936 gtk_widget_destroy (pview->goto_window);
937 pview->goto_window = NULL;
938 pview->goto_entry = NULL;
941 GTK_OBJECT_CLASS (ev_view_presentation_parent_class)->destroy (object);
945 ev_view_presentation_size_request (GtkWidget *widget,
946 GtkRequisition *requisition)
948 requisition->width = 0;
949 requisition->height = 0;
953 ev_view_presentation_size_allocate (GtkWidget *widget,
954 GtkAllocation *allocation)
956 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
957 GdkScreen *screen = gtk_widget_get_screen (widget);
961 allocation->width = gdk_screen_get_width (screen);
962 allocation->height = gdk_screen_get_height (screen);
964 GTK_WIDGET_CLASS (ev_view_presentation_parent_class)->size_allocate (widget, allocation);
966 ev_view_presentation_update_scale (pview);
968 gtk_widget_queue_draw (widget);
972 ev_view_presentation_draw_end_page (EvViewPresentation *pview)
974 GtkWidget *widget = GTK_WIDGET (pview);
976 PangoFontDescription *font_desc;
978 GdkRectangle area = {0};
979 const gchar *text = _("End of presentation. Click to exit.");
981 if (pview->state != EV_PRESENTATION_END)
984 layout = gtk_widget_create_pango_layout (widget, NULL);
985 markup = g_strdup_printf ("<span foreground=\"white\">%s</span>", text);
986 pango_layout_set_markup (layout, markup, -1);
989 font_desc = pango_font_description_new ();
990 pango_font_description_set_size (font_desc, 16 * PANGO_SCALE);
991 pango_layout_set_font_description (layout, font_desc);
993 area.width = widget->allocation.width;
994 area.height = widget->allocation.height;
996 gtk_paint_layout (widget->style,
998 GTK_WIDGET_STATE (widget),
1007 pango_font_description_free (font_desc);
1008 g_object_unref (layout);
1012 ev_view_presentation_expose_event (GtkWidget *widget,
1013 GdkEventExpose *event)
1015 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1016 GdkRectangle page_area;
1017 GdkRectangle overlap;
1018 cairo_surface_t *surface;
1021 switch (pview->state) {
1022 case EV_PRESENTATION_END:
1023 ev_view_presentation_draw_end_page (pview);
1025 case EV_PRESENTATION_BLACK:
1026 case EV_PRESENTATION_WHITE:
1028 case EV_PRESENTATION_NORMAL:
1032 if (pview->animation) {
1033 if (ev_transition_animation_ready (pview->animation)) {
1034 ev_view_presentation_get_page_area (pview, &page_area);
1036 cr = gdk_cairo_create (widget->window);
1038 /* normalize to x=0, y=0 */
1039 cairo_translate (cr, page_area.x, page_area.y);
1040 page_area.x = page_area.y = 0;
1042 /* Try to fix rounding errors */
1045 ev_transition_animation_paint (pview->animation, cr, page_area);
1052 surface = pview->curr_job ? EV_JOB_RENDER (pview->curr_job)->surface : NULL;
1054 ev_view_presentation_update_current_surface (pview, surface);
1055 } else if (pview->current_surface) {
1056 surface = pview->current_surface;
1061 ev_view_presentation_get_page_area (pview, &page_area);
1062 if (gdk_rectangle_intersect (&page_area, &(event->area), &overlap)) {
1063 cr = gdk_cairo_create (widget->window);
1065 /* Try to fix rounding errors. See bug #438760 */
1066 if (overlap.width == page_area.width)
1069 cairo_rectangle (cr, overlap.x, overlap.y, overlap.width, overlap.height);
1070 cairo_set_source_surface (cr, surface, page_area.x, page_area.y);
1079 ev_view_presentation_key_press_event (GtkWidget *widget,
1082 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1084 if (pview->state == EV_PRESENTATION_END)
1085 return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
1087 switch (event->keyval) {
1091 case GDK_KP_Decimal:
1092 if (pview->state == EV_PRESENTATION_BLACK)
1093 ev_view_presentation_set_normal (pview);
1095 ev_view_presentation_set_black (pview);
1100 if (pview->state == EV_PRESENTATION_WHITE)
1101 ev_view_presentation_set_normal (pview);
1103 ev_view_presentation_set_white (pview);
1107 if (pview->state == EV_PRESENTATION_NORMAL) {
1108 ev_view_presentation_update_current_page (pview, 0);
1113 if (pview->state == EV_PRESENTATION_NORMAL) {
1116 page = ev_document_get_n_pages (pview->document) - 1;
1117 ev_view_presentation_update_current_page (pview, page);
1126 ev_view_presentation_set_normal (pview);
1128 if (ev_document_get_n_pages (pview->document) > 1 && KEY_IS_NUMERIC (event->keyval)) {
1131 ev_view_presentation_goto_window_create (pview);
1132 ev_view_presentation_goto_window_send_key_event (pview, (GdkEvent *)event);
1133 gtk_widget_get_pointer (GTK_WIDGET (pview), &x, &y);
1134 gtk_window_move (GTK_WINDOW (pview->goto_window), x, y);
1135 gtk_widget_show (pview->goto_window);
1136 ev_view_presentation_goto_entry_grab_focus (pview);
1141 return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
1145 ev_view_presentation_button_release_event (GtkWidget *widget,
1146 GdkEventButton *event)
1148 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1150 switch (event->button) {
1154 if (pview->state == EV_PRESENTATION_END) {
1155 g_signal_emit (pview, signals[FINISHED], 0, NULL);
1160 link = ev_view_presentation_get_link_at_location (pview,
1164 ev_vew_presentation_goto_link_dest (pview, link);
1166 ev_view_presentation_next_page (pview);
1170 ev_view_presentation_previous_page (pview);
1180 ev_view_presentation_focus_out (GtkWidget *widget,
1181 GdkEventFocus *event)
1183 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1185 if (pview->goto_window)
1186 ev_view_presentation_goto_window_hide (pview);
1192 ev_view_presentation_motion_notify_event (GtkWidget *widget,
1193 GdkEventMotion *event)
1195 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1197 ev_view_presentation_hide_cursor_timeout_start (pview);
1198 ev_view_presentation_set_cursor_for_location (pview, event->x, event->y);
1204 ev_view_presentation_realize (GtkWidget *widget)
1206 GdkWindowAttr attributes;
1208 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1210 attributes.window_type = GDK_WINDOW_CHILD;
1211 attributes.wclass = GDK_INPUT_OUTPUT;
1212 attributes.visual = gtk_widget_get_visual (widget);
1213 attributes.colormap = gtk_widget_get_colormap (widget);
1215 attributes.x = widget->allocation.x;
1216 attributes.y = widget->allocation.y;
1217 attributes.width = widget->allocation.width;
1218 attributes.height = widget->allocation.height;
1219 attributes.event_mask = GDK_EXPOSURE_MASK |
1220 GDK_BUTTON_PRESS_MASK |
1221 GDK_BUTTON_RELEASE_MASK |
1223 GDK_KEY_PRESS_MASK |
1224 GDK_POINTER_MOTION_MASK |
1225 GDK_POINTER_MOTION_HINT_MASK |
1226 GDK_ENTER_NOTIFY_MASK |
1227 GDK_LEAVE_NOTIFY_MASK;
1229 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1231 GDK_WA_X | GDK_WA_Y |
1234 gdk_window_set_user_data (widget->window, widget);
1235 widget->style = gtk_style_attach (widget->style, widget->window);
1237 gdk_window_set_background (widget->window, &widget->style->black);
1239 gtk_widget_queue_resize (widget);
1243 ev_view_presentation_change_page (EvViewPresentation *pview,
1244 GtkScrollType scroll)
1247 case GTK_SCROLL_PAGE_FORWARD:
1248 ev_view_presentation_next_page (pview);
1250 case GTK_SCROLL_PAGE_BACKWARD:
1251 ev_view_presentation_previous_page (pview);
1254 g_assert_not_reached ();
1259 ev_view_presentation_scroll_event (GtkWidget *widget,
1260 GdkEventScroll *event)
1262 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1265 state = event->state & gtk_accelerator_get_default_mod_mask ();
1269 switch (event->direction) {
1270 case GDK_SCROLL_DOWN:
1271 case GDK_SCROLL_RIGHT:
1272 ev_view_presentation_change_page (pview, GTK_SCROLL_PAGE_FORWARD);
1275 case GDK_SCROLL_LEFT:
1276 ev_view_presentation_change_page (pview, GTK_SCROLL_PAGE_BACKWARD);
1285 add_change_page_binding_keypad (GtkBindingSet *binding_set,
1287 GdkModifierType modifiers,
1288 GtkScrollType scroll)
1290 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
1292 gtk_binding_entry_add_signal (binding_set, keyval, modifiers,
1294 GTK_TYPE_SCROLL_TYPE, scroll);
1295 gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers,
1297 GTK_TYPE_SCROLL_TYPE, scroll);
1301 ev_view_presentation_set_property (GObject *object,
1303 const GValue *value,
1306 EvViewPresentation *pview = EV_VIEW_PRESENTATION (object);
1310 pview->document = g_value_dup_object (value);
1311 pview->enable_animations = EV_IS_DOCUMENT_TRANSITION (pview->document);
1313 case PROP_CURRENT_PAGE:
1314 pview->current_page = g_value_get_uint (value);
1317 pview->rotation = g_value_get_uint (value);
1320 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1325 ev_view_presentation_constructor (GType type,
1326 guint n_construct_properties,
1327 GObjectConstructParam *construct_params)
1330 EvViewPresentation *pview;
1333 object = G_OBJECT_CLASS (ev_view_presentation_parent_class)->constructor (type,
1334 n_construct_properties,
1336 pview = EV_VIEW_PRESENTATION (object);
1338 if (EV_IS_DOCUMENT_LINKS (pview->document)) {
1339 pview->page_cache = ev_page_cache_new (pview->document);
1340 ev_page_cache_set_flags (pview->page_cache, EV_PAGE_DATA_INCLUDE_LINKS);
1343 /* Call allocate asap to update page scale */
1344 ev_view_presentation_size_allocate (GTK_WIDGET (pview), &a);
1345 ev_view_presentation_update_current_page (pview, pview->current_page);
1346 ev_view_presentation_hide_cursor_timeout_start (pview);
1352 ev_view_presentation_class_init (EvViewPresentationClass *klass)
1354 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
1355 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1356 GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass);
1357 GtkBindingSet *binding_set;
1359 klass->change_page = ev_view_presentation_change_page;
1361 widget_class->size_allocate = ev_view_presentation_size_allocate;
1362 widget_class->size_request = ev_view_presentation_size_request;
1363 widget_class->realize = ev_view_presentation_realize;
1364 widget_class->expose_event = ev_view_presentation_expose_event;
1365 widget_class->key_press_event = ev_view_presentation_key_press_event;
1366 widget_class->button_release_event = ev_view_presentation_button_release_event;
1367 widget_class->focus_out_event = ev_view_presentation_focus_out;
1368 widget_class->motion_notify_event = ev_view_presentation_motion_notify_event;
1369 widget_class->scroll_event = ev_view_presentation_scroll_event;
1371 gtk_object_class->destroy = ev_view_presentation_destroy;
1373 gobject_class->constructor = ev_view_presentation_constructor;
1374 gobject_class->set_property = ev_view_presentation_set_property;
1376 g_object_class_install_property (gobject_class,
1378 g_param_spec_object ("document",
1383 G_PARAM_CONSTRUCT_ONLY));
1384 g_object_class_install_property (gobject_class,
1386 g_param_spec_uint ("current_page",
1391 G_PARAM_CONSTRUCT_ONLY));
1392 g_object_class_install_property (gobject_class,
1394 g_param_spec_uint ("rotation",
1396 "Current rotation angle",
1399 G_PARAM_CONSTRUCT_ONLY));
1401 signals[CHANGE_PAGE] =
1402 g_signal_new ("change_page",
1403 G_OBJECT_CLASS_TYPE (gobject_class),
1404 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1405 G_STRUCT_OFFSET (EvViewPresentationClass, change_page),
1407 g_cclosure_marshal_VOID__ENUM,
1409 GTK_TYPE_SCROLL_TYPE);
1411 g_signal_new ("finished",
1412 G_OBJECT_CLASS_TYPE (gobject_class),
1413 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1414 G_STRUCT_OFFSET (EvViewPresentationClass, finished),
1416 g_cclosure_marshal_VOID__VOID,
1420 binding_set = gtk_binding_set_by_class (klass);
1421 add_change_page_binding_keypad (binding_set, GDK_Left, 0, GTK_SCROLL_PAGE_BACKWARD);
1422 add_change_page_binding_keypad (binding_set, GDK_Right, 0, GTK_SCROLL_PAGE_FORWARD);
1423 add_change_page_binding_keypad (binding_set, GDK_Up, 0, GTK_SCROLL_PAGE_BACKWARD);
1424 add_change_page_binding_keypad (binding_set, GDK_Down, 0, GTK_SCROLL_PAGE_FORWARD);
1425 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
1427 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1428 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
1430 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1431 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
1433 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1434 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
1436 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1437 gtk_binding_entry_add_signal (binding_set, GDK_J, 0,
1439 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1440 gtk_binding_entry_add_signal (binding_set, GDK_H, 0,
1442 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1443 gtk_binding_entry_add_signal (binding_set, GDK_L, 0,
1445 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1446 gtk_binding_entry_add_signal (binding_set, GDK_K, 0,
1448 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1452 ev_view_presentation_init (EvViewPresentation *pview)
1454 GTK_WIDGET_SET_FLAGS (pview, GTK_CAN_FOCUS);
1458 ev_view_presentation_new (EvDocument *document,
1462 g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL);
1463 g_return_val_if_fail (current_page < ev_document_get_n_pages (document), NULL);
1465 return GTK_WIDGET (g_object_new (EV_TYPE_VIEW_PRESENTATION,
1466 "document", document,
1467 "current_page", current_page,
1468 "rotation", rotation,
1473 ev_view_presentation_get_current_page (EvViewPresentation *pview)
1475 return pview->current_page;