]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-window.c
[shell] dualscreen yay alpha works
[evince.git] / shell / ev-window.c
index 2d69097069cee0eb1489f7dafe323074bfbaadf5..d76fddc1486dc34ea3276892190e98cd97d904cf 100644 (file)
 #include "ephy-zoom.h"
 
 #include "ev-application.h"
+#include "ev-dualscreen.h"
 #include "ev-document-factory.h"
 #include "ev-document-find.h"
 #include "ev-document-fonts.h"
 #include "ev-document-images.h"
 #include "ev-document-links.h"
-#include "ev-document-thumbnails.h"
 #include "ev-document-annotations.h"
 #include "ev-document-type-builtins.h"
 #include "ev-document-misc.h"
@@ -76,6 +76,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"
@@ -92,6 +93,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"
@@ -139,6 +142,7 @@ struct _EvWindowPrivate {
        GtkWidget *sidebar_attachments;
        GtkWidget *sidebar_layers;
        GtkWidget *sidebar_annots;
+       GtkWidget *sidebar_bookmarks;
 
        /* Settings */
        GSettings *settings;
@@ -164,6 +168,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 */
@@ -193,6 +199,7 @@ struct _EvWindowPrivate {
        EvWindowPageMode page_mode;
        EvWindowTitle *title;
        EvMetadata *metadata;
+       EvBookmarks *bookmarks;
        gboolean is_new_doc;
 
        /* Load params */
@@ -247,6 +254,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"
@@ -302,9 +310,9 @@ static void     ev_window_stop_fullscreen               (EvWindow         *windo
                                                         gboolean          unfullscreen_window);
 static void     ev_window_cmd_view_fullscreen           (GtkAction        *action,
                                                         EvWindow         *window);
-static void     ev_window_run_presentation              (EvWindow         *window);
-static void     ev_window_stop_presentation             (EvWindow         *window,
-                                                        gboolean          unfullscreen_window);
+static void     ev_window_run_presentation_wrapper      (EvWindow        *window);
+static void     ev_window_stop_presentation_wrapper     (EvWindow        *window,
+                                                        gboolean          unfullscreen_window);
 static void     ev_window_cmd_view_presentation         (GtkAction        *action,
                                                         EvWindow         *window);
 static void     ev_view_popup_cmd_open_link             (GtkAction        *action,
@@ -336,6 +344,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,
@@ -344,7 +354,9 @@ static void     ev_window_media_player_key_pressed      (EvWindow         *windo
 static void     ev_window_update_max_min_scale          (EvWindow         *window);
 #ifdef ENABLE_DBUS
 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;
 
@@ -359,6 +371,12 @@ get_screen_dpi (EvWindow *window)
        return ev_document_misc_get_screen_dpi (screen);
 }
 
+static gboolean
+ev_window_is_editing_toolbar (EvWindow *ev_window)
+{
+       return egg_editable_toolbar_get_edit_mode (EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar));
+}
+
 static void
 ev_window_set_action_sensitive (EvWindow   *ev_window,
                                const char *name,
@@ -431,6 +449,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);
@@ -440,6 +459,7 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window)
        ev_window_set_action_sensitive (ev_window, "EditRotateRight", has_pages);
 
         /* View menu */
+       ev_window_set_action_sensitive (ev_window, "ViewToolbar", !ev_window_is_editing_toolbar (ev_window));
        ev_window_set_action_sensitive (ev_window, "ViewContinuous", has_pages);
        ev_window_set_action_sensitive (ev_window, "ViewDual", has_pages);
        ev_window_set_action_sensitive (ev_window, "ViewBestFit", has_pages);
@@ -448,6 +468,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 +808,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 +828,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 +840,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 +897,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);
@@ -895,6 +932,13 @@ view_selection_changed_cb (EvView   *view,
                                        ev_view_get_has_selection (view));
 }
 
