~ubuntu-branches/ubuntu/vivid/gnome-desktop3/vivid-proposed

« back to all changes in this revision

Viewing changes to libgnome-desktop/gnome-idle-monitor.c

  • Committer: Package Import Robot
  • Author(s): Tim Lunn
  • Date: 2014-09-12 07:22:38 UTC
  • mfrom: (1.6.4) (31.1.1 utopic-proposed)
  • Revision ID: package-import@ubuntu.com-20140912072238-fv5g0rpwuk5yynip
Tags: 3.12.2-2ubuntu1
* New upstream release (LP: #1372346)
* Merge with Debian, Remaining changes:
  - debian/patches:
    + 04_compute_average_color.patch: Compute the avergage color in
      gnome-desktop itself, not in unity to fix some races (LP #963140)
    + tweak_color_computation.patch, Patch from Gord, no patch header,
      no bug link.
    + git_revert_draw_background.patch
    + ubuntu_language.patch, Ported relevant bits from g-c-c 
      52_region_language.patch, as required for gnome 3.8 region panel
    + ubuntu_language_list_from_SUPPORTED.patch,
      adds api to get list of available languages from SUPPORTED file.
      To be used by gnome 3.8 region panel language installation.
  - debian/rules:
    + drop obsolete --disable-scrollkeeper configure flag
  - debian/libgnome-desktop-3-10.symbols:
    + Add symbols included in Ubuntu patches
  - debian/control.in:
    + Mark gnome-desktop3-data Multi-Arch: foreign
* Dropped changes:
  - 02_refuse_to_break_GL_compositors.patch:
    + xrandr code has moved into libunity-settings-daemon now

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 * GNU General Public License for more details.
16
16
 *
17
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.
 
18
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20
19
 */
21
20
 
22
21
#include "config.h"
24
23
#include <time.h>
25
24
#include <string.h>
26
25
 
27
 
#include <X11/Xlib.h>
28
 
#include <X11/extensions/sync.h>
29
 
 
30
26
#include <glib.h>
31
27
#include <gdk/gdkx.h>
32
28
#include <gdk/gdk.h>
33
29
 
34
30
#define GNOME_DESKTOP_USE_UNSTABLE_API
35
31
#include "gnome-idle-monitor.h"
 
32
#include "meta-dbus-idle-monitor.h"
36
33
 
37
34
#define GNOME_IDLE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_IDLE_MONITOR, GnomeIdleMonitorPrivate))
38
35
 
40
37
 
41
38
struct _GnomeIdleMonitorPrivate
42
39
{
43
 
        Display     *display;
44
 
 
45
 
        GHashTable  *watches;
46
 
        GHashTable  *alarms;
47
 
        int          sync_event_base;
48
 
        XSyncCounter counter;
49
 
 
50
 
        XSyncAlarm   user_active_alarm;
51
 
 
52
 
        GdkDevice   *device;
 
40
        GCancellable        *cancellable;
 
41
        MetaDBusIdleMonitor *proxy;
 
42
        MetaDBusObjectManagerClient *om;
 
43
        int                  name_watch_id;
 
44
        GHashTable          *watches;
 
45
        GHashTable          *watches_by_upstream_id;
 
46
        GdkDevice           *device;
 
47
        gchar               *path;
53
48
};
54
49
 
55
50
typedef struct
56
51
{
 
52
        int                       ref_count;
 
53
        gboolean                  dead;
57
54
        GnomeIdleMonitor         *monitor;
58
55
        guint                     id;
 
56
        guint                     upstream_id;
59
57
        GnomeIdleMonitorWatchFunc callback;
60
58
        gpointer                  user_data;
61
59
        GDestroyNotify            notify;
62
 
        XSyncAlarm                xalarm;
 
60
        guint64                   timeout_msec;
63
61
} GnomeIdleMonitorWatch;
64
62
 
65
63
enum
72
70
static GParamSpec *obj_props[PROP_LAST];
73
71
 
74
72
static void gnome_idle_monitor_initable_iface_init (GInitableIface *iface);
 
73
static void gnome_idle_monitor_remove_watch_internal (GnomeIdleMonitor *monitor,
 
74
                                                      guint             id);
 
75
 
 
76
static void add_idle_watch (GnomeIdleMonitor *, GnomeIdleMonitorWatch *);
 
77
static void add_active_watch (GnomeIdleMonitor *, GnomeIdleMonitorWatch *);
75
78
 
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))
79
82
 
