]> www.fi.muni.cz Git - evince.git/blob - cut-n-paste/totem-screensaver/totem-scrsaver.c
c8dcc09edf1a3b3cc1ec92356931fbad6643b933
[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
283 #ifdef HAVE_XTEST
284         if (scr->priv->have_xtest != FALSE)
285         {
286                 g_source_remove_by_user_data (scr);
287                 return;
288         }
289 #endif /* HAVE_XTEST */
290
291         XLockDisplay (GDK_DISPLAY());
292         XSetScreenSaver (GDK_DISPLAY(),
293                         scr->priv->timeout,
294                         scr->priv->interval,
295                         scr->priv->prefer_blanking,
296                         scr->priv->allow_exposures);
297         XUnlockDisplay (GDK_DISPLAY());
298 }
299
300 #ifdef HAVE_XTEST
301 static gboolean
302 fake_event (TotemScrsaver *scr)
303 {
304         if (scr->priv->disabled)
305         {
306                 XLockDisplay (GDK_DISPLAY());
307                 XTestFakeKeyEvent (GDK_DISPLAY(), *scr->priv->keycode,
308                                 True, CurrentTime);
309                 XTestFakeKeyEvent (GDK_DISPLAY(), *scr->priv->keycode,
310                                 False, CurrentTime);
311                 XUnlockDisplay (GDK_DISPLAY());
312                 /* Swap the keycode */
313                 if (scr->priv->keycode == &scr->priv->keycode1)
314                         scr->priv->keycode = &scr->priv->keycode2;
315                 else
316                         scr->priv->keycode = &scr->priv->keycode1;
317         }
318
319         return TRUE;
320 }
321 #endif /* HAVE_XTEST */
322
323 static void
324 screensaver_disable_x11 (TotemScrsaver *scr)
325 {
326
327 #ifdef HAVE_XTEST
328         if (scr->priv->have_xtest != FALSE)
329         {
330                 XLockDisplay (GDK_DISPLAY());
331                 XGetScreenSaver(GDK_DISPLAY(), &scr->priv->timeout,
332                                 &scr->priv->interval,
333                                 &scr->priv->prefer_blanking,
334                                 &scr->priv->allow_exposures);
335                 XUnlockDisplay (GDK_DISPLAY());
336
337                 if (scr->priv->timeout != 0) {
338                         g_timeout_add_seconds (scr->priv->timeout / 2,
339                                                (GSourceFunc) fake_event, scr);
340                 } else {
341                         g_timeout_add_seconds (XSCREENSAVER_MIN_TIMEOUT / 2,
342                                                (GSourceFunc) fake_event, scr);
343                 }
344
345                 return;
346         }
347 #endif /* HAVE_XTEST */
348
349         XLockDisplay (GDK_DISPLAY());
350         XGetScreenSaver(GDK_DISPLAY(), &scr->priv->timeout,
351                         &scr->priv->interval,
352                         &scr->priv->prefer_blanking,
353                         &scr->priv->allow_exposures);
354         XSetScreenSaver(GDK_DISPLAY(), 0, 0,
355                         DontPreferBlanking, DontAllowExposures);
356         XUnlockDisplay (GDK_DISPLAY());
357 }
358
359 static void
360 screensaver_init_x11 (TotemScrsaver *scr)
361 {
362 #ifdef HAVE_XTEST
363         int a, b, c, d;
364
365         XLockDisplay (GDK_DISPLAY());
366         scr->priv->have_xtest = (XTestQueryExtension (GDK_DISPLAY(), &a, &b, &c, &d) == True);
367         if (scr->priv->have_xtest != FALSE)
368         {
369                 scr->priv->keycode1 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
370                 if (scr->priv->keycode1 == 0) {
371                         g_warning ("scr->priv->keycode1 not existant");
372                 }
373                 scr->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_R);
374                 if (scr->priv->keycode2 == 0) {
375                         scr->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
376                         if (scr->priv->keycode2 == 0) {
377                                 g_warning ("scr->priv->keycode2 not existant");
378                         }
379                 }
380                 scr->priv->keycode = &scr->priv->keycode1;
381         }
382         XUnlockDisplay (GDK_DISPLAY());
383 #endif /* HAVE_XTEST */
384 }
385
386 static void
387 screensaver_finalize_x11 (TotemScrsaver *scr)
388 {
389         g_source_remove_by_user_data (scr);
390 }
391 #endif
392
393 static void
394 totem_scrsaver_get_property (GObject *object,
395                              guint property_id,
396                              GValue *value,
397                              GParamSpec *pspec)
398 {
399         TotemScrsaver *scr;
400
401         scr = TOTEM_SCRSAVER (object);
402
403         switch (property_id)
404         {
405         case PROP_REASON:
406                 g_value_set_string (value, scr->priv->reason);
407                 break;
408         default:
409                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
410         }
411 }
412
413 static void
414 totem_scrsaver_set_property (GObject *object,
415                              guint property_id,
416                              const GValue *value,
417                              GParamSpec *pspec)
418 {
419         TotemScrsaver *scr;
420
421         scr = TOTEM_SCRSAVER (object);
422
423         switch (property_id)
424         {
425         case PROP_REASON:
426                 g_free (scr->priv->reason);
427                 scr->priv->reason = g_value_dup_string (value);
428                 break;
429         default:
430                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
431         }
432 }
433
434 static void
435 totem_scrsaver_class_init (TotemScrsaverClass *klass)
436 {
437         GObjectClass *object_class = G_OBJECT_CLASS (klass);
438
439         g_type_class_add_private (klass, sizeof (TotemScrsaverPrivate));
440
441         object_class->set_property = totem_scrsaver_set_property;
442         object_class->get_property = totem_scrsaver_get_property;
443         object_class->finalize = totem_scrsaver_finalize;
444
445         g_object_class_install_property (object_class, PROP_REASON,
446                                          g_param_spec_string ("reason", NULL, NULL,
447                                                               NULL, G_PARAM_READWRITE));
448
449 }
450
451 /**
452  * totem_scrsaver_new:
453  *
454  * Creates a #TotemScrsaver object.
455  * If the GNOME screen saver is running, it uses its DBUS interface to
456  * inhibit the screensaver; otherwise it falls back to using the X
457  * screensaver functionality for this.
458  *
459  * Returns: a newly created #TotemScrsaver
460  */
461 TotemScrsaver *
462 totem_scrsaver_new (void)
463 {
464         return TOTEM_SCRSAVER (g_object_new (TOTEM_TYPE_SCRSAVER, NULL));
465 }
466
467 static void
468 totem_scrsaver_init (TotemScrsaver *scr)
469 {
470         scr->priv = G_TYPE_INSTANCE_GET_PRIVATE (scr,
471                                                  TOTEM_TYPE_SCRSAVER,
472                                                  TotemScrsaverPrivate);
473
474         screensaver_init_dbus (scr);
475 #ifdef GDK_WINDOWING_X11
476         screensaver_init_x11 (scr);
477 #else
478 #warning Unimplemented
479 #endif
480 }
481
482 void
483 totem_scrsaver_disable (TotemScrsaver *scr)
484 {
485         g_return_if_fail (TOTEM_SCRSAVER (scr));
486
487         if (scr->priv->disabled != FALSE)
488                 return;
489
490         scr->priv->disabled = TRUE;
491
492         if (screensaver_is_running_dbus (scr) != FALSE)
493                 screensaver_disable_dbus (scr);
494         else 
495 #ifdef GDK_WINDOWING_X11
496                 screensaver_disable_x11 (scr);
497 #else
498 #warning Unimplemented
499         {}
500 #endif
501 }
502
503 void
504 totem_scrsaver_enable (TotemScrsaver *scr)
505 {
506         g_return_if_fail (TOTEM_SCRSAVER (scr));
507
508         if (scr->priv->disabled == FALSE)
509                 return;
510
511         scr->priv->disabled = FALSE;
512
513         if (screensaver_is_running_dbus (scr) != FALSE)
514                 screensaver_enable_dbus (scr);
515         else
516 #ifdef GDK_WINDOWING_X11
517                 screensaver_enable_x11 (scr);
518 #else
519 #warning Unimplemented
520         {}
521 #endif
522 }
523
524 void
525 totem_scrsaver_set_state (TotemScrsaver *scr, gboolean enable)
526 {
527         g_return_if_fail (TOTEM_SCRSAVER (scr));
528
529         if (scr->priv->disabled == !enable)
530                 return;
531
532         if (enable == FALSE)
533                 totem_scrsaver_disable (scr);
534         else
535                 totem_scrsaver_enable (scr);
536 }
537
538 static void
539 totem_scrsaver_finalize (GObject *object)
540 {
541         TotemScrsaver *scr = TOTEM_SCRSAVER (object);
542
543         g_free (scr->priv->reason);
544
545         screensaver_finalize_dbus (scr);
546 #ifdef GDK_WINDOWING_X11
547         screensaver_finalize_x11 (scr);
548 #else
549 #warning Unimplemented
550         {}
551 #endif
552
553         G_OBJECT_CLASS (totem_scrsaver_parent_class)->finalize (object);
554 }