+static void
+view_layers_changed_cb (EvView   *view,
+                       EvWindow *window)
+{
+       ev_sidebar_layers_update_layers_state (EV_SIDEBAR_LAYERS (window->priv->sidebar_layers));
+}
+
 static void
 ev_window_page_changed_cb (EvWindow        *ev_window,
                           gint             old_page,
@@ -934,6 +978,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();
        }
@@ -954,6 +1000,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)) {
@@ -970,6 +1017,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);
        }
 }
 
@@ -977,7 +1027,7 @@ static void
 update_document_mode (EvWindow *window, EvDocumentMode mode)
 {
        if (mode == EV_DOCUMENT_MODE_PRESENTATION) {
-               ev_window_run_presentation (window);
+               ev_window_run_presentation_wrapper (window);
        }
        else if (mode == EV_DOCUMENT_MODE_FULL_SCREEN) {
                ev_window_run_fullscreen (window);
@@ -1268,7 +1318,7 @@ setup_view_from_metadata (EvWindow *window)
        /* Presentation */
        if (ev_metadata_get_boolean (window->priv->metadata, "presentation", &presentation)) {
                if (presentation) {
-                       ev_window_run_presentation (window);
+                       ev_window_run_presentation_wrapper (window);
                }
        }
 }
@@ -1310,8 +1360,7 @@ ev_window_refresh_window_thumbnail (EvWindow *ev_window)
        gint rotation;
        EvDocument *document = ev_window->priv->document;
 
-       if (!EV_IS_DOCUMENT_THUMBNAILS (document) ||
-           ev_document_get_n_pages (document) <= 0 ||
+       if (ev_document_get_n_pages (document) <= 0 ||
            !ev_document_check_dimensions (document)) {
                return;
        }
@@ -1426,9 +1475,16 @@ 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;
-               ev_window_run_presentation (ev_window);
+
+               /* Update the model with the current presentation page */
+               ev_document_model_set_page (ev_window->priv->model, current_page);
+               ev_window_run_presentation_wrapper (ev_window);
        }
 
        if (ev_window->priv->setup_document_idle > 0)
@@ -1531,6 +1587,9 @@ ev_window_load_job_cb (EvJob *job,
        if (!ev_job_is_failed (job)) {
                ev_document_model_set_document (ev_window->priv->model, document);
 
+#ifdef ENABLE_DBUS
+               ev_window_emit_doc_loaded (ev_window);
+#endif
                setup_chrome_from_metadata (ev_window);
                update_chrome_actions (ev_window);
                setup_document_from_metadata (ev_window);
@@ -1562,7 +1621,7 @@ ev_window_load_job_cb (EvJob *job,
                                ev_window_run_fullscreen (ev_window);
                                break;
                        case EV_WINDOW_MODE_PRESENTATION:
-                               ev_window_run_presentation (ev_window);
+                               ev_window_run_presentation_wrapper (ev_window);
                                break;
                        default:
                                break;
@@ -1999,6 +2058,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)) {
@@ -2008,6 +2069,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 ?
@@ -2019,6 +2091,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,
@@ -2085,7 +2158,7 @@ ev_window_open_document (EvWindow       *ev_window,
                ev_window_run_fullscreen (ev_window);
                break;
        case EV_WINDOW_MODE_PRESENTATION:
-               ev_window_run_presentation (ev_window);
+               ev_window_run_presentation_wrapper (ev_window);
                break;
        default:
                break;
@@ -2864,6 +2937,48 @@ ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
        gtk_widget_show (fc);
 }
 
+static void
+ev_window_cmd_open_containing_folder (GtkAction *action, EvWindow *ev_window)
+{
+       GtkWidget *ev_window_widget;
+       GFile *file;
+       GFile *parent;
+
+       ev_window_widget = GTK_WIDGET (ev_window);
+
+       file = g_file_new_for_uri (ev_window->priv->uri);
+       parent = g_file_get_parent (file);
+
+       if (parent) {
+               char *parent_uri;
+
+               parent_uri = g_file_get_uri (parent);
+               if (parent_uri) {
+                       GdkScreen *screen;
+                       guint32 timestamp;
+                       GError *error;
+
+                       screen = gtk_widget_get_screen (ev_window_widget);
+                       timestamp = gtk_get_current_event_time ();
+
+                       error = NULL;
+                       if (!gtk_show_uri (screen, parent_uri, timestamp, &error)) {
+                               ev_window_error_message (ev_window, error, _("Could not open the containing folder"));
+                               g_error_free (error);
+                       }
+
+                       g_free (parent_uri);
+               }
+       }
+
+       if (file)
+               g_object_unref (file);
+
+       if (parent)
+               g_object_unref (parent);
+       
+}
+
 static GKeyFile *
 get_print_settings_file (void)
 {
@@ -3366,6 +3481,91 @@ ev_window_cmd_file_properties (GtkAction *action, EvWindow *ev_window)
        ev_document_fc_mutex_unlock ();
 }
 
+static void
+document_modified_confirmation_dialog_response (GtkDialog *dialog,
+                                               gint       response,
+                                               EvWindow  *ev_window)
+{
+       gtk_widget_destroy (GTK_WIDGET (dialog));
+
+       switch (response) {
+       case GTK_RESPONSE_YES:
+               ev_window_cmd_save_as (NULL, ev_window);
+               break;
+       case GTK_RESPONSE_NO:
+               gtk_widget_destroy (GTK_WIDGET (ev_window));
+               break;
+       case GTK_RESPONSE_CANCEL:
+       default:
+               break;
+       }
+}
+
+static gboolean
+ev_window_check_document_modified (EvWindow *ev_window)
+{
+       EvDocument  *document = ev_window->priv->document;
+       GtkWidget   *dialog;
+       gchar       *text, *markup;
+       const gchar *secondary_text;
+
+       if (!document)
+               return FALSE;
+
+       if (EV_IS_DOCUMENT_FORMS (document) &&
+           ev_document_forms_document_is_modified (EV_DOCUMENT_FORMS (document))) {
+               secondary_text = _("Document contains form fields that have been filled out. "
+                                  "If you don't save a copy, changes will be permanently lost.");
+       } else if (EV_IS_DOCUMENT_ANNOTATIONS (document) &&
+                  ev_document_annotations_document_is_modified (EV_DOCUMENT_ANNOTATIONS (document))) {
+               secondary_text = _("Document contains new or modified annotations. "
+                                  "If you don't save a copy, changes will be permanently lost.");
+       } else {
+               return FALSE;
+       }
+
+
+       text = g_markup_printf_escaped (_("Save a copy of document “%s” before closing?"),
+                                       gtk_window_get_title (GTK_WINDOW (ev_window)));
+
+       dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
+                                        GTK_DIALOG_MODAL,
+                                        GTK_MESSAGE_QUESTION,
+                                        GTK_BUTTONS_NONE,
+                                        NULL);
+
+       markup = g_strdup_printf ("<b>%s</b>", text);
+       g_free (text);
+
+       gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), markup);
+       g_free (markup);
+
+       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                                 "%s", secondary_text);
+
+       gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                               _("Close _without Saving"),
+                               GTK_RESPONSE_NO,
+                               GTK_STOCK_CANCEL,
+                               GTK_RESPONSE_CANCEL,
+                               _("Save a _Copy"),
+                               GTK_RESPONSE_YES,
+                               NULL);
+       gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
+        gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+                                                 GTK_RESPONSE_YES,
+                                                 GTK_RESPONSE_NO,
+                                                 GTK_RESPONSE_CANCEL,
+                                                 -1);
+
+       g_signal_connect (dialog, "response",
+                         G_CALLBACK (document_modified_confirmation_dialog_response),
+                         ev_window);
+       gtk_widget_show (dialog);
+
+       return TRUE;
+}
+
 static void
 print_jobs_confirmation_dialog_response (GtkDialog *dialog,
                                         gint       response,
@@ -3397,31 +3597,18 @@ print_jobs_confirmation_dialog_response (GtkDialog *dialog,
        }
 }
 
