1/*
2 * Copyright (C) 2017 Collabora Ltd.
3 * Copyright (C) 2018 Igalia S.L.
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 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 Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include "config.h"
21#include "LowPowerModeNotifier.h"
22
23#include <cstring>
24#include <gio/gio.h>
25#include <wtf/glib/GUniquePtr.h>
26
27namespace WebCore {
28
29static const char kWarningLevel[] = "WarningLevel";
30
31LowPowerModeNotifier::LowPowerModeNotifier(LowPowerModeChangeCallback&& callback)
32 : m_cancellable(adoptGRef(g_cancellable_new()))
33 , m_callback(WTFMove(callback))
34{
35 g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, static_cast<GDBusProxyFlags>(G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES),
36 nullptr, "org.freedesktop.UPower", "/org/freedesktop/UPower/devices/DisplayDevice", "org.freedesktop.UPower.Device", m_cancellable.get(),
37 [](GObject*, GAsyncResult* result, gpointer userData) {
38 GUniqueOutPtr<GError> error;
39 GRefPtr<GDBusProxy> proxy = adoptGRef(g_dbus_proxy_new_for_bus_finish(result, &error.outPtr()));
40 if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
41 return;
42
43 auto* self = static_cast<LowPowerModeNotifier*>(userData);
44 if (proxy) {
45 GUniquePtr<char> nameOwner(g_dbus_proxy_get_name_owner(proxy.get()));
46 if (nameOwner) {
47 self->m_displayDeviceProxy = WTFMove(proxy);
48 self->updateWarningLevel();
49 g_signal_connect_swapped(self->m_displayDeviceProxy.get(), "g-properties-changed", G_CALLBACK(gPropertiesChangedCallback), self);
50 return;
51 }
52 }
53
54 // Now, if there is no name owner, it would be good to try to
55 // connect to a Flatpak battery status portal instead.
56 // Unfortunately, no such portal currently exists.
57 self->m_cancellable = nullptr;
58 }, this);
59}
60
61void LowPowerModeNotifier::updateWarningLevel()
62{
63 GRefPtr<GVariant> variant = adoptGRef(g_dbus_proxy_get_cached_property(m_displayDeviceProxy.get(), kWarningLevel));
64 if (!variant) {
65 m_lowPowerModeEnabled = false;
66 return;
67 }
68
69 // 0: Unknown
70 // 1: None
71 // 2: Discharging (only for universal power supplies)
72 // 3: Low
73 // 4: Critical
74 // 5: Action
75 m_lowPowerModeEnabled = g_variant_get_uint32(variant.get()) > 1;
76}
77
78void LowPowerModeNotifier::warningLevelChanged()
79{
80 updateWarningLevel();
81 m_callback(m_lowPowerModeEnabled);
82}
83
84void LowPowerModeNotifier::gPropertiesChangedCallback(LowPowerModeNotifier* self, GVariant* changedProperties)
85{
86 GUniqueOutPtr<GVariantIter> iter;
87 g_variant_get(changedProperties, "a{sv}", &iter.outPtr());
88
89 const char* propertyName;
90 while (g_variant_iter_next(iter.get(), "{&sv}", &propertyName, nullptr)) {
91 if (!strcmp(propertyName, kWarningLevel)) {
92 self->warningLevelChanged();
93 break;
94 }
95 }
96}
97
98LowPowerModeNotifier::~LowPowerModeNotifier()
99{
100 g_cancellable_cancel(m_cancellable.get());
101}
102
103bool LowPowerModeNotifier::isLowPowerModeEnabled() const
104{
105 return m_lowPowerModeEnabled;
106}
107
108} // namespace WebCore
109