1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright 2019 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "config.h"
20
21 #include "gmemorymonitor.h"
22 #include "gmemorymonitordbus.h"
23 #include "gioerror.h"
24 #include "ginitable.h"
25 #include "giomodule-priv.h"
26 #include "glibintl.h"
27 #include "glib/gstdio.h"
28 #include "gcancellable.h"
29 #include "gdbusproxy.h"
30 #include "gdbusnamewatching.h"
31
32 #define G_MEMORY_MONITOR_DBUS_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable))
33
34 static void g_memory_monitor_dbus_iface_init (GMemoryMonitorInterface *iface);
35 static void g_memory_monitor_dbus_initable_iface_init (GInitableIface *iface);
36
37 struct _GMemoryMonitorDBus
38 {
39 GObject parent_instance;
40
41 guint watch_id;
42 GCancellable *cancellable;
43 GDBusProxy *proxy;
44 gulong signal_id;
45 };
46
47 G_DEFINE_TYPE_WITH_CODE (GMemoryMonitorDBus, g_memory_monitor_dbus, G_TYPE_OBJECT,
48 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
49 g_memory_monitor_dbus_initable_iface_init)
50 G_IMPLEMENT_INTERFACE (G_TYPE_MEMORY_MONITOR,
51 g_memory_monitor_dbus_iface_init)
52 _g_io_modules_ensure_extension_points_registered ();
53 g_io_extension_point_implement (G_MEMORY_MONITOR_EXTENSION_POINT_NAME,
54 g_define_type_id,
55 "dbus",
56 30))
57
58 static void
g_memory_monitor_dbus_init(GMemoryMonitorDBus * dbus)59 g_memory_monitor_dbus_init (GMemoryMonitorDBus *dbus)
60 {
61 }
62
63 static void
proxy_signal_cb(GDBusProxy * proxy,const gchar * sender_name,const gchar * signal_name,GVariant * parameters,GMemoryMonitorDBus * dbus)64 proxy_signal_cb (GDBusProxy *proxy,
65 const gchar *sender_name,
66 const gchar *signal_name,
67 GVariant *parameters,
68 GMemoryMonitorDBus *dbus)
69 {
70 guint8 level;
71
72 if (g_strcmp0 (signal_name, "LowMemoryWarning") != 0)
73 return;
74 if (parameters == NULL)
75 return;
76
77 g_variant_get (parameters, "(y)", &level);
78 g_signal_emit_by_name (dbus, "low-memory-warning", level);
79 }
80
81 static void
lmm_proxy_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)82 lmm_proxy_cb (GObject *source_object,
83 GAsyncResult *res,
84 gpointer user_data)
85 {
86 GMemoryMonitorDBus *dbus = user_data;
87 GDBusProxy *proxy;
88 GError *error = NULL;
89
90 proxy = g_dbus_proxy_new_finish (res, &error);
91 if (!proxy)
92 {
93 g_debug ("Failed to create LowMemoryMonitor D-Bus proxy: %s",
94 error->message);
95 g_error_free (error);
96 return;
97 }
98
99 dbus->signal_id = g_signal_connect (G_OBJECT (proxy), "g-signal",
100 G_CALLBACK (proxy_signal_cb), dbus);
101 dbus->proxy = proxy;
102
103 }
104
105 static void
lmm_appeared_cb(GDBusConnection * connection,const gchar * name,const gchar * name_owner,gpointer user_data)106 lmm_appeared_cb (GDBusConnection *connection,
107 const gchar *name,
108 const gchar *name_owner,
109 gpointer user_data)
110 {
111 GMemoryMonitorDBus *dbus = user_data;
112
113 g_dbus_proxy_new (connection,
114 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
115 NULL,
116 "org.freedesktop.LowMemoryMonitor",
117 "/org/freedesktop/LowMemoryMonitor",
118 "org.freedesktop.LowMemoryMonitor",
119 dbus->cancellable,
120 lmm_proxy_cb,
121 dbus);
122 }
123
124 static void
lmm_vanished_cb(GDBusConnection * connection,const gchar * name,gpointer user_data)125 lmm_vanished_cb (GDBusConnection *connection,
126 const gchar *name,
127 gpointer user_data)
128 {
129 GMemoryMonitorDBus *dbus = user_data;
130
131 g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
132 g_clear_object (&dbus->proxy);
133 }
134
135 static gboolean
g_memory_monitor_dbus_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)136 g_memory_monitor_dbus_initable_init (GInitable *initable,
137 GCancellable *cancellable,
138 GError **error)
139 {
140 GMemoryMonitorDBus *dbus = G_MEMORY_MONITOR_DBUS (initable);
141
142 dbus->cancellable = g_cancellable_new ();
143 dbus->watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
144 "org.freedesktop.LowMemoryMonitor",
145 G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
146 lmm_appeared_cb,
147 lmm_vanished_cb,
148 dbus,
149 NULL);
150
151 return TRUE;
152 }
153
154 static void
g_memory_monitor_dbus_finalize(GObject * object)155 g_memory_monitor_dbus_finalize (GObject *object)
156 {
157 GMemoryMonitorDBus *dbus = G_MEMORY_MONITOR_DBUS (object);
158
159 g_cancellable_cancel (dbus->cancellable);
160 g_clear_object (&dbus->cancellable);
161 g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
162 g_clear_object (&dbus->proxy);
163 g_clear_handle_id (&dbus->watch_id, g_bus_unwatch_name);
164
165 G_OBJECT_CLASS (g_memory_monitor_dbus_parent_class)->finalize (object);
166 }
167
168 static void
g_memory_monitor_dbus_class_init(GMemoryMonitorDBusClass * nl_class)169 g_memory_monitor_dbus_class_init (GMemoryMonitorDBusClass *nl_class)
170 {
171 GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
172
173 gobject_class->finalize = g_memory_monitor_dbus_finalize;
174 }
175
176 static void
g_memory_monitor_dbus_iface_init(GMemoryMonitorInterface * monitor_iface)177 g_memory_monitor_dbus_iface_init (GMemoryMonitorInterface *monitor_iface)
178 {
179 }
180
181 static void
g_memory_monitor_dbus_initable_iface_init(GInitableIface * iface)182 g_memory_monitor_dbus_initable_iface_init (GInitableIface *iface)
183 {
184 iface->init = g_memory_monitor_dbus_initable_init;
185 }
186