80
 
static gint64
81
 
_xsyncvalue_to_int64 (XSyncValue value)
82
 
{
83
 
        return ((guint64) XSyncValueHigh32 (value)) << 32
84
 
                | (guint64) XSyncValueLow32 (value);
85
 
}
86
 
 
87
 
#define GINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, value, ((guint64)value) >> 32)
88
 
 
89
 
static XSyncAlarm
90
 
_xsync_alarm_set (GnomeIdleMonitor      *monitor,
91
 
                  XSyncTestType          test_type,
92
 
                  guint64                interval,
93
 
                  gboolean               want_events)
94
 
{
95
 
        XSyncAlarmAttributes attr;
96
 
        XSyncValue           delta;
97
 
        guint                flags;
98
 
 
99
 
        flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
100
 
                XSyncCAValue | XSyncCADelta | XSyncCAEvents;
101
 
 
102
 
        XSyncIntToValue (&delta, 0);
103
 
        attr.trigger.counter = monitor->priv->counter;
104
 
        attr.trigger.value_type = XSyncAbsolute;
105
 
        attr.delta = delta;
106
 
        attr.events = want_events;
107
 
 
108
 
        GINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
109
 
        attr.trigger.test_type = test_type;
110
 
        return XSyncCreateAlarm (monitor->priv->display, flags, &attr);
111
 
}
112
 
 
113
 
static void
114
 
ensure_alarm_rescheduled (Display    *dpy,
115
 
                          XSyncAlarm  alarm)
116
 
{
117
 
        XSyncAlarmAttributes attr;
118
 
 
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);
123
 
}
124
 
 
125
 
static void
126
 
set_alarm_enabled (Display    *dpy,
127
 
                   XSyncAlarm  alarm,
128
 
                   gboolean    enabled)
129
 
{
130
 
        XSyncAlarmAttributes attr;
131
 
        attr.events = enabled;
132
 
        XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
133
 
}
134
 
 
135
 
static void
136
 
fire_watch (gpointer data,
137
 
            gpointer user_data)
138
 
{
139
 
        GnomeIdleMonitorWatch *watch = data;
140
 
        XSyncAlarm alarm = (XSyncAlarm) user_data;
141
 
        GnomeIdleMonitor *monitor;
142
 
 
143
 
        if (watch->xalarm != alarm) {
 
83
static void
 
84
on_watch_fired (MetaDBusIdleMonitor *proxy,
 
85
                guint                upstream_id,
 
86
                GnomeIdleMonitor    *monitor)
 
87
{
 
88
        GnomeIdleMonitorWatch *watch;
 
89
 
 
90
        watch = g_hash_table_lookup (monitor->priv->watches_by_upstream_id, GINT_TO_POINTER (upstream_id));
 
91
        if (!watch)
144
92
                return;
145
 
        }
146
93
 
147
 
        monitor = watch->monitor;
148
94
        g_object_ref (monitor);
149
95
 
150
96
        if (watch->callback) {
153
99
                                 watch->user_data);
154
100
        }
155
101
 
156
 
        if (watch->xalarm == monitor->priv->user_active_alarm) {
157
 
                gnome_idle_monitor_remove_watch (monitor, watch->id);
158
 
        }
 
102
        if (watch->timeout_msec == 0)
 
103
                gnome_idle_monitor_remove_watch_internal (monitor, watch->id);
159
104
 
160
105
        g_object_unref (monitor);
161
106
}
162
107
 
163
 
static void
164
 
handle_alarm_notify_event (GnomeIdleMonitor         *monitor,
165
 
                           XSyncAlarmNotifyEvent    *alarm_event)
166
 