-static void
-ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
+static gboolean
+ev_window_check_print_queue (EvWindow *ev_window)
 {
        GtkWidget *dialog;
        gchar     *text, *markup;
        gint       n_print_jobs;
 
-       if (EV_WINDOW_IS_PRESENTATION (ev_window)) {
-               gint current_page;
-
-               /* Save current page */
-               current_page = ev_view_presentation_get_current_page (
-                       EV_VIEW_PRESENTATION (ev_window->priv->presentation_view));
-               ev_document_model_set_page (ev_window->priv->model, current_page);
-       }
-
-       /* TODO: warn about form fields, and annots not saved */
-
        n_print_jobs = ev_window->priv->print_queue ?
                g_queue_get_length (ev_window->priv->print_queue) : 0;
-       
-       if (n_print_jobs == 0) {
-               gtk_widget_destroy (GTK_WIDGET (ev_window));
-               return;
-       }
+
+       if (n_print_jobs == 0)
+               return FALSE;
 
        dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
                                         GTK_DIALOG_MODAL,
@@ -3452,7 +3639,7 @@ ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s",
                                                  _("If you close the window, pending print "
                                                    "jobs will not be printed."));
-       
+
        gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                                _("Cancel _print and Close"),
                                GTK_RESPONSE_NO,
@@ -3472,6 +3659,36 @@ ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
                          G_CALLBACK (print_jobs_confirmation_dialog_response),
                          ev_window);
        gtk_widget_show (dialog);
