]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-window.c
Updated list of documenters in about dialog
[evince.git] / shell / ev-window.c
index b7c4bd2dd25ed48eba67cc788c0877487172c5d1..9ef85aab2d7051d56b362c5ebb27c0b5808597ad 100644 (file)
@@ -75,6 +75,7 @@
 #include "ev-properties-dialog.h"
 #include "ev-sidebar-annotations.h"
 #include "ev-sidebar-attachments.h"
+#include "ev-sidebar-bookmarks.h"
 #include "ev-sidebar.h"
 #include "ev-sidebar-links.h"
 #include "ev-sidebar-page.h"
@@ -91,6 +92,8 @@
 #include "ev-print-operation.h"
 #include "ev-progress-message-area.h"
 #include "ev-annotation-properties-dialog.h"
+#include "ev-bookmarks.h"
+#include "ev-bookmark-action.h"
 
 #ifdef ENABLE_DBUS
 #include "ev-media-player-keys.h"
@@ -138,6 +141,7 @@ struct _EvWindowPrivate {
        GtkWidget *sidebar_attachments;
        GtkWidget *sidebar_layers;
        GtkWidget *sidebar_annots;
+       GtkWidget *sidebar_bookmarks;
 
        /* Settings */
        GSettings *settings;
@@ -163,6 +167,8 @@ struct _EvWindowPrivate {
        GtkRecentManager *recent_manager;
        GtkActionGroup   *recent_action_group;
        guint             recent_ui_id;
+       GtkActionGroup   *bookmarks_action_group;
+       guint             bookmarks_ui_id;
        GtkUIManager     *ui_manager;
 
        /* Fullscreen mode */
@@ -192,6 +198,7 @@ struct _EvWindowPrivate {
        EvWindowPageMode page_mode;
        EvWindowTitle *title;
        EvMetadata *metadata;
+       EvBookmarks *bookmarks;
        gboolean is_new_doc;
 
        /* Load params */
@@ -246,6 +253,7 @@ struct _EvWindowPrivate {
 #define ATTACHMENTS_SIDEBAR_ID "attachments"
 #define LAYERS_SIDEBAR_ID "layers"
 #define ANNOTS_SIDEBAR_ID "annotations"
+#define BOOKMARKS_SIDEBAR_ID "bookmarks"
 
 #define EV_PRINT_SETTINGS_FILE  "print-settings"
 #define EV_PRINT_SETTINGS_GROUP "Print Settings"
@@ -335,6 +343,8 @@ static void     ev_window_cmd_edit_find                 (GtkAction        *actio
 static void     find_bar_search_changed_cb              (EggFindBar       *find_bar,
                                                         GParamSpec       *param,
                                                         EvWindow         *ev_window);
+static void     view_external_link_cb                   (EvWindow         *window,
+                                                        EvLinkAction     *action);
 static void     ev_window_load_file_remote              (EvWindow         *ev_window,
                                                         GFile            *source_file);
 static void     ev_window_media_player_key_pressed      (EvWindow         *window,
@@ -345,6 +355,7 @@ static void     ev_window_update_max_min_scale          (EvWindow         *windo
 static void    ev_window_emit_closed                   (EvWindow         *window);
 static void    ev_window_emit_doc_loaded               (EvWindow         *window);
 #endif
+static void     ev_window_setup_bookmarks               (EvWindow         *window);
 
 static guint ev_window_n_copies = 0;
 
@@ -431,6 +442,7 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window)
        ev_window_set_action_sensitive (ev_window, "FileSaveAs", has_document && ok_to_copy);
        ev_window_set_action_sensitive (ev_window, "FilePrint", has_pages && ok_to_print);
        ev_window_set_action_sensitive (ev_window, "FileProperties", has_document && has_properties);
+       ev_window_set_action_sensitive (ev_window, "FileOpenContainingFolder", has_document);
 
         /* Edit menu */
        ev_window_set_action_sensitive (ev_window, "EditSelectAll", has_pages && can_get_text);
@@ -448,6 +460,10 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window)
        ev_window_set_action_sensitive (ev_window, "ViewAutoscroll", has_pages);
        ev_window_set_action_sensitive (ev_window, "ViewInvertedColors", has_pages);
 
+       /* Bookmarks menu */
+       ev_window_set_action_sensitive (ev_window, "BookmarksAdd",
+                                       has_pages && ev_window->priv->bookmarks);
+
        /* Toolbar-specific actions: */
        ev_window_set_action_sensitive (ev_window, PAGE_SELECTOR_ACTION, has_pages);
        ev_window_set_action_sensitive (ev_window, ZOOM_CONTROL_ACTION,  has_pages);
@@ -784,18 +800,17 @@ ev_window_warning_message (EvWindow    *window,
        ev_window_set_message_area (window, area);
 }
 
-typedef struct _FindTask {
+typedef struct _PageTitleData {
        const gchar *page_label;
-       gchar *chapter;
-} FindTask;
+       gchar       *page_title;
+} PageTitleData;
 
 static gboolean
-ev_window_find_chapter (GtkTreeModel *tree_model,
-                       GtkTreePath  *path,
-                       GtkTreeIter  *iter,
-                       gpointer      data)
+ev_window_find_page_title (GtkTreeModel  *tree_model,
+                          GtkTreePath   *path,
+                          GtkTreeIter   *iter,
+                          PageTitleData *data)
 {
-       FindTask *task = (FindTask *)data;
        gchar *page_string;
        
        gtk_tree_model_get (tree_model, iter,
@@ -805,9 +820,9 @@ ev_window_find_chapter (GtkTreeModel *tree_model,
        if (!page_string)
                return FALSE;
        
-       if (!strcmp (page_string, task->page_label)) {
+       if (!strcmp (page_string, data->page_label)) {
                gtk_tree_model_get (tree_model, iter,
-                                   EV_DOCUMENT_LINKS_COLUMN_MARKUP, &task->chapter
+                                   EV_DOCUMENT_LINKS_COLUMN_MARKUP, &data->page_title
                                    -1);
                g_free (page_string);
                return TRUE;
@@ -817,12 +832,41 @@ ev_window_find_chapter (GtkTreeModel *tree_model,
        return FALSE;
 }
 
+static gchar *
+ev_window_get_page_title (EvWindow    *window,
+                         const gchar *page_label)
+{
+       if (EV_IS_DOCUMENT_LINKS (window->priv->document) &&
+           ev_document_links_has_document_links (EV_DOCUMENT_LINKS (window->priv->document))) {
+               PageTitleData data;
+               GtkTreeModel *model;
+
+               data.page_label = page_label;
+               data.page_title = NULL;
+
+               g_object_get (G_OBJECT (window->priv->sidebar_links),
+                             "model", &model,
+                             NULL);
+               if (model) {
+                       gtk_tree_model_foreach (model,
+                                               (GtkTreeModelForeachFunc)ev_window_find_page_title,
+                                               &data);
+
+                       g_object_unref (model);
+               }
+
+               return data.page_title;
+       }
+
+       return NULL;
+}
+
 static void
 ev_window_add_history (EvWindow *window, gint page, EvLink *link)
 {
        gchar *page_label = NULL;
+       gchar *page_title;
        gchar *link_title;
-       FindTask find_task;
        EvLink *real_link;
        EvLinkAction *action;
        EvLinkDest *dest;
@@ -845,34 +889,19 @@ ev_window_add_history (EvWindow *window, gint page, EvLink *link)
 
        if (!page_label)
                return;
-       
-       find_task.page_label = page_label;
-       find_task.chapter = NULL;
-       
-       if (ev_document_links_has_document_links (EV_DOCUMENT_LINKS (window->priv->document))) {
-               GtkTreeModel *model;
-       
-               g_object_get (G_OBJECT (window->priv->sidebar_links), "model", &model, NULL);
-               
-               if (model) {
-                       gtk_tree_model_foreach (model,
-                                               ev_window_find_chapter,
-                                               &find_task);
-       
-                       g_object_unref (model);
-               }
-       }
 
-       if (find_task.chapter)
-               link_title = g_strdup_printf (_("Page %s — %s"), page_label, find_task.chapter);
-       else
+       page_title = ev_window_get_page_title (window, page_label);
+       if (page_title) {
+               link_title = g_strdup_printf (_("Page %s — %s"), page_label, page_title);
+               g_free (page_title);
+       } else {
                link_title = g_strdup_printf (_("Page %s"), page_label);
-       
+       }
+
        real_link = ev_link_new (link_title, action);
        
        ev_history_add_link (window->priv->history, real_link);
 
-       g_free (find_task.chapter);
        g_free (link_title);
        g_free (page_label);
        g_object_unref (real_link);
@@ -941,6 +970,8 @@ ev_window_sidebar_get_current_page_id (EvWindow *ev_window)
                id = LAYERS_SIDEBAR_ID;
        } else if (current_page == ev_window->priv->sidebar_annots) {
                id = ANNOTS_SIDEBAR_ID;
+       } else if (current_page == ev_window->priv->sidebar_bookmarks) {
+               id = BOOKMARKS_SIDEBAR_ID;
        } else {
                g_assert_not_reached();
        }
@@ -961,6 +992,7 @@ ev_window_sidebar_set_current_page (EvWindow    *window,
        GtkWidget  *attachments = window->priv->sidebar_attachments;
        GtkWidget  *annots = window->priv->sidebar_annots;
        GtkWidget  *layers = window->priv->sidebar_layers;
+       GtkWidget  *bookmarks = window->priv->sidebar_bookmarks;
 
        if (strcmp (page_id, LINKS_SIDEBAR_ID) == 0 &&
            ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) {
@@ -977,6 +1009,9 @@ ev_window_sidebar_set_current_page (EvWindow    *window,
        } else if (strcmp (page_id, ANNOTS_SIDEBAR_ID) == 0 &&
                   ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (annots), document)) {
                ev_sidebar_set_page (sidebar, annots);
+       } else if (strcmp (page_id, BOOKMARKS_SIDEBAR_ID) == 0 &&
+                  ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (bookmarks), document)) {
+               ev_sidebar_set_page (sidebar, bookmarks);
        }
 }
 
@@ -1432,8 +1467,15 @@ ev_window_set_document (EvWindow *ev_window, EvDocument *document)
        }
 
        if (EV_WINDOW_IS_PRESENTATION (ev_window)) {
+               gint current_page;
+
+               current_page = ev_view_presentation_get_current_page (
+                       EV_VIEW_PRESENTATION (ev_window->priv->presentation_view));
                gtk_widget_destroy (ev_window->priv->presentation_view);
                ev_window->priv->presentation_view = NULL;
+
+               /* Update the model with the current presentation page */
+               ev_document_model_set_page (ev_window->priv->model, current_page);
                ev_window_run_presentation (ev_window);
        }
 
@@ -2008,6 +2050,8 @@ ev_window_open_uri (EvWindow       *ev_window,
 
        if (ev_window->priv->metadata)
                g_object_unref (ev_window->priv->metadata);
+       if (ev_window->priv->bookmarks)
+               g_object_unref (ev_window->priv->bookmarks);
 
        source_file = g_file_new_for_uri (uri);
        if (!ev_file_is_temp (source_file) && ev_is_metadata_supported_for_file (source_file)) {
@@ -2017,6 +2061,17 @@ ev_window_open_uri (EvWindow       *ev_window,
                ev_window->priv->metadata = NULL;
        }
 
+       if (ev_window->priv->metadata) {
+               ev_window->priv->bookmarks = ev_bookmarks_new (ev_window->priv->metadata);
+               ev_sidebar_bookmarks_set_bookmarks (EV_SIDEBAR_BOOKMARKS (ev_window->priv->sidebar_bookmarks),
+                                                   ev_window->priv->bookmarks);
+               g_signal_connect_swapped (ev_window->priv->bookmarks, "changed",
+                                         G_CALLBACK (ev_window_setup_bookmarks),
+                                         ev_window);
+       } else {
+               ev_window->priv->bookmarks = NULL;
+       }
+
        if (ev_window->priv->search_string)
                g_free (ev_window->priv->search_string);
        ev_window->priv->search_string = search_string ?
@@ -2028,6 +2083,7 @@ ev_window_open_uri (EvWindow       *ev_window,
 
        setup_size_from_metadata (ev_window);
        setup_model_from_metadata (ev_window);
+       ev_window_setup_bookmarks (ev_window);
 
        ev_window->priv->load_job = ev_job_load_new (uri);
        g_signal_connect (ev_window->priv->load_job,
@@ -3798,22 +3854,19 @@ fullscreen_toolbar_setup_item_properties (GtkUIManager *ui_manager)
 static void
 fullscreen_toolbar_remove_shadow (GtkWidget *toolbar)
 {
-       static gboolean done = FALSE;
+       GtkCssProvider *provider;
 
-       if (!done) {
-               gtk_rc_parse_string (
-                       "\n"
-                       "   style \"fullscreen-toolbar-style\"\n"
-                       "   {\n"
-                       "      GtkToolbar::shadow-type=GTK_SHADOW_NONE\n"
-                       "   }\n"
-                       "\n"
-                       "    widget \"*.fullscreen-toolbar\" style \"fullscreen-toolbar-style\"\n"
-                       "\n");
-               done = TRUE;
-       }
-       
-       gtk_widget_set_name (toolbar, "fullscreen-toolbar");
+       gtk_widget_set_name (toolbar, "ev-fullscreen-toolbar");
+
+       provider = gtk_css_provider_new ();
+       gtk_css_provider_load_from_data (provider,
+                                        "#ev-fullscreen-toolbar {\n"
+                                        " -GtkToolbar-shadow-type: none; }",
+                                        -1, NULL);
+       gtk_style_context_add_provider (gtk_widget_get_style_context (toolbar),
+                                       GTK_STYLE_PROVIDER (provider),
+                                       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+       g_object_unref (provider);
 }
 
 static void
@@ -3923,6 +3976,22 @@ ev_window_view_presentation_finished (EvWindow *window)
        ev_window_stop_presentation (window, TRUE);
 }
 
+static gboolean
+ev_window_view_presentation_focus_in (EvWindow *window)
+{
+       ev_application_screensaver_disable (EV_APP);
+
+       return FALSE;
+}
+
+static gboolean
+ev_window_view_presentation_focus_out (EvWindow *window)
+{
+       ev_application_screensaver_enable (EV_APP);
+
+       return FALSE;
+}
+
 static void
 ev_window_run_presentation (EvWindow *window)
 {
@@ -3949,6 +4018,15 @@ ev_window_run_presentation (EvWindow *window)
        g_signal_connect_swapped (window->priv->presentation_view, "finished",
                                  G_CALLBACK (ev_window_view_presentation_finished),
                                  window);
+       g_signal_connect_swapped (window->priv->presentation_view, "external-link",
+                                 G_CALLBACK (view_external_link_cb),
+                                 window);
+       g_signal_connect_swapped (window->priv->presentation_view, "focus-in-event",
+                                 G_CALLBACK (ev_window_view_presentation_focus_in),
+                                 window);
+       g_signal_connect_swapped (window->priv->presentation_view, "focus-out-event",
+                                 G_CALLBACK (ev_window_view_presentation_focus_out),
+                                 window);
 
        gtk_box_pack_start (GTK_BOX (window->priv->main_box),
                            window->priv->presentation_view,
@@ -3975,12 +4053,15 @@ ev_window_stop_presentation (EvWindow *window,
                             gboolean  unfullscreen_window)
 {
        guint current_page;
+       guint rotation;
 
        if (!EV_WINDOW_IS_PRESENTATION (window))
                return;
 
        current_page = ev_view_presentation_get_current_page (EV_VIEW_PRESENTATION (window->priv->presentation_view));
        ev_document_model_set_page (window->priv->model, current_page);
+       rotation = ev_view_presentation_get_rotation (EV_VIEW_PRESENTATION (window->priv->presentation_view));
+       ev_document_model_set_rotation (window->priv->model, rotation);
 
        gtk_container_remove (GTK_CONTAINER (window->priv->main_box),
                              window->priv->presentation_view);
@@ -4152,17 +4233,33 @@ ev_window_set_page_mode (EvWindow         *window,
 static void
 ev_window_cmd_edit_rotate_left (GtkAction *action, EvWindow *ev_window)
 {
-       gint rotation = ev_document_model_get_rotation (ev_window->priv->model);
+       gint rotation;
+
+       if (EV_WINDOW_IS_PRESENTATION (ev_window)) {
+               rotation = ev_view_presentation_get_rotation (EV_VIEW_PRESENTATION (ev_window->priv->presentation_view));
+               ev_view_presentation_set_rotation (EV_VIEW_PRESENTATION (ev_window->priv->presentation_view),
+                                                  rotation - 90);
+       } else {
+               rotation = ev_document_model_get_rotation (ev_window->priv->model);
 
-       ev_document_model_set_rotation (ev_window->priv->model, rotation - 90);
+               ev_document_model_set_rotation (ev_window->priv->model, rotation - 90);
+       }
 }
 
 static void
 ev_window_cmd_edit_rotate_right (GtkAction *action, EvWindow *ev_window)
 {
-       gint rotation = ev_document_model_get_rotation (ev_window->priv->model);
+       gint rotation;
+
+       if (EV_WINDOW_IS_PRESENTATION (ev_window)) {
+               rotation = ev_view_presentation_get_rotation (EV_VIEW_PRESENTATION (ev_window->priv->presentation_view));
+               ev_view_presentation_set_rotation (EV_VIEW_PRESENTATION (ev_window->priv->presentation_view),
+                                                  rotation + 90);
+       } else {
+               rotation = ev_document_model_get_rotation (ev_window->priv->model);
 
-       ev_document_model_set_rotation (ev_window->priv->model, rotation + 90);
+               ev_document_model_set_rotation (ev_window->priv->model, rotation + 90);
+       }
 }
 
 static void
@@ -4211,9 +4308,6 @@ ev_window_cmd_edit_toolbar (GtkAction *action, EvWindow *ev_window)
        gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
        gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)), 5);
        gtk_box_set_spacing (GTK_BOX (content_area), 2);
-#if !GTK_CHECK_VERSION (2, 90, 7)
-       gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
-#endif
        gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 400);
 
        toolbar = EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar);
@@ -4223,7 +4317,7 @@ ev_window_cmd_edit_toolbar (GtkAction *action, EvWindow *ev_window)
        gtk_container_set_border_width (GTK_CONTAINER (editor), 5);
        gtk_box_set_spacing (GTK_BOX (EGG_TOOLBAR_EDITOR (editor)), 5);
 
-       gtk_container_add (GTK_CONTAINER (content_area), editor);
+        gtk_box_pack_start (GTK_BOX (content_area), editor, TRUE, TRUE, 0);
 
        egg_editable_toolbar_set_edit_mode (toolbar, TRUE);
 
@@ -4341,6 +4435,92 @@ ev_window_cmd_go_backward (GtkAction *action, EvWindow *ev_window)
        }
 }
 
+static void
+ev_window_cmd_bookmark_activate (GtkAction *action,
+                                EvWindow  *window)
+{
+       guint page = ev_bookmark_action_get_page (EV_BOOKMARK_ACTION (action));
+
+       ev_document_model_set_page (window->priv->model, page);
+}
+
+static gint
+compare_bookmarks (EvBookmark *a,
+                  EvBookmark *b)
+{
+       return strcmp (a->title, b->title);
+}
+
+static void
+ev_window_setup_bookmarks (EvWindow *window)
+{
+       GList *items, *l;
+
+       if (!window->priv->bookmarks)
+               return;
+
+       if (window->priv->bookmarks_ui_id > 0) {
+               gtk_ui_manager_remove_ui (window->priv->ui_manager,
+                                         window->priv->bookmarks_ui_id);
+               gtk_ui_manager_ensure_update (window->priv->ui_manager);
+       }
+       window->priv->bookmarks_ui_id = gtk_ui_manager_new_merge_id (window->priv->ui_manager);
+
+       if (window->priv->bookmarks_action_group) {
+               gtk_ui_manager_remove_action_group (window->priv->ui_manager,
+                                                   window->priv->bookmarks_action_group);
+               g_object_unref (window->priv->bookmarks_action_group);
+       }
+       window->priv->bookmarks_action_group = gtk_action_group_new ("BookmarksActions");
+       gtk_ui_manager_insert_action_group (window->priv->ui_manager,
+                                           window->priv->bookmarks_action_group, -1);
+
+       items = ev_bookmarks_get_bookmarks (window->priv->bookmarks);
+       items = g_list_sort (items, (GCompareFunc)compare_bookmarks);
+
+       for (l = items; l && l->data; l = g_list_next (l)) {
+               EvBookmark *bm = (EvBookmark *)l->data;
+               GtkAction  *action;
+
+               action = ev_bookmark_action_new (bm);
+               g_signal_connect (action, "activate",
+                                 G_CALLBACK (ev_window_cmd_bookmark_activate),
+                                 window);
+               gtk_action_group_add_action (window->priv->bookmarks_action_group,
+                                            action);
+
+               gtk_ui_manager_add_ui (window->priv->ui_manager,
+                                      window->priv->bookmarks_ui_id,
+                                      "/MainMenu/BookmarksMenu/BookmarksItems",
+                                      gtk_action_get_label (action),
+                                      gtk_action_get_name (action),
+                                      GTK_UI_MANAGER_MENUITEM,
+                                      FALSE);
+
+               g_object_unref (action);
+       }
+
+       g_list_free (items);
+}
+
+static void
+ev_window_cmd_bookmarks_add (GtkAction *action,
+                            EvWindow  *window)
+{
+       EvBookmark bm;
+       gchar     *page_label;
+       gchar     *page_title;
+
+       bm.page = ev_document_model_get_page (window->priv->model);
+       page_label = ev_document_get_page_label (window->priv->document, bm.page);
+       page_title = ev_window_get_page_title (window, page_label);
+       bm.title = page_title ? page_title : g_strdup_printf (_("Page %s"), page_label);
+       g_free (page_label);
+
+       /* EvBookmarks takes ownership of bookmark */
+       ev_bookmarks_add (window->priv->bookmarks, &bm);
+}
+
 static void
 ev_window_cmd_view_reload (GtkAction *action, EvWindow *ev_window)
 {
@@ -4609,6 +4789,8 @@ ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
 
        const char *documenters[] = {
                "Nickolay V. Shmyrev <nshmyrev@yandex.ru>",
+               "Phil Bull <philbull@gmail.com>",
+               "Tiffany Antpolski <tiffany.antopolski@gmail.com>",
                NULL
        };
 
@@ -4649,7 +4831,7 @@ ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
                "name", _("Evince"),
                "version", VERSION,
                "copyright",
-               _("© 1996–2009 The Evince authors"),
+               _("© 1996–2010 The Evince authors"),
                "license", license_trans,
                "website", "http://www.gnome.org/projects/evince",
                "comments", comments,
@@ -4716,6 +4898,8 @@ ev_window_sidebar_visibility_changed_cb (EvSidebar  *ev_sidebar,
                if (ev_window->priv->metadata)
                        ev_metadata_set_boolean (ev_window->priv->metadata, "sidebar_visibility",
                                                 visible);
+               if (!visible)
+                       gtk_widget_grab_focus (ev_window->priv->view);
        }
 }
 
@@ -5175,6 +5359,11 @@ ev_window_dispose (GObject *object)
        }
 #endif /* ENABLE_DBUS */
 
+       if (priv->bookmarks) {
+               g_object_unref (priv->bookmarks);
+               priv->bookmarks = NULL;
+       }
+
        if (priv->metadata) {
                g_object_unref (priv->metadata);
                priv->metadata = NULL;
@@ -5220,6 +5409,11 @@ ev_window_dispose (GObject *object)
                priv->recent_action_group = NULL;
        }
 
+       if (priv->bookmarks_action_group) {
+               g_object_unref (priv->bookmarks_action_group);
+               priv->bookmarks_action_group = NULL;
+       }
+
        if (priv->recent_manager) {
                g_signal_handlers_disconnect_by_func (priv->recent_manager,
                                                      ev_window_setup_recent,
@@ -5449,6 +5643,7 @@ static const GtkActionEntry entries[] = {
         { "Edit", NULL, N_("_Edit") },
        { "View", NULL, N_("_View") },
         { "Go", NULL, N_("_Go") },
+       { "Bookmarks", NULL, N_("_Bookmarks") },
        { "Help", NULL, N_("_Help") },
 
        /* File menu */
@@ -5522,6 +5717,11 @@ static const GtkActionEntry entries[] = {
           N_("Go to the last page"),
           G_CALLBACK (ev_window_cmd_go_last_page) },
 
+       /* Bookmarks menu */
+       { "BookmarksAdd", GTK_STOCK_ADD, N_("_Add Bookmark"), "<control>D",
+         N_("Add a bookmark for the current page"),
+         G_CALLBACK (ev_window_cmd_bookmarks_add) },
+
        /* Help menu */
        { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1", NULL,
          G_CALLBACK (ev_window_cmd_help_contents) },
@@ -5709,6 +5909,13 @@ sidebar_annots_annot_add_cancelled (EvSidebarAnnotations *sidebar_annots,
        ev_view_cancel_add_annotation (EV_VIEW (window->priv->view));
 }
 
+static void
+sidebar_bookmarks_add_bookmark (EvSidebarBookmarks *sidebar_bookmarks,
+                               EvWindow           *window)
+{
+       ev_window_cmd_bookmarks_add (NULL, window);
+}
+
 static void
 register_custom_actions (EvWindow *window, GtkActionGroup *group)
 {
@@ -6080,7 +6287,7 @@ do_action_named (EvWindow *window, EvLinkAction *action)
 }
 
 static void
-view_external_link_cb (EvView *view, EvLinkAction *action, EvWindow *window)
+view_external_link_cb (EvWindow *window, EvLinkAction *action)
 {
        switch (ev_link_action_get_action_type (action)) {
                case EV_LINK_ACTION_TYPE_GOTO_DEST: {
@@ -6146,6 +6353,30 @@ ev_view_popup_cmd_copy_link_address (GtkAction *action, EvWindow *window)
                                   ev_action);
 }
 
+static GFile *
+create_file_from_uri_for_format (const gchar     *uri,
+                                GdkPixbufFormat *format)
+{
+       GFile  *target_file;
+       gchar **extensions;
+       gchar  *uri_extension;
+       gint    i;
+
+       extensions = gdk_pixbuf_format_get_extensions (format);
+       for (i = 0; extensions[i]; i++) {
+               if (g_str_has_suffix (uri, extensions[i])) {
+                       g_strfreev (extensions);
+                       return g_file_new_for_uri (uri);
+               }
+       }
+
+       uri_extension = g_strconcat (uri, ".", extensions[0], NULL);
+       target_file = g_file_new_for_uri (uri_extension);
+       g_free (uri_extension);
+       g_strfreev (extensions);
+
+       return target_file;
+}
 
 static void
 image_save_dialog_response_cb (GtkWidget *fc,
@@ -6157,7 +6388,6 @@ image_save_dialog_response_cb (GtkWidget *fc,
        GError          *error = NULL;
        GdkPixbuf       *pixbuf;
        gchar           *uri;
-       gchar          **extensions;
        gchar           *filename;
        gchar           *file_format;
        GdkPixbufFormat *format;
@@ -6195,19 +6425,9 @@ image_save_dialog_response_cb (GtkWidget *fc,
                return;
        }
 
-       extensions = gdk_pixbuf_format_get_extensions (format);
-       if (!g_str_has_suffix (uri, extensions[0])) {
-               gchar *uri_extension;
-               
-               uri_extension = g_strconcat (uri, ".", extensions[0], NULL);
-               target_file = g_file_new_for_uri (uri_extension);
-               g_free (uri_extension);
-       } else {
-               target_file = g_file_new_for_uri (uri);
-       }
-       g_strfreev (extensions);
+       target_file = create_file_from_uri_for_format (uri, format);
        g_free (uri);
-       
+
        is_native = g_file_is_native (target_file);
        if (is_native) {
                filename = g_file_get_path (target_file);
@@ -6535,9 +6755,15 @@ ev_window_media_player_key_pressed (EvWindow    *window,
        if (strcmp (key, "Play") == 0) {
                ev_window_run_presentation (window);
        } else if (strcmp (key, "Previous") == 0) {
-               ev_window_cmd_go_previous_page (NULL, window);
+               if (EV_WINDOW_IS_PRESENTATION (window))
+                       ev_view_presentation_previous_page (EV_VIEW_PRESENTATION (window->priv->presentation_view));
+               else
+                       ev_window_cmd_go_previous_page (NULL, window);
        } else if (strcmp (key, "Next") == 0) {
-               ev_window_cmd_go_next_page (NULL, window);
+               if (EV_WINDOW_IS_PRESENTATION (window))
+                       ev_view_presentation_next_page (EV_VIEW_PRESENTATION (window->priv->presentation_view));
+               else
+                       ev_window_cmd_go_next_page (NULL, window);
        } else if (strcmp (key, "FastForward") == 0) {
                ev_window_cmd_go_last_page (NULL, window);
        } else if (strcmp (key, "Rewind") == 0) {
@@ -6598,6 +6824,9 @@ ev_window_sync_source (EvWindow     *window,
 {
        GDBusConnection *connection;
        GError          *error = NULL;
+       guint32          timestamp;
+       gchar           *uri_input;
+       GFile           *input_gfile;
 
        if (window->priv->dbus_object_id <= 0)
                return;
@@ -6606,16 +6835,41 @@ ev_window_sync_source (EvWindow     *window,
        if (!connection)
                return;
 
+       timestamp = gtk_get_current_event_time ();
+       if (g_path_is_absolute (link->filename)) {
+               input_gfile = g_file_new_for_path (link->filename);
+       } else {
+               GFile *gfile, *parent_gfile;
+
+               gfile = g_file_new_for_uri (window->priv->uri);
+               parent_gfile = g_file_get_parent (gfile);
+
+               /* parent_gfile should never be NULL */
+               if (parent_gfile == NULL) {
+                       g_printerr ("Document URI is '/'\n");
+                       return;
+               }
+
+               input_gfile = g_file_get_child (parent_gfile, link->filename);
+               g_object_unref (parent_gfile);
+               g_object_unref (gfile);
+       }
+
+       uri_input = g_file_get_uri (input_gfile);
+       g_object_unref (input_gfile);
+
        g_dbus_connection_emit_signal (connection,
                                       NULL,
                                       window->priv->dbus_object_path,
                                       EV_WINDOW_DBUS_INTERFACE,
                                       "SyncSource",
-                                      g_variant_new ("(s(ii))",
-                                                     link->filename,
+                                      g_variant_new ("(s(ii)u)",
+                                                     uri_input,
                                                      link->line,
-                                                     link->col),
+                                                     link->col,
+                                                     timestamp),
                                       &error);
+       g_free (uri_input);
        if (error) {
                g_printerr ("Failed to emit DBus signal SyncSource: %s\n",
                            error->message);
@@ -6725,6 +6979,7 @@ static const char introspection_xml[] =
            "<signal name='SyncSource'>"
              "<arg type='s' name='source_file' direction='out'/>"
              "<arg type='(ii)' name='source_point' direction='out'/>"
+             "<arg type='u' name='timestamp' direction='out'/>"
            "</signal>"
             "<signal name='Closed'/>"
            "<signal name='DocumentLoaded'>"
@@ -6882,6 +7137,10 @@ ev_window_init (EvWindow *ev_window)
                               NULL));
        g_object_unref (toolbars_model);
 
+       gtk_style_context_add_class
+               (gtk_widget_get_style_context (GTK_WIDGET (ev_window->priv->toolbar)),
+                GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
+
        egg_editable_toolbar_show (EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar),
                                   "DefaultToolBar");
        gtk_box_pack_start (GTK_BOX (ev_window->priv->main_box),
@@ -6890,7 +7149,7 @@ ev_window_init (EvWindow *ev_window)
        gtk_widget_show (ev_window->priv->toolbar);
 
        /* Add the main area */
-       ev_window->priv->hpaned = gtk_hpaned_new ();
+       ev_window->priv->hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
        g_signal_connect (ev_window->priv->hpaned,
                          "notify::position",
                          G_CALLBACK (ev_window_sidebar_position_change_cb),
@@ -6974,6 +7233,16 @@ ev_window_init (EvWindow *ev_window)
        ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
                             sidebar_widget);
 
+       sidebar_widget = ev_sidebar_bookmarks_new ();
+       ev_window->priv->sidebar_bookmarks = sidebar_widget;
+       g_signal_connect (sidebar_widget,
+                         "add-bookmark",
+                         G_CALLBACK (sidebar_bookmarks_add_bookmark),
+                         ev_window);
+       gtk_widget_show (sidebar_widget);
+       ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
+                            sidebar_widget);
+
        ev_window->priv->view_box = gtk_vbox_new (FALSE, 0);
        ev_window->priv->scrolled_window =
                GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
@@ -7003,9 +7272,9 @@ 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_swapped (ev_window->priv->view, "external-link",
+                                 G_CALLBACK (view_external_link_cb),
+                                 ev_window);
        g_signal_connect_object (ev_window->priv->view, "handle-link",
                                 G_CALLBACK (view_handle_link_cb),
                                 ev_window, 0);