diff options
Diffstat (limited to 'gio/gapplicationimpl-dbus.c')
-rw-r--r-- | gio/gapplicationimpl-dbus.c | 268 |
1 files changed, 266 insertions, 2 deletions
diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c index d8999d7c5..a0212e3c4 100644 --- a/gio/gapplicationimpl-dbus.c +++ b/gio/gapplicationimpl-dbus.c @@ -30,6 +30,7 @@ #include "gdbusconnection.h" #include "gdbusintrospection.h" #include "gdbuserror.h" +#include "gdbusproxy.h" #include "gmenuexporter.h" #include <string.h> @@ -103,6 +104,11 @@ struct _GApplicationImpl gboolean properties_live; gboolean primary; gpointer app; + + gchar *app_id; + GDBusProxy *sm_proxy; + gchar *client_path; + GDBusProxy *client_proxy; }; @@ -467,11 +473,15 @@ g_application_impl_destroy (GApplicationImpl *impl) { g_application_impl_stop_primary (impl); - if (impl->session_bus) - g_object_unref (impl->session_bus); + g_clear_object (&impl->session_bus); g_free (impl->object_path); + g_clear_object (&impl->sm_proxy); + g_clear_object (&impl->client_proxy); + g_free (impl->client_path); + g_free (impl->app_id); + g_slice_free (GApplicationImpl, impl); } @@ -817,6 +827,260 @@ g_dbus_command_line_new (GDBusMethodInvocation *invocation) return G_APPLICATION_COMMAND_LINE (gdbcl); } +/* Session Management {{{1 */ + +static void +unregister_client (GApplicationImpl *impl) +{ + GError *error = NULL; + + g_debug ("Unregistering client\n"); + + g_dbus_proxy_call_sync (impl->sm_proxy, + "UnregisterClient", + g_variant_new ("(o)", impl->client_path), + 0, + G_MAXINT, + NULL, + &error); + + if (error) + { + g_warning ("Failed to unregister client: %s\n", error->message); + g_error_free (error); + } + + g_clear_object (&impl->client_proxy); + + g_free (impl->client_path); + impl->client_path = NULL; +} + +static void +client_proxy_signal (GDBusProxy *proxy, + const gchar *sender_name, + const gchar *signal_name, + GVariant *parameters, + GApplicationImpl *impl) +{ + if (strcmp (signal_name, "QueryEndSession") == 0) + { + g_debug ("Received QueryEndSession\n"); + g_application_emit_quit_requested (impl->app); + } + else if (strcmp (signal_name, "EndSession") == 0) + { + g_debug ("Received EndSession\n"); + g_application_impl_quit_response (impl, TRUE, NULL); + unregister_client (impl); + g_application_emit_quit (impl->app); + } + else if (strcmp (signal_name, "CancelEndSession") == 0) + { + g_debug ("Received CancelEndSession\n"); + g_application_emit_quit_cancelled (impl->app); + } + else if (strcmp (signal_name, "Stop") == 0) + { + g_debug ("Received Stop\n"); + unregister_client (impl); + g_application_emit_quit (impl->app); + } +} + +void +g_application_impl_session_startup (GApplicationImpl *impl) +{ + static gchar *client_id; + GError *error = NULL; + GVariant *res; + + if (client_id == NULL) + { + const gchar *desktop_autostart_id; + + desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID"); + /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to + * use the same client id. + */ + g_unsetenv ("DESKTOP_AUTOSTART_ID"); + client_id = g_strdup (desktop_autostart_id ? desktop_autostart_id : ""); + } + + g_debug ("Connecting to session manager\n"); + + impl->sm_proxy = g_dbus_proxy_new_sync (impl->session_bus, 0, + NULL, /* FIXME */ + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.gnome.SessionManager", + NULL, + &error); + if (error) + { + g_warning ("Failed to get a session proxy: %s", error->message); + g_error_free (error); + return; + } + + impl->app_id = g_strdup (g_get_prgname ()); + + g_debug ("Registering client '%s' '%s'\n", impl->app_id, client_id); + + res = g_dbus_proxy_call_sync (impl->sm_proxy, + "RegisterClient", + g_variant_new ("(ss)", impl->app_id, client_id), + 0, + -1, + NULL, + &error); + + if (error) + { + g_warning ("Failed to register client: %s\n", error->message); + g_error_free (error); + g_clear_object (&impl->sm_proxy); + return; + } + + g_variant_get (res, "(o)", &impl->client_path); + g_variant_unref (res); + + g_debug ("Registered client at '%s'\n", impl->client_path); + + impl->client_proxy = g_dbus_proxy_new_sync (impl->session_bus, 0, + NULL, /* FIXME */ + "org.gnome.SessionManager", + impl->client_path, + "org.gnome.SessionManager.ClientPrivate", + NULL, + &error); + if (error) + { + g_warning ("Failed to get client proxy: %s\n", error->message); + g_error_free (error); + g_clear_object (&impl->sm_proxy); + g_free (impl->client_path); + impl->client_path = NULL; + return; + } + + g_signal_connect (impl->client_proxy, "g-signal", G_CALLBACK (client_proxy_signal), impl); +} + +void +g_application_impl_quit_response (GApplicationImpl *impl, + gboolean will_quit, + const gchar *reason) +{ + g_return_if_fail (impl->client_proxy != NULL); + + g_debug ("Calling EndSessionResponse %d '%s'\n", will_quit, reason); + + g_dbus_proxy_call (impl->client_proxy, + "EndSessionResponse", + g_variant_new ("(bs)", will_quit, reason ? reason : ""), + 0, G_MAXINT, + NULL, NULL, NULL); +} + +guint +g_application_impl_inhibit (GApplicationImpl *impl, + GApplicationInhibitFlags flags, + const gchar *reason) +{ + GVariant *res; + GError *error = NULL; + guint cookie; + + g_return_val_if_fail (impl->sm_proxy != NULL, 0); + + g_debug ("Calling Inhibit\n"); + + res = g_dbus_proxy_call_sync (impl->sm_proxy, + "Inhibit", + g_variant_new ("(susu)", + impl->app_id, + 0, /* toplevel XID */ + reason, + flags), + 0, + -1, + NULL, + &error); + if (error) + { + g_warning ("Calling Inhibit failed: %s\n", error->message); + g_error_free (error); + return 0; + } + + g_variant_get (res, "(u)", &cookie); + g_variant_unref (res); + + return cookie; +} + +void +g_application_impl_uninhibit (GApplicationImpl *impl, + guint cookie) +{ + GVariant *res; + GError *error = NULL; + + g_return_if_fail (impl->sm_proxy != NULL); + + g_debug ("Calling Uninhibit\n"); + + res = g_dbus_proxy_call_sync (impl->sm_proxy, + "Uninhibit", + g_variant_new ("(u)", cookie), + 0, + -1, + NULL, + &error); + if (error) + { + g_warning ("Calling Uninhibit failed: %s\n", error->message); + g_error_free (error); + return; + } + + g_variant_unref (res); +} + +gboolean +g_application_impl_is_inhibited (GApplicationImpl *impl, + GApplicationInhibitFlags flags) +{ + GVariant *res; + GError *error = NULL; + gboolean inhibited; + + g_return_val_if_fail (impl->sm_proxy != NULL, FALSE); + + g_debug ("Calling IsInhibited\n"); + + res = g_dbus_proxy_call_sync (impl->sm_proxy, + "IsInhibited", + g_variant_new ("(u)", flags), + 0, + -1, + NULL, + &error); + if (error) + { + g_warning ("Calling IsInhibited failed: %s\n", error->message); + g_error_free (error); + return FALSE; + } + + inhibited = g_variant_get_boolean (res); + g_variant_unref (res); + + return inhibited; +} + /* Epilogue {{{1 */ /* vim:set foldmethod=marker: */ |