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