2
* Copyright 2013 Red Hat, Inc.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation, either version 3 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
18
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
23
#include "meta-idle-monitor-xsync.h"
28
struct _MetaIdleMonitorXSync
30
MetaIdleMonitor parent;
35
XSyncAlarm user_active_alarm;
38
struct _MetaIdleMonitorXSyncClass
40
MetaIdleMonitorClass parent_class;
44
MetaIdleMonitorWatch base;
47
} MetaIdleMonitorWatchXSync;
49
G_DEFINE_TYPE (MetaIdleMonitorXSync, meta_idle_monitor_xsync, META_TYPE_IDLE_MONITOR)
52
_xsyncvalue_to_int64 (XSyncValue value)
54
return ((guint64) XSyncValueHigh32 (value)) << 32
55
| (guint64) XSyncValueLow32 (value);
58
#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32)
61
_xsync_alarm_set (MetaIdleMonitorXSync *monitor_xsync,
62
XSyncTestType test_type,
66
XSyncAlarmAttributes attr;
70
flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
71
XSyncCAValue | XSyncCADelta | XSyncCAEvents;
73
XSyncIntToValue (&delta, 0);
74
attr.trigger.counter = monitor_xsync->counter;
75
attr.trigger.value_type = XSyncAbsolute;
77
attr.events = want_events;
79
GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
80
attr.trigger.test_type = test_type;
81
return XSyncCreateAlarm (monitor_xsync->display, flags, &attr);
85
ensure_alarm_rescheduled (Display *dpy,
88
XSyncAlarmAttributes attr;
90
/* Some versions of Xorg have an issue where alarms aren't
91
* always rescheduled. Calling XSyncChangeAlarm, even
92
* without any attributes, will reschedule the alarm. */
93
XSyncChangeAlarm (dpy, alarm, 0, &attr);
97
set_alarm_enabled (Display *dpy,
101
XSyncAlarmAttributes attr;
102
attr.events = enabled;
103
XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
107
check_x11_watch (gpointer data,
110
MetaIdleMonitorWatchXSync *watch_xsync = data;
111
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_xsync;
112
XSyncAlarm alarm = (XSyncAlarm) user_data;
114
if (watch_xsync->xalarm != alarm)
117
_meta_idle_monitor_watch_fire (watch);
121
counter_name_for_device (int device_id)
124
return g_strdup_printf ("DEVICEIDLETIME %d", device_id);
126
return g_strdup ("IDLETIME");
130
find_idletime_counter (MetaIdleMonitorXSync *monitor_xsync)
132
MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_xsync);
135
XSyncSystemCounter *counters;
136
XSyncCounter counter = None;
139
counter_name = counter_name_for_device (monitor->device_id);
140
counters = XSyncListSystemCounters (monitor_xsync->display, &ncounters);
141
for (i = 0; i < ncounters; i++)
143
if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0)
145
counter = counters[i].counter;
149
XSyncFreeSystemCounterList (counters);
150
g_free (counter_name);
156
init_xsync (MetaIdleMonitorXSync *monitor_xsync)
158
monitor_xsync->counter = find_idletime_counter (monitor_xsync);
159
/* IDLETIME counter not found? */
160
if (monitor_xsync->counter == None)
162
g_warning ("IDLETIME counter not found\n");
166
monitor_xsync->user_active_alarm = _xsync_alarm_set (monitor_xsync, XSyncNegativeTransition, 1, FALSE);
170
meta_idle_monitor_xsync_dispose (GObject *object)
172
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object);
174
if (monitor_xsync->user_active_alarm != None)
176
XSyncDestroyAlarm (monitor_xsync->display, monitor_xsync->user_active_alarm);
177
monitor_xsync->user_active_alarm = None;
180
g_clear_pointer (&monitor_xsync->alarms, g_hash_table_destroy);
182
G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->dispose (object);
186
meta_idle_monitor_xsync_constructed (GObject *object)
188
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object);
189
GdkDisplay *display = gdk_display_get_default ();
191
monitor_xsync->display = gdk_x11_display_get_xdisplay (display);
192
init_xsync (monitor_xsync);
194
G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->constructed (object);
198
meta_idle_monitor_xsync_get_idletime (MetaIdleMonitor *monitor)
200
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
203
if (!XSyncQueryCounter (monitor_xsync->display, monitor_xsync->counter, &value))
206
return _xsyncvalue_to_int64 (value);
210
fire_watch_idle (gpointer data)
212
MetaIdleMonitorWatch *watch = data;
214
watch->idle_source_id = 0;
215
_meta_idle_monitor_watch_fire (watch);
221
get_next_watch_serial (void)
223
static guint32 serial = 0;
224
g_atomic_int_inc (&serial);
229
free_watch (gpointer data)
231
MetaIdleMonitorWatchXSync *watch_xsync = data;
232
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_xsync;
233
MetaIdleMonitor *monitor = watch->monitor;
234
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
236
g_object_ref (monitor);
238
if (watch->idle_source_id)
240
g_source_remove (watch->idle_source_id);
241
watch->idle_source_id = 0;
244
if (watch->notify != NULL)
245
watch->notify (watch->user_data);
247
if (watch_xsync->xalarm != monitor_xsync->user_active_alarm &&
248
watch_xsync->xalarm != None)
250
XSyncDestroyAlarm (monitor_xsync->display, watch_xsync->xalarm);
251
g_hash_table_remove (monitor_xsync->alarms, (gpointer) watch_xsync->xalarm);
254
g_object_unref (monitor);
255
g_slice_free (MetaIdleMonitorWatchXSync, watch_xsync);
258
static MetaIdleMonitorWatch *
259
meta_idle_monitor_xsync_make_watch (MetaIdleMonitor *monitor,
260
guint64 timeout_msec,
261
MetaIdleMonitorWatchFunc callback,
263
GDestroyNotify notify)
265
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
266
MetaIdleMonitorWatchXSync *watch_xsync;
267
MetaIdleMonitorWatch *watch;
269
watch_xsync = g_slice_new0 (MetaIdleMonitorWatchXSync);
270
watch = (MetaIdleMonitorWatch *) watch_xsync;
272
watch->monitor = monitor;
273
watch->id = get_next_watch_serial ();
274
watch->callback = callback;
275
watch->user_data = user_data;
276
watch->notify = notify;
277
watch->timeout_msec = timeout_msec;
279
if (monitor_xsync->user_active_alarm != None)
281
if (timeout_msec != 0)
283
watch_xsync->xalarm = _xsync_alarm_set (monitor_xsync, XSyncPositiveTransition, timeout_msec, TRUE);
285
g_hash_table_add (monitor_xsync->alarms, (gpointer) watch_xsync->xalarm);
287
if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec)
289
watch->idle_source_id = g_idle_add (fire_watch_idle, watch);
290
g_source_set_name_by_id (watch->idle_source_id, "[mutter] fire_watch_idle");
295
watch_xsync->xalarm = monitor_xsync->user_active_alarm;
297
set_alarm_enabled (monitor_xsync->display, monitor_xsync->user_active_alarm, TRUE);
305
meta_idle_monitor_xsync_class_init (MetaIdleMonitorXSyncClass *klass)
307
GObjectClass *object_class = G_OBJECT_CLASS (klass);
308
MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass);
310
object_class->dispose = meta_idle_monitor_xsync_dispose;
311
object_class->constructed = meta_idle_monitor_xsync_constructed;
313
idle_monitor_class->get_idletime = meta_idle_monitor_xsync_get_idletime;
314
idle_monitor_class->make_watch = meta_idle_monitor_xsync_make_watch;
318
meta_idle_monitor_xsync_init (MetaIdleMonitorXSync *monitor_xsync)
320
MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_xsync);
322
monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch);
323
monitor_xsync->alarms = g_hash_table_new (NULL, NULL);
327
meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor *monitor,
328
XSyncAlarmNotifyEvent *alarm_event)
330
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
335
if (alarm_event->state != XSyncAlarmActive)
338
alarm = alarm_event->alarm;
342
if (alarm == monitor_xsync->user_active_alarm)
344
set_alarm_enabled (monitor_xsync->display,
349
else if (g_hash_table_contains (monitor_xsync->alarms, (gpointer) alarm))
351
ensure_alarm_rescheduled (monitor_xsync->display,
358
watches = g_hash_table_get_values (monitor->watches);
360
g_list_foreach (watches, check_x11_watch, (gpointer) alarm);
361
g_list_free (watches);