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