72
70
static GParamSpec *obj_props[PROP_LAST];
74
72
static void gnome_idle_monitor_initable_iface_init (GInitableIface *iface);
73
static void gnome_idle_monitor_remove_watch_internal (GnomeIdleMonitor *monitor,
76
static void add_idle_watch (GnomeIdleMonitor *, GnomeIdleMonitorWatch *);
77
static void add_active_watch (GnomeIdleMonitor *, GnomeIdleMonitorWatch *);
76
79
G_DEFINE_TYPE_WITH_CODE (GnomeIdleMonitor, gnome_idle_monitor, G_TYPE_OBJECT,
77
80
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
78
81
gnome_idle_monitor_initable_iface_init))
81
_xsyncvalue_to_int64 (XSyncValue value)
83
return ((guint64) XSyncValueHigh32 (value)) << 32
84
| (guint64) XSyncValueLow32 (value);
87
#define GINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, value, ((guint64)value) >> 32)
90
_xsync_alarm_set (GnomeIdleMonitor *monitor,
91
XSyncTestType test_type,
95
XSyncAlarmAttributes attr;
99
flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
100
XSyncCAValue | XSyncCADelta | XSyncCAEvents;
102
XSyncIntToValue (&delta, 0);
103
attr.trigger.counter = monitor->priv->counter;
104
attr.trigger.value_type = XSyncAbsolute;
106
attr.events = want_events;
108
GINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
109
attr.trigger.test_type = test_type;
110
return XSyncCreateAlarm (monitor->priv->display, flags, &attr);
114
ensure_alarm_rescheduled (Display *dpy,
117
XSyncAlarmAttributes attr;
119
/* Some versions of Xorg have an issue where alarms aren't
120
* always rescheduled. Calling XSyncChangeAlarm, even
121
* without any attributes, will reschedule the alarm. */
122
XSyncChangeAlarm (dpy, alarm, 0, &attr);
126
set_alarm_enabled (Display *dpy,
130
XSyncAlarmAttributes attr;
131
attr.events = enabled;
132
XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
136
fire_watch (gpointer data,
139
GnomeIdleMonitorWatch *watch = data;
140
XSyncAlarm alarm = (XSyncAlarm) user_data;
141
GnomeIdleMonitor *monitor;
143
if (watch->xalarm != alarm) {
84
on_watch_fired (MetaDBusIdleMonitor *proxy,
86
GnomeIdleMonitor *monitor)
88
GnomeIdleMonitorWatch *watch;
90
watch = g_hash_table_lookup (monitor->priv->watches_by_upstream_id, GINT_TO_POINTER (upstream_id));
147
monitor = watch->monitor;
148
94
g_object_ref (monitor);
150
96
if (watch->callback) {
153
99
watch->user_data);
156
if (watch->xalarm == monitor->priv->user_active_alarm) {
157
gnome_idle_monitor_remove_watch (monitor, watch->id);
102
if (watch->timeout_msec == 0)
103
gnome_idle_monitor_remove_watch_internal (monitor, watch->id);
160
105
g_object_unref (monitor);
164
handle_alarm_notify_event (GnomeIdleMonitor *monitor,
165
XSyncAlarmNotifyEvent *alarm_event)
171
if (alarm_event->state != XSyncAlarmActive) {
175
alarm = alarm_event->alarm;
179
if (alarm == monitor->priv->user_active_alarm) {
180
set_alarm_enabled (monitor->priv->display,
184
} else if (g_hash_table_contains (monitor->priv->alarms, (gpointer) alarm)) {
185
ensure_alarm_rescheduled (monitor->priv->display,
191
watches = g_hash_table_get_values (monitor->priv->watches);
193
g_list_foreach (watches,
197
g_list_free (watches);
201
static GdkFilterReturn
202
xevent_filter (GdkXEvent *xevent,
204
GnomeIdleMonitor *monitor)
207
XSyncAlarmNotifyEvent *alarm_event;
210
if (ev->xany.type != monitor->priv->sync_event_base + XSyncAlarmNotify) {
211
return GDK_FILTER_CONTINUE;
214
alarm_event = xevent;
215
handle_alarm_notify_event (monitor, alarm_event);
217
return GDK_FILTER_CONTINUE;
221
counter_name_for_device (GdkDevice *device)
224
gint device_id = gdk_x11_device_get_id (device);
226
return g_strdup_printf ("DEVICEIDLETIME %d", device_id);
229
return g_strdup ("IDLETIME");
233
find_idletime_counter (GnomeIdleMonitor *monitor)
237
XSyncSystemCounter *counters;
238
XSyncCounter counter = None;
241
counter_name = counter_name_for_device (monitor->priv->device);
242
counters = XSyncListSystemCounters (monitor->priv->display, &ncounters);
243
for (i = 0; i < ncounters; i++) {
244
if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0) {
245
counter = counters[i].counter;
249
XSyncFreeSystemCounterList (counters);
250
g_free (counter_name);
256
109
get_next_watch_serial (void)
258
static guint32 serial = 0;
259
g_atomic_int_inc (&serial);
111
static guint32 serial = 0;
112
g_atomic_int_inc (&serial);
264
idle_monitor_watch_free (GnomeIdleMonitorWatch *watch)
117
idle_monitor_watch_unref (GnomeIdleMonitorWatch *watch)
266
GnomeIdleMonitor *monitor;
120
if (watch->ref_count)
272
monitor = watch->monitor;
274
if (watch->notify != NULL) {
123
if (watch->notify != NULL)
275
124
watch->notify (watch->user_data);
278
if (watch->xalarm != monitor->priv->user_active_alarm) {
279
XSyncDestroyAlarm (monitor->priv->display, watch->xalarm);
280
g_hash_table_remove (monitor->priv->alarms, (gpointer) watch->xalarm);
127
if (watch->upstream_id != 0)
128
g_hash_table_remove (watch->monitor->priv->watches_by_upstream_id,
129
GINT_TO_POINTER (watch->upstream_id));
283
131
g_slice_free (GnomeIdleMonitorWatch, watch);
134
static GnomeIdleMonitorWatch *
135
idle_monitor_watch_ref (GnomeIdleMonitorWatch *watch)
137
g_assert (watch->ref_count > 0);
287
init_xsync (GnomeIdleMonitor *monitor)
144
idle_monitor_watch_destroy (GnomeIdleMonitorWatch *watch)
294
res = XSyncQueryExtension (monitor->priv->display,
295
&monitor->priv->sync_event_base,
298
g_warning ("GnomeIdleMonitor: Sync extension not present");
302
res = XSyncInitialize (monitor->priv->display, &major, &minor);
304
g_warning ("GnomeIdleMonitor: Unable to initialize Sync extension");
308
monitor->priv->counter = find_idletime_counter (monitor);
309
/* IDLETIME counter not found? */
310
if (monitor->priv->counter == None)
313
monitor->priv->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE);
315
gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
147
idle_monitor_watch_unref (watch);
323
155
monitor = GNOME_IDLE_MONITOR (object);
157
if (monitor->priv->cancellable)
158
g_cancellable_cancel (monitor->priv->cancellable);
159
g_clear_object (&monitor->priv->cancellable);
161
if (monitor->priv->name_watch_id) {
162
g_bus_unwatch_name (monitor->priv->name_watch_id);
163
monitor->priv->name_watch_id = 0;
166
g_clear_object (&monitor->priv->proxy);
167
g_clear_object (&monitor->priv->om);
325
168
g_clear_pointer (&monitor->priv->watches, g_hash_table_destroy);
326
g_clear_pointer (&monitor->priv->alarms, g_hash_table_destroy);
169
g_clear_pointer (&monitor->priv->watches_by_upstream_id, g_hash_table_destroy);
327
170
g_clear_object (&monitor->priv->device);
329
if (monitor->priv->user_active_alarm != None) {
330
XSyncDestroyAlarm (monitor->priv->display, monitor->priv->user_active_alarm);
331
monitor->priv->user_active_alarm = None;
334
gdk_window_remove_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
171
g_clear_pointer (&monitor->priv->path, g_free);
336
173
G_OBJECT_CLASS (gnome_idle_monitor_parent_class)->dispose (object);
376
gnome_idle_monitor_constructed (GObject *object)
378
GnomeIdleMonitor *monitor = GNOME_IDLE_MONITOR (object);
380
monitor->priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
381
init_xsync (monitor);
222
add_known_watch (gpointer key,
226
GnomeIdleMonitor *monitor = user_data;
227
GnomeIdleMonitorWatch *watch = value;
229
if (watch->timeout_msec == 0)
230
add_active_watch (monitor, watch);
232
add_idle_watch (monitor, watch);
236
connect_proxy (GDBusObject *object,
237
GnomeIdleMonitor *monitor)
239
MetaDBusIdleMonitor *proxy;
241
proxy = meta_dbus_object_get_idle_monitor (META_DBUS_OBJECT (object));
243
g_critical ("Unable to get idle monitor from object at %s",
244
g_dbus_object_get_object_path (object));
248
monitor->priv->proxy = proxy;
249
g_signal_connect_object (proxy, "watch-fired", G_CALLBACK (on_watch_fired), monitor, 0);
250
g_hash_table_foreach (monitor->priv->watches, add_known_watch, monitor);
254
on_object_added (GDBusObjectManager *manager,
258
GnomeIdleMonitor *monitor = user_data;
260
if (!g_str_equal (monitor->priv->path, g_dbus_object_get_object_path (object)))
263
connect_proxy (object, monitor);
265
g_signal_handlers_disconnect_by_func (manager, on_object_added, user_data);
269
get_proxy (GnomeIdleMonitor *monitor)
273
object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (monitor->priv->om),
274
monitor->priv->path);
276
connect_proxy (object, monitor);
277
g_object_unref (object);
281
g_signal_connect_object (monitor->priv->om, "object-added",
282
G_CALLBACK (on_object_added), monitor, 0);
286
on_object_manager_ready (GObject *source,
290
GnomeIdleMonitor *monitor = user_data;
291
GDBusObjectManager *om;
292
GError *error = NULL;
294
om = meta_dbus_object_manager_client_new_finish (res, &error);
296
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
297
g_warning ("Failed to acquire idle monitor object manager: %s", error->message);
298
g_error_free (error);
302
monitor->priv->om = META_DBUS_OBJECT_MANAGER_CLIENT (om);
307
on_name_appeared (GDBusConnection *connection,
309
const char *name_owner,
312
GnomeIdleMonitor *monitor = user_data;
314
meta_dbus_object_manager_client_new (connection,
315
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
317
"/org/gnome/Mutter/IdleMonitor",
318
monitor->priv->cancellable,
319
on_object_manager_ready,
324
clear_watch (gpointer key,
328
GnomeIdleMonitorWatch *watch = value;
329
GnomeIdleMonitor *monitor = user_data;
331
g_hash_table_remove (monitor->priv->watches_by_upstream_id, GINT_TO_POINTER (watch->upstream_id));
332
watch->upstream_id = 0;
336
on_name_vanished (GDBusConnection *connection,
340
GnomeIdleMonitor *monitor = user_data;
342
g_hash_table_foreach (monitor->priv->watches, clear_watch, monitor);
343
g_clear_object (&monitor->priv->proxy);
344
g_clear_object (&monitor->priv->om);
467
432
* idletime for all devices, use gnome_idle_monitor_new().
469
434
GnomeIdleMonitor *
470
gnome_idle_monitor_new_for_device (GdkDevice *device)
435
gnome_idle_monitor_new_for_device (GdkDevice *device,
472
return GNOME_IDLE_MONITOR (g_initable_new (GNOME_TYPE_IDLE_MONITOR, NULL, NULL,
438
return GNOME_IDLE_MONITOR (g_initable_new (GNOME_TYPE_IDLE_MONITOR, NULL, error,
473
439
"device", device, NULL));
476
442
static GnomeIdleMonitorWatch *
477
443
make_watch (GnomeIdleMonitor *monitor,
444
guint64 timeout_msec,
479
445
GnomeIdleMonitorWatchFunc callback,
480
446
gpointer user_data,
481
447
GDestroyNotify notify)
483
449
GnomeIdleMonitorWatch *watch;
485
451
watch = g_slice_new0 (GnomeIdleMonitorWatch);
452
watch->ref_count = 1;
453
watch->id = get_next_watch_serial ();
486
454
watch->monitor = monitor;
487
watch->id = get_next_watch_serial ();
488
455
watch->callback = callback;
489
456
watch->user_data = user_data;
490
457
watch->notify = notify;
491
watch->xalarm = xalarm;
458
watch->timeout_msec = timeout_msec;
493
g_hash_table_insert (monitor->priv->watches,
494
GUINT_TO_POINTER (watch->id),
464
on_watch_added (GObject *object,
465
GAsyncResult *result,
468
GnomeIdleMonitorWatch *watch = user_data;
469
GnomeIdleMonitor *monitor;
474
res = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), result, &error);
476
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
477
g_error_free (error);
478
idle_monitor_watch_unref (watch);
482
g_warning ("Failed to acquire idle monitor proxy: %s", error->message);
483
g_error_free (error);
484
idle_monitor_watch_unref (watch);
489
idle_monitor_watch_unref (watch);
493
monitor = watch->monitor;
494
g_variant_get (res, "(u)", &watch->upstream_id);
495
g_variant_unref (res);
497
g_hash_table_insert (monitor->priv->watches_by_upstream_id,
498
GINT_TO_POINTER (watch->upstream_id), watch);
499
idle_monitor_watch_unref (watch);
503
add_idle_watch (GnomeIdleMonitor *monitor,
504
GnomeIdleMonitorWatch *watch)
506
meta_dbus_idle_monitor_call_add_idle_watch (monitor->priv->proxy,
508
monitor->priv->cancellable,
509
on_watch_added, idle_monitor_watch_ref (watch));
513
add_active_watch (GnomeIdleMonitor *monitor,
514
GnomeIdleMonitorWatch *watch)
516
meta_dbus_idle_monitor_call_add_user_active_watch (monitor->priv->proxy,
517
monitor->priv->cancellable,
518
on_watch_added, idle_monitor_watch_ref (watch));
500
522
* gnome_idle_monitor_add_idle_watch:
501
523
* @monitor: A #GnomeIdleMonitor
530
552
g_return_val_if_fail (GNOME_IS_IDLE_MONITOR (monitor), 0);
532
554
watch = make_watch (monitor,
533
_xsync_alarm_set (monitor, XSyncPositiveTransition, interval_msec, TRUE),
538
g_hash_table_add (monitor->priv->alarms,
539
(gpointer) watch->xalarm);
560
g_hash_table_insert (monitor->priv->watches,
561
GUINT_TO_POINTER (watch->id),
564
if (monitor->priv->proxy)
565
add_idle_watch (monitor, watch);
541
567
return watch->id;