{
167
 
        XSyncAlarm alarm;
168
 
        GList *watches;
169
 
        gboolean has_alarm;
170
 
 
171
 
        if (alarm_event->state != XSyncAlarmActive) {
172
 
                return;
173
 
        }
174
 
 
175
 
        alarm = alarm_event->alarm;
176
 
 
177
 
        has_alarm = FALSE;
178
 
 
179
 
        if (alarm == monitor->priv->user_active_alarm) {
180
 
                set_alarm_enabled (monitor->priv->display,
181
 
                                   alarm,
182
 
                                   FALSE);
183
 
                has_alarm = TRUE;
184
 
        } else if (g_hash_table_contains (monitor->priv->alarms, (gpointer) alarm)) {
185
 
                ensure_alarm_rescheduled (monitor->priv->display,
186
 
                                          alarm);
187
 
                has_alarm = TRUE;
188
 
        }
189
 
 
190
 
        if (has_alarm) {
191
 
                watches = g_hash_table_get_values (monitor->priv->watches);
192
 
 
193
 
                g_list_foreach (watches,
194
 
                                fire_watch,
195
 
                                (gpointer) alarm);
196
 
 
197
 
                g_list_free (watches);
198
 
        }
199
 
}
200
 
 
201
 
static GdkFilterReturn
202
 
xevent_filter (GdkXEvent        *xevent,
203
 
               GdkEvent         *event,
204
 
               GnomeIdleMonitor *monitor)
205
 
{
206
 
        XEvent                *ev;
207
 
        XSyncAlarmNotifyEvent *alarm_event;
208
 
 
209
 
        ev = xevent;
210
 
        if (ev->xany.type != monitor->priv->sync_event_base + XSyncAlarmNotify) {
211
 
                return GDK_FILTER_CONTINUE;
212
 
        }
213
 
 
214
 
        alarm_event = xevent;
215
 
        handle_alarm_notify_event (monitor, alarm_event);
216
 
 
217
 
        return GDK_FILTER_CONTINUE;
218
 
}
219
 
 
220
 
static char *
221
 
counter_name_for_device (GdkDevice *device)
222
 
{
223
 
        if (device) {
224
 
                gint device_id = gdk_x11_device_get_id (device);
225
 
                if (device_id > 0)
226
 
                        return g_strdup_printf ("DEVICEIDLETIME %d", device_id);
227
 
        }
228
 
 
229
 
        return g_strdup ("IDLETIME");
230
 
}
231
 
 
232
 
static XSyncCounter
233
 
find_idletime_counter (GnomeIdleMonitor *monitor)
234
 
{
235
 
        int                 i;
236
 
        int                 ncounters;
237
 
        XSyncSystemCounter *counters;
238
 
        XSyncCounter        counter = None;
239
 
        char               *counter_name;
240
 
 
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;
246
 
                        break;
247
 
                }
248
 
        }
249
 
        XSyncFreeSystemCounterList (counters);
250
 
        g_free (counter_name);
251
 
 
252
 
        return counter;
253
 
}
254
 
 
255
108
static guint32
256
109
get_next_watch_serial (void)
257
110
{
258
 
        static guint32 serial = 0;
259
 
        g_atomic_int_inc (&serial);
260
 
        return serial;
 
111
  static guint32 serial = 0;
 
112
  g_atomic_int_inc (&serial);
 
113
  return serial;
261
114
}
262
115
 
263
116
static void
264
 
idle_monitor_watch_free (GnomeIdleMonitorWatch *watch)
 
117
idle_monitor_watch_unref (GnomeIdleMonitorWatch *watch)
265
118
{
266
 
        GnomeIdleMonitor *monitor;
267
 
 
268
 
        if (watch == NULL) {
 
119
        watch->ref_count--;
 
120
        if (watch->ref_count)
269
121
                return;
270
 
        }
271
 
 
272
 
        monitor = watch->monitor;
273
 
 
274
 
        if (watch->notify != NULL) {
 
122
 
 
123
        if (watch->notify != NULL)
275
124
                watch->notify (watch->user_data);
276
 
        }
277
 
 
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);
281
 
        }
 
125
 
 
126
 
 
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));
282
130
 
283
131
        g_slice_free (GnomeIdleMonitorWatch, watch);
