1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright 2019 Red Hat, Inc.
4 * Copyrgith 2021 Igalia S.L.
5 *
6 * SPDX-License-Identifier: LGPL-2.1-or-later
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General
19 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23
24 #include "gpowerprofilemonitor.h"
25 #include "gpowerprofilemonitordbus.h"
26 #include "gioerror.h"
27 #include "ginitable.h"
28 #include "giomodule-priv.h"
29 #include "glibintl.h"
30 #include "glib/gstdio.h"
31 #include "gcancellable.h"
32 #include "gdbusproxy.h"
33 #include "gdbusnamewatching.h"
34
35 #define G_POWER_PROFILE_MONITOR_DBUS_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable))
36
37 static void g_power_profile_monitor_dbus_iface_init (GPowerProfileMonitorInterface *iface);
38 static void g_power_profile_monitor_dbus_initable_iface_init (GInitableIface *iface);
39
40 struct _GPowerProfileMonitorDBus
41 {
42 GObject parent_instance;
43
44 guint watch_id;
45 GCancellable *cancellable;
46 GDBusProxy *proxy;
47 gulong signal_id;
48
49 gboolean power_saver_enabled;
50 };
51
52 typedef enum
53 {
54 PROP_POWER_SAVER_ENABLED = 1,
55 } GPowerProfileMonitorDBusProperty;
56
57 #define POWERPROFILES_DBUS_NAME "net.hadess.PowerProfiles"
58 #define POWERPROFILES_DBUS_IFACE "net.hadess.PowerProfiles"
59 #define POWERPROFILES_DBUS_PATH "/net/hadess/PowerProfiles"
60
61 G_DEFINE_TYPE_WITH_CODE (GPowerProfileMonitorDBus, g_power_profile_monitor_dbus, G_TYPE_OBJECT,
62 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
63 g_power_profile_monitor_dbus_initable_iface_init)
64 G_IMPLEMENT_INTERFACE (G_TYPE_POWER_PROFILE_MONITOR,
65 g_power_profile_monitor_dbus_iface_init)
66 _g_io_modules_ensure_extension_points_registered ();
67 g_io_extension_point_implement (G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME,
68 g_define_type_id,
69 "dbus",
70 30))
71
72 static void
73 g_power_profile_monitor_dbus_init (GPowerProfileMonitorDBus *dbus)
74 {
75 dbus->power_saver_enabled = FALSE;
76 }
77
78 static void
79 ppd_properties_changed_cb (GDBusProxy *proxy,
80 GVariant *changed_properties,
81 GStrv *invalidated_properties,
82 gpointer user_data)
83 {
84 GPowerProfileMonitorDBus *dbus = user_data;
85 const char *active_profile;
86 gboolean enabled;
87
88 if (!g_variant_lookup (changed_properties, "ActiveProfile", "&s", &active_profile))
89 return;
90
91 enabled = g_strcmp0 (active_profile, "power-saver") == 0;
92 if (enabled == dbus->power_saver_enabled)
93 return;
94
95 dbus->power_saver_enabled = enabled;
96 g_object_notify (G_OBJECT (dbus), "power-saver-enabled");
97 }
98
99 static void
100 ppd_proxy_cb (GObject *source_object,
101 GAsyncResult *res,
102 gpointer user_data)
103 {
104 GPowerProfileMonitorDBus *dbus = user_data;
105 GVariant *active_profile_variant;
106 GDBusProxy *proxy;
107 GError *error = NULL;
108 const char *active_profile;
109 gboolean power_saver_enabled;
110
111 proxy = g_dbus_proxy_new_finish (res, &error);
112 if (!proxy)
113 {
114 g_debug ("GPowerProfileMonitorDBus: Failed to create PowerProfiles D-Bus proxy: %s",
115 error->message);
116 g_error_free (error);
117 return;
118 }
119
120 active_profile_variant = g_dbus_proxy_get_cached_property (proxy, "ActiveProfile");
121 if (active_profile_variant != NULL &&
122 g_variant_is_of_type (active_profile_variant, G_VARIANT_TYPE_STRING))
123 {
124 active_profile = g_variant_get_string (active_profile_variant, NULL);
125 power_saver_enabled = g_strcmp0 (active_profile, "power-saver") == 0;
126 if (power_saver_enabled != dbus->power_saver_enabled)
127 {
128 dbus->power_saver_enabled = power_saver_enabled;
129 g_object_notify (G_OBJECT (dbus), "power-saver-enabled");
130 }
131 }
132 g_clear_pointer (&active_profile_variant, g_variant_unref);
133
134 dbus->signal_id = g_signal_connect (G_OBJECT (proxy), "g-properties-changed",
135 G_CALLBACK (ppd_properties_changed_cb), dbus);
136 dbus->proxy = g_steal_pointer (&proxy);
137 }
138
139 static void
140 ppd_appeared_cb (GDBusConnection *connection,
141 const gchar *name,
142 const gchar *name_owner,
143 gpointer user_data)
144 {
145 GPowerProfileMonitorDBus *dbus = user_data;
146
147 g_dbus_proxy_new (connection,
148 G_DBUS_PROXY_FLAGS_NONE,
149 NULL,
150 POWERPROFILES_DBUS_NAME,
151 POWERPROFILES_DBUS_PATH,
152 POWERPROFILES_DBUS_IFACE,
153 dbus->cancellable,
154 ppd_proxy_cb,
155 dbus);
156 }
157
158 static void
159 ppd_vanished_cb (GDBusConnection *connection,
160 const gchar *name,
161 gpointer user_data)
162 {
163 GPowerProfileMonitorDBus *dbus = user_data;
164
165 g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
166 g_clear_object (&dbus->proxy);
167
168 dbus->power_saver_enabled = FALSE;
169 g_object_notify (G_OBJECT (dbus), "power-saver-enabled");
170 }
171
172 static void
173 g_power_profile_monitor_dbus_get_property (GObject *object,
174 guint prop_id,
175 GValue *value,
176 GParamSpec *pspec)
177 {
178 GPowerProfileMonitorDBus *dbus = G_POWER_PROFILE_MONITOR_DBUS (object);
179
180 switch ((GPowerProfileMonitorDBusProperty) prop_id)
181 {
182 case PROP_POWER_SAVER_ENABLED:
183 g_value_set_boolean (value, dbus->power_saver_enabled);
184 break;
185
186 default:
187 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
188 }
189 }
190
191 static gboolean
192 g_power_profile_monitor_dbus_initable_init (GInitable *initable,
193 GCancellable *cancellable,
194 GError **error)
195 {
196 GPowerProfileMonitorDBus *dbus = G_POWER_PROFILE_MONITOR_DBUS (initable);
197
198 dbus->cancellable = g_cancellable_new ();
199 dbus->watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
200 POWERPROFILES_DBUS_NAME,
201 G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
202 ppd_appeared_cb,
203 ppd_vanished_cb,
204 dbus,
205 NULL);
206
207 return TRUE;
208 }
209
210 static void
211 g_power_profile_monitor_dbus_finalize (GObject *object)
212 {
213 GPowerProfileMonitorDBus *dbus = G_POWER_PROFILE_MONITOR_DBUS (object);
214
215 g_cancellable_cancel (dbus->cancellable);
216 g_clear_object (&dbus->cancellable);
217 g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
218 g_clear_object (&dbus->proxy);
219 g_clear_handle_id (&dbus->watch_id, g_bus_unwatch_name);
220
221 G_OBJECT_CLASS (g_power_profile_monitor_dbus_parent_class)->finalize (object);
222 }
223
224 static void
225 g_power_profile_monitor_dbus_class_init (GPowerProfileMonitorDBusClass *nl_class)
226 {
227 GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
228
229 gobject_class->get_property = g_power_profile_monitor_dbus_get_property;
230 gobject_class->finalize = g_power_profile_monitor_dbus_finalize;
231
232 g_object_class_override_property (gobject_class, PROP_POWER_SAVER_ENABLED, "power-saver-enabled");
233 }
234
235 static void
236 g_power_profile_monitor_dbus_iface_init (GPowerProfileMonitorInterface *monitor_iface)
237 {
238 }
239
240 static void
241 g_power_profile_monitor_dbus_initable_iface_init (GInitableIface *iface)
242 {
243 iface->init = g_power_profile_monitor_dbus_initable_init;
244 }