[gnome-session] Add new SessionIsActive property



commit 27ded0935c16ac7c5889eeda751345db4a12ce80
Author: Colin Walters <walters verbum org>
Date:   Wed Nov 7 07:27:22 2012 -0500

    Add new SessionIsActive property
    
    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 consumers.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=687821

 gnome-session/gsm-consolekit.c             |   90 +++++++++++++
 gnome-session/gsm-manager.c                |   70 ++++++++++
 gnome-session/gsm-system.c                 |   26 ++++
 gnome-session/gsm-system.h                 |    2 +
 gnome-session/gsm-systemd.c                |  196 ++++++++++++++++++++++++----
 gnome-session/org.gnome.SessionManager.xml |    9 ++
 6 files changed, 369 insertions(+), 24 deletions(-)
---
diff --git a/gnome-session/gsm-consolekit.c b/gnome-session/gsm-consolekit.c
index 4c0eca5..c20004a 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 3effdbf..f9bd0be 100644
--- a/gnome-session/gsm-manager.c
+++ b/gnome-session/gsm-manager.c
@@ -166,6 +166,7 @@ enum {
         PROP_0,
         PROP_CLIENT_STORE,
         PROP_SESSION_NAME,
+        PROP_SESSION_IS_ACTIVE,
         PROP_FALLBACK,
         PROP_FAILSAFE
 };
@@ -2435,6 +2436,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;
@@ -2634,6 +2638,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
@@ -2676,6 +2694,56 @@ 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 *iface_name = GSM_MANAGER_DBUS_NAME;
+        const char *prop_name = "SessionIsActive";
+
+        g_object_notify ((GObject*)self, "session-is-active");
+
+        g_debug ("emitting SessionIsActive");
+
+        /* 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_SESSION, 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);
+        dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &iface_name);
+        /* 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);
+
+        dbus_connection_send (connection, message, NULL);
+        dbus_message_unref (message);
+}
+
 static gboolean
 idle_timeout_get_mapping (GValue *value,
                           GVariant *variant,
@@ -2728,6 +2796,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 7ace678..49a4316 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 b284e16..6941823 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 016a85b..98e9f27 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;
         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);
@@ -84,6 +92,10 @@ gsm_systemd_finalize (GObject *object)
         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,156 @@ 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) {
+                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 +264,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 +301,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 d07a488..11a545e 100644
--- a/gnome-session/org.gnome.SessionManager.xml
+++ b/gnome-session/org.gnome.SessionManager.xml
@@ -426,5 +426,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>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]