284
132
}
285
133
 
 
134
static GnomeIdleMonitorWatch *
 
135
idle_monitor_watch_ref (GnomeIdleMonitorWatch *watch)
 
136
{
 
137
        g_assert (watch->ref_count > 0);
 
138
 
 
139
        watch->ref_count++;
 
140
        return watch;
 
141
}
 
142
 
286
143
static void
287
 
init_xsync (GnomeIdleMonitor *monitor)
 
144
idle_monitor_watch_destroy (GnomeIdleMonitorWatch *watch)
288
145
{
289
 
        int                 sync_error_base;
290
 
        int                 res;
291
 
        int                 major;
292
 
        int                 minor;
293
 
 
294
 
        res = XSyncQueryExtension (monitor->priv->display,
295
 
                                   &monitor->priv->sync_event_base,
296
 
                                   &sync_error_base);
297
 
        if (! res) {
298
 
                g_warning ("GnomeIdleMonitor: Sync extension not present");
299
 
                return;
300
 
        }
301
 
 
302
 
        res = XSyncInitialize (monitor->priv->display, &major, &minor);
303
 
        if (! res) {
304
 
                g_warning ("GnomeIdleMonitor: Unable to initialize Sync extension");
305
 
                return;
306
 
        }
307
 
 
308
 
        monitor->priv->counter = find_idletime_counter (monitor);
309
 
        /* IDLETIME counter not found? */
310
 
        if (monitor->priv->counter == None)
311
 
                return;
312
 
 
313
 
        monitor->priv->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE);
314
 
 
315
 
        gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
 
146
        watch->dead = TRUE;
 
147
        idle_monitor_watch_unref (watch);
316
148
}
317
149
 
318
150
static void
322
154
 
323
155
        monitor = GNOME_IDLE_MONITOR (object);
324
156
 
 
157
        if (monitor->priv->cancellable)
 
158
                g_cancellable_cancel (monitor->priv->cancellable);
 
159
        g_clear_object (&monitor->priv->cancellable);
 
160
 
 
161
        if (monitor->priv->name_watch_id) {
 
162
                g_bus_unwatch_name (monitor->priv->name_watch_id);
 
163
                monitor->priv->name_watch_id = 0;
 
164
        }
 
165
 
 
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);
328
 
 
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;
332
 
        }
333
 
 
334
 
        gdk_window_remove_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
 
171
        g_clear_pointer (&monitor->priv->path, g_free);
335
172
 
336
173
        G_OBJECT_CLASS (gnome_idle_monitor_parent_class)->dispose (object);
337
174
}
365
202
        {
366
203
        case PROP_DEVICE:
367
204
                monitor->priv->device = g_value_dup_object (value);
 
205
 
 
206
                g_free (monitor->priv->path);
 
207
                if (monitor->priv->device) {
 
208
                        monitor->priv->path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d",
 
209
                                                               gdk_x11_device_get_id (monitor->priv->device));
 
210
                } else {
 
211
                        monitor->priv->path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core");
 
212
                }
 
213
 
368
214
                break;
369
215
        default:
370
216
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
373
219
}
374
220
 
375
221
static void
376
 
gnome_idle_monitor_constructed (GObject *object)
377
 
{
378
 
        GnomeIdleMonitor *monitor = GNOME_IDLE_MONITOR (object);
379
 
 
380
 
        monitor->priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
381
 
        init_xsync (monitor);
 
222
add_known_watch (gpointer key,
 
223
                 gpointer value,
 
224
                 gpointer user_data)
 
225
{
 
226
        GnomeIdleMonitor *monitor = user_data;
 
227
        GnomeIdleMonitorWatch *watch = value;
 
228
 
 
229
        if (watch->timeout_msec == 0)
 
230
                add_active_watch (monitor, watch);
 
231
        else
 
232
                add_idle_watch (monitor, watch);
 
233
}
 
234
 
 
235
static void
 
236
connect_proxy (GDBusObject      *object,
 
237
               GnomeIdleMonitor *monitor)
 
238
{
 
239
        MetaDBusIdleMonitor *proxy;
 
240
 
 
241
        proxy = meta_dbus_object_get_idle_monitor (META_DBUS_OBJECT (object));
 
242
        if (!proxy) {
 
243
                g_critical ("Unable to get idle monitor from object at %s",
 
244
                            g_dbus_object_get_object_path (object));
 
245
                return;
 
246
        }
 
247
 
 
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);
 
251
}
 
