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 "gdbusproxy.h"
29 #include "gdbusnamewatching.h"
30
31 #define G_MEMORY_MONITOR_DBUS_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable))
32
33 static void g_memory_monitor_dbus_iface_init (GMemoryMonitorInterface *iface);
34 static void g_memory_monitor_dbus_initable_iface_init (GInitableIface *iface);
35
36 struct _GMemoryMonitorDBus
37 {
38 GObject parent_instance;
39
40 guint watch_id;
41 GDBusProxy *proxy;
42 gulong signal_id;
43 };
44
45 G_DEFINE_TYPE_WITH_CODE (GMemoryMonitorDBus, g_memory_monitor_dbus, G_TYPE_OBJECT,
46 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
47 g_memory_monitor_dbus_initable_iface_init)
48 G_IMPLEMENT_INTERFACE (G_TYPE_MEMORY_MONITOR,
49 g_memory_monitor_dbus_iface_init)
50 _g_io_modules_ensure_extension_points_registered ();
51 g_io_extension_point_implement (G_MEMORY_MONITOR_EXTENSION_POINT_NAME,
52 g_define_type_id,
53 "dbus",
54 30))
55
56 static void
g_memory_monitor_dbus_init(GMemoryMonitorDBus * dbus)57 g_memory_monitor_dbus_init (GMemoryMonitorDBus *dbus)
58 {
59 }
60
61 static void
proxy_signal_cb(GDBusProxy * proxy,const gchar * sender_name,const gchar * signal_name,GVariant * parameters,GMemoryMonitorDBus * dbus)62 proxy_signal_cb (GDBusProxy *proxy,
63 const gchar *sender_name,
64 const gchar *signal_name,
65 GVariant *parameters,
66 GMemoryMonitorDBus *dbus)
67 {
68 guint8 level;
69
70 if (g_strcmp0 (signal_name, "LowMemoryWarning") != 0)
71 return;
72 if (parameters == NULL)
73 return;
74
75 g_variant_get (parameters, "(y)", &level);
76 g_signal_emit_by_name (dbus, "low-memory-warning", level);
77 }
78
79 static void
lmm_appeared_cb(GDBusConnection * connection,const gchar * name,const gchar * name_owner,gpointer user_data)80 lmm_appeared_cb (GDBusConnection *connection,
81 const gchar *name,
82 const gchar *name_owner,
83 gpointer user_data)
84 {
85 GMemoryMonitorDBus *dbus = user_data;
86 GDBusProxy *proxy;
87 GError *error = NULL;
88
89 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
90 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
91 NULL,
92 "org.freedesktop.LowMemoryMonitor",
93 "/org/freedesktop/LowMemoryMonitor",
94 "org.freedesktop.LowMemoryMonitor",
95 NULL,
96 &error);
97
98 if (!proxy)
99 {
100 g_debug ("Failed to create LowMemoryMonitor D-Bus proxy: %s",
101 error->message);
102 g_error_free (error);
103 return;
104 }
105
106 dbus->signal_id = g_signal_connect (G_OBJECT (proxy), "g-signal",
107 G_CALLBACK (proxy_signal_cb), dbus);
108 dbus->proxy = proxy;
109 }
110
111 static void
lmm_vanished_cb(GDBusConnection * connection,const gchar * name,gpointer user_data)112 lmm_vanished_cb (GDBusConnection *connection,
113 const gchar *name,
114 gpointer user_data)
115 {
116 GMemoryMonitorDBus *dbus = user_data;
117
118 if (dbus->proxy != NULL)
119 g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
120 g_clear_object (&dbus->proxy);
121 }
122
123 static gboolean
g_memory_monitor_dbus_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)124 g_memory_monitor_dbus_initable_init (GInitable *initable,
125 GCancellable *cancellable,
126 GError **error)
127 {
128 GMemoryMonitorDBus *dbus = G_MEMORY_MONITOR_DBUS (initable);
129
130 dbus->watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
131 "org.freedesktop.LowMemoryMonitor",
132 G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
133 lmm_appeared_cb,
134 lmm_vanished_cb,
135 dbus,
136 NULL);
137
138 return TRUE;
139 }
140
141 static void
g_memory_monitor_dbus_finalize(GObject * object)142 g_memory_monitor_dbus_finalize (GObject *object)
143 {
144 GMemoryMonitorDBus *dbus = G_MEMORY_MONITOR_DBUS (object);
145
146 if (dbus->proxy != NULL)
147 g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
148 g_clear_object (&dbus->proxy);
149 g_clear_handle_id (&dbus->watch_id, g_bus_unwatch_name);
150
151 G_OBJECT_CLASS (g_memory_monitor_dbus_parent_class)->finalize (object);
152 }
153
154 static void
g_memory_monitor_dbus_class_init(GMemoryMonitorDBusClass * nl_class)155 g_memory_monitor_dbus_class_init (GMemoryMonitorDBusClass *nl_class)
156 {
157 GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
158
159 gobject_class->finalize = g_memory_monitor_dbus_finalize;
160 }
161
162 static void
g_memory_monitor_dbus_iface_init(GMemoryMonitorInterface * monitor_iface)163 g_memory_monitor_dbus_iface_init (GMemoryMonitorInterface *monitor_iface)
164 {
165 }
166
167 static void
g_memory_monitor_dbus_initable_iface_init(GInitableIface * iface)168 g_memory_monitor_dbus_initable_iface_init (GInitableIface *iface)
169 {
170 iface->init = g_memory_monitor_dbus_initable_init;
171 }
172