summaryrefslogtreecommitdiff
path: root/cut-n-paste/totem-screensaver/totem-scrsaver.c
diff options
context:
space:
mode:
Diffstat (limited to 'cut-n-paste/totem-screensaver/totem-scrsaver.c')
-rw-r--r--cut-n-paste/totem-screensaver/totem-scrsaver.c556
1 files changed, 556 insertions, 0 deletions
diff --git a/cut-n-paste/totem-screensaver/totem-scrsaver.c b/cut-n-paste/totem-screensaver/totem-scrsaver.c
new file mode 100644
index 0000000..bf2bce9
--- /dev/null
+++ b/cut-n-paste/totem-screensaver/totem-scrsaver.c
@@ -0,0 +1,556 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+
+ Copyright (C) 2004-2006 Bastien Nocera <[email protected]>
+ Copyright © 2010 Christian Persch
+ Copyright © 2010 Carlos Garcia Campos
+
+ The Mate Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Mate Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Mate Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA.
+
+ Authors: Bastien Nocera <[email protected]>
+ Christian Persch
+ Carlos Garcia Campos
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <gdk/gdk.h>
+
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#include <X11/keysym.h>
+
+#ifdef HAVE_XTEST
+#include <X11/extensions/XTest.h>
+#endif /* HAVE_XTEST */
+#endif /* GDK_WINDOWING_X11 */
+
+#include "totem-scrsaver.h"
+
+#define GS_SERVICE "org.mate.ScreenSaver"
+#define GS_PATH "/org/mate/ScreenSaver"
+#define GS_INTERFACE "org.mate.ScreenSaver"
+
+#define XSCREENSAVER_MIN_TIMEOUT 60
+
+enum {
+ PROP_0,
+ PROP_REASON
+};
+
+static void totem_scrsaver_finalize (GObject *object);
+
+struct TotemScrsaverPrivate {
+ /* Whether the screensaver is disabled */
+ gboolean disabled;
+ /* The reason for the inhibition */
+ char *reason;
+
+ GDBusProxy *gs_proxy;
+ gboolean have_screensaver_dbus;
+ guint32 cookie;
+ gboolean old_dbus_api;
+
+ /* To save the screensaver info */
+ int timeout;
+ int interval;
+ int prefer_blanking;
+ int allow_exposures;
+
+ /* For use with XTest */
+ int keycode1, keycode2;
+ int *keycode;
+ gboolean have_xtest;
+};
+
+G_DEFINE_TYPE(TotemScrsaver, totem_scrsaver, G_TYPE_OBJECT)
+
+static gboolean
+screensaver_is_running_dbus (TotemScrsaver *scr)
+{
+ return scr->priv->have_screensaver_dbus;
+}
+
+static void
+on_inhibit_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source_object);
+ TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
+ GVariant *value;
+ GError *error = NULL;
+
+ value = g_dbus_proxy_call_finish (proxy, res, &error);
+ if (!value) {
+ if (!scr->priv->old_dbus_api &&
+ g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
+ g_return_if_fail (scr->priv->reason != NULL);
+ /* try the old API */
+ scr->priv->old_dbus_api = TRUE;
+ g_dbus_proxy_call (proxy,
+ "InhibitActivation",
+ g_variant_new ("(s)",
+ scr->priv->reason),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1,
+ NULL,
+ on_inhibit_cb,
+ scr);
+ } else {
+ g_warning ("Problem inhibiting the screensaver: %s", error->message);
+ }
+ g_error_free (error);
+
+ return;
+ }
+
+ /* save the cookie */
+ if (g_variant_is_of_type (value, G_VARIANT_TYPE ("(u)")))
+ g_variant_get (value, "(u)", &scr->priv->cookie);
+ else
+ scr->priv->cookie = 0;
+ g_variant_unref (value);
+}
+
+static void
+on_uninhibit_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source_object);
+ TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
+ GVariant *value;
+ GError *error = NULL;
+
+ value = g_dbus_proxy_call_finish (proxy, res, &error);
+ if (!value) {
+ if (!scr->priv->old_dbus_api &&
+ g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
+ /* try the old API */
+ scr->priv->old_dbus_api = TRUE;
+ g_dbus_proxy_call (proxy,
+ "AllowActivation",
+ g_variant_new ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1,
+ NULL,
+ on_uninhibit_cb,
+ scr);
+ } else {
+ g_warning ("Problem uninhibiting the screensaver: %s", error->message);
+ }
+ g_error_free (error);
+
+ return;
+ }
+
+ /* clear the cookie */
+ scr->priv->cookie = 0;
+ g_variant_unref (value);
+}
+
+static void
+screensaver_inhibit_dbus (TotemScrsaver *scr,
+ gboolean inhibit)
+{
+ TotemScrsaverPrivate *priv = scr->priv;
+
+ if (!priv->have_screensaver_dbus)
+ return;
+
+ scr->priv->old_dbus_api = FALSE;
+
+ if (inhibit) {
+ g_return_if_fail (scr->priv->reason != NULL);
+ g_dbus_proxy_call (priv->gs_proxy,
+ "Inhibit",
+ g_variant_new ("(ss)",
+ g_get_application_name (),
+ scr->priv->reason),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1,
+ NULL,
+ on_inhibit_cb,
+ scr);
+ } else {
+ g_dbus_proxy_call (priv->gs_proxy,
+ "UnInhibit",
+ g_variant_new ("(u)", priv->cookie),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1,
+ NULL,
+ on_uninhibit_cb,
+ scr);
+ }
+}
+
+static void
+screensaver_enable_dbus (TotemScrsaver *scr)
+{
+ screensaver_inhibit_dbus (scr, FALSE);
+}
+
+static void
+screensaver_disable_dbus (TotemScrsaver *scr)
+{
+ screensaver_inhibit_dbus (scr, TRUE);
+}
+
+static void
+screensaver_update_dbus_presence (TotemScrsaver *scr)
+{
+ TotemScrsaverPrivate *priv = scr->priv;
+ gchar *name_owner;
+
+ name_owner = g_dbus_proxy_get_name_owner (priv->gs_proxy);
+ if (name_owner) {
+ priv->have_screensaver_dbus = TRUE;
+ g_free (name_owner);
+ } else {
+ priv->have_screensaver_dbus = FALSE;
+ }
+}
+
+static void
+screensaver_dbus_owner_changed_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
+
+ screensaver_update_dbus_presence (scr);
+}
+
+static void
+screensaver_dbus_proxy_new_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
+ TotemScrsaverPrivate *priv = scr->priv;
+
+ priv->gs_proxy = g_dbus_proxy_new_for_bus_finish (result, NULL);
+ if (!priv->gs_proxy)
+ return;
+
+ screensaver_update_dbus_presence (scr);
+
+ g_signal_connect (priv->gs_proxy, "notify::g-name-owner",
+ G_CALLBACK (screensaver_dbus_owner_changed_cb),
+ scr);
+}
+
+static void
+screensaver_init_dbus (TotemScrsaver *scr)
+{
+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+ NULL,
+ GS_SERVICE,
+ GS_PATH,
+ GS_INTERFACE,
+ NULL,
+ screensaver_dbus_proxy_new_cb,
+ scr);
+}
+
+static void
+screensaver_finalize_dbus (TotemScrsaver *scr)
+{
+ if (scr->priv->gs_proxy) {
+ g_object_unref (scr->priv->gs_proxy);
+ }
+}
+
+#ifdef GDK_WINDOWING_X11
+static void
+screensaver_enable_x11 (TotemScrsaver *scr)
+{
+
+#ifdef HAVE_XTEST
+ if (scr->priv->have_xtest != FALSE)
+ {
+ g_source_remove_by_user_data (scr);
+ return;
+ }
+#endif /* HAVE_XTEST */
+
+ XLockDisplay (GDK_DISPLAY());
+ XSetScreenSaver (GDK_DISPLAY(),
+ scr->priv->timeout,
+ scr->priv->interval,
+ scr->priv->prefer_blanking,
+ scr->priv->allow_exposures);
+ XUnlockDisplay (GDK_DISPLAY());
+}
+
+#ifdef HAVE_XTEST
+static gboolean
+fake_event (TotemScrsaver *scr)
+{
+ if (scr->priv->disabled)
+ {
+ XLockDisplay (GDK_DISPLAY());
+ XTestFakeKeyEvent (GDK_DISPLAY(), *scr->priv->keycode,
+ True, CurrentTime);
+ XTestFakeKeyEvent (GDK_DISPLAY(), *scr->priv->keycode,
+ False, CurrentTime);
+ XUnlockDisplay (GDK_DISPLAY());
+ /* Swap the keycode */
+ if (scr->priv->keycode == &scr->priv->keycode1)
+ scr->priv->keycode = &scr->priv->keycode2;
+ else
+ scr->priv->keycode = &scr->priv->keycode1;
+ }
+
+ return TRUE;
+}
+#endif /* HAVE_XTEST */
+
+static void
+screensaver_disable_x11 (TotemScrsaver *scr)
+{
+
+#ifdef HAVE_XTEST
+ if (scr->priv->have_xtest != FALSE)
+ {
+ XLockDisplay (GDK_DISPLAY());
+ XGetScreenSaver(GDK_DISPLAY(), &scr->priv->timeout,
+ &scr->priv->interval,
+ &scr->priv->prefer_blanking,
+ &scr->priv->allow_exposures);
+ XUnlockDisplay (GDK_DISPLAY());
+
+ if (scr->priv->timeout != 0) {
+ g_timeout_add_seconds (scr->priv->timeout / 2,
+ (GSourceFunc) fake_event, scr);
+ } else {
+ g_timeout_add_seconds (XSCREENSAVER_MIN_TIMEOUT / 2,
+ (GSourceFunc) fake_event, scr);
+ }
+
+ return;
+ }
+#endif /* HAVE_XTEST */
+
+ XLockDisplay (GDK_DISPLAY());
+ XGetScreenSaver(GDK_DISPLAY(), &scr->priv->timeout,
+ &scr->priv->interval,
+ &scr->priv->prefer_blanking,
+ &scr->priv->allow_exposures);
+ XSetScreenSaver(GDK_DISPLAY(), 0, 0,
+ DontPreferBlanking, DontAllowExposures);
+ XUnlockDisplay (GDK_DISPLAY());
+}
+
+static void
+screensaver_init_x11 (TotemScrsaver *scr)
+{
+#ifdef HAVE_XTEST
+ int a, b, c, d;
+
+ XLockDisplay (GDK_DISPLAY());
+ scr->priv->have_xtest = (XTestQueryExtension (GDK_DISPLAY(), &a, &b, &c, &d) == True);
+ if (scr->priv->have_xtest != FALSE)
+ {
+ scr->priv->keycode1 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
+ if (scr->priv->keycode1 == 0) {
+ g_warning ("scr->priv->keycode1 not existant");
+ }
+ scr->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_R);
+ if (scr->priv->keycode2 == 0) {
+ scr->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
+ if (scr->priv->keycode2 == 0) {
+ g_warning ("scr->priv->keycode2 not existant");
+ }
+ }
+ scr->priv->keycode = &scr->priv->keycode1;
+ }
+ XUnlockDisplay (GDK_DISPLAY());
+#endif /* HAVE_XTEST */
+}
+
+static void
+screensaver_finalize_x11 (TotemScrsaver *scr)
+{
+ g_source_remove_by_user_data (scr);
+}
+#endif
+
+static void
+totem_scrsaver_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TotemScrsaver *scr;
+
+ scr = TOTEM_SCRSAVER (object);
+
+ switch (property_id)
+ {
+ case PROP_REASON:
+ g_value_set_string (value, scr->priv->reason);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+totem_scrsaver_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TotemScrsaver *scr;
+
+ scr = TOTEM_SCRSAVER (object);
+
+ switch (property_id)
+ {
+ case PROP_REASON:
+ g_free (scr->priv->reason);
+ scr->priv->reason = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+totem_scrsaver_class_init (TotemScrsaverClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (TotemScrsaverPrivate));
+
+ object_class->set_property = totem_scrsaver_set_property;
+ object_class->get_property = totem_scrsaver_get_property;
+ object_class->finalize = totem_scrsaver_finalize;
+
+ g_object_class_install_property (object_class, PROP_REASON,
+ g_param_spec_string ("reason", NULL, NULL,
+ NULL, G_PARAM_READWRITE));
+
+}
+
+/**
+ * totem_scrsaver_new:
+ *
+ * Creates a #TotemScrsaver object.
+ * If the MATE screen saver is running, it uses its DBUS interface to
+ * inhibit the screensaver; otherwise it falls back to using the X
+ * screensaver functionality for this.
+ *
+ * Returns: a newly created #TotemScrsaver
+ */
+TotemScrsaver *
+totem_scrsaver_new (void)
+{
+ return TOTEM_SCRSAVER (g_object_new (TOTEM_TYPE_SCRSAVER, NULL));
+}
+
+static void
+totem_scrsaver_init (TotemScrsaver *scr)
+{
+ scr->priv = G_TYPE_INSTANCE_GET_PRIVATE (scr,
+ TOTEM_TYPE_SCRSAVER,
+ TotemScrsaverPrivate);
+
+ screensaver_init_dbus (scr);
+#ifdef GDK_WINDOWING_X11
+ screensaver_init_x11 (scr);
+#else
+#warning Unimplemented
+#endif
+}
+
+void
+totem_scrsaver_disable (TotemScrsaver *scr)
+{
+ g_return_if_fail (TOTEM_SCRSAVER (scr));
+
+ if (scr->priv->disabled != FALSE)
+ return;
+
+ scr->priv->disabled = TRUE;
+
+ if (screensaver_is_running_dbus (scr) != FALSE)
+ screensaver_disable_dbus (scr);
+ else
+#ifdef GDK_WINDOWING_X11
+ screensaver_disable_x11 (scr);
+#else
+#warning Unimplemented
+ {}
+#endif
+}
+
+void
+totem_scrsaver_enable (TotemScrsaver *scr)
+{
+ g_return_if_fail (TOTEM_SCRSAVER (scr));
+
+ if (scr->priv->disabled == FALSE)
+ return;
+
+ scr->priv->disabled = FALSE;
+
+ if (screensaver_is_running_dbus (scr) != FALSE)
+ screensaver_enable_dbus (scr);
+ else
+#ifdef GDK_WINDOWING_X11
+ screensaver_enable_x11 (scr);
+#else
+#warning Unimplemented
+ {}
+#endif
+}
+
+void
+totem_scrsaver_set_state (TotemScrsaver *scr, gboolean enable)
+{
+ g_return_if_fail (TOTEM_SCRSAVER (scr));
+
+ if (scr->priv->disabled == !enable)
+ return;
+
+ if (enable == FALSE)
+ totem_scrsaver_disable (scr);
+ else
+ totem_scrsaver_enable (scr);
+}
+
+static void
+totem_scrsaver_finalize (GObject *object)
+{
+ TotemScrsaver *scr = TOTEM_SCRSAVER (object);
+
+ g_free (scr->priv->reason);
+
+ screensaver_finalize_dbus (scr);
+#ifdef GDK_WINDOWING_X11
+ screensaver_finalize_x11 (scr);
+#else
+#warning Unimplemented
+ {}
+#endif
+
+ G_OBJECT_CLASS (totem_scrsaver_parent_class)->finalize (object);
+}