diff options
-rw-r--r-- | shell/ev-daemon.c | 298 |
1 files changed, 171 insertions, 127 deletions
diff --git a/shell/ev-daemon.c b/shell/ev-daemon.c index ea7f66ef..ae5f2bba 100644 --- a/shell/ev-daemon.c +++ b/shell/ev-daemon.c @@ -2,7 +2,7 @@ * this file is part of atril, a mate document viewer * * Copyright (C) 2009 Carlos Garcia Campos <[email protected]> - * Copyright © 2010 Christian Persch + * Copyright © 2010, 2012 Christian Persch * * Atril is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by @@ -43,9 +43,32 @@ #define LOG g_printerr -static GList *ev_daemon_docs = NULL; -static guint kill_timer_id; -static GHashTable *pending_invocations = NULL; + +#define EV_TYPE_DAEMON_APPLICATION (ev_daemon_application_get_type ()) +#define EV_DAEMON_APPLICATION(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), EV_TYPE_DAEMON_APPLICATION, EvDaemonApplication)) +#define EV_DAEMON_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_DAEMON_APPLICATION, EvDaemonApplicationClass)) +#define EV_IS_DAEMON_APPLICATION(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), EV_TYPE_DAEMON_APPLICATION)) +#define EV_IS_DAEMON_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_DAEMON_APPLICATION)) +#define EV_DAEMON_APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_DAEMON_APPLICATION, EvDaemonApplicationClass)) + +typedef struct _EvDaemonApplication EvDaemonApplication; +typedef struct _EvDaemonApplicationClass EvDaemonApplicationClass; + +struct _EvDaemonApplicationClass { + GApplicationClass parent_class; +}; + +struct _EvDaemonApplication +{ + GApplication parent_instance; + + EvDaemon *daemon; + GHashTable *pending_invocations; + GList *docs; +}; + +static GType ev_daemon_application_get_type (void); +G_DEFINE_TYPE (EvDaemonApplication, ev_daemon_application, G_TYPE_APPLICATION) typedef struct { gchar *dbus_name; @@ -69,11 +92,12 @@ ev_doc_free (EvDoc *doc) } static EvDoc * -ev_daemon_find_doc (const gchar *uri) +ev_daemon_application_find_doc (EvDaemonApplication *application, + const gchar *uri) { GList *l; - for (l = ev_daemon_docs; l != NULL; l = l->next) { + for (l = application->docs; l != NULL; l = l->next) { EvDoc *doc = (EvDoc *)l->data; if (strcmp (doc->uri, uri) == 0) @@ -83,39 +107,6 @@ ev_daemon_find_doc (const gchar *uri) return NULL; } -static void -ev_daemon_stop_killtimer (void) -{ - if (kill_timer_id != 0) - g_source_remove (kill_timer_id); - kill_timer_id = 0; -} - -static gboolean -ev_daemon_shutdown (gpointer user_data) -{ - GMainLoop *loop = (GMainLoop *) user_data; - - LOG ("Timeout; exiting daemon.\n"); - - if (g_main_loop_is_running (loop)) - g_main_loop_quit (loop); - - return FALSE; -} - -static void -ev_daemon_maybe_start_killtimer (gpointer data) -{ - ev_daemon_stop_killtimer (); - if (ev_daemon_docs != NULL) - return; - - kill_timer_id = g_timeout_add_seconds (DAEMON_TIMEOUT, - (GSourceFunc) ev_daemon_shutdown, - data); -} - static gboolean spawn_atril (const gchar *uri) { @@ -153,11 +144,12 @@ name_vanished_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { + EvDaemonApplication *application = EV_DAEMON_APPLICATION (user_data); GList *l; LOG ("Watch name'%s' disappeared\n", name); - for (l = ev_daemon_docs; l != NULL; l = l->next) { + for (l = application->docs; l != NULL; l = l->next) { EvDoc *doc = (EvDoc *) l->data; if (strcmp (doc->dbus_name, name) != 0) @@ -165,23 +157,25 @@ name_vanished_cb (GDBusConnection *connection, LOG ("Watch found URI '%s' for name; removing\n", doc->uri); - ev_daemon_docs = g_list_delete_link (ev_daemon_docs, l); + application->docs = g_list_delete_link (application->docs, l); ev_doc_free (doc); - ev_daemon_maybe_start_killtimer (user_data); + g_application_release (G_APPLICATION (application)); + return; } } static void -process_pending_invocations (const gchar *uri, - const gchar *dbus_name) +process_pending_invocations (EvDaemonApplication *application, + const gchar *uri, + const gchar *dbus_name) { GList *l; GList *uri_invocations; LOG ("RegisterDocument process pending invocations for URI %s\n", uri); - uri_invocations = g_hash_table_lookup (pending_invocations, uri); + uri_invocations = g_hash_table_lookup (application->pending_invocations, uri); for (l = uri_invocations; l != NULL; l = l->next) { GDBusMethodInvocation *invocation; @@ -192,7 +186,7 @@ process_pending_invocations (const gchar *uri, } g_list_free (uri_invocations); - g_hash_table_remove (pending_invocations, uri); + g_hash_table_remove (application->pending_invocations, uri); } static void @@ -202,27 +196,33 @@ document_loaded_cb (GDBusConnection *connection, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, - EvDoc *doc) + gpointer user_data) { - const gchar *uri; + EvDaemonApplication *application = EV_DAEMON_APPLICATION (user_data); + const gchar *uri; + EvDoc *doc; g_variant_get (parameters, "(&s)", &uri); - if (strcmp (uri, doc->uri) == 0) - process_pending_invocations (uri, sender_name); + doc = ev_daemon_application_find_doc (application, uri); + if (doc != NULL && strcmp (uri, doc->uri) == 0) { + process_pending_invocations (application, uri, sender_name); + } + g_dbus_connection_signal_unsubscribe (connection, doc->loaded_id); + doc->loaded_id = 0; } static gboolean -handle_register_document_cb (EvDaemon *object, +handle_register_document_cb (EvDaemon *object, GDBusMethodInvocation *invocation, - const gchar *uri, - gpointer user_data) + const gchar *uri, + EvDaemonApplication *application) { GDBusConnection *connection; const char *sender; EvDoc *doc; - doc = ev_daemon_find_doc (uri); + doc = ev_daemon_application_find_doc (application, uri); if (doc != NULL) { LOG ("RegisterDocument found owner '%s' for URI '%s'\n", doc->dbus_name, uri); ev_daemon_complete_register_document (object, invocation, doc->dbus_name); @@ -230,15 +230,17 @@ handle_register_document_cb (EvDaemon *object, return TRUE; } - ev_daemon_stop_killtimer (); - sender = g_dbus_method_invocation_get_sender (invocation); connection = g_dbus_method_invocation_get_connection (invocation); + LOG ("RegisterDocument registered owner '%s' for URI '%s'\n", sender, uri); + doc = g_new (EvDoc, 1); doc->dbus_name = g_strdup (sender); doc->uri = g_strdup (uri); + application->docs = g_list_prepend (application->docs, doc); + doc->loaded_id = g_dbus_connection_signal_subscribe (connection, doc->dbus_name, EV_DBUS_WINDOW_INTERFACE_NAME, @@ -246,36 +248,34 @@ handle_register_document_cb (EvDaemon *object, NULL, NULL, 0, - (GDBusSignalCallback) document_loaded_cb, - doc, - NULL); + document_loaded_cb, + application, NULL); doc->watch_id = g_bus_watch_name_on_connection (connection, sender, G_BUS_NAME_WATCHER_FLAGS_NONE, name_appeared_cb, name_vanished_cb, - user_data, NULL); - - LOG ("RegisterDocument registered owner '%s' for URI '%s'\n", doc->dbus_name, uri); - ev_daemon_docs = g_list_prepend (ev_daemon_docs, doc); + application, NULL); ev_daemon_complete_register_document (object, invocation, ""); + g_application_hold (G_APPLICATION (application)); + return TRUE; } static gboolean -handle_unregister_document_cb (EvDaemon *object, +handle_unregister_document_cb (EvDaemon *object, GDBusMethodInvocation *invocation, - const gchar *uri, - gpointer user_data) + const gchar *uri, + EvDaemonApplication *application) { EvDoc *doc; const char *sender; LOG ("UnregisterDocument URI '%s'\n", uri); - doc = ev_daemon_find_doc (uri); + doc = ev_daemon_application_find_doc (application, uri); if (doc == NULL) { LOG ("UnregisterDocument URI was not registered!\n"); g_dbus_method_invocation_return_error_literal (invocation, @@ -297,27 +297,35 @@ handle_unregister_document_cb (EvDaemon *object, return TRUE; } - ev_daemon_docs = g_list_remove (ev_daemon_docs, doc); + application->docs = g_list_remove (application->docs, doc); + + if (doc->loaded_id != 0) { + g_dbus_connection_signal_unsubscribe (g_dbus_method_invocation_get_connection (invocation), + doc->loaded_id); + doc->loaded_id = 0; + } + ev_doc_free (doc); - ev_daemon_maybe_start_killtimer (user_data); ev_daemon_complete_unregister_document (object, invocation); + g_application_release (G_APPLICATION (application)); + return TRUE; } static gboolean -handle_find_document_cb (EvDaemon *object, +handle_find_document_cb (EvDaemon *object, GDBusMethodInvocation *invocation, - const gchar *uri, - gboolean spawn, - gpointer user_data) + const gchar *uri, + gboolean spawn, + EvDaemonApplication *application) { EvDoc *doc; LOG ("FindDocument URI '%s' \n", uri); - doc = ev_daemon_find_doc (uri); + doc = ev_daemon_application_find_doc (application, uri); if (doc != NULL) { ev_daemon_complete_find_document (object, invocation, doc->dbus_name); @@ -328,7 +336,7 @@ handle_find_document_cb (EvDaemon *object, GList *uri_invocations; gboolean ret_val = TRUE; - uri_invocations = g_hash_table_lookup (pending_invocations, uri); + uri_invocations = g_hash_table_lookup (application->pending_invocations, uri); if (uri_invocations == NULL) { /* Only spawn once. */ @@ -338,7 +346,7 @@ handle_find_document_cb (EvDaemon *object, if (ret_val) { /* Only defer DBUS answer if atril was succesfully spawned */ uri_invocations = g_list_prepend (uri_invocations, invocation); - g_hash_table_insert (pending_invocations, + g_hash_table_insert (application->pending_invocations, g_strdup (uri), uri_invocations); return TRUE; @@ -352,87 +360,123 @@ handle_find_document_cb (EvDaemon *object, return TRUE; } -static void -bus_acquired_cb (GDBusConnection *connection, - const gchar *name, - gpointer user_data) +/* ------------------------------------------------------------------------- */ + +static gboolean +ev_daemon_application_dbus_register (GApplication *gapplication, + GDBusConnection *connection, + const gchar *object_path, + GError **error) { - GMainLoop *loop = (GMainLoop *) user_data; + EvDaemonApplication *application = EV_DAEMON_APPLICATION (gapplication); EvDaemon *skeleton; - GError *error = NULL; + + if (!G_APPLICATION_CLASS (ev_daemon_application_parent_class)->dbus_register (gapplication, + connection, + object_path, + error)) + return FALSE; skeleton = ev_daemon_skeleton_new (); if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton), connection, EV_DBUS_DAEMON_OBJECT_PATH, - &error)) { - g_printerr ("Failed to export object: %s\n", error->message); - g_error_free (error); - - if (g_main_loop_is_running (loop)) - g_main_loop_quit (loop); - } + error)) { + g_object_unref (skeleton); + return FALSE; + } + + application->daemon = skeleton; g_signal_connect (skeleton, "handle-register-document", - G_CALLBACK (handle_register_document_cb), loop); + G_CALLBACK (handle_register_document_cb), application); g_signal_connect (skeleton, "handle-unregister-document", - G_CALLBACK (handle_unregister_document_cb), loop); + G_CALLBACK (handle_unregister_document_cb), application); g_signal_connect (skeleton, "handle-find-document", - G_CALLBACK (handle_find_document_cb), loop); + G_CALLBACK (handle_find_document_cb), application); + return TRUE; } static void -name_acquired_cb (GDBusConnection *connection, - const gchar *name, - gpointer user_data) +ev_daemon_application_dbus_unregister (GApplication *gapplication, + GDBusConnection *connection, + const gchar *object_path) +{ + EvDaemonApplication *application = EV_DAEMON_APPLICATION (gapplication); + + if (application->daemon) { + g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (application->daemon)); + g_object_unref (application->daemon); + application->daemon = NULL; + } + + G_APPLICATION_CLASS (ev_daemon_application_parent_class)->dbus_unregister (gapplication, + connection, + object_path); +} + +static void +ev_daemon_application_init (EvDaemonApplication *application) { - ev_daemon_maybe_start_killtimer (user_data); + application->pending_invocations = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + NULL); } static void -name_lost_cb (GDBusConnection *connection, - const gchar *name, - gpointer user_data) +ev_daemon_application_finalize (GObject *object) { - GMainLoop *loop = (GMainLoop *) user_data; + EvDaemonApplication *application = EV_DAEMON_APPLICATION (object); - /* Failed to acquire the name; exit daemon */ - if (g_main_loop_is_running (loop)) - g_main_loop_quit (loop); + g_warn_if_fail (g_hash_table_size (application->pending_invocations) == 0); + g_hash_table_destroy (application->pending_invocations); + + g_list_free_full (application->docs, (GDestroyNotify) ev_doc_free); + + G_OBJECT_CLASS (ev_daemon_application_parent_class)->finalize (object); } +static void +ev_daemon_application_class_init (EvDaemonApplicationClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GApplicationClass *g_application_class = G_APPLICATION_CLASS (klass); + + object_class->finalize = ev_daemon_application_finalize; + + g_application_class->dbus_register = ev_daemon_application_dbus_register; + g_application_class->dbus_unregister = ev_daemon_application_dbus_unregister; +} + +/* ------------------------------------------------------------------------- */ + gint main (gint argc, gchar **argv) { - GMainLoop *loop; - guint owner_id; + GApplication *application; + const GApplicationFlags flags = G_APPLICATION_IS_SERVICE; + GError *error = NULL; + int status; g_set_prgname ("atril-daemon"); - loop = g_main_loop_new (NULL, FALSE); - - pending_invocations = g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify)g_free, - NULL); + application = g_object_new (EV_TYPE_DAEMON_APPLICATION, + "application-id", EV_DBUS_DAEMON_NAME, + "flags", flags, + NULL); + g_application_set_inactivity_timeout (application, DAEMON_TIMEOUT); - owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, - EV_DBUS_DAEMON_NAME, - G_BUS_NAME_OWNER_FLAGS_NONE, - bus_acquired_cb, - name_acquired_cb, - name_lost_cb, - g_main_loop_ref (loop), - (GDestroyNotify) g_main_loop_unref); + if (!g_application_register (application, NULL, &error)) { + g_printerr ("Failed to register: %s\n", error->message); + g_error_free (error); + g_object_unref (application); - g_main_loop_run (loop); - - g_bus_unown_name (owner_id); + return 1; + } - g_main_loop_unref (loop); - g_list_foreach (ev_daemon_docs, (GFunc)ev_doc_free, NULL); - g_list_free (ev_daemon_docs); - g_hash_table_destroy (pending_invocations); + status = g_application_run (application, 0, NULL); + g_object_unref (application); - return 0; + return status; } |