~ubuntu-branches/ubuntu/vivid/gnome-flashback/vivid

« back to all changes in this revision

Viewing changes to gnome-flashback/libidle-monitor/meta-idle-monitor-xsync.c

  • Committer: Package Import Robot
  • Author(s): Dmitry Shachnev
  • Date: 2014-09-19 17:09:43 UTC
  • Revision ID: package-import@ubuntu.com-20140919170943-oboafsedi6z69951
Tags: upstream-3.10.0
ImportĀ upstreamĀ versionĀ 3.10.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2013 Red Hat, Inc.
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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/>.
 
16
 *
 
17
 * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
 
18
 *         from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include "meta-idle-monitor-xsync.h"
 
24
 
 
25
#include <string.h>
 
26
#include <gdk/gdkx.h>
 
27
 
 
28
struct _MetaIdleMonitorXSync
 
29
{
 
30
  MetaIdleMonitor parent;
 
31
 
 
32
  GHashTable  *alarms;
 
33
  Display     *display;
 
34
  XSyncCounter counter;
 
35
  XSyncAlarm   user_active_alarm;
 
36
};
 
37
 
 
38
struct _MetaIdleMonitorXSyncClass
 
39
{
 
40
  MetaIdleMonitorClass parent_class;
 
41
};
 
42
 
 
43
typedef struct {
 
44
  MetaIdleMonitorWatch base;
 
45
 
 
46
  XSyncAlarm xalarm;
 
47
} MetaIdleMonitorWatchXSync;
 
48
 
 
49
G_DEFINE_TYPE (MetaIdleMonitorXSync, meta_idle_monitor_xsync, META_TYPE_IDLE_MONITOR)
 
50
 
 
51
static gint64
 
52
_xsyncvalue_to_int64 (XSyncValue value)
 
53
{
 
54
  return ((guint64) XSyncValueHigh32 (value)) << 32
 
55
    | (guint64) XSyncValueLow32 (value);
 
56
}
 
57
 
 
58
#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32)
 
59
 
 
60
static XSyncAlarm
 
61
_xsync_alarm_set (MetaIdleMonitorXSync  *monitor_xsync,
 
62
                  XSyncTestType          test_type,
 
63
                  guint64                interval,
 
64
                  gboolean               want_events)
 
65
{
 
66
  XSyncAlarmAttributes attr;
 
67
  XSyncValue         delta;
 
68
  guint              flags;
 
69
 
 
70
  flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
 
71
    XSyncCAValue | XSyncCADelta | XSyncCAEvents;
 
72
 
 
73
  XSyncIntToValue (&delta, 0);
 
74
  attr.trigger.counter = monitor_xsync->counter;
 
75
  attr.trigger.value_type = XSyncAbsolute;
 
76
  attr.delta = delta;
 
77
  attr.events = want_events;
 
78
 
 
79
  GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
 
80
  attr.trigger.test_type = test_type;
 
81
  return XSyncCreateAlarm (monitor_xsync->display, flags, &attr);
 
82
}
 
83
 
 
84
static void
 
85
ensure_alarm_rescheduled (Display    *dpy,
 
86
                          XSyncAlarm  alarm)
 
87
{
 
88
  XSyncAlarmAttributes attr;
 
89
 
 
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);
 
94
}
 
95
 
 
96
static void
 
97
set_alarm_enabled (Display    *dpy,
 
98
                   XSyncAlarm  alarm,
 
99
                   gboolean    enabled)
 
100
{
 
101
  XSyncAlarmAttributes attr;
 
102
  attr.events = enabled;
 
103
  XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
 
104
}
 
105
 
 
106
static void
 
107
check_x11_watch (gpointer data,
 
108
                 gpointer user_data)
 
109
{
 
110
  MetaIdleMonitorWatchXSync *watch_xsync = data;
 
111
  MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_xsync;
 
112
  XSyncAlarm alarm = (XSyncAlarm) user_data;
 
113
 
 
114
  if (watch_xsync->xalarm != alarm)
 
115
    return;
 
116
 
 
117
  _meta_idle_monitor_watch_fire (watch);
 
118
}
 
119
 
 
120
static char *
 
121
counter_name_for_device (int device_id)
 
122
{
 
123
  if (device_id > 0)
 
124
    return g_strdup_printf ("DEVICEIDLETIME %d", device_id);
 
125
 
 
126
  return g_strdup ("IDLETIME");
 
127
}
 
