gnome-shell-3.6.3.1/src/shell-idle-monitor.c

No issues found

Incomplete coverage

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
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  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 }