No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | shell-idle-monitor.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Adapted from gnome-session/gnome-session/gs-idle-monitor.c
4 *
5 * Copyright (C) 2012 Red Hat, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * Authors: William Jon McCann <mccann@jhu.edu>
22 *
23 */
24
25 #include "config.h"
26
27 #include <time.h>
28 #include <string.h>
29
30 #include <X11/Xlib.h>
31 #include <X11/extensions/sync.h>
32
33 #include <glib.h>
34 #include <gdk/gdkx.h>
35 #include <gdk/gdk.h>
36
37 #include "shell-idle-monitor.h"
38
39 #define SHELL_IDLE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SHELL_TYPE_IDLE_MONITOR, ShellIdleMonitorPrivate))
40
41 struct ShellIdleMonitorPrivate
42 {
43 Display *display;
44
45 GHashTable *watches;
46 int sync_event_base;
47 XSyncCounter counter;
48 };
49
50 typedef struct
51 {
52 Display *display;
53 guint id;
54 XSyncValue interval;
55 ShellIdleMonitorWatchFunc callback;
56 gpointer user_data;
57 GDestroyNotify notify;
58 XSyncAlarm xalarm_positive;
59 XSyncAlarm xalarm_negative;
60 } ShellIdleMonitorWatch;
61
62 static guint32 watch_serial = 1;
63
64 G_DEFINE_TYPE (ShellIdleMonitor, shell_idle_monitor, G_TYPE_OBJECT)
65
66 static gint64
67 _xsyncvalue_to_int64 (XSyncValue value)
68 {
69 return ((guint64) XSyncValueHigh32 (value)) << 32
70 | (guint64) XSyncValueLow32 (value);
71 }
72
73 static XSyncValue
74 _int64_to_xsyncvalue (gint64 value)
75 {
76 XSyncValue ret;
77
78 XSyncIntsToValue (&ret, value, ((guint64)value) >> 32);
79
80 return ret;
81 }
82
83 static void
84 shell_idle_monitor_dispose (GObject *object)
85 {
86 ShellIdleMonitor *monitor;
87
88 monitor = SHELL_IDLE_MONITOR (object);
89
90 if (monitor->priv->watches != NULL) {
91 g_hash_table_destroy (monitor->priv->watches);
92 monitor->priv->watches = NULL;
93 }
94
95 G_OBJECT_CLASS (shell_idle_monitor_parent_class)->dispose (object);
96 }
97
98 static gboolean
99 _find_alarm (gpointer key,
100 ShellIdleMonitorWatch *watch,
101 XSyncAlarm *alarm)
102 {
103 /* g_debug ("Searching for %d in %d,%d", (int)*alarm, (int)watch->xalarm_positive, (int)watch->xalarm_negative); */
104 if (watch->xalarm_positive == *alarm
105 || watch->xalarm_negative == *alarm) {
106 return TRUE;
107 }
108 return FALSE;
109 }
110
111 static ShellIdleMonitorWatch *
112 find_watch_for_alarm (ShellIdleMonitor *monitor,
113 XSyncAlarm alarm)
114 {
115 ShellIdleMonitorWatch *watch;
116
117 watch = g_hash_table_find (monitor->priv->watches,
118 (GHRFunc)_find_alarm,
119 &alarm);
120 return watch;
121 }
122
123 static void
124 handle_alarm_notify_event (ShellIdleMonitor *monitor,
125 XSyncAlarmNotifyEvent *alarm_event)
126 {
127 ShellIdleMonitorWatch *watch;
128 gboolean condition;
129
130 if (alarm_event->state == XSyncAlarmDestroyed) {
131 return;
132 }
133
134 watch = find_watch_for_alarm (monitor, alarm_event->alarm);
135
136 if (watch == NULL) {
137 /* g_debug ("Unable to find watch for alarm %d", (int)alarm_event->alarm); */
138 return;
139 }
140
141 /* g_debug ("Watch %d fired, idle time = %" G_GINT64_FORMAT,
142 watch->id,
143 _xsyncvalue_to_int64 (alarm_event->counter_value)); */
144
145 if (alarm_event->alarm == watch->xalarm_positive) {
146 condition = TRUE;
147 } else {
148 condition = FALSE;
149 }
150
151 if (watch->callback != NULL) {
152 watch->callback (monitor,
153 watch->id,
154 condition,
155 watch->user_data);
156 }
157 }
158
159 static GdkFilterReturn
160 xevent_filter (GdkXEvent *xevent,
161 GdkEvent *event,
162 ShellIdleMonitor *monitor)
163 {
164 XEvent *ev;
165 XSyncAlarmNotifyEvent *alarm_event;
166
167 ev = xevent;
168 if (ev->xany.type != monitor->priv->sync_event_base + XSyncAlarmNotify) {
169 return GDK_FILTER_CONTINUE;
170 }
171
172 alarm_event = xevent;
173
174 handle_alarm_notify_event (monitor, alarm_event);
175
176 return GDK_FILTER_CONTINUE;
177 }
178
179 static gboolean
180 init_xsync (ShellIdleMonitor *monitor)
181 {
182 int sync_error_base;
183 int res;
184 int major;
185 int minor;
186 int i;
187 int ncounters;
188 XSyncSystemCounter *counters;
189
190 res = XSyncQueryExtension (monitor->priv->display,
191 &monitor->priv->sync_event_base,
192 &sync_error_base);
193 if (! res) {
194 g_warning ("ShellIdleMonitor: Sync extension not present");
195 return FALSE;
196 }
197
198 res = XSyncInitialize (monitor->priv->display, &major, &minor);
199 if (! res) {
200 g_warning ("ShellIdleMonitor: Unable to initialize Sync extension");
201 return FALSE;
202 }
203
204 counters = XSyncListSystemCounters (monitor->priv->display, &ncounters);
205 for (i = 0; i < ncounters; i++) {
206 if (counters[i].name != NULL
207 && strcmp (counters[i].name, "IDLETIME") == 0) {
208 monitor->priv->counter = counters[i].counter;
209 break;
210 }
211 }
212 XSyncFreeSystemCounterList (counters);
213
214 if (monitor->priv->counter == None) {
215 g_warning ("ShellIdleMonitor: IDLETIME counter not found");
216 return FALSE;
217 }
218
219 gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
220
221 return TRUE;
222 }
223
224 static GObject *
225 shell_idle_monitor_constructor (GType type,
226 guint n_construct_properties,
227 GObjectConstructParam *construct_properties)
228 {
229 ShellIdleMonitor *monitor;
230
231 monitor = SHELL_IDLE_MONITOR (G_OBJECT_CLASS (shell_idle_monitor_parent_class)->constructor (type,
232 n_construct_properties,
233 construct_properties));
234
235 monitor->priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
236
237 if (! init_xsync (monitor)) {
238 g_object_unref (monitor);
239 return NULL;
240 }
241
242 return G_OBJECT (monitor);
243 }
244
245 static void
246 shell_idle_monitor_class_init (ShellIdleMonitorClass *klass)
247 {
248 GObjectClass *object_class = G_OBJECT_CLASS (klass);
249
250 object_class->dispose = shell_idle_monitor_dispose;
251 object_class->constructor = shell_idle_monitor_constructor;
252
253 g_type_class_add_private (klass, sizeof (ShellIdleMonitorPrivate));
254 }
255
256 static guint32
257 get_next_watch_serial (void)
258 {
259 guint32 serial;
260
261 serial = watch_serial++;
262
263 if ((gint32)watch_serial < 0) {
264 watch_serial = 1;
265 }
266
267 /* FIXME: make sure it isn't in the hash */
268
269 return serial;
270 }
271
272 static ShellIdleMonitorWatch *
273 idle_monitor_watch_new (guint interval)
274 {
275 ShellIdleMonitorWatch *watch;
276
277 watch = g_slice_new0 (ShellIdleMonitorWatch);
278 watch->interval = _int64_to_xsyncvalue ((gint64)interval);
279 watch->id = get_next_watch_serial ();
280 watch->xalarm_positive = None;
281 watch->xalarm_negative = None;
282
283 return watch;
284 }
285
286 static void
287 idle_monitor_watch_free (ShellIdleMonitorWatch *watch)
288 {
289 if (watch == NULL) {
290 return;
291 }
292
293 if (watch->notify != NULL) {
294 watch->notify (watch->user_data);
295 }
296
297 if (watch->xalarm_positive != None) {
298 XSyncDestroyAlarm (watch->display, watch->xalarm_positive);
299 }
300 if (watch->xalarm_negative != None) {
301 XSyncDestroyAlarm (watch->display, watch->xalarm_negative);
302 }
303 g_slice_free (ShellIdleMonitorWatch, watch);
304 }
305
306 static void
307 shell_idle_monitor_init (ShellIdleMonitor *monitor)
308 {
309 monitor->priv = SHELL_IDLE_MONITOR_GET_PRIVATE (monitor);
310
311 monitor->priv->watches = g_hash_table_new_full (NULL,
312 NULL,
313 NULL,
314 (GDestroyNotify)idle_monitor_watch_free);
315
316 monitor->priv->counter = None;
317 }
318
319 /**
320 * shell_idle_monitor_get:
321 *
322 * Returns: (transfer none): the global #ShellIdleMonitor.
323 */
324 ShellIdleMonitor *
325 shell_idle_monitor_get (void)
326 {
327 static ShellIdleMonitor *idle_monitor;
328
329 if (G_UNLIKELY (idle_monitor == NULL))
330 idle_monitor = g_object_new (SHELL_TYPE_IDLE_MONITOR,
331 NULL);
332
333 return idle_monitor;
334 }
335
336 static gboolean
337 _xsync_alarm_set (ShellIdleMonitor *monitor,
338 ShellIdleMonitorWatch *watch)
339 {
340 XSyncAlarmAttributes attr;
341 XSyncValue delta;
342 guint flags;
343
344 flags = XSyncCACounter
345 | XSyncCAValueType
346 | XSyncCATestType
347 | XSyncCAValue
348 | XSyncCADelta
349 | XSyncCAEvents;
350
351 XSyncIntToValue (&delta, 0);
352 attr.trigger.counter = monitor->priv->counter;
353 attr.trigger.value_type = XSyncAbsolute;
354 attr.trigger.wait_value = watch->interval;
355 attr.delta = delta;
356 attr.events = TRUE;
357
358 attr.trigger.test_type = XSyncPositiveTransition;
359 if (watch->xalarm_positive != None) {
360 /* g_debug ("ShellIdleMonitor: updating alarm for positive transition wait=%" G_GINT64_FORMAT,
361 _xsyncvalue_to_int64 (attr.trigger.wait_value)); */
362 XSyncChangeAlarm (monitor->priv->display, watch->xalarm_positive, flags, &attr);
363 } else {
364 /* g_debug ("ShellIdleMonitor: creating new alarm for positive transition wait=%" G_GINT64_FORMAT,
365 _xsyncvalue_to_int64 (attr.trigger.wait_value)); */
366 watch->xalarm_positive = XSyncCreateAlarm (monitor->priv->display, flags, &attr);
367 }
368
369 attr.trigger.wait_value = _int64_to_xsyncvalue (_xsyncvalue_to_int64 (watch->interval) - 1);
370 attr.trigger.test_type = XSyncNegativeTransition;
371 if (watch->xalarm_negative != None) {
372 /* g_debug ("ShellIdleMonitor: updating alarm for negative transition wait=%" G_GINT64_FORMAT,
373 _xsyncvalue_to_int64 (attr.trigger.wait_value)); */
374 XSyncChangeAlarm (monitor->priv->display, watch->xalarm_negative, flags, &attr);
375 } else {
376 /* g_debug ("ShellIdleMonitor: creating new alarm for negative transition wait=%" G_GINT64_FORMAT,
377 _xsyncvalue_to_int64 (attr.trigger.wait_value)); */
378 watch->xalarm_negative = XSyncCreateAlarm (monitor->priv->display, flags, &attr);
379 }
380
381 return TRUE;
382 }
383
384 guint
385 shell_idle_monitor_add_watch (ShellIdleMonitor *monitor,
386 guint interval,
387 ShellIdleMonitorWatchFunc callback,
388 gpointer user_data,
389 GDestroyNotify notify)
390 {
391 ShellIdleMonitorWatch *watch;
392
393 g_return_val_if_fail (SHELL_IS_IDLE_MONITOR (monitor), 0);
394 g_return_val_if_fail (callback != NULL, 0);
395
396 watch = idle_monitor_watch_new (interval);
397 watch->display = monitor->priv->display;
398 watch->callback = callback;
399 watch->user_data = user_data;
400 watch->notify = notify;
401
402 _xsync_alarm_set (monitor, watch);
403
404 g_hash_table_insert (monitor->priv->watches,
405 GUINT_TO_POINTER (watch->id),
406 watch);
407 return watch->id;
408 }
409
410 void
411 shell_idle_monitor_remove_watch (ShellIdleMonitor *monitor,
412 guint id)
413 {
414 g_return_if_fail (SHELL_IS_IDLE_MONITOR (monitor));
415
416 g_hash_table_remove (monitor->priv->watches,
417 GUINT_TO_POINTER (id));
418 }
419
420 gint64
421 shell_idle_monitor_get_idletime (ShellIdleMonitor *monitor)
422 {
423 XSyncValue value;
424
425 if (!XSyncQueryCounter (monitor->priv->display, monitor->priv->counter, &value))
426 return FALSE;
427
428 return _xsyncvalue_to_int64 (value);
429 }