252
 
 
253
static void
 
254
on_object_added (GDBusObjectManager     *manager,
 
255
                 GDBusObject            *object,
 
256
                 gpointer                user_data)
 
257
{
 
258
        GnomeIdleMonitor *monitor = user_data;
 
259
 
 
260
        if (!g_str_equal (monitor->priv->path, g_dbus_object_get_object_path (object)))
 
261
                return;
 
262
 
 
263
        connect_proxy (object, monitor);
 
264
 
 
265
        g_signal_handlers_disconnect_by_func (manager, on_object_added, user_data);
 
266
}
 
267
 
 
268
static void
 
269
get_proxy (GnomeIdleMonitor *monitor)
 
270
{
 
271
        GDBusObject *object;
 
272
 
 
273
        object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (monitor->priv->om),
 
274
                                                   monitor->priv->path);
 
275
        if (object) {
 
276
                connect_proxy (object, monitor);
 
277
                g_object_unref (object);
 
278
                return;
 
279
        }
 
280
 
 
281
        g_signal_connect_object (monitor->priv->om, "object-added",
 
282
                                 G_CALLBACK (on_object_added), monitor, 0);
 
283
}
 
284
 
 
285
static void
 
286
on_object_manager_ready (GObject        *source,
 
287
                         GAsyncResult   *res,
 
288
                         gpointer        user_data)
 
289
{
 
290
        GnomeIdleMonitor *monitor = user_data;
 
291
        GDBusObjectManager *om;
 
292
        GError *error = NULL;
 
293
 
 
294
        om = meta_dbus_object_manager_client_new_finish (res, &error);
 
295
        if (!om) {
 
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);
 
299
                return;
 
300
        }
 
301
 
 
302
        monitor->priv->om = META_DBUS_OBJECT_MANAGER_CLIENT (om);
 
303
        get_proxy (monitor);
 
304
}
 
305
 
 
306
static void
 
307
on_name_appeared (GDBusConnection *connection,
 
308
                  const char      *name,
 
309
                  const char      *name_owner,
 
310
                  gpointer         user_data)
 
311
{
 
312
        GnomeIdleMonitor *monitor = user_data;
 
313
 
 
314
        meta_dbus_object_manager_client_new (connection,
 
315
                                             G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
 
316
                                             name_owner,
 
317
                                             "/org/gnome/Mutter/IdleMonitor",
 
318
                                             monitor->priv->cancellable,
 
319
                                             on_object_manager_ready,
 
320
                                             monitor);
 
321
}
 
322
 
 
323
static void
 
324
clear_watch (gpointer key,
 
325
             gpointer value,
 
326
             gpointer user_data)
 
327
{
 
328
        GnomeIdleMonitorWatch *watch = value;
 
329
        GnomeIdleMonitor *monitor = user_data;
 
330
 
 
331
        g_hash_table_remove (monitor->priv->watches_by_upstream_id, GINT_TO_POINTER (watch->upstream_id));
 
332
        watch->upstream_id = 0;
 
333
}
 
334
 
 
335
static void
 
336
on_name_vanished (GDBusConnection *connection,
 
337
                  const char      *name,
 
338
                  gpointer         user_data)
 
339
{
 
340
        GnomeIdleMonitor *monitor = user_data;
 
341
 
 
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);
382
345
}
383
346
 
384
347
static gboolean
390
353
 
391
354
        monitor = GNOME_IDLE_MONITOR (initable);
392
355
 
393
 
        if (monitor->priv->counter == None) {
394
 
                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
395
 
                                     "Per-device idletime is not supported");
396
 
                return FALSE;
397
 
        }
 
356
        monitor->priv->name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
 
357
                                                         "org.gnome.Mutter.IdleMonitor",
 
