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-device-preferences-dialog"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <glib/gi18n-lib.h>
9 : : #include <adwaita.h>
10 : : #include <gtk/gtk.h>
11 : : #include <valent.h>
12 : :
13 : : #include "valent-device-preferences-battery.h"
14 : : #include "valent-device-preferences-clipboard.h"
15 : : #include "valent-device-preferences-commands.h"
16 : : #include "valent-device-preferences-connectivity.h"
17 : : #include "valent-device-preferences-contacts.h"
18 : : #include "valent-device-preferences-notification.h"
19 : : #include "valent-device-preferences-sftp.h"
20 : : #include "valent-device-preferences-share.h"
21 : : #include "valent-device-preferences-telephony.h"
22 : : #include "valent-device-preferences-group.h"
23 : : #include "valent-plugin-row.h"
24 : :
25 : : #include "valent-device-preferences-dialog.h"
26 : :
27 : :
28 : : struct _ValentDevicePreferencesDialog
29 : : {
30 : : AdwPreferencesDialog parent_instance;
31 : :
32 : : ValentDevice *device;
33 : : GHashTable *plugins;
34 : :
35 : : /* template */
36 : : AdwPreferencesPage *status_page;
37 : : AdwPreferencesPage *sync_page;
38 : : AdwPreferencesPage *other_page;
39 : : AdwPreferencesPage *plugin_page;
40 : : GtkListBox *plugin_list;
41 : : };
42 : :
43 [ + + + - ]: 54 : G_DEFINE_FINAL_TYPE (ValentDevicePreferencesDialog, valent_device_preferences_dialog, ADW_TYPE_PREFERENCES_DIALOG)
44 : :
45 : : enum {
46 : : PROP_0,
47 : : PROP_DEVICE,
48 : : N_PROPERTIES
49 : : };
50 : :
51 : : static GParamSpec *properties[N_PROPERTIES] = { NULL, };
52 : :
53 : :
54 : : static int
55 : 3 : plugin_list_sort (GtkListBoxRow *row1,
56 : : GtkListBoxRow *row2,
57 : : gpointer user_data)
58 : : {
59 [ + - - + ]: 3 : if G_UNLIKELY (!ADW_IS_PREFERENCES_ROW (row1) ||
60 : : !ADW_IS_PREFERENCES_ROW (row2))
61 : 0 : return 0;
62 : :
63 : 3 : return g_utf8_collate (adw_preferences_row_get_title ((AdwPreferencesRow *)row1),
64 : 3 : adw_preferences_row_get_title ((AdwPreferencesRow *)row2));
65 : : }
66 : :
67 : : /*
68 : : * Plugin Callbacks
69 : : */
70 : : typedef struct
71 : : {
72 : : AdwPreferencesDialog *window;
73 : : AdwPreferencesPage *page;
74 : : AdwPreferencesGroup *group;
75 : : GtkWidget *row;
76 : : } PluginData;
77 : :
78 : : static void
79 : 6 : plugin_data_free (gpointer data)
80 : : {
81 : 6 : PluginData *plugin = (PluginData *)data;
82 : 6 : ValentDevicePreferencesDialog *self = VALENT_DEVICE_PREFERENCES_DIALOG (plugin->window);
83 : :
84 [ + - ]: 6 : g_assert (VALENT_IS_DEVICE_PREFERENCES_DIALOG (self));
85 : :
86 [ - + - - ]: 6 : if (plugin->page != NULL && plugin->group != NULL)
87 : 0 : adw_preferences_page_remove (plugin->page, plugin->group);
88 : :
89 [ + - ]: 6 : if (plugin->row != NULL)
90 : 6 : gtk_list_box_remove (self->plugin_list, plugin->row);
91 : :
92 : 6 : g_free (plugin);
93 : 6 : }
94 : :
95 : : static void
96 : 6 : valent_device_preferences_dialog_add_plugin (ValentDevicePreferencesDialog *self,
97 : : const char *module)
98 : : {
99 : 6 : ValentContext *context = NULL;
100 : 12 : g_autoptr (ValentContext) plugin_context = NULL;
101 : 6 : PeasEngine *engine;
102 : 6 : PeasPluginInfo *info;
103 : 6 : PluginData *plugin;
104 : 6 : const char *title;
105 : 6 : const char *subtitle;
106 : :
107 [ + - ]: 6 : g_assert (VALENT_IS_DEVICE_PREFERENCES_DIALOG (self));
108 [ + - - + ]: 6 : g_assert (module != NULL && *module != '\0');
109 : :
110 : 6 : engine = valent_get_plugin_engine ();
111 : 6 : info = peas_engine_get_plugin_info (engine, module);
112 : 6 : plugin = g_new0 (PluginData, 1);
113 : 6 : plugin->window = ADW_PREFERENCES_DIALOG (self);
114 : :
115 : 6 : title = peas_plugin_info_get_name (info);
116 : 6 : subtitle = peas_plugin_info_get_description (info);
117 : :
118 : : /* Plugin Row
119 : : */
120 : 6 : context = valent_device_get_context (self->device);
121 : 6 : plugin_context = valent_context_get_plugin_context (context, info);
122 : :
123 : 6 : plugin->row = g_object_new (VALENT_TYPE_PLUGIN_ROW,
124 : : "context", plugin_context,
125 : : "plugin-info", info,
126 : : "title", title,
127 : : "subtitle", subtitle,
128 : : NULL);
129 : 6 : gtk_list_box_insert (self->plugin_list, plugin->row, -1);
130 : :
131 : : /* Preferences Page
132 : : */
133 : 6 : struct
134 : : {
135 : : const char *name;
136 : : const char *category;
137 : : GType type;
138 : 60 : } preferences[] = {
139 : : {
140 : : .name = "battery",
141 : : .category = "status",
142 : 6 : .type = VALENT_TYPE_BATTERY_PREFERENCES,
143 : : },
144 : : {
145 : : .name = "connectivity_report",
146 : : .category = "status",
147 : 6 : .type = VALENT_TYPE_CONNECTIVITY_REPORT_PREFERENCES,
148 : : },
149 : : {
150 : : .name = "telephony",
151 : : .category = "status",
152 : 6 : .type = VALENT_TYPE_TELEPHONY_PREFERENCES,
153 : : },
154 : :
155 : : {
156 : : .name = "clipboard",
157 : : .category = "sync",
158 : 6 : .type = VALENT_TYPE_CLIPBOARD_PREFERENCES,
159 : : },
160 : : {
161 : : .name = "contacts",
162 : : .category = "sync",
163 : 6 : .type = VALENT_TYPE_CONTACTS_PREFERENCES,
164 : : },
165 : : {
166 : : .name = "notification",
167 : : .category = "sync",
168 : 6 : .type = VALENT_TYPE_NOTIFICATION_PREFERENCES,
169 : : },
170 : : {
171 : : .name = "sftp",
172 : : .category = "sync",
173 : 6 : .type = VALENT_TYPE_SFTP_PREFERENCES,
174 : : },
175 : :
176 : : {
177 : : .name = "runcommand",
178 : : .category = "other",
179 : 6 : .type = VALENT_TYPE_RUNCOMMAND_PREFERENCES,
180 : : },
181 : : {
182 : : .name = "share",
183 : : .category = "other",
184 : 6 : .type = VALENT_TYPE_SHARE_PREFERENCES,
185 : : },
186 : : };
187 : :
188 [ + + ]: 60 : for (size_t i = 0; i < G_N_ELEMENTS (preferences); i++)
189 : : {
190 [ - + ]: 54 : if (g_str_equal (preferences[i].name, module))
191 : : {
192 : 0 : plugin->group = g_object_new (preferences[i].type,
193 : : "context", plugin_context,
194 : : "plugin-info", info,
195 : : "name", module,
196 : : "title", title,
197 : : "description", subtitle,
198 : : NULL);
199 : :
200 [ # # ]: 0 : if (g_str_equal (preferences[i].category, "status"))
201 : 0 : plugin->page = self->status_page;
202 [ # # ]: 0 : else if (g_str_equal (preferences[i].category, "sync"))
203 : 0 : plugin->page = self->sync_page;
204 : : else
205 : 0 : plugin->page = self->other_page;
206 : :
207 : 0 : adw_preferences_page_add (plugin->page, plugin->group);
208 : 0 : break;
209 : : }
210 : : }
211 : :
212 [ - + + - ]: 12 : g_hash_table_replace (self->plugins,
213 : 6 : g_strdup (module),
214 : : g_steal_pointer (&plugin));
215 : 6 : }
216 : :
217 : : static int
218 : 3 : plugin_sort (gconstpointer a,
219 : : gconstpointer b)
220 : : {
221 : 3 : const char *a_ = *(char **)a;
222 : 3 : const char *b_ = *(char **)b;
223 : :
224 : 3 : return strcmp (a_, b_);
225 : : }
226 : :
227 : : static void
228 : 6 : on_plugins_changed (ValentDevice *device,
229 : : GParamSpec *pspec,
230 : : ValentDevicePreferencesDialog *self)
231 : : {
232 : 12 : g_auto (GStrv) plugins = NULL;
233 : 6 : GHashTableIter iter;
234 : 6 : const char *module;
235 : :
236 : 6 : plugins = valent_device_get_plugins (device);
237 : 6 : qsort (plugins, g_strv_length (plugins), sizeof (char *), plugin_sort);
238 : :
239 : : /* Remove */
240 : 6 : g_hash_table_iter_init (&iter, self->plugins);
241 : :
242 [ + + ]: 17 : while (g_hash_table_iter_next (&iter, (void **)&module, NULL))
243 : : {
244 [ + + ]: 5 : if (!g_strv_contains ((const char * const *)plugins, module))
245 : 2 : g_hash_table_iter_remove (&iter);
246 : : }
247 : :
248 [ + + ]: 15 : for (unsigned int i = 0; plugins[i] != NULL; i++)
249 : : {
250 [ + + ]: 9 : if (!g_hash_table_contains (self->plugins, plugins[i]))
251 : 6 : valent_device_preferences_dialog_add_plugin (self, plugins[i]);
252 : : }
253 : 6 : }
254 : :
255 : : /*
256 : : * GObject
257 : : */
258 : : static void
259 : 3 : valent_device_preferences_dialog_constructed (GObject *object)
260 : : {
261 : 3 : ValentDevicePreferencesDialog *self = VALENT_DEVICE_PREFERENCES_DIALOG (object);
262 : :
263 : : /* Device */
264 : 3 : g_object_bind_property (self->device, "name",
265 : : self, "title",
266 : : G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
267 : :
268 : 3 : gtk_widget_insert_action_group (GTK_WIDGET (self),
269 : : "device",
270 : 3 : G_ACTION_GROUP (self->device));
271 : :
272 : : /* Device_plugins */
273 : 3 : g_signal_connect_object (self->device,
274 : : "notify::plugins",
275 : : G_CALLBACK (on_plugins_changed),
276 : : self, 0);
277 : 3 : on_plugins_changed (self->device, NULL, self);
278 : :
279 : 3 : G_OBJECT_CLASS (valent_device_preferences_dialog_parent_class)->constructed (object);
280 : 3 : }
281 : :
282 : : static void
283 : 3 : valent_device_preferences_dialog_dispose (GObject *object)
284 : : {
285 : 3 : ValentDevicePreferencesDialog *self = VALENT_DEVICE_PREFERENCES_DIALOG (object);
286 : :
287 [ + - ]: 3 : g_clear_object (&self->device);
288 [ + - ]: 3 : g_clear_pointer (&self->plugins, g_hash_table_unref);
289 : :
290 : 3 : gtk_widget_dispose_template (GTK_WIDGET (object),
291 : : VALENT_TYPE_DEVICE_PREFERENCES_DIALOG);
292 : :
293 : 3 : G_OBJECT_CLASS (valent_device_preferences_dialog_parent_class)->dispose (object);
294 : 3 : }
295 : :
296 : : static void
297 : 1 : valent_device_preferences_dialog_get_property (GObject *object,
298 : : guint prop_id,
299 : : GValue *value,
300 : : GParamSpec *pspec)
301 : : {
302 : 1 : ValentDevicePreferencesDialog *self = VALENT_DEVICE_PREFERENCES_DIALOG (object);
303 : :
304 [ + - ]: 1 : switch (prop_id)
305 : : {
306 : 1 : case PROP_DEVICE:
307 : 1 : g_value_set_object (value, self->device);
308 : 1 : break;
309 : :
310 : 0 : default:
311 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
312 : : }
313 : 1 : }
314 : :
315 : : static void
316 : 3 : valent_device_preferences_dialog_set_property (GObject *object,
317 : : guint prop_id,
318 : : const GValue *value,
319 : : GParamSpec *pspec)
320 : : {
321 : 3 : ValentDevicePreferencesDialog *self = VALENT_DEVICE_PREFERENCES_DIALOG (object);
322 : :
323 [ + - ]: 3 : switch (prop_id)
324 : : {
325 : 3 : case PROP_DEVICE:
326 : 3 : self->device = g_value_dup_object (value);
327 : 3 : break;
328 : :
329 : 0 : default:
330 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
331 : : }
332 : 3 : }
333 : :
334 : : static void
335 : 2 : valent_device_preferences_dialog_class_init (ValentDevicePreferencesDialogClass *klass)
336 : : {
337 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
338 : 2 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
339 : :
340 : 2 : object_class->constructed = valent_device_preferences_dialog_constructed;
341 : 2 : object_class->dispose = valent_device_preferences_dialog_dispose;
342 : 2 : object_class->get_property = valent_device_preferences_dialog_get_property;
343 : 2 : object_class->set_property = valent_device_preferences_dialog_set_property;
344 : :
345 : 2 : gtk_widget_class_set_template_from_resource (widget_class, "/plugins/gnome/valent-device-preferences-dialog.ui");
346 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePreferencesDialog, status_page);
347 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePreferencesDialog, sync_page);
348 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePreferencesDialog, other_page);
349 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePreferencesDialog, plugin_page);
350 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentDevicePreferencesDialog, plugin_list);
351 : :
352 : : /**
353 : : * ValentDevicePreferencesDialog:device:
354 : : *
355 : : * The device this panel controls and represents.
356 : : */
357 : 4 : properties [PROP_DEVICE] =
358 : 2 : g_param_spec_object ("device", NULL, NULL,
359 : : VALENT_TYPE_DEVICE,
360 : : (G_PARAM_READWRITE |
361 : : G_PARAM_CONSTRUCT_ONLY |
362 : : G_PARAM_EXPLICIT_NOTIFY |
363 : : G_PARAM_STATIC_STRINGS));
364 : :
365 : 2 : g_object_class_install_properties (object_class, N_PROPERTIES, properties);
366 : 2 : }
367 : :
368 : : static void
369 : 3 : valent_device_preferences_dialog_init (ValentDevicePreferencesDialog *self)
370 : : {
371 : 3 : gtk_widget_init_template (GTK_WIDGET (self));
372 : :
373 : 3 : gtk_list_box_set_sort_func (self->plugin_list, plugin_list_sort, NULL, NULL);
374 : 3 : self->plugins = g_hash_table_new_full (g_str_hash,
375 : : g_str_equal,
376 : : g_free,
377 : : plugin_data_free);
378 : 3 : }
379 : :
|