128
 
 
129
static XSyncCounter
 
130
find_idletime_counter (MetaIdleMonitorXSync *monitor_xsync)
 
131
{
 
132
  MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_xsync);
 
133
  int                 i;
 
134
  int                 ncounters;
 
135
  XSyncSystemCounter *counters;
 
136
  XSyncCounter        counter = None;
 
137
  char               *counter_name;
 
138
 
 
139
  counter_name = counter_name_for_device (monitor->device_id);
 
140
  counters = XSyncListSystemCounters (monitor_xsync->display, &ncounters);
 
141
  for (i = 0; i < ncounters; i++)
 
142
    {
 
143
      if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0)
 
144
        {
 
145
          counter = counters[i].counter;
 
146
          break;
 
147
        }
 
148
    }
 
149
  XSyncFreeSystemCounterList (counters);
 
150
  g_free (counter_name);
 
151
 
 
152
  return counter;
 
153
}
 
154
 
 
155
static void
 
156
init_xsync (MetaIdleMonitorXSync *monitor_xsync)
 
157
{
 
158
  monitor_xsync->counter = find_idletime_counter (monitor_xsync);
 
159
  /* IDLETIME counter not found? */
 
160
  if (monitor_xsync->counter == None)
 
161
    {
 
162
      g_warning ("IDLETIME counter not found\n");
 
163
      return;
 
164
    }
 
165
 
 
166
  monitor_xsync->user_active_alarm = _xsync_alarm_set (monitor_xsync, XSyncNegativeTransition, 1, FALSE);
 
167
}
 
168
 
 
169
static void
 
170
meta_idle_monitor_xsync_dispose (GObject *object)
 
171
{
 
172
  MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object);
 
173
 
 
174
  if (monitor_xsync->user_active_alarm != None)
 
175
    {
 
176
      XSyncDestroyAlarm (monitor_xsync->display, monitor_xsync->user_active_alarm);
 
177
      monitor_xsync->user_active_alarm = None;
 
178
    }
 
179
 
 
180
  g_clear_pointer (&monitor_xsync->alarms, g_hash_table_destroy);
 
181
 
 
182
  G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->dispose (object);
 
183
}
 
184
 
 
185
static void
 
186
meta_idle_monitor_xsync_constructed (GObject *object)
 
187
{
 
188
  MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object);
 
189
  GdkDisplay *display = gdk_display_get_default ();
 
190
 
 
191
  monitor_xsync->display = gdk_x11_display_get_xdisplay (display);
 
192
  init_xsync (monitor_xsync);
 
193
 
 
194
  G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->constructed (object);
 
195
}
 
196
 
 
197
static gint64
 
198
meta_idle_monitor_xsync_get_idletime (MetaIdleMonitor *monitor)
 
199
{
 
200
  MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
 
201
  XSyncValue value;
 
202
 
 
203
  if (!XSyncQueryCounter (monitor_xsync->display, monitor_xsync->counter, &value))
 
204
    return -1;
 
205
 
 
206
  return _xsyncvalue_to_int64 (value);
 
207
}
 
208
 
 
209
static gboolean
 
210
fire_watch_idle (gpointer data)
 
211
{
 
212
  MetaIdleMonitorWatch *watch = data;
 
213
 
 
214
  watch->idle_source_id = 0;
 
215
  _meta_idle_monitor_watch_fire (watch);
 
216
 
 
217
  return FALSE;
 
218
}
 
219
 
 
220
static guint32
 
221
get_next_watch_serial (void)
 
222
{
 
223
  static guint32 serial = 0;
 
224
  g_atomic_int_inc (&serial);
 
225
  return serial;
 
226
}
 
227
 
 
228
static void
 
229
free_watch (gpointer data)
 
230
{
 
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);
 
235
 
 
236
  g_object_ref (monitor);
 
237
 
 
238
  if (watch->idle_source_id)
 
239
    {
 
240
      g_source_remove (watch->idle_source_id);
 
241
      watch->idle_source_id = 0;
 
242
    }
 
243
 
 
244
  if (watch->notify != NULL)
 
245
    watch->notify (watch->user_data);
 
246
 
 
247
  if (watch_xsync->xalarm != monitor_xsync->user_active_alarm &&
 
248
      watch_xsync->xalarm != None)
 
