/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright 2013-2021 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 "backends/meta-idle-manager.h" #include "backends/meta-idle-monitor-private.h" #include "clutter/clutter.h" #include "meta/main.h" #include "meta/meta-context.h" #include "meta/meta-idle-monitor.h" #include "meta/util.h" #include "meta-dbus-idle-monitor.h" typedef struct _MetaIdleManager { MetaBackend *backend; guint dbus_name_id; GHashTable *device_monitors; } MetaIdleManager; static gboolean handle_get_idletime (MetaDBusIdleMonitor *skeleton, GDBusMethodInvocation *invocation, MetaIdleMonitor *monitor) { guint64 idletime; idletime = meta_idle_monitor_get_idletime (monitor); meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime); return TRUE; } static gboolean handle_reset_idletime (MetaDBusIdleMonitor *skeleton, GDBusMethodInvocation *invocation, MetaIdleMonitor *monitor) { if (!g_getenv ("MUTTER_DEBUG_RESET_IDLETIME")) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "This method is for testing purposes only. MUTTER_DEBUG_RESET_IDLETIME must be set to use it"); return TRUE; } meta_idle_manager_reset_idle_time (meta_idle_monitor_get_manager (monitor)); meta_dbus_idle_monitor_complete_reset_idletime (skeleton, invocation); return TRUE; } typedef struct { MetaDBusIdleMonitor *dbus_monitor; MetaIdleMonitor *monitor; char *dbus_name; guint watch_id; guint name_watcher_id; } DBusWatch; static void destroy_dbus_watch (gpointer data) { DBusWatch *watch = data; g_object_unref (watch->dbus_monitor); g_object_unref (watch->monitor); g_free (watch->dbus_name); g_bus_unwatch_name (watch->name_watcher_id); g_free (watch); } static void dbus_idle_callback (MetaIdleMonitor *monitor, guint watch_id, gpointer user_data) { DBusWatch *watch = user_data; GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor); g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton), watch->dbus_name, g_dbus_interface_skeleton_get_object_path (skeleton), "org.gnome.Mutter.IdleMonitor", "WatchFired", g_variant_new ("(u)", watch_id), NULL); } static void name_vanished_callback (GDBusConnection *connection, const char *name, gpointer user_data) { DBusWatch *watch = user_data; meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id); } static DBusWatch * make_dbus_watch (MetaDBusIdleMonitor *skeleton, GDBusMethodInvocation *invocation, MetaIdleMonitor *monitor) { DBusWatch *watch; watch = g_new0 (DBusWatch, 1); watch->dbus_monitor = g_object_ref (skeleton); watch->monitor = g_object_ref (monitor); watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation)); watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation), watch->dbus_name, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, /* appeared */ name_vanished_callback, watch, NULL); return watch; } static gboolean handle_add_idle_watch (MetaDBusIdleMonitor *skeleton, GDBusMethodInvocation *invocation, guint64 interval, MetaIdleMonitor *monitor) { DBusWatch *watch; watch = make_dbus_watch (skeleton, invocation, monitor); watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval, dbus_idle_callback, watch, destroy_dbus_watch); meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id); return TRUE; } static gboolean handle_add_user_active_watch (MetaDBusIdleMonitor *skeleton, GDBusMethodInvocation *invocation, MetaIdleMonitor *monitor) { DBusWatch *watch; watch = make_dbus_watch (skeleton, invocation, monitor); watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor, dbus_idle_callback, watch, destroy_dbus_watch); meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id); return TRUE; } static gboolean handle_remove_watch (MetaDBusIdleMonitor *skeleton, GDBusMethodInvocation *invocation, guint id, MetaIdleMonitor *monitor) { meta_idle_monitor_remove_watch (monitor, id); meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation); return TRUE; } static void create_monitor_skeleton (GDBusObjectManagerServer *manager, MetaIdleMonitor *monitor, const char *path) { MetaDBusIdleMonitor *skeleton; MetaDBusObjectSkeleton *object; skeleton = meta_dbus_idle_monitor_skeleton_new (); g_signal_connect (skeleton, "handle-add-idle-watch", G_CALLBACK (handle_add_idle_watch), monitor); g_signal_connect (skeleton, "handle-add-user-active-watch", G_CALLBACK (handle_add_user_active_watch), monitor); g_signal_connect (skeleton, "handle-remove-watch", G_CALLBACK (handle_remove_watch), monitor); g_signal_connect (skeleton, "handle-reset-idletime", G_CALLBACK (handle_reset_idletime), monitor); g_signal_connect (skeleton, "handle-get-idletime", G_CALLBACK (handle_get_idletime), monitor); object = meta_dbus_object_skeleton_new (path); meta_dbus_object_skeleton_set_idle_monitor (object, skeleton); g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object)); g_object_unref (skeleton); g_object_unref (object); } static void on_bus_acquired (GDBusConnection *connection, const char *name, gpointer user_data) { MetaIdleManager *manager = user_data; GDBusObjectManagerServer *object_manager; MetaIdleMonitor *monitor; char *path; object_manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor"); /* We never clear the core monitor, as that's supposed to cumulate idle times from all devices */ monitor = meta_idle_manager_get_core_monitor (manager); path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core"); create_monitor_skeleton (object_manager, monitor, path); g_free (path); g_dbus_object_manager_server_set_connection (object_manager, connection); } static void on_name_acquired (GDBusConnection *connection, const char *name, gpointer user_data) { meta_verbose ("Acquired name %s", name); } static void on_name_lost (GDBusConnection *connection, const char *name, gpointer user_data) { meta_verbose ("Lost or failed to acquire name %s", name); } MetaIdleMonitor * meta_idle_manager_get_monitor (MetaIdleManager *idle_manager, ClutterInputDevice *device) { return g_hash_table_lookup (idle_manager->device_monitors, device); } MetaIdleMonitor * meta_idle_manager_get_core_monitor (MetaIdleManager *idle_manager) { MetaBackend *backend = meta_get_backend (); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); return meta_backend_get_idle_monitor (backend, clutter_seat_get_pointer (seat)); } void meta_idle_manager_reset_idle_time (MetaIdleManager *idle_manager) { MetaIdleMonitor *core_monitor; core_monitor = meta_idle_manager_get_core_monitor (idle_manager); meta_idle_monitor_reset_idletime (core_monitor); } static void create_device_monitor (MetaIdleManager *idle_manager, ClutterInputDevice *device) { MetaIdleMonitor *idle_monitor; if (g_hash_table_contains (idle_manager->device_monitors, device)) return; idle_monitor = meta_idle_monitor_new (idle_manager, device); g_hash_table_insert (idle_manager->device_monitors, device, idle_monitor); } static void on_device_added (ClutterSeat *seat, ClutterInputDevice *device, gpointer user_data) { MetaIdleManager *idle_manager = user_data; create_device_monitor (idle_manager, device); } static void on_device_removed (ClutterSeat *seat, ClutterInputDevice *device, gpointer user_data) { MetaIdleManager *idle_manager = user_data; g_hash_table_remove (idle_manager->device_monitors, device); } static void create_device_monitors (MetaIdleManager *idle_manager, ClutterSeat *seat) { GList *l, *devices; create_device_monitor (idle_manager, clutter_seat_get_pointer (seat)); create_device_monitor (idle_manager, clutter_seat_get_keyboard (seat)); devices = clutter_seat_list_devices (seat); for (l = devices; l; l = l->next) { ClutterInputDevice *device = l->data; create_device_monitor (idle_manager, device); } g_list_free (devices); } MetaIdleManager * meta_idle_manager_new (MetaBackend *backend) { MetaContext *context = meta_backend_get_context (backend); ClutterSeat *seat = meta_backend_get_default_seat (backend); MetaIdleManager *idle_manager; idle_manager = g_new0 (MetaIdleManager, 1); idle_manager->backend = backend; idle_manager->dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION, "org.gnome.Mutter.IdleMonitor", G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | (meta_context_is_replacing (context) ? G_BUS_NAME_OWNER_FLAGS_REPLACE : G_BUS_NAME_OWNER_FLAGS_NONE), on_bus_acquired, on_name_acquired, on_name_lost, idle_manager, NULL); idle_manager->device_monitors = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref); g_signal_connect (seat, "device-added", G_CALLBACK (on_device_added), idle_manager); g_signal_connect_after (seat, "device-removed", G_CALLBACK (on_device_removed), idle_manager); create_device_monitors (idle_manager, seat); return idle_manager; } void meta_idle_manager_free (MetaIdleManager *idle_manager) { g_clear_pointer (&idle_manager->device_monitors, g_hash_table_destroy); g_bus_unown_name (idle_manager->dbus_name_id); g_free (idle_manager); }