1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 
3 /*
4  * Copyright 2013-2021 Red Hat, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
20  *         from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
21  */
22 
23 #include "config.h"
24 
25 #include "backends/meta-idle-manager.h"
26 
27 #include "backends/meta-idle-monitor-private.h"
28 #include "clutter/clutter.h"
29 #include "meta/main.h"
30 #include "meta/meta-context.h"
31 #include "meta/meta-idle-monitor.h"
32 #include "meta/util.h"
33 
34 #include "meta-dbus-idle-monitor.h"
35 
36 typedef struct _MetaIdleManager
37 {
38   MetaBackend *backend;
39   guint dbus_name_id;
40 
41   GHashTable *device_monitors;
42 } MetaIdleManager;
43 
44 static gboolean
handle_get_idletime(MetaDBusIdleMonitor * skeleton,GDBusMethodInvocation * invocation,MetaIdleMonitor * monitor)45 handle_get_idletime (MetaDBusIdleMonitor   *skeleton,
46                      GDBusMethodInvocation *invocation,
47                      MetaIdleMonitor       *monitor)
48 {
49   guint64 idletime;
50 
51   idletime = meta_idle_monitor_get_idletime (monitor);
52   meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime);
53 
54   return TRUE;
55 }
56 
57 static gboolean
handle_reset_idletime(MetaDBusIdleMonitor * skeleton,GDBusMethodInvocation * invocation,MetaIdleMonitor * monitor)58 handle_reset_idletime (MetaDBusIdleMonitor   *skeleton,
59                        GDBusMethodInvocation *invocation,
60                        MetaIdleMonitor       *monitor)
61 {
62   if (!g_getenv ("MUTTER_DEBUG_RESET_IDLETIME"))
63     {
64       g_dbus_method_invocation_return_error_literal (invocation,
65                                                      G_DBUS_ERROR,
66                                                      G_DBUS_ERROR_UNKNOWN_METHOD,
67                                                      "This method is for testing purposes only. MUTTER_DEBUG_RESET_IDLETIME must be set to use it");
68       return TRUE;
69     }
70 
71   meta_idle_manager_reset_idle_time (meta_idle_monitor_get_manager (monitor));
72   meta_dbus_idle_monitor_complete_reset_idletime (skeleton, invocation);
73 
74   return TRUE;
75 }
76 
77 typedef struct {
78   MetaDBusIdleMonitor *dbus_monitor;
79   MetaIdleMonitor *monitor;
80   char *dbus_name;
81   guint watch_id;
82   guint name_watcher_id;
83 } DBusWatch;
84 
85 static void
destroy_dbus_watch(gpointer data)86 destroy_dbus_watch (gpointer data)
87 {
88   DBusWatch *watch = data;
89 
90   g_object_unref (watch->dbus_monitor);
91   g_object_unref (watch->monitor);
92   g_free (watch->dbus_name);
93   g_bus_unwatch_name (watch->name_watcher_id);
94 
95   g_free (watch);
96 }
97 
98 static void
dbus_idle_callback(MetaIdleMonitor * monitor,guint watch_id,gpointer user_data)99 dbus_idle_callback (MetaIdleMonitor *monitor,
100                     guint            watch_id,
101                     gpointer         user_data)
102 {
103   DBusWatch *watch = user_data;
104   GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor);
105 
106   g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton),
107                                  watch->dbus_name,
108                                  g_dbus_interface_skeleton_get_object_path (skeleton),
109                                  "org.gnome.Mutter.IdleMonitor",
110                                  "WatchFired",
111                                  g_variant_new ("(u)", watch_id),
112                                  NULL);
113 }
114 
115 static void
name_vanished_callback(GDBusConnection * connection,const char * name,gpointer user_data)116 name_vanished_callback (GDBusConnection *connection,
117                         const char      *name,
118                         gpointer         user_data)
119 {
120   DBusWatch *watch = user_data;
121 
122   meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id);
123 }
124 
125 static DBusWatch *
make_dbus_watch(MetaDBusIdleMonitor * skeleton,GDBusMethodInvocation * invocation,MetaIdleMonitor * monitor)126 make_dbus_watch (MetaDBusIdleMonitor   *skeleton,
127                  GDBusMethodInvocation *invocation,
128                  MetaIdleMonitor       *monitor)
129 {
130   DBusWatch *watch;
131 
132   watch = g_new0 (DBusWatch, 1);
133   watch->dbus_monitor = g_object_ref (skeleton);
134   watch->monitor = g_object_ref (monitor);
135   watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation));
136   watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation),
137                                                            watch->dbus_name,
138                                                            G_BUS_NAME_WATCHER_FLAGS_NONE,
139                                                            NULL, /* appeared */
140                                                            name_vanished_callback,
141                                                            watch, NULL);
142 
143   return watch;
144 }
145 
146 static gboolean
handle_add_idle_watch(MetaDBusIdleMonitor * skeleton,GDBusMethodInvocation * invocation,guint64 interval,MetaIdleMonitor * monitor)147 handle_add_idle_watch (MetaDBusIdleMonitor   *skeleton,
148                        GDBusMethodInvocation *invocation,
149                        guint64                interval,
150                        MetaIdleMonitor       *monitor)
151 {
152   DBusWatch *watch;
153 
154   watch = make_dbus_watch (skeleton, invocation, monitor);
155   watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval,
156                                                       dbus_idle_callback, watch, destroy_dbus_watch);
157 
158   meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id);
159 
160   return TRUE;
161 }
162 
163 static gboolean
handle_add_user_active_watch(MetaDBusIdleMonitor * skeleton,GDBusMethodInvocation * invocation,MetaIdleMonitor * monitor)164 handle_add_user_active_watch (MetaDBusIdleMonitor   *skeleton,
165                               GDBusMethodInvocation *invocation,
166                               MetaIdleMonitor       *monitor)
167 {
168   DBusWatch *watch;
169 
170   watch = make_dbus_watch (skeleton, invocation, monitor);
171   watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor,
172                                                              dbus_idle_callback, watch,
173                                                              destroy_dbus_watch);
174 
175   meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id);
176 
177   return TRUE;
178 }
179 
180 static gboolean
handle_remove_watch(MetaDBusIdleMonitor * skeleton,GDBusMethodInvocation * invocation,guint id,MetaIdleMonitor * monitor)181 handle_remove_watch (MetaDBusIdleMonitor   *skeleton,
182                      GDBusMethodInvocation *invocation,
183                      guint                  id,
184                      MetaIdleMonitor       *monitor)
185 {
186   meta_idle_monitor_remove_watch (monitor, id);
187   meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation);
188 
189   return TRUE;
190 }
191 
192 static void
create_monitor_skeleton(GDBusObjectManagerServer * manager,MetaIdleMonitor * monitor,const char * path)193 create_monitor_skeleton (GDBusObjectManagerServer *manager,
194                          MetaIdleMonitor          *monitor,
195                          const char               *path)
196 {
197   MetaDBusIdleMonitor *skeleton;
198   MetaDBusObjectSkeleton *object;
199 
200   skeleton = meta_dbus_idle_monitor_skeleton_new ();
201   g_signal_connect (skeleton, "handle-add-idle-watch",
202                     G_CALLBACK (handle_add_idle_watch), monitor);
203   g_signal_connect (skeleton, "handle-add-user-active-watch",
204                     G_CALLBACK (handle_add_user_active_watch), monitor);
205   g_signal_connect (skeleton, "handle-remove-watch",
206                     G_CALLBACK (handle_remove_watch), monitor);
207   g_signal_connect (skeleton, "handle-reset-idletime",
208                     G_CALLBACK (handle_reset_idletime), monitor);
209   g_signal_connect (skeleton, "handle-get-idletime",
210                     G_CALLBACK (handle_get_idletime), monitor);
211 
212   object = meta_dbus_object_skeleton_new (path);
213   meta_dbus_object_skeleton_set_idle_monitor (object, skeleton);
214 
215   g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
216 
217   g_object_unref (skeleton);
218   g_object_unref (object);
219 }
220 
221 static void
on_bus_acquired(GDBusConnection * connection,const char * name,gpointer user_data)222 on_bus_acquired (GDBusConnection *connection,
223                  const char      *name,
224                  gpointer         user_data)
225 {
226   MetaIdleManager *manager = user_data;
227   GDBusObjectManagerServer *object_manager;
228   MetaIdleMonitor *monitor;
229   char *path;
230 
231   object_manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor");
232 
233   /* We never clear the core monitor, as that's supposed to cumulate idle times from
234      all devices */
235   monitor = meta_idle_manager_get_core_monitor (manager);
236   path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core");
237   create_monitor_skeleton (object_manager, monitor, path);
238   g_free (path);
239 
240   g_dbus_object_manager_server_set_connection (object_manager, connection);
241 }
242 
243 static void
on_name_acquired(GDBusConnection * connection,const char * name,gpointer user_data)244 on_name_acquired (GDBusConnection *connection,
245                   const char      *name,
246                   gpointer         user_data)
247 {
248   meta_verbose ("Acquired name %s", name);
249 }
250 
251 static void
on_name_lost(GDBusConnection * connection,const char * name,gpointer user_data)252 on_name_lost (GDBusConnection *connection,
253               const char      *name,
254               gpointer         user_data)
255 {
256   meta_verbose ("Lost or failed to acquire name %s", name);
257 }
258 
259 MetaIdleMonitor *
meta_idle_manager_get_monitor(MetaIdleManager * idle_manager,ClutterInputDevice * device)260 meta_idle_manager_get_monitor (MetaIdleManager    *idle_manager,
261                                ClutterInputDevice *device)
262 {
263   return g_hash_table_lookup (idle_manager->device_monitors, device);
264 }
265 
266 MetaIdleMonitor *
meta_idle_manager_get_core_monitor(MetaIdleManager * idle_manager)267 meta_idle_manager_get_core_monitor (MetaIdleManager *idle_manager)
268 {
269   MetaBackend *backend = meta_get_backend ();
270   ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
271   ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend);
272 
273   return meta_backend_get_idle_monitor (backend,
274                                         clutter_seat_get_pointer (seat));
275 }
276 
277 void
meta_idle_manager_reset_idle_time(MetaIdleManager * idle_manager)278 meta_idle_manager_reset_idle_time (MetaIdleManager *idle_manager)
279 {
280   MetaIdleMonitor *core_monitor;
281 
282   core_monitor = meta_idle_manager_get_core_monitor (idle_manager);
283   meta_idle_monitor_reset_idletime (core_monitor);
284 }
285 
286 static void
create_device_monitor(MetaIdleManager * idle_manager,ClutterInputDevice * device)287 create_device_monitor (MetaIdleManager    *idle_manager,
288                        ClutterInputDevice *device)
289 {
290   MetaIdleMonitor *idle_monitor;
291 
292   if (g_hash_table_contains (idle_manager->device_monitors, device))
293     return;
294 
295   idle_monitor = meta_idle_monitor_new (idle_manager, device);
296   g_hash_table_insert (idle_manager->device_monitors, device, idle_monitor);
297 }
298 
299 static void
on_device_added(ClutterSeat * seat,ClutterInputDevice * device,gpointer user_data)300 on_device_added (ClutterSeat        *seat,
301                  ClutterInputDevice *device,
302                  gpointer            user_data)
303 {
304   MetaIdleManager *idle_manager = user_data;
305 
306   create_device_monitor (idle_manager, device);
307 }
308 
309 static void
on_device_removed(ClutterSeat * seat,ClutterInputDevice * device,gpointer user_data)310 on_device_removed (ClutterSeat        *seat,
311                    ClutterInputDevice *device,
312                    gpointer            user_data)
313 {
314   MetaIdleManager *idle_manager = user_data;
315 
316   g_hash_table_remove (idle_manager->device_monitors, device);
317 }
318 
319 static void
create_device_monitors(MetaIdleManager * idle_manager,ClutterSeat * seat)320 create_device_monitors (MetaIdleManager *idle_manager,
321                         ClutterSeat     *seat)
322 {
323   GList *l, *devices;
324 
325   create_device_monitor (idle_manager, clutter_seat_get_pointer (seat));
326   create_device_monitor (idle_manager, clutter_seat_get_keyboard (seat));
327 
328   devices = clutter_seat_list_devices (seat);
329   for (l = devices; l; l = l->next)
330     {
331       ClutterInputDevice *device = l->data;
332 
333       create_device_monitor (idle_manager, device);
334     }
335 
336   g_list_free (devices);
337 }
338 
339 MetaIdleManager *
meta_idle_manager_new(MetaBackend * backend)340 meta_idle_manager_new (MetaBackend *backend)
341 {
342   MetaContext *context = meta_backend_get_context (backend);
343   ClutterSeat *seat = meta_backend_get_default_seat (backend);
344   MetaIdleManager *idle_manager;
345 
346   idle_manager = g_new0 (MetaIdleManager, 1);
347   idle_manager->backend = backend;
348 
349   idle_manager->dbus_name_id =
350     g_bus_own_name (G_BUS_TYPE_SESSION,
351                     "org.gnome.Mutter.IdleMonitor",
352                     G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
353                     (meta_context_is_replacing (context) ?
354                      G_BUS_NAME_OWNER_FLAGS_REPLACE :
355                      G_BUS_NAME_OWNER_FLAGS_NONE),
356                     on_bus_acquired,
357                     on_name_acquired,
358                     on_name_lost,
359                     idle_manager,
360                     NULL);
361 
362   idle_manager->device_monitors =
363     g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref);
364   g_signal_connect (seat, "device-added",
365                     G_CALLBACK (on_device_added), idle_manager);
366   g_signal_connect_after (seat, "device-removed",
367                           G_CALLBACK (on_device_removed), idle_manager);
368   create_device_monitors (idle_manager, seat);
369 
370   return idle_manager;
371 }
372 
373 void
meta_idle_manager_free(MetaIdleManager * idle_manager)374 meta_idle_manager_free (MetaIdleManager *idle_manager)
375 {
376   g_clear_pointer (&idle_manager->device_monitors, g_hash_table_destroy);
377   g_bus_unown_name (idle_manager->dbus_name_id);
378   g_free (idle_manager);
379 }
380