249
    {
 
250
      XSyncDestroyAlarm (monitor_xsync->display, watch_xsync->xalarm);
 
251
      g_hash_table_remove (monitor_xsync->alarms, (gpointer) watch_xsync->xalarm);
 
252
    }
 
253
 
 
254
  g_object_unref (monitor);
 
255
  g_slice_free (MetaIdleMonitorWatchXSync, watch_xsync);
 
256
}
 
257
 
 
258
static MetaIdleMonitorWatch *
 
259
meta_idle_monitor_xsync_make_watch (MetaIdleMonitor           *monitor,
 
260
                                    guint64                    timeout_msec,
 
261
                                    MetaIdleMonitorWatchFunc   callback,
 
262
                                    gpointer                   user_data,
 
263
                                    GDestroyNotify             notify)
 
264
{
 
265
  MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
 
266
  MetaIdleMonitorWatchXSync *watch_xsync;
 
267
  MetaIdleMonitorWatch *watch;
 
268
 
 
269
  watch_xsync = g_slice_new0 (MetaIdleMonitorWatchXSync);
 
270
  watch = (MetaIdleMonitorWatch *) watch_xsync;
 
271
 
 
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;
 
278
 
 
279
  if (monitor_xsync->user_active_alarm != None)
 
280
    {
 
281
      if (timeout_msec != 0)
 
282
        {
 
283
          watch_xsync->xalarm = _xsync_alarm_set (monitor_xsync, XSyncPositiveTransition, timeout_msec, TRUE);
 
284
 
 
285
          g_hash_table_add (monitor_xsync->alarms, (gpointer) watch_xsync->xalarm);
 
286
 
 
287
          if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec)
 
288
            {
 
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");
 
291
            }
 
292
        }
 
293
      else
 
294
        {
 
295
          watch_xsync->xalarm = monitor_xsync->user_active_alarm;
 
296
 
 
297
          set_alarm_enabled (monitor_xsync->display, monitor_xsync->user_active_alarm, TRUE);
 
298
        }
 
299
    }
 
300
 
 
301
  return watch;
 
302
}
 
303
 
 
304
static void
 
305
meta_idle_monitor_xsync_class_init (MetaIdleMonitorXSyncClass *klass)
 
306
{
 
307
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
308
  MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass);
 
309
 
 
310
  object_class->dispose = meta_idle_monitor_xsync_dispose;
 
311
  object_class->constructed = meta_idle_monitor_xsync_constructed;
 
312
 
 
313
  idle_monitor_class->get_idletime = meta_idle_monitor_xsync_get_idletime;
 
314
  idle_monitor_class->make_watch = meta_idle_monitor_xsync_make_watch;
 
315
}
 
316
 
 
317
static void
 
318
meta_idle_monitor_xsync_init (MetaIdleMonitorXSync *monitor_xsync)
 
319
{
 
320
  MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_xsync);
 
321
 
 
322
  monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch);
 
323
  monitor_xsync->alarms = g_hash_table_new (NULL, NULL);
 
324
}
 
325
 
 
326
void
 
327
meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor       *monitor,
 
328
                                       XSyncAlarmNotifyEvent *alarm_event)
 
329
{
 
330
  MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
 
331
  XSyncAlarm alarm;
 
332
  GList *watches;
 
333
  gboolean has_alarm;
 
334
 
 
335
  if (alarm_event->state != XSyncAlarmActive)
 
336
    return;
 
337
 
 
338
  alarm = alarm_event->alarm;
 
339
 
 
340
  has_alarm = FALSE;
 
341
 
 
342
  if (alarm == monitor_xsync->user_active_alarm)
 
343
    {
 
344
      set_alarm_enabled (monitor_xsync->display,
 
345
                         alarm,
 
346
                         FALSE);
 
347
      has_alarm = TRUE;
 
348
    }
 
349
  else if (g_hash_table_contains (monitor_xsync->alarms, (gpointer) alarm))
 
350
    {
 
351
      ensure_alarm_rescheduled (monitor_xsync->display,
 
352
                                alarm);
 
353
      has_alarm = TRUE;
 
354
    }
 
355
 
 
356
  if (has_alarm)
 
357
    {
 
358
      watches = g_hash_table_get_values (monitor->watches);
 
359
 
 
360
      g_list_foreach (watches, check_x11_watch, (gpointer) alarm);
 
361
      g_list_free (watches);
 
362
    }
 
363
}