]> www.fi.muni.cz Git - evince.git/blob - cut-n-paste/totem-screensaver/totem-scrsaver.c
[shell] Update ©
[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
6    The Gnome Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The Gnome Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the Gnome Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19    Boston, MA 02110-1301  USA.
20
21    Author: Bastien Nocera <hadess@hadess.net>
22  */
23
24
25 #include "config.h"
26
27 #include <glib/gi18n.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 static GObjectClass *parent_class = NULL;
49 static void totem_scrsaver_finalize   (GObject *object);
50
51 struct TotemScrsaverPrivate {
52         /* Whether the screensaver is disabled */
53         gboolean disabled;
54
55         GDBusConnection *connection;
56         gboolean have_screensaver_dbus;
57         guint watch_id;
58         guint32 cookie;
59
60         /* To save the screensaver info */
61         int timeout;
62         int interval;
63         int prefer_blanking;
64         int allow_exposures;
65
66         /* For use with XTest */
67         int keycode1, keycode2;
68         int *keycode;
69         gboolean have_xtest;
70 };
71
72 enum {
73         PROP_0,
74         PROP_CONNECTION
75 };
76
77 G_DEFINE_TYPE(TotemScrsaver, totem_scrsaver, G_TYPE_OBJECT)
78
79 static gboolean
80 screensaver_is_running_dbus (TotemScrsaver *scr)
81 {
82         return scr->priv->have_screensaver_dbus;
83 }
84
85 static void
86 screensaver_inhibit_dbus (TotemScrsaver *scr,
87                           gboolean       inhibit)
88 {
89         TotemScrsaverPrivate *priv = scr->priv;
90         GError *error = NULL;
91         GVariant *value;
92
93         if (!priv->have_screensaver_dbus)
94                 return;
95
96         if (inhibit) {
97                 value = g_dbus_connection_call_sync (priv->connection,
98                                                      GS_SERVICE,
99                                                      GS_PATH,
100                                                      GS_INTERFACE,
101                                                      "Inhibit",
102                                                      g_variant_new ("(ss)",
103                                                                     "Evince",
104                                                                     _("Running in presentation mode")),
105                                                      G_DBUS_CALL_FLAGS_NO_AUTO_START,
106                                                      -1,
107                                                      NULL,
108                                                      &error);
109                 if (error && g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
110                         /* try the old API */
111                         g_clear_error (&error);
112                         value = g_dbus_connection_call_sync (priv->connection,
113                                                              GS_SERVICE,
114                                                              GS_PATH,
115                                                              GS_INTERFACE,
116                                                              "InhibitActivation",
117                                                              g_variant_new ("(s)",
118                                                                             _("Running in presentation mode")),
119                                                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
120                                                              -1,
121                                                              NULL,
122                                                              &error);
123                 }
124                 if (value != NULL) {
125                         /* save the cookie */
126                         if (g_variant_is_of_type (value, G_VARIANT_TYPE ("(u)")))
127                                g_variant_get (value, "(u)", &priv->cookie);
128                         else
129                                 priv->cookie = 0;
130                         g_variant_unref (value);
131                 } else {
132                         g_warning ("Problem inhibiting the screensaver: %s", error->message);
133                         g_error_free (error);
134                 }
135
136         } else {
137                 value = g_dbus_connection_call_sync (priv->connection,
138                                                      GS_SERVICE,
139                                                      GS_PATH,
140                                                      GS_INTERFACE,
141                                                      "UnInhibit",
142                                                      g_variant_new ("(u)", priv->cookie),
143                                                      G_DBUS_CALL_FLAGS_NO_AUTO_START,
144                                                      -1,
145                                                      NULL,
146                                                      &error);
147                 if (error && g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
148                         /* try the old API */
149                         g_clear_error (&error);
150                         value = g_dbus_connection_call_sync (priv->connection,
151                                                              GS_SERVICE,
152                                                              GS_PATH,
153                                                              GS_INTERFACE,
154                                                              "AllowActivation",
155                                                              g_variant_new ("()"),
156                                                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
157                                                              -1,
158                                                              NULL,
159                                                              &error);
160                 }
161                 if (value != NULL) {
162                         /* clear the cookie */
163                         priv->cookie = 0;
164                         g_variant_unref (value);
165                 } else {
166                         g_warning ("Problem uninhibiting the screensaver: %s", error->message);
167                         g_error_free (error);
168                 }
169         }
170 }
171
172 static void
173 screensaver_enable_dbus (TotemScrsaver *scr)
174 {
175         screensaver_inhibit_dbus (scr, FALSE);
176 }
177
178 static void
179 screensaver_disable_dbus (TotemScrsaver *scr)
180 {
181         screensaver_inhibit_dbus (scr, TRUE);
182 }
183
184 static void
185 screensaver_dbus_appeared_cb (GDBusConnection *connection,
186                               const char      *name,
187                               const char      *name_owner,
188                               gpointer         user_data)
189 {
190         TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
191         TotemScrsaverPrivate *priv = scr->priv;
192
193         g_assert (connection == priv->connection);
194
195         priv->have_screensaver_dbus = TRUE;
196 }
197
198 static void
199 screensaver_dbus_disappeared_cb (GDBusConnection *connection,
200                                  const char      *name,
201                                  gpointer         user_data)
202 {
203         TotemScrsaver *scr = TOTEM_SCRSAVER (user_data);
204         TotemScrsaverPrivate *priv = scr->priv;
205
206         g_assert (connection == priv->connection);
207
208         priv->have_screensaver_dbus = FALSE;
209 }
210
211 static void
212 screensaver_finalize_dbus (TotemScrsaver *scr)
213 {
214         TotemScrsaverPrivate *priv = scr->priv;
215
216         if (priv->connection == NULL)
217                 return;
218
219         g_bus_unwatch_name (priv->watch_id);
220
221         g_object_unref (priv->connection);
222 }
223
224 #ifdef GDK_WINDOWING_X11
225 static void
226 screensaver_enable_x11 (TotemScrsaver *scr)
227 {
228
229 #ifdef HAVE_XTEST
230         if (scr->priv->have_xtest != FALSE)
231         {
232                 g_source_remove_by_user_data (scr);
233                 return;
234         }
235 #endif /* HAVE_XTEST */
236
237         XLockDisplay (GDK_DISPLAY());
238         XSetScreenSaver (GDK_DISPLAY(),
239                         scr->priv->timeout,
240                         scr->priv->interval,
241                         scr->priv->prefer_blanking,
242                         scr->priv->allow_exposures);
243         XUnlockDisplay (GDK_DISPLAY());
244 }
245
246 #ifdef HAVE_XTEST
247 static gboolean
248 fake_event (TotemScrsaver *scr)
249 {
250         if (scr->priv->disabled)
251         {
252                 XLockDisplay (GDK_DISPLAY());
253                 XTestFakeKeyEvent (GDK_DISPLAY(), *scr->priv->keycode,
254                                 True, CurrentTime);
255                 XTestFakeKeyEvent (GDK_DISPLAY(), *scr->priv->keycode,
256                                 False, CurrentTime);
257                 XUnlockDisplay (GDK_DISPLAY());
258                 /* Swap the keycode */
259                 if (scr->priv->keycode == &scr->priv->keycode1)
260                         scr->priv->keycode = &scr->priv->keycode2;
261                 else
262                         scr->priv->keycode = &scr->priv->keycode1;
263         }
264
265         return TRUE;
266 }
267 #endif /* HAVE_XTEST */
268
269 static void
270 screensaver_disable_x11 (TotemScrsaver *scr)
271 {
272
273 #ifdef HAVE_XTEST
274         if (scr->priv->have_xtest != FALSE)
275         {
276                 XLockDisplay (GDK_DISPLAY());
277                 XGetScreenSaver(GDK_DISPLAY(), &scr->priv->timeout,
278                                 &scr->priv->interval,
279                                 &scr->priv->prefer_blanking,
280                                 &scr->priv->allow_exposures);
281                 XUnlockDisplay (GDK_DISPLAY());
282
283                 if (scr->priv->timeout != 0) {
284                         g_timeout_add_seconds (scr->priv->timeout / 2,
285                                                (GSourceFunc) fake_event, scr);
286                 } else {
287                         g_timeout_add_seconds (XSCREENSAVER_MIN_TIMEOUT / 2,
288                                                (GSourceFunc) fake_event, scr);
289                 }
290
291                 return;
292         }
293 #endif /* HAVE_XTEST */
294
295         XLockDisplay (GDK_DISPLAY());
296         XGetScreenSaver(GDK_DISPLAY(), &scr->priv->timeout,
297                         &scr->priv->interval,
298                         &scr->priv->prefer_blanking,
299                         &scr->priv->allow_exposures);
300         XSetScreenSaver(GDK_DISPLAY(), 0, 0,
301                         DontPreferBlanking, DontAllowExposures);
302         XUnlockDisplay (GDK_DISPLAY());
303 }
304
305 static void
306 screensaver_init_x11 (TotemScrsaver *scr)
307 {
308 #ifdef HAVE_XTEST
309         int a, b, c, d;
310
311         XLockDisplay (GDK_DISPLAY());
312         scr->priv->have_xtest = (XTestQueryExtension (GDK_DISPLAY(), &a, &b, &c, &d) == True);
313         if (scr->priv->have_xtest != FALSE)
314         {
315                 scr->priv->keycode1 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
316                 if (scr->priv->keycode1 == 0) {
317                         g_warning ("scr->priv->keycode1 not existant");
318                 }
319                 scr->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_R);
320                 if (scr->priv->keycode2 == 0) {
321                         scr->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
322                         if (scr->priv->keycode2 == 0) {
323                                 g_warning ("scr->priv->keycode2 not existant");
324                         }
325                 }
326                 scr->priv->keycode = &scr->priv->keycode1;
327         }
328         XUnlockDisplay (GDK_DISPLAY());
329 #endif /* HAVE_XTEST */
330 }
331
332 static void
333 screensaver_finalize_x11 (TotemScrsaver *scr)
334 {
335         g_source_remove_by_user_data (scr);
336 }
337 #endif
338
339 static void
340 totem_scrsaver_constructed (GObject *object)
341 {
342         TotemScrsaver *scr = TOTEM_SCRSAVER (object);
343         TotemScrsaverPrivate *priv = scr->priv;
344
345         if (priv->connection == NULL)
346                 return;
347
348         priv->watch_id = g_bus_watch_name_on_connection (priv->connection,
349                                                          GS_SERVICE,
350                                                          G_BUS_NAME_WATCHER_FLAGS_NONE,
351                                                          screensaver_dbus_appeared_cb,
352                                                          screensaver_dbus_disappeared_cb,
353                                                          scr, NULL);
354 }
355
356 static void
357 totem_scrsaver_set_property (GObject      *object,
358                              guint         prop_id,
359                              const GValue *value,
360                              GParamSpec   *pspec)
361 {
362         TotemScrsaver *scr = TOTEM_SCRSAVER (object);
363         TotemScrsaverPrivate *priv = scr->priv;
364
365         switch (prop_id) {
366         case PROP_CONNECTION:
367                 priv->connection = g_value_dup_object (value);
368                 break;
369         default:
370                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
371                 break;
372         }
373 }
374
375 static void
376 totem_scrsaver_class_init (TotemScrsaverClass *klass)
377 {
378         GObjectClass *object_class = G_OBJECT_CLASS (klass);
379
380         object_class->set_property = totem_scrsaver_set_property;
381         object_class->constructed = totem_scrsaver_constructed;
382         object_class->finalize = totem_scrsaver_finalize;
383
384         g_object_class_install_property (object_class,
385                                          PROP_CONNECTION,
386                                          g_param_spec_object ("connection", NULL, NULL,
387                                                               G_TYPE_DBUS_CONNECTION,
388                                                               G_PARAM_WRITABLE |
389                                                               G_PARAM_CONSTRUCT_ONLY |
390                                                               G_PARAM_STATIC_STRINGS));
391 }
392
393 /**
394  * totem_scrsaver_new:
395  * @connection: (allow-none): a #GDBusConnection, or %NULL
396  *
397  * Creates a #TotemScrsaver object. If @connection is non-%NULL,
398  * and the GNOME screen saver is running, it uses its DBUS interface to
399  * inhibit the screensaver; otherwise it falls back to using the X
400  * screensaver functionality for this.
401  *
402  * Returns: a newly created #TotemScrsaver
403  */
404 TotemScrsaver *
405 totem_scrsaver_new (GDBusConnection *connection)
406 {
407         return g_object_new (TOTEM_TYPE_SCRSAVER,
408                              "connection", connection,
409                              NULL);
410 }
411
412 static void
413 totem_scrsaver_init (TotemScrsaver *scr)
414 {
415         scr->priv = G_TYPE_INSTANCE_GET_PRIVATE (scr, TOTEM_TYPE_SCRSAVER, TotemScrsaverPrivate);
416
417 #ifdef GDK_WINDOWING_X11
418         screensaver_init_x11 (scr);
419 #else
420 #warning Unimplemented
421 #endif
422 }
423
424 void
425 totem_scrsaver_disable (TotemScrsaver *scr)
426 {
427         g_return_if_fail (TOTEM_SCRSAVER (scr));
428
429         if (scr->priv->disabled != FALSE)
430                 return;
431
432         scr->priv->disabled = TRUE;
433
434         if (screensaver_is_running_dbus (scr) != FALSE)
435                 screensaver_disable_dbus (scr);
436         else 
437 #ifdef GDK_WINDOWING_X11
438                 screensaver_disable_x11 (scr);
439 #else
440 #warning Unimplemented
441         {}
442 #endif
443 }
444
445 void
446 totem_scrsaver_enable (TotemScrsaver *scr)
447 {
448         g_return_if_fail (TOTEM_SCRSAVER (scr));
449
450         if (scr->priv->disabled == FALSE)
451                 return;
452
453         scr->priv->disabled = FALSE;
454
455         if (screensaver_is_running_dbus (scr) != FALSE)
456                 screensaver_enable_dbus (scr);
457         else 
458 #ifdef GDK_WINDOWING_X11
459                 screensaver_enable_x11 (scr);
460 #else
461 #warning Unimplemented
462         {}
463 #endif
464 }
465
466 void
467 totem_scrsaver_set_state (TotemScrsaver *scr, gboolean enable)
468 {
469         g_return_if_fail (TOTEM_SCRSAVER (scr));
470
471         if (scr->priv->disabled == !enable)
472                 return;
473
474         if (enable == FALSE)
475                 totem_scrsaver_disable (scr);
476         else
477                 totem_scrsaver_enable (scr);
478 }
479
480 static void
481 totem_scrsaver_finalize (GObject *object)
482 {
483         TotemScrsaver *scr = TOTEM_SCRSAVER (object);
484
485         screensaver_finalize_dbus (scr);
486 #ifdef GDK_WINDOWING_X11
487         screensaver_finalize_x11 (scr);
488 #else
489 #warning Unimplemented
490         {}
491 #endif
492
493         G_OBJECT_CLASS (parent_class)->finalize (object);
494 }