summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2018-08-30 01:06:51 -0400
committerMatthias Clasen <mclasen@redhat.com>2018-08-30 16:39:06 -0400
commitdc89a164693ede7125f2eec975d85cee89c9409b (patch)
tree61bdc6898bc257faa0844baa5499ae26a77c9b1b
parentcc141caaeb5289c911e9247641509e223d15a7be (diff)
downloadgtk+-screensaver.tar.gz
GtkApplication: track screensaver statescreensaver
A number of applications want to track the state of the screensaver. Make this information available as a boolean property. We only listen for state changes when ::register-session is set to TRUE. This is implemented for unsandboxed D-Bus access by talking directly to org.gnome.ScreenSaver or org.freedesktop.ScreenSaver, and for sandboxed D-Bus by using a (new) portal API. A Quartz implementation is missing.
-rw-r--r--gtk/gtkapplication-dbus.c126
-rw-r--r--gtk/gtkapplication.c37
-rw-r--r--gtk/gtkapplicationprivate.h6
-rw-r--r--gtk/gtkprivate.h1
4 files changed, 170 insertions, 0 deletions
diff --git a/gtk/gtkapplication-dbus.c b/gtk/gtkapplication-dbus.c
index d0110a73a9..3c241ca7b0 100644
--- a/gtk/gtkapplication-dbus.c
+++ b/gtk/gtkapplication-dbus.c
@@ -39,6 +39,9 @@ G_DEFINE_TYPE (GtkApplicationImplDBus, gtk_application_impl_dbus, GTK_TYPE_APPLI
#define XFCE_DBUS_OBJECT_PATH "/org/xfce/SessionManager"
#define XFCE_DBUS_INTERFACE "org.xfce.Session.Manager"
#define XFCE_DBUS_CLIENT_INTERFACE "org.xfce.Session.Client"
+#define GNOME_SCREENSAVER_DBUS_NAME "org.gnome.ScreenSaver"
+#define GNOME_SCREENSAVER_DBUS_OBJECT_PATH "/org/gnome/ScreenSaver"
+#define GNOME_SCREENSAVER_DBUS_INTERFACE "org.gnome.ScreenSaver"
static void
unregister_client (GtkApplicationImplDBus *dbus)
@@ -176,6 +179,63 @@ stash_desktop_autostart_id (void)
}
static void
+screensaver_signal_session (GDBusProxy *proxy,
+ const char *sender_name,
+ const char *signal_name,
+ GVariant *parameters,
+ GtkApplication *application)
+{
+ gboolean active;
+
+ if (!g_str_equal (signal_name, "ActiveChanged"))
+ return;
+
+ g_variant_get (parameters, "(b)", &active);
+ gtk_application_set_screensaver_active (application, active);
+}
+
+static void
+screensaver_signal_portal (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer data)
+{
+ GtkApplication *application = data;
+ gboolean active;
+ GVariant *state;
+
+ if (!g_str_equal (signal_name, "StateChanged"))
+ return;
+
+ g_variant_get (parameters, "(o@a{sv})", NULL, &state);
+ g_variant_lookup (state, "screensaver-active", "b", &active);
+ gtk_application_set_screensaver_active (application, active);
+}
+
+static void
+create_monitor_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
+ GError *error = NULL;
+ GVariant *ret = NULL;
+
+ ret = g_dbus_proxy_call_finish (proxy, result, &error);
+ if (ret == NULL)
+ {
+ g_warning ("Creating a portal monitor failed: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_variant_unref (ret);
+}
+
+static void
gtk_application_impl_dbus_startup (GtkApplicationImpl *impl,
gboolean register_session)
{
@@ -243,6 +303,27 @@ gtk_application_impl_dbus_startup (GtkApplicationImpl *impl,
if (!register_session)
goto out;
+ dbus->ss_proxy = gtk_application_get_proxy_if_service_present (dbus->session,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+ G_DBUS_PROXY_FLAGS_NONE,
+ GNOME_SCREENSAVER_DBUS_NAME,
+ GNOME_SCREENSAVER_DBUS_OBJECT_PATH,
+ GNOME_SCREENSAVER_DBUS_INTERFACE,
+ &error);
+ if (error)
+ {
+ g_debug ("Failed to get the GNOME screensaver proxy: %s", error->message);
+ g_clear_error (&error);
+ g_clear_object (&dbus->ss_proxy);
+ }
+
+ if (dbus->ss_proxy)
+ {
+ g_signal_connect (dbus->ss_proxy, "g-signal",
+ G_CALLBACK (screensaver_signal_session), impl->application);
+ }
+
g_debug ("Registering client '%s' '%s'", dbus->application_id, client_id);
res = g_dbus_proxy_call_sync (dbus->sm_proxy,
@@ -355,8 +436,43 @@ gtk_application_impl_dbus_startup (GtkApplicationImpl *impl,
{
g_debug ("Failed to get an inhibit portal proxy: %s", error->message);
g_clear_error (&error);
+ goto end;
+ }
+
+ if (register_session)
+ {
+ char *token;
+ GVariantBuilder opt_builder;
+
+ /* Monitor screensaver state */
+
+ dbus->session_id = gtk_get_portal_session_path (dbus->session, &token);
+ dbus->state_changed_handler =
+ g_dbus_connection_signal_subscribe (dbus->session,
+ PORTAL_BUS_NAME,
+ PORTAL_INHIBIT_INTERFACE,
+ "StateChanged",
+ PORTAL_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
+ screensaver_signal_portal,
+ impl->application,
+ NULL);
+ g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add (&opt_builder, "{sv}",
+ "session_handle_token", g_variant_new_string (token));
+ g_dbus_proxy_call (dbus->inhibit_proxy,
+ "CreateMonitor",
+ g_variant_new ("(sa{sv})", "", &opt_builder),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ create_monitor_cb, dbus);
+ g_free (token);
}
}
+
+end:;
}
static void
@@ -674,11 +790,21 @@ gtk_application_impl_dbus_finalize (GObject *object)
{
GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) object;
+ g_dbus_connection_call (dbus->session,
+ PORTAL_BUS_NAME,
+ dbus->session_id,
+ PORTAL_SESSION_INTERFACE,
+ "Close",
+ NULL, NULL, 0, -1, NULL, NULL, NULL);
+
+ g_free (dbus->session_id);
+ g_dbus_connection_signal_unsubscribe (dbus->session, dbus->state_changed_handler);
g_clear_object (&dbus->inhibit_proxy);
g_slist_free_full (dbus->inhibit_handles, inhibit_handle_free);
g_free (dbus->app_menu_path);
g_free (dbus->menubar_path);
g_clear_object (&dbus->sm_proxy);
+ g_clear_object (&dbus->ss_proxy);
G_OBJECT_CLASS (gtk_application_impl_dbus_parent_class)->finalize (object);
}
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c
index aab751ce66..999ef1523e 100644
--- a/gtk/gtkapplication.c
+++ b/gtk/gtkapplication.c
@@ -137,6 +137,7 @@ static guint gtk_application_signals[LAST_SIGNAL];
enum {
PROP_ZERO,
PROP_REGISTER_SESSION,
+ PROP_SCREENSAVER_ACTIVE,
PROP_APP_MENU,
PROP_MENUBAR,
PROP_ACTIVE_WINDOW,
@@ -157,6 +158,7 @@ typedef struct
guint last_window_id;
gboolean register_session;
+ gboolean screensaver_active;
GtkActionMuxer *muxer;
GtkBuilder *menus_builder;
gchar *help_overlay_path;
@@ -534,6 +536,10 @@ gtk_application_get_property (GObject *object,
g_value_set_boolean (value, priv->register_session);
break;
+ case PROP_SCREENSAVER_ACTIVE:
+ g_value_set_boolean (value, priv->screensaver_active);
+ break;
+
case PROP_APP_MENU:
g_value_set_object (value, gtk_application_get_app_menu (application));
break;
@@ -661,6 +667,24 @@ gtk_application_class_init (GtkApplicationClass *class)
FALSE,
G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
+ /**
+ * GtkApplication:screensaver-active:
+ *
+ * This property is %TRUE if GTK+ believes that the screensaver is
+ * currently active. GTK+ only tracks session state (including this)
+ * when #GtkApplication::register-session is set to %TRUE.
+ *
+ * Tracking the screensaver state is supported on Linux.
+ *
+ * Since: 3.24
+ */
+ gtk_application_props[PROP_SCREENSAVER_ACTIVE] =
+ g_param_spec_boolean ("screensaver-active",
+ P_("Screensaver Active"),
+ P_("Whether the screensaver is active"),
+ FALSE,
+ G_PARAM_READABLE|G_PARAM_STATIC_STRINGS);
+
gtk_application_props[PROP_APP_MENU] =
g_param_spec_object ("app-menu",
P_("Application menu"),
@@ -1370,3 +1394,16 @@ gtk_application_get_menu_by_id (GtkApplication *application,
return G_MENU (object);
}
+
+void
+gtk_application_set_screensaver_active (GtkApplication *application,
+ gboolean active)
+{
+ GtkApplicationPrivate *priv = gtk_application_get_instance_private (application);
+
+ if (priv->screensaver_active != active)
+ {
+ priv->screensaver_active = active;
+ g_object_notify (G_OBJECT (application), "screensaver-active");
+ }
+}
diff --git a/gtk/gtkapplicationprivate.h b/gtk/gtkapplicationprivate.h
index 74403de894..8f6cdb001d 100644
--- a/gtk/gtkapplicationprivate.h
+++ b/gtk/gtkapplicationprivate.h
@@ -45,6 +45,9 @@ void gtk_application_insert_action_group (GtkAppl
GtkApplicationAccels * gtk_application_get_application_accels (GtkApplication *application);
+void gtk_application_set_screensaver_active (GtkApplication *application,
+ gboolean active);
+
#define GTK_TYPE_APPLICATION_IMPL (gtk_application_impl_get_type ())
#define GTK_APPLICATION_IMPL_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
GTK_TYPE_APPLICATION_IMPL, \
@@ -129,10 +132,13 @@ typedef struct
GDBusProxy *sm_proxy;
GDBusProxy *client_proxy;
gchar *client_path;
+ GDBusProxy *ss_proxy;
/* Portal support */
GDBusProxy *inhibit_proxy;
GSList *inhibit_handles;
+ guint state_changed_handler;
+ char * session_id;
} GtkApplicationImplDBus;
typedef struct
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index 809c855959..58b2453930 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -118,6 +118,7 @@ char *gtk_get_portal_session_path (GDBusConnection *connection,
#define PORTAL_BUS_NAME "org.freedesktop.portal.Desktop"
#define PORTAL_OBJECT_PATH "/org/freedesktop/portal/desktop"
#define PORTAL_REQUEST_INTERFACE "org.freedesktop.portal.Request"
+#define PORTAL_SESSION_INTERFACE "org.freedesktop.portal.Session"
#define PORTAL_FILECHOOSER_INTERFACE "org.freedesktop.portal.FileChooser"
#define PORTAL_PRINT_INTERFACE "org.freedesktop.portal.Print"
#define PORTAL_SCREENSHOT_INTERFACE "org.freedesktop.portal.Screenshot"