diff options
author | Colin Walters <walters@verbum.org> | 2012-11-06 17:47:24 -0500 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2012-11-06 21:04:11 -0500 |
commit | 92c64b500a91f2f5289b972961f85f8d268ab88f (patch) | |
tree | 1f51cde658f494bcb229d21262ff862bc7f703d8 | |
parent | 5aff5ed2e24146f16c6eabbd4f39e9c9fc28dbb9 (diff) | |
download | gnome-session-wip/isactive.tar.gz |
[wip] Add new SessionIsActive propertywip/isactive
Merge the code from gnome-settings-daemon to monitor session active
state, unfortunately down-porting it to dbus-glib in the ConsoleKit
case. Even more unfortunately, we hand-roll a PropertiesChanged
signal for GDBus consuemrs.
-rw-r--r-- | gnome-session/gsm-consolekit.c | 90 | ||||
-rw-r--r-- | gnome-session/gsm-manager.c | 67 | ||||
-rw-r--r-- | gnome-session/gsm-system.c | 26 | ||||
-rw-r--r-- | gnome-session/gsm-system.h | 2 | ||||
-rw-r--r-- | gnome-session/gsm-systemd.c | 201 | ||||
-rw-r--r-- | gnome-session/org.gnome.SessionManager.xml | 9 |
6 files changed, 369 insertions, 26 deletions
diff --git a/gnome-session/gsm-consolekit.c b/gnome-session/gsm-consolekit.c index 4c0eca56..c20004af 100644 --- a/gnome-session/gsm-consolekit.c +++ b/gnome-session/gsm-consolekit.c @@ -56,6 +56,13 @@ struct _GsmConsolekitPrivate DBusGProxy *bus_proxy; DBusGProxy *ck_proxy; UpClient *up_client; + + gboolean is_active; +}; + +enum { + PROP_0, + PROP_ACTIVE }; static void gsm_consolekit_class_init (GsmConsolekitClass *klass); @@ -81,14 +88,53 @@ G_DEFINE_TYPE_WITH_CODE (GsmConsolekit, gsm_consolekit, G_TYPE_OBJECT, gsm_consolekit_system_init)) static void +gsm_consolekit_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GsmConsolekit *self = GSM_CONSOLEKIT (object); + + switch (prop_id) { + case PROP_ACTIVE: + self->priv->is_active = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gsm_consolekit_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GsmConsolekit *self = GSM_CONSOLEKIT (object); + + switch (prop_id) { + case PROP_ACTIVE: + g_value_set_boolean (value, self->priv->is_active); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gsm_consolekit_class_init (GsmConsolekitClass *manager_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (manager_class); + object_class->get_property = gsm_consolekit_get_property; + object_class->set_property = gsm_consolekit_set_property; object_class->finalize = gsm_consolekit_finalize; + g_object_class_override_property (object_class, PROP_ACTIVE, "active"); + g_type_class_add_private (manager_class, sizeof (GsmConsolekitPrivate)); } @@ -112,6 +158,41 @@ gsm_consolekit_dbus_filter (DBusConnection *connection, return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } +static void +is_active_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer data) +{ + GsmConsolekit *self = data; + GError *local_error = NULL; + gboolean is_active; + + if (!dbus_g_proxy_end_call (proxy, call, &local_error, + G_TYPE_BOOLEAN, &is_active, + G_TYPE_INVALID)) { + g_warning ("Failed isActive call to ConsoleKit: %s", + local_error->message); + g_clear_error (&local_error); + return; + } + + if (is_active != self->priv->is_active) { + self->priv->is_active = is_active; + g_object_notify ((GObject*) self, "active"); + } +} + +static void +on_active_changed (DBusGProxy *proxy, + gboolean is_active, + GsmConsolekit *self) +{ + if (is_active != self->priv->is_active) { + self->priv->is_active = is_active; + g_object_notify ((GObject*) self, "active"); + } +} + static gboolean gsm_consolekit_ensure_ck_connection (GsmConsolekit *manager, GError **error) @@ -180,6 +261,15 @@ gsm_consolekit_ensure_ck_connection (GsmConsolekit *manager, is_connected = FALSE; goto out; } + + dbus_g_proxy_begin_call (manager->priv->ck_proxy, + "IsActive", + is_active_cb, g_object_ref (manager), + (GDestroyNotify)g_object_unref, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (manager->priv->ck_proxy, "ActiveChanged", G_TYPE_BOOLEAN, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (manager->priv->ck_proxy, "ActiveChanged", + G_CALLBACK (on_active_changed), manager, NULL); } is_connected = TRUE; diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c index 192c81df..52f4b0f9 100644 --- a/gnome-session/gsm-manager.c +++ b/gnome-session/gsm-manager.c @@ -165,6 +165,7 @@ enum { PROP_0, PROP_CLIENT_STORE, PROP_SESSION_NAME, + PROP_SESSION_IS_ACTIVE, PROP_FALLBACK, PROP_FAILSAFE }; @@ -2434,6 +2435,9 @@ gsm_manager_get_property (GObject *object, case PROP_SESSION_NAME: g_value_set_string (value, self->priv->session_name); break; + case PROP_SESSION_IS_ACTIVE: + g_value_set_boolean (value, gsm_system_is_active (self->priv->system)); + break; case PROP_FALLBACK: g_value_set_boolean (value, self->priv->is_fallback_session); break; @@ -2633,6 +2637,20 @@ gsm_manager_class_init (GsmManagerClass *klass) NULL, NULL, G_PARAM_READABLE)); + /** + + * GsmManager::session-is-active + * + * If true, the current session is in the foreground and + * available for user input. + */ + g_object_class_install_property (object_class, + PROP_SESSION_IS_ACTIVE, + g_param_spec_boolean ("session-is-active", + NULL, + NULL, + TRUE, + G_PARAM_READABLE)); /** * GsmManager::fallback @@ -2675,6 +2693,53 @@ on_presence_status_changed (GsmPresence *presence, g_object_unref (system); } +static void +on_gsm_system_active_changed (GsmSystem *system, + GParamSpec *pspec, + GsmManager *self) +{ + DBusGConnection *gconnection; + DBusConnection *connection; + DBusMessage *message; + DBusMessageIter iter; + DBusMessageIter subiter; + DBusMessageIter dict_iter; + DBusMessageIter v_iter; + dbus_bool_t is_active; + const char *prop_name = "SessionIsActive"; + + g_object_notify ((GObject*)self, "session-is-active"); + + /* Now, the following bits emit the PropertiesChanged signal + * that GDBus expects. This code should just die in a port to + * GDBus. + */ + gconnection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); + g_assert (gconnection); + connection = dbus_g_connection_get_connection (gconnection); + is_active = gsm_system_is_active (self->priv->system); + message = dbus_message_new_signal (GSM_MANAGER_DBUS_PATH, "org.freedesktop.DBus.Properties", + "PropertiesChanged"); + g_assert (message != NULL); + dbus_message_iter_init_append (message, &iter); + /* changed */ + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &subiter); + dbus_message_iter_open_container (&subiter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_iter); + dbus_message_iter_append_basic (&dict_iter, DBUS_TYPE_STRING, &prop_name); + dbus_message_iter_open_container (&dict_iter, DBUS_TYPE_VARIANT, "b", &v_iter); + dbus_message_iter_append_basic (&v_iter, DBUS_TYPE_BOOLEAN, &is_active); + dbus_message_iter_close_container (&dict_iter, &v_iter); + dbus_message_iter_close_container (&subiter, &dict_iter); + dbus_message_iter_close_container (&iter, &subiter); + /* invalidated */ + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &subiter); + dbus_message_iter_close_container (&iter, &subiter); + + g_printerr ("SESSION: EMIT ACTIVE CHANGED %d\n", is_active); + dbus_connection_send (connection, message, NULL); + dbus_message_unref (message); +} + static gboolean idle_timeout_get_mapping (GValue *value, GVariant *variant, @@ -2727,6 +2792,8 @@ gsm_manager_init (GsmManager *manager) NULL, NULL); manager->priv->system = gsm_get_system (); + g_signal_connect (manager->priv->system, "notify::active", + G_CALLBACK (on_gsm_system_active_changed), manager); manager->priv->shell = gsm_get_shell (); } diff --git a/gnome-session/gsm-system.c b/gnome-session/gsm-system.c index 7ace678d..49a4316d 100644 --- a/gnome-session/gsm-system.c +++ b/gnome-session/gsm-system.c @@ -32,6 +32,11 @@ enum { LAST_SIGNAL }; +enum { + PROP_0, + PROP_ACTIVE +}; + static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_INTERFACE (GsmSystem, gsm_system, G_TYPE_OBJECT) @@ -39,6 +44,7 @@ G_DEFINE_INTERFACE (GsmSystem, gsm_system, G_TYPE_OBJECT) static void gsm_system_default_init (GsmSystemInterface *iface) { + GParamSpec *pspec; signals [REQUEST_COMPLETED] = g_signal_new ("request-completed", GSM_TYPE_SYSTEM, @@ -47,6 +53,12 @@ gsm_system_default_init (GsmSystemInterface *iface) NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_POINTER); + pspec = g_param_spec_boolean ("active", + "Active", + "Whether or not session is active", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT); + g_object_interface_install_property (iface, pspec); } GQuark @@ -143,6 +155,20 @@ gsm_system_is_login_session (GsmSystem *system) return GSM_SYSTEM_GET_IFACE (system)->is_login_session (system); } +/** + * gsm_system_is_active: + * + * Returns: %TRUE if the current session is in the foreground + * Since: 3.8 + */ +gboolean +gsm_system_is_active (GsmSystem *system) +{ + gboolean is_active; + g_object_get ((GObject*)system, "active", &is_active, NULL); + return is_active; +} + GsmSystem * gsm_get_system (void) { diff --git a/gnome-session/gsm-system.h b/gnome-session/gsm-system.h index b284e16b..69418238 100644 --- a/gnome-session/gsm-system.h +++ b/gnome-session/gsm-system.h @@ -102,6 +102,8 @@ void gsm_system_set_session_idle (GsmSystem *system, gboolean gsm_system_is_login_session (GsmSystem *system); +gboolean gsm_system_is_active (GsmSystem *system); + void gsm_system_add_inhibitor (GsmSystem *system, const gchar *id, GsmInhibitorFlag flags); diff --git a/gnome-session/gsm-systemd.c b/gnome-session/gsm-systemd.c index 417bb601..92df6b2f 100644 --- a/gnome-session/gsm-systemd.c +++ b/gnome-session/gsm-systemd.c @@ -51,12 +51,20 @@ struct _GsmSystemdPrivate { + GSource *sd_source; GDBusProxy *sd_proxy; - gchar *session_id; + char *session_id; gchar *session_path; GSList *inhibitors; gint inhibit_fd; + + gboolean is_active; +}; + +enum { + PROP_0, + PROP_ACTIVE }; static void gsm_systemd_system_init (GsmSystemInterface *iface); @@ -81,9 +89,13 @@ gsm_systemd_finalize (GObject *object) GsmSystemd *systemd = GSM_SYSTEMD (object); g_clear_object (&systemd->priv->sd_proxy); - g_free (systemd->priv->session_id); + free (systemd->priv->session_id); g_free (systemd->priv->session_path); + if (systemd->priv->sd_source) { + g_source_destroy (systemd->priv->sd_source); + } + if (systemd->priv->inhibitors != NULL) { g_slist_free_full (systemd->priv->inhibitors, g_free); } @@ -93,21 +105,157 @@ gsm_systemd_finalize (GObject *object) } static void +gsm_systemd_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GsmSystemd *self = GSM_SYSTEMD (object); + + switch (prop_id) { + case PROP_ACTIVE: + self->priv->is_active = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gsm_systemd_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GsmSystemd *self = GSM_SYSTEMD (object); + + switch (prop_id) { + case PROP_ACTIVE: + g_value_set_boolean (value, self->priv->is_active); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gsm_systemd_class_init (GsmSystemdClass *manager_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (manager_class); + object_class->get_property = gsm_systemd_get_property; + object_class->set_property = gsm_systemd_set_property; object_class->finalize = gsm_systemd_finalize; + g_object_class_override_property (object_class, PROP_ACTIVE, "active"); + g_type_class_add_private (manager_class, sizeof (GsmSystemdPrivate)); } +typedef struct +{ + GSource source; + GPollFD pollfd; + sd_login_monitor *monitor; +} SdSource; + +static gboolean +sd_source_prepare (GSource *source, + gint *timeout) +{ + *timeout = -1; + return FALSE; +} + +static gboolean +sd_source_check (GSource *source) +{ + SdSource *sd_source = (SdSource *)source; + + return sd_source->pollfd.revents != 0; +} + +static gboolean +sd_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) + +{ + SdSource *sd_source = (SdSource *)source; + gboolean ret; + + g_warn_if_fail (callback != NULL); + + ret = (*callback) (user_data); + + sd_login_monitor_flush (sd_source->monitor); + return ret; +} + +static void +sd_source_finalize (GSource *source) +{ + SdSource *sd_source = (SdSource*)source; + + sd_login_monitor_unref (sd_source->monitor); +} + +static GSourceFuncs sd_source_funcs = { + sd_source_prepare, + sd_source_check, + sd_source_dispatch, + sd_source_finalize +}; + +static GSource * +sd_source_new (void) +{ + GSource *source; + SdSource *sd_source; + int ret; + + source = g_source_new (&sd_source_funcs, sizeof (SdSource)); + sd_source = (SdSource *)source; + + if ((ret = sd_login_monitor_new (NULL, &sd_source->monitor)) < 0) { + g_warning ("Error getting login monitor: %d", ret); + } else { + sd_source->pollfd.fd = sd_login_monitor_get_fd (sd_source->monitor); + sd_source->pollfd.events = G_IO_IN; + g_source_add_poll (source, &sd_source->pollfd); + } + + return source; +} + +static gboolean +on_sd_source_changed (gpointer user_data) +{ + GsmSystemd *self = user_data; + int active_r; + gboolean active; + + active_r = sd_session_is_active (self->priv->session_id); + if (active_r < 0) + active = FALSE; + else + active = active_r; + if (active != self->priv->is_active) { + g_printerr ("SESSION: NOTIFY ACTIVE %d -> %d\n", self->priv->is_active, active); + self->priv->is_active = active; + g_object_notify (G_OBJECT (self), "active"); + } + + return TRUE; +} + static void gsm_systemd_init (GsmSystemd *manager) { - GError *error; + GError *error = NULL; GDBusConnection *bus; GVariant *res; @@ -117,33 +265,26 @@ gsm_systemd_init (GsmSystemd *manager) manager->priv->inhibit_fd = -1; - error = NULL; - bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); - if (bus == NULL) { - g_warning ("Failed to connect to system bus: %s", + if (bus == NULL) + g_error ("Failed to connect to system bus: %s", + error->message); + manager->priv->sd_proxy = + g_dbus_proxy_new_sync (bus, + 0, + NULL, + SD_NAME, + SD_PATH, + SD_INTERFACE, + NULL, + &error); + if (manager->priv->sd_proxy == NULL) { + g_warning ("Failed to connect to systemd: %s", error->message); - g_error_free (error); - } else { - manager->priv->sd_proxy = - g_dbus_proxy_new_sync (bus, - 0, - NULL, - SD_NAME, - SD_PATH, - SD_INTERFACE, - NULL, - &error); - - if (manager->priv->sd_proxy == NULL) { - g_warning ("Failed to connect to systemd: %s", - error->message); - g_error_free (error); - } - - g_object_unref (bus); + g_clear_error (&error); } + sd_pid_get_session (getpid (), &manager->priv->session_id); if (manager->priv->session_id == NULL) { @@ -161,6 +302,14 @@ gsm_systemd_init (GsmSystemd *manager) NULL); g_variant_get (res, "(o)", &manager->priv->session_path); g_variant_unref (res); + + manager->priv->sd_source = sd_source_new (); + g_source_set_callback (manager->priv->sd_source, on_sd_source_changed, manager, NULL); + g_source_attach (manager->priv->sd_source, NULL); + + on_sd_source_changed (manager); + + g_object_unref (bus); } static void diff --git a/gnome-session/org.gnome.SessionManager.xml b/gnome-session/org.gnome.SessionManager.xml index 8ed6bda5..b1d459d7 100644 --- a/gnome-session/org.gnome.SessionManager.xml +++ b/gnome-session/org.gnome.SessionManager.xml @@ -408,5 +408,14 @@ </doc:doc> </property> + <property name="SessionIsActive" type="b" access="read"> + <doc:doc> + <doc:description> + <doc:para>If true, the session is currently in the + foreground and available for user input.</doc:para> + </doc:description> + </doc:doc> + </property> + </interface> </node> |