+ g_object_get (G_OBJECT (ev_sidebar_links),
+ "model", &model,
+ NULL);
+
+ action = gtk_action_group_get_action (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
+ ev_page_action_set_links_model (EV_PAGE_ACTION (action), model);
+ g_object_unref (model);
+}
+
+static gboolean
+view_actions_focus_in_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *window)
+{
+#ifdef ENABLE_DBUS
+ GObject *keys;
+
+ keys = ev_application_get_media_keys (EV_APP);
+ ev_media_player_keys_focused (EV_MEDIA_PLAYER_KEYS (keys));
+#endif /* ENABLE_DBUS */
+
+ update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, FALSE);
+ ev_window_set_action_sensitive (window, "ViewToolbar", TRUE);
+
+ ev_window_set_view_accels_sensitivity (window, TRUE);
+
+ update_chrome_visibility (window);
+
+ return FALSE;
+}
+
+static gboolean
+view_actions_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *window)
+{
+ ev_window_set_view_accels_sensitivity (window, FALSE);
+
+ return FALSE;
+}
+
+static void
+sidebar_page_main_widget_update_cb (GObject *ev_sidebar_page,
+ GParamSpec *pspec,
+ EvWindow *ev_window)
+{
+ GtkWidget *widget;
+
+ g_object_get (ev_sidebar_page, "main_widget", &widget, NULL);
+
+ if (widget != NULL) {
+ g_signal_connect_object (widget, "focus_in_event",
+ G_CALLBACK (view_actions_focus_in_cb),
+ ev_window, 0);
+ g_signal_connect_object (widget, "focus_out_event",
+ G_CALLBACK (view_actions_focus_out_cb),
+ ev_window, 0);
+ g_object_unref (widget);
+ }
+}
+
+static gboolean
+window_state_event_cb (EvWindow *window, GdkEventWindowState *event, gpointer dummy)
+{
+ if (!(event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
+ gboolean maximized;
+
+ maximized = event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED;
+ if (window->priv->metadata && !ev_window_is_empty (window))
+ ev_metadata_set_boolean (window->priv->metadata, "window_maximized", maximized);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+window_configure_event_cb (EvWindow *window, GdkEventConfigure *event, gpointer dummy)
+{
+ GdkWindowState state;
+ gdouble document_width, document_height;
+
+ if (!window->priv->metadata)
+ return FALSE;
+
+ state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
+
+ if (!(state & GDK_WINDOW_STATE_FULLSCREEN)) {
+ if (window->priv->document) {
+ ev_document_get_max_page_size (window->priv->document,
+ &document_width, &document_height);
+ g_settings_set (window->priv->default_settings, "window-ratio", "(dd)",
+ (double)event->width / document_width,
+ (double)event->height / document_height);
+
+ ev_metadata_set_int (window->priv->metadata, "window_x", event->x);
+ ev_metadata_set_int (window->priv->metadata, "window_y", event->y);
+ ev_metadata_set_int (window->priv->metadata, "window_width", event->width);
+ ev_metadata_set_int (window->priv->metadata, "window_height", event->height);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+launch_action (EvWindow *window, EvLinkAction *action)
+{
+ const char *filename = ev_link_action_get_filename (action);
+ GAppInfo *app_info;
+ GFile *file;
+ GList file_list = {NULL};
+ GAppLaunchContext *context;
+ GError *error = NULL;
+
+ if (filename == NULL)
+ return;
+
+ if (g_path_is_absolute (filename)) {
+ file = g_file_new_for_path (filename);
+ } else {
+ GFile *base_file;
+ gchar *dir;
+
+ dir = g_path_get_dirname (window->priv->uri);
+ base_file = g_file_new_for_uri (dir);
+ g_free (dir);
+
+ file = g_file_resolve_relative_path (base_file, filename);
+ g_object_unref (base_file);
+ }
+
+ app_info = g_file_query_default_handler (file, NULL, &error);
+ if (!app_info) {
+ ev_window_error_message (window, error,
+ "%s",
+ _("Unable to launch external application."));
+ g_object_unref (file);
+ g_error_free (error);
+
+ return;
+ }
+
+ context = G_APP_LAUNCH_CONTEXT (gdk_app_launch_context_new ());
+ gdk_app_launch_context_set_screen (GDK_APP_LAUNCH_CONTEXT (context),
+ gtk_window_get_screen (GTK_WINDOW (window)));
+ gdk_app_launch_context_set_timestamp (GDK_APP_LAUNCH_CONTEXT (context),
+ gtk_get_current_event_time ());
+
+ file_list.data = file;
+ if (!g_app_info_launch (app_info, &file_list, context, &error)) {
+ ev_window_error_message (window, error,
+ "%s",
+ _("Unable to launch external application."));
+ g_error_free (error);
+ }
+
+ g_object_unref (app_info);
+ g_object_unref (file);
+ /* FIXMEchpe: unref launch context? */
+
+ /* According to the PDF spec filename can be an executable. I'm not sure
+ allowing to launch executables is a good idea though. -- marco */
+}
+
+static void
+launch_external_uri (EvWindow *window, EvLinkAction *action)
+{
+ const gchar *uri = ev_link_action_get_uri (action);
+ GError *error = NULL;
+ gboolean ret;
+ GAppLaunchContext *context;
+
+ context = G_APP_LAUNCH_CONTEXT (gdk_app_launch_context_new ());
+ gdk_app_launch_context_set_screen (GDK_APP_LAUNCH_CONTEXT (context),
+ gtk_window_get_screen (GTK_WINDOW (window)));
+ gdk_app_launch_context_set_timestamp (GDK_APP_LAUNCH_CONTEXT (context),
+ gtk_get_current_event_time ());
+
+ if (!g_strstr_len (uri, strlen (uri), "://") &&
+ !g_str_has_prefix (uri, "mailto:")) {
+ gchar *new_uri;
+
+ /* Not a valid uri, assume http if it starts with www */
+ if (g_str_has_prefix (uri, "www.")) {
+ new_uri = g_strdup_printf ("http://%s", uri);
+ } else {
+ GFile *file, *parent;
+
+ file = g_file_new_for_uri (window->priv->uri);
+ parent = g_file_get_parent (file);
+ g_object_unref (file);
+ if (parent) {
+ gchar *parent_uri = g_file_get_uri (parent);
+
+ new_uri = g_build_filename (parent_uri, uri, NULL);
+ g_free (parent_uri);
+ g_object_unref (parent);
+ } else {
+ new_uri = g_strdup_printf ("file:///%s", uri);
+ }
+ }
+ ret = g_app_info_launch_default_for_uri (new_uri, context, &error);
+ g_free (new_uri);
+ } else {
+ ret = g_app_info_launch_default_for_uri (uri, context, &error);
+ }
+
+ if (ret == FALSE) {
+ ev_window_error_message (window, error,
+ "%s", _("Unable to open external link"));
+ g_error_free (error);
+ }
+
+ /* FIXMEchpe: unref launch context? */
+}
+
+static void
+open_remote_link (EvWindow *window, EvLinkAction *action)
+{
+ gchar *uri;
+ gchar *dir;
+
+ dir = g_path_get_dirname (window->priv->uri);
+
+ uri = g_build_filename (dir, ev_link_action_get_filename (action),
+ NULL);
+ g_free (dir);
+
+ ev_application_open_uri_at_dest (EV_APP, uri,
+ gtk_window_get_screen (GTK_WINDOW (window)),
+ ev_link_action_get_dest (action),
+ 0,
+ NULL,
+ gtk_get_current_event_time ());
+
+ g_free (uri);
+}
+
+static void
+do_action_named (EvWindow *window, EvLinkAction *action)
+{
+ const gchar *name = ev_link_action_get_name (action);
+
+ if (g_ascii_strcasecmp (name, "FirstPage") == 0) {
+ ev_window_cmd_go_first_page (NULL, window);
+ } else if (g_ascii_strcasecmp (name, "PrevPage") == 0) {
+ ev_window_cmd_go_previous_page (NULL, window);
+ } else if (g_ascii_strcasecmp (name, "NextPage") == 0) {
+ ev_window_cmd_go_next_page (NULL, window);
+ } else if (g_ascii_strcasecmp (name, "LastPage") == 0) {
+ ev_window_cmd_go_last_page (NULL, window);
+ } else if (g_ascii_strcasecmp (name, "GoToPage") == 0) {
+ ev_window_cmd_focus_page_selector (NULL, window);
+ } else if (g_ascii_strcasecmp (name, "Find") == 0) {
+ ev_window_cmd_edit_find (NULL, window);
+ } else if (g_ascii_strcasecmp (name, "Close") == 0) {
+ ev_window_cmd_file_close_window (NULL, window);
+ } else if (g_ascii_strcasecmp (name, "Print") == 0) {
+ ev_window_cmd_file_print (NULL, window);
+ } else {
+ g_warning ("Unimplemented named action: %s, please post a "
+ "bug report in Evince bugzilla "
+ "(http://bugzilla.gnome.org) with a testcase.",
+ name);
+ }
+}
+
+static void
+view_external_link_cb (EvView *view, EvLinkAction *action, EvWindow *window)
+{
+ switch (ev_link_action_get_action_type (action)) {
+ case EV_LINK_ACTION_TYPE_GOTO_DEST: {
+ EvLinkDest *dest;
+
+ dest = ev_link_action_get_dest (action);
+ if (!dest)
+ return;
+
+ ev_window_open_copy_at_dest (window, dest);
+ }
+ break;
+ case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
+ launch_external_uri (window, action);
+ break;
+ case EV_LINK_ACTION_TYPE_LAUNCH:
+ launch_action (window, action);
+ break;
+ case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
+ open_remote_link (window, action);
+ break;
+ case EV_LINK_ACTION_TYPE_NAMED:
+ do_action_named (window, action);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+ev_view_popup_cmd_open_link (GtkAction *action, EvWindow *window)
+{
+ ev_view_handle_link (EV_VIEW (window->priv->view), window->priv->link);
+}
+
+static void
+ev_view_popup_cmd_open_link_new_window (GtkAction *action, EvWindow *window)
+{
+ EvLinkAction *ev_action = NULL;
+ EvLinkDest *dest;
+
+ ev_action = ev_link_get_action (window->priv->link);
+ if (!ev_action)
+ return;
+
+ dest = ev_link_action_get_dest (ev_action);
+ if (!dest)
+ return;
+
+ ev_window_open_copy_at_dest (window, dest);
+}
+
+static void
+ev_view_popup_cmd_copy_link_address (GtkAction *action, EvWindow *window)
+{
+ EvLinkAction *ev_action;
+
+ ev_action = ev_link_get_action (window->priv->link);
+ if (!ev_action)
+ return;
+
+ ev_view_copy_link_address (EV_VIEW (window->priv->view),
+ ev_action);
+}
+
+
+static void
+image_save_dialog_response_cb (GtkWidget *fc,
+ gint response_id,
+ EvWindow *ev_window)
+{
+ GFile *target_file;
+ gboolean is_native;
+ GError *error = NULL;
+ GdkPixbuf *pixbuf;
+ gchar *uri;
+ gchar **extensions;
+ gchar *filename;
+ gchar *file_format;
+ GdkPixbufFormat *format;
+ GtkFileFilter *filter;
+
+ if (response_id != GTK_RESPONSE_OK) {
+ gtk_widget_destroy (fc);
+ return;
+ }
+
+ uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
+ filter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (fc));
+ format = g_object_get_data (G_OBJECT (filter), "pixbuf-format");
+
+ if (format == NULL) {
+ format = get_gdk_pixbuf_format_by_extension (uri);
+ }
+
+ if (format == NULL && g_strrstr (uri, ".") == NULL) {
+ /* no extension found and no extension provided within uri */
+ format = get_gdk_pixbuf_format_by_extension (".png");
+ if (format == NULL) {
+ /* no .png support, try .jpeg */
+ format = get_gdk_pixbuf_format_by_extension (".jpeg");
+ }
+ }
+
+ if (format == NULL) {
+ ev_window_error_message (ev_window, NULL,
+ "%s",
+ _("Couldn't find appropriate format to save image"));
+ g_free (uri);
+ gtk_widget_destroy (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);
+ g_free (uri);
+
+ is_native = g_file_is_native (target_file);
+ if (is_native) {
+ filename = g_file_get_path (target_file);
+ } else {
+ /* Create a temporary local file to save to */
+ if (ev_mkstemp ("saveimage.XXXXXX", &filename, &error) == -1)
+ goto has_error;
+ }
+
+ ev_document_doc_mutex_lock ();
+ pixbuf = ev_document_images_get_image (EV_DOCUMENT_IMAGES (ev_window->priv->document),
+ ev_window->priv->image);
+ ev_document_doc_mutex_unlock ();
+
+ file_format = gdk_pixbuf_format_get_name (format);
+ gdk_pixbuf_save (pixbuf, filename, file_format, &error, NULL);
+ g_free (file_format);
+ g_object_unref (pixbuf);
+
+ has_error:
+ if (error) {
+ ev_window_error_message (ev_window, error,
+ "%s", _("The image could not be saved."));
+ g_error_free (error);
+ g_free (filename);
+ g_object_unref (target_file);
+ gtk_widget_destroy (fc);
+
+ return;
+ }
+
+ if (!is_native) {
+ GFile *source_file;
+
+ source_file = g_file_new_for_path (filename);
+
+ ev_window_save_remote (ev_window, EV_SAVE_IMAGE,
+ source_file, target_file);
+ g_object_unref (source_file);
+ }
+
+ g_free (filename);
+ g_object_unref (target_file);
+ gtk_widget_destroy (fc);
+}
+
+static void
+ev_view_popup_cmd_save_image_as (GtkAction *action, EvWindow *window)
+{
+ GtkWidget *fc;
+
+ if (!window->priv->image)
+ return;
+
+ fc = gtk_file_chooser_dialog_new (_("Save Image"),
+ GTK_WINDOW (window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (fc), GTK_RESPONSE_OK);
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (fc),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (fc), FALSE);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (fc), TRUE);
+
+ file_chooser_dialog_add_writable_pixbuf_formats (GTK_FILE_CHOOSER (fc));
+
+ g_signal_connect (fc, "response",
+ G_CALLBACK (image_save_dialog_response_cb),
+ window);
+
+ gtk_widget_show (fc);