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