358
                                                         G_BUS_NAME_WATCHER_FLAGS_NONE,
 
359
                                                         on_name_appeared,
 
360
                                                         on_name_vanished,
 
361
                                                         monitor, NULL);
398
362
 
399
363
        return TRUE;
400
364
}
411
375
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
412
376
 
413
377
        object_class->dispose = gnome_idle_monitor_dispose;
414
 
        object_class->constructed = gnome_idle_monitor_constructed;
415
378
        object_class->get_property = gnome_idle_monitor_get_property;
416
379
        object_class->set_property = gnome_idle_monitor_set_property;
417
380
 
439
402
        monitor->priv->watches = g_hash_table_new_full (NULL,
440
403
                                                        NULL,
441
404
                                                        NULL,
442
 
                                                        (GDestroyNotify)idle_monitor_watch_free);
 
405
                                                        (GDestroyNotify)idle_monitor_watch_destroy);
 
406
        monitor->priv->watches_by_upstream_id = g_hash_table_new (NULL, NULL);
443
407
 
444
 
        monitor->priv->alarms = g_hash_table_new (NULL, NULL);
 
408
        monitor->priv->cancellable = g_cancellable_new ();
445
409
}
446
410
 
447
411
/**
460
424
/**
461
425
 * gnome_idle_monitor_new_for_device:
462
426
 * @device: A #GdkDevice to get the idle time for.
 
427
 * @error: A pointer to a #GError or %NULL.
463
428
 *
464
429
 * Returns: a new #GnomeIdleMonitor that tracks the device-specific
465
430
 * idletime for @device. If device-specific idletime is not available,
467
432
 * idletime for all devices, use gnome_idle_monitor_new().
468
433
 */
469
434
GnomeIdleMonitor *
470
 
gnome_idle_monitor_new_for_device (GdkDevice  *device)
 
435
gnome_idle_monitor_new_for_device (GdkDevice  *device,
 
436
                                   GError    **error)
471
437
{
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));
474
440
}
475
441
 
476
442
static GnomeIdleMonitorWatch *
477
443
make_watch (GnomeIdleMonitor          *monitor,
478
 
            XSyncAlarm                 xalarm,
 
444
            guint64                    timeout_msec,
479
445
            GnomeIdleMonitorWatchFunc  callback,
480
446
            gpointer                   user_data,
481
447
            GDestroyNotify             notify)
483
449
        GnomeIdleMonitorWatch *watch;
484
450
 
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;
492
459
 
493
 
        g_hash_table_insert (monitor->priv->watches,
494
 
                             GUINT_TO_POINTER (watch->id),
495
 
                             watch);
496
460
        return watch;
497
461
}
498
462
 
 
463
static void
 
464
on_watch_added (GObject      *object,
 
465
                GAsyncResult *result,
 
466
                gpointer      user_data)
 
467
{
 
468
        GnomeIdleMonitorWatch *watch = user_data;
 
469
        GnomeIdleMonitor *monitor;
 
470
        GError *error;
 
471
        GVariant *res;
 
472
 
 
473
        error = NULL;
 
474
        res = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), result, &error);
 
475
        if (!res) {
 
476
                if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
 
477
                        g_error_free (error);
 
478
                        idle_monitor_watch_unref (watch);
 
479
                        return;
 
480
                }
 
481
 
 
482
                g_warning ("Failed to acquire idle monitor proxy: %s", error->message);
 
483
                g_error_free (error);
 
484
                idle_monitor_watch_unref (watch);
 
485
                return;
 
486
        }
 
487
 
 
488
        if (watch->dead) {
 
489
                idle_monitor_watch_unref (watch);
 
490
                return;
 
491
        }
 
492
 
 
493
        monitor = watch->monitor;
 
494
        g_variant_get (res, "(u)", &watch->upstream_id);
 
495
        g_variant_unref (res);
 
496
 
 
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);
 
500
}
 
501
 
 
502
static void
 
503
add_idle_watch (GnomeIdleMonitor      *monitor,
 
504
                GnomeIdleMonitorWatch *watch)
 
