]> www.fi.muni.cz Git - evince.git/blob - cut-n-paste/totem-screensaver/totem-scrsaver.c
efa2b31506a7e13c7f74c10da9e7f43e4c19b297
[evince.git] / cut-n-paste / totem-screensaver / totem-scrsaver.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2
3    Copyright (C) 2004-2006 Bastien Nocera <hadess@hadess.net>
4    Copyright © 2010 Christian Persch
5
6    The Gnome Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The Gnome Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the Gnome Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19    Boston, MA 02110-1301  USA.
20
21    Author: Bastien Nocera <hadess@hadess.net>
22  */
23
24
25 #include "config.h"
26
27 #include <glib/gi18n.h>
28
29 #include <gdk/gdk.h>
30
31 #ifdef GDK_WINDOWING_X11
32 #include <gdk/gdkx.h>
33 #include <X11/keysym.h>
34
35 #ifdef HAVE_XTEST
36 #include <X11/extensions/XTest.h>
37 #endif /* HAVE_XTEST */
38 #endif /* GDK_WINDOWING_X11 */
39
40 #include "totem-scrsaver.h"
41
42 #define GS_SERVICE   "org.gnome.ScreenSaver"
43 #define GS_PATH      "/org/gnome/ScreenSaver"
44 #define GS_INTERFACE "org.gnome.ScreenSaver"
45
46 #define XSCREENSAVER_MIN_TIMEOUT 60
47
48 static void totem_scrsaver_finalize   (GObject *object);
49
50 struct TotemScrsaverPrivate {
51         /* Whether the screensaver is disabled */
52         gboolean disabled;
53
54         GDBusProxy *gs_proxy;
55         gboolean have_screensaver_dbus;
56         guint watch_id;
57         guint32 cookie;
58
59         /* To save the screensaver info */
60         int timeout;
61         int interval;
62         int prefer_blanking;
63         int allow_exposures;
64
65         /* For use with XTest */
66         int keycode1, keycode2;
67         int *keycode;
68         gboolean have_xtest;
69 };
70
71 G_DEFINE_TYPE(TotemScrsaver, totem_scrsaver, G_TYPE_OBJECT)
72
73 static gboolean
74 screensaver_is_running_dbus (TotemScrsaver *scr)
75 {
76         return scr->priv->have_screensaver_dbus;
77 }
78
79 static void
80 screensaver_inhibit_dbus (TotemScrsaver *scr,
81                           gboolean       inhibit)
82 {
83         TotemScrsaverPrivate *priv = scr->priv;
84         GError *error = NULL;
85         GVariant *value;
86
87         if (!priv->have_screensaver_dbus)
88                 return;
89
90         if (inhibit) {
91                 value = g_dbus_proxy_call_sync (priv->gs_proxy,
92                                                 "Inhibit",
93                                                 g_variant_new ("(ss)",
94                                                                "Evince",
95                                                                _("Running in presentation mode")),
96                                                 G_DBUS_CALL_FLAGS_NO_AUTO_START,
97                                                 -1,
98                                                 NULL,
99                                                 &error);
100                 if (error && g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
101                         /* try the old API */
102                         g_clear_error (&error);
103                         value = g_dbus_proxy_call_sync (priv->gs_proxy,
104                                                         "InhibitActivation",
105                                                         g_variant_new ("(s)",
106                                                                        _("Running in presentation mode")),
107                                                         G_DBUS_CALL_FLAGS_NO_AUTO_START,
108                                                         -1,
109                                                         NULL,
110                                                         &error);
111                 }
112                 if (value != NULL) {
113                         /* save the cookie */
114                         if (g_variant_is_of_type (value, G_VARIANT_TYPE ("(u)")))
115                                g_variant_get (value, "(u)", &priv->cookie);
116                         else
117                                 priv->cookie = 0;
118                         g_variant_unref (value);
119                 } else {
120                         g_warning ("Problem inhibiting the screensaver: %s", error->message);
121                         g_error_free (error);
122                 }
123
124         } else {
125                 value = g_dbus_proxy_call_sync (priv->gs_proxy,
126                                                 "UnInhibit",
127                                                 g_variant_new ("(u)", priv->cookie),
128                                                 G_DBUS_CALL_FLAGS_NO_AUTO_START,
129                                                 -1,
130                                                 NULL,
131                                                 &error);
132                 if (error && g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
133                         /* try the old API */
134                         g_clear_error (&error);
135                         value = g_dbus_proxy_call_sync (priv->gs_proxy,
136                                                         "AllowActivation",
137                                                         g_variant_new ("()"),
138                                                         G_DBUS_CALL_FLAGS_NO_AUTO_START,
139                                                         -1,
140                                                         NULL,
141                                                         &error);
142                 }
143                 if (value != NULL) {
144                         /* clear the cookie */
145                         priv->cookie = 0;
146                         g_variant_unref (value);
147                 } else {
148                         g_warning ("Problem uninhibiting the screensaver: %s", error->message);
149                         g_error_free (error);
150                 }
151         }
152 }
153
154 static void
155 screensaver_enable_dbus (TotemScrsaver *scr)
156 {
157         screensaver_inhibit_dbus (scr, FALSE);
158 }
159
160 static void
161 screensaver_disable_dbus (TotemScrsaver *scr)
162 {
163         screensaver_inhibit_dbus (scr, TRUE);
164 }
165
166 static void
167 screensaver_dbus_appeared_cb (GDBusConnection *connection,
168                               const gchar     *name,
169                               const gchar     *name_owner,
170                               GDBusProxy      *proxy,
171                               gpointer         user_data)
172 {
173         TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
174         TotemScrsaverPrivate *priv = scr->priv;
175
176         priv->gs_proxy = g_object_ref (proxy);
177
178         priv->have_screensaver_dbus = TRUE;
179 }
180
181 static void
182 screensaver_dbus_disappeared_cb (GDBusConnection *connection,
183                                  const gchar     *name,
184                                  gpointer         user_data)
185 {
186         TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
187         TotemScrsaverPrivate *priv = scr->priv;
188
189         if (priv->gs_proxy) {
190                 g_object_unref (priv->gs_proxy);
191                 priv->gs_proxy = NULL;
192         }
193
194         priv->have_screensaver_dbus = FALSE;
195 }
196
197 static void
198 screensaver_init_dbus (TotemScrsaver *scr)
199 {
200         TotemScrsaverPrivate *priv = scr->priv;
201
202         priv->watch_id = g_bus_watch_proxy (G_BUS_TYPE_SESSION,
203                                             GS_SERVICE,
204                                             G_BUS_NAME_WATCHER_FLAGS_NONE,
205                                             GS_PATH,
206                                             GS_INTERFACE,
207                                             G_TYPE_DBUS_PROXY,
208                                             G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
209                                             G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
210                                             screensaver_dbus_appeared_cb,
211                                             screensaver_dbus_disappeared_cb,
212                                             scr, NULL);
213 }
214
215 static void
216 screensaver_finalize_dbus (TotemScrsaver *scr)
217 {
218         TotemScrsaverPrivate *priv = scr->priv;
219
220         if (scr->priv->gs_proxy) {
221                 g_object_unref (scr->priv->gs_proxy);
222         }
223
224         if (priv->watch_id > 0)
225                 g_bus_unwatch_proxy (priv->watch_id);
226 }
227
228 #ifdef GDK_WINDOWING_X11
229 static void
230 screensaver_enable_x11 (TotemScrsaver *scr)
231 {
232
233 #ifdef HAVE_XTEST
234         if (scr->priv->have_xtest != FALSE)
235         {
236                 g_source_remove_by_user_data (scr);
237                 return;
238         }
239 #endif /* HAVE_XTEST */
240
241         XLockDisplay (GDK_DISPLAY());
242         XSetScreenSaver (GDK_DISPLAY(),
243                         scr->priv->timeout,
244                         scr->priv->interval,
245                         scr->priv->prefer_blanking,
246                         scr->priv->allow_exposures);
247         XUnlockDisplay (GDK_DISPLAY());
248 }
249
250 #ifdef HAVE_XTEST
251 static gboolean
252 fake_event (TotemScrsaver *scr)
253 {
254         if (scr->priv->disabled)
255         {
256                 XLockDisplay (GDK_DISPLAY());
257                 XTestFakeKeyEvent (GDK_DISPLAY(), *scr->priv->keycode,
258                                 True, CurrentTime);
259                 XTestFakeKeyEvent (GDK_DISPLAY(), *scr->priv->keycode,
260                                 False, CurrentTime);
261                 XUnlockDisplay (GDK_DISPLAY());
262                 /* Swap the keycode */
263                 if (scr->priv->keycode == &scr->priv->keycode1)
264                         scr->priv->keycode = &scr->priv->keycode2;
265                 else
266                         scr->priv->keycode = &scr->priv->keycode1;
267         }
268
269         return TRUE;
270 }
271 #endif /* HAVE_XTEST */
272
273 static void
274 screensaver_disable_x11 (TotemScrsaver *scr)
275 {
276
277 #ifdef HAVE_XTEST
278         if (scr->priv->have_xtest != FALSE)
279         {
280                 XLockDisplay (GDK_DISPLAY());
281                 XGetScreenSaver(GDK_DISPLAY(), &scr->priv->timeout,
282                                 &scr->priv->interval,
283                                 &scr->priv->prefer_blanking,
284                                 &scr->priv->allow_exposures);
285                 XUnlockDisplay (GDK_DISPLAY());
286
287                 if (scr->priv->timeout != 0) {
288                         g_timeout_add_seconds (scr->priv->timeout / 2,
289                                                (GSourceFunc) fake_event, scr);
290                 } else {
291                         g_timeout_add_seconds (XSCREENSAVER_MIN_TIMEOUT / 2,
292                                                (GSourceFunc) fake_event, scr);
293                 }
294
295                 return;
296         }
297 #endif /* HAVE_XTEST */
298
299         XLockDisplay (GDK_DISPLAY());
300         XGetScreenSaver(GDK_DISPLAY(), &scr->priv->timeout,
301                         &scr->priv->interval,
302                         &scr->priv->prefer_blanking,
303                         &scr->priv->allow_exposures);
304         XSetScreenSaver(GDK_DISPLAY(), 0, 0,
305                         DontPreferBlanking, DontAllowExposures);
306         XUnlockDisplay (GDK_DISPLAY());
307 }
308
309 static void
310 screensaver_init_x11 (TotemScrsaver *scr)
311 {
312 #ifdef HAVE_XTEST
313         int a, b, c, d;
314
315         XLockDisplay (GDK_DISPLAY());
316         scr->priv->have_xtest = (XTestQueryExtension (GDK_DISPLAY(), &a, &b, &c, &d) == True);
317         if (scr->priv->have_xtest != FALSE)
318         {
319                 scr->priv->keycode1 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
320                 if (scr->priv->keycode1 == 0) {
321                         g_warning ("scr->priv->keycode1 not existant");
322                 }
323                 scr->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_R);
324                 if (scr->priv->keycode2 == 0) {
325                         scr->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
326                         if (scr->priv->keycode2 == 0) {
327                                 g_warning ("scr->priv->keycode2 not existant");
328                         }
329                 }
330                 scr->priv->keycode = &scr->priv->keycode1;
331         }
332         XUnlockDisplay (GDK_DISPLAY());
333 #endif /* HAVE_XTEST */
334 }
335
336 static void
337 screensaver_finalize_x11 (TotemScrsaver *scr)
338 {
339         g_source_remove_by_user_data (scr);
340 }
341 #endif
342
343 static void
344 totem_scrsaver_class_init (TotemScrsaverClass *klass)
345 {
346         GObjectClass *object_class = G_OBJECT_CLASS (klass);
347
348         object_class->finalize = totem_scrsaver_finalize;
349 }
350
351 /**
352  * totem_scrsaver_new:
353  *
354  * Creates a #TotemScrsaver object.
355  * If the GNOME screen saver is running, it uses its DBUS interface to
356  * inhibit the screensaver; otherwise it falls back to using the X
357  * screensaver functionality for this.
358  *
359  * Returns: a newly created #TotemScrsaver
360  */
361 TotemScrsaver *
362 totem_scrsaver_new (void)
363 {
364         return TOTEM_SCRSAVER (g_object_new (TOTEM_TYPE_SCRSAVER, NULL));
365 }
366
367 static void
368 totem_scrsaver_init (TotemScrsaver *scr)
369 {
370         scr->priv = g_new0 (TotemScrsaverPrivate, 1);
371
372         screensaver_init_dbus (scr);
373 #ifdef GDK_WINDOWING_X11
374         screensaver_init_x11 (scr);
375 #else
376 #warning Unimplemented
377 #endif
378 }
379
380 void
381 totem_scrsaver_disable (TotemScrsaver *scr)
382 {
383         g_return_if_fail (TOTEM_SCRSAVER (scr));
384
385         if (scr->priv->disabled != FALSE)
386                 return;
387
388         scr->priv->disabled = TRUE;
389
390         if (screensaver_is_running_dbus (scr) != FALSE)
391                 screensaver_disable_dbus (scr);
392         else 
393 #ifdef GDK_WINDOWING_X11
394                 screensaver_disable_x11 (scr);
395 #else
396 #warning Unimplemented
397         {}
398 #endif
399 }
400
401 void
402 totem_scrsaver_enable (TotemScrsaver *scr)
403 {
404         g_return_if_fail (TOTEM_SCRSAVER (scr));
405
406         if (scr->priv->disabled == FALSE)
407                 return;
408
409         scr->priv->disabled = FALSE;
410
411         if (screensaver_is_running_dbus (scr) != FALSE)
412                 screensaver_enable_dbus (scr);
413         else 
414 #ifdef GDK_WINDOWING_X11
415                 screensaver_enable_x11 (scr);
416 #else
417 #warning Unimplemented
418         {}
419 #endif
420 }
421
422 void
423 totem_scrsaver_set_state (TotemScrsaver *scr, gboolean enable)
424 {
425         g_return_if_fail (TOTEM_SCRSAVER (scr));
426
427         if (scr->priv->disabled == !enable)
428                 return;
429
430         if (enable == FALSE)
431                 totem_scrsaver_disable (scr);
432         else
433                 totem_scrsaver_enable (scr);
434 }
435
436 static void
437 totem_scrsaver_finalize (GObject *object)
438 {
439         TotemScrsaver *scr = TOTEM_SCRSAVER (object);
440
441         screensaver_finalize_dbus (scr);
442 #ifdef GDK_WINDOWING_X11
443         screensaver_finalize_x11 (scr);
444 #else
445 #warning Unimplemented
446         {}
447 #endif
448
449         G_OBJECT_CLASS (totem_scrsaver_parent_class)->finalize (object);
450 }