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