]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-window.c
Update context menu for internal links. Fix for the bug #325066
[evince.git] / shell / ev-window.c
index 17baf74402de94012764ea89b02b86eb670e2480..8d3601b5f6c7678495037a0ec2a87a1380ea7614 100644 (file)
@@ -114,12 +114,17 @@ struct _EvWindowPrivate {
 
        /* UI Builders */
        GtkActionGroup *action_group;
+       GtkActionGroup *popups_action_group;
        GtkUIManager *ui_manager;
 
        /* Fullscreen mode */
        GtkWidget *fullscreen_toolbar;
        GtkWidget *fullscreen_popup;
        GSource   *fullscreen_timeout_source;
+       
+       /* Popup link */
+       GtkWidget *popup;
+       EvLink    *link;
 
        /* Document */
        char *uri;
@@ -152,7 +157,6 @@ static const GtkTargetEntry ev_drop_types[] = {
 #define PAGE_SELECTOR_ACTION   "PageSelector"
 #define ZOOM_CONTROL_ACTION    "ViewZoom"
 
-#define GCONF_CHROME_TOOLBAR        "/apps/evince/show_toolbar"
 #define GCONF_OVERRIDE_RESTRICTIONS "/apps/evince/override_restrictions"
 #define GCONF_LOCKDOWN_SAVE         "/desktop/gnome/lockdown/disable_save_to_disk"
 #define GCONF_LOCKDOWN_PRINT        "/desktop/gnome/lockdown/disable_printing"
@@ -192,6 +196,10 @@ static void     ev_window_stop_presentation             (EvWindow         *windo
 static void     ev_window_cmd_view_presentation         (GtkAction        *action,
                                                         EvWindow         *window);
 static void     show_fullscreen_popup                   (EvWindow         *window);
+static void     ev_popup_cmd_open_link                  (GtkAction        *action,
+                                                        EvWindow         *window);
+static void     ev_popup_cmd_copy_link_address          (GtkAction        *action,
+                                                        EvWindow         *window);
 
 
 G_DEFINE_TYPE (EvWindow, ev_window, GTK_TYPE_WINDOW)
@@ -219,6 +227,8 @@ update_action_sensitivity (EvWindow *ev_window)
        gboolean ok_to_copy = TRUE;
        gboolean has_properties = TRUE;
        gboolean override_restrictions = FALSE;
+       gboolean can_get_text = FALSE;
+       gboolean ok_to_copy_text = FALSE;
        GConfClient *client;
 
        view = EV_VIEW (ev_window->priv->view);
@@ -263,6 +273,11 @@ update_action_sensitivity (EvWindow *ev_window)
        
        g_object_unref (client);
 
+       if (has_document && ev_document_can_get_text (document)) {
+               can_get_text = TRUE;
+               ok_to_copy_text = ev_view_get_has_selection (view);
+       }
+       
        /* File menu */
        /* "FileOpen": always sensitive */
        set_action_sensitive (ev_window, "FileSaveAs", has_document && ok_to_copy);
@@ -272,8 +287,8 @@ update_action_sensitivity (EvWindow *ev_window)
 
         /* Edit menu */
        sensitive = has_pages && ev_document_can_get_text (document);
-       set_action_sensitive (ev_window, "EditCopy", sensitive && ok_to_copy);
-       set_action_sensitive (ev_window, "EditSelectAll", sensitive && ok_to_copy);
+       set_action_sensitive (ev_window, "EditCopy", sensitive && ok_to_copy_text);
+       set_action_sensitive (ev_window, "EditSelectAll", sensitive && can_get_text);
        set_action_sensitive (ev_window, "EditFind",
                              has_pages && EV_IS_DOCUMENT_FIND (document));
        set_action_sensitive (ev_window, "Slash",
@@ -375,24 +390,16 @@ update_chrome_visibility (EvWindow *window)
 }
 
 static void
-update_chrome_flag (EvWindow *window, EvChrome flag, const char *pref, gboolean active)
+update_chrome_flag (EvWindow *window, EvChrome flag, gboolean active)
 {
        EvWindowPrivate *priv = window->priv;
-       GConfClient *client;
        
        if (active) {
                priv->chrome |= flag;
-       }
-       else {
+       } else {
                priv->chrome &= ~flag;
        }
 
-       if (pref != NULL) {
-               client = gconf_client_get_default ();
-               gconf_client_set_bool (client, pref, active, NULL);
-               g_object_unref (client);
-       }
-
        update_chrome_visibility (window);
 }
 
@@ -401,7 +408,7 @@ ev_window_cmd_focus_page_selector (GtkAction *act, EvWindow *window)
 {
        GtkAction *action;
        
-       update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, NULL, TRUE);
+       update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, TRUE);
        set_action_sensitive (window, "ViewToolbar", FALSE);
        
        action = gtk_action_group_get_action (window->priv->action_group,
@@ -610,7 +617,7 @@ update_sidebar_visibility (EvWindow *window)
        char *uri = window->priv->uri;
        GValue sidebar_visibility = { 0, };
 
-       if (uri && ev_metadata_manager_get (uri, "sidebar_visibility", &sidebar_visibility)) {
+       if (uri && ev_metadata_manager_get (uri, "sidebar_visibility", &sidebar_visibility, TRUE)) {
                set_widget_visibility (window->priv->sidebar,
                                       g_value_get_boolean (&sidebar_visibility));
        }
@@ -623,12 +630,26 @@ setup_document_from_metadata (EvWindow *window)
        GValue page = { 0, };
 
        /* Page */
-       if (uri && ev_metadata_manager_get (uri, "page", &page)) {
+       if (uri && ev_metadata_manager_get (uri, "page", &page, TRUE)) {
                ev_page_cache_set_current_page (window->priv->page_cache,
                                                g_value_get_int (&page));
        }
 }
 
+static void
+setup_chrome_from_metadata (EvWindow *window)
+{
+       EvChrome chrome = EV_CHROME_NORMAL;
+       GValue show_toolbar = { 0, };
+
+       if (ev_metadata_manager_get (NULL, "show_toolbar", &show_toolbar, FALSE)) {
+               if (!g_value_get_boolean (&show_toolbar))
+                       chrome &= ~EV_CHROME_TOOLBAR;
+       }
+       window->priv->chrome = chrome;
+}
+
+
 static void
 setup_sidebar_from_metadata (EvWindow *window, EvDocument *document)
 {
@@ -639,12 +660,12 @@ setup_sidebar_from_metadata (EvWindow *window, EvDocument *document)
        GValue sidebar_size = { 0, };
        GValue sidebar_page = { 0, };
 
-       if (ev_metadata_manager_get (uri, "sidebar_size", &sidebar_size)) {
+       if (ev_metadata_manager_get (uri, "sidebar_size", &sidebar_size, FALSE)) {
                gtk_paned_set_position (GTK_PANED (window->priv->hpaned),
                                        g_value_get_int (&sidebar_size));
        }
 
-       if (ev_metadata_manager_get (uri, "sidebar_page", &sidebar_page)) {
+       if (ev_metadata_manager_get (uri, "sidebar_page", &sidebar_page, FALSE)) {
                const char *page_id = g_value_get_string (&sidebar_page);
 
                if (strcmp (page_id, "links") == 0) {
@@ -691,8 +712,8 @@ ev_window_setup_document (EvWindow *ev_window)
                ev_view_set_document (view, document);
        }
 
-       ev_window_title_set_uri (ev_window->priv->title, ev_window->priv->uri);
        ev_window_title_set_document (ev_window->priv->title, document);
+       ev_window_title_set_uri (ev_window->priv->title, ev_window->priv->uri);
        action = gtk_action_group_get_action (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
        ev_page_action_set_document (EV_PAGE_ACTION (action), document);
        update_action_sensitivity (ev_window);
@@ -945,15 +966,11 @@ setup_view_from_metadata (EvWindow *window)
        GValue fullscreen = { 0, };
        GValue rotation = { 0, };
 
-       if (window->priv->uri == NULL) {
-               return;
-       }
-
        /* Window size */
        if (!GTK_WIDGET_VISIBLE (window)) {
                gboolean restore_size = TRUE;
 
-               if (ev_metadata_manager_get (uri, "window_maximized", &maximized)) {
+               if (ev_metadata_manager_get (uri, "window_maximized", &maximized, TRUE)) {
                        if (g_value_get_boolean (&maximized)) {
                                gtk_window_maximize (GTK_WINDOW (window));
                                restore_size = FALSE;
@@ -961,20 +978,22 @@ setup_view_from_metadata (EvWindow *window)
                }
 
                if (restore_size &&
-                   ev_metadata_manager_get (uri, "window_x", &x) &&
-                   ev_metadata_manager_get (uri, "window_y", &y) &&
-                   ev_metadata_manager_get (uri, "window_width", &width) &&
-                   ev_metadata_manager_get (uri, "window_height", &height)) {
+                   ev_metadata_manager_get (uri, "window_width", &width, TRUE) &&
+                   ev_metadata_manager_get (uri, "window_height", &height, TRUE)) {
                        gtk_window_set_default_size (GTK_WINDOW (window),
                                                     g_value_get_int (&width),
                                                     g_value_get_int (&height));
+               }
+               if (restore_size &&
+                   ev_metadata_manager_get (uri, "window_x", &x, TRUE) &&
+                   ev_metadata_manager_get (uri, "window_y", &y, TRUE)) {
                        gtk_window_move (GTK_WINDOW (window), g_value_get_int (&x),
                                         g_value_get_int (&y));
                }
        }
 
        /* Sizing mode */
-       if (ev_metadata_manager_get (uri, "sizing_mode", &sizing_mode)) {
+       if (ev_metadata_manager_get (uri, "sizing_mode", &sizing_mode, FALSE)) {
                enum_value = g_enum_get_value_by_nick
                        (EV_SIZING_MODE_CLASS, g_value_get_string (&sizing_mode));
                g_value_unset (&sizing_mode);
@@ -982,37 +1001,37 @@ setup_view_from_metadata (EvWindow *window)
        }
 
        /* Zoom */
-       if (ev_metadata_manager_get (uri, "zoom", &zoom) &&
+       if (ev_metadata_manager_get (uri, "zoom", &zoom, FALSE) &&
            ev_view_get_sizing_mode (view) == EV_SIZING_FREE) {
                ev_view_set_zoom (view, g_value_get_double (&zoom), FALSE);
        }
 
        /* Continuous */
-       if (ev_metadata_manager_get (uri, "continuous", &continuous)) {
+       if (ev_metadata_manager_get (uri, "continuous", &continuous, FALSE)) {
                ev_view_set_continuous (view, g_value_get_boolean (&continuous));
        }
 
        /* Dual page */
-       if (ev_metadata_manager_get (uri, "dual-page", &dual_page)) {
+       if (ev_metadata_manager_get (uri, "dual-page", &dual_page, FALSE)) {
                ev_view_set_dual_page (view, g_value_get_boolean (&dual_page));
        }
 
        /* Presentation */
-       if (ev_metadata_manager_get (uri, "presentation", &presentation)) {
+       if (ev_metadata_manager_get (uri, "presentation", &presentation, FALSE)) {
                if (g_value_get_boolean (&presentation)) {
                        ev_window_run_presentation (window);
                }
        }
 
        /* Fullscreen */
-       if (ev_metadata_manager_get (uri, "fullscreen", &fullscreen)) {
+       if (ev_metadata_manager_get (uri, "fullscreen", &fullscreen, FALSE)) {
                if (g_value_get_boolean (&fullscreen)) {
                        ev_window_run_fullscreen (window);
                }
        }
 
        /* Rotation */
-       if (ev_metadata_manager_get (uri, "rotation", &rotation)) {
+       if (ev_metadata_manager_get (uri, "rotation", &rotation, TRUE)) {
                if (g_value_get_int (&rotation)) {
                        switch (g_value_get_int (&rotation)) {
                        case 90:
@@ -1539,7 +1558,7 @@ ev_window_cmd_edit_find (GtkAction *action, EvWindow *ev_window)
        } else if (!EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
                find_not_supported_dialog (ev_window);
        } else {
-               update_chrome_flag (ev_window, EV_CHROME_FINDBAR, NULL, TRUE);
+               update_chrome_flag (ev_window, EV_CHROME_FINDBAR, TRUE);
 
                gtk_widget_grab_focus (ev_window->priv->find_bar);
        }
@@ -2240,7 +2259,7 @@ ev_window_cmd_escape (GtkAction *action, EvWindow *window)
 
        widget = gtk_window_get_focus (GTK_WINDOW (window));
        if (widget && gtk_widget_get_ancestor (widget, EGG_TYPE_FIND_BAR)) {
-               update_chrome_flag (window, EV_CHROME_FINDBAR, NULL, FALSE);
+               update_chrome_flag (window, EV_CHROME_FINDBAR, FALSE);
                gtk_widget_grab_focus (window->priv->view);
        } else {
                gboolean fullscreen;
@@ -2345,15 +2364,6 @@ ev_window_sizing_mode_changed_cb (EvView *view, GParamSpec *pspec,
                                  G_CALLBACK (update_view_size),
                                  ev_window);
                break;
-       case EV_SIZING_FIT_HEIGHT:
-               g_object_set (G_OBJECT (scrolled_window),
-                             "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
-                             "vscrollbar-policy", GTK_POLICY_NEVER,
-                             NULL);
-               g_signal_connect (ev_window->priv->view, "zoom_invalid",
-                                 G_CALLBACK (update_view_size),
-                                 ev_window);
-               break;
        case EV_SIZING_FREE:
                g_object_set (G_OBJECT (scrolled_window),
                              "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
@@ -2432,6 +2442,12 @@ ev_window_rotation_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *window
                                       rotation);
 }
 
+static void
+ev_window_has_selection_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *window)
+{
+       update_action_sensitivity (window);
+}
+
 static void     
 ev_window_dual_mode_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *ev_window)
 {
@@ -2538,9 +2554,11 @@ ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
 static void
 ev_window_view_toolbar_cb (GtkAction *action, EvWindow *ev_window)
 {
-       update_chrome_flag (ev_window, EV_CHROME_TOOLBAR,
-                           GCONF_CHROME_TOOLBAR,
-                           gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
+       gboolean active;
+       
+       active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+       update_chrome_flag (ev_window, EV_CHROME_TOOLBAR, active);
+       ev_metadata_manager_set_boolean (NULL, "show_toolbar", active);
 }
 
 static void
@@ -2591,12 +2609,68 @@ ev_window_sidebar_visibility_changed_cb (EvSidebar *ev_sidebar, GParamSpec *pspe
        g_signal_handlers_unblock_by_func
                (action, G_CALLBACK (ev_window_view_sidebar_cb), ev_window);
 
-       if (!ev_view_get_presentation (view) && !ev_view_get_fullscreen (view)) {
+       if (!ev_view_get_presentation (view) && 
+           !ev_view_get_fullscreen (view)) {
                ev_metadata_manager_set_boolean (ev_window->priv->uri, "sidebar_visibility",
                                                 GTK_WIDGET_VISIBLE (ev_sidebar));
        }
 }
 
+static gboolean
+view_menu_popup_cb (EvView         *view,
+                   EvLink         *link,
+                   EvWindow       *ev_window)
+{
+       GtkWidget *popup;
+       gboolean   show_external = FALSE;
+       gboolean   show_internal = FALSE;
+       GtkAction *action;
+       
+       if (ev_window->priv->link)
+               g_object_unref (ev_window->priv->link);
+       if (link)
+               ev_window->priv->link = g_object_ref (link);
+       else    
+               ev_window->priv->link = NULL;
+
+       popup = ev_window->priv->popup;
+
+       if (ev_window->priv->link) 
+               switch (ev_link_get_link_type (ev_window->priv->link)) {
+                       case EV_LINK_TYPE_PAGE:
+                       case EV_LINK_TYPE_PAGE_FIT:
+                       case EV_LINK_TYPE_PAGE_FITH:
+                       case EV_LINK_TYPE_PAGE_FITV:
+                       case EV_LINK_TYPE_PAGE_FITR:
+                       case EV_LINK_TYPE_PAGE_XYZ:
+                               show_internal = TRUE;
+                               break;
+                       case EV_LINK_TYPE_EXTERNAL_URI:
+                       case EV_LINK_TYPE_LAUNCH:       
+                               show_external = TRUE;
+                               break;
+                       default:
+                               break;
+               }
+       
+       action = gtk_action_group_get_action (ev_window->priv->popups_action_group,
+                                             "OpenLink");
+       gtk_action_set_visible (action, show_external);
+
+       action = gtk_action_group_get_action (ev_window->priv->popups_action_group,
+                                             "CopyLinkAddress");
+       gtk_action_set_visible (action, show_external);
+
+       action = gtk_action_group_get_action (ev_window->priv->popups_action_group,
+                                             "GoLink");
+       gtk_action_set_visible (action, show_internal);
+
+       gtk_menu_popup (GTK_MENU (popup), NULL, NULL,
+                       NULL, NULL,
+                       3, gtk_get_current_event_time ());
+       return TRUE;
+}
+
 static void
 view_find_status_changed_cb (EvView     *view,
                             GParamSpec *pspec,
@@ -2627,7 +2701,7 @@ static void
 find_bar_close_cb (EggFindBar *find_bar,
                   EvWindow   *ev_window)
 {
-       update_chrome_flag (ev_window, EV_CHROME_FINDBAR, NULL, FALSE);
+       update_chrome_flag (ev_window, EV_CHROME_FINDBAR, FALSE);
 }
 
 static void
@@ -2712,7 +2786,6 @@ ev_window_finalize (GObject *object)
                g_list_free (windows);
        }
        
-       g_list_free (windows);
        G_OBJECT_CLASS (ev_window_parent_class)->finalize (object);
 }
 
@@ -2742,6 +2815,11 @@ ev_window_dispose (GObject *object)
                priv->action_group = NULL;
        }
 
+       if (priv->popups_action_group) {
+               g_object_unref (priv->popups_action_group);
+               priv->popups_action_group = NULL;
+       }
+
        if (priv->page_cache) {
                g_signal_handlers_disconnect_by_func (priv->page_cache, page_changed_cb, window);
                priv->page_cache = NULL;
@@ -2784,6 +2862,11 @@ ev_window_dispose (GObject *object)
                gtk_widget_destroy (priv->password_dialog);
        }
 
+       if (priv->link) {
+               g_object_unref (priv->link);
+               priv->link = NULL;
+       }
+
        if (priv->find_bar) {
                g_signal_handlers_disconnect_by_func
                        (window->priv->find_bar,
@@ -2835,7 +2918,8 @@ static const GtkActionEntry entries[] = {
        { "FileOpen", GTK_STOCK_OPEN, N_("_Open..."), "<control>O",
          N_("Open an existing document"),
          G_CALLBACK (ev_window_cmd_file_open) },
-               { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("_Save a Copy..."), NULL, NULL,
+               { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("_Save a Copy..."), "<control>S",
+         N_("Save a copy of the current document"),
          G_CALLBACK (ev_window_cmd_save_as) },
        { "FilePrint", GTK_STOCK_PRINT, N_("_Print..."), "<control>P",
          N_("Print this document"),
@@ -2916,10 +3000,16 @@ static const GtkActionEntry entries[] = {
           G_CALLBACK (ev_window_cmd_scroll_backward) },
         { "ShiftBackSpace", NULL, "", "<shift>BackSpace", NULL,
           G_CALLBACK (ev_window_cmd_scroll_forward) },
+        { "Return", NULL, "", "Return", NULL,
+          G_CALLBACK (ev_window_cmd_scroll_forward) },
+        { "ShiftReturn", NULL, "", "<shift>Return", NULL,
+          G_CALLBACK (ev_window_cmd_scroll_backward) },
         { "Plus", GTK_STOCK_ZOOM_IN, NULL, "plus", NULL,
           G_CALLBACK (ev_window_cmd_view_zoom_in) },
         { "CtrlEqual", GTK_STOCK_ZOOM_IN, NULL, "<control>equal", NULL,
           G_CALLBACK (ev_window_cmd_view_zoom_in) },
+        { "Equal", GTK_STOCK_ZOOM_IN, NULL, "equal", NULL,
+          G_CALLBACK (ev_window_cmd_view_zoom_in) },
         { "Minus", GTK_STOCK_ZOOM_OUT, NULL, "minus", NULL,
           G_CALLBACK (ev_window_cmd_view_zoom_out) },
         { "FocusPageSelector", NULL, "", "<control>l", NULL,
@@ -2932,6 +3022,10 @@ static const GtkActionEntry entries[] = {
           G_CALLBACK (ev_window_cmd_view_zoom_in) },
         { "KpMinus", GTK_STOCK_ZOOM_OUT, NULL, "KP_Subtract", NULL,
           G_CALLBACK (ev_window_cmd_view_zoom_out) },
+        { "CtrlKpPlus", GTK_STOCK_ZOOM_IN, NULL, "<control>KP_Add", NULL,
+          G_CALLBACK (ev_window_cmd_view_zoom_in) },
+        { "CtrlKpMinus", GTK_STOCK_ZOOM_OUT, NULL, "<control>KP_Subtract", NULL,
+          G_CALLBACK (ev_window_cmd_view_zoom_out) },
 };
 
 /* Toggle items */
@@ -2963,6 +3057,18 @@ static const GtkToggleActionEntry toggle_entries[] = {
           G_CALLBACK (ev_window_cmd_view_page_width) },
 };
 
+/* Popups specific items */
+static const GtkActionEntry popups_entries [] = {
+       /* Links */
+       { "OpenLink", GTK_STOCK_OPEN, N_("_Open Link"), NULL,
+         NULL, G_CALLBACK (ev_popup_cmd_open_link) },
+       { "GoLink", GTK_STOCK_GO_FORWARD, N_("_Go To"), NULL,
+         NULL, G_CALLBACK (ev_popup_cmd_open_link) },
+       { "CopyLinkAddress", NULL, N_("_Copy Link Address"), NULL,
+         NULL,
+         G_CALLBACK (ev_popup_cmd_copy_link_address) },
+};
+
 static void
 drag_data_received_cb (GtkWidget *widget, GdkDragContext *context,
                       gint x, gint y, GtkSelectionData *selection_data,
@@ -3097,28 +3203,6 @@ set_chrome_actions (EvWindow *window)
                (action, G_CALLBACK (ev_window_view_toolbar_cb), window);
 }
 
-static EvChrome
-load_chrome (void)
-{
-       EvChrome chrome = EV_CHROME_NORMAL;
-       GConfClient *client;
-       GConfValue *value;
-
-       client = gconf_client_get_default ();
-
-       value = gconf_client_get (client, GCONF_CHROME_TOOLBAR, NULL);
-       if (value != NULL) {
-               if (value->type == GCONF_VALUE_BOOL && !gconf_value_get_bool (value)) {
-                       chrome &= ~EV_CHROME_TOOLBAR;
-               }
-               gconf_value_free (value);
-       }
-
-       g_object_unref (client);
-
-       return chrome;
-}
-
 static void
 sidebar_widget_model_set (EvSidebarLinks *ev_sidebar_links,
                          GParamSpec     *pspec,
@@ -3147,18 +3231,21 @@ ev_window_set_view_accels_sensitivity (EvWindow *window, gboolean sensitive)
                set_action_sensitive (window, "ShiftSpace", sensitive);
                set_action_sensitive (window, "BackSpace", sensitive);
                set_action_sensitive (window, "ShiftBackSpace", sensitive);
+               set_action_sensitive (window, "Return", sensitive);
+               set_action_sensitive (window, "ShiftReturn", sensitive);
                set_action_sensitive (window, "Slash", sensitive);
                set_action_sensitive (window, "Plus", sensitive);
                set_action_sensitive (window, "Minus", sensitive);
                set_action_sensitive (window, "KpPlus", sensitive);
                set_action_sensitive (window, "KpMinus", sensitive);
+               set_action_sensitive (window, "Equal", sensitive);
        }
 }
 
 static gboolean
 view_actions_focus_in_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *window)
 {
-       update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, NULL, FALSE);
+       update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, FALSE);
        set_action_sensitive (window, "ViewToolbar", TRUE);
 
        ev_window_set_view_accels_sensitivity (window, TRUE);
@@ -3237,6 +3324,87 @@ sidebar_links_link_activated_cb (EvSidebarLinks *sidebar_links, EvLink *link, Ev
        ev_view_goto_link (EV_VIEW (window->priv->view), link);
 }
 
+static void
+launch_link (EvWindow *window, EvLink *link)
+{
+       const char *filename = ev_link_get_filename (link);
+       char *uri = NULL;
+
+       if (filename  && g_path_is_absolute (filename)) {
+               uri = gnome_vfs_get_uri_from_local_path (filename);
+       } else {
+               GnomeVFSURI *base_uri, *resolved_uri;
+
+               base_uri = gnome_vfs_uri_new (window->priv->uri);
+               if (base_uri && filename) {
+                       resolved_uri = gnome_vfs_uri_resolve_relative (base_uri, filename);     
+                       if (resolved_uri) {
+                               uri = gnome_vfs_uri_to_string (resolved_uri, GNOME_VFS_URI_HIDE_NONE);
+                               gnome_vfs_uri_unref (resolved_uri);
+                       }
+                       gnome_vfs_uri_unref (base_uri);
+               }
+       }
+
+       if (uri) {
+               gnome_vfs_url_show (uri);
+       } else {
+               gnome_vfs_url_show (filename);
+       }
+
+       g_free (uri);
+
+       /* According to the PDF spec filename can be an executable. I'm not sure
+          allowing to launch executables is a good idea though. -- marco */
+}
+
+static void
+launch_external_uri (EvWindow *window, EvLink *link)
+{
+       const char *uri;
+       char *escaped;
+
+       uri = ev_link_get_uri (link);
+       escaped = gnome_vfs_escape_host_and_path_string (uri);
+
+       gnome_vfs_url_show (escaped);
+       g_free (escaped);
+}
+
+static void
+view_external_link_cb (EvView *view, EvLink *link, EvWindow *window)
+{
+       switch (ev_link_get_link_type (link)) {
+       case EV_LINK_TYPE_EXTERNAL_URI:
+               launch_external_uri (window, link);
+               break;
+       case EV_LINK_TYPE_LAUNCH:
+               launch_link (window, link);
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+}
+
+static void
+ev_popup_cmd_open_link (GtkAction *action, EvWindow *window)
+{
+       ev_view_goto_link (EV_VIEW (window->priv->view), window->priv->link);
+}
+
+static void
+ev_popup_cmd_copy_link_address (GtkAction *action, EvWindow *window)
+{
+       GtkClipboard *clipboard;
+       const gchar *uri;
+
+       uri = ev_link_get_uri (window->priv->link);
+
+       clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window),
+                                             GDK_SELECTION_CLIPBOARD);
+       gtk_clipboard_set_text (clipboard, uri, -1);
+}
+
 static void
 ev_window_init (EvWindow *ev_window)
 {
@@ -3280,6 +3448,14 @@ ev_window_init (EvWindow *ev_window)
 
        ev_window_set_view_accels_sensitivity (ev_window, FALSE);
 
+       action_group = gtk_action_group_new ("PopupsActions");
+       ev_window->priv->popups_action_group = action_group;
+       gtk_action_group_set_translation_domain (action_group, NULL);
+       gtk_action_group_add_actions (action_group, popups_entries,
+                                     G_N_ELEMENTS (popups_entries), ev_window);
+       gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
+                                           action_group, 0);
+
        if (!gtk_ui_manager_add_ui_from_file (ev_window->priv->ui_manager,
                                              DATADIR"/evince-ui.xml",
                                              &error)) {
@@ -3377,9 +3553,20 @@ ev_window_init (EvWindow *ev_window)
        g_signal_connect_object (ev_window->priv->view, "focus_out_event",
                                 G_CALLBACK (view_actions_focus_out_cb),
                                 ev_window, 0);
+       g_signal_connect_object (ev_window->priv->view, "external-link",
+                                G_CALLBACK (view_external_link_cb),
+                                ev_window, 0);
+       g_signal_connect_object (ev_window->priv->view,
+                                "popup",
+                                G_CALLBACK (view_menu_popup_cb),
+                                ev_window, 0);
        gtk_widget_show (ev_window->priv->view);
        gtk_widget_show (ev_window->priv->password_view);
 
+       ev_window->priv->find_bar = egg_find_bar_new ();
+       gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
+                         ev_window->priv->find_bar,
+                         FALSE, TRUE, 0);
 
        /* We own a ref on these widgets, as we can swap them in and out */
        g_object_ref (ev_window->priv->view);
@@ -3413,18 +3600,12 @@ ev_window_init (EvWindow *ev_window)
                          "notify::rotation",
                          G_CALLBACK (ev_window_rotation_changed_cb),
                          ev_window);
+       g_signal_connect (ev_window->priv->view,
+                         "notify::has-selection",
+                         G_CALLBACK (ev_window_has_selection_changed_cb),
+                         ev_window);
 
-       ev_window->priv->find_bar = egg_find_bar_new ();
-       gtk_box_pack_end (GTK_BOX (ev_window->priv->main_box),
-                         ev_window->priv->find_bar,
-                         FALSE, TRUE, 0);
-
-       ev_window_setup_recent (ev_window);
-       ev_window->priv->chrome = load_chrome ();
-       set_chrome_actions (ev_window);
-       update_chrome_visibility (ev_window);
-
-       /* Connect sidebar signals */
+       /* Connect sidebar signals */
        g_signal_connect (ev_window->priv->sidebar,
                          "notify::visible",
                          G_CALLBACK (ev_window_sidebar_visibility_changed_cb),
@@ -3460,6 +3641,11 @@ ev_window_init (EvWindow *ev_window)
                          G_CALLBACK (find_bar_search_changed_cb),
                          ev_window);
 
+       /* Popups */
+       ev_window->priv->popup = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
+                                                          "/DocumentPopup");
+       ev_window->priv->link = NULL;
+
        /* Give focus to the document view */
        gtk_widget_grab_focus (ev_window->priv->view);
 
@@ -3471,7 +3657,16 @@ ev_window_init (EvWindow *ev_window)
        g_signal_connect (G_OBJECT (ev_window), "drag_data_received",
                          G_CALLBACK (drag_data_received_cb), NULL);
 
-       /* Set it to something random to force a change */
+       /* Set it user interface params */
+
+       ev_window_setup_recent (ev_window);
+       setup_chrome_from_metadata (ev_window);
+       set_chrome_actions (ev_window);
+       update_chrome_visibility (ev_window);
+
+       gtk_window_set_default_size (GTK_WINDOW (ev_window),
+                                    600, 600);
+       setup_view_from_metadata (ev_window);
 
         ev_window_sizing_mode_changed_cb (EV_VIEW (ev_window->priv->view), NULL, ev_window);
        update_action_sensitivity (ev_window);
@@ -3484,8 +3679,6 @@ ev_window_new (void)
 
        ev_window = GTK_WIDGET (g_object_new (EV_TYPE_WINDOW,
                                              "type", GTK_WINDOW_TOPLEVEL,
-                                             "default-width", 600,
-                                             "default-height", 600,
                                              NULL));
 
        return ev_window;