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