]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-application.c
Fix indentation
[evince.git] / shell / ev-application.c
index 5a9bb8a55da0fc7c4a1e4abaa6273981daad6a0d..600880a1e6ad86dd2d8eff036493fcfcc07505da 100644 (file)
@@ -91,8 +91,6 @@ G_DEFINE_TYPE (EvApplication, ev_application, G_TYPE_OBJECT);
 #define EVINCE_DAEMON_INTERFACE      "org.gnome.evince.Daemon"
 #endif
 
-static const gchar *userdir = NULL;
-
 static void _ev_application_open_uri_at_dest (EvApplication  *application,
                                              const gchar    *uri,
                                              GdkScreen      *screen,
@@ -223,17 +221,6 @@ ev_display_open_if_needed (const gchar *name)
        return display != NULL ? display : gdk_display_open (name);
 }
 
-static void
-child_setup (gpointer user_data)
-{
-       gchar *startup_id;
-
-       startup_id = g_strdup_printf ("_TIME%lu",
-                                     (unsigned long)GPOINTER_TO_INT (user_data));
-       g_setenv ("DESKTOP_STARTUP_ID", startup_id, TRUE);
-       g_free (startup_id);
-}
-
 static void
 ev_spawn (const char     *uri,
          GdkScreen      *screen,
@@ -242,69 +229,91 @@ ev_spawn (const char     *uri,
          const gchar    *search_string,
          guint           timestamp)
 {
-       gchar   *argv[6];
-       guint    arg = 0;
-       gint     i;
-       gboolean res;
+       GString *cmd;
+       gchar *path, *cmdline;
+       GAppInfo *app;
+       GdkAppLaunchContext *ctx;
        GError  *error = NULL;
 
+       cmd = g_string_new (NULL);
+
 #ifdef G_OS_WIN32
 {
        gchar *dir;
 
        dir = g_win32_get_package_installation_directory_of_module (NULL);
-       argv[arg++] = g_build_filename (dir, "bin", "evince", NULL);
+       path = g_build_filename (dir, "bin", "evince", NULL);
+
        g_free (dir);
 }
 #else
-       argv[arg++] = g_build_filename (BINDIR, "evince", NULL);
+       path = g_build_filename (BINDIR, "evince", NULL);
 #endif
 
+       g_string_append_printf (cmd, " %s", path);
+       g_free (path);
+       
        /* Page label */
        if (dest) {
                const gchar *page_label;
 
                page_label = ev_link_dest_get_page_label (dest);
+
                if (page_label)
-                       argv[arg++] = g_strdup_printf ("--page-label=%s", page_label);
+                       g_string_append_printf (cmd, " --page-label=%s", page_label);
                else
-                       argv[arg++] = g_strdup_printf ("--page-label=%d",
-                                                      ev_link_dest_get_page (dest));
+                       g_string_append_printf (cmd, " --page-label=%d",
+                                               ev_link_dest_get_page (dest));
        }
 
        /* Find string */
        if (search_string) {
-               argv[arg++] = g_strdup_printf ("--find=%s", search_string);
+               g_string_append_printf (cmd, " --find=%s", search_string);
        }
 
        /* Mode */
        switch (mode) {
        case EV_WINDOW_MODE_FULLSCREEN:
-               argv[arg++] = g_strdup ("-f");
+               g_string_append (cmd, " -f");
                break;
        case EV_WINDOW_MODE_PRESENTATION:
-               argv[arg++] = g_strdup ("-s");
+               g_string_append (cmd, " -s");
                break;
        default:
                break;
        }
 
-       argv[arg++] = (gchar *)uri;
-       argv[arg] = NULL;
+       cmdline = g_string_free (cmd, FALSE);
+       app = g_app_info_create_from_commandline (cmdline, NULL, 0, &error);
+
+       if (app != NULL) {
+                GList uri_list;
+
+               ctx = gdk_display_get_app_launch_context (gdk_screen_get_display (screen));
+               gdk_app_launch_context_set_screen (ctx, screen);
+               gdk_app_launch_context_set_timestamp (ctx, timestamp);
+
+                /* Some URIs can be changed when passed through a GFile
+                 * (for instance unsupported uris with strange formats like mailto:),
+                 * so if you have a textual uri you want to pass in as argument,
+                 * consider using g_app_info_launch_uris() instead.
+                 * See https://bugzilla.gnome.org/show_bug.cgi?id=644604
+                 */
+                uri_list.data = (gchar *)uri;
+                uri_list.prev = uri_list.next = NULL;
+               g_app_info_launch_uris (app, &uri_list,
+                                        G_APP_LAUNCH_CONTEXT (ctx), &error);
+
+               g_object_unref (app);
+               g_object_unref (ctx);
+       }
 
-       res = gdk_spawn_on_screen (screen, NULL /* wd */, argv, NULL /* env */,
-                                  0,
-                                  child_setup,
-                                  GINT_TO_POINTER(timestamp),
-                                  NULL, &error);
-       if (!res) {
+       if (error != NULL) {
                g_warning ("Error launching evince %s: %s\n", uri, error->message);
                g_error_free (error);
        }
 
-       for (i = 0; i < arg - 1; i++) {
-               g_free (argv[i]);
-       }
+       g_free (cmdline);
 }
 
 static GList *
@@ -376,9 +385,9 @@ ev_register_doc_data_free (EvRegisterDocData *data)
 }
 
 static void
-on_open_uri_cb (GObject      *source_object,
-               GAsyncResult *res,
-               gpointer      user_data)
+on_reload_cb (GObject      *source_object,
+             GAsyncResult *res,
+             gpointer      user_data)
 {
        GDBusConnection *connection = G_DBUS_CONNECTION (source_object);
        GVariant        *value;
@@ -386,11 +395,15 @@ on_open_uri_cb (GObject      *source_object,
 
        value = g_dbus_connection_call_finish (connection, res, &error);
        if (!value) {
-               g_warning ("Failed to OpenURI: %s", error->message);
+               g_warning ("Failed to Reload: %s", error->message);
                g_error_free (error);
        }
        g_variant_unref (value);
 
+       /* We did not open a window, so manually clear the startup
+        * notification. */
+       gdk_notify_startup_complete ();
+
        ev_application_shutdown (EV_APP);
 }
 
@@ -447,9 +460,7 @@ on_register_uri_cb (GObject      *source_object,
         }
 
        /* Already registered */
-       g_variant_builder_init (&builder, G_VARIANT_TYPE ("(sa{sv}u)"));
-        g_variant_builder_add (&builder, "s", data->uri);
-
+       g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a{sv}u)"));
         g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
         g_variant_builder_add (&builder, "{sv}",
                                "display",
@@ -458,9 +469,17 @@ on_register_uri_cb (GObject      *source_object,
                                "screen",
                                g_variant_new_int32 (gdk_screen_get_number (data->screen)));
        if (data->dest) {
-                g_variant_builder_add (&builder, "{sv}",
-                                       "page-label",
-                                       g_variant_new_string (ev_link_dest_get_page_label (data->dest)));
+                const gchar *page_label = ev_link_dest_get_page_label (data->dest);
+
+                if (page_label) {
+                        g_variant_builder_add (&builder, "{sv}",
+                                               "page-label",
+                                               g_variant_new_string (page_label));
+                } else {
+                        g_variant_builder_add (&builder, "{sv}",
+                                               "page-index",
+                                               g_variant_new_uint32 (ev_link_dest_get_page (data->dest)));
+                }
        }
        if (data->search_string) {
                 g_variant_builder_add (&builder, "{sv}",
@@ -480,13 +499,13 @@ on_register_uri_cb (GObject      *source_object,
                                owner,
                                APPLICATION_DBUS_OBJECT_PATH,
                                APPLICATION_DBUS_INTERFACE,
-                               "OpenURI",
+                               "Reload",
                                g_variant_builder_end (&builder),
                                NULL,
                                G_DBUS_CALL_FLAGS_NONE,
                                -1,
                                NULL,
-                               on_open_uri_cb,
+                               on_reload_cb,
                                NULL);
        g_variant_unref (value);
        ev_register_doc_data_free (data);
@@ -682,7 +701,7 @@ ev_application_open_uri_at_dest (EvApplication  *application,
        }
 
 #ifdef ENABLE_DBUS
-       /* Register the uri or send OpenURI to
+       /* Register the uri or send Reload to
         * remote instance if already registered
         */
        ev_application_register_uri (application, uri, screen, dest, mode, search_string, timestamp);
@@ -742,7 +761,6 @@ method_call_cb (GDBusConnection       *connection,
 {
         EvApplication   *application = EV_APPLICATION (user_data);
        GList           *windows, *l;
-        const gchar     *uri;
         guint            timestamp;
         GVariantIter    *iter;
         const gchar     *key;
@@ -754,72 +772,80 @@ method_call_cb (GDBusConnection       *connection,
        const gchar     *search_string = NULL;
        GdkScreen       *screen = NULL;
 
-        if (g_strcmp0 (method_name, "OpenURI") != 0)
-                return;
+       if (g_strcmp0 (method_name, "Reload") == 0) {
+               g_variant_get (parameters, "(a{sv}u)", &iter, &timestamp);
+
+               while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) {
+                       if (strcmp (key, "display") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
+                               display = ev_display_open_if_needed (g_variant_get_string (value, NULL));
+                       } else if (strcmp (key, "screen") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_INT32) {
+                               screen_number = g_variant_get_int32 (value);
+                       } else if (strcmp (key, "mode") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_UINT32) {
+                                mode = g_variant_get_uint32 (value);
+                       } else if (strcmp (key, "page-label") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
+                               dest = ev_link_dest_new_page_label (g_variant_get_string (value, NULL));
+                        } else if (strcmp (key, "page-index") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_UINT32) {
+                                dest = ev_link_dest_new_page (g_variant_get_uint32 (value));
+                       } else if (strcmp (key, "find-string") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
+                               search_string = g_variant_get_string (value, NULL);
+                       }
+               }
+               g_variant_iter_free (iter);
 
-        g_variant_get (parameters, "(&sa{sv}u)", &uri, &iter, &timestamp);
+               if (display != NULL &&
+                   screen_number >= 0 &&
+                   screen_number < gdk_display_get_n_screens (display))
+                       screen = gdk_display_get_screen (display, screen_number);
+               else
+                       screen = gdk_screen_get_default ();
 
-       /* FIXME: we don't need uri anymore,
-        * maybe this method should be renamed
-        * as reload, refresh or something like that
-        */
-       if (g_strcmp0 (application->uri, uri) != 0) {
-                g_dbus_method_invocation_return_error (invocation,
-                                                       G_DBUS_ERROR,
-                                                       G_DBUS_ERROR_INVALID_ARGS,
-                                                       "Unexpected URI \"%s\"",
-                                                       uri);
-                g_variant_iter_free (iter);
-               return;
-       }
+               windows = ev_application_get_windows (application);
+               for (l = windows; l != NULL; l = g_list_next (l)) {
+                       EvWindow *ev_window = EV_WINDOW (l->data);
 
-        while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) {
-                if (strcmp (key, "display") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
-                        display = ev_display_open_if_needed (g_variant_get_string (value, NULL));
-                } else if (strcmp (key, "screen") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
-                        screen_number = g_variant_get_int32 (value);
-                } else if (strcmp (key, "mode") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_UINT32) {
-                        mode = g_variant_get_uint32 (value);
-                } else if (strcmp (key, "page-label") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
-                        dest = ev_link_dest_new_page_label (g_variant_get_string (value, NULL));
-                } else if (strcmp (key, "find-string") == 0 && g_variant_classify (value) == G_VARIANT_CLASS_STRING) {
-                        search_string = g_variant_get_string (value, NULL);
-                }
-        }
-        g_variant_iter_free (iter);
-
-        if (display != NULL &&
-            screen_number >= 0 &&
-            screen_number < gdk_display_get_n_screens (display))
-                screen = gdk_display_get_screen (display, screen_number);
-        else
-                screen = gdk_screen_get_default ();
-
-       windows = ev_application_get_windows (application);
-       for (l = windows; l != NULL; l = g_list_next (l)) {
-               EvWindow *ev_window = EV_WINDOW (l->data);
-
-               ev_application_open_uri_in_window (application, uri, ev_window,
-                                                  screen, dest, mode,
-                                                  search_string,
-                                                  timestamp);
-       }
-       g_list_free (windows);
+                       ev_application_open_uri_in_window (application, application->uri,
+                                                          ev_window,
+                                                          screen, dest, mode,
+                                                          search_string,
+                                                          timestamp);
+               }
+               g_list_free (windows);
+
+               if (dest)
+                       g_object_unref (dest);
+
+               g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+       } else if (g_strcmp0 (method_name, "GetWindowList") == 0) {
+               GList          *windows = ev_application_get_windows (application);
+               GVariantBuilder builder;
+               GList          *l;
 
-       if (dest)
-               g_object_unref (dest);
+               g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ao)"));
+               g_variant_builder_open (&builder, G_VARIANT_TYPE ("ao"));
 
-       g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+               for (l = windows; l; l = g_list_next (l)) {
+                       EvWindow *window = (EvWindow *)l->data;
+
+                       g_variant_builder_add (&builder, "o", ev_window_get_dbus_object_path (window));
+               }
+
+               g_variant_builder_close (&builder);
+               g_list_free (windows);
+
+               g_dbus_method_invocation_return_value (invocation, g_variant_builder_end (&builder));
+       }
 }
 
 static const char introspection_xml[] =
         "<node>"
           "<interface name='org.gnome.evince.Application'>"
-            "<method name='OpenURI'>"
-              "<arg type='s' name='uri' direction='in'/>"
+            "<method name='Reload'>"
               "<arg type='a{sv}' name='args' direction='in'/>"
               "<arg type='u' name='timestamp' direction='in'/>"
             "</method>"
+            "<method name='GetWindowList'>"
+              "<arg type='ao' name='window_list' direction='out'/>"
+            "</method>"
           "</interface>"
         "</node>";
 
@@ -854,15 +880,7 @@ ev_application_accel_map_save (EvApplication *application)
        gchar *tmp_filename;
        gint   fd;
 
-       if (userdir) {
-               accel_map_file = g_build_filename (userdir, "accels",
-                                                  "evince", NULL);
-       } else {
-               accel_map_file = g_build_filename (g_get_home_dir (),
-                                                  ".gnome2", "accels",
-                                                  "evince", NULL);
-       }
-
+        accel_map_file = g_build_filename (application->dot_dir, "accels", NULL);
        tmp_filename = g_strdup_printf ("%s.XXXXXX", accel_map_file);
 
        fd = g_mkstemp (tmp_filename);
@@ -875,6 +893,7 @@ ev_application_accel_map_save (EvApplication *application)
        gtk_accel_map_save_fd (fd);
        close (fd);
 
+        g_mkdir_with_parents (application->dot_dir, 0700);
        if (g_rename (tmp_filename, accel_map_file) == -1) {
                /* FIXME: win32? */
                g_unlink (tmp_filename);
@@ -889,19 +908,107 @@ ev_application_accel_map_load (EvApplication *application)
 {
        gchar *accel_map_file;
 
-       if (userdir) {
-               accel_map_file = g_build_filename (userdir, "accels",
-                                                  "evince", NULL);
-       } else {
-               accel_map_file = g_build_filename (g_get_home_dir (),
-                                                  ".gnome2", "accels",
-                                                  "evince", NULL);
-       }
-
+        accel_map_file = g_build_filename (application->dot_dir, "accels", NULL);
        gtk_accel_map_load (accel_map_file);
        g_free (accel_map_file);
 }
 
+static void
+ev_application_migrate_config_dir (EvApplication *application)
+{
+        const gchar        *userdir;
+        gchar              *old_dot_dir;
+        gchar              *old_accels;
+        GError             *error;
+        gint                i;
+        gboolean            dir_created = FALSE;
+        static const gchar *config_files[] = {
+                "evince_toolbar.xml",
+                "print-settings",
+                NULL
+        };
+
+        userdir = g_getenv ("GNOME22_USER_DIR");
+        if (userdir) {
+                old_dot_dir = g_build_filename (userdir, "evince", NULL);
+                old_accels = g_build_filename (userdir, "accels", "evince", NULL);
+        } else {
+                old_dot_dir = g_build_filename (g_get_home_dir (),
+                                                ".gnome2",
+                                                "evince",
+                                                NULL);
+                old_accels = g_build_filename (g_get_home_dir (),
+                                               ".gnome2", "accels",
+                                               "evince", NULL);
+        }
+
+        if (g_file_test (old_dot_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
+                for (i = 0; config_files[i]; i++) {
+                        gchar   *old_filename;
+                        gchar   *new_filename;
+                        GFile   *old_file;
+                        GFile   *new_file;
+
+                        old_filename = g_build_filename (old_dot_dir, config_files[i], NULL);
+                        if (!g_file_test (old_filename, G_FILE_TEST_EXISTS)) {
+                                g_free (old_filename);
+                                continue;
+                        }
+
+                        if (!dir_created) {
+                                g_mkdir_with_parents (application->dot_dir, 0700);
+                                dir_created = TRUE;
+                        }
+
+                        new_filename = g_build_filename (application->dot_dir, config_files[i], NULL);
+                        old_file = g_file_new_for_path (old_filename);
+                        new_file = g_file_new_for_path (new_filename);
+
+                        error = NULL;
+                        g_file_move (old_file, new_file, 0, NULL, NULL, NULL, &error);
+                        if (error) {
+                                g_warning ("Error migrating config file %s: %s\n",
+                                           old_filename, error->message);
+                                g_error_free (error);
+                        }
+
+                        g_free (old_filename);
+                        g_free (new_filename);
+                        g_object_unref (old_file);
+                        g_object_unref (new_file);
+                }
+        }
+
+        g_free (old_dot_dir);
+
+        if (g_file_test (old_accels, G_FILE_TEST_EXISTS)) {
+                gchar *new_accels;
+                GFile *old_accels_file;
+                GFile *new_accels_file;
+
+                if (!dir_created)
+                        g_mkdir_with_parents (application->dot_dir, 0700);
+
+                new_accels = g_build_filename (application->dot_dir, "accels", NULL);
+                old_accels_file = g_file_new_for_path (old_accels);
+                new_accels_file = g_file_new_for_path (new_accels);
+
+                error = NULL;
+                g_file_move (old_accels_file, new_accels_file, 0, NULL, NULL, NULL, &error);
+                if (error) {
+                        g_warning ("Error migrating accelerator specifications file %s: %s\n",
+                                   old_accels, error->message);
+                        g_error_free (error);
+                }
+
+                g_free (new_accels);
+                g_object_unref (old_accels_file);
+                g_object_unref (new_accels_file);
+        }
+
+        g_free (old_accels);
+}
+
 void
 ev_application_shutdown (EvApplication *application)
 {
@@ -964,14 +1071,10 @@ ev_application_init (EvApplication *ev_application)
 {
        GError *error = NULL;
 
-       userdir = g_getenv ("GNOME22_USER_DIR");
-       if (userdir)
-               ev_application->dot_dir = g_build_filename (userdir, "evince", NULL);
-       else
-               ev_application->dot_dir = g_build_filename (g_get_home_dir (),
-                                                           ".gnome2",
-                                                           "evince",
-                                                           NULL);
+        ev_application->dot_dir = g_build_filename (g_get_user_config_dir (),
+                                                    "evince", NULL);
+        if (!g_file_test (ev_application->dot_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
+                ev_application_migrate_config_dir (ev_application);
 
 #ifdef G_OS_WIN32
 {
@@ -982,7 +1085,7 @@ ev_application_init (EvApplication *ev_application)
        g_free (dir);
 }
 #else
-       ev_application->data_dir = g_strdup (DATADIR);
+       ev_application->data_dir = g_strdup (EVINCEDATADIR);
 #endif
 
        ev_application_init_session (ev_application);
@@ -1020,13 +1123,48 @@ ev_application_init (EvApplication *ev_application)
                      NULL);
 }
 
+GDBusConnection *
+ev_application_get_dbus_connection (EvApplication *application)
+{
+#ifdef ENABLE_DBUS
+       return application->connection;
+#else
+       return NULL;
+#endif
+}
+
 gboolean
 ev_application_has_window (EvApplication *application)
 {
-       GList   *windows = ev_application_get_windows (application);
-       gboolean retval = windows != NULL;
+       GList    *l, *toplevels;
+       gboolean  retval = FALSE;
 
-       g_list_free (windows);
+       toplevels = gtk_window_list_toplevels ();
+
+       for (l = toplevels; l != NULL && !retval; l = l->next) {
+               if (EV_IS_WINDOW (l->data))
+                       retval = TRUE;
+       }
+
+       g_list_free (toplevels);
+
+       return retval;
+}
+
+guint
+ev_application_get_n_windows (EvApplication *application)
+{
+       GList *l, *toplevels;
+       guint  retval = 0;
+
+       toplevels = gtk_window_list_toplevels ();
+
+       for (l = toplevels; l != NULL; l = l->next) {
+               if (EV_IS_WINDOW (l->data))
+                       retval++;
+       }
+
+       g_list_free (toplevels);
 
        return retval;
 }