]> www.fi.muni.cz Git - evince.git/blob - cut-n-paste/totem-screensaver/totem-scrsaver.c
2b6c0d3f50cee245d22ae8f84b9f2a2bee230a57
[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         gboolean old_dbus_api;
59
60         /* To save the screensaver info */
61         int timeout;
62         int interval;
63         int prefer_blanking;
64         int allow_exposures;
65
66         /* For use with XTest */
67         int keycode1, keycode2;
68         int *keycode;
69         gboolean have_xtest;
70 };
71
72 G_DEFINE_TYPE(TotemScrsaver, totem_scrsaver, G_TYPE_OBJECT)
73
74 static gboolean
75 screensaver_is_running_dbus (TotemScrsaver *scr)
76 {
77         return scr->priv->have_screensaver_dbus;
78 }
79
80 static void
81 on_inhibit_cb (GObject      *source_object,
82                GAsyncResult *res,
83                gpointer      user_data)
84 {
85         GDBusProxy    *proxy = G_DBUS_PROXY (source_object);
86         TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
87         GVariant      *value;
88         GError        *error = NULL;
89
90         value = g_dbus_proxy_call_finish (proxy, res, &error);
91         if (!value) {
92                 if (!scr->priv->old_dbus_api &&
93                     g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
94                         /* try the old API */
95                         scr->priv->old_dbus_api = TRUE;
96                         g_dbus_proxy_call (proxy,
97                                            "InhibitActivation",
98                                            g_variant_new ("(s)",
99                                                           _("Running in presentation mode")),
100                                            G_DBUS_CALL_FLAGS_NO_AUTO_START,
101                                            -1,
102                                            NULL,
103                                            on_inhibit_cb,
104                                            scr);
105                 } else {
106                         g_warning ("Problem inhibiting the screensaver: %s", error->message);
107                 }
108                 g_error_free (error);
109
110                 return;
111         }
112
113         /* save the cookie */
114         if (g_variant_is_of_type (value, G_VARIANT_TYPE ("(u)")))
115                 g_variant_get (value, "(u)", &scr->priv->cookie);
116         else
117                 scr->priv->cookie = 0;
118         g_variant_unref (value);
119 }
120
121 static void
122 on_uninhibit_cb (GObject      *source_object,
123                  GAsyncResult *res,
124                  gpointer      user_data)
125 {
126         GDBusProxy    *proxy = G_DBUS_PROXY (source_object);
127         TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
128         GVariant      *value;
129         GError        *error = NULL;
130
131         value = g_dbus_proxy_call_finish (proxy, res, &error);
132         if (!value) {
133                 if (!scr->priv->old_dbus_api &&
134                     g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
135                         /* try the old API */
136                         scr->priv->old_dbus_api = TRUE;
137                         g_dbus_proxy_call (proxy,
138                                            "AllowActivation",
139                                            g_variant_new ("()"),
140                                            G_DBUS_CALL_FLAGS_NO_AUTO_START,
141                                            -1,
142                                            NULL,
143                                            on_uninhibit_cb,
144                                            scr);
145                 } else {
146                         g_warning ("Problem uninhibiting the screensaver: %s", error->message);
147                 }
148                 g_error_free (error);
149
150                 return;
151         }
152
153         /* clear the cookie */
154         scr->priv->cookie = 0;
155         g_variant_unref (value);
156 }
157
158 static void
159 screensaver_inhibit_dbus (TotemScrsaver *scr,
160                           gboolean       inhibit)
161 {
162         TotemScrsaverPrivate *priv = scr->priv;
163
164         if (!priv->have_screensaver_dbus)
165                 return;
166
167         scr->priv->old_dbus_api = FALSE;
168
169         if (inhibit) {
170                 g_dbus_proxy_call (priv->gs_proxy,
171                                    "Inhibit",
172                                    g_variant_new ("(ss)",
173                                                   "Evince",
174                                                   _("Running in presentation mode")),
175                                    G_DBUS_CALL_FLAGS_NO_AUTO_START,
176                                    -1,
177                                    NULL,
178                                    on_inhibit_cb,
179                                    scr);
180         } else {
181                 g_dbus_proxy_call (priv->gs_proxy,
182                                    "UnInhibit",
183                                    g_variant_new ("(u)", priv->cookie),
184                                    G_DBUS_CALL_FLAGS_NO_AUTO_START,
185                                    -1,
186                                    NULL,
187                                    on_uninhibit_cb,
188                                    scr);
189         }
190 }
191
192 static void
193 screensaver_enable_dbus (TotemScrsaver *scr)
194 {
195         screensaver_inhibit_dbus (scr, FALSE);
196 }
197
198 static void
199 screensaver_disable_dbus (TotemScrsaver *scr)
200 {
201         screensaver_inhibit_dbus (scr, TRUE);
202 }
203
204 static void
205 screensaver_dbus_appeared_cb (GDBusConnection *connection,
206                               const gchar     *name,
207                               const gchar     *name_owner,
208                               GDBusProxy      *proxy,
209                               gpointer         user_data)
210 {
211         TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
212         TotemScrsaverPrivate *priv = scr->priv;
213
214         priv->gs_proxy = g_object_ref (proxy);
215
216         priv->have_screensaver_dbus = TRUE;
217 }
218
219 static void
220 screensaver_dbus_disappeared_cb (GDBusConnection *connection,
221                                  const gchar     *name,
222                                  gpointer         user_data)
223 {
224         TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
225         TotemScrsaverPrivate *priv = scr->priv;
226
227         if (priv->gs_proxy) {
228                 g_object_unref (priv->gs_proxy);
229                 priv->gs_proxy = NULL;
230         }
231
232         priv->have_screensaver_dbus = FALSE;
233 }
234
235 static void
236 screensaver_init_dbus (TotemScrsaver *scr)
237 {
238         TotemScrsaverPrivate *priv = scr->priv;
239
240         priv->watch_id = g_bus_watch_proxy (G_BUS_TYPE_SESSION,
241                                             GS_SERVICE,
242                                             G_BUS_NAME_WATCHER_FLAGS_NONE,
243                                             GS_PATH,
244                                             GS_INTERFACE,
245                                             G_TYPE_DBUS_PROXY,
246                                             G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
247                                             G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
248                                             screensaver_dbus_appeared_cb,
249                                             screensaver_dbus_disappeared_cb,
250                                             scr, NULL);
251 }
252
253 static void
254 screensaver_finalize_dbus (TotemScrsaver *scr)
255 {
256         TotemScrsaverPrivate *priv = scr->priv;
257
258         if (scr->priv->gs_proxy) {
259                 g_object_unref (scr->priv->gs_proxy);
260         }
261
262         if (priv->watch_id > 0)
263                 g_bus_unwatch_proxy (priv->watch_id);
264 }
265
266 #ifdef GDK_WINDOWING_X11
267 static void
268 screensaver_enable_x11 (TotemScrsaver *scr)
269 {
270
271 #ifdef HAVE_XTEST
272         if (scr->priv->have_xtest != FALSE)
273         {
274                 g_source_remove_by_user_data (scr);
275                 return;
276         }
277 #endif /* HAVE_XTEST */
278
279         XLockDisplay (GDK_DISPLAY());
280         XSetScreenSaver (GDK_DISPLAY(),
281                         scr->priv->timeout,
282                         scr->priv->interval,
283                         scr->priv->prefer_blanking,
284                         scr->priv->allow_exposures);
285         XUnlockDisplay (GDK_DISPLAY());
286 }
287
288 #ifdef HAVE_XTEST
289 static gboolean
290 fake_event (TotemScrsaver *scr)
291 {
292         if (scr->priv->disabled)
293         {
294                 XLockDisplay (GDK_DISPLAY());
295                 XTestFakeKeyEvent (GDK_DISPLAY(), *scr->priv->keycode,
296                                 True, CurrentTime);
297                 XTestFakeKeyEvent (GDK_DISPLAY(), *scr->priv->keycode,
298                                 False, CurrentTime);
299                 XUnlockDisplay (GDK_DISPLAY());
300                 /* Swap the keycode */
301                 if (scr->priv->keycode == &scr->priv->keycode1)
302                         scr->priv->keycode = &scr->priv->keycode2;
303                 else
304                         scr->priv->keycode = &scr->priv->keycode1;
305         }
306
307         return TRUE;
308 }
309 #endif /* HAVE_XTEST */
310
311 static void
312 screensaver_disable_x11 (TotemScrsaver *scr)
313 {
314
315 #ifdef HAVE_XTEST
316         if (scr->priv->have_xtest != FALSE)
317         {
318                 XLockDisplay (GDK_DISPLAY());
319                 XGetScreenSaver(GDK_DISPLAY(), &scr->priv->timeout,
320                                 &scr->priv->interval,
321                                 &scr->priv->prefer_blanking,
322                                 &scr->priv->allow_exposures);
323                 XUnlockDisplay (GDK_DISPLAY());
324
325                 if (scr->priv->timeout != 0) {
326                         g_timeout_add_seconds (scr->priv->timeout / 2,
327                                                (GSourceFunc) fake_event, scr);
328                 } else {
329                         g_timeout_add_seconds (XSCREENSAVER_MIN_TIMEOUT / 2,
330                                                (GSourceFunc) fake_event, scr);
331                 }
332
333                 return;
334         }
335 #endif /* HAVE_XTEST */
336
337         XLockDisplay (GDK_DISPLAY());
338         XGetScreenSaver(GDK_DISPLAY(), &scr->priv->timeout,
339                         &scr->priv->interval,
340                         &scr->priv->prefer_blanking,
341                         &scr->priv->allow_exposures);
342         XSetScreenSaver(GDK_DISPLAY(), 0, 0,
343                         DontPreferBlanking, DontAllowExposures);
344         XUnlockDisplay (GDK_DISPLAY());
345 }
346
347 static void
348 screensaver_init_x11 (TotemScrsaver *scr)
349 {
350 #ifdef HAVE_XTEST
351         int a, b, c, d;
352
353         XLockDisplay (GDK_DISPLAY());
354         scr->priv->have_xtest = (XTestQueryExtension (GDK_DISPLAY(), &a, &b, &c, &d) == True);
355         if (scr->priv->have_xtest != FALSE)
356         {
357                 scr->priv->keycode1 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
358                 if (scr->priv->keycode1 == 0) {
359                         g_warning ("scr->priv->keycode1 not existant");
360                 }
361                 scr->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_R);
362                 if (scr->priv->keycode2 == 0) {
363                         scr->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
364                         if (scr->priv->keycode2 == 0) {
365                                 g_warning ("scr->priv->keycode2 not existant");
366                         }
367                 }
368                 scr->priv->keycode = &scr->priv->keycode1;
369         }
370         XUnlockDisplay (GDK_DISPLAY());
371 #endif /* HAVE_XTEST */
372 }
373
374 static void
375 screensaver_finalize_x11 (TotemScrsaver *scr)
376 {
377         g_source_remove_by_user_data (scr);
378 }
379 #endif
380
381 static void
382 totem_scrsaver_class_init (TotemScrsaverClass *klass)
383 {
384         GObjectClass *object_class = G_OBJECT_CLASS (klass);
385
386         g_type_class_add_private (klass, sizeof (TotemScrsaverPrivate));
387
388         object_class->finalize = totem_scrsaver_finalize;
389 }
390
391 /**
392  * totem_scrsaver_new:
393  *
394  * Creates a #TotemScrsaver object.
395  * If the GNOME screen saver is running, it uses its DBUS interface to
396  * inhibit the screensaver; otherwise it falls back to using the X
397  * screensaver functionality for this.
398  *
399  * Returns: a newly created #TotemScrsaver
400  */
401 TotemScrsaver *
402 totem_scrsaver_new (void)
403 {
404         return TOTEM_SCRSAVER (g_object_new (TOTEM_TYPE_SCRSAVER, NULL));
405 }
406
407 static void
408 totem_scrsaver_init (TotemScrsaver *scr)
409 {
410         scr->priv = G_TYPE_INSTANCE_GET_PRIVATE (scr,
411                                                  TOTEM_TYPE_SCRSAVER,
412                                                  TotemScrsaverPrivate);
413
414         screensaver_init_dbus (scr);
415 #ifdef GDK_WINDOWING_X11
416         screensaver_init_x11 (scr);
417 #else
418 #warning Unimplemented
419 #endif
420 }
421
422 void
423 totem_scrsaver_disable (TotemScrsaver *scr)
424 {
425         g_return_if_fail (TOTEM_SCRSAVER (scr));
426
427         if (scr->priv->disabled != FALSE)
428                 return;
429
430         scr->priv->disabled = TRUE;
431
432         if (screensaver_is_running_dbus (scr) != FALSE)
433                 screensaver_disable_dbus (scr);
434         else 
435 #ifdef GDK_WINDOWING_X11
436                 screensaver_disable_x11 (scr);
437 #else
438 #warning Unimplemented
439         {}
440 #endif
441 }
442
443 void
444 totem_scrsaver_enable (TotemScrsaver *scr)
445 {
446         g_return_if_fail (TOTEM_SCRSAVER (scr));
447
448         if (scr->priv->disabled == FALSE)
449                 return;
450
451         scr->priv->disabled = FALSE;
452
453         if (screensaver_is_running_dbus (scr) != FALSE)
454                 screensaver_enable_dbus (scr);
455         else 
456 #ifdef GDK_WINDOWING_X11
457                 screensaver_enable_x11 (scr);
458 #else
459 #warning Unimplemented
460         {}
461 #endif
462 }
463
464 void
465 totem_scrsaver_set_state (TotemScrsaver *scr, gboolean enable)
466 {
467         g_return_if_fail (TOTEM_SCRSAVER (scr));
468
469         if (scr->priv->disabled == !enable)
470                 return;
471
472         if (enable == FALSE)
473                 totem_scrsaver_disable (scr);
474         else
475                 totem_scrsaver_enable (scr);
476 }
477
478 static void
479 totem_scrsaver_finalize (GObject *object)
480 {
481         TotemScrsaver *scr = TOTEM_SCRSAVER (object);
482
483         screensaver_finalize_dbus (scr);
484 #ifdef GDK_WINDOWING_X11
485         screensaver_finalize_x11 (scr);
486 #else
487 #warning Unimplemented
488         {}
489 #endif
490
491         G_OBJECT_CLASS (totem_scrsaver_parent_class)->finalize (object);
492 }