X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=shell%2Fev-window.c;h=ef6f0b16ac85271cb1e5207cc7d2508e5d60e4fa;hb=3653856f03c6a5fefc3b6ea67bd789650b5bfa1e;hp=38ac098ad74b0153e8805c0a419a6f2d0877ab31;hpb=5a3fc72a0268f18a72702149eec1fb5dc2882f0f;p=evince.git diff --git a/shell/ev-window.c b/shell/ev-window.c index 38ac098a..ef6f0b16 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -34,16 +34,13 @@ #include #include #include +#include #include #include #include #include -#ifdef WITH_GCONF -#include -#endif - #include "egg-editable-toolbar.h" #include "egg-toolbar-editor.h" #include "egg-toolbars-model.h" @@ -54,12 +51,12 @@ #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" @@ -77,7 +74,9 @@ #include "ev-page-action.h" #include "ev-password-view.h" #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" @@ -93,6 +92,9 @@ #include "ev-window-title.h" #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,10 +141,13 @@ struct _EvWindowPrivate { GtkWidget *sidebar_links; GtkWidget *sidebar_attachments; GtkWidget *sidebar_layers; + GtkWidget *sidebar_annots; + GtkWidget *sidebar_bookmarks; /* Settings */ GSettings *settings; - GSettings *last_settings; + GSettings *default_settings; + GSettings *lockdown_settings; /* Menubar accels */ guint menubar_accel_keyval; @@ -163,15 +168,18 @@ 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 */ GtkWidget *fullscreen_toolbar; /* Popup view */ - GtkWidget *view_popup; - EvLink *link; - EvImage *image; + GtkWidget *view_popup; + EvLink *link; + EvImage *image; + EvAnnotation *annot; /* Popup attachment */ GtkWidget *attachment_popup; @@ -191,6 +199,8 @@ struct _EvWindowPrivate { EvWindowPageMode page_mode; EvWindowTitle *title; EvMetadata *metadata; + EvBookmarks *bookmarks; + gboolean is_new_doc; /* Load params */ EvLinkDest *dest; @@ -208,8 +218,11 @@ struct _EvWindowPrivate { GtkPrintSettings *print_settings; GtkPageSetup *print_page_setup; gboolean close_after_print; -#ifdef WITH_GCONF - GConfClient *gconf_client; + +#ifdef ENABLE_DBUS + /* DBus */ + guint dbus_object_id; + gchar *dbus_object_path; #endif }; @@ -222,20 +235,26 @@ struct _EvWindowPrivate { #define ZOOM_CONTROL_ACTION "ViewZoom" #define NAVIGATION_ACTION "Navigation" -#define GCONF_LOCKDOWN_DIR "/desktop/gnome/lockdown" -#define GCONF_OVERRIDE_RESTRICTIONS "/apps/evince/override_restrictions" -#define GCONF_LOCKDOWN_SAVE "/desktop/gnome/lockdown/disable_save_to_disk" -#define GCONF_LOCKDOWN_PRINT "/desktop/gnome/lockdown/disable_printing" -#define GCONF_LOCKDOWN_PRINT_SETUP "/desktop/gnome/lockdown/disable_print_setup" +#define GS_LOCKDOWN_SCHEMA_NAME "org.gnome.desktop.lockdown" +#define GS_LOCKDOWN_SAVE "disable-save-to-disk" +#define GS_LOCKDOWN_PRINT "disable-printing" +#define GS_LOCKDOWN_PRINT_SETUP "disable-print-setup" + +#ifdef ENABLE_DBUS +#define EV_WINDOW_DBUS_OBJECT_PATH "/org/gnome/evince/Window/%d" +#define EV_WINDOW_DBUS_INTERFACE "org.gnome.evince.Window" +#endif #define GS_SCHEMA_NAME "org.gnome.Evince" -#define GS_OVERRIDE_RESTRICTIONS "override_restrictions" +#define GS_OVERRIDE_RESTRICTIONS "override-restrictions" #define SIDEBAR_DEFAULT_SIZE 132 #define LINKS_SIDEBAR_ID "links" #define THUMBNAILS_SIDEBAR_ID "thumbnails" #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" @@ -244,7 +263,7 @@ struct _EvWindowPrivate { #define EV_TOOLBARS_FILENAME "evince-toolbar.xml" #define MIN_SCALE 0.05409 -#define MAX_SCALE 4.0 +#define PAGE_CACHE_SIZE 52428800 /* 50MB */ #define MAX_RECENT_ITEM_LEN (40) @@ -264,6 +283,8 @@ static void ev_window_update_actions (EvWindow *ev_window); static void ev_window_sidebar_visibility_changed_cb (EvSidebar *ev_sidebar, GParamSpec *pspec, EvWindow *ev_window); +static void ev_window_view_toolbar_cb (GtkAction *action, + EvWindow *ev_window); static void ev_window_set_page_mode (EvWindow *window, EvWindowPageMode page_mode); static void ev_window_load_job_cb (EvJob *job, @@ -289,9 +310,6 @@ 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_cmd_view_presentation (GtkAction *action, EvWindow *window); static void ev_view_popup_cmd_open_link (GtkAction *action, @@ -304,6 +322,8 @@ static void ev_view_popup_cmd_save_image_as (GtkAction *actio EvWindow *window); static void ev_view_popup_cmd_copy_image (GtkAction *action, EvWindow *window); +static void ev_view_popup_cmd_annot_properties (GtkAction *action, + EvWindow *window); static void ev_attachment_popup_cmd_open_attachment (GtkAction *action, EvWindow *window); static void ev_attachment_popup_cmd_save_attachment_as (GtkAction *action, @@ -321,11 +341,19 @@ 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, const gchar *key, gpointer user_data); +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; @@ -340,6 +368,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, @@ -358,7 +392,6 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) const EvDocumentInfo *info = NULL; gboolean has_document = FALSE; gboolean ok_to_print = TRUE; - gboolean ok_to_print_setup = TRUE; gboolean ok_to_copy = TRUE; gboolean has_properties = TRUE; gboolean override_restrictions = TRUE; @@ -398,28 +431,22 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) if (has_document && !ev_print_operation_exists_for_document(document)) ok_to_print = FALSE; -#ifdef WITH_GCONF - if (has_document && - gconf_client_get_bool (ev_window->priv->gconf_client, GCONF_LOCKDOWN_SAVE, NULL)) { + if (has_document && ev_window->priv->lockdown_settings && + g_settings_get_boolean (ev_window->priv->lockdown_settings, GS_LOCKDOWN_SAVE)) { ok_to_copy = FALSE; } - if (has_document && - gconf_client_get_bool (ev_window->priv->gconf_client, GCONF_LOCKDOWN_PRINT, NULL)) { + if (has_document && ev_window->priv->lockdown_settings && + g_settings_get_boolean (ev_window->priv->lockdown_settings, GS_LOCKDOWN_PRINT)) { ok_to_print = FALSE; } - if (has_document && - gconf_client_get_bool (ev_window->priv->gconf_client, GCONF_LOCKDOWN_PRINT_SETUP, NULL)) { - ok_to_print_setup = FALSE; - } -#endif - /* File menu */ ev_window_set_action_sensitive (ev_window, "FileOpenCopy", has_document); 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); @@ -429,6 +456,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); @@ -437,6 +465,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); @@ -644,6 +676,22 @@ update_sizing_buttons (EvWindow *window) } } +static void +update_chrome_actions (EvWindow *window) +{ + EvWindowPrivate *priv = window->priv; + GtkActionGroup *action_group = priv->action_group; + GtkAction *action; + + action= gtk_action_group_get_action (action_group, "ViewToolbar"); + g_signal_handlers_block_by_func + (action, G_CALLBACK (ev_window_view_toolbar_cb), window); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + (priv->chrome & EV_CHROME_TOOLBAR) != 0); + g_signal_handlers_unblock_by_func + (action, G_CALLBACK (ev_window_view_toolbar_cb), window); +} + /** * ev_window_is_empty: * @ev_window: The instance of the #EvWindow. @@ -757,18 +805,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, @@ -778,9 +825,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; @@ -790,12 +837,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; @@ -818,34 +894,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); @@ -868,6 +929,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, @@ -887,6 +955,71 @@ ev_window_page_changed_cb (EvWindow *ev_window, ev_metadata_set_int (ev_window->priv->metadata, "page", new_page); } +static const gchar * +ev_window_sidebar_get_current_page_id (EvWindow *ev_window) +{ + GtkWidget *current_page; + const gchar *id; + + g_object_get (ev_window->priv->sidebar, + "current_page", ¤t_page, + NULL); + + if (current_page == ev_window->priv->sidebar_links) { + id = LINKS_SIDEBAR_ID; + } else if (current_page == ev_window->priv->sidebar_thumbs) { + id = THUMBNAILS_SIDEBAR_ID; + } else if (current_page == ev_window->priv->sidebar_attachments) { + id = ATTACHMENTS_SIDEBAR_ID; + } else if (current_page == ev_window->priv->sidebar_layers) { + 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(); + } + + g_object_unref (current_page); + + return id; +} + +static void +ev_window_sidebar_set_current_page (EvWindow *window, + const gchar *page_id) +{ + EvDocument *document = window->priv->document; + EvSidebar *sidebar = EV_SIDEBAR (window->priv->sidebar); + GtkWidget *links = window->priv->sidebar_links; + GtkWidget *thumbs = window->priv->sidebar_thumbs; + 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)) { + ev_sidebar_set_page (sidebar, links); + } else if (strcmp (page_id, THUMBNAILS_SIDEBAR_ID) == 0 && + ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (thumbs), document)) { + ev_sidebar_set_page (sidebar, thumbs); + } else if (strcmp (page_id, ATTACHMENTS_SIDEBAR_ID) == 0 && + ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (attachments), document)) { + ev_sidebar_set_page (sidebar, attachments); + } else if (strcmp (page_id, LAYERS_SIDEBAR_ID) == 0 && + ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (layers), document)) { + ev_sidebar_set_page (sidebar, layers); + } 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); + } +} + static void update_document_mode (EvWindow *window, EvDocumentMode mode) { @@ -902,18 +1035,24 @@ static void setup_chrome_from_metadata (EvWindow *window) { EvChrome chrome = EV_CHROME_NORMAL; - gboolean show_toolbar; + gboolean show_toolbar = TRUE; - if (window->priv->document) { - if (!window->priv->metadata || - !ev_metadata_get_boolean (window->priv->metadata, "show_toolbar", &show_toolbar)) { - show_toolbar = g_settings_get_boolean (window->priv->last_settings, "show-toolbar"); - } + if (ev_window_is_empty (window)) { + window->priv->chrome = chrome; + + return; + } - if (!show_toolbar) - chrome &= ~EV_CHROME_TOOLBAR; + if (!window->priv->metadata) { + show_toolbar = g_settings_get_boolean (window->priv->default_settings, "show-toolbar"); + } else if (!ev_metadata_get_boolean (window->priv->metadata, "show_toolbar", &show_toolbar)) { + if (window->priv->is_new_doc) + show_toolbar = g_settings_get_boolean (window->priv->default_settings, "show-toolbar"); } + if (!show_toolbar) + chrome &= ~EV_CHROME_TOOLBAR; + window->priv->chrome = chrome; } @@ -921,65 +1060,85 @@ static void setup_sidebar_from_metadata (EvWindow *window) { EvDocument *document = window->priv->document; - GtkWidget *sidebar = window->priv->sidebar; - GtkWidget *links = window->priv->sidebar_links; - GtkWidget *thumbs = window->priv->sidebar_thumbs; - GtkWidget *attachments = window->priv->sidebar_attachments; - GtkWidget *layers = window->priv->sidebar_layers; + GSettings *settings = window->priv->default_settings; gchar *page_id; gint sidebar_size; - gboolean sidebar_visibility; + gboolean sidebar_visibility = TRUE; - if (!window->priv->metadata) + if (ev_window_is_empty (window)) return; - if (ev_metadata_get_int (window->priv->metadata, "sidebar_size", &sidebar_size)) { - gtk_paned_set_position (GTK_PANED (window->priv->hpaned), sidebar_size); + if (!window->priv->metadata) { + sidebar_visibility = g_settings_get_boolean (settings, "show-sidebar"); + } else if (!ev_metadata_get_boolean (window->priv->metadata, "sidebar_visibility", &sidebar_visibility)) { + if (window->priv->is_new_doc) + sidebar_visibility = g_settings_get_boolean (settings, "show-sidebar"); } - if (document && ev_metadata_get_string (window->priv->metadata, "sidebar_page", &page_id)) { - if (strcmp (page_id, LINKS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) { - ev_sidebar_set_page (EV_SIDEBAR (sidebar), links); - } else if (strcmp (page_id, THUMBNAILS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (thumbs), document)) { - ev_sidebar_set_page (EV_SIDEBAR (sidebar), thumbs); - } else if (strcmp (page_id, ATTACHMENTS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (attachments), document)) { - ev_sidebar_set_page (EV_SIDEBAR (sidebar), attachments); - } else if (strcmp (page_id, LAYERS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (layers), document)) { - ev_sidebar_set_page (EV_SIDEBAR (sidebar), layers); - } - } else if (document) { - if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) { - ev_sidebar_set_page (EV_SIDEBAR (sidebar), links); - } else if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (thumbs), document)) { - ev_sidebar_set_page (EV_SIDEBAR (sidebar), thumbs); - } else if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (attachments), document)) { - ev_sidebar_set_page (EV_SIDEBAR (sidebar), attachments); - } else if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (layers), document)) { - ev_sidebar_set_page (EV_SIDEBAR (sidebar), layers); + update_chrome_flag (window, EV_CHROME_SIDEBAR, sidebar_visibility); + update_chrome_visibility (window); + + if (!window->priv->metadata) { + /* Set default values */ + gtk_paned_set_position (GTK_PANED (window->priv->hpaned), + g_settings_get_int (settings, "sidebar-size")); + if (document) { + page_id = g_settings_get_string (settings, "sidebar-page"); + ev_window_sidebar_set_current_page (window, page_id); + g_free (page_id); } + + return; + } + + if (ev_metadata_get_int (window->priv->metadata, "sidebar_size", &sidebar_size)) { + gtk_paned_set_position (GTK_PANED (window->priv->hpaned), sidebar_size); + } else if (window->priv->is_new_doc) { + gtk_paned_set_position (GTK_PANED (window->priv->hpaned), + g_settings_get_int (settings, "sidebar-size")); } - if (!ev_metadata_get_boolean (window->priv->metadata, "sidebar_visibility", &sidebar_visibility)) - sidebar_visibility = g_settings_get_boolean (window->priv->last_settings, "show-sidebar"); + if (!document) + return; - update_chrome_flag (window, EV_CHROME_SIDEBAR, sidebar_visibility); - update_chrome_visibility (window); + if (ev_metadata_get_string (window->priv->metadata, "sidebar_page", &page_id)) { + ev_window_sidebar_set_current_page (window, page_id); + } else if (window->priv->is_new_doc) { + page_id = g_settings_get_string (settings, "sidebar-page"); + ev_window_sidebar_set_current_page (window, page_id); + g_free (page_id); + } } static void setup_model_from_metadata (EvWindow *window) { - gint page; - gchar *sizing_mode; - gdouble zoom; - gint rotation; - gboolean inverted_colors = FALSE; - gboolean continuous = FALSE; - gboolean dual_page = FALSE; - gboolean fullscreen = FALSE; + GSettings *settings = window->priv->default_settings; + gint page; + gchar *sizing_mode; + gdouble zoom; + gint rotation; + gboolean inverted_colors = FALSE; + gboolean continuous = FALSE; + gboolean dual_page = FALSE; + gboolean fullscreen = FALSE; + + if (!window->priv->metadata) { + /* Set default values */ + ev_document_model_set_sizing_mode (window->priv->model, + g_settings_get_enum (settings, "sizing-mode")); + ev_document_model_set_inverted_colors (window->priv->model, + g_settings_get_boolean (settings, "inverted-colors")); + ev_document_model_set_continuous (window->priv->model, + g_settings_get_boolean (settings, "continuous")); + ev_document_model_set_dual_page (window->priv->model, + g_settings_get_boolean (settings, "dual-page")); + fullscreen = g_settings_get_boolean (settings, "fullscreen"); + if (fullscreen) + ev_window_run_fullscreen (window); - if (!window->priv->metadata) return; + } /* Current page */ if (!window->priv->dest && @@ -994,6 +1153,9 @@ setup_model_from_metadata (EvWindow *window) enum_value = g_enum_get_value_by_nick (g_type_class_peek (EV_TYPE_SIZING_MODE), sizing_mode); ev_document_model_set_sizing_mode (window->priv->model, enum_value->value); + } else if (window->priv->is_new_doc) { + ev_document_model_set_sizing_mode (window->priv->model, + g_settings_get_enum (settings, "sizing-mode")); } /* Zoom */ @@ -1023,25 +1185,37 @@ setup_model_from_metadata (EvWindow *window) } /* Inverted Colors */ - if (ev_metadata_get_boolean (window->priv->metadata, "inverted-colors", &inverted_colors)) + if (ev_metadata_get_boolean (window->priv->metadata, "inverted-colors", &inverted_colors)) { ev_document_model_set_inverted_colors (window->priv->model, inverted_colors); + } else if (window->priv->is_new_doc) { + ev_document_model_set_inverted_colors (window->priv->model, + g_settings_get_boolean (settings, "inverted-colors")); + } /* Continuous */ if (ev_metadata_get_boolean (window->priv->metadata, "continuous", &continuous)) { ev_document_model_set_continuous (window->priv->model, continuous); + } else if (window->priv->is_new_doc) { + ev_document_model_set_continuous (window->priv->model, + g_settings_get_boolean (settings, "continuous")); } /* Dual page */ if (ev_metadata_get_boolean (window->priv->metadata, "dual-page", &dual_page)) { ev_document_model_set_dual_page (window->priv->model, dual_page); + } else if (window->priv->is_new_doc) { + ev_document_model_set_dual_page (window->priv->model, + g_settings_get_boolean (settings, "dual-page")); } /* Fullscreen */ - if (ev_metadata_get_boolean (window->priv->metadata, "fullscreen", &fullscreen)) { - if (fullscreen) { - ev_window_run_fullscreen (window); - } + if (!ev_metadata_get_boolean (window->priv->metadata, "fullscreen", &fullscreen)) { + if (window->priv->is_new_doc) + fullscreen = g_settings_get_boolean (settings, "fullscreen"); } + + if (fullscreen) + ev_window_run_fullscreen (window); } static void @@ -1053,25 +1227,24 @@ setup_document_from_metadata (EvWindow *window) gdouble width_ratio; gdouble height_ratio; - if (!window->priv->metadata) - return; - - /* Make sure to not open a document on the last page, - * since closing it on the last page most likely means the - * user was finished reading the document. In that case, reopening should - * show the first page. */ - page = ev_document_model_get_page (window->priv->model); - n_pages = ev_document_get_n_pages (window->priv->document); - if (page == n_pages - 1) - ev_document_model_set_page (window->priv->model, 0); - setup_sidebar_from_metadata (window); - if (ev_metadata_get_int (window->priv->metadata, "window_width", &width) && - ev_metadata_get_int (window->priv->metadata, "window_height", &height)) - return; /* size was already set in setup_size_from_metadata */ + if (window->priv->metadata) { + /* Make sure to not open a document on the last page, + * since closing it on the last page most likely means the + * user was finished reading the document. In that case, reopening should + * show the first page. */ + page = ev_document_model_get_page (window->priv->model); + n_pages = ev_document_get_n_pages (window->priv->document); + if (page == n_pages - 1) + ev_document_model_set_page (window->priv->model, 0); + + if (ev_metadata_get_int (window->priv->metadata, "window_width", &width) && + ev_metadata_get_int (window->priv->metadata, "window_height", &height)) + return; /* size was already set in setup_size_from_metadata */ + } - g_settings_get (window->priv->last_settings, "window-ratio", "(dd)", &width_ratio, &height_ratio); + g_settings_get (window->priv->default_settings, "window-ratio", "(dd)", &width_ratio, &height_ratio); if (width_ratio > 0. && height_ratio > 0.) { gdouble document_width; gdouble document_height; @@ -1088,7 +1261,7 @@ setup_document_from_metadata (EvWindow *window) screen = gtk_window_get_screen (GTK_WINDOW (window)); if (screen) { request_width = MIN (request_width, gdk_screen_get_width (screen)); - request_height = MIN (request_width, gdk_screen_get_height (screen)); + request_height = MIN (request_height, gdk_screen_get_height (screen)); } if (request_width > 0 && request_height > 0) { @@ -1184,8 +1357,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; } @@ -1211,16 +1383,13 @@ override_restrictions_changed (GSettings *settings, ev_window_setup_action_sensitivity (ev_window); } -#ifdef WITH_GCONF static void -lockdown_changed (GConfClient *client, - guint cnxn_id, - GConfEntry *entry, +lockdown_changed (GSettings *lockdown, + const gchar *key, EvWindow *ev_window) { ev_window_setup_action_sensitivity (ev_window); } -#endif /* WITH_GCONF */ static gboolean ev_window_setup_document (EvWindow *ev_window) @@ -1230,31 +1399,30 @@ ev_window_setup_document (EvWindow *ev_window) GtkAction *action; ev_window->priv->setup_document_idle = 0; - + ev_window_refresh_window_thumbnail (ev_window); ev_window_set_page_mode (ev_window, PAGE_MODE_DOCUMENT); ev_window_title_set_document (ev_window->priv->title, document); ev_window_title_set_uri (ev_window->priv->title, ev_window->priv->uri); - ev_window->priv->settings = g_settings_new (GS_SCHEMA_NAME); - g_signal_connect (ev_window->priv->settings, - "changed::"GS_OVERRIDE_RESTRICTIONS, - G_CALLBACK (override_restrictions_changed), - ev_window); + if (!ev_window->priv->settings) { + ev_window->priv->settings = g_settings_new (GS_SCHEMA_NAME); + g_signal_connect (ev_window->priv->settings, + "changed::"GS_OVERRIDE_RESTRICTIONS, + G_CALLBACK (override_restrictions_changed), + ev_window); + } -#ifdef WITH_GCONF - if (!ev_window->priv->gconf_client) - ev_window->priv->gconf_client = gconf_client_get_default (); - gconf_client_add_dir (ev_window->priv->gconf_client, - GCONF_LOCKDOWN_DIR, - GCONF_CLIENT_PRELOAD_ONELEVEL, - NULL); - gconf_client_notify_add (ev_window->priv->gconf_client, - GCONF_LOCKDOWN_DIR, - (GConfClientNotifyFunc)lockdown_changed, - ev_window, NULL, NULL); -#endif /* WITH_GCONF */ +#ifdef HAVE_DESKTOP_SCHEMAS + if (!ev_window->priv->lockdown_settings) { + ev_window->priv->lockdown_settings = g_settings_new (GS_LOCKDOWN_SCHEMA_NAME); + g_signal_connect (ev_window->priv->lockdown_settings, + "changed", + G_CALLBACK (lockdown_changed), + ev_window); + } +#endif ev_window_setup_action_sensitivity (ev_window); @@ -1291,6 +1459,8 @@ ev_window_set_document (EvWindow *ev_window, EvDocument *document) g_object_unref (ev_window->priv->document); ev_window->priv->document = g_object_ref (document); + ev_window_update_max_min_scale (ev_window); + ev_window_set_message_area (ev_window, NULL); if (ev_document_get_n_pages (document) <= 0) { @@ -1301,6 +1471,19 @@ ev_window_set_document (EvWindow *ev_window, EvDocument *document) _("The document contains only empty pages")); } + 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); + } + if (ev_window->priv->setup_document_idle > 0) g_source_remove (ev_window->priv->setup_document_idle); @@ -1401,6 +1584,11 @@ 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); setup_view_from_metadata (ev_window); @@ -1858,7 +2046,6 @@ ev_window_open_uri (EvWindow *ev_window, ev_window_close_dialogs (ev_window); ev_window_clear_load_job (ev_window); ev_window_clear_local_uri (ev_window); - ev_view_set_loading (EV_VIEW (ev_window->priv->view), TRUE); ev_window->priv->window_mode = mode; @@ -1868,12 +2055,27 @@ 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_is_metadata_supported_for_file (source_file)) + if (!ev_file_is_temp (source_file) && ev_is_metadata_supported_for_file (source_file)) { ev_window->priv->metadata = ev_metadata_new (source_file); - else + ev_window->priv->is_new_doc = ev_metadata_is_empty (ev_window->priv->metadata); + } else { 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); @@ -1886,6 +2088,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, @@ -1896,6 +2099,7 @@ ev_window_open_uri (EvWindow *ev_window, if (!g_file_is_native (source_file) && !ev_window->priv->local_uri) { ev_window_load_file_remote (ev_window, source_file); } else { + ev_view_set_loading (EV_VIEW (ev_window->priv->view), TRUE); g_object_unref (source_file); ev_job_scheduler_push_job (ev_window->priv->load_job, EV_JOB_PRIORITY_NONE); } @@ -2629,6 +2833,8 @@ ev_window_save_job_cb (EvJob *job, ev_window_error_message (window, job->error, _("The file could not be saved as “%s”."), EV_JOB_SAVE (job)->uri); + } else { + ev_window_add_recent (window, EV_JOB_SAVE (job)->uri); } ev_window_clear_save_job (window); @@ -2728,6 +2934,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) { @@ -2786,21 +3034,25 @@ ev_window_save_print_settings (EvWindow *window, key_file = get_print_settings_file (); gtk_print_settings_to_key_file (print_settings, key_file, EV_PRINT_SETTINGS_GROUP); - save_print_setting_file (key_file); - g_key_file_free (key_file); - - if (!window->priv->metadata) - return; /* Save print settings that are specific to the document */ for (i = 0; i < G_N_ELEMENTS (document_print_settings); i++) { - const gchar *value; + /* Remove it from global settings */ + g_key_file_remove_key (key_file, EV_PRINT_SETTINGS_GROUP, + document_print_settings[i], NULL); - value = gtk_print_settings_get (print_settings, - document_print_settings[i]); - ev_metadata_set_string (window->priv->metadata, - document_print_settings[i], value); + if (window->priv->metadata) { + const gchar *value; + + value = gtk_print_settings_get (print_settings, + document_print_settings[i]); + ev_metadata_set_string (window->priv->metadata, + document_print_settings[i], value); + } } + + save_print_setting_file (key_file); + g_key_file_free (key_file); } static void @@ -2811,6 +3063,19 @@ ev_window_save_print_page_setup (EvWindow *window, key_file = get_print_settings_file (); gtk_page_setup_to_key_file (page_setup, key_file, EV_PAGE_SETUP_GROUP); + + /* Do not save document settings in global file */ + g_key_file_remove_key (key_file, EV_PAGE_SETUP_GROUP, + "page-setup-orientation", NULL); + g_key_file_remove_key (key_file, EV_PAGE_SETUP_GROUP, + "page-setup-margin-top", NULL); + g_key_file_remove_key (key_file, EV_PAGE_SETUP_GROUP, + "page-setup-margin-bottom", NULL); + g_key_file_remove_key (key_file, EV_PAGE_SETUP_GROUP, + "page-setup-margin-left", NULL); + g_key_file_remove_key (key_file, EV_PAGE_SETUP_GROUP, + "page-setup-margin-right", NULL); + save_print_setting_file (key_file); g_key_file_free (key_file); @@ -3116,6 +3381,7 @@ ev_window_print_range (EvWindow *ev_window, GtkPageSetup *print_page_setup; gint current_page; gint document_last_page; + gboolean embed_page_setup; g_return_if_fail (EV_IS_WINDOW (ev_window)); g_return_if_fail (ev_window->priv->document != NULL); @@ -3167,13 +3433,11 @@ ev_window_print_range (EvWindow *ev_window, ev_print_operation_set_current_page (op, current_page); ev_print_operation_set_print_settings (op, print_settings); ev_print_operation_set_default_page_setup (op, print_page_setup); -#ifdef WITH_GCONF - ev_print_operation_set_embed_page_setup (op, !gconf_client_get_bool (ev_window->priv->gconf_client, - GCONF_LOCKDOWN_PRINT_SETUP, - NULL)); -#else - ev_print_operation_set_embed_page_setup (op, TRUE); -#endif + embed_page_setup = ev_window->priv->lockdown_settings ? + !g_settings_get_boolean (ev_window->priv->lockdown_settings, + GS_LOCKDOWN_PRINT_SETUP) : + TRUE; + ev_print_operation_set_embed_page_setup (op, embed_page_setup); g_object_unref (print_settings); g_object_unref (print_page_setup); @@ -3215,67 +3479,141 @@ ev_window_cmd_file_properties (GtkAction *action, EvWindow *ev_window) } static void -print_jobs_confirmation_dialog_response (GtkDialog *dialog, - gint response, - EvWindow *ev_window) +document_modified_confirmation_dialog_response (GtkDialog *dialog, + gint response, + EvWindow *ev_window) { - gtk_widget_destroy (GTK_WIDGET (dialog)); - + gtk_widget_destroy (GTK_WIDGET (dialog)); + switch (response) { case GTK_RESPONSE_YES: - if (!ev_window->priv->print_queue || - g_queue_is_empty (ev_window->priv->print_queue)) - gtk_widget_destroy (GTK_WIDGET (ev_window)); - else - ev_window->priv->close_after_print = TRUE; + ev_window_cmd_save_as (NULL, ev_window); break; case GTK_RESPONSE_NO: - ev_window->priv->close_after_print = TRUE; - if (ev_window->priv->print_queue && - !g_queue_is_empty (ev_window->priv->print_queue)) { - gtk_widget_set_sensitive (GTK_WIDGET (ev_window), FALSE); - ev_window_print_cancel (ev_window); - } else { - gtk_widget_destroy (GTK_WIDGET (ev_window)); - } + gtk_widget_destroy (GTK_WIDGET (ev_window)); break; case GTK_RESPONSE_CANCEL: default: - ev_window->priv->close_after_print = FALSE; + break; } } -static void -ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window) +static gboolean +ev_window_check_document_modified (EvWindow *ev_window) { - GtkWidget *dialog; - gchar *text, *markup; - gint n_print_jobs; + EvDocument *document = ev_window->priv->document; + GtkWidget *dialog; + gchar *text, *markup; + const gchar *secondary_text; - if (EV_WINDOW_IS_PRESENTATION (ev_window)) { - gint current_page; + if (!document) + return FALSE; - /* 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_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; } - 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; - } + + 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); - if (n_print_jobs == 1) { - EvPrintOperation *op; + + markup = g_strdup_printf ("%s", 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, + EvWindow *ev_window) +{ + gtk_widget_destroy (GTK_WIDGET (dialog)); + + switch (response) { + case GTK_RESPONSE_YES: + if (!ev_window->priv->print_queue || + g_queue_is_empty (ev_window->priv->print_queue)) + gtk_widget_destroy (GTK_WIDGET (ev_window)); + else + ev_window->priv->close_after_print = TRUE; + break; + case GTK_RESPONSE_NO: + ev_window->priv->close_after_print = TRUE; + if (ev_window->priv->print_queue && + !g_queue_is_empty (ev_window->priv->print_queue)) { + gtk_widget_set_sensitive (GTK_WIDGET (ev_window), FALSE); + ev_window_print_cancel (ev_window); + } else { + gtk_widget_destroy (GTK_WIDGET (ev_window)); + } + break; + case GTK_RESPONSE_CANCEL: + default: + ev_window->priv->close_after_print = FALSE; + } +} + +static gboolean +ev_window_check_print_queue (EvWindow *ev_window) +{ + GtkWidget *dialog; + gchar *text, *markup; + gint n_print_jobs; + + n_print_jobs = ev_window->priv->print_queue ? + g_queue_get_length (ev_window->priv->print_queue) : 0; + + if (n_print_jobs == 0) + return FALSE; + + dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + NULL); + if (n_print_jobs == 1) { + EvPrintOperation *op; const gchar *job_name; op = g_queue_peek_tail (ev_window->priv->print_queue); @@ -3298,7 +3636,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, @@ -3318,6 +3656,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 @@ -3491,22 +3859,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 @@ -3616,7 +3981,23 @@ ev_window_view_presentation_finished (EvWindow *window) ev_window_stop_presentation (window, TRUE); } -static void +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; +} + +void ev_window_run_presentation (EvWindow *window) { gboolean fullscreen_window = TRUE; @@ -3639,9 +4020,19 @@ ev_window_run_presentation (EvWindow *window) current_page, rotation, inverted_colors); + 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, @@ -3661,19 +4052,30 @@ ev_window_run_presentation (EvWindow *window) if (window->priv->metadata && !ev_window_is_empty (window)) ev_metadata_set_boolean (window->priv->metadata, "presentation", TRUE); + + if ( get_num_monitors(GTK_WINDOW(window)) > 1) { + EvDSCWindow *control = ev_dscwindow_get_control(); + gtk_window_present (GTK_WINDOW (control)); + ev_dscwindow_set_presentation (control, window, + window->priv->document, + EV_VIEW_PRESENTATION(window->priv->presentation_view)); + } } -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); @@ -3733,23 +4135,47 @@ ev_window_setup_gtk_settings (EvWindow *window) g_free (menubar_accel_accel); } +static void +ev_window_update_max_min_scale (EvWindow *window) +{ + gdouble dpi; + GtkAction *action; + gdouble min_width, min_height; + gdouble width, height; + gdouble max_scale; + gint rotation = ev_document_model_get_rotation (window->priv->model); + + if (!window->priv->document) + return; + + dpi = get_screen_dpi (window) / 72.0; + + ev_document_get_min_page_size (window->priv->document, &min_width, &min_height); + width = (rotation == 0 || rotation == 180) ? min_width : min_height; + height = (rotation == 0 || rotation == 180) ? min_height : min_width; + max_scale = sqrt (PAGE_CACHE_SIZE / (width * dpi * 4 * height * dpi)); + + action = gtk_action_group_get_action (window->priv->action_group, + ZOOM_CONTROL_ACTION); + ephy_zoom_action_set_max_zoom_level (EPHY_ZOOM_ACTION (action), max_scale * dpi); + + ev_document_model_set_min_scale (window->priv->model, MIN_SCALE * dpi); + ev_document_model_set_max_scale (window->priv->model, max_scale * dpi); +} + static void ev_window_screen_changed (GtkWidget *widget, GdkScreen *old_screen) { EvWindow *window = EV_WINDOW (widget); - EvWindowPrivate *priv = window->priv; GdkScreen *screen; - gdouble dpi; screen = gtk_widget_get_screen (widget); if (screen == old_screen) return; ev_window_setup_gtk_settings (window); - dpi = get_screen_dpi (window); - ev_document_model_set_min_scale (priv->model, MIN_SCALE * dpi / 72.0); - ev_document_model_set_max_scale (priv->model, MAX_SCALE * dpi / 72.0); + ev_window_update_max_min_scale (window); if (GTK_WIDGET_CLASS (ev_window_parent_class)->screen_changed) { GTK_WIDGET_CLASS (ev_window_parent_class)->screen_changed (widget, old_screen); @@ -3821,17 +4247,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 @@ -3852,6 +4294,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); @@ -3880,7 +4323,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); @@ -3890,9 +4332,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), @@ -3900,6 +4343,34 @@ ev_window_cmd_edit_toolbar (GtkAction *action, EvWindow *ev_window) gtk_widget_show_all (dialog); } +static void +ev_window_cmd_edit_save_settings (GtkAction *action, EvWindow *ev_window) +{ + EvWindowPrivate *priv = ev_window->priv; + EvDocumentModel *model = priv->model; + GSettings *settings = priv->default_settings; + + g_settings_set_boolean (settings, "continuous", + ev_document_model_get_continuous (model)); + g_settings_set_boolean (settings, "dual-page", + ev_document_model_get_dual_page (model)); + g_settings_set_boolean (settings, "fullscreen", + ev_document_model_get_fullscreen (model)); + g_settings_set_boolean (settings, "inverted-colors", + ev_document_model_get_inverted_colors (model)); + g_settings_set_enum (settings, "sizing-mode", + ev_document_model_get_sizing_mode (model)); + g_settings_set_boolean (settings, "show-toolbar", + gtk_widget_get_visible (priv->toolbar)); + g_settings_set_boolean (settings, "show-sidebar", + gtk_widget_get_visible (priv->sidebar)); + g_settings_set_int (settings, "sidebar-size", + gtk_paned_get_position (GTK_PANED (priv->hpaned))); + g_settings_set_string (settings, "sidebar-page", + ev_window_sidebar_get_current_page_id (ev_window)); + g_settings_apply (settings); +} + static void ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window) { @@ -3980,6 +4451,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) { @@ -4167,6 +4724,7 @@ ev_window_rotation_changed_cb (EvDocumentModel *model, ev_metadata_set_int (window->priv->metadata, "rotation", rotation); + ev_window_update_max_min_scale (window); ev_window_refresh_window_thumbnail (window); } @@ -4247,6 +4805,8 @@ ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window) const char *documenters[] = { "Nickolay V. Shmyrev ", + "Phil Bull ", + "Tiffany Antpolski ", NULL }; @@ -4287,7 +4847,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, @@ -4312,8 +4872,6 @@ ev_window_view_toolbar_cb (GtkAction *action, EvWindow *ev_window) update_chrome_visibility (ev_window); if (ev_window->priv->metadata) ev_metadata_set_boolean (ev_window->priv->metadata, "show_toolbar", active); - if (ev_window->priv->document) - g_settings_set_boolean (ev_window->priv->last_settings, "show-toolbar", active); } static void @@ -4332,27 +4890,11 @@ ev_window_sidebar_current_page_changed_cb (EvSidebar *ev_sidebar, GParamSpec *pspec, EvWindow *ev_window) { - GtkWidget *current_page; - const char *id; - - g_object_get (G_OBJECT (ev_sidebar), "current_page", ¤t_page, NULL); - - if (current_page == ev_window->priv->sidebar_links) { - id = LINKS_SIDEBAR_ID; - } else if (current_page == ev_window->priv->sidebar_thumbs) { - id = THUMBNAILS_SIDEBAR_ID; - } else if (current_page == ev_window->priv->sidebar_attachments) { - id = ATTACHMENTS_SIDEBAR_ID; - } else if (current_page == ev_window->priv->sidebar_layers) { - id = LAYERS_SIDEBAR_ID; - } else { - g_assert_not_reached(); + if (ev_window->priv->metadata && !ev_window_is_empty (ev_window)) { + ev_metadata_set_string (ev_window->priv->metadata, + "sidebar_page", + ev_window_sidebar_get_current_page_id (ev_window)); } - - g_object_unref (current_page); - - if (ev_window->priv->metadata && !ev_window_is_empty (ev_window)) - ev_metadata_set_string (ev_window->priv->metadata, "sidebar_page", id); } static void @@ -4372,8 +4914,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 (ev_window->priv->document) - g_settings_set_boolean (ev_window->priv->last_settings, "show-sidebar", visible); + if (!visible) + gtk_widget_grab_focus (ev_window->priv->view); } } @@ -4463,9 +5005,18 @@ view_menu_annot_popup (EvWindow *ev_window, GtkAction *action; gboolean show_annot = FALSE; + if (ev_window->priv->annot) + g_object_unref (ev_window->priv->annot); + ev_window->priv->annot = (annot) ? g_object_ref (annot) : NULL; + + action = gtk_action_group_get_action (ev_window->priv->view_popup_action_group, + "AnnotProperties"); + gtk_action_set_visible (action, (annot != NULL && EV_IS_ANNOTATION_MARKUP (annot))); + if (annot && EV_IS_ANNOTATION_ATTACHMENT (annot)) { - EvAttachment *attachment = EV_ANNOTATION_ATTACHMENT (annot)->attachment; + EvAttachment *attachment; + attachment = ev_annotation_attachment_get_attachment (EV_ANNOTATION_ATTACHMENT (annot)); if (attachment) { show_annot = TRUE; if (ev_window->priv->attach_list) { @@ -4560,17 +5111,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; @@ -4646,30 +5203,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); @@ -4679,12 +5229,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, @@ -4697,11 +5256,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); } @@ -4804,6 +5362,25 @@ ev_window_dispose (GObject *object) window); } +#ifdef ENABLE_DBUS + if (priv->dbus_object_id > 0) { + ev_window_emit_closed (window); + g_dbus_connection_unregister_object (ev_application_get_dbus_connection (EV_APP), + priv->dbus_object_id); + priv->dbus_object_id = 0; + } + + if (priv->dbus_object_path) { + g_free (priv->dbus_object_path); + priv->dbus_object_path = NULL; + } +#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; @@ -4814,13 +5391,6 @@ ev_window_dispose (GObject *object) priv->setup_document_idle = 0; } -#ifdef WITH_GCONF - if (priv->gconf_client) { - g_object_unref (priv->gconf_client); - priv->gconf_client = NULL; - } -#endif - if (priv->monitor) { g_object_unref (priv->monitor); priv->monitor = NULL; @@ -4856,6 +5426,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, @@ -4868,9 +5443,15 @@ ev_window_dispose (GObject *object) priv->settings = NULL; } - if (priv->last_settings) { - g_object_unref (priv->last_settings); - priv->last_settings = NULL; + if (priv->default_settings) { + g_settings_apply (priv->default_settings); + g_object_unref (priv->default_settings); + priv->default_settings = NULL; + } + + if (priv->lockdown_settings) { + g_object_unref (priv->lockdown_settings); + priv->lockdown_settings = NULL; } priv->recent_ui_id = 0; @@ -4941,6 +5522,11 @@ ev_window_dispose (GObject *object) priv->image = NULL; } + if (priv->annot) { + g_object_unref (priv->annot); + priv->annot = NULL; + } + if (priv->attach_list) { g_list_foreach (priv->attach_list, (GFunc) g_object_unref, @@ -5043,6 +5629,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) { @@ -5052,6 +5645,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; @@ -5066,6 +5660,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 */ @@ -5078,6 +5673,9 @@ static const GtkActionEntry entries[] = { { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("_Save a Copy…"), "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…"), "P", N_("Print this document"), G_CALLBACK (ev_window_cmd_file_print) }, @@ -5104,6 +5702,8 @@ static const GtkActionEntry entries[] = { G_CALLBACK (ev_window_cmd_edit_rotate_left) }, { "EditRotateRight", EV_STOCK_ROTATE_RIGHT, N_("Rotate _Right"), "Right", NULL, G_CALLBACK (ev_window_cmd_edit_rotate_right) }, + { "EditSaveSettings", NULL, N_("Save Current Settings as _Default"), "T", NULL, + G_CALLBACK (ev_window_cmd_edit_save_settings) }, /* View menu */ @@ -5134,6 +5734,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"), "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) }, @@ -5250,6 +5855,8 @@ static const GtkActionEntry view_popup_entries [] = { NULL, G_CALLBACK (ev_view_popup_cmd_save_image_as) }, { "CopyImage", NULL, N_("Copy _Image"), NULL, NULL, G_CALLBACK (ev_view_popup_cmd_copy_image) }, + { "AnnotProperties", NULL, N_("Annotation Properties…"), NULL, + NULL, G_CALLBACK (ev_view_popup_cmd_annot_properties) } }; static const GtkActionEntry attachment_popup_entries [] = { @@ -5287,6 +5894,45 @@ sidebar_layers_visibility_changed (EvSidebarLayers *layers, ev_view_reload (EV_VIEW (window->priv->view)); } +static void +sidebar_annots_annot_activated_cb (EvSidebarAnnotations *sidebar_annots, + EvMapping *annot_mapping, + EvWindow *window) +{ + ev_view_focus_annotation (EV_VIEW (window->priv->view), annot_mapping); +} + +static void +sidebar_annots_begin_annot_add (EvSidebarAnnotations *sidebar_annots, + EvAnnotationType annot_type, + EvWindow *window) +{ + ev_view_begin_add_annotation (EV_VIEW (window->priv->view), annot_type); +} + +static void +view_annot_added (EvView *view, + EvAnnotation *annot, + EvWindow *window) +{ + ev_sidebar_annotations_annot_added (EV_SIDEBAR_ANNOTATIONS (window->priv->sidebar_annots), + annot); +} + +static void +sidebar_annots_annot_add_cancelled (EvSidebarAnnotations *sidebar_annots, + EvWindow *window) +{ + 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) { @@ -5352,6 +5998,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*/ @@ -5382,22 +6032,6 @@ set_action_properties (GtkActionGroup *action_group) g_object_set (action, "is-important", TRUE, NULL); } -static void -set_chrome_actions (EvWindow *window) -{ - EvWindowPrivate *priv = window->priv; - GtkActionGroup *action_group = priv->action_group; - GtkAction *action; - - action= gtk_action_group_get_action (action_group, "ViewToolbar"); - g_signal_handlers_block_by_func - (action, G_CALLBACK (ev_window_view_toolbar_cb), window); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), - (priv->chrome & EV_CHROME_TOOLBAR) != 0); - g_signal_handlers_unblock_by_func - (action, G_CALLBACK (ev_window_view_toolbar_cb), window); -} - static void sidebar_widget_model_set (EvSidebarLinks *ev_sidebar_links, GParamSpec *pspec, @@ -5426,7 +6060,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); @@ -5492,7 +6127,7 @@ window_configure_event_cb (EvWindow *window, GdkEventConfigure *event, gpointer if (window->priv->document) { ev_document_get_max_page_size (window->priv->document, &document_width, &document_height); - g_settings_set (window->priv->last_settings, "window-ratio", "(dd)", + g_settings_set (window->priv->default_settings, "window-ratio", "(dd)", (double)event->width / document_width, (double)event->height / document_height); @@ -5670,7 +6305,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: { @@ -5736,6 +6371,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, @@ -5747,7 +6406,6 @@ image_save_dialog_response_cb (GtkWidget *fc, GError *error = NULL; GdkPixbuf *pixbuf; gchar *uri; - gchar **extensions; gchar *filename; gchar *file_format; GdkPixbufFormat *format; @@ -5785,19 +6443,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); @@ -5898,6 +6546,67 @@ ev_view_popup_cmd_copy_image (GtkAction *action, EvWindow *window) g_object_unref (pixbuf); } +static void +ev_view_popup_cmd_annot_properties (GtkAction *action, + EvWindow *window) +{ + const gchar *author; + GdkColor color; + gdouble opacity; + gboolean popup_is_open; + EvAnnotationPropertiesDialog *dialog; + EvAnnotation *annot = window->priv->annot; + EvAnnotationsSaveMask mask = EV_ANNOTATIONS_SAVE_NONE; + + if (!annot) + return; + + dialog = EV_ANNOTATION_PROPERTIES_DIALOG (ev_annotation_properties_dialog_new_with_annotation (window->priv->annot)); + if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_APPLY) { + gtk_widget_destroy (GTK_WIDGET (dialog)); + + return; + } + + /* Set annotations changes */ + author = ev_annotation_properties_dialog_get_author (dialog); + if (ev_annotation_markup_set_label (EV_ANNOTATION_MARKUP (annot), author)) + mask |= EV_ANNOTATIONS_SAVE_LABEL; + + ev_annotation_properties_dialog_get_color (dialog, &color); + if (ev_annotation_set_color (annot, &color)) + mask |= EV_ANNOTATIONS_SAVE_COLOR; + + opacity = ev_annotation_properties_dialog_get_opacity (dialog); + if (ev_annotation_markup_set_opacity (EV_ANNOTATION_MARKUP (annot), opacity)) + mask |= EV_ANNOTATIONS_SAVE_OPACITY; + + popup_is_open = ev_annotation_properties_dialog_get_popup_is_open (dialog); + if (ev_annotation_markup_set_popup_is_open (EV_ANNOTATION_MARKUP (annot), popup_is_open)) + mask |= EV_ANNOTATIONS_SAVE_POPUP_IS_OPEN; + + if (EV_IS_ANNOTATION_TEXT (annot)) { + EvAnnotationTextIcon icon; + + icon = ev_annotation_properties_dialog_get_text_icon (dialog); + if (ev_annotation_text_set_icon (EV_ANNOTATION_TEXT (annot), icon)) + mask |= EV_ANNOTATIONS_SAVE_TEXT_ICON; + } + + if (mask != EV_ANNOTATIONS_SAVE_NONE) { + ev_document_doc_mutex_lock (); + ev_document_annotations_save_annotation (EV_DOCUMENT_ANNOTATIONS (window->priv->document), + window->priv->annot, + mask); + ev_document_doc_mutex_unlock (); + + /* FIXME: update annot region only */ + ev_view_reload (EV_VIEW (window->priv->view)); + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + static void ev_attachment_popup_cmd_open_attachment (GtkAction *action, EvWindow *window) { @@ -6064,9 +6773,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) { @@ -6120,6 +6835,186 @@ get_toolbars_model (void) return toolbars_model; } +#ifdef ENABLE_DBUS +static void +ev_window_sync_source (EvWindow *window, + EvSourceLink *link) +{ + GDBusConnection *connection; + GError *error = NULL; + guint32 timestamp; + gchar *uri_input; + GFile *input_gfile; + + if (window->priv->dbus_object_id <= 0) + return; + + connection = ev_application_get_dbus_connection (EV_APP); + 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)u)", + uri_input, + link->line, + link->col, + timestamp), + &error); + g_free (uri_input); + if (error) { + g_printerr ("Failed to emit DBus signal SyncSource: %s\n", + error->message); + g_error_free (error); + } +} + +static void +ev_window_emit_closed (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, + "Closed", + NULL, + &error); + if (error) { + g_printerr ("Failed to emit DBus signal Closed: %s\n", + error->message); + g_error_free (error); + + return; + } + + /* If this is the last window call g_dbus_connection_flush_sync() + * to make sure the signal is emitted. + */ + if (ev_application_get_n_windows (EV_APP) == 1) + 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, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + EvWindow *window = EV_WINDOW (user_data); + + if (g_strcmp0 (method_name, "SyncView") != 0) + return; + + if (window->priv->document && ev_document_has_synctex (window->priv->document)) { + EvSourceLink link; + guint32 timestamp; + + g_variant_get (parameters, "(&s(ii)u)", &link.filename, &link.line, &link.col, ×tamp); + ev_view_highlight_forward_search (EV_VIEW (window->priv->view), &link); + gtk_window_present_with_time (GTK_WINDOW (window), timestamp); + } + + g_dbus_method_invocation_return_value (invocation, g_variant_new ("()")); +} + +static const char introspection_xml[] = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + +static const GDBusInterfaceVTable interface_vtable = { + method_call_cb, + NULL, + NULL +}; + +static GDBusNodeInfo *introspection_data; +#endif /* ENABLE_DBUS */ + static void ev_window_init (EvWindow *ev_window) { @@ -6131,7 +7026,10 @@ ev_window_init (EvWindow *ev_window) EggToolbarsModel *toolbars_model; GObject *mpkeys; gchar *ui_path; - gdouble dpi; +#ifdef ENABLE_DBUS + GDBusConnection *connection; + static gint window_id = 0; +#endif g_signal_connect (ev_window, "configure_event", G_CALLBACK (window_configure_event_cb), NULL); @@ -6140,6 +7038,35 @@ ev_window_init (EvWindow *ev_window) ev_window->priv = EV_WINDOW_GET_PRIVATE (ev_window); +#ifdef ENABLE_DBUS + connection = ev_application_get_dbus_connection (EV_APP); + if (connection) { + if (!introspection_data) { + introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, &error); + if (error) g_warning ("%s\n", error->message); + } + g_assert (introspection_data != NULL); + + ev_window->priv->dbus_object_path = g_strdup_printf (EV_WINDOW_DBUS_OBJECT_PATH, window_id++); + ev_window->priv->dbus_object_id = + g_dbus_connection_register_object (connection, + ev_window->priv->dbus_object_path, + introspection_data->interfaces[0], + &interface_vtable, + ev_window, NULL, + &error); + if (ev_window->priv->dbus_object_id == 0) { + g_printerr ("Failed to register bus object %s: %s\n", + ev_window->priv->dbus_object_path, error->message); + g_error_free (error); + g_free (ev_window->priv->dbus_object_path); + ev_window->priv->dbus_object_path = NULL; + error = NULL; + } + } + +#endif /* ENABLE_DBUS */ + ev_window->priv->model = ev_document_model_new (); ev_window->priv->page_mode = PAGE_MODE_DOCUMENT; @@ -6228,6 +7155,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), @@ -6236,7 +7167,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), @@ -6302,6 +7233,34 @@ ev_window_init (EvWindow *ev_window) ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar), sidebar_widget); + sidebar_widget = ev_sidebar_annotations_new (); + ev_window->priv->sidebar_annots = sidebar_widget; + g_signal_connect (sidebar_widget, + "annot_activated", + G_CALLBACK (sidebar_annots_annot_activated_cb), + ev_window); + g_signal_connect (sidebar_widget, + "begin_annot_add", + G_CALLBACK (sidebar_annots_begin_annot_add), + ev_window); + g_signal_connect (sidebar_widget, + "annot_add_cancelled", + G_CALLBACK (sidebar_annots_annot_add_cancelled), + ev_window); + gtk_widget_show (sidebar_widget); + 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, @@ -6317,10 +7276,9 @@ ev_window_init (EvWindow *ev_window) gtk_widget_show (ev_window->priv->view_box); ev_window->priv->view = ev_view_new (); + ev_view_set_page_cache_size (EV_VIEW (ev_window->priv->view), PAGE_CACHE_SIZE); ev_view_set_model (EV_VIEW (ev_window->priv->view), ev_window->priv->model); - dpi = get_screen_dpi (ev_window); - ev_document_model_set_min_scale (ev_window->priv->model, MIN_SCALE * dpi / 72.0); - ev_document_model_set_max_scale (ev_window->priv->model, MAX_SCALE * dpi / 72.0); + ev_window->priv->password_view = ev_password_view_new (GTK_WINDOW (ev_window)); g_signal_connect_swapped (ev_window->priv->password_view, "unlock", @@ -6332,9 +7290,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); @@ -6344,6 +7302,17 @@ ev_window_init (EvWindow *ev_window) g_signal_connect_object (ev_window->priv->view, "selection-changed", G_CALLBACK (view_selection_changed_cb), ev_window, 0); + 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), + ev_window); +#endif gtk_widget_show (ev_window->priv->view); gtk_widget_show (ev_window->priv->password_view); @@ -6454,7 +7423,8 @@ ev_window_init (EvWindow *ev_window) /* Give focus to the document view */ gtk_widget_grab_focus (ev_window->priv->view); - ev_window->priv->last_settings = g_settings_new (GS_SCHEMA_NAME".Default"); + ev_window->priv->default_settings = g_settings_new (GS_SCHEMA_NAME".Default"); + g_settings_delay (ev_window->priv->default_settings); /* Set it user interface params */ ev_window_setup_recent (ev_window); @@ -6462,7 +7432,7 @@ ev_window_init (EvWindow *ev_window) ev_window_setup_gtk_settings (ev_window); setup_chrome_from_metadata (ev_window); - set_chrome_actions (ev_window); + update_chrome_actions (ev_window); update_chrome_visibility (ev_window); gtk_window_set_default_size (GTK_WINDOW (ev_window), 600, 600); @@ -6499,3 +7469,13 @@ ev_window_new (void) return ev_window; } + +const gchar * +ev_window_get_dbus_object_path (EvWindow *ev_window) +{ +#ifdef ENABLE_DBUS + return ev_window->priv->dbus_object_path; +#else + return NULL; +#endif +}