]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-view.c
Acquire lock document when drawing "Loading..." text so that only one
[evince.git] / shell / ev-view.c
index 32ba7c3ee28f8161f07d91978c66b7af1da1ee55..e8bcf0bd1d1146a43386bbc7241346fbcc49a10d 100644 (file)
@@ -386,6 +386,7 @@ view_set_adjustment_values (EvView         *view,
        factor = 1.0;
        switch (view->pending_scroll) {
                case SCROLL_TO_KEEP_POSITION:
+               case SCROLL_TO_FIND_LOCATION:
                        factor = (adjustment->value) / adjustment->upper;
                        break;
                case SCROLL_TO_PAGE_POSITION:
@@ -406,6 +407,7 @@ view_set_adjustment_values (EvView         *view,
         */
        switch (view->pending_scroll) {
                case SCROLL_TO_KEEP_POSITION:
+               case SCROLL_TO_FIND_LOCATION:
                        new_value = CLAMP (adjustment->upper * factor + 0.5, 0, adjustment->upper - adjustment->page_size);
                        gtk_adjustment_set_value (adjustment, (int)new_value);
                        break;
@@ -428,9 +430,6 @@ view_update_range_and_current_page (EvView *view)
        gint current_page;
        gint best_current_page = -1;
        
-       if (view->pending_scroll != SCROLL_TO_KEEP_POSITION)
-               return;
-
        /* Presentation trumps all other modes */
        if (view->presentation) {
                view->start_page = view->current_page;
@@ -496,7 +495,7 @@ view_update_range_and_current_page (EvView *view)
        best_current_page = MAX (best_current_page, view->start_page);
        current_page = ev_page_cache_get_current_page (view->page_cache);
 
-       if (current_page != best_current_page) {
+       if ((current_page != best_current_page) && (view->pending_scroll == SCROLL_TO_KEEP_POSITION)) {
                view->current_page = best_current_page;
                ev_page_cache_set_current_page (view->page_cache, best_current_page);
        }
@@ -582,7 +581,7 @@ ev_view_scroll (EvView        *view,
 
        view->jump_to_find_result = FALSE;
 
-       if (view->presentation) {
+       if (view->presentation || view->sizing_mode == EV_SIZING_BEST_FIT) {
                switch (scroll) {
                        case EV_SCROLL_PAGE_BACKWARD:
                        case EV_SCROLL_STEP_BACKWARD:
@@ -667,7 +666,7 @@ ensure_rectangle_is_visible (EvView *view, GdkRectangle *rect)
        GtkAdjustment *adjustment;
        int value;
 
-       view->pending_scroll = SCROLL_TO_KEEP_POSITION;
+       view->pending_scroll = SCROLL_TO_FIND_LOCATION;
 
        adjustment = view->vadjustment;
 
@@ -692,6 +691,8 @@ ensure_rectangle_is_visible (EvView *view, GdkRectangle *rect)
                             widget->allocation.width + MARGIN);
                gtk_adjustment_set_value (view->hadjustment, value);
        }
+
+       gtk_widget_queue_resize (GTK_WIDGET (view));
 }
 
 /*** Geometry computations ***/
@@ -1050,6 +1051,47 @@ location_in_selected_text (EvView  *view,
        return FALSE;
 }
 
+static gboolean
+get_doc_point_from_offset (EvView *view, 
+                          gint    page, 
+                          gint    x_offset, 
+                          gint    y_offset, 
+                          gint   *x_new, 
+                          gint   *y_new)
+{
+        int width, height;
+       double x, y;
+
+        ev_page_cache_get_size (view->page_cache, page,
+                                view->rotation,
+                                1.0,
+                                &width, &height);
+
+       x_offset = x_offset / view->scale;
+       y_offset = y_offset / view->scale;
+
+        if (view->rotation == 0) {
+                x = x_offset;
+                y = y_offset;
+        } else if (view->rotation == 90) {
+                x = y_offset;
+                y = width - x_offset;
+        } else if (view->rotation == 180) {
+                x = width - x_offset;
+                y = height - y_offset;
+        } else if (view->rotation == 270) {
+                x = height - y_offset; 
+                y = x_offset;
+        } else {
+                g_assert_not_reached ();
+        }
+
+       *x_new = x;
+       *y_new = y;
+       
+       return TRUE;
+}
+
 /*** Hyperref ***/
 static EvLink *
 ev_view_get_link_at_location (EvView  *view,
@@ -1058,6 +1100,7 @@ ev_view_get_link_at_location (EvView  *view,
 {
        gint page = -1;
        gint x_offset = 0, y_offset = 0;
+       gint x_new = 0, y_new = 0;
        GList *link_mapping;
        
        x += view->scroll_x;
@@ -1068,10 +1111,15 @@ ev_view_get_link_at_location (EvView  *view,
        if (page == -1)
                return NULL;
 
+       
+       if (get_doc_point_from_offset (view, page, x_offset, 
+                                      y_offset, &x_new, &y_new) == FALSE)
+               return NULL;
+
        link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page);
 
        if (link_mapping)
-               return ev_link_mapping_find (link_mapping, x_offset / view->scale, y_offset / view->scale);
+               return ev_link_mapping_find (link_mapping, x_new, y_new);
        else
                return NULL;
 }
@@ -1080,22 +1128,20 @@ static void
 goto_fitr_dest (EvView *view, EvLinkDest *dest)
 {
        EvPoint doc_point;
-       int page;
        double zoom;
 
        zoom = zoom_for_size_best_fit (ev_link_dest_get_right (dest) - ev_link_dest_get_left (dest),
-                                      ev_link_dest_get_top (dest) - ev_link_dest_get_bottom (dest),
+                                      ev_link_dest_get_bottom (dest) - ev_link_dest_get_top (dest),
                                       ev_view_get_width (view),
                                       ev_view_get_height (view), 0, 0);
 
        ev_view_set_sizing_mode (view, EV_SIZING_FREE);
        ev_view_set_zoom (view, zoom, FALSE);
 
-       page = ev_link_dest_get_page (dest);
        doc_point.x = ev_link_dest_get_left (dest);
        doc_point.y = ev_link_dest_get_top (dest);
        
-       view->current_page = page;
+       view->current_page = ev_link_dest_get_page (dest);
        view->pending_point = doc_point;
        view->pending_scroll = SCROLL_TO_PAGE_POSITION;
 
@@ -1140,13 +1186,13 @@ goto_fith_dest (EvView *view, EvLinkDest *dest)
        ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
 
        doc_point.x = 0;
-       doc_point.y = doc_height - ev_link_dest_get_top (dest);
+       doc_point.y = ev_link_dest_get_top (dest);
 
        zoom = zoom_for_size_fit_width (doc_width, ev_link_dest_get_top (dest),
                                        ev_view_get_width (view),
                                        ev_view_get_height (view), 0);
 
-       ev_view_set_sizing_mode (view, EV_SIZING_FREE);
+       ev_view_set_sizing_mode (view, EV_SIZING_FIT_WIDTH);
        ev_view_set_zoom (view, zoom, FALSE);
 
        view->current_page = page;
@@ -1169,7 +1215,7 @@ goto_fit_dest (EvView *view, EvLinkDest *dest)
        zoom = zoom_for_size_best_fit (doc_width, doc_height, ev_view_get_width (view),
                                       ev_view_get_height (view), 0, 0);
 
-       ev_view_set_sizing_mode (view, EV_SIZING_FREE);
+       ev_view_set_sizing_mode (view, EV_SIZING_BEST_FIT);
        ev_view_set_zoom (view, zoom, FALSE);
 
        view->current_page = page;
@@ -1182,20 +1228,19 @@ static void
 goto_xyz_dest (EvView *view, EvLinkDest *dest)
 {
        EvPoint doc_point;
-       int height, page;
+       gint page;
        double zoom;
 
        zoom = ev_link_dest_get_zoom (dest);
        page = ev_link_dest_get_page (dest);
-       ev_page_cache_get_size (view->page_cache, page, 0, 1.0, NULL, &height);
 
-       if (zoom != 0) {
+       if (zoom > 1) {
                ev_view_set_sizing_mode (view, EV_SIZING_FREE);
                ev_view_set_zoom (view, zoom, FALSE);
        }
 
        doc_point.x = ev_link_dest_get_left (dest);
-       doc_point.y = height - ev_link_dest_get_top (dest);
+       doc_point.y = ev_link_dest_get_top (dest);
 
        view->current_page = page;
        view->pending_point = doc_point;
@@ -1379,10 +1424,10 @@ tip_from_link (EvView *view, EvLink *link)
                        break;
                case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
                        if (title) {
-                               msg = g_strdup_printf (_("Go to %s on file %s"), title,
+                               msg = g_strdup_printf (_("Go to %s on file ā€œ%sā€"), title,
                                                       ev_link_action_get_filename (action));
                        } else {
-                               msg = g_strdup_printf (_("Go to file %s"),
+                               msg = g_strdup_printf (_("Go to file ā€œ%sā€"),
                                                       ev_link_action_get_filename (action));
                        }
                        
@@ -1613,12 +1658,12 @@ ev_view_size_allocate (GtkWidget      *widget,
        view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
        view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
 
-       view->pending_scroll = SCROLL_TO_KEEP_POSITION;
-       view->pending_resize = FALSE;
-
        if (view->document)
                view_update_range_and_current_page (view);
 
+       view->pending_scroll = SCROLL_TO_KEEP_POSITION;
+       view->pending_resize = FALSE;
+
        GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
 }
 
@@ -1741,6 +1786,42 @@ find_selection_for_page (EvView *view,
        return NULL;
 }
 
+static void
+draw_end_presentation_page (EvView       *view,
+                           GdkRectangle *page_area)
+{
+       PangoLayout *layout;
+       PangoFontDescription *font_desc;
+       gchar *markup;
+       const gchar *text = _("End of presentation. Press Escape to exit.");
+
+       if (view->presentation_state != EV_PRESENTATION_END)
+               return;
+
+       layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), NULL);
+       markup = g_strdup_printf ("<span foreground=\"white\">%s</span>", text);
+       pango_layout_set_markup (layout, markup, -1);
+       g_free (markup);
+
+       font_desc = pango_font_description_new ();
+       pango_font_description_set_size (font_desc, 16 * PANGO_SCALE);
+       pango_layout_set_font_description (layout, font_desc);
+
+       gtk_paint_layout (GTK_WIDGET (view)->style,
+                         GTK_WIDGET (view)->window,
+                         GTK_WIDGET_STATE (view),
+                         FALSE,
+                         page_area,
+                         GTK_WIDGET (view),
+                         NULL,
+                         page_area->x + 15,
+                         page_area->y + 15,
+                         layout);
+
+       pango_font_description_free (font_desc);
+       g_object_unref (layout);
+}
+
 static gboolean
 ev_view_expose_event (GtkWidget      *widget,
                      GdkEventExpose *event)
@@ -1748,6 +1829,26 @@ ev_view_expose_event (GtkWidget      *widget,
        EvView *view = EV_VIEW (widget);
        int i;
 
+       if (view->presentation) {
+               switch (view->presentation_state) {
+                       case EV_PRESENTATION_END: {
+                               GdkRectangle area = {0};
+
+                               area.width = widget->allocation.width;
+                               area.height = widget->allocation.height;
+                               
+                               draw_end_presentation_page (view, &area);
+                       }
+                               return FALSE;
+                       case EV_PRESENTATION_BLACK:
+                       case EV_PRESENTATION_WHITE:
+                               return FALSE;
+                       case EV_PRESENTATION_NORMAL:
+                       default:
+                               break;
+               }
+       }
+       
        if (view->loading) {
                GdkRectangle area = {0};
                
@@ -2013,11 +2114,7 @@ ev_view_motion_notify_event (GtkWidget      *widget,
 
                        return TRUE;
                }
-       /* For the Evince 0.4.x release, we limit links to un-rotated documents
-        * only.
-        */
-       } else if (view->pressed_button <= 0 &&
-                  view->rotation == 0) {
+       } else if (view->pressed_button <= 0) {
                handle_link_over_xy (view, x, y);
                return TRUE;
        }
@@ -2036,7 +2133,7 @@ ev_view_button_release_event (GtkWidget      *widget,
                ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
        }
 
-       if (view->document) {
+       if (view->document && view->pressed_button == 1) {
                link = ev_view_get_link_at_location (view, event->x, event->y);
        } else {
                link = NULL;
@@ -2079,6 +2176,61 @@ ev_view_button_release_event (GtkWidget      *widget,
        return FALSE;
 }
 
+static gboolean
+ev_view_key_press_event (GtkWidget   *widget,
+                        GdkEventKey *event)
+{
+       EvView *view = EV_VIEW (widget);
+       EvPresentationState current;
+
+       if (!view->presentation ||
+           view->presentation_state == EV_PRESENTATION_END)
+               return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
+
+
+       current = view->presentation_state;
+
+       switch (event->keyval) {
+               case GDK_b:
+               case GDK_B:
+                       view->presentation_state =
+                               (view->presentation_state == EV_PRESENTATION_BLACK) ?
+                               EV_PRESENTATION_NORMAL : EV_PRESENTATION_BLACK;
+                       break;
+               case GDK_w:
+               case GDK_W:
+                       view->presentation_state =
+                               (view->presentation_state == EV_PRESENTATION_WHITE) ?
+                               EV_PRESENTATION_NORMAL : EV_PRESENTATION_WHITE;
+                       break;
+               default:
+                       if (view->presentation_state == EV_PRESENTATION_BLACK ||
+                           view->presentation_state == EV_PRESENTATION_WHITE) {
+                               view->presentation_state = EV_PRESENTATION_NORMAL;
+                       }
+       }
+
+       if (current == view->presentation_state)
+               return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
+
+       switch (view->presentation_state) {
+               case EV_PRESENTATION_NORMAL:
+               case EV_PRESENTATION_BLACK:
+                       gdk_window_set_background (widget->window,
+                                                  &widget->style->black);
+                       break;
+               case EV_PRESENTATION_WHITE:
+                       gdk_window_set_background (widget->window,
+                                                  &widget->style->white);
+                       break;
+               default:
+                       return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
+       }
+
+       gtk_widget_queue_draw (widget);
+       return TRUE;
+}
+
 static gint
 ev_view_focus_in (GtkWidget     *widget,
                  GdkEventFocus *event)
@@ -2230,8 +2382,16 @@ draw_loading_text (EvView       *view,
        double real_scale;
        int target_width;
 
+       /* Don't annoy users with loading messages during presentations.
+        * FIXME: Temporary "workaround" for
+        * http://bugzilla.gnome.org/show_bug.cgi?id=320352 */
+       if (view->presentation)
+               return;
+
        const char *loading_text = _("Loading...");     
 
+       ev_document_doc_mutex_lock ();
+       
        layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), loading_text);
 
        font_desc = pango_font_description_new ();
@@ -2262,6 +2422,8 @@ draw_loading_text (EvView       *view,
 
        pango_font_description_free (font_desc);
        g_object_unref (layout);
+
+       ev_document_doc_mutex_unlock ();
 }
 
 static void
@@ -2280,7 +2442,7 @@ draw_one_page (EvView          *view,
        gint current_page;
 
        g_assert (view->document);
-       
+
        if (! gdk_rectangle_intersect (page_area, expose_area, &overlap))
                return;
        
@@ -2409,6 +2571,7 @@ ev_view_destroy (GtkObject *object)
 
        if (view->link_tooltip) {
                gtk_widget_destroy (view->link_tooltip);
+               view->link_tooltip = NULL;
        }
 
        if (view->selection_scroll_id) {
@@ -2553,6 +2716,7 @@ ev_view_class_init (EvViewClass *class)
        widget_class->button_press_event = ev_view_button_press_event;
        widget_class->motion_notify_event = ev_view_motion_notify_event;
        widget_class->button_release_event = ev_view_button_release_event;
+       widget_class->key_press_event = ev_view_key_press_event;
        widget_class->focus_in_event = ev_view_focus_in;
        widget_class->focus_out_event = ev_view_focus_out;
        widget_class->get_accessible = ev_view_get_accessible;
@@ -2726,6 +2890,7 @@ ev_view_init (EvView *view)
        view->continuous = TRUE;
        view->dual_page = FALSE;
        view->presentation = FALSE;
+       view->presentation_state = EV_PRESENTATION_NORMAL;
        view->fullscreen = FALSE;
        view->sizing_mode = EV_SIZING_FIT_WIDTH;
        view->pending_scroll = SCROLL_TO_KEEP_POSITION;
@@ -3015,6 +3180,9 @@ ev_view_set_presentation (EvView   *view,
        if (view->presentation == presentation)
                return;
 
+       if (!presentation)
+               view->presentation_state = EV_PRESENTATION_NORMAL;
+       
        view->presentation = presentation;
        view->pending_scroll = SCROLL_TO_PAGE_POSITION;
        gtk_widget_queue_resize (GTK_WIDGET (view));
@@ -3028,7 +3196,6 @@ ev_view_set_presentation (EvView   *view,
                                                   &GTK_WIDGET (view)->style->mid [GTK_STATE_NORMAL]);
        }
 
-
        g_object_notify (G_OBJECT (view), "presentation");
 }
 
@@ -4126,27 +4293,47 @@ ev_view_show_cursor (EvView *view)
        ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
 }
 
+static void
+ev_view_reset_presentation_state (EvView *view)
+{
+       if (!view->presentation ||
+           view->presentation_state == EV_PRESENTATION_NORMAL)
+               return;
+
+       view->presentation_state = EV_PRESENTATION_NORMAL;
+       gdk_window_set_background (GTK_WIDGET (view)->window,
+                                  &GTK_WIDGET (view)->style->black);
+       gtk_widget_queue_draw (GTK_WIDGET (view));
+}
+
 gboolean
 ev_view_next_page (EvView *view)
 {
-       int page;
+       int page, n_pages;
 
        g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
        
        if (!view->page_cache)
                return FALSE;
 
+       ev_view_reset_presentation_state (view);
+       
        page = ev_page_cache_get_current_page (view->page_cache);
+       n_pages = ev_page_cache_get_n_pages (view->page_cache);
 
        if (view->dual_page && !view->presentation)
                page = page + 2; 
        else 
                page = page + 1;
 
-       if (page < ev_page_cache_get_n_pages (view->page_cache)) {
+       if (page < n_pages) {
                ev_page_cache_set_current_page (view->page_cache, page);
                return TRUE;
-       } else if (ev_view_get_dual_page (view) && page == ev_page_cache_get_n_pages (view->page_cache)) {
+       } else if (view->presentation && page == n_pages) {
+               view->presentation_state = EV_PRESENTATION_END;
+               gtk_widget_queue_draw (GTK_WIDGET (view));
+               return TRUE;
+       } else if (view->dual_page && page == n_pages) {
                ev_page_cache_set_current_page (view->page_cache, page - 1);
                return TRUE;
        } else {
@@ -4164,6 +4351,14 @@ ev_view_previous_page (EvView *view)
        if (!view->page_cache)
                return FALSE;
 
+       if (view->presentation &&
+           view->presentation_state == EV_PRESENTATION_END) {
+               ev_view_reset_presentation_state (view);
+               return TRUE;
+       }
+
+       ev_view_reset_presentation_state (view);
+
        page = ev_page_cache_get_current_page (view->page_cache);
 
        if (view->dual_page && !view->presentation)