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=c3e40bf5787c557535f623470f65c010a0a70a6d;hb=b43ae08397c06479da37a5bf094a0a071cb4d394;hp=24a8801242869f398cb16eeef5cc9c54658d0a76;hpb=0981b6257ec356fd5fb0dac919640f3af41c2351;p=evince.git diff --git a/libview/ev-view-presentation.c b/libview/ev-view-presentation.c index 24a88012..c3e40bf5 100644 --- a/libview/ev-view-presentation.c +++ b/libview/ev-view-presentation.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" @@ -30,18 +30,22 @@ #include "ev-transition-animation.h" #include "ev-view-cursor.h" #include "ev-page-cache.h" -#include "ev-mapping.h" + + enum { PROP_0, PROP_DOCUMENT, PROP_CURRENT_PAGE, - PROP_ROTATION + PROP_PAGE, + PROP_ROTATION, + PROP_INVERTED_COLORS }; enum { CHANGE_PAGE, FINISHED, + SIGNAL_EXTERNAL_LINK, N_SIGNALS }; @@ -56,12 +60,17 @@ struct _EvViewPresentation { GtkWidget base; + guint is_constructing : 1; + guint current_page; cairo_surface_t *current_surface; EvDocument *document; guint rotation; + gboolean inverted_colors; EvPresentationState state; gdouble scale; + gint monitor_width; + gint monitor_height; /* Cursors */ EvViewCursor cursor; @@ -91,15 +100,15 @@ struct _EvViewPresentationClass GtkWidgetClass base_class; /* signals */ - void (* change_page) (EvViewPresentation *pview, - GtkScrollType scroll); - void (* finished) (EvViewPresentation *pview); + void (* change_page) (EvViewPresentation *pview, + GtkScrollType scroll); + void (* finished) (EvViewPresentation *pview); + void (* external_link) (EvViewPresentation *pview, + EvLinkAction *action); }; static guint signals[N_SIGNALS] = { 0 }; -static void ev_view_presentation_next_page (EvViewPresentation *pview); -static void ev_view_presentation_previous_page (EvViewPresentation *pview); static void ev_view_presentation_set_cursor_for_location (EvViewPresentation *pview, gdouble x, gdouble y); @@ -108,6 +117,9 @@ static void ev_view_presentation_set_cursor_for_location (EvViewPresentation *pv G_DEFINE_TYPE (EvViewPresentation, ev_view_presentation, GTK_TYPE_WIDGET) +static GdkRGBA black = { 0., 0., 0., 1. }; +static GdkRGBA white = { 1., 1., 1., 1. }; + static void ev_view_presentation_set_normal (EvViewPresentation *pview) { @@ -117,7 +129,7 @@ ev_view_presentation_set_normal (EvViewPresentation *pview) return; pview->state = EV_PRESENTATION_NORMAL; - gdk_window_set_background (widget->window, &widget->style->black); + gdk_window_set_background_rgba (gtk_widget_get_window (widget), &black); gtk_widget_queue_draw (widget); } @@ -130,7 +142,7 @@ ev_view_presentation_set_black (EvViewPresentation *pview) return; pview->state = EV_PRESENTATION_BLACK; - gdk_window_set_background (widget->window, &widget->style->black); + gdk_window_set_background_rgba (gtk_widget_get_window (widget), &black); gtk_widget_queue_draw (widget); } @@ -143,7 +155,7 @@ ev_view_presentation_set_white (EvViewPresentation *pview) return; pview->state = EV_PRESENTATION_WHITE; - gdk_window_set_background (widget->window, &widget->style->white); + gdk_window_set_background_rgba (gtk_widget_get_window (widget), &white); gtk_widget_queue_draw (widget); } @@ -163,47 +175,50 @@ 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 ev_view_presentation_get_page_area (EvViewPresentation *pview, GdkRectangle *area) { - GtkWidget *widget = GTK_WIDGET (pview); - gdouble doc_width, doc_height; - gint view_width, view_height; + GtkWidget *widget = GTK_WIDGET (pview); + GtkAllocation allocation; + gdouble doc_width, doc_height; + gint view_width, view_height; + gdouble scale; ev_document_get_page_size (pview->document, pview->current_page, &doc_width, &doc_height); + scale = ev_view_presentation_get_scale_for_page (pview, pview->current_page); if (pview->rotation == 90 || pview->rotation == 270) { - view_width = (gint)((doc_height * pview->scale) + 0.5); - view_height = (gint)((doc_width * pview->scale) + 0.5); + view_width = (gint)((doc_height * scale) + 0.5); + view_height = (gint)((doc_width * scale) + 0.5); } else { - view_width = (gint)((doc_width * pview->scale) + 0.5); - view_height = (gint)((doc_height * pview->scale) + 0.5); + view_width = (gint)((doc_width * scale) + 0.5); + view_height = (gint)((doc_height * scale) + 0.5); } - area->x = (MAX (0, widget->allocation.width - view_width)) / 2; - area->y = (MAX (0, widget->allocation.height - view_height)) / 2; + gtk_widget_get_allocation (widget, &allocation); + + area->x = (MAX (0, allocation.width - view_width)) / 2; + area->y = (MAX (0, allocation.height - view_height)) / 2; area->width = view_width; area->height = view_height; } @@ -237,7 +252,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,16 +306,16 @@ ev_view_presentation_animation_start (EvViewPresentation *pview, pview->animation = ev_transition_animation_new (effect); - surface = EV_JOB_RENDER (pview->curr_job)->surface; + surface = pview->curr_job ? EV_JOB_RENDER (pview->curr_job)->surface : NULL; ev_transition_animation_set_origin_surface (pview->animation, surface != NULL ? surface : pview->current_surface); jump = new_page - pview->current_page; if (jump == -1) - surface = EV_JOB_RENDER (pview->prev_job)->surface; + surface = pview->prev_job ? EV_JOB_RENDER (pview->prev_job)->surface : NULL; else if (jump == 1) - surface = EV_JOB_RENDER (pview->next_job)->surface; + surface = pview->next_job ? EV_JOB_RENDER (pview->next_job)->surface : NULL; else surface = NULL; if (surface) @@ -321,6 +336,9 @@ job_finished_cb (EvJob *job, { EvJobRender *job_render = EV_JOB_RENDER (job); + if (pview->inverted_colors) + ev_document_misc_invert_surface (job_render->surface); + if (job != pview->curr_job) return; @@ -344,11 +362,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); @@ -369,6 +384,25 @@ ev_view_presentation_delete_job (EvViewPresentation *pview, g_object_unref (job); } +static void +ev_view_presentation_reset_jobs (EvViewPresentation *pview) +{ + if (pview->curr_job) { + ev_view_presentation_delete_job (pview, pview->curr_job); + pview->curr_job = NULL; + } + + if (pview->prev_job) { + ev_view_presentation_delete_job (pview, pview->prev_job); + pview->prev_job = NULL; + } + + if (pview->next_job) { + ev_view_presentation_delete_job (pview, pview->next_job); + pview->next_job = NULL; + } +} + static void ev_view_presentation_update_current_page (EvViewPresentation *pview, guint page) @@ -458,7 +492,8 @@ ev_view_presentation_update_current_page (EvViewPresentation *pview, } pview->current_page = page; - ev_view_presentation_update_scale (pview); + g_object_notify (G_OBJECT(pview), "page"); + if (pview->page_cache) ev_page_cache_set_page_range (pview->page_cache, page, page); @@ -473,7 +508,20 @@ ev_view_presentation_update_current_page (EvViewPresentation *pview, gtk_widget_queue_draw (GTK_WIDGET (pview)); } -static void +void +ev_view_presentation_set_page (EvViewPresentation *pview, gint new_page) +{ + guint n_pages; + + n_pages = ev_document_get_n_pages (pview->document); + + if (new_page >= n_pages) + ev_view_presentation_set_end (pview); + else + ev_view_presentation_update_current_page (pview, new_page); +} + +void ev_view_presentation_next_page (EvViewPresentation *pview) { guint n_pages; @@ -498,7 +546,7 @@ ev_view_presentation_next_page (EvViewPresentation *pview) ev_view_presentation_update_current_page (pview, new_page); } -static void +void ev_view_presentation_previous_page (EvViewPresentation *pview) { gint new_page = 0; @@ -522,7 +570,7 @@ ev_view_presentation_previous_page (EvViewPresentation *pview) /* Goto Window */ #define KEY_IS_NUMERIC(keyval) \ - ((keyval >= GDK_0 && keyval <= GDK_9) || (keyval >= GDK_KP_0 && keyval <= GDK_KP_9)) + ((keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9) || (keyval >= GDK_KEY_KP_0 && keyval <= GDK_KEY_KP_9)) /* Cut and paste from gtkwindow.c */ static void @@ -531,22 +579,14 @@ send_focus_change (GtkWidget *widget, { GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE); - g_object_ref (widget); - - if (in) - GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); - else - GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); - fevent->focus_change.type = GDK_FOCUS_CHANGE; - fevent->focus_change.window = g_object_ref (widget->window); + fevent->focus_change.window = gtk_widget_get_window (widget); fevent->focus_change.in = in; + if (fevent->focus_change.window) + g_object_ref (fevent->focus_change.window); - gtk_widget_event (widget, fevent); - - g_object_notify (G_OBJECT (widget), "has-focus"); + gtk_widget_send_focus_change (widget, fevent); - g_object_unref (widget); gdk_event_free (fevent); } @@ -575,17 +615,17 @@ ev_view_presentation_goto_window_key_press_event (GtkWidget *widget, EvViewPresentation *pview) { switch (event->keyval) { - case GDK_Escape: - case GDK_Tab: - case GDK_KP_Tab: - case GDK_ISO_Left_Tab: + case GDK_KEY_Escape: + case GDK_KEY_Tab: + case GDK_KEY_KP_Tab: + case GDK_KEY_ISO_Left_Tab: ev_view_presentation_goto_window_hide (pview); return TRUE; - case GDK_Return: - case GDK_KP_Enter: - case GDK_ISO_Enter: - case GDK_BackSpace: - case GDK_Delete: + case GDK_KEY_Return: + case GDK_KEY_KP_Enter: + case GDK_KEY_ISO_Enter: + case GDK_KEY_BackSpace: + case GDK_KEY_Delete: return FALSE; default: if (!KEY_IS_NUMERIC (event->keyval)) @@ -622,29 +662,29 @@ ev_view_presentation_goto_entry_activate (GtkEntry *entry, static void ev_view_presentation_goto_window_create (EvViewPresentation *pview) { - GtkWidget *frame, *hbox, *toplevel, *label; + GtkWidget *frame, *hbox, *label; + GtkWindow *toplevel, *goto_window; - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (pview)); + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (pview))); if (pview->goto_window) { - if (GTK_WINDOW (toplevel)->group) - gtk_window_group_add_window (GTK_WINDOW (toplevel)->group, - GTK_WINDOW (pview->goto_window)); - else if (GTK_WINDOW (pview->goto_window)->group) - gtk_window_group_remove_window (GTK_WINDOW (pview->goto_window)->group, - GTK_WINDOW (pview->goto_window)); + goto_window = GTK_WINDOW (pview->goto_window); + if (gtk_window_has_group (toplevel)) + gtk_window_group_add_window (gtk_window_get_group (toplevel), goto_window); + else if (gtk_window_has_group (goto_window)) + gtk_window_group_remove_window (gtk_window_get_group (goto_window), goto_window); + return; } pview->goto_window = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_set_screen (GTK_WINDOW (pview->goto_window), - gtk_widget_get_screen (GTK_WIDGET (pview))); + goto_window = GTK_WINDOW (pview->goto_window); + gtk_window_set_screen (goto_window, gtk_widget_get_screen (GTK_WIDGET (pview))); - if (GTK_WINDOW (toplevel)->group) - gtk_window_group_add_window (GTK_WINDOW (toplevel)->group, - GTK_WINDOW (pview->goto_window)); + if (gtk_window_has_group (toplevel)) + gtk_window_group_add_window (gtk_window_get_group (toplevel), goto_window); - gtk_window_set_modal (GTK_WINDOW (pview->goto_window), TRUE); + gtk_window_set_modal (goto_window, TRUE); g_signal_connect (pview->goto_window, "delete_event", G_CALLBACK (ev_view_presentation_goto_window_delete_event), @@ -707,7 +747,9 @@ ev_view_presentation_goto_window_send_key_event (EvViewPresentation *pview, new_event = (GdkEventKey *) gdk_event_copy (event); g_object_unref (new_event->window); - new_event->window = g_object_ref (pview->goto_window->window); + new_event->window = gtk_widget_get_window (pview->goto_window); + if (new_event->window) + g_object_ref (new_event->window); gtk_widget_realize (pview->goto_window); gtk_widget_event (pview->goto_window, (GdkEvent *)new_event); @@ -730,6 +772,9 @@ ev_view_presentation_link_is_supported (EvViewPresentation *pview, case EV_LINK_ACTION_TYPE_GOTO_DEST: return ev_link_action_get_dest (action) != NULL; case EV_LINK_ACTION_TYPE_NAMED: + case EV_LINK_ACTION_TYPE_GOTO_REMOTE: + case EV_LINK_ACTION_TYPE_EXTERNAL_URI: + case EV_LINK_ACTION_TYPE_LAUNCH: return TRUE; default: return FALSE; @@ -743,19 +788,21 @@ ev_view_presentation_get_link_at_location (EvViewPresentation *pview, gdouble x, gdouble y) { - GdkRectangle page_area; - GList *link_mapping; - EvLink *link; - gdouble width, height; - gdouble new_x, new_y; + GdkRectangle page_area; + EvMappingList *link_mapping; + 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: @@ -786,14 +833,15 @@ ev_view_presentation_get_link_at_location (EvViewPresentation *pview, } static void -ev_vew_presentation_goto_link_dest (EvViewPresentation *pview, - EvLink *link) +ev_vew_presentation_handle_link (EvViewPresentation *pview, + EvLink *link) { EvLinkAction *action; action = ev_link_get_action (link); - if (ev_link_action_get_action_type (action) == EV_LINK_ACTION_TYPE_NAMED) { + switch (ev_link_action_get_action_type (action)) { + case EV_LINK_ACTION_TYPE_NAMED: { const gchar *name = ev_link_action_get_name (action); if (g_ascii_strcasecmp (name, "FirstPage") == 0) { @@ -808,13 +856,25 @@ ev_vew_presentation_goto_link_dest (EvViewPresentation *pview, n_pages = ev_document_get_n_pages (pview->document); ev_view_presentation_update_current_page (pview, n_pages - 1); } - } else { + } + break; + + case EV_LINK_ACTION_TYPE_GOTO_DEST: { EvLinkDest *dest; gint page; dest = ev_link_action_get_dest (action); page = ev_document_links_get_dest_page (EV_DOCUMENT_LINKS (pview->document), dest); ev_view_presentation_update_current_page (pview, page); + } + break; + case EV_LINK_ACTION_TYPE_GOTO_REMOTE: + case EV_LINK_ACTION_TYPE_EXTERNAL_URI: + case EV_LINK_ACTION_TYPE_LAUNCH: + g_signal_emit (pview, signals[SIGNAL_EXTERNAL_LINK], 0, action); + break; + default: + break; } } @@ -830,16 +890,16 @@ ev_view_presentation_set_cursor (EvViewPresentation *pview, return; widget = GTK_WIDGET (pview); - if (!GTK_WIDGET_REALIZED (widget)) + if (!gtk_widget_get_realized (widget)) gtk_widget_realize (widget); pview->cursor = view_cursor; cursor = ev_view_cursor_new (gtk_widget_get_display (widget), view_cursor); - gdk_window_set_cursor (widget->window, cursor); + gdk_window_set_cursor (gtk_widget_get_window (widget), cursor); gdk_flush (); if (cursor) - gdk_cursor_unref (cursor); + g_object_unref (cursor); } static void @@ -894,7 +954,7 @@ ev_view_presentation_update_current_surface (EvViewPresentation *pview, } static void -ev_view_presentation_destroy (GtkObject *object) +ev_view_presentation_dispose (GObject *object) { EvViewPresentation *pview = EV_VIEW_PRESENTATION (object); @@ -906,21 +966,7 @@ ev_view_presentation_destroy (GtkObject *object) ev_view_presentation_animation_cancel (pview); ev_view_presentation_transition_stop (pview); ev_view_presentation_hide_cursor_timeout_stop (pview); - - if (pview->curr_job) { - ev_view_presentation_delete_job (pview, pview->curr_job); - pview->curr_job = NULL; - } - - if (pview->prev_job) { - ev_view_presentation_delete_job (pview, pview->prev_job); - pview->prev_job = NULL; - } - - if (pview->next_job) { - ev_view_presentation_delete_job (pview, pview->next_job); - pview->next_job = NULL; - } + ev_view_presentation_reset_jobs (pview); if (pview->current_surface) { cairo_surface_destroy (pview->current_surface); @@ -938,43 +984,34 @@ ev_view_presentation_destroy (GtkObject *object) pview->goto_entry = NULL; } - GTK_OBJECT_CLASS (ev_view_presentation_parent_class)->destroy (object); + G_OBJECT_CLASS (ev_view_presentation_parent_class)->dispose (object); } static void -ev_view_presentation_size_request (GtkWidget *widget, - GtkRequisition *requisition) +ev_view_presentation_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) { - requisition->width = 0; - requisition->height = 0; + *minimum = *natural = 0; } static void -ev_view_presentation_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) +ev_view_presentation_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) { - 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); + *minimum = *natural = 0; } static void -ev_view_presentation_draw_end_page (EvViewPresentation *pview) +ev_view_presentation_draw_end_page (EvViewPresentation *pview, + cairo_t *cr) { GtkWidget *widget = GTK_WIDGET (pview); PangoLayout *layout; PangoFontDescription *font_desc; gchar *markup; + GtkAllocation allocation; GdkRectangle area = {0}; const gchar *text = _("End of presentation. Click to exit."); @@ -990,37 +1027,33 @@ ev_view_presentation_draw_end_page (EvViewPresentation *pview) pango_font_description_set_size (font_desc, 16 * PANGO_SCALE); pango_layout_set_font_description (layout, font_desc); - area.width = widget->allocation.width; - area.height = widget->allocation.height; + gtk_widget_get_allocation (widget, &allocation); + area.width = allocation.width; + area.height = allocation.height; - gtk_paint_layout (widget->style, - widget->window, - GTK_WIDGET_STATE (widget), - FALSE, - &area, - widget, - NULL, - 15, - 15, - layout); + gtk_render_layout (gtk_widget_get_style_context (widget), + cr, 15, 15, layout); pango_font_description_free (font_desc); g_object_unref (layout); } static gboolean -ev_view_presentation_expose_event (GtkWidget *widget, - GdkEventExpose *event) +ev_view_presentation_draw (GtkWidget *widget, + cairo_t *cr) { EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); GdkRectangle page_area; GdkRectangle overlap; cairo_surface_t *surface; - cairo_t *cr; + GdkRectangle clip_rect; + + if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect)) + return FALSE; switch (pview->state) { case EV_PRESENTATION_END: - ev_view_presentation_draw_end_page (pview); + ev_view_presentation_draw_end_page (pview, cr); return FALSE; case EV_PRESENTATION_BLACK: case EV_PRESENTATION_WHITE: @@ -1033,7 +1066,7 @@ ev_view_presentation_expose_event (GtkWidget *widget, if (ev_transition_animation_ready (pview->animation)) { ev_view_presentation_get_page_area (pview, &page_area); - cr = gdk_cairo_create (widget->window); + cairo_save (cr); /* normalize to x=0, y=0 */ cairo_translate (cr, page_area.x, page_area.y); @@ -1043,7 +1076,8 @@ ev_view_presentation_expose_event (GtkWidget *widget, page_area.width--; ev_transition_animation_paint (pview->animation, cr, page_area); - cairo_destroy (cr); + + cairo_restore (cr); } return TRUE; @@ -1059,8 +1093,8 @@ ev_view_presentation_expose_event (GtkWidget *widget, } ev_view_presentation_get_page_area (pview, &page_area); - if (gdk_rectangle_intersect (&page_area, &(event->area), &overlap)) { - cr = gdk_cairo_create (widget->window); + if (gdk_rectangle_intersect (&page_area, &clip_rect, &overlap)) { + cairo_save (cr); /* Try to fix rounding errors. See bug #438760 */ if (overlap.width == page_area.width) @@ -1069,7 +1103,8 @@ ev_view_presentation_expose_event (GtkWidget *widget, 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); + + cairo_restore (cr); } return FALSE; @@ -1082,27 +1117,43 @@ ev_view_presentation_key_press_event (GtkWidget *widget, EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); if (pview->state == EV_PRESENTATION_END) - return gtk_bindings_activate_event (GTK_OBJECT (widget), event); + return gtk_bindings_activate_event (G_OBJECT (widget), event); switch (event->keyval) { - case GDK_b: - case GDK_B: - case GDK_period: - case GDK_KP_Decimal: + case GDK_KEY_b: + case GDK_KEY_B: + case GDK_KEY_period: + case GDK_KEY_KP_Decimal: if (pview->state == EV_PRESENTATION_BLACK) ev_view_presentation_set_normal (pview); else ev_view_presentation_set_black (pview); return TRUE; - case GDK_w: - case GDK_W: + case GDK_KEY_w: + case GDK_KEY_W: if (pview->state == EV_PRESENTATION_WHITE) ev_view_presentation_set_normal (pview); else ev_view_presentation_set_white (pview); return TRUE; + case GDK_KEY_Home: + if (pview->state == EV_PRESENTATION_NORMAL) { + ev_view_presentation_update_current_page (pview, 0); + return TRUE; + } + break; + case GDK_KEY_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; } @@ -1122,7 +1173,7 @@ ev_view_presentation_key_press_event (GtkWidget *widget, return TRUE; } - return gtk_bindings_activate_event (GTK_OBJECT (widget), event); + return gtk_bindings_activate_event (G_OBJECT (widget), event); } static gboolean @@ -1145,7 +1196,7 @@ ev_view_presentation_button_release_event (GtkWidget *widget, event->x, event->y); if (link) - ev_vew_presentation_goto_link_dest (pview, link); + ev_vew_presentation_handle_link (pview, link); else ev_view_presentation_next_page (pview); } @@ -1184,22 +1235,84 @@ ev_view_presentation_motion_notify_event (GtkWidget *widget, return FALSE; } +static GdkRectangle +ev_view_presentation_get_monitor_geometry (EvViewPresentation *pview) +{ + GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET(pview)); + GdkRectangle monitor; + gint monitor_num; + + monitor_num = gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window (GTK_WIDGET(pview))); + gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + + return monitor; +} + +static void +ev_view_presentation_update_scale (EvViewPresentation *pview) +{ + GdkRectangle monitor = ev_view_presentation_get_monitor_geometry (pview); + + if((pview->monitor_width != monitor.width)||(pview->monitor_height != monitor.height)) { + pview->monitor_width = monitor.width; + pview->monitor_height = monitor.height; + + pview->scale = 0; + ev_view_presentation_reset_jobs (pview); + ev_view_presentation_update_current_page (pview, pview->current_page); + } +} + +static void +ev_view_presentation_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + gtk_widget_set_allocation (widget, allocation); + if (gtk_widget_get_realized (widget)) + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, + allocation->y, + allocation->width, + allocation->height); + ev_view_presentation_update_scale (EV_VIEW_PRESENTATION (widget)); +} + +static gboolean +init_presentation (GtkWidget *widget) +{ + EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); + GdkRectangle monitor = ev_view_presentation_get_monitor_geometry (pview); + + pview->monitor_width = monitor.width; + pview->monitor_height = monitor.height; + + g_signal_connect_swapped (G_OBJECT (widget), "screen-changed", + G_CALLBACK (ev_view_presentation_update_scale), pview); + + 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) { - GdkWindowAttr attributes; + GdkWindow *window; + GdkWindowAttr attributes; + GtkAllocation allocation; - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + gtk_widget_set_realized (widget, TRUE); attributes.window_type = GDK_WINDOW_CHILD; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; + gtk_widget_get_allocation (widget, &allocation); + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; attributes.event_mask = GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | @@ -1207,20 +1320,20 @@ 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), - &attributes, - GDK_WA_X | GDK_WA_Y | - GDK_WA_COLORMAP | - GDK_WA_VISUAL); - gdk_window_set_user_data (widget->window, widget); - widget->style = gtk_style_attach (widget->style, widget->window); + window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, + GDK_WA_X | GDK_WA_Y | + GDK_WA_VISUAL); - gdk_window_set_background (widget->window, &widget->style->black); + gdk_window_set_user_data (window, widget); + gtk_widget_set_window (widget, window); + gtk_style_context_set_background (gtk_widget_get_style_context (widget), + window); - gtk_widget_queue_resize (widget); + g_idle_add ((GSourceFunc)init_presentation, widget); } static void @@ -1271,7 +1384,7 @@ add_change_page_binding_keypad (GtkBindingSet *binding_set, GdkModifierType modifiers, GtkScrollType scroll) { - guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left; + guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left; gtk_binding_entry_add_signal (binding_set, keyval, modifiers, "change_page", 1, @@ -1297,38 +1410,59 @@ ev_view_presentation_set_property (GObject *object, case PROP_CURRENT_PAGE: pview->current_page = g_value_get_uint (value); break; + case PROP_PAGE: + pview->current_page = g_value_get_uint (value); + break; case PROP_ROTATION: - pview->rotation = g_value_get_uint (value); + ev_view_presentation_set_rotation (pview, g_value_get_uint (value)); + break; + case PROP_INVERTED_COLORS: + pview->inverted_colors = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } +static void +ev_view_presentation_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EvViewPresentation *pview = EV_VIEW_PRESENTATION (object); + + switch (prop_id) { + case PROP_PAGE: + g_value_set_uint (value, ev_view_presentation_get_current_page (pview)); + break; + case PROP_ROTATION: + g_value_set_uint (value, ev_view_presentation_get_rotation (pview)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + static GObject * ev_view_presentation_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_params) + guint n_construct_properties, + GObjectConstructParam *construct_params) { GObject *object; EvViewPresentation *pview; - GtkAllocation a; object = G_OBJECT_CLASS (ev_view_presentation_parent_class)->constructor (type, n_construct_properties, construct_params); pview = EV_VIEW_PRESENTATION (object); + pview->is_constructing = FALSE; if (EV_IS_DOCUMENT_LINKS (pview->document)) { pview->page_cache = ev_page_cache_new (pview->document); 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; } @@ -1337,25 +1471,27 @@ ev_view_presentation_class_init (EvViewPresentationClass *klass) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass); GtkBindingSet *binding_set; + GtkCssProvider *provider; klass->change_page = ev_view_presentation_change_page; + gobject_class->dispose = ev_view_presentation_dispose; + widget_class->size_allocate = ev_view_presentation_size_allocate; - widget_class->size_request = ev_view_presentation_size_request; + widget_class->get_preferred_width = ev_view_presentation_get_preferred_width; + widget_class->get_preferred_height = ev_view_presentation_get_preferred_height; widget_class->realize = ev_view_presentation_realize; - widget_class->expose_event = ev_view_presentation_expose_event; + widget_class->draw = ev_view_presentation_draw; widget_class->key_press_event = ev_view_presentation_key_press_event; widget_class->button_release_event = ev_view_presentation_button_release_event; widget_class->focus_out_event = ev_view_presentation_focus_out; widget_class->motion_notify_event = ev_view_presentation_motion_notify_event; widget_class->scroll_event = ev_view_presentation_scroll_event; - gtk_object_class->destroy = ev_view_presentation_destroy; - gobject_class->constructor = ev_view_presentation_constructor; gobject_class->set_property = ev_view_presentation_set_property; + gobject_class->get_property = ev_view_presentation_get_property; g_object_class_install_property (gobject_class, PROP_DOCUMENT, @@ -1365,13 +1501,20 @@ ev_view_presentation_class_init (EvViewPresentationClass *klass) EV_TYPE_DOCUMENT, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (gobject_class, + PROP_PAGE, + g_param_spec_uint ("page", + "Current Page", + "The current page", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_CURRENT_PAGE, g_param_spec_uint ("current_page", "Current Page", "The current page", 0, G_MAXUINT, 0, - G_PARAM_WRITABLE | + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_ROTATION, @@ -1379,8 +1522,16 @@ ev_view_presentation_class_init (EvViewPresentationClass *klass) "Rotation", "Current rotation angle", 0, 360, 0, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + g_object_class_install_property (gobject_class, + PROP_INVERTED_COLORS, + g_param_spec_boolean ("inverted_colors", + "Inverted Colors", + "Whether presentation is displayed with inverted colors", + FALSE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); signals[CHANGE_PAGE] = g_signal_new ("change_page", @@ -1391,6 +1542,7 @@ 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), @@ -1400,48 +1552,69 @@ ev_view_presentation_class_init (EvViewPresentationClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + signals[SIGNAL_EXTERNAL_LINK] = + g_signal_new ("external-link", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvViewPresentationClass, external_link), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); binding_set = gtk_binding_set_by_class (klass); - add_change_page_binding_keypad (binding_set, GDK_Left, 0, GTK_SCROLL_PAGE_BACKWARD); - add_change_page_binding_keypad (binding_set, GDK_Right, 0, GTK_SCROLL_PAGE_FORWARD); - add_change_page_binding_keypad (binding_set, GDK_Up, 0, GTK_SCROLL_PAGE_BACKWARD); - add_change_page_binding_keypad (binding_set, GDK_Down, 0, GTK_SCROLL_PAGE_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_space, 0, + add_change_page_binding_keypad (binding_set, GDK_KEY_Left, 0, GTK_SCROLL_PAGE_BACKWARD); + add_change_page_binding_keypad (binding_set, GDK_KEY_Right, 0, GTK_SCROLL_PAGE_FORWARD); + add_change_page_binding_keypad (binding_set, GDK_KEY_Up, 0, GTK_SCROLL_PAGE_BACKWARD); + add_change_page_binding_keypad (binding_set, GDK_KEY_Down, 0, GTK_SCROLL_PAGE_FORWARD); + gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "change_page", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "change_page", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD); - gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Down, 0, "change_page", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Up, 0, "change_page", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD); - gtk_binding_entry_add_signal (binding_set, GDK_J, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_J, 0, "change_page", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_H, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_H, 0, "change_page", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD); - gtk_binding_entry_add_signal (binding_set, GDK_L, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_L, 0, "change_page", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_K, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_K, 0, "change_page", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD); + + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (provider, + "EvViewPresentation {\n" + " background-color: black; }", + -1, NULL); + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref (provider); } static void ev_view_presentation_init (EvViewPresentation *pview) { - GTK_WIDGET_SET_FLAGS (pview, GTK_CAN_FOCUS); + gtk_widget_set_can_focus (GTK_WIDGET (pview), TRUE); + pview->is_constructing = TRUE; } GtkWidget * ev_view_presentation_new (EvDocument *document, guint current_page, - guint rotation) + guint rotation, + gboolean inverted_colors) { g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL); g_return_val_if_fail (current_page < ev_document_get_n_pages (document), NULL); @@ -1450,6 +1623,7 @@ ev_view_presentation_new (EvDocument *document, "document", document, "current_page", current_page, "rotation", rotation, + "inverted_colors", inverted_colors, NULL)); } @@ -1458,3 +1632,31 @@ ev_view_presentation_get_current_page (EvViewPresentation *pview) { return pview->current_page; } + +void +ev_view_presentation_set_rotation (EvViewPresentation *pview, + gint rotation) +{ + if (rotation >= 360) + rotation -= 360; + else if (rotation < 0) + rotation += 360; + + if (pview->rotation == rotation) + return; + + pview->rotation = rotation; + g_object_notify (G_OBJECT (pview), "rotation"); + if (pview->is_constructing) + return; + + pview->scale = 0; + ev_view_presentation_reset_jobs (pview); + ev_view_presentation_update_current_page (pview, pview->current_page); +} + +guint +ev_view_presentation_get_rotation (EvViewPresentation *pview) +{ + return pview->rotation; +}