From 78457cf7b4a3148fc6410d15b3cf5c04256cded4 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sun, 30 Mar 2014 20:52:25 -0400 Subject: [PATCH] idle-monitor: Create separate subtypes for backend-specific idle monitors The separation here isn't 100% clean yet, as there's common parts that are still protocol specific. We'll clean that up in the next commit. --- src/Makefile.am | 4 + src/core/events.c | 11 +- src/core/meta-idle-monitor-native.c | 174 ++++++++++++ src/core/meta-idle-monitor-native.h | 43 +++ src/core/meta-idle-monitor-private.h | 58 +++- src/core/meta-idle-monitor-xsync.c | 311 ++++++++++++++++++++ src/core/meta-idle-monitor-xsync.h | 49 ++++ src/core/meta-idle-monitor.c | 411 +++------------------------ 8 files changed, 675 insertions(+), 386 deletions(-) create mode 100644 src/core/meta-idle-monitor-native.c create mode 100644 src/core/meta-idle-monitor-native.h create mode 100644 src/core/meta-idle-monitor-xsync.c create mode 100644 src/core/meta-idle-monitor-xsync.h diff --git a/src/Makefile.am b/src/Makefile.am index 9a0cbe809..c81d0963d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -133,6 +133,10 @@ libmutter_wayland_la_SOURCES = \ core/meta-idle-monitor-private.h \ core/meta-idle-monitor-dbus.c \ core/meta-idle-monitor-dbus.h \ + core/meta-idle-monitor-xsync.c \ + core/meta-idle-monitor-xsync.h \ + core/meta-idle-monitor-native.c \ + core/meta-idle-monitor-native.h \ core/meta-xrandr-shared.h \ core/monitor.c \ core/monitor-config.c \ diff --git a/src/core/events.c b/src/core/events.c index 3d113bdf4..49a37d320 100644 --- a/src/core/events.c +++ b/src/core/events.c @@ -34,7 +34,8 @@ #include "window-private.h" #include "bell.h" #include "workspace-private.h" -#include "meta-idle-monitor-private.h" +#include "meta-idle-monitor-xsync.h" +#include "meta-idle-monitor-native.h" #include "x11/window-x11.h" #include "x11/xprops.h" @@ -1244,7 +1245,7 @@ handle_other_xevent (MetaDisplay *display, bypass_gtk = TRUE; /* GTK doesn't want to see this really */ } else - meta_idle_monitor_handle_xevent_all (event); + meta_idle_monitor_xsync_handle_xevent_all (event); goto out; } @@ -1870,15 +1871,15 @@ handle_idletime_for_event (const ClutterEvent *event) core_monitor = meta_idle_monitor_get_core (); device_monitor = meta_idle_monitor_get_for_device (device_id); - meta_idle_monitor_reset_idletime (core_monitor); - meta_idle_monitor_reset_idletime (device_monitor); + meta_idle_monitor_native_reset_idletime (core_monitor); + meta_idle_monitor_native_reset_idletime (device_monitor); source_device = clutter_event_get_source_device (event); if (source_device != device) { device_id = clutter_input_device_get_device_id (device); device_monitor = meta_idle_monitor_get_for_device (device_id); - meta_idle_monitor_reset_idletime (device_monitor); + meta_idle_monitor_native_reset_idletime (device_monitor); } } diff --git a/src/core/meta-idle-monitor-native.c b/src/core/meta-idle-monitor-native.c new file mode 100644 index 000000000..eb3ab6a26 --- /dev/null +++ b/src/core/meta-idle-monitor-native.c @@ -0,0 +1,174 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#include "config.h" + +#include "meta-idle-monitor-native.h" +#include "meta-idle-monitor-private.h" + +#include +#include "display-private.h" + +#include + +struct _MetaIdleMonitorNative +{ + MetaIdleMonitor parent; +}; + +struct _MetaIdleMonitorNativeClass +{ + MetaIdleMonitorClass parent_class; +}; + +G_DEFINE_TYPE (MetaIdleMonitorNative, meta_idle_monitor_native, META_TYPE_IDLE_MONITOR) + +static gint64 +meta_idle_monitor_native_get_idletime (MetaIdleMonitor *monitor) +{ + return (g_get_monotonic_time () - monitor->last_event_time) / 1000; +} + +static guint32 +get_next_watch_serial (void) +{ + static guint32 serial = 0; + g_atomic_int_inc (&serial); + return serial; +} + +static gboolean +native_dispatch_timeout (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + MetaIdleMonitorWatch *watch = user_data; + + _meta_idle_monitor_watch_fire (watch); + g_source_set_ready_time (watch->timeout_source, -1); + return TRUE; +} + +static GSourceFuncs native_source_funcs = { + NULL, /* prepare */ + NULL, /* check */ + native_dispatch_timeout, + NULL, /* finalize */ +}; + +static MetaIdleMonitorWatch * +meta_idle_monitor_native_make_watch (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatch *watch; + + watch = g_slice_new0 (MetaIdleMonitorWatch); + watch->monitor = monitor; + watch->id = get_next_watch_serial (); + watch->callback = callback; + watch->user_data = user_data; + watch->notify = notify; + watch->timeout_msec = timeout_msec; + + if (timeout_msec != 0) + { + GSource *source = g_source_new (&native_source_funcs, sizeof (GSource)); + + g_source_set_callback (source, NULL, watch, NULL); + g_source_set_ready_time (source, monitor->last_event_time + timeout_msec * 1000); + g_source_attach (source, NULL); + g_source_unref (source); + + watch->timeout_source = source; + } + + return watch; +} + +static void +meta_idle_monitor_native_class_init (MetaIdleMonitorNativeClass *klass) +{ + MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass); + + idle_monitor_class->get_idletime = meta_idle_monitor_native_get_idletime; + idle_monitor_class->make_watch = meta_idle_monitor_native_make_watch; +} + +static void +meta_idle_monitor_native_init (MetaIdleMonitorNative *monitor) +{ +} + +typedef struct { + MetaIdleMonitor *monitor; + GList *fired_watches; +} CheckNativeClosure; + +static gboolean +check_native_watch (gpointer key, + gpointer value, + gpointer user_data) +{ + MetaIdleMonitorWatch *watch = value; + CheckNativeClosure *closure = user_data; + gboolean steal; + + if (watch->timeout_msec == 0) + { + closure->fired_watches = g_list_prepend (closure->fired_watches, watch); + steal = TRUE; + } + else + { + g_source_set_ready_time (watch->timeout_source, + closure->monitor->last_event_time + + watch->timeout_msec * 1000); + steal = FALSE; + } + + return steal; +} + +static void +fire_native_watch (gpointer watch, + gpointer data) +{ + _meta_idle_monitor_watch_fire (watch); +} + +void +meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor) +{ + CheckNativeClosure closure; + + monitor->last_event_time = g_get_monotonic_time (); + + closure.monitor = monitor; + closure.fired_watches = NULL; + g_hash_table_foreach_steal (monitor->watches, check_native_watch, &closure); + + g_list_foreach (closure.fired_watches, fire_native_watch, NULL); + g_list_free (closure.fired_watches); +} diff --git a/src/core/meta-idle-monitor-native.h b/src/core/meta-idle-monitor-native.h new file mode 100644 index 000000000..37745c489 --- /dev/null +++ b/src/core/meta-idle-monitor-native.h @@ -0,0 +1,43 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#ifndef META_IDLE_MONITOR_NATIVE_H +#define META_IDLE_MONITOR_NATIVE_H + +#include +#include + +#define META_TYPE_IDLE_MONITOR_NATIVE (meta_idle_monitor_native_get_type ()) +#define META_IDLE_MONITOR_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNative)) +#define META_IDLE_MONITOR_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNativeClass)) +#define META_IS_IDLE_MONITOR_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR_NATIVE)) +#define META_IS_IDLE_MONITOR_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_IDLE_MONITOR_NATIVE)) +#define META_IDLE_MONITOR_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNativeClass)) + +typedef struct _MetaIdleMonitorNative MetaIdleMonitorNative; +typedef struct _MetaIdleMonitorNativeClass MetaIdleMonitorNativeClass; + +GType meta_idle_monitor_native_get_type (void); + +void meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor); + +#endif /* META_IDLE_MONITOR_NATIVE_H */ diff --git a/src/core/meta-idle-monitor-private.h b/src/core/meta-idle-monitor-private.h index aabd1cc3b..b34ca83d1 100644 --- a/src/core/meta-idle-monitor-private.h +++ b/src/core/meta-idle-monitor-private.h @@ -20,8 +20,62 @@ * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c */ +#ifndef META_IDLE_MONITOR_PRIVATE_H +#define META_IDLE_MONITOR_PRIVATE_H + #include +#include "display-private.h" -void meta_idle_monitor_handle_xevent_all (XEvent *xevent); +#include +#include -void meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor); +typedef struct +{ + MetaIdleMonitor *monitor; + guint id; + MetaIdleMonitorWatchFunc callback; + gpointer user_data; + GDestroyNotify notify; + guint64 timeout_msec; + + /* x11 */ + XSyncAlarm xalarm; + int idle_source_id; + + /* wayland */ + GSource *timeout_source; +} MetaIdleMonitorWatch; + +struct _MetaIdleMonitor +{ + GObject parent_instance; + + GHashTable *watches; + GHashTable *alarms; + int device_id; + + /* X11 implementation */ + Display *display; + int sync_event_base; + XSyncCounter counter; + XSyncAlarm user_active_alarm; + + /* Wayland implementation */ + guint64 last_event_time; +}; + +struct _MetaIdleMonitorClass +{ + GObjectClass parent_class; + + gint64 (*get_idletime) (MetaIdleMonitor *monitor); + MetaIdleMonitorWatch * (*make_watch) (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify); +}; + +void _meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch); + +#endif /* META_IDLE_MONITOR_PRIVATE_H */ diff --git a/src/core/meta-idle-monitor-xsync.c b/src/core/meta-idle-monitor-xsync.c new file mode 100644 index 000000000..b1f47ba18 --- /dev/null +++ b/src/core/meta-idle-monitor-xsync.c @@ -0,0 +1,311 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#include "config.h" + +#include "meta-idle-monitor-xsync.h" +#include "meta-idle-monitor-private.h" + +#include +#include "display-private.h" + +#include + +struct _MetaIdleMonitorXSync +{ + MetaIdleMonitor parent; +}; + +struct _MetaIdleMonitorXSyncClass +{ + MetaIdleMonitorClass parent_class; +}; + +G_DEFINE_TYPE (MetaIdleMonitorXSync, meta_idle_monitor_xsync, META_TYPE_IDLE_MONITOR) + +static gint64 +_xsyncvalue_to_int64 (XSyncValue value) +{ + return ((guint64) XSyncValueHigh32 (value)) << 32 + | (guint64) XSyncValueLow32 (value); +} + +#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32) + +static XSyncAlarm +_xsync_alarm_set (MetaIdleMonitor *monitor, + XSyncTestType test_type, + guint64 interval, + gboolean want_events) +{ + XSyncAlarmAttributes attr; + XSyncValue delta; + guint flags; + + flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | + XSyncCAValue | XSyncCADelta | XSyncCAEvents; + + XSyncIntToValue (&delta, 0); + attr.trigger.counter = monitor->counter; + attr.trigger.value_type = XSyncAbsolute; + attr.delta = delta; + attr.events = want_events; + + GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value); + attr.trigger.test_type = test_type; + return XSyncCreateAlarm (monitor->display, flags, &attr); +} + +static void +ensure_alarm_rescheduled (Display *dpy, + XSyncAlarm alarm) +{ + XSyncAlarmAttributes attr; + + /* Some versions of Xorg have an issue where alarms aren't + * always rescheduled. Calling XSyncChangeAlarm, even + * without any attributes, will reschedule the alarm. */ + XSyncChangeAlarm (dpy, alarm, 0, &attr); +} + +static void +set_alarm_enabled (Display *dpy, + XSyncAlarm alarm, + gboolean enabled) +{ + XSyncAlarmAttributes attr; + attr.events = enabled; + XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr); +} + +static void +check_x11_watch (gpointer data, + gpointer user_data) +{ + MetaIdleMonitorWatch *watch = data; + XSyncAlarm alarm = (XSyncAlarm) user_data; + + if (watch->xalarm != alarm) + return; + + _meta_idle_monitor_watch_fire (watch); +} + +static char * +counter_name_for_device (int device_id) +{ + if (device_id > 0) + return g_strdup_printf ("DEVICEIDLETIME %d", device_id); + + return g_strdup ("IDLETIME"); +} + +static XSyncCounter +find_idletime_counter (MetaIdleMonitor *monitor) +{ + int i; + int ncounters; + XSyncSystemCounter *counters; + XSyncCounter counter = None; + char *counter_name; + + counter_name = counter_name_for_device (monitor->device_id); + counters = XSyncListSystemCounters (monitor->display, &ncounters); + for (i = 0; i < ncounters; i++) + { + if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0) + { + counter = counters[i].counter; + break; + } + } + XSyncFreeSystemCounterList (counters); + g_free (counter_name); + + return counter; +} + +static void +init_xsync (MetaIdleMonitor *monitor) +{ + monitor->counter = find_idletime_counter (monitor); + /* IDLETIME counter not found? */ + if (monitor->counter == None) + { + g_warning ("IDLETIME counter not found\n"); + return; + } + + monitor->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE); +} + +static void +meta_idle_monitor_xsync_dispose (GObject *object) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); + + if (monitor->user_active_alarm != None) + { + XSyncDestroyAlarm (monitor->display, monitor->user_active_alarm); + monitor->user_active_alarm = None; + } + + G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->dispose (object); +} + +static void +meta_idle_monitor_xsync_constructed (GObject *object) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); + + g_assert (!meta_is_wayland_compositor ()); + + monitor->display = meta_get_display ()->xdisplay; + init_xsync (monitor); + + G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->constructed (object); +} + +static gint64 +meta_idle_monitor_xsync_get_idletime (MetaIdleMonitor *monitor) +{ + XSyncValue value; + + if (!XSyncQueryCounter (monitor->display, monitor->counter, &value)) + return -1; + + return _xsyncvalue_to_int64 (value); +} + +static gboolean +fire_watch_idle (gpointer data) +{ + MetaIdleMonitorWatch *watch = data; + + watch->idle_source_id = 0; + _meta_idle_monitor_watch_fire (watch); + + return FALSE; +} + +static guint32 +get_next_watch_serial (void) +{ + static guint32 serial = 0; + g_atomic_int_inc (&serial); + return serial; +} + +static MetaIdleMonitorWatch * +meta_idle_monitor_xsync_make_watch (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatch *watch; + + watch = g_slice_new0 (MetaIdleMonitorWatch); + watch->monitor = monitor; + watch->id = get_next_watch_serial (); + watch->callback = callback; + watch->user_data = user_data; + watch->notify = notify; + watch->timeout_msec = timeout_msec; + + if (monitor->user_active_alarm != None) + { + if (timeout_msec != 0) + { + watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE); + + g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm); + + if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec) + watch->idle_source_id = g_idle_add (fire_watch_idle, watch); + } + else + { + watch->xalarm = monitor->user_active_alarm; + + set_alarm_enabled (monitor->display, monitor->user_active_alarm, TRUE); + } + } + + return watch; +} + +static void +meta_idle_monitor_xsync_class_init (MetaIdleMonitorXSyncClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass); + + object_class->dispose = meta_idle_monitor_xsync_dispose; + object_class->constructed = meta_idle_monitor_xsync_constructed; + + idle_monitor_class->get_idletime = meta_idle_monitor_xsync_get_idletime; + idle_monitor_class->make_watch = meta_idle_monitor_xsync_make_watch; +} + +static void +meta_idle_monitor_xsync_init (MetaIdleMonitorXSync *monitor) +{ +} + +void +meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor *monitor, + XSyncAlarmNotifyEvent *alarm_event) +{ + XSyncAlarm alarm; + GList *watches; + gboolean has_alarm; + + if (alarm_event->state != XSyncAlarmActive) + return; + + alarm = alarm_event->alarm; + + has_alarm = FALSE; + + if (alarm == monitor->user_active_alarm) + { + set_alarm_enabled (monitor->display, + alarm, + FALSE); + has_alarm = TRUE; + } + else if (g_hash_table_contains (monitor->alarms, (gpointer) alarm)) + { + ensure_alarm_rescheduled (monitor->display, + alarm); + has_alarm = TRUE; + } + + if (has_alarm) + { + watches = g_hash_table_get_values (monitor->watches); + + g_list_foreach (watches, check_x11_watch, (gpointer) alarm); + g_list_free (watches); + } +} diff --git a/src/core/meta-idle-monitor-xsync.h b/src/core/meta-idle-monitor-xsync.h new file mode 100644 index 000000000..f8e88f09e --- /dev/null +++ b/src/core/meta-idle-monitor-xsync.h @@ -0,0 +1,49 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#ifndef META_IDLE_MONITOR_XSYNC_H +#define META_IDLE_MONITOR_XSYNC_H + +#include +#include + +#include +#include + +#define META_TYPE_IDLE_MONITOR_XSYNC (meta_idle_monitor_xsync_get_type ()) +#define META_IDLE_MONITOR_XSYNC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSync)) +#define META_IDLE_MONITOR_XSYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSyncClass)) +#define META_IS_IDLE_MONITOR_XSYNC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR_XSYNC)) +#define META_IS_IDLE_MONITOR_XSYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_IDLE_MONITOR_XSYNC)) +#define META_IDLE_MONITOR_XSYNC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSyncClass)) + +typedef struct _MetaIdleMonitorXSync MetaIdleMonitorXSync; +typedef struct _MetaIdleMonitorXSyncClass MetaIdleMonitorXSyncClass; + +GType meta_idle_monitor_xsync_get_type (void); + +void meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor *monitor, + XSyncAlarmNotifyEvent *xevent); + +void meta_idle_monitor_xsync_handle_xevent_all (XEvent *xevent); + +#endif /* META_IDLE_MONITOR_XSYNC_H */ diff --git a/src/core/meta-idle-monitor.c b/src/core/meta-idle-monitor.c index 7af248584..522727004 100644 --- a/src/core/meta-idle-monitor.c +++ b/src/core/meta-idle-monitor.c @@ -38,50 +38,11 @@ #include #include "meta-idle-monitor-private.h" #include "meta-idle-monitor-dbus.h" -#include "display-private.h" +#include "meta-idle-monitor-xsync.h" +#include "meta-idle-monitor-native.h" G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer)); -struct _MetaIdleMonitor -{ - GObject parent_instance; - - GHashTable *watches; - GHashTable *alarms; - int device_id; - - /* X11 implementation */ - Display *display; - int sync_event_base; - XSyncCounter counter; - XSyncAlarm user_active_alarm; - - /* Wayland implementation */ - guint64 last_event_time; -}; - -struct _MetaIdleMonitorClass -{ - GObjectClass parent_class; -}; - -typedef struct -{ - MetaIdleMonitor *monitor; - guint id; - MetaIdleMonitorWatchFunc callback; - gpointer user_data; - GDestroyNotify notify; - guint64 timeout_msec; - - /* x11 */ - XSyncAlarm xalarm; - int idle_source_id; - - /* wayland */ - GSource *timeout_source; -} MetaIdleMonitorWatch; - enum { PROP_0, @@ -96,8 +57,8 @@ G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT) static MetaIdleMonitor *device_monitors[256]; static int device_id_max; -static void -fire_watch (MetaIdleMonitorWatch *watch) +void +_meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch) { MetaIdleMonitor *monitor; guint id; @@ -124,164 +85,6 @@ fire_watch (MetaIdleMonitorWatch *watch) g_object_unref (monitor); } -static gint64 -_xsyncvalue_to_int64 (XSyncValue value) -{ - return ((guint64) XSyncValueHigh32 (value)) << 32 - | (guint64) XSyncValueLow32 (value); -} - -#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32) - -static XSyncAlarm -_xsync_alarm_set (MetaIdleMonitor *monitor, - XSyncTestType test_type, - guint64 interval, - gboolean want_events) -{ - XSyncAlarmAttributes attr; - XSyncValue delta; - guint flags; - - flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | - XSyncCAValue | XSyncCADelta | XSyncCAEvents; - - XSyncIntToValue (&delta, 0); - attr.trigger.counter = monitor->counter; - attr.trigger.value_type = XSyncAbsolute; - attr.delta = delta; - attr.events = want_events; - - GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value); - attr.trigger.test_type = test_type; - return XSyncCreateAlarm (monitor->display, flags, &attr); -} - -static void -ensure_alarm_rescheduled (Display *dpy, - XSyncAlarm alarm) -{ - XSyncAlarmAttributes attr; - - /* Some versions of Xorg have an issue where alarms aren't - * always rescheduled. Calling XSyncChangeAlarm, even - * without any attributes, will reschedule the alarm. */ - XSyncChangeAlarm (dpy, alarm, 0, &attr); -} - -static void -set_alarm_enabled (Display *dpy, - XSyncAlarm alarm, - gboolean enabled) -{ - XSyncAlarmAttributes attr; - attr.events = enabled; - XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr); -} - -static void -check_x11_watch (gpointer data, - gpointer user_data) -{ - MetaIdleMonitorWatch *watch = data; - XSyncAlarm alarm = (XSyncAlarm) user_data; - - if (watch->xalarm != alarm) - return; - - fire_watch (watch); -} - -static void -meta_idle_monitor_handle_xevent (MetaIdleMonitor *monitor, - XSyncAlarmNotifyEvent *alarm_event) -{ - XSyncAlarm alarm; - GList *watches; - gboolean has_alarm; - - if (alarm_event->state != XSyncAlarmActive) - return; - - alarm = alarm_event->alarm; - - has_alarm = FALSE; - - if (alarm == monitor->user_active_alarm) - { - set_alarm_enabled (monitor->display, - alarm, - FALSE); - has_alarm = TRUE; - } - else if (g_hash_table_contains (monitor->alarms, (gpointer) alarm)) - { - ensure_alarm_rescheduled (monitor->display, - alarm); - has_alarm = TRUE; - } - - if (has_alarm) - { - watches = g_hash_table_get_values (monitor->watches); - - g_list_foreach (watches, check_x11_watch, (gpointer) alarm); - g_list_free (watches); - } -} - -void -meta_idle_monitor_handle_xevent_all (XEvent *xevent) -{ - int i; - - for (i = 0; i <= device_id_max; i++) - if (device_monitors[i]) - meta_idle_monitor_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent); -} - -static char * -counter_name_for_device (int device_id) -{ - if (device_id > 0) - return g_strdup_printf ("DEVICEIDLETIME %d", device_id); - - return g_strdup ("IDLETIME"); -} - -static XSyncCounter -find_idletime_counter (MetaIdleMonitor *monitor) -{ - int i; - int ncounters; - XSyncSystemCounter *counters; - XSyncCounter counter = None; - char *counter_name; - - counter_name = counter_name_for_device (monitor->device_id); - counters = XSyncListSystemCounters (monitor->display, &ncounters); - for (i = 0; i < ncounters; i++) - { - if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0) - { - counter = counters[i].counter; - break; - } - } - XSyncFreeSystemCounterList (counters); - g_free (counter_name); - - return counter; -} - -static guint32 -get_next_watch_serial (void) -{ - static guint32 serial = 0; - g_atomic_int_inc (&serial); - return serial; -} - static void idle_monitor_watch_free (MetaIdleMonitorWatch *watch) { @@ -316,36 +119,14 @@ idle_monitor_watch_free (MetaIdleMonitorWatch *watch) g_slice_free (MetaIdleMonitorWatch, watch); } -static void -init_xsync (MetaIdleMonitor *monitor) -{ - monitor->counter = find_idletime_counter (monitor); - /* IDLETIME counter not found? */ - if (monitor->counter == None) - { - meta_warning ("IDLETIME counter not found\n"); - return; - } - - monitor->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE); -} - static void meta_idle_monitor_dispose (GObject *object) { - MetaIdleMonitor *monitor; - - monitor = META_IDLE_MONITOR (object); + MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); g_clear_pointer (&monitor->watches, g_hash_table_destroy); g_clear_pointer (&monitor->alarms, g_hash_table_destroy); - if (monitor->user_active_alarm != None) - { - XSyncDestroyAlarm (monitor->display, monitor->user_active_alarm); - monitor->user_active_alarm = None; - } - G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object); } @@ -386,25 +167,12 @@ meta_idle_monitor_set_property (GObject *object, } } -static void -meta_idle_monitor_constructed (GObject *object) -{ - MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); - - if (!meta_is_wayland_compositor ()) - { - monitor->display = meta_get_display ()->xdisplay; - init_xsync (monitor); - } -} - static void meta_idle_monitor_class_init (MetaIdleMonitorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = meta_idle_monitor_dispose; - object_class->constructed = meta_idle_monitor_constructed; object_class->get_property = meta_idle_monitor_get_property; object_class->set_property = meta_idle_monitor_set_property; @@ -433,13 +201,24 @@ meta_idle_monitor_init (MetaIdleMonitor *monitor) monitor->alarms = g_hash_table_new (NULL, NULL); } +static GType +get_idle_monitor_type (void) +{ + if (meta_is_wayland_compositor ()) + return META_TYPE_IDLE_MONITOR_NATIVE; + else + return META_TYPE_IDLE_MONITOR_XSYNC; +} + static void ensure_device_monitor (int device_id) { if (device_monitors[device_id]) return; - device_monitors[device_id] = g_object_new (META_TYPE_IDLE_MONITOR, "device-id", device_id, NULL); + device_monitors[device_id] = g_object_new (get_idle_monitor_type (), + "device-id", device_id, + NULL); device_id_max = MAX (device_id_max, device_id); } @@ -483,85 +262,20 @@ meta_idle_monitor_get_for_device (int device_id) return device_monitors[device_id]; } -static gboolean -wayland_dispatch_timeout (GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - MetaIdleMonitorWatch *watch = user_data; - - fire_watch (watch); - g_source_set_ready_time (watch->timeout_source, -1); - return TRUE; -} - -static GSourceFuncs wayland_source_funcs = { - NULL, /* prepare */ - NULL, /* check */ - wayland_dispatch_timeout, - NULL, /* finalize */ -}; - -static gboolean -fire_watch_idle (gpointer data) -{ - MetaIdleMonitorWatch *watch = data; - - watch->idle_source_id = 0; - fire_watch (watch); - - return FALSE; -} - static MetaIdleMonitorWatch * make_watch (MetaIdleMonitor *monitor, guint64 timeout_msec, - MetaIdleMonitorWatchFunc callback, - gpointer user_data, - GDestroyNotify notify) + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) { MetaIdleMonitorWatch *watch; - watch = g_slice_new0 (MetaIdleMonitorWatch); - watch->monitor = monitor; - watch->id = get_next_watch_serial (); - watch->callback = callback; - watch->user_data = user_data; - watch->notify = notify; - watch->timeout_msec = timeout_msec; - - if (meta_is_wayland_compositor ()) - { - if (timeout_msec != 0) - { - GSource *source = g_source_new (&wayland_source_funcs, sizeof (GSource)); - - g_source_set_callback (source, NULL, watch, NULL); - g_source_set_ready_time (source, monitor->last_event_time + timeout_msec * 1000); - g_source_attach (source, NULL); - g_source_unref (source); - - watch->timeout_source = source; - } - } - else if (monitor->user_active_alarm != None) - { - if (timeout_msec != 0) - { - watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE); - - g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm); - - if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec) - watch->idle_source_id = g_idle_add (fire_watch_idle, watch); - } - else - { - watch->xalarm = monitor->user_active_alarm; - - set_alarm_enabled (monitor->display, monitor->user_active_alarm, TRUE); - } - } + watch = META_IDLE_MONITOR_GET_CLASS (monitor)->make_watch (monitor, + timeout_msec, + callback, + user_data, + notify); g_hash_table_insert (monitor->watches, GUINT_TO_POINTER (watch->id), @@ -668,23 +382,6 @@ meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor, g_object_unref (monitor); } -static gint64 -meta_idle_monitor_get_idletime_wayland (MetaIdleMonitor *monitor) -{ - return (g_get_monotonic_time () - monitor->last_event_time) / 1000; -} - -static gint64 -meta_idle_monitor_get_idletime_x11 (MetaIdleMonitor *monitor) -{ - XSyncValue value; - - if (!XSyncQueryCounter (monitor->display, monitor->counter, &value)) - return -1; - - return _xsyncvalue_to_int64 (value); -} - /** * meta_idle_monitor_get_idletime: * @monitor: A #MetaIdleMonitor @@ -694,61 +391,17 @@ meta_idle_monitor_get_idletime_x11 (MetaIdleMonitor *monitor) gint64 meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor) { - if (meta_is_wayland_compositor ()) - return meta_idle_monitor_get_idletime_wayland (monitor); - else - return meta_idle_monitor_get_idletime_x11 (monitor); -} - -typedef struct { - MetaIdleMonitor *monitor; - GList *fired_watches; -} CheckWaylandClosure; - -static gboolean -check_wayland_watch (gpointer key, - gpointer value, - gpointer user_data) -{ - MetaIdleMonitorWatch *watch = value; - CheckWaylandClosure *closure = user_data; - gboolean steal; - - if (watch->timeout_msec == 0) - { - closure->fired_watches = g_list_prepend (closure->fired_watches, watch); - steal = TRUE; - } - else - { - g_source_set_ready_time (watch->timeout_source, - closure->monitor->last_event_time + - watch->timeout_msec * 1000); - steal = FALSE; - } - - return steal; -} - -static void -fire_wayland_watch (gpointer watch, - gpointer data) -{ - fire_watch (watch); + return META_IDLE_MONITOR_GET_CLASS (monitor)->get_idletime (monitor); } void -meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor) +meta_idle_monitor_xsync_handle_xevent_all (XEvent *xevent) { - CheckWaylandClosure closure; + int i; - monitor->last_event_time = g_get_monotonic_time (); + g_assert (!meta_is_wayland_compositor ()); - closure.monitor = monitor; - closure.fired_watches = NULL; - g_hash_table_foreach_steal (monitor->watches, check_wayland_watch, &closure); - - g_list_foreach (closure.fired_watches, fire_wayland_watch, NULL); - g_list_free (closure.fired_watches); + for (i = 0; i <= device_id_max; i++) + if (device_monitors[i]) + meta_idle_monitor_xsync_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent); } -