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"
48 EV_PRESENTATION_NORMAL,
49 EV_PRESENTATION_BLACK,
50 EV_PRESENTATION_WHITE,
52 } EvPresentationState;
54 struct _EvViewPresentation
61 EvPresentationState state;
66 guint hide_cursor_timeout_id;
69 GtkWidget *goto_window;
70 GtkWidget *goto_entry;
73 guint trans_timeout_id;
76 gboolean enable_animations;
77 EvTransitionAnimation *animation;
80 EvPageCache *page_cache;
87 struct _EvViewPresentationClass
89 GtkWidgetClass base_class;
92 void (* change_page) (EvViewPresentation *pview,
93 GtkScrollType scroll);
96 static guint signals[N_SIGNALS] = { 0 };
98 static void ev_view_presentation_next_page (EvViewPresentation *pview);
99 static void ev_view_presentation_previous_page (EvViewPresentation *pview);
100 static void ev_view_presentation_set_cursor_for_location (EvViewPresentation *pview,
104 #define HIDE_CURSOR_TIMEOUT 5
106 G_DEFINE_TYPE (EvViewPresentation, ev_view_presentation, GTK_TYPE_WIDGET)
109 ev_view_presentation_set_normal (EvViewPresentation *pview)
111 GtkWidget *widget = GTK_WIDGET (pview);
113 if (pview->state == EV_PRESENTATION_NORMAL)
116 pview->state = EV_PRESENTATION_NORMAL;
117 gdk_window_set_background (widget->window, &widget->style->black);
118 gtk_widget_queue_draw (widget);
122 ev_view_presentation_set_black (EvViewPresentation *pview)
124 GtkWidget *widget = GTK_WIDGET (pview);
126 if (pview->state == EV_PRESENTATION_BLACK)
129 pview->state = EV_PRESENTATION_BLACK;
130 gdk_window_set_background (widget->window, &widget->style->black);
131 gtk_widget_queue_draw (widget);
135 ev_view_presentation_set_white (EvViewPresentation *pview)
137 GtkWidget *widget = GTK_WIDGET (pview);
139 if (pview->state == EV_PRESENTATION_WHITE)
142 pview->state = EV_PRESENTATION_WHITE;
143 gdk_window_set_background (widget->window, &widget->style->white);
144 gtk_widget_queue_draw (widget);
148 ev_view_presentation_set_end (EvViewPresentation *pview)
150 GtkWidget *widget = GTK_WIDGET (pview);
152 if (pview->state == EV_PRESENTATION_END)
155 pview->state = EV_PRESENTATION_END;
156 gtk_widget_queue_draw (widget);
160 ev_view_presentation_get_scale_for_page (EvViewPresentation *pview,
163 gdouble width, height;
165 ev_document_get_page_size (pview->document, page, &width, &height);
167 if (pview->rotation == 90 || pview->rotation == 270)
168 return GTK_WIDGET (pview)->allocation.height / width;
170 return GTK_WIDGET (pview)->allocation.height / height;
174 ev_view_presentation_update_scale (EvViewPresentation *pview)
176 if (ev_document_is_page_size_uniform (pview->document) && pview->scale != 0)
179 pview->scale = ev_view_presentation_get_scale_for_page (pview, pview->current_page);
183 ev_view_presentation_get_page_area (EvViewPresentation *pview,
186 GtkWidget *widget = GTK_WIDGET (pview);
187 gdouble width, height;
189 ev_document_get_page_size (pview->document,
193 if (pview->rotation == 90 || pview->rotation == 270) {
201 width *= pview->scale;
202 height *= pview->scale;
204 area->x = (MAX (0, widget->allocation.width - width)) / 2;
205 area->y = (MAX (0, widget->allocation.height - height)) / 2;
207 area->height = height;
210 /* Page Transition */
212 transition_next_page (EvViewPresentation *pview)
214 ev_view_presentation_next_page (pview);
220 ev_view_presentation_transition_stop (EvViewPresentation *pview)
222 if (pview->trans_timeout_id > 0)
223 g_source_remove (pview->trans_timeout_id);
224 pview->trans_timeout_id = 0;
228 ev_view_presentation_transition_start (EvViewPresentation *pview)
232 if (!EV_IS_DOCUMENT_TRANSITION (pview->document))
235 ev_view_presentation_transition_stop (pview);
237 duration = ev_document_transition_get_page_duration (EV_DOCUMENT_TRANSITION (pview->document),
238 pview->current_page);
240 pview->trans_timeout_id =
241 g_timeout_add_seconds (duration,
242 (GSourceFunc) transition_next_page,
249 ev_view_presentation_animation_cancel (EvViewPresentation *pview)
251 if (pview->animation) {
252 g_object_unref (pview->animation);
253 pview->animation = NULL;
258 ev_view_presentation_transition_animation_finish (EvViewPresentation *pview)
260 ev_view_presentation_animation_cancel (pview);
261 ev_view_presentation_transition_start (pview);
262 gtk_widget_queue_draw (GTK_WIDGET (pview));
266 ev_view_presentation_transition_animation_frame (EvViewPresentation *pview,
269 gtk_widget_queue_draw (GTK_WIDGET (pview));
273 ev_view_presentation_animation_start (EvViewPresentation *pview,
276 EvTransitionEffect *effect = NULL;
277 cairo_surface_t *surface;
280 if (!pview->enable_animations)
283 if (pview->current_page == new_page)
286 effect = ev_document_transition_get_effect (EV_DOCUMENT_TRANSITION (pview->document),
291 pview->animation = ev_transition_animation_new (effect);
293 surface = EV_JOB_RENDER (pview->curr_job)->surface;
294 ev_transition_animation_set_origin_surface (pview->animation, surface);
296 jump = new_page - pview->current_page;
298 surface = EV_JOB_RENDER (pview->prev_job)->surface;
300 surface = EV_JOB_RENDER (pview->next_job)->surface;
304 ev_transition_animation_set_dest_surface (pview->animation, surface);
306 g_signal_connect_swapped (pview->animation, "frame",
307 G_CALLBACK (ev_view_presentation_transition_animation_frame),
309 g_signal_connect_swapped (pview->animation, "finished",
310 G_CALLBACK (ev_view_presentation_transition_animation_finish),
314 /* Page Navigation */
316 job_finished_cb (EvJob *job,
317 EvViewPresentation *pview)
319 EvJobRender *job_render = EV_JOB_RENDER (job);
321 if (job != pview->curr_job)
324 if (pview->animation) {
325 ev_transition_animation_set_dest_surface (pview->animation,
326 job_render->surface);
328 ev_view_presentation_transition_start (pview);
329 gtk_widget_queue_draw (GTK_WIDGET (pview));
334 ev_view_presentation_schedule_new_job (EvViewPresentation *pview,
336 EvJobPriority priority)
341 if (page < 0 || page >= ev_document_get_n_pages (pview->document))
344 if (ev_document_is_page_size_uniform (pview->document))
345 scale = pview->scale;
347 scale = ev_view_presentation_get_scale_for_page (pview, page);
348 job = ev_job_render_new (pview->document, page, pview->rotation, pview->scale, 0, 0);
349 g_signal_connect (job, "finished",
350 G_CALLBACK (job_finished_cb),
352 ev_job_scheduler_push_job (job, priority);
358 ev_view_presentation_delete_job (EvViewPresentation *pview,
364 g_signal_handlers_disconnect_by_func (job, job_finished_cb, pview);
366 g_object_unref (job);
370 ev_view_presentation_update_current_page (EvViewPresentation *pview,
375 if (page < 0 || page >= ev_document_get_n_pages (pview->document))
378 ev_view_presentation_animation_cancel (pview);
379 ev_view_presentation_animation_start (pview, page);
381 jump = page - pview->current_page;
385 if (!pview->curr_job)
386 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
387 if (!pview->next_job)
388 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_HIGH);
389 if (!pview->prev_job)
390 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_LOW);
393 ev_view_presentation_delete_job (pview, pview->next_job);
394 pview->next_job = pview->curr_job;
395 pview->curr_job = pview->prev_job;
397 if (!pview->curr_job)
398 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
400 ev_job_scheduler_update_job (pview->curr_job, EV_JOB_PRIORITY_URGENT);
401 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_HIGH);
402 ev_job_scheduler_update_job (pview->next_job, EV_JOB_PRIORITY_LOW);
406 ev_view_presentation_delete_job (pview, pview->prev_job);
407 pview->prev_job = pview->curr_job;
408 pview->curr_job = pview->next_job;
410 if (!pview->curr_job)
411 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
413 ev_job_scheduler_update_job (pview->curr_job, EV_JOB_PRIORITY_URGENT);
414 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_HIGH);
415 ev_job_scheduler_update_job (pview->prev_job, EV_JOB_PRIORITY_LOW);
419 ev_view_presentation_delete_job (pview, pview->next_job);
420 ev_view_presentation_delete_job (pview, pview->curr_job);
421 pview->next_job = pview->prev_job;
423 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
424 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_HIGH);
425 if (!pview->next_job)
426 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_LOW);
428 ev_job_scheduler_update_job (pview->next_job, EV_JOB_PRIORITY_LOW);
431 ev_view_presentation_delete_job (pview, pview->prev_job);
432 ev_view_presentation_delete_job (pview, pview->curr_job);
433 pview->prev_job = pview->next_job;
435 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
436 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_HIGH);
437 if (!pview->prev_job)
438 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_LOW);
440 ev_job_scheduler_update_job (pview->prev_job, EV_JOB_PRIORITY_LOW);
443 ev_view_presentation_delete_job (pview, pview->prev_job);
444 ev_view_presentation_delete_job (pview, pview->curr_job);
445 ev_view_presentation_delete_job (pview, pview->next_job);
447 pview->curr_job = ev_view_presentation_schedule_new_job (pview, page, EV_JOB_PRIORITY_URGENT);
449 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_HIGH);
450 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_LOW);
452 pview->prev_job = ev_view_presentation_schedule_new_job (pview, page - 1, EV_JOB_PRIORITY_HIGH);
453 pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_LOW);
457 pview->current_page = page;
458 ev_view_presentation_update_scale (pview);
459 if (pview->page_cache)
460 ev_page_cache_set_page_range (pview->page_cache, page, page);
462 if (pview->cursor != EV_VIEW_CURSOR_HIDDEN) {
465 gtk_widget_get_pointer (GTK_WIDGET (pview), &x, &y);
466 ev_view_presentation_set_cursor_for_location (pview, x, y);
469 if (EV_JOB_RENDER (pview->curr_job)->surface)
470 gtk_widget_queue_draw (GTK_WIDGET (pview));
474 ev_view_presentation_next_page (EvViewPresentation *pview)
479 switch (pview->state) {
480 case EV_PRESENTATION_BLACK:
481 case EV_PRESENTATION_WHITE:
482 ev_view_presentation_set_normal (pview);
483 case EV_PRESENTATION_END:
485 case EV_PRESENTATION_NORMAL:
489 n_pages = ev_document_get_n_pages (pview->document);
490 new_page = pview->current_page + 1;
492 if (new_page == n_pages)
493 ev_view_presentation_set_end (pview);
495 ev_view_presentation_update_current_page (pview, new_page);
499 ev_view_presentation_previous_page (EvViewPresentation *pview)
503 switch (pview->state) {
504 case EV_PRESENTATION_BLACK:
505 case EV_PRESENTATION_WHITE:
506 ev_view_presentation_set_normal (pview);
508 case EV_PRESENTATION_END:
509 pview->state = EV_PRESENTATION_NORMAL;
510 new_page = pview->current_page;
512 case EV_PRESENTATION_NORMAL:
513 new_page = pview->current_page - 1;
517 ev_view_presentation_update_current_page (pview, new_page);
521 #define KEY_IS_NUMERIC(keyval) \
522 ((keyval >= GDK_0 && keyval <= GDK_9) || (keyval >= GDK_KP_0 && keyval <= GDK_KP_9))
524 /* Cut and paste from gtkwindow.c */
526 send_focus_change (GtkWidget *widget,
529 GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
531 g_object_ref (widget);
534 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
536 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
538 fevent->focus_change.type = GDK_FOCUS_CHANGE;
539 fevent->focus_change.window = g_object_ref (widget->window);
540 fevent->focus_change.in = in;
542 gtk_widget_event (widget, fevent);
544 g_object_notify (G_OBJECT (widget), "has-focus");
546 g_object_unref (widget);
547 gdk_event_free (fevent);
551 ev_view_presentation_goto_window_hide (EvViewPresentation *pview)
553 /* send focus-in event */
554 send_focus_change (pview->goto_entry, FALSE);
555 gtk_widget_hide (pview->goto_window);
556 gtk_entry_set_text (GTK_ENTRY (pview->goto_entry), "");
560 ev_view_presentation_goto_window_delete_event (GtkWidget *widget,
562 EvViewPresentation *pview)
564 ev_view_presentation_goto_window_hide (pview);
570 ev_view_presentation_goto_window_key_press_event (GtkWidget *widget,
572 EvViewPresentation *pview)
574 switch (event->keyval) {
578 case GDK_ISO_Left_Tab:
579 ev_view_presentation_goto_window_hide (pview);
588 if (!KEY_IS_NUMERIC (event->keyval))
596 ev_view_presentation_goto_window_button_press_event (GtkWidget *widget,
597 GdkEventButton *event,
598 EvViewPresentation *pview)
600 ev_view_presentation_goto_window_hide (pview);
606 ev_view_presentation_goto_entry_activate (GtkEntry *entry,
607 EvViewPresentation *pview)
612 text = gtk_entry_get_text (entry);
613 page = atoi (text) - 1;
615 ev_view_presentation_goto_window_hide (pview);
616 ev_view_presentation_update_current_page (pview, page);
620 ev_view_presentation_goto_window_create (EvViewPresentation *pview)
622 GtkWidget *frame, *hbox, *toplevel, *label;
624 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (pview));
626 if (pview->goto_window) {
627 if (GTK_WINDOW (toplevel)->group)
628 gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
629 GTK_WINDOW (pview->goto_window));
630 else if (GTK_WINDOW (pview->goto_window)->group)
631 gtk_window_group_remove_window (GTK_WINDOW (pview->goto_window)->group,
632 GTK_WINDOW (pview->goto_window));
636 pview->goto_window = gtk_window_new (GTK_WINDOW_POPUP);
637 gtk_window_set_screen (GTK_WINDOW (pview->goto_window),
638 gtk_widget_get_screen (GTK_WIDGET (pview)));
640 if (GTK_WINDOW (toplevel)->group)
641 gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
642 GTK_WINDOW (pview->goto_window));
644 gtk_window_set_modal (GTK_WINDOW (pview->goto_window), TRUE);
646 g_signal_connect (pview->goto_window, "delete_event",
647 G_CALLBACK (ev_view_presentation_goto_window_delete_event),
649 g_signal_connect (pview->goto_window, "key_press_event",
650 G_CALLBACK (ev_view_presentation_goto_window_key_press_event),
652 g_signal_connect (pview->goto_window, "button_press_event",
653 G_CALLBACK (ev_view_presentation_goto_window_button_press_event),
656 frame = gtk_frame_new (NULL);
657 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
658 gtk_container_add (GTK_CONTAINER (pview->goto_window), frame);
659 gtk_widget_show (frame);
661 hbox = gtk_hbox_new (FALSE, 0);
662 gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);
663 gtk_container_add (GTK_CONTAINER (frame), hbox);
664 gtk_widget_show (hbox);
666 label = gtk_label_new (_("Jump to page:"));
667 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 3);
668 gtk_widget_show (label);
669 gtk_widget_realize (label);
671 pview->goto_entry = gtk_entry_new ();
672 g_signal_connect (pview->goto_entry, "activate",
673 G_CALLBACK (ev_view_presentation_goto_entry_activate),
675 gtk_box_pack_start (GTK_BOX (hbox), pview->goto_entry, TRUE, TRUE, 0);
676 gtk_widget_show (pview->goto_entry);
677 gtk_widget_realize (pview->goto_entry);
681 ev_view_presentation_goto_entry_grab_focus (EvViewPresentation *pview)
683 GtkWidgetClass *entry_parent_class;
685 entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (pview->goto_entry));
686 (entry_parent_class->grab_focus) (pview->goto_entry);
688 send_focus_change (pview->goto_entry, TRUE);
692 ev_view_presentation_goto_window_send_key_event (EvViewPresentation *pview,
695 GdkEventKey *new_event;
698 /* Move goto window off screen */
699 screen = gtk_widget_get_screen (GTK_WIDGET (pview));
700 gtk_window_move (GTK_WINDOW (pview->goto_window),
701 gdk_screen_get_width (screen) + 1,
702 gdk_screen_get_height (screen) + 1);
703 gtk_widget_show (pview->goto_window);
705 new_event = (GdkEventKey *) gdk_event_copy (event);
706 g_object_unref (new_event->window);
707 new_event->window = g_object_ref (pview->goto_window->window);
708 gtk_widget_realize (pview->goto_window);
710 gtk_widget_event (pview->goto_window, (GdkEvent *)new_event);
711 gdk_event_free ((GdkEvent *)new_event);
712 gtk_widget_hide (pview->goto_window);
717 ev_view_presentation_link_is_supported (EvViewPresentation *pview,
720 EvLinkAction *action;
722 action = ev_link_get_action (link);
726 switch (ev_link_action_get_action_type (action)) {
727 case EV_LINK_ACTION_TYPE_GOTO_DEST:
728 return ev_link_action_get_dest (action) != NULL;
729 case EV_LINK_ACTION_TYPE_NAMED:
739 ev_view_presentation_get_link_at_location (EvViewPresentation *pview,
743 GdkRectangle page_area;
746 gdouble width, height;
747 gdouble new_x, new_y;
749 if (!pview->page_cache)
752 ev_document_get_page_size (pview->document, pview->current_page, &width, &height);
753 ev_view_presentation_get_page_area (pview, &page_area);
754 x = (x - page_area.x) / pview->scale;
755 y = (y - page_area.y) / pview->scale;
756 switch (pview->rotation) {
775 g_assert_not_reached ();
778 link_mapping = ev_page_cache_get_link_mapping (pview->page_cache, pview->current_page);
780 link = link_mapping ? ev_mapping_list_get_data (link_mapping, new_x, new_y) : NULL;
782 return link && ev_view_presentation_link_is_supported (pview, link) ? link : NULL;
786 ev_vew_presentation_goto_link_dest (EvViewPresentation *pview,
789 EvLinkAction *action;
791 action = ev_link_get_action (link);
793 if (ev_link_action_get_action_type (action) == EV_LINK_ACTION_TYPE_NAMED) {
794 const gchar *name = ev_link_action_get_name (action);
796 if (g_ascii_strcasecmp (name, "FirstPage") == 0) {
797 ev_view_presentation_update_current_page (pview, 0);
798 } else if (g_ascii_strcasecmp (name, "PrevPage") == 0) {
799 ev_view_presentation_update_current_page (pview, pview->current_page - 1);
800 } else if (g_ascii_strcasecmp (name, "NextPage") == 0) {
801 ev_view_presentation_update_current_page (pview, pview->current_page + 1);
802 } else if (g_ascii_strcasecmp (name, "LastPage") == 0) {
805 n_pages = ev_document_get_n_pages (pview->document);
806 ev_view_presentation_update_current_page (pview, n_pages - 1);
812 dest = ev_link_action_get_dest (action);
813 page = ev_document_links_get_dest_page (EV_DOCUMENT_LINKS (pview->document), dest);
814 ev_view_presentation_update_current_page (pview, page);
820 ev_view_presentation_set_cursor (EvViewPresentation *pview,
821 EvViewCursor view_cursor)
826 if (pview->cursor == view_cursor)
829 widget = GTK_WIDGET (pview);
830 if (!GTK_WIDGET_REALIZED (widget))
831 gtk_widget_realize (widget);
833 pview->cursor = view_cursor;
835 cursor = ev_view_cursor_new (gtk_widget_get_display (widget), view_cursor);
836 gdk_window_set_cursor (widget->window, cursor);
839 gdk_cursor_unref (cursor);
843 ev_view_presentation_set_cursor_for_location (EvViewPresentation *pview,
847 if (ev_view_presentation_get_link_at_location (pview, x, y))
848 ev_view_presentation_set_cursor (pview, EV_VIEW_CURSOR_LINK);
850 ev_view_presentation_set_cursor (pview, EV_VIEW_CURSOR_NORMAL);
854 hide_cursor_timeout_cb (EvViewPresentation *pview)
856 ev_view_presentation_set_cursor (pview, EV_VIEW_CURSOR_HIDDEN);
857 pview->hide_cursor_timeout_id = 0;
863 ev_view_presentation_hide_cursor_timeout_stop (EvViewPresentation *pview)
865 if (pview->hide_cursor_timeout_id > 0)
866 g_source_remove (pview->hide_cursor_timeout_id);
867 pview->hide_cursor_timeout_id = 0;
871 ev_view_presentation_hide_cursor_timeout_start (EvViewPresentation *pview)
873 ev_view_presentation_hide_cursor_timeout_stop (pview);
874 pview->hide_cursor_timeout_id =
875 g_timeout_add_seconds (HIDE_CURSOR_TIMEOUT,
876 (GSourceFunc)hide_cursor_timeout_cb,
881 ev_view_presentation_destroy (GtkObject *object)
883 EvViewPresentation *pview = EV_VIEW_PRESENTATION (object);
885 if (pview->document) {
886 g_object_unref (pview->document);
887 pview->document = NULL;
890 ev_view_presentation_animation_cancel (pview);
891 ev_view_presentation_transition_stop (pview);
892 ev_view_presentation_hide_cursor_timeout_stop (pview);
894 if (pview->curr_job) {
895 ev_view_presentation_delete_job (pview, pview->curr_job);
896 pview->curr_job = NULL;
899 if (pview->prev_job) {
900 ev_view_presentation_delete_job (pview, pview->prev_job);
901 pview->prev_job = NULL;
904 if (pview->next_job) {
905 ev_view_presentation_delete_job (pview, pview->next_job);
906 pview->next_job = NULL;
909 if (pview->page_cache) {
910 g_object_unref (pview->page_cache);
911 pview->page_cache = NULL;
914 if (pview->goto_window) {
915 gtk_widget_destroy (pview->goto_window);
916 pview->goto_window = NULL;
917 pview->goto_entry = NULL;
920 GTK_OBJECT_CLASS (ev_view_presentation_parent_class)->destroy (object);
924 ev_view_presentation_size_request (GtkWidget *widget,
925 GtkRequisition *requisition)
927 requisition->width = 0;
928 requisition->height = 0;
932 ev_view_presentation_size_allocate (GtkWidget *widget,
933 GtkAllocation *allocation)
935 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
936 GdkScreen *screen = gtk_widget_get_screen (widget);
940 allocation->width = gdk_screen_get_width (screen);
941 allocation->height = gdk_screen_get_height (screen);
943 GTK_WIDGET_CLASS (ev_view_presentation_parent_class)->size_allocate (widget, allocation);
945 ev_view_presentation_update_scale (pview);
947 gtk_widget_queue_draw (widget);
951 ev_view_presentation_draw_end_page (EvViewPresentation *pview)
953 GtkWidget *widget = GTK_WIDGET (pview);
955 PangoFontDescription *font_desc;
957 GdkRectangle area = {0};
958 const gchar *text = _("End of presentation. Press Escape to exit.");
960 if (pview->state != EV_PRESENTATION_END)
963 layout = gtk_widget_create_pango_layout (widget, NULL);
964 markup = g_strdup_printf ("<span foreground=\"white\">%s</span>", text);
965 pango_layout_set_markup (layout, markup, -1);
968 font_desc = pango_font_description_new ();
969 pango_font_description_set_size (font_desc, 16 * PANGO_SCALE);
970 pango_layout_set_font_description (layout, font_desc);
972 area.width = widget->allocation.width;
973 area.height = widget->allocation.height;
975 gtk_paint_layout (widget->style,
977 GTK_WIDGET_STATE (widget),
986 pango_font_description_free (font_desc);
987 g_object_unref (layout);
991 ev_view_presentation_expose_event (GtkWidget *widget,
992 GdkEventExpose *event)
994 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
995 GdkRectangle page_area;
996 GdkRectangle overlap;
997 cairo_surface_t *surface;
1000 switch (pview->state) {
1001 case EV_PRESENTATION_END:
1002 ev_view_presentation_draw_end_page (pview);
1004 case EV_PRESENTATION_BLACK:
1005 case EV_PRESENTATION_WHITE:
1007 case EV_PRESENTATION_NORMAL:
1011 if (pview->animation) {
1012 if (ev_transition_animation_ready (pview->animation)) {
1013 ev_view_presentation_get_page_area (pview, &page_area);
1015 cr = gdk_cairo_create (widget->window);
1017 /* normalize to x=0, y=0 */
1018 cairo_translate (cr, page_area.x, page_area.y);
1019 page_area.x = page_area.y = 0;
1021 ev_transition_animation_paint (pview->animation, cr, page_area);
1028 surface = pview->curr_job ? EV_JOB_RENDER (pview->curr_job)->surface : NULL;
1032 ev_view_presentation_get_page_area (pview, &page_area);
1033 if (gdk_rectangle_intersect (&page_area, &(event->area), &overlap)) {
1034 cr = gdk_cairo_create (widget->window);
1036 cairo_translate (cr, overlap.x, overlap.y);
1037 cairo_surface_set_device_offset (surface,
1038 overlap.x - page_area.x,
1039 overlap.y - page_area.y);
1040 cairo_set_source_surface (cr, surface, 0, 0);
1049 ev_view_presentation_key_press_event (GtkWidget *widget,
1052 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1054 if (pview->state == EV_PRESENTATION_END)
1055 return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
1057 switch (event->keyval) {
1061 case GDK_KP_Decimal:
1062 if (pview->state == EV_PRESENTATION_BLACK)
1063 ev_view_presentation_set_normal (pview);
1065 ev_view_presentation_set_black (pview);
1070 if (pview->state == EV_PRESENTATION_WHITE)
1071 ev_view_presentation_set_normal (pview);
1073 ev_view_presentation_set_white (pview);
1080 ev_view_presentation_set_normal (pview);
1082 if (ev_document_get_n_pages (pview->document) > 1 && KEY_IS_NUMERIC (event->keyval)) {
1085 ev_view_presentation_goto_window_create (pview);
1086 ev_view_presentation_goto_window_send_key_event (pview, (GdkEvent *)event);
1087 gtk_widget_get_pointer (GTK_WIDGET (pview), &x, &y);
1088 gtk_window_move (GTK_WINDOW (pview->goto_window), x, y);
1089 gtk_widget_show (pview->goto_window);
1090 ev_view_presentation_goto_entry_grab_focus (pview);
1095 return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
1099 ev_view_presentation_button_release_event (GtkWidget *widget,
1100 GdkEventButton *event)
1102 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1104 switch (event->button) {
1108 link = ev_view_presentation_get_link_at_location (pview,
1112 ev_vew_presentation_goto_link_dest (pview, link);
1114 ev_view_presentation_next_page (pview);
1118 ev_view_presentation_previous_page (pview);
1128 ev_view_presentation_focus_out (GtkWidget *widget,
1129 GdkEventFocus *event)
1131 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1133 if (pview->goto_window)
1134 ev_view_presentation_goto_window_hide (pview);
1140 ev_view_presentation_motion_notify_event (GtkWidget *widget,
1141 GdkEventMotion *event)
1143 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1145 ev_view_presentation_hide_cursor_timeout_start (pview);
1146 ev_view_presentation_set_cursor_for_location (pview, event->x, event->y);
1152 ev_view_presentation_realize (GtkWidget *widget)
1154 GdkWindowAttr attributes;
1156 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1158 attributes.window_type = GDK_WINDOW_CHILD;
1159 attributes.wclass = GDK_INPUT_OUTPUT;
1160 attributes.visual = gtk_widget_get_visual (widget);
1161 attributes.colormap = gtk_widget_get_colormap (widget);
1163 attributes.x = widget->allocation.x;
1164 attributes.y = widget->allocation.y;
1165 attributes.width = widget->allocation.width;
1166 attributes.height = widget->allocation.height;
1167 attributes.event_mask = GDK_EXPOSURE_MASK |
1168 GDK_BUTTON_PRESS_MASK |
1169 GDK_BUTTON_RELEASE_MASK |
1171 GDK_KEY_PRESS_MASK |
1172 GDK_POINTER_MOTION_MASK |
1173 GDK_POINTER_MOTION_HINT_MASK |
1174 GDK_ENTER_NOTIFY_MASK |
1175 GDK_LEAVE_NOTIFY_MASK;
1177 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1179 GDK_WA_X | GDK_WA_Y |
1182 gdk_window_set_user_data (widget->window, widget);
1183 widget->style = gtk_style_attach (widget->style, widget->window);
1185 gdk_window_set_background (widget->window, &widget->style->black);
1187 gtk_widget_queue_resize (widget);
1191 ev_view_presentation_change_page (EvViewPresentation *pview,
1192 GtkScrollType scroll)
1195 case GTK_SCROLL_PAGE_FORWARD:
1196 ev_view_presentation_next_page (pview);
1198 case GTK_SCROLL_PAGE_BACKWARD:
1199 ev_view_presentation_previous_page (pview);
1202 g_assert_not_reached ();
1207 ev_view_presentation_scroll_event (GtkWidget *widget,
1208 GdkEventScroll *event)
1210 EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget);
1213 state = event->state & gtk_accelerator_get_default_mod_mask ();
1217 switch (event->direction) {
1218 case GDK_SCROLL_DOWN:
1219 case GDK_SCROLL_RIGHT:
1220 ev_view_presentation_change_page (pview, GTK_SCROLL_PAGE_FORWARD);
1223 case GDK_SCROLL_LEFT:
1224 ev_view_presentation_change_page (pview, GTK_SCROLL_PAGE_BACKWARD);
1233 add_change_page_binding_keypad (GtkBindingSet *binding_set,
1235 GdkModifierType modifiers,
1236 GtkScrollType scroll)
1238 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
1240 gtk_binding_entry_add_signal (binding_set, keyval, modifiers,
1242 GTK_TYPE_SCROLL_TYPE, scroll);
1243 gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers,
1245 GTK_TYPE_SCROLL_TYPE, scroll);
1249 ev_view_presentation_set_property (GObject *object,
1251 const GValue *value,
1254 EvViewPresentation *pview = EV_VIEW_PRESENTATION (object);
1258 pview->document = g_value_dup_object (value);
1259 pview->enable_animations = EV_IS_DOCUMENT_TRANSITION (pview->document);
1261 case PROP_CURRENT_PAGE:
1262 pview->current_page = g_value_get_uint (value);
1265 pview->rotation = g_value_get_uint (value);
1268 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1273 ev_view_presentation_constructor (GType type,
1274 guint n_construct_properties,
1275 GObjectConstructParam *construct_params)
1278 EvViewPresentation *pview;
1281 object = G_OBJECT_CLASS (ev_view_presentation_parent_class)->constructor (type,
1282 n_construct_properties,
1284 pview = EV_VIEW_PRESENTATION (object);
1286 if (EV_IS_DOCUMENT_LINKS (pview->document)) {
1287 pview->page_cache = ev_page_cache_new (pview->document);
1288 ev_page_cache_set_flags (pview->page_cache, EV_PAGE_DATA_INCLUDE_LINKS);
1291 /* Call allocate asap to update page scale */
1292 ev_view_presentation_size_allocate (GTK_WIDGET (pview), &a);
1293 ev_view_presentation_update_current_page (pview, pview->current_page);
1294 ev_view_presentation_hide_cursor_timeout_start (pview);
1300 ev_view_presentation_class_init (EvViewPresentationClass *klass)
1302 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
1303 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1304 GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass);
1305 GtkBindingSet *binding_set;
1307 klass->change_page = ev_view_presentation_change_page;
1309 widget_class->size_allocate = ev_view_presentation_size_allocate;
1310 widget_class->size_request = ev_view_presentation_size_request;
1311 widget_class->realize = ev_view_presentation_realize;
1312 widget_class->expose_event = ev_view_presentation_expose_event;
1313 widget_class->key_press_event = ev_view_presentation_key_press_event;
1314 widget_class->button_release_event = ev_view_presentation_button_release_event;
1315 widget_class->focus_out_event = ev_view_presentation_focus_out;
1316 widget_class->motion_notify_event = ev_view_presentation_motion_notify_event;
1317 widget_class->scroll_event = ev_view_presentation_scroll_event;
1319 gtk_object_class->destroy = ev_view_presentation_destroy;
1321 gobject_class->constructor = ev_view_presentation_constructor;
1322 gobject_class->set_property = ev_view_presentation_set_property;
1324 g_object_class_install_property (gobject_class,
1326 g_param_spec_object ("document",
1331 G_PARAM_CONSTRUCT_ONLY));
1332 g_object_class_install_property (gobject_class,
1334 g_param_spec_uint ("current_page",
1339 G_PARAM_CONSTRUCT_ONLY));
1340 g_object_class_install_property (gobject_class,
1342 g_param_spec_uint ("rotation",
1344 "Current rotation angle",
1347 G_PARAM_CONSTRUCT_ONLY));
1349 signals[CHANGE_PAGE] =
1350 g_signal_new ("change_page",
1351 G_OBJECT_CLASS_TYPE (gobject_class),
1352 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1353 G_STRUCT_OFFSET (EvViewPresentationClass, change_page),
1355 g_cclosure_marshal_VOID__ENUM,
1357 GTK_TYPE_SCROLL_TYPE);
1359 binding_set = gtk_binding_set_by_class (klass);
1360 add_change_page_binding_keypad (binding_set, GDK_Left, 0, GTK_SCROLL_PAGE_BACKWARD);
1361 add_change_page_binding_keypad (binding_set, GDK_Right, 0, GTK_SCROLL_PAGE_FORWARD);
1362 add_change_page_binding_keypad (binding_set, GDK_Up, 0, GTK_SCROLL_PAGE_BACKWARD);
1363 add_change_page_binding_keypad (binding_set, GDK_Down, 0, GTK_SCROLL_PAGE_FORWARD);
1364 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
1366 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1367 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
1369 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1370 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
1372 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1373 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
1375 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1376 gtk_binding_entry_add_signal (binding_set, GDK_J, 0,
1378 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1379 gtk_binding_entry_add_signal (binding_set, GDK_H, 0,
1381 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1382 gtk_binding_entry_add_signal (binding_set, GDK_L, 0,
1384 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1385 gtk_binding_entry_add_signal (binding_set, GDK_K, 0,
1387 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1391 ev_view_presentation_init (EvViewPresentation *pview)
1393 GTK_WIDGET_SET_FLAGS (pview, GTK_CAN_FOCUS);
1397 ev_view_presentation_new (EvDocument *document,
1401 g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL);
1402 g_return_val_if_fail (current_page < ev_document_get_n_pages (document), NULL);
1404 return GTK_WIDGET (g_object_new (EV_TYPE_VIEW_PRESENTATION,
1405 "document", document,
1406 "current_page", current_page,
1407 "rotation", rotation,
1412 ev_view_presentation_get_current_page (EvViewPresentation *pview)
1414 return pview->current_page;