+
+       return TRUE;
+}
+
+static gboolean
+ev_window_close (EvWindow *ev_window)
+{
+       if (EV_WINDOW_IS_PRESENTATION (ev_window)) {
+               gint current_page;
+
+               /* Save current page */
+               current_page = ev_view_presentation_get_current_page (
+                       EV_VIEW_PRESENTATION (ev_window->priv->presentation_view));
+               ev_document_model_set_page (ev_window->priv->model, current_page);
+       }
+
+       if (ev_window_check_document_modified (ev_window))
+               return FALSE;
+
+       if (ev_window_check_print_queue (ev_window))
+               return FALSE;
+
+       return TRUE;
+}
+
+static void
+ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
+{
+       if (ev_window_close (ev_window))
+               gtk_widget_destroy (GTK_WIDGET (ev_window));
 }
 
 static void
@@ -3645,22 +3862,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
@@ -3770,7 +3984,42 @@ 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_wrapper (EvWindow *window)
+{
+       if ( get_num_monitors(GTK_WINDOW(window)) > 1) {
+               EvWindow *presentation_window = window;
+               EvDSCWindow *control = ev_dscwindow_get_control();
+
+               ev_dscwindow_set_presentation (control, presentation_window,
+                                               presentation_window->priv->document);
+               gtk_window_present (GTK_WINDOW (control));
+       } else
+               ev_window_run_presentation (window);
+
+}
 static void
+ev_window_stop_presentation_wrapper(EvWindow *window, gboolean unfullscreen_window)
+{
+}
+
+void
 ev_window_run_presentation (EvWindow *window)
 {
        gboolean fullscreen_window = TRUE;
@@ -3796,6 +4045,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,
@@ -3817,17 +4075,20 @@ ev_window_run_presentation (EvWindow *window)
                ev_metadata_set_boolean (window->priv->metadata, "presentation", TRUE);
 }
 
-static void
+void
 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);
@@ -3854,7 +4115,7 @@ ev_window_cmd_view_presentation (GtkAction *action, EvWindow *window)
 
        presentation = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
        if (presentation) {
-               ev_window_run_presentation (window);
+               ev_window_run_presentation_wrapper (window);
        }
 }
 
@@ -3999,17 +4260,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;
 
-       ev_document_model_set_rotation (ev_window->priv->model, rotation - 90);
+       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);
+       }
 }
 
 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
@@ -4030,6 +4307,7 @@ ev_window_cmd_edit_toolbar_cb (GtkDialog *dialog,
 
        toolbar = EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar);
         egg_editable_toolbar_set_edit_mode (toolbar, FALSE);
