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