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