X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=libview%2Fev-view-presentation.c;h=17491ae7f8461b3f2d1834d38bffbb4e0a353a00;hb=5a058f12f1606d6d87c9ed592df93b33235d3766;hp=8f91869745facbb9f16f69c7834670cac176bec3;hpb=6d690c345c434c074333fa0971af0406eeb2719e;p=evince.git diff --git a/libview/ev-view-presentation.c b/libview/ev-view-presentation.c index 8f918697..17491ae7 100644 --- a/libview/ev-view-presentation.c +++ b/libview/ev-view-presentation.c @@ -41,6 +41,7 @@ enum { enum { CHANGE_PAGE, + FINISHED, N_SIGNALS }; @@ -56,10 +57,13 @@ struct _EvViewPresentation GtkWidget base; guint current_page; + cairo_surface_t *current_surface; EvDocument *document; guint rotation; EvPresentationState state; gdouble scale; + gint monitor_width; + gint monitor_height; /* Cursors */ EvViewCursor cursor; @@ -91,6 +95,7 @@ struct _EvViewPresentationClass /* signals */ void (* change_page) (EvViewPresentation *pview, GtkScrollType scroll); + void (* finished) (EvViewPresentation *pview); }; static guint signals[N_SIGNALS] = { 0 }; @@ -160,23 +165,21 @@ static gdouble ev_view_presentation_get_scale_for_page (EvViewPresentation *pview, guint page) { - gdouble width, height; + if (!ev_document_is_page_size_uniform (pview->document) || pview->scale == 0) { + gdouble width, height; - ev_document_get_page_size (pview->document, page, &width, &height); + ev_document_get_page_size (pview->document, page, &width, &height); + if (pview->rotation == 90 || pview->rotation == 270) { + gdouble tmp; - if (pview->rotation == 90 || pview->rotation == 270) - return GTK_WIDGET (pview)->allocation.height / width; - else - return GTK_WIDGET (pview)->allocation.height / height; -} - -static void -ev_view_presentation_update_scale (EvViewPresentation *pview) -{ - if (ev_document_is_page_size_uniform (pview->document) && pview->scale != 0) - return; + tmp = width; + width = height; + height = tmp; + } + pview->scale = MIN (pview->monitor_width / width, pview->monitor_height / height); + } - pview->scale = ev_view_presentation_get_scale_for_page (pview, pview->current_page); + return pview->scale; } static void @@ -184,27 +187,27 @@ ev_view_presentation_get_page_area (EvViewPresentation *pview, GdkRectangle *area) { GtkWidget *widget = GTK_WIDGET (pview); - gdouble width, height; + gdouble doc_width, doc_height; + gint view_width, view_height; + gdouble scale; ev_document_get_page_size (pview->document, pview->current_page, - &width, &height); + &doc_width, &doc_height); + scale = ev_view_presentation_get_scale_for_page (pview, pview->current_page); if (pview->rotation == 90 || pview->rotation == 270) { - gdouble tmp; - - tmp = width; - width = height; - height = tmp; + view_width = (gint)((doc_height * scale) + 0.5); + view_height = (gint)((doc_width * scale) + 0.5); + } else { + view_width = (gint)((doc_width * scale) + 0.5); + view_height = (gint)((doc_height * scale) + 0.5); } - width *= pview->scale; - height *= pview->scale; - - area->x = (MAX (0, widget->allocation.width - width)) / 2; - area->y = (MAX (0, widget->allocation.height - height)) / 2; - area->width = width; - area->height = height; + area->x = (MAX (0, widget->allocation.width - view_width)) / 2; + area->y = (MAX (0, widget->allocation.height - view_height)) / 2; + area->width = view_width; + area->height = view_height; } /* Page Transition */ @@ -236,7 +239,7 @@ ev_view_presentation_transition_start (EvViewPresentation *pview) duration = ev_document_transition_get_page_duration (EV_DOCUMENT_TRANSITION (pview->document), pview->current_page); - if (duration > 0) { + if (duration >= 0) { pview->trans_timeout_id = g_timeout_add_seconds (duration, (GSourceFunc) transition_next_page, @@ -291,7 +294,9 @@ ev_view_presentation_animation_start (EvViewPresentation *pview, pview->animation = ev_transition_animation_new (effect); surface = EV_JOB_RENDER (pview->curr_job)->surface; - ev_transition_animation_set_origin_surface (pview->animation, surface); + ev_transition_animation_set_origin_surface (pview->animation, + surface != NULL ? + surface : pview->current_surface); jump = new_page - pview->current_page; if (jump == -1) @@ -341,11 +346,8 @@ ev_view_presentation_schedule_new_job (EvViewPresentation *pview, if (page < 0 || page >= ev_document_get_n_pages (pview->document)) return NULL; - if (ev_document_is_page_size_uniform (pview->document)) - scale = pview->scale; - else - scale = ev_view_presentation_get_scale_for_page (pview, page); - job = ev_job_render_new (pview->document, page, pview->rotation, pview->scale, 0, 0); + scale = ev_view_presentation_get_scale_for_page (pview, page); + job = ev_job_render_new (pview->document, page, pview->rotation, scale, 0, 0); g_signal_connect (job, "finished", G_CALLBACK (job_finished_cb), pview); @@ -455,7 +457,7 @@ ev_view_presentation_update_current_page (EvViewPresentation *pview, } pview->current_page = page; - ev_view_presentation_update_scale (pview); + if (pview->page_cache) ev_page_cache_set_page_range (pview->page_cache, page, page); @@ -745,14 +747,16 @@ ev_view_presentation_get_link_at_location (EvViewPresentation *pview, EvLink *link; gdouble width, height; gdouble new_x, new_y; + gdouble scale; if (!pview->page_cache) return NULL; ev_document_get_page_size (pview->document, pview->current_page, &width, &height); ev_view_presentation_get_page_area (pview, &page_area); - x = (x - page_area.x) / pview->scale; - y = (y - page_area.y) / pview->scale; + scale = ev_view_presentation_get_scale_for_page (pview, pview->current_page); + x = (x - page_area.x) / scale; + y = (y - page_area.y) / scale; switch (pview->rotation) { case 0: case 360: @@ -877,6 +881,19 @@ ev_view_presentation_hide_cursor_timeout_start (EvViewPresentation *pview) pview); } +static void +ev_view_presentation_update_current_surface (EvViewPresentation *pview, + cairo_surface_t *surface) +{ + if (!surface || pview->current_surface == surface) + return; + + cairo_surface_reference (surface); + if (pview->current_surface) + cairo_surface_destroy (pview->current_surface); + pview->current_surface = surface; +} + static void ev_view_presentation_destroy (GtkObject *object) { @@ -906,6 +923,11 @@ ev_view_presentation_destroy (GtkObject *object) pview->next_job = NULL; } + if (pview->current_surface) { + cairo_surface_destroy (pview->current_surface); + pview->current_surface = NULL; + } + if (pview->page_cache) { g_object_unref (pview->page_cache); pview->page_cache = NULL; @@ -932,19 +954,9 @@ static void ev_view_presentation_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { - EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); - GdkScreen *screen = gtk_widget_get_screen (widget); - - allocation->x = 0; - allocation->y = 0; - allocation->width = gdk_screen_get_width (screen); - allocation->height = gdk_screen_get_height (screen); - GTK_WIDGET_CLASS (ev_view_presentation_parent_class)->size_allocate (widget, allocation); - ev_view_presentation_update_scale (pview); - - gtk_widget_queue_draw (widget); + widget->allocation = *allocation; } static void @@ -955,7 +967,7 @@ ev_view_presentation_draw_end_page (EvViewPresentation *pview) PangoFontDescription *font_desc; gchar *markup; GdkRectangle area = {0}; - const gchar *text = _("End of presentation. Press Escape to exit."); + const gchar *text = _("End of presentation. Click to exit."); if (pview->state != EV_PRESENTATION_END) return; @@ -1018,6 +1030,9 @@ ev_view_presentation_expose_event (GtkWidget *widget, cairo_translate (cr, page_area.x, page_area.y); page_area.x = page_area.y = 0; + /* Try to fix rounding errors */ + page_area.width--; + ev_transition_animation_paint (pview->animation, cr, page_area); cairo_destroy (cr); } @@ -1026,19 +1041,25 @@ ev_view_presentation_expose_event (GtkWidget *widget, } surface = pview->curr_job ? EV_JOB_RENDER (pview->curr_job)->surface : NULL; - if (!surface) + if (surface) { + ev_view_presentation_update_current_surface (pview, surface); + } else if (pview->current_surface) { + surface = pview->current_surface; + } else { return FALSE; + } ev_view_presentation_get_page_area (pview, &page_area); if (gdk_rectangle_intersect (&page_area, &(event->area), &overlap)) { cr = gdk_cairo_create (widget->window); - cairo_translate (cr, overlap.x, overlap.y); - cairo_surface_set_device_offset (surface, - overlap.x - page_area.x, - overlap.y - page_area.y); - cairo_set_source_surface (cr, surface, 0, 0); - cairo_paint (cr); + /* Try to fix rounding errors. See bug #438760 */ + if (overlap.width == page_area.width) + overlap.width--; + + cairo_rectangle (cr, overlap.x, overlap.y, overlap.width, overlap.height); + cairo_set_source_surface (cr, surface, page_area.x, page_area.y); + cairo_fill (cr); cairo_destroy (cr); } @@ -1073,6 +1094,22 @@ ev_view_presentation_key_press_event (GtkWidget *widget, ev_view_presentation_set_white (pview); return TRUE; + case GDK_Home: + if (pview->state == EV_PRESENTATION_NORMAL) { + ev_view_presentation_update_current_page (pview, 0); + return TRUE; + } + break; + case GDK_End: + if (pview->state == EV_PRESENTATION_NORMAL) { + gint page; + + page = ev_document_get_n_pages (pview->document) - 1; + ev_view_presentation_update_current_page (pview, page); + + return TRUE; + } + break; default: break; } @@ -1105,6 +1142,12 @@ ev_view_presentation_button_release_event (GtkWidget *widget, case 1: { EvLink *link; + if (pview->state == EV_PRESENTATION_END) { + g_signal_emit (pview, signals[FINISHED], 0, NULL); + + return FALSE; + } + link = ev_view_presentation_get_link_at_location (pview, event->x, event->y); @@ -1148,6 +1191,25 @@ ev_view_presentation_motion_notify_event (GtkWidget *widget, return FALSE; } +static gboolean +init_presentation (GtkWidget *widget) +{ + EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); + GdkScreen *screen = gtk_widget_get_screen (widget); + GdkRectangle monitor; + gint monitor_num; + + monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window); + gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + pview->monitor_width = monitor.width; + pview->monitor_height = monitor.height; + + ev_view_presentation_update_current_page (pview, pview->current_page); + ev_view_presentation_hide_cursor_timeout_start (pview); + + return FALSE; +} + static void ev_view_presentation_realize (GtkWidget *widget) { @@ -1171,7 +1233,7 @@ ev_view_presentation_realize (GtkWidget *widget) GDK_KEY_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | - GDK_ENTER_NOTIFY_MASK | + GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK; widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), @@ -1184,7 +1246,7 @@ ev_view_presentation_realize (GtkWidget *widget) gdk_window_set_background (widget->window, &widget->style->black); - gtk_widget_queue_resize (widget); + g_idle_add ((GSourceFunc)init_presentation, widget); } static void @@ -1276,7 +1338,6 @@ ev_view_presentation_constructor (GType type, { GObject *object; EvViewPresentation *pview; - GtkAllocation a; object = G_OBJECT_CLASS (ev_view_presentation_parent_class)->constructor (type, n_construct_properties, @@ -1288,11 +1349,6 @@ ev_view_presentation_constructor (GType type, ev_page_cache_set_flags (pview->page_cache, EV_PAGE_DATA_INCLUDE_LINKS); } - /* Call allocate asap to update page scale */ - ev_view_presentation_size_allocate (GTK_WIDGET (pview), &a); - ev_view_presentation_update_current_page (pview, pview->current_page); - ev_view_presentation_hide_cursor_timeout_start (pview); - return object; } @@ -1355,6 +1411,15 @@ ev_view_presentation_class_init (EvViewPresentationClass *klass) g_cclosure_marshal_VOID__ENUM, G_TYPE_NONE, 1, GTK_TYPE_SCROLL_TYPE); + signals[FINISHED] = + g_signal_new ("finished", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvViewPresentationClass, finished), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0, + G_TYPE_NONE); binding_set = gtk_binding_set_by_class (klass); add_change_page_binding_keypad (binding_set, GDK_Left, 0, GTK_SCROLL_PAGE_BACKWARD);