1 /*******************************************************************************
2 **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
3 **      10        20        30        40        50        60        70        80
4 **
5 ** notify-osd
6 **
7 ** dnd.c - implements the "do not disturb"-mode, e.g. gsmgr, presentations
8 **
9 ** Copyright 2009 Canonical Ltd.
10 **
11 ** Authors:
12 **    Mirco "MacSlow" Mueller <mirco.mueller@canonical.com>
13 **    David Barth <david.barth@canonical.com>
14 **
15 ** This program is free software: you can redistribute it and/or modify it
16 ** under the terms of the GNU General Public License version 3, as published
17 ** by the Free Software Foundation.
18 **
19 ** This program is distributed in the hope that it will be useful, but
20 ** WITHOUT ANY WARRANTY; without even the implied warranties of
21 ** MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
22 ** PURPOSE.  See the GNU General Public License for more details.
23 **
24 ** You should have received a copy of the GNU General Public License along
25 ** with this program.  If not, see <http://www.gnu.org/licenses/>.
26 **
27 *******************************************************************************/
28 
29 #include "config.h"
30 #include <stdlib.h>
31 
32 #include <glib.h>
33 #include <glib-object.h>
34 
35 #include <dbus/dbus-glib.h>
36 
37 #include <X11/Xproto.h>
38 #include <X11/Xlib.h>
39 #include <X11/Xutil.h>
40 #include <X11/Xatom.h>
41 #include <gdk/gdkx.h>
42 
43 #include <libwnck/libwnck.h>
44 
45 #include "dbus.h"
46 
47 static DBusGProxy *gsmgr = NULL;
48 
49 gboolean
dnd_is_xscreensaver_active()50 dnd_is_xscreensaver_active ()
51 {
52 	GdkDisplay *display = gdk_display_get_default ();
53 
54 	Atom XA_BLANK =
55 		gdk_x11_get_xatom_by_name_for_display(display, "BLANK");
56 	Atom XA_LOCK =
57 		gdk_x11_get_xatom_by_name_for_display(display, "BLANK");
58 	Atom XA_SCREENSAVER_STATUS =
59 		gdk_x11_get_xatom_by_name_for_display(display,
60 						      "_SCREENSAVER_STATUS");
61 	gboolean active = FALSE;
62 
63 	Atom type;
64 	int format;
65 	int status;
66 	unsigned long nitems, bytesafter;
67 	unsigned char* data = NULL;
68 
69 	Display *dpy = gdk_x11_get_default_xdisplay ();
70 	Window   win = gdk_x11_get_default_root_xwindow ();
71 
72 	gdk_error_trap_push ();
73 	status = XGetWindowProperty (dpy, win,
74 				     XA_SCREENSAVER_STATUS,
75 				     0, 999, False, XA_INTEGER,
76 				     &type, &format, &nitems, &bytesafter,
77 				     (unsigned char **) &data);
78 	gdk_flush ();
79 	gdk_error_trap_pop_ignored ();
80 
81 	if (status == Success
82 	    && type == XA_INTEGER
83 	    && nitems >= 3
84 	    && data != NULL)
85 	{
86 		CARD32* tmp_data = (CARD32*) data;
87 
88 		active = (tmp_data[0] == XA_BLANK || tmp_data[0] == XA_LOCK)
89 			&& ((time_t)tmp_data[1] > (time_t)666000000L);
90 
91 		g_debug ("Screensaver is currently active");
92 	}
93 
94 	if (data != NULL)
95 		free (data);
96 
97 	return active;
98 }
99 
100 static DBusGProxy*
get_screensaver_proxy(void)101 get_screensaver_proxy (void)
102 {
103 	if (gsmgr == NULL)
104 	{
105 		DBusGConnection *connection = dbus_get_connection ();
106 		gsmgr = dbus_g_proxy_new_for_name (connection,
107 						   "org.gnome.ScreenSaver",
108 						   "/org/gnome/ScreenSaver",
109 						   "org.gnome.ScreenSaver");
110 	}
111 
112 	return gsmgr;
113 }
114 
115 gboolean
dnd_is_screensaver_inhibited()116 dnd_is_screensaver_inhibited ()
117 {
118 	GError  *error = NULL;
119 	gboolean inhibited = FALSE;
120 	char **list;
121 
122 	if (! get_screensaver_proxy ())
123 		return FALSE;
124 
125 	if (dbus_g_proxy_call_with_timeout (
126 		    gsmgr, "GetInhibitors", 2000, &error,
127 		    G_TYPE_INVALID,
128 		    G_TYPE_STRV, &list,
129 		    G_TYPE_INVALID))
130 	{
131 		if (error)
132 		{
133 			g_warning ("dnd_is_screensaver_inhibited(): "
134 			           "got error \"%s\"\n",
135 			           error->message);
136 			g_error_free (error);
137 			error = NULL;
138 		}
139 
140 		/* if the list is not empty, the screensaver is inhibited */
141 		if (*list)
142 		{
143 			inhibited = TRUE;
144 			g_debug ("Screensaver has been inhibited");
145 		}
146 		g_strfreev (list);
147 	}
148 
149 	return inhibited;
150 }
151 
152 gboolean
dnd_is_screensaver_active()153 dnd_is_screensaver_active ()
154 {
155 	GError  *error = NULL;
156 	gboolean active = FALSE;;
157 
158 	if (! get_screensaver_proxy ())
159 		return FALSE;
160 
161 	dbus_g_proxy_call_with_timeout (
162 		gsmgr, "GetActive", 2000, &error,
163 		G_TYPE_INVALID,
164 		G_TYPE_BOOLEAN, &active,
165 		G_TYPE_INVALID);
166 
167 	if (error)
168 	{
169 		g_warning ("dnd_is_screensaver_active(): Got error \"%s\"\n",
170 		           error->message);
171 		g_error_free (error);
172 		error = NULL;
173 	}
174 
175 	if (active)
176 		g_debug ("Gnome screensaver is active");
177 
178 	return active;
179 }
180 
181 static gboolean
dnd_is_online_presence_dnd()182 dnd_is_online_presence_dnd ()
183 {
184 	/* TODO: ask FUSA if we're in DND mode */
185 
186 	return FALSE;
187 }
188 
189 static int
is_fullscreen_cb(WnckWindow * window,WnckWorkspace * workspace)190 is_fullscreen_cb (WnckWindow *window, WnckWorkspace *workspace)
191 {
192 	if (wnck_window_is_visible_on_workspace (window, workspace)
193 		&& wnck_window_is_fullscreen (window))
194 	{
195 		return 0;
196 	} else {
197 		return 1;
198 	}
199 }
200 
201 gboolean
dnd_has_one_fullscreen_window(void)202 dnd_has_one_fullscreen_window (void)
203 {
204 	gboolean result;
205 
206 	WnckScreen *screen = wnck_screen_get_default ();
207 	wnck_screen_force_update (screen);
208 	WnckWorkspace *workspace = wnck_screen_get_active_workspace (screen);
209 	GList *list = wnck_screen_get_windows (screen);
210 	GList *item = g_list_find_custom (list, workspace, (GCompareFunc) is_fullscreen_cb);
211 	result = item != NULL;
212 #ifdef HAVE_WNCK_SHUTDOWN
213 	wnck_shutdown ();
214 #endif
215 	return result;
216 }
217 
218 /* Tries to determine whether the user is in "do not disturb" mode */
219 gboolean
dnd_dont_disturb_user(void)220 dnd_dont_disturb_user (void)
221 {
222 	return (dnd_is_online_presence_dnd()
223 		|| dnd_is_xscreensaver_active()
224 		|| dnd_is_screensaver_active()
225 		|| dnd_is_screensaver_inhibited()
226 		|| dnd_has_one_fullscreen_window()
227 		);
228 }
229