+       ev_window_set_action_sensitive (ev_window, "ViewToolbar", TRUE);
 
        toolbars_file = g_build_filename (ev_application_get_dot_dir (EV_APP, TRUE),
                                          "evince_toolbar.xml", NULL);
@@ -4058,7 +4336,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);
-       gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
        gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 400);
 
        toolbar = EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar);
@@ -4068,9 +4345,10 @@ 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);
+       ev_window_set_action_sensitive (ev_window, "ViewToolbar", FALSE);
 
        g_signal_connect (dialog, "response",
                          G_CALLBACK (ev_window_cmd_edit_toolbar_cb),
@@ -4186,6 +4464,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)
 {
@@ -4229,7 +4593,7 @@ ev_window_cmd_leave_fullscreen (GtkAction *action, EvWindow *window)
 static void
 ev_window_cmd_start_presentation (GtkAction *action, EvWindow *window)
 {
-       ev_window_run_presentation (window);
+       ev_window_run_presentation_wrapper (window);
 }
 
 static void
@@ -4454,6 +4818,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
        };
 
@@ -4494,7 +4860,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,
@@ -4561,6 +4927,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);
        }
 }
 
@@ -4756,17 +5124,23 @@ ev_window_update_find_status_message (EvWindow *ev_window)
                return;
        
        if (ev_job_is_finished (ev_window->priv->find_job)) {
-               gint n_results;
-
-               n_results = ev_job_find_get_n_results (EV_JOB_FIND (ev_window->priv->find_job),
-                                                      ev_document_model_get_page (ev_window->priv->model));
-               /* TRANS: Sometimes this could be better translated as
-                                     "%d hit(s) on this page".  Therefore this string
-                                     contains plural cases. */
-               message = g_strdup_printf (ngettext ("%d found on this page",
-                                                    "%d found on this page",
-                                                    n_results),
-                                          n_results);
+               EvJobFind *job_find = EV_JOB_FIND (ev_window->priv->find_job);
+
+               if (ev_job_find_has_results (job_find)) {
+                       gint n_results;
+
+                       n_results = ev_job_find_get_n_results (job_find,
+                                                              ev_document_model_get_page (ev_window->priv->model));
+                       /* TRANS: Sometimes this could be better translated as
+                          "%d hit(s) on this page".  Therefore this string
+                          contains plural cases. */
+                       message = g_strdup_printf (ngettext ("%d found on this page",
+                                                            "%d found on this page",
+                                                            n_results),
+                                                  n_results);
+               } else {
+                       message = g_strdup (_("Not found"));
+               }
        } else {
                gdouble percent;
 
@@ -4842,30 +5216,23 @@ find_bar_close_cb (EggFindBar *find_bar,
 }
 
 static void
-find_bar_search_changed_cb (EggFindBar *find_bar,
-                           GParamSpec *param,
-                           EvWindow   *ev_window)
+ev_window_search_start (EvWindow *ev_window)
 {
-       gboolean case_sensitive;
+       EggFindBar *find_bar = EGG_FIND_BAR (ev_window->priv->find_bar);
        const char *search_string;
 
        if (!ev_window->priv->document || !EV_IS_DOCUMENT_FIND (ev_window->priv->document))
                return;
-       
-       /* Either the string or case sensitivity could have changed. */
-       case_sensitive = egg_find_bar_get_case_sensitive (find_bar);
-       search_string = egg_find_bar_get_search_string (find_bar);
 
-       ev_view_find_search_changed (EV_VIEW (ev_window->priv->view));
+       search_string = egg_find_bar_get_search_string (find_bar);
 
        ev_window_clear_find_job (ev_window);
-
        if (search_string && search_string[0]) {
                ev_window->priv->find_job = ev_job_find_new (ev_window->priv->document,
                                                             ev_document_model_get_page (ev_window->priv->model),
                                                             ev_document_get_n_pages (ev_window->priv->document),
                                                             search_string,
-                                                            case_sensitive);
+                                                            egg_find_bar_get_case_sensitive (find_bar));
                g_signal_connect (ev_window->priv->find_job, "finished",
                                  G_CALLBACK (ev_window_find_job_finished_cb),
                                  ev_window);
@@ -4875,12 +5242,21 @@ find_bar_search_changed_cb (EggFindBar *find_bar,
                ev_job_scheduler_push_job (ev_window->priv->find_job, EV_JOB_PRIORITY_NONE);
        } else {
                ev_window_update_actions (ev_window);
-               egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
-                                             NULL);
+               egg_find_bar_set_status_text (find_bar, NULL);
                gtk_widget_queue_draw (GTK_WIDGET (ev_window->priv->view));
        }
 }
 
