summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/ev-daemon.c298
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;
}