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