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 : : #include "config.h"
5 : :
6 : : #include <glib/gi18n-lib.h>
7 : : #include <adwaita.h>
8 : : #include <gtk/gtk.h>
9 : : #include <pango/pango.h>
10 : : #include <valent.h>
11 : :
12 : : #include "valent-device-page.h"
13 : : #include "valent-device-preferences-dialog.h"
14 : : #include "valent-menu-list.h"
15 : : #include "valent-menu-stack.h"
16 : :
17 : :
18 : : struct _ValentDevicePage
19 : : {
20 : : AdwNavigationPage parent_instance;
21 : :
22 : : ValentDevice *device;
23 : : GHashTable *plugins;
24 : : AdwDialog *preferences;
25 : :
26 : : /* template */
27 : : GtkStack *stack;
28 : : GtkWidget *gadgets;
29 : : GtkWidget *battery_status;
30 : : GtkWidget *battery_status_label;
31 : : GtkWidget *battery_status_level;
32 : : GtkWidget *connectivity_status;
33 : : GtkWidget *connectivity_status_box;
34 : : AdwStatusPage *pair_page;
35 : : GtkWidget *pair_request;
36 : : GtkSpinner *pair_spinner;
37 : : GtkWidget *verification_key;
38 : :
39 : : ValentMenuStack *menu_actions;
40 : : };
41 : :
42 [ + + + - ]: 45 : G_DEFINE_FINAL_TYPE (ValentDevicePage, valent_device_page, ADW_TYPE_NAVIGATION_PAGE)
43 : :
44 : : typedef enum {
45 : : PROP_DEVICE = 1,
46 : : } ValentDevicePageProperty;
47 : :
48 : : static GParamSpec *properties[PROP_DEVICE + 1] = { NULL, };
49 : :
50 : : /*
51 : : * Pairing
52 : : */
53 : : static void
54 : 6 : on_state_changed (ValentDevice *device,
55 : : GParamSpec *pspec,
56 : : ValentDevicePage *self)
57 : : {
58 : 6 : ValentDeviceState state = VALENT_DEVICE_STATE_NONE;
59 : 6 : gboolean connected, paired;
60 : :
61 [ + - ]: 6 : g_assert (VALENT_IS_DEVICE (device));
62 [ - + ]: 6 : g_assert (VALENT_IS_DEVICE_PAGE (self));
63 : :
64 : 6 : state = valent_device_get_state (self->device);
65 : 6 : connected = (state & VALENT_DEVICE_STATE_CONNECTED) != 0;
66 : 6 : paired = (state & VALENT_DEVICE_STATE_PAIRED) != 0;
67 : :
68 : : /* Ensure the proper controls are displayed */
69 : 6 : gtk_widget_action_set_enabled (GTK_WIDGET (self), "page.pair", !paired);
70 : 6 : gtk_widget_action_set_enabled (GTK_WIDGET (self), "page.unpair", paired);
71 : :
72 [ + - ]: 6 : if (!connected)
73 : : {
74 : 6 : gtk_stack_set_visible_child_name (self->stack, "disconnected");
75 : : }
76 [ # # ]: 0 : else if (!paired)
77 : : {
78 : 0 : g_autofree char *description = NULL;
79 : 0 : g_autofree char *verification_key = NULL;
80 : 0 : gboolean pair_incoming, pair_outgoing;
81 : :
82 : 0 : pair_incoming = (state & VALENT_DEVICE_STATE_PAIR_INCOMING) != 0;
83 : 0 : pair_outgoing = (state & VALENT_DEVICE_STATE_PAIR_OUTGOING) != 0;
84 : :
85 : : /* Get the channel verification key */
86 [ # # ]: 0 : if (pair_incoming || pair_outgoing)
87 : : {
88 : 0 : description = g_strdup_printf (_("Please confirm the verification key "
89 : : "below matches the one on “%s”"),
90 : : valent_device_get_name (self->device));
91 : 0 : verification_key = valent_device_get_verification_key (self->device);
92 : : }
93 : : else
94 : : {
95 : 0 : description = g_strdup_printf (_("Open the app on your “%s” to "
96 : : "request or accept pairing."),
97 : : valent_device_get_name (self->device));
98 : : }
99 : :
100 : 0 : gtk_label_set_text (GTK_LABEL (self->verification_key), verification_key);
101 : 0 : adw_status_page_set_description (self->pair_page, description);
102 : :
103 : : /* Adjust the actions */
104 : 0 : gtk_widget_set_visible (self->pair_request, !pair_incoming);
105 : 0 : gtk_widget_set_sensitive (self->pair_request, !pair_outgoing);
106 : 0 : gtk_spinner_set_spinning (self->pair_spinner, pair_outgoing);
107 : :
108 : 0 : gtk_stack_set_visible_child_name (self->stack, "pairing");
109 : : }
110 : : else
111 : : {
112 : 0 : gtk_stack_set_visible_child_name (self->stack, "connected");
113 : : }
114 : 6 : }
115 : :
116 : : /*
117 : : * Battery
118 : : */
119 : : static void
120 : 0 : on_battery_state_changed (GActionGroup *action_group,
121 : : const char *action_name,
122 : : GVariant *value,
123 : : ValentDevicePage *self)
124 : : {
125 : 0 : g_autofree char *label = NULL;
126 : 0 : gboolean charging = FALSE;
127 : 0 : gboolean is_present = FALSE;
128 : 0 : double percentage = 0.0;
129 : 0 : const char *icon_name;
130 : :
131 [ # # ]: 0 : g_assert (VALENT_IS_DEVICE_PAGE (self));
132 : :
133 : 0 : g_variant_lookup (value, "is-present", "b", &is_present);
134 [ # # ]: 0 : if (!is_present)
135 : : {
136 : 0 : gtk_widget_set_visible (self->battery_status, FALSE);
137 : 0 : return;
138 : : }
139 : :
140 [ # # # # ]: 0 : if (!g_variant_lookup (value, "percentage", "d", &percentage) ||
141 : 0 : !g_variant_lookup (value, "charging", "b", &charging))
142 : : {
143 : 0 : gtk_widget_set_visible (self->battery_status, FALSE);
144 : 0 : return;
145 : : }
146 : :
147 [ # # ]: 0 : if (!g_variant_lookup (value, "icon-name", "&s", &icon_name))
148 : 0 : icon_name = "battery-missing-symbolic";
149 : :
150 [ # # ]: 0 : if (percentage >= 100.0)
151 : : {
152 : : /* TRANSLATORS: When the battery level is 100%
153 : : */
154 [ # # ]: 0 : label = g_strdup (_("Fully Charged"));
155 : : }
156 : : else
157 : : {
158 : 0 : int64_t total_seconds = 0;
159 : 0 : unsigned int total_minutes;
160 : 0 : unsigned int minutes;
161 : 0 : unsigned int hours;
162 : :
163 [ # # ]: 0 : if (charging)
164 : 0 : g_variant_lookup (value, "time-to-full", "x", &total_seconds);
165 : : else
166 : 0 : g_variant_lookup (value, "time-to-empty", "x", &total_seconds);
167 : :
168 [ # # ]: 0 : if (total_seconds > 0)
169 : : {
170 : 0 : total_minutes = (unsigned int)floor (total_seconds / 60);
171 : 0 : minutes = total_minutes % 60;
172 : 0 : hours = (unsigned int)floor (total_minutes / 60);
173 : : }
174 : :
175 [ # # ]: 0 : if (total_seconds <= 0)
176 : : {
177 : : /* TRANSLATORS: This is <percentage> (Estimating…)
178 : : */
179 : 0 : label = g_strdup_printf (_("%g%% (Estimating…)"), percentage);
180 : : }
181 [ # # ]: 0 : else if (charging)
182 : : {
183 : : /* TRANSLATORS: This is <percentage> (<hours>:<minutes> Until Full)
184 : : */
185 : 0 : label = g_strdup_printf (_("%g%% (%d∶%02d Until Full)"),
186 : : percentage, hours, minutes);
187 : : }
188 : : else
189 : : {
190 : : /* TRANSLATORS: This is <percentage> (<hours>:<minutes> Remaining)
191 : : */
192 : 0 : label = g_strdup_printf (_("%g%% (%d∶%02d Remaining)"),
193 : : percentage, hours, minutes);
194 : : }
195 : : }
196 : :
197 [ # # ]: 0 : if (g_action_group_get_action_enabled (action_group, action_name))
198 : : {
199 : 0 : gtk_widget_set_visible (self->battery_status, TRUE);
200 : 0 : gtk_menu_button_set_icon_name (GTK_MENU_BUTTON (self->battery_status),
201 : : icon_name);
202 : :
203 : 0 : gtk_label_set_text (GTK_LABEL (self->battery_status_label), label);
204 : 0 : gtk_level_bar_set_value (GTK_LEVEL_BAR (self->battery_status_level),
205 : : percentage);
206 : : }
207 : : }
208 : :
209 : : static void
210 : 3 : on_battery_enabled_changed (GActionGroup *action_group,
211 : : const char *action_name,
212 : : gboolean enabled,
213 : : ValentDevicePage *self)
214 : : {
215 : 6 : g_autoptr (GVariant) state = NULL;
216 : :
217 : 3 : gtk_widget_set_visible (self->battery_status, enabled);
218 : :
219 [ - + ]: 3 : if (enabled)
220 : 0 : state = g_action_group_get_action_state (action_group, action_name);
221 : :
222 [ # # ]: 0 : if (state != NULL)
223 : 0 : on_battery_state_changed (action_group, action_name, state, self);
224 : 3 : }
225 : :
226 : : /*
227 : : * Connectivity Status
228 : : */
229 : : static void
230 : 0 : on_connectivity_state_changed (GActionGroup *action_group,
231 : : const char *action_name,
232 : : GVariant *value,
233 : : ValentDevicePage *self)
234 : : {
235 : 0 : GtkWidget *child;
236 : 0 : g_autoptr (GVariant) signal_strengths = NULL;
237 : 0 : GVariantIter iter;
238 : 0 : char *signal_id = NULL;
239 : 0 : GVariant *signal_state;
240 : 0 : const char *icon_name;
241 : 0 : const char *title;
242 : :
243 [ # # ]: 0 : g_assert (VALENT_IS_DEVICE_PAGE (self));
244 : :
245 : : /* Clear the popup
246 : : */
247 [ # # ]: 0 : while ((child = gtk_widget_get_first_child (self->connectivity_status_box)) != NULL)
248 : 0 : gtk_box_remove (GTK_BOX (self->connectivity_status_box), child);
249 : :
250 [ # # ]: 0 : if (!g_variant_lookup (value, "signal-strengths", "@a{sv}", &signal_strengths))
251 : : {
252 : 0 : gtk_widget_set_visible (self->connectivity_status, FALSE);
253 [ # # ]: 0 : return;
254 : : }
255 : :
256 : : /* Add each signal
257 : : */
258 : 0 : g_variant_iter_init (&iter, signal_strengths);
259 : :
260 [ # # ]: 0 : while (g_variant_iter_loop (&iter, "{sv}", &signal_id, &signal_state))
261 : : {
262 : 0 : GtkWidget *box;
263 : 0 : GtkWidget *level;
264 : 0 : GtkWidget *icon;
265 : 0 : const char *signal_icon;
266 : 0 : const char *network_type;
267 : 0 : int64_t signal_strength;
268 : :
269 : 0 : box = g_object_new (GTK_TYPE_BOX,
270 : : "spacing", 6,
271 : : NULL);
272 : :
273 : 0 : icon = g_object_new (GTK_TYPE_IMAGE,
274 : : "pixel-size", 16,
275 : : "valign", GTK_ALIGN_CENTER,
276 : : NULL);
277 : 0 : gtk_box_append (GTK_BOX (box), icon);
278 : :
279 : 0 : level = g_object_new (GTK_TYPE_LEVEL_BAR,
280 : : "mode", GTK_LEVEL_BAR_MODE_DISCRETE,
281 : : "min-value", 0.0,
282 : : "max-value", 5.0,
283 : : "value", 0.0,
284 : : "valign", GTK_ALIGN_CENTER,
285 : : "hexpand", TRUE,
286 : : "height-request", 3,
287 : : "width-request", 64,
288 : : NULL);
289 : 0 : gtk_box_append (GTK_BOX (box), level);
290 : :
291 [ # # ]: 0 : if (g_variant_lookup (signal_state, "icon-name", "&s", &signal_icon))
292 : 0 : gtk_image_set_from_icon_name (GTK_IMAGE (icon), signal_icon);
293 : :
294 [ # # ]: 0 : if (g_variant_lookup (signal_state, "network-type", "&s", &network_type))
295 : 0 : gtk_widget_set_tooltip_text (GTK_WIDGET (icon), network_type);
296 : :
297 [ # # ]: 0 : if (g_variant_lookup (signal_state, "signal-strength", "x", &signal_strength))
298 : 0 : gtk_level_bar_set_value (GTK_LEVEL_BAR (level), signal_strength);
299 : :
300 : 0 : gtk_box_append (GTK_BOX (self->connectivity_status_box), box);
301 : : }
302 : :
303 : : /* Add status properties
304 : : */
305 [ # # ]: 0 : if (g_action_group_get_action_enabled (action_group, action_name))
306 : : {
307 : 0 : gtk_widget_set_visible (self->connectivity_status, TRUE);
308 : :
309 [ # # ]: 0 : if (g_variant_lookup (value, "icon-name", "&s", &icon_name))
310 : 0 : gtk_menu_button_set_icon_name (GTK_MENU_BUTTON (self->connectivity_status), icon_name);
311 : :
312 [ # # ]: 0 : if (g_variant_lookup (value, "title", "&s", &title))
313 : 0 : gtk_accessible_update_property (GTK_ACCESSIBLE (self->connectivity_status),
314 : : GTK_ACCESSIBLE_PROPERTY_LABEL, title,
315 : : -1);
316 : : }
317 : : }
318 : :
319 : : static void
320 : 3 : on_connectivity_enabled_changed (GActionGroup *action_group,
321 : : const char *action_name,
322 : : gboolean enabled,
323 : : ValentDevicePage *self)
324 : : {
325 : 6 : g_autoptr (GVariant) state = NULL;
326 : :
327 : : /* gtk_widget_set_visible (self->button, enabled); */
328 : :
329 [ - + ]: 3 : if (enabled)
330 : 0 : state = g_action_group_get_action_state (action_group, action_name);
331 : :
332 [ # # ]: 0 : if (state != NULL)
333 : 0 : on_connectivity_state_changed (action_group, action_name, state, self);
334 : 3 : }
335 : :
336 : : /*
337 : : * GAction
338 : : */
339 : : static void
340 : 2 : page_preferences_action (GtkWidget *widget,
341 : : const char *action_name,
342 : : GVariant *parameter)
343 : : {
344 : 2 : ValentDevicePage *self = VALENT_DEVICE_PAGE (widget);
345 : 2 : GtkRoot *window = gtk_widget_get_root (widget);
346 : :
347 [ + - ]: 2 : if (self->preferences == NULL)
348 : : {
349 : :
350 : :
351 : 2 : self->preferences = g_object_new (VALENT_TYPE_DEVICE_PREFERENCES_DIALOG,
352 : : "device", self->device,
353 : : NULL);
354 : :
355 : 2 : g_object_add_weak_pointer (G_OBJECT (self->preferences),
356 : 2 : (gpointer)&self->preferences);
357 : : }
358 : :
359 : 2 : adw_dialog_present (ADW_DIALOG (self->preferences), GTK_WIDGET (window));
360 : 2 : }
361 : :
362 : : static void
363 : 1 : page_pair_action (GtkWidget *widget,
364 : : const char *action_name,
365 : : GVariant *parameter)
366 : : {
367 : 1 : ValentDevicePage *self = VALENT_DEVICE_PAGE (widget);
368 : :
369 [ + - ]: 1 : g_assert (VALENT_IS_DEVICE (self->device));
370 : :
371 : 1 : g_action_group_activate_action (G_ACTION_GROUP (self->device), "pair", NULL);
372 : 1 : }
373 : :
374 : : static void
375 : 1 : page_unpair_action (GtkWidget *widget,
376 : : const char *action_name,
377 : : GVariant *parameter)
378 : : {
379 : 1 : ValentDevicePage *self = VALENT_DEVICE_PAGE (widget);
380 : :
381 [ + - ]: 1 : g_assert (VALENT_IS_DEVICE (self->device));
382 : :
383 : 1 : g_action_group_activate_action (G_ACTION_GROUP (self->device), "unpair", NULL);
384 : 1 : }
385 : :
386 : : /*
387 : : * GObject
388 : : */
389 : : static void
390 : 3 : valent_device_page_constructed (GObject *object)
391 : : {
392 : 3 : ValentDevicePage *self = VALENT_DEVICE_PAGE (object);
393 : 3 : GActionGroup *action_group = G_ACTION_GROUP (self->device);
394 : 3 : GMenuModel *menu;
395 : 3 : gboolean enabled;
396 : :
397 : 3 : G_OBJECT_CLASS (valent_device_page_parent_class)->constructed (object);
398 : :
399 : 3 : g_object_bind_property (self->device, "id",
400 : : self, "tag",
401 : : G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
402 : 3 : g_object_bind_property (self->device, "name",
403 : : self, "title",
404 : : G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
405 : :
406 : : /* Actions & Menu
407 : : */
408 : 3 : gtk_widget_insert_action_group (GTK_WIDGET (self), "device", action_group);
409 : 3 : menu = valent_device_get_menu (self->device);
410 : 3 : valent_menu_stack_set_menu_model (self->menu_actions, menu);
411 : :
412 : : /* Pair Section
413 : : */
414 : 3 : g_signal_connect_object (self->device,
415 : : "notify::state",
416 : : G_CALLBACK (on_state_changed),
417 : : self,
418 : : G_CONNECT_DEFAULT);
419 : 3 : on_state_changed (self->device, NULL, self);
420 : :
421 : : /*
422 : : * Battery Status
423 : : */
424 : 3 : g_signal_connect_object (action_group,
425 : : "action-state-changed::battery.state",
426 : : G_CALLBACK (on_battery_state_changed),
427 : : self,
428 : : G_CONNECT_DEFAULT);
429 : 3 : g_signal_connect_object (action_group,
430 : : "action-enabled-changed::battery.state",
431 : : G_CALLBACK (on_battery_enabled_changed),
432 : : self,
433 : : G_CONNECT_DEFAULT);
434 : :
435 : 3 : enabled = g_action_group_get_action_enabled (action_group, "battery.state");
436 : 3 : on_battery_enabled_changed (action_group, "battery.state", enabled, self);
437 : :
438 : : /*
439 : : * Connectivity Status
440 : : */
441 : 3 : g_signal_connect_object (action_group,
442 : : "action-state-changed::connectivity_report.state",
443 : : G_CALLBACK (on_connectivity_state_changed),
444 : : self, 0);
445 : :
446 : 3 : g_signal_connect_object (action_group,
447 : : "action-enabled-changed::connectivity_report.state",
448 : : G_CALLBACK (on_connectivity_enabled_changed),
449 : : self,
450 : : G_CONNECT_DEFAULT);
451 : :
452 : 3 : enabled = g_action_group_get_action_enabled (action_group, "connectivity_report.state");
453 : 3 : on_connectivity_enabled_changed (action_group, "connectivity_report.state", enabled, self);
454 : 3 : }
455 : :
456 : : static void
457 : 3 : valent_device_page_dispose (GObject *object)
458 : : {
459 : 3 : ValentDevicePage *self = VALENT_DEVICE_PAGE (object);
460 : :
461 [ + - ]: 3 : g_clear_object (&self->device);
462 [ - + ]: 3 : g_clear_pointer (&self->preferences, adw_dialog_force_close);
463 : :
464 : 3 : gtk_widget_dispose_template (GTK_WIDGET (object), VALENT_TYPE_DEVICE_PAGE);
465 : :
466 : 3 : G_OBJECT_CLASS (valent_device_page_parent_class)->dispose (object);
467 : 3 : }
468 : :
469 : : static void
470 : 1 : valent_device_page_get_property (GObject *object,
471 : : guint prop_id,
472 : : GValue *value,
473 : : GParamSpec *pspec)
474 : : {
475 : 1 : ValentDevicePage *self = VALENT_DEVICE_PAGE (object);
476 : :
477 [ + - ]: 1 : switch ((ValentDevicePageProperty)prop_id)
478 : : {
479 : 1 : case PROP_DEVICE:
480 : 1 : g_value_set_object (value, self->device);
481 : 1 : break;
482 : :
483 : 0 : default:
484 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
485 : : }
486 : 1 : }
487 : :
488 : : static void
489 : 3 : valent_device_page_set_property (GObject *object,
490 : : guint prop_id,
491 : : const GValue *value,
492 : : GParamSpec *pspec)
493 : : {
494 : 3 : ValentDevicePage *self = VALENT_DEVICE_PAGE (object);
495 : :
496 [ + - ]: 3 : switch ((ValentDevicePageProperty)prop_id)
497 : : {
498 : 3 : case PROP_DEVICE:
499 : 3 : self->device = g_value_dup_object (value);
500 : 3 : break;
501 : :
502 : 0 : default:
503 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
504 : : }
505 : 3 : }
506 : :
507 : : static void
508 : 2 : valent_device_page_class_init (ValentDevicePageClass *klass)
509 : : {
510 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
511 : 2 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
512 : :
513 : 2 : object_class->constructed = valent_device_page_constructed;
514 : 2 : object_class->dispose = valent_device_page_dispose;
515 : 2 : object_class->get_property = valent_device_page_get_property;
516 : 2 : object_class->set_property = valent_device_page_set_property;
517 : :
518 : : /* template */
519 : 2 : gtk_widget_class_set_template_from_resource (widget_class, "/plugins/gnome/valent-device-page.ui");
520 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, gadgets);
521 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, battery_status);
522 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, battery_status_label);
523 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, battery_status_level);
524 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, connectivity_status);
525 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, connectivity_status_box);
526 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, stack);
527 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, pair_page);
528 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, pair_request);
529 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, pair_spinner);
530 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, verification_key);
531 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePage, menu_actions);
532 : :
533 : 2 : gtk_widget_class_install_action (widget_class, "page.preferences", NULL, page_preferences_action);
534 : 2 : gtk_widget_class_install_action (widget_class, "page.pair", NULL, page_pair_action);
535 : 2 : gtk_widget_class_install_action (widget_class, "page.unpair", NULL, page_unpair_action);
536 : :
537 : : /**
538 : : * ValentDevicePage:device:
539 : : *
540 : : * The device this panel controls and represents.
541 : : */
542 : 4 : properties [PROP_DEVICE] =
543 : 2 : g_param_spec_object ("device", NULL, NULL,
544 : : VALENT_TYPE_DEVICE,
545 : : (G_PARAM_READWRITE |
546 : : G_PARAM_CONSTRUCT_ONLY |
547 : : G_PARAM_EXPLICIT_NOTIFY |
548 : : G_PARAM_STATIC_STRINGS));
549 : :
550 : 2 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
551 : :
552 : : /* Ensure the private types we need are ready */
553 : 2 : g_type_ensure (VALENT_TYPE_MENU_LIST);
554 : 2 : g_type_ensure (VALENT_TYPE_MENU_STACK);
555 : 2 : }
556 : :
557 : : static void
558 : 3 : valent_device_page_init (ValentDevicePage *self)
559 : : {
560 : 3 : gtk_widget_init_template (GTK_WIDGET (self));
561 : 3 : }
562 : :
|