]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-view.c
Implement launch links. Delegate external link opening to the window.
[evince.git] / shell / ev-view.c
index 78266944ac9ad6d47292a989e6d3ffa7203ea704..15bd41244edcf10215eae5d720374955b0372632 100644 (file)
@@ -60,6 +60,7 @@ enum {
 enum {
        SIGNAL_BINDING_ACTIVATED,
        SIGNAL_ZOOM_INVALID,
+       SIGNAL_EXTERNAL_LINK,
        N_SIGNALS,
 };
 
@@ -188,6 +189,8 @@ struct _EvViewClass {
                                           GtkScrollType   scroll,
                                           gboolean        horizontal);
        void    (*zoom_invalid)           (EvView         *view);
+       void    (*external_link)          (EvView         *view,
+                                          EvLink         *link);
 };
 
 /*** Scrolling ***/
@@ -264,7 +267,6 @@ static void       ev_view_size_request                       (GtkWidget
 static void       ev_view_size_allocate                      (GtkWidget          *widget,
                                                              GtkAllocation      *allocation);
 static void       ev_view_realize                            (GtkWidget          *widget);
-static void       ev_view_unrealize                          (GtkWidget          *widget);
 static gboolean   ev_view_scroll_event                       (GtkWidget          *widget,
                                                              GdkEventScroll     *event);
 static gboolean   ev_view_expose_event                       (GtkWidget          *widget,
@@ -328,6 +330,11 @@ static double   zoom_for_size_fit_width                         (int doc_width,
                                                              int target_width,
                                                              int target_height,
                                                              int vsb_width);
+static double   zoom_for_size_fit_height                    (int doc_width,
+                                                             int doc_height,
+                                                             int target_width,
+                                                             int target_height,
+                                                             int vsb_height);
 static double  zoom_for_size_best_fit                       (int doc_width,
                                                              int doc_height,
                                                              int target_width,
@@ -1073,6 +1080,18 @@ location_in_text (EvView  *view,
                return FALSE;
 }
 
+static int
+ev_view_get_width (EvView *view)
+{
+       return GTK_WIDGET (view)->allocation.width;
+}
+
+static int
+ev_view_get_height (EvView *view)
+{
+       return GTK_WIDGET (view)->allocation.height;
+}
+
 /*** Hyperref ***/
 static EvLink *
 get_link_at_location (EvView  *view,
@@ -1096,6 +1115,99 @@ get_link_at_location (EvView  *view,
                return NULL;
 }
 
+static void
+goto_fitr_link (EvView *view, EvLink *link)
+{
+       GdkPoint view_point;
+       EvPoint doc_point;
+       int doc_width, doc_height, page;
+       double zoom;
+
+       page = ev_link_get_page (link);
+       ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
+
+       doc_point.x = ev_link_get_left (link);
+       doc_point.y = ev_link_get_top (link);
+       doc_point_to_view_point (view, page, &doc_point, &view_point);
+
+       zoom = zoom_for_size_best_fit (ev_link_get_right (link) - ev_link_get_left (link),
+                                      ev_link_get_top (link) - ev_link_get_bottom (link),
+                                      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);
+       ev_page_cache_set_current_page (view->page_cache, page);
+       gtk_adjustment_set_value (view->hadjustment, view_point.x);
+}
+
+static void
+goto_fitv_link (EvView *view, EvLink *link)
+{
+       GdkPoint view_point;
+       EvPoint doc_point;
+       int doc_width, doc_height, page;
+       double zoom;
+
+       page = ev_link_get_page (link);
+       ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
+
+       doc_point.x = ev_link_get_left (link);
+       doc_point.y = 0;
+       doc_point_to_view_point (view, page, &doc_point, &view_point);
+
+       zoom = zoom_for_size_fit_height (doc_width - doc_point.x , doc_height,
+                                        ev_view_get_width (view),
+                                        ev_view_get_height (view), 0);
+
+       ev_view_set_sizing_mode (view, EV_SIZING_FREE);
+       ev_view_set_zoom (view, zoom, FALSE);
+       ev_page_cache_set_current_page (view->page_cache, page);
+       gtk_adjustment_set_value (view->hadjustment, view_point.x);
+}
+
+static void
+goto_fith_link (EvView *view, EvLink *link)
+{
+       GdkPoint view_point;
+       EvPoint doc_point;
+       int doc_width, doc_height, page;
+       double zoom;
+
+       page = ev_link_get_page (link);
+       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_get_top (link);
+       doc_point_to_view_point (view, page, &doc_point, &view_point);
+
+       zoom = zoom_for_size_fit_width (doc_width, ev_link_get_top (link),
+                                       ev_view_get_width (view),
+                                       ev_view_get_height (view), 0);
+
+       ev_view_set_sizing_mode (view, EV_SIZING_FREE);
+       ev_view_set_zoom (view, zoom, FALSE);
+       gtk_adjustment_set_value (view->vadjustment, view_point.y);
+}
+
+static void
+goto_fit_link (EvView *view, EvLink *link)
+{
+       double zoom;
+       int doc_width, doc_height;
+       int page;
+
+       page = ev_link_get_page (link);
+       ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
+
+       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_zoom (view, zoom, FALSE);
+       ev_page_cache_set_current_page (view->page_cache, page);
+}
+
 static void
 goto_xyz_link (EvView *view, EvLink *link)
 {
@@ -1125,7 +1237,6 @@ void
 ev_view_goto_link (EvView *view, EvLink *link)
 {
        EvLinkType type;
-       const char *uri;
        int page;
 
        type = ev_link_get_link_type (link);
@@ -1137,12 +1248,24 @@ ev_view_goto_link (EvView *view, EvLink *link)
                        page = ev_link_get_page (link);
                        ev_page_cache_set_current_page (view->page_cache, page);
                        break;
+               case EV_LINK_TYPE_PAGE_FIT:
+                       goto_fit_link (view, link);
+                       break;
+               case EV_LINK_TYPE_PAGE_FITH:
+                       goto_fith_link (view, link);
+                       break;
+               case EV_LINK_TYPE_PAGE_FITV:
+                       goto_fitv_link (view, link);
+                       break;
+               case EV_LINK_TYPE_PAGE_FITR:
+                       goto_fitr_link (view, link);
+                       break;
                case EV_LINK_TYPE_PAGE_XYZ:
                        goto_xyz_link (view, link);
                        break;
                case EV_LINK_TYPE_EXTERNAL_URI:
-                       uri = ev_link_get_uri (link);
-                       gnome_vfs_url_show (uri);
+               case EV_LINK_TYPE_LAUNCH:
+                       g_signal_emit (view, signals[SIGNAL_EXTERNAL_LINK], 0, link);
                        break;
        }
 }
@@ -1370,7 +1493,7 @@ ev_view_size_allocate (GtkWidget      *widget,
        EvView *view = EV_VIEW (widget);
 
        if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
-                 view->sizing_mode == EV_SIZING_BEST_FIT) {
+           view->sizing_mode == EV_SIZING_BEST_FIT) {
 
                g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0);
 
@@ -1430,39 +1553,59 @@ ev_view_realize (GtkWidget *widget)
                gdk_window_set_background (widget->window, &widget->style->mid [GTK_STATE_NORMAL]);
 }
 
-static void
-ev_view_unrealize (GtkWidget *widget)
-{
-       GTK_WIDGET_CLASS (ev_view_parent_class)->unrealize (widget);
-}
-
 static gboolean
 ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
 {
-       EvView *view = EV_VIEW (widget);
+       EvView *view = EV_VIEW (widget);
+       guint state;
+
+       state = event->state & gtk_accelerator_get_default_mod_mask ();
 
-       if ((event->state & GDK_CONTROL_MASK) != 0) {
+       if (state == GDK_CONTROL_MASK && view->presentation == FALSE) {
+               ev_view_set_sizing_mode (view, EV_SIZING_FREE);
 
-                ev_view_set_sizing_mode (view, EV_SIZING_FREE);
+               if (event->direction == GDK_SCROLL_UP ||
+                   event->direction == GDK_SCROLL_LEFT) {
+                       if (ev_view_can_zoom_in (view)) {
+                               ev_view_zoom_in (view);
+                       }
+               } else {
+                       if (ev_view_can_zoom_out (view)) {
+                               ev_view_zoom_out (view);
+                       }
+               }
 
-                if (event->direction == GDK_SCROLL_UP ||
-                       event->direction == GDK_SCROLL_LEFT) {
-                           if (ev_view_can_zoom_in (view)) {
-                                   ev_view_zoom_in (view);
-                           }
-                } else {
-                           if (ev_view_can_zoom_out (view)) {
-                                   ev_view_zoom_out (view);
-                           }
-                }
-                return TRUE;
+               return TRUE;
        }
 
-       if ((event->state & GDK_SHIFT_MASK) != 0) {
+       /* Shift+Wheel scrolls the in the perpendicular direction */
+       if (state & GDK_SHIFT_MASK) {
                if (event->direction == GDK_SCROLL_UP)
                        event->direction = GDK_SCROLL_LEFT;
+               if (event->direction == GDK_SCROLL_LEFT)
+                       event->direction = GDK_SCROLL_UP;
                if (event->direction == GDK_SCROLL_DOWN)
                        event->direction = GDK_SCROLL_RIGHT;
+               if (event->direction == GDK_SCROLL_RIGHT)
+                       event->direction = GDK_SCROLL_DOWN;
+
+               event->state &= ~GDK_SHIFT_MASK;
+               state &= ~GDK_SHIFT_MASK;
+       }
+
+       if (state == 0 && view->presentation) {
+               switch (event->direction) {
+               case GDK_SCROLL_DOWN:
+               case GDK_SCROLL_RIGHT:
+                       ev_view_next_page (view);       
+                       break;
+               case GDK_SCROLL_UP:
+               case GDK_SCROLL_LEFT:
+                       ev_view_previous_page (view);
+                       break;
+               }
+
+               return TRUE;
        }
 
        return FALSE;
@@ -1646,25 +1789,37 @@ ev_view_button_release_event (GtkWidget      *widget,
                              GdkEventButton *event)
 {
        EvView *view = EV_VIEW (widget);
+       EvLink *link;
 
        if (view->pressed_button == 2) {
                ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
        }
 
+       if (view->document) {
+               link = get_link_at_location (view, event->x + view->scroll_x,
+                                            event->y + view->scroll_y);
+       } else {
+               link = NULL;
+       }
+
        view->pressed_button = -1;
        view->drag_info.in_drag = FALSE;
 
        if (view->selection_info.selections) {
                ev_view_update_primary_selection (view);
-       } else if (view->document) {
-               EvLink *link;
-
-               link = get_link_at_location (view, event->x + view->scroll_x, event->y + view->scroll_y);
-               if (link) {
-                       ev_view_goto_link (view, link);
+       } else if (link) {
+               ev_view_goto_link (view, link);
+       } else if (view->presentation) {
+               switch (event->button) {
+               case 1:
+                       ev_view_next_page (view);       
+                       return TRUE;
+               case 3:
+                       ev_view_previous_page (view);   
+                       return TRUE;
                }
        }
-
        return FALSE;
 }
 
@@ -2098,7 +2253,6 @@ ev_view_class_init (EvViewClass *class)
        widget_class->size_request = ev_view_size_request;
        widget_class->size_allocate = ev_view_size_allocate;
        widget_class->realize = ev_view_realize;
-       widget_class->unrealize = ev_view_unrealize;
        widget_class->scroll_event = ev_view_scroll_event;
        widget_class->enter_notify_event = ev_view_enter_notify_event;
        widget_class->leave_notify_event = ev_view_leave_notify_event;
@@ -2136,6 +2290,14 @@ ev_view_class_init (EvViewClass *class)
                         NULL, NULL,
                         ev_marshal_VOID__VOID,
                         G_TYPE_NONE, 0, G_TYPE_NONE);
+       signals[SIGNAL_EXTERNAL_LINK] = g_signal_new ("external-link",
+                        G_TYPE_FROM_CLASS (object_class),
+                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                        G_STRUCT_OFFSET (EvViewClass, external_link),
+                        NULL, NULL,
+                        g_cclosure_marshal_VOID__OBJECT,
+                        G_TYPE_NONE, 1,
+                        G_TYPE_OBJECT);
 
        g_object_class_install_property (object_class,
                                         PROP_STATUS,
@@ -2647,6 +2809,23 @@ zoom_for_size_fit_width (int doc_width,
        return scale;
 }
 
+static double
+zoom_for_size_fit_height (int doc_width,
+                         int doc_height,
+                         int target_width,
+                         int target_height,
+                         int vsb_height)
+{
+       double scale;
+
+       scale = (double)target_height / doc_height;
+
+       if (doc_width * scale > target_width)
+               scale = (double) (target_height - vsb_height) / doc_height;
+
+       return scale;
+}
+
 static double
 zoom_for_size_best_fit (int doc_width,
                        int doc_height,