+static void
+find_bar_search_changed_cb (EggFindBar *find_bar,
+                           GParamSpec *param,
+                           EvWindow   *ev_window)
+{
+       /* Either the string or case sensitivity could have changed. */
+       ev_view_find_search_changed (EV_VIEW (ev_window->priv->view));
+       ev_window_search_start (ev_window);
+}
+
 static void
 find_bar_visibility_changed_cb (EggFindBar *find_bar,
                                GParamSpec *param,
@@ -4893,11 +5269,10 @@ find_bar_visibility_changed_cb (EggFindBar *find_bar,
        if (ev_window->priv->document &&
            EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
                ev_view_find_set_highlight_search (EV_VIEW (ev_window->priv->view), visible);
-               ev_view_find_search_changed (EV_VIEW (ev_window->priv->view));
                ev_window_update_actions (ev_window);
 
                if (visible)
-                       find_bar_search_changed_cb (find_bar, NULL, ev_window);
+                       ev_window_search_start (ev_window);
                else
                        egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar), NULL);
        }
@@ -5014,6 +5389,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;
@@ -5059,6 +5439,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,
@@ -5257,6 +5642,13 @@ ev_window_key_press_event (GtkWidget   *widget,
        return handled;
 }
 
+static gboolean
+ev_window_delete_event (GtkWidget   *widget,
+                       GdkEventAny *event)
+{
+       return !ev_window_close (EV_WINDOW (widget));
+}
+
 static void
 ev_window_class_init (EvWindowClass *ev_window_class)
 {
@@ -5266,6 +5658,7 @@ ev_window_class_init (EvWindowClass *ev_window_class)
        g_object_class->dispose = ev_window_dispose;
        g_object_class->finalize = ev_window_finalize;
 
+       widget_class->delete_event = ev_window_delete_event;
        widget_class->key_press_event = ev_window_key_press_event;
        widget_class->screen_changed = ev_window_screen_changed;
        widget_class->window_state_event = ev_window_state_event;
@@ -5280,6 +5673,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 */
@@ -5292,6 +5686,9 @@ static const GtkActionEntry entries[] = {
                { "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) },
+       { "FileOpenContainingFolder", GTK_STOCK_DIRECTORY, N_("Open Containing _Folder"), NULL,
+         N_("Show the folder which contains this file in the file manager"),
+         G_CALLBACK (ev_window_cmd_open_containing_folder) },
        { "FilePrint", GTK_STOCK_PRINT, N_("_Print…"), "<control>P",
          N_("Print this document"),
          G_CALLBACK (ev_window_cmd_file_print) },
@@ -5350,6 +5747,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) },
@@ -5537,6 +5939,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)
 {
@@ -5602,6 +6011,10 @@ set_action_properties (GtkActionGroup *action_group)
 {
        GtkAction *action;
 
+       action = gtk_action_group_get_action (action_group, "FileOpenContainingFolder");
+       /*translators: this is the label for toolbar button*/
+       g_object_set (action, "short_label", _("Open Folder"), NULL);
+
        action = gtk_action_group_get_action (action_group, "GoPreviousPage");
        g_object_set (action, "is-important", TRUE, NULL);
        /*translators: this is the label for toolbar button*/
@@ -5660,7 +6073,8 @@ view_actions_focus_in_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *win
 #endif /* ENABLE_DBUS */
 
        update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, FALSE);
-       ev_window_set_action_sensitive (window, "ViewToolbar", TRUE);
+       ev_window_set_action_sensitive (window, "ViewToolbar",
+                                       !ev_window_is_editing_toolbar (window));
 
        ev_window_set_view_accels_sensitivity (window, TRUE);
 
@@ -5904,7 +6318,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: {
@@ -5970,6 +6384,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,
@@ -5981,7 +6419,6 @@ image_save_dialog_response_cb (GtkWidget *fc,
        GError          *error = NULL;
        GdkPixbuf       *pixbuf;
        gchar           *uri;
-       gchar          **extensions;
        gchar           *filename;
        gchar           *file_format;
        GdkPixbufFormat *format;
@@ -6019,19 +6456,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);
@@ -6357,11 +6784,17 @@ ev_window_media_player_key_pressed (EvWindow    *window,
         * often seen keys
         */
        if (strcmp (key, "Play") == 0) {
-               ev_window_run_presentation (window);
+               ev_window_run_presentation_wrapper (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) {
@@ -6422,6 +6855,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;
@@ -6430,16 +6866,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);
@@ -6482,6 +6943,35 @@ ev_window_emit_closed (EvWindow *window)
                g_dbus_connection_flush_sync (connection, NULL, NULL);
 }
 
+static void
+ev_window_emit_doc_loaded (EvWindow *window)
+{
+       GDBusConnection *connection;
+       GError          *error = NULL;
+
+       if (window->priv->dbus_object_id <= 0)
+               return;
+
+       connection = ev_application_get_dbus_connection (EV_APP);
+       if (!connection)
+               return;
+
+       g_dbus_connection_emit_signal (connection,
+                                      NULL,
+                                      window->priv->dbus_object_path,
+                                      EV_WINDOW_DBUS_INTERFACE,
+                                      "DocumentLoaded",
+                                      g_variant_new("(s)", window->priv->uri),
+                                      &error);
+       if (error) {
+               g_printerr ("Failed to emit DBus signal DocumentLoaded: %s\n",
+                           error->message);
+               g_error_free (error);
+
+               return;
+       }
+}
+
 static void
 method_call_cb (GDBusConnection       *connection,
                 const gchar           *sender,
@@ -6499,10 +6989,11 @@ method_call_cb (GDBusConnection       *connection,
 
        if (window->priv->document && ev_document_has_synctex (window->priv->document)) {
                EvSourceLink link;
+               guint32      timestamp;
 
-               g_variant_get (parameters, "(&s(ii))", &link.filename, &link.line, &link.col);
+               g_variant_get (parameters, "(&s(ii)u)", &link.filename, &link.line, &link.col, &timestamp);
                ev_view_highlight_forward_search (EV_VIEW (window->priv->view), &link);
-               gtk_window_present (GTK_WINDOW (window));
+               gtk_window_present_with_time (GTK_WINDOW (window), timestamp);
        }
 
        g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
@@ -6514,12 +7005,17 @@ static const char introspection_xml[] =
             "<method name='SyncView'>"
               "<arg type='s' name='source_file' direction='in'/>"
               "<arg type='(ii)' name='source_point' direction='in'/>"
+              "<arg type='u' name='timestamp' direction='in'/>"
             "</method>"
            "<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'>"
+             "<arg type='s' name='uri' direction='out'/>"
+           "</signal>"
           "</interface>"
         "</node>";
 
@@ -6672,6 +7168,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),
@@ -6680,7 +7180,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),
@@ -6764,6 +7264,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,
@@ -6793,9 +7303,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);
@@ -6808,6 +7318,9 @@ ev_window_init (EvWindow *ev_window)
        g_signal_connect_object (ev_window->priv->view, "annot-added",
                                 G_CALLBACK (view_annot_added),
                                 ev_window, 0);
+       g_signal_connect_object (ev_window->priv->view, "layers-changed",
+                                G_CALLBACK (view_layers_changed_cb),
+                                ev_window, 0);
 #ifdef ENABLE_DBUS
        g_signal_connect_swapped (ev_window->priv->view, "sync-source",
                                  G_CALLBACK (ev_window_sync_source),