505
{
 
506
        meta_dbus_idle_monitor_call_add_idle_watch (monitor->priv->proxy,
 
507
                                                    watch->timeout_msec,
 
508
                                                    monitor->priv->cancellable,
 
509
                                                    on_watch_added, idle_monitor_watch_ref (watch));
 
510
}
 
511
 
 
512
static void
 
513
add_active_watch (GnomeIdleMonitor      *monitor,
 
514
                  GnomeIdleMonitorWatch *watch)
 
515
{
 
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));
 
519
}
 
520
 
499
521
/**
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);
531
553
 
532
554
        watch = make_watch (monitor,
533
 
                            _xsync_alarm_set (monitor, XSyncPositiveTransition, interval_msec, TRUE),
 
555
                            interval_msec,
534
556
                            callback,
535
557
                            user_data,
536
558
                            notify);
537
559
 
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),
 
562
                             watch);
 
563
 
 
564
        if (monitor->priv->proxy)
 
565
                add_idle_watch (monitor, watch);
540
566
 
541
567
        return watch->id;
542
568
}
567
593
 
568
594
        g_return_val_if_fail (GNOME_IS_IDLE_MONITOR (monitor), 0);
569
595
 
570
 
        set_alarm_enabled (monitor->priv->display,
571
 
                           monitor->priv->user_active_alarm,
572
 
                           TRUE);
573
 
 
574
596
        watch = make_watch (monitor,
575
 
                            monitor->priv->user_active_alarm,
 
597
                            0,
576
598
                            callback,
577
599
                            user_data,
578
600
                            notify);
579
601
 
 
602
        g_hash_table_insert (monitor->priv->watches,
 
603
                             GUINT_TO_POINTER (watch->id),
 
604
                             watch);
 
605
 
 
606
        if (monitor->priv->proxy)
 
607
                add_active_watch (monitor, watch);
 
608
 
580
609
        return watch->id;
581
610
}
582
611
 
593
622
gnome_idle_monitor_remove_watch (GnomeIdleMonitor *monitor,
594
623
                                 guint             id)
595
624
{
 
625
        GnomeIdleMonitorWatch *watch;
 
626
 
596
627
        g_return_if_fail (GNOME_IS_IDLE_MONITOR (monitor));
597
628
 
 
629
        watch = g_hash_table_lookup (monitor->priv->watches, GINT_TO_POINTER (id));
 
630
        if (!watch)
 
631
                return;
 
632
 
 
633
        if (watch->upstream_id)
 
634
                meta_dbus_idle_monitor_call_remove_watch (monitor->priv->proxy,
 
635
                                                          watch->upstream_id,
 
636
                                                          NULL, NULL, NULL);
 
637
 
 
638
        gnome_idle_monitor_remove_watch_internal (monitor, id);
 
639
}
 
640
 
 
641
static void
 
642
gnome_idle_monitor_remove_watch_internal (GnomeIdleMonitor *monitor,
 
643
                                          guint             id)
 
644
{
598
645
        g_hash_table_remove (monitor->priv->watches,
599
646
                             GUINT_TO_POINTER (id));
600
647
}
603
650
 * gnome_idle_monitor_get_idletime:
604
651
 * @monitor: A #GnomeIdleMonitor
605
652
 *
606
 
 * Returns: The current idle time, in milliseconds, or -1 for not supported
 
653
 * Returns: The current idle time, in milliseconds
607
654
 */
608
 
gint64
 
655
guint64
609
656
gnome_idle_monitor_get_idletime (GnomeIdleMonitor *monitor)
610
657
{
611
 
        XSyncValue value;
612
 
 
613
 
        if (!XSyncQueryCounter (monitor->priv->display, monitor->priv->counter, &value))
614
 
                return -1;
615
 
 
616
 
        return _xsyncvalue_to_int64 (value);
 
658
        guint64 value;
 
659
 
 
660
        value = 0;
 
661
        if (monitor->priv->proxy)
 
662
                meta_dbus_idle_monitor_call_get_idletime_sync (monitor->priv->proxy, &value,
 
663
                                                               NULL, NULL);
 
664
 
 
665
        return value;
617
666
}