Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-battery-gadget"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <math.h>
9 : :
10 : : #include <gtk/gtk.h>
11 : : #include <glib/gi18n.h>
12 : : #include <valent.h>
13 : :
14 : : #include "valent-battery-gadget.h"
15 : :
16 : :
17 : : struct _ValentBatteryGadget
18 : : {
19 : : ValentDeviceGadget parent_instance;
20 : :
21 : : GtkWidget *button;
22 : : GtkWidget *level_bar;
23 : : GtkWidget *label;
24 : : };
25 : :
26 [ + + + - ]: 20 : G_DEFINE_FINAL_TYPE (ValentBatteryGadget, valent_battery_gadget, VALENT_TYPE_DEVICE_GADGET)
27 : :
28 : :
29 : : static void
30 : 11 : on_action_state_changed (GActionGroup *action_group,
31 : : const char *action_name,
32 : : GVariant *value,
33 : : ValentBatteryGadget *self)
34 : : {
35 : 11 : g_autofree char *label = NULL;
36 : 11 : gboolean charging = FALSE;
37 : 11 : gboolean is_present = FALSE;
38 : 11 : double percentage = 0.0;
39 : 11 : const char *icon_name;
40 : :
41 [ + - ]: 11 : g_assert (VALENT_IS_BATTERY_GADGET (self));
42 : :
43 : 11 : g_variant_lookup (value, "is-present", "b", &is_present);
44 : :
45 [ + + ]: 11 : if (!is_present)
46 : : {
47 : 1 : gtk_widget_set_visible (self->button, FALSE);
48 : 1 : return;
49 : : }
50 : :
51 [ + - - + ]: 20 : if (!g_variant_lookup (value, "percentage", "d", &percentage) ||
52 : 10 : !g_variant_lookup (value, "charging", "b", &charging))
53 : : {
54 : 0 : gtk_widget_set_visible (self->button, FALSE);
55 : 0 : return;
56 : : }
57 : :
58 [ - + ]: 10 : if (!g_variant_lookup (value, "icon-name", "&s", &icon_name))
59 : 0 : icon_name = "battery-missing-symbolic";
60 : :
61 [ + + ]: 10 : if (percentage >= 100.0)
62 : : {
63 : : /* TRANSLATORS: When the battery level is 100% */
64 [ - + ]: 1 : label = g_strdup (_("Fully Charged"));
65 : : }
66 : : else
67 : : {
68 : 9 : int64_t total_seconds = 0;
69 : 9 : int64_t total_minutes;
70 : 9 : int minutes;
71 : 9 : int hours;
72 : :
73 [ + + ]: 9 : if (charging)
74 : 5 : g_variant_lookup (value, "time-to-full", "x", &total_seconds);
75 : : else
76 : 4 : g_variant_lookup (value, "time-to-empty", "x", &total_seconds);
77 : :
78 [ + - ]: 9 : if (total_seconds > 0)
79 : : {
80 : 9 : total_minutes = floor (total_seconds / 60);
81 : 9 : minutes = total_minutes % 60;
82 : 9 : hours = floor (total_minutes / 60);
83 : : }
84 : :
85 [ - + ]: 9 : if (total_seconds <= 0)
86 : : {
87 : : /* TRANSLATORS: This is <percentage> (Estimating…) */
88 : 0 : label = g_strdup_printf (_("%g%% (Estimating…)"), percentage);
89 : : }
90 [ + + ]: 9 : else if (charging)
91 : : {
92 : : /* TRANSLATORS: This is <percentage> (<hours>:<minutes> Until Full) */
93 : 5 : label = g_strdup_printf (_("%g%% (%d∶%02d Until Full)"),
94 : : percentage, hours, minutes);
95 : : }
96 : : else
97 : : {
98 : : /* TRANSLATORS: This is <percentage> (<hours>:<minutes> Remaining) */
99 : 4 : label = g_strdup_printf (_("%g%% (%d∶%02d Remaining)"),
100 : : percentage, hours, minutes);
101 : : }
102 : : }
103 : :
104 : 10 : gtk_menu_button_set_icon_name (GTK_MENU_BUTTON (self->button), icon_name);
105 : :
106 : 10 : gtk_level_bar_set_value (GTK_LEVEL_BAR (self->level_bar), percentage);
107 : 10 : gtk_label_set_text (GTK_LABEL (self->label), label);
108 : :
109 [ + - ]: 10 : if (g_action_group_get_action_enabled (action_group, action_name))
110 : 10 : gtk_widget_set_visible (self->button, TRUE);
111 : : }
112 : :
113 : : static void
114 : 2 : on_action_enabled_changed (GActionGroup *action_group,
115 : : const char *action_name,
116 : : gboolean enabled,
117 : : ValentBatteryGadget *self)
118 : : {
119 : 4 : g_autoptr (GVariant) state = NULL;
120 : :
121 : 2 : gtk_widget_set_visible (self->button, enabled);
122 : :
123 [ + + ]: 2 : if (enabled)
124 : 1 : state = g_action_group_get_action_state (action_group, action_name);
125 : :
126 [ + - ]: 1 : if (state != NULL)
127 : 1 : on_action_state_changed (action_group, action_name, state, self);
128 : 2 : }
129 : :
130 : : /*
131 : : * GObject
132 : : */
133 : : static void
134 : 1 : valent_battery_gadget_constructed (GObject *object)
135 : : {
136 : 1 : ValentBatteryGadget *self = VALENT_BATTERY_GADGET (object);
137 : 1 : GActionGroup *action_group = NULL;
138 : 1 : gboolean enabled = FALSE;
139 : :
140 : 1 : g_object_get (object, "device", &action_group, NULL);
141 : 1 : g_signal_connect_object (action_group,
142 : : "action-state-changed::battery.state",
143 : : G_CALLBACK (on_action_state_changed),
144 : : self, 0);
145 : 1 : g_signal_connect_object (action_group,
146 : : "action-enabled-changed::battery.state",
147 : : G_CALLBACK (on_action_enabled_changed),
148 : : self, 0);
149 : :
150 : 1 : enabled = g_action_group_get_action_enabled (action_group, "battery.state");
151 : 1 : on_action_enabled_changed (action_group, "battery.state", enabled, self);
152 [ + - ]: 1 : g_clear_object (&action_group);
153 : :
154 : 1 : G_OBJECT_CLASS (valent_battery_gadget_parent_class)->constructed (object);
155 : 1 : }
156 : :
157 : : static void
158 : 1 : valent_battery_gadget_dispose (GObject *object)
159 : : {
160 : 1 : ValentBatteryGadget *self = VALENT_BATTERY_GADGET (object);
161 : :
162 [ + - ]: 1 : g_clear_pointer (&self->button, gtk_widget_unparent);
163 : :
164 : 1 : G_OBJECT_CLASS (valent_battery_gadget_parent_class)->dispose (object);
165 : 1 : }
166 : :
167 : : static void
168 : 3 : valent_battery_gadget_class_init (ValentBatteryGadgetClass *klass)
169 : : {
170 : 3 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
171 : :
172 : 3 : object_class->constructed = valent_battery_gadget_constructed;
173 : 3 : object_class->dispose = valent_battery_gadget_dispose;
174 : : }
175 : :
176 : : static void
177 : 1 : valent_battery_gadget_init (ValentBatteryGadget *self)
178 : : {
179 : 1 : GtkWidget *popover;
180 : 1 : GtkWidget *box;
181 : :
182 : : /* Popover */
183 : 1 : popover = g_object_new (GTK_TYPE_POPOVER,
184 : : "autohide", TRUE,
185 : : NULL);
186 : :
187 : 1 : box = g_object_new (GTK_TYPE_BOX,
188 : : "margin-top", 6,
189 : : "margin-bottom", 6,
190 : : "margin-start", 6,
191 : : "margin-end", 6,
192 : : "orientation", GTK_ORIENTATION_VERTICAL,
193 : : "spacing", 6,
194 : : NULL);
195 : 1 : gtk_popover_set_child (GTK_POPOVER (popover), box);
196 : :
197 : 1 : self->label = gtk_label_new (NULL);
198 : 1 : gtk_box_append (GTK_BOX (box), self->label);
199 : :
200 : 1 : self->level_bar = g_object_new (GTK_TYPE_LEVEL_BAR,
201 : : "min-value", 0.0,
202 : : "max-value", 100.0,
203 : : "value", 42.0,
204 : : "width-request", 100,
205 : : "height-request", 3,
206 : : NULL);
207 : 1 : gtk_box_append (GTK_BOX (box), self->level_bar);
208 : :
209 : : /* Button */
210 : 1 : self->button = g_object_new (GTK_TYPE_MENU_BUTTON,
211 : : "icon-name", "battery-missing-symbolic",
212 : : "popover", popover,
213 : : "has-frame", FALSE,
214 : : NULL);
215 : 1 : gtk_widget_set_parent (self->button, GTK_WIDGET (self));
216 : 1 : }
217 : :
|