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-runcommand-preferences"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <glib/gi18n.h>
9 : : #include <adwaita.h>
10 : : #include <gtk/gtk.h>
11 : : #include <libportal/portal.h>
12 : : #include <valent.h>
13 : :
14 : : #include "valent-device-preferences-commands-editor.h"
15 : :
16 : : #include "valent-device-preferences-commands.h"
17 : :
18 : :
19 : : struct _ValentRuncommandPreferences
20 : : {
21 : : ValentDevicePreferencesGroup parent_instance;
22 : :
23 : : GtkWindow *editor;
24 : :
25 : : /* template */
26 : : AdwExpanderRow *command_list_row;
27 : : GtkListBox *command_list;
28 : : };
29 : :
30 [ + + + - ]: 44 : G_DEFINE_FINAL_TYPE (ValentRuncommandPreferences, valent_runcommand_preferences, VALENT_TYPE_DEVICE_PREFERENCES_GROUP)
31 : :
32 : :
33 : : /*
34 : : * Rows
35 : : */
36 : : static void
37 : 1 : valent_runcommand_preferences_populate (ValentRuncommandPreferences *self)
38 : : {
39 : 1 : ValentDevicePreferencesGroup *group = VALENT_DEVICE_PREFERENCES_GROUP (self);
40 : 1 : GSettings *settings;
41 : 1 : GtkWidget *child;
42 : 2 : g_autoptr (GVariant) commands = NULL;
43 : 1 : GVariantIter iter;
44 : 1 : char *uuid;
45 : 1 : GVariant *item;
46 : :
47 [ + - ]: 1 : g_assert (VALENT_IS_RUNCOMMAND_PREFERENCES (self));
48 : :
49 : 1 : for (child = gtk_widget_get_first_child (GTK_WIDGET (self->command_list));
50 [ - + ]: 1 : child != NULL;)
51 : : {
52 : 0 : GtkWidget *current_child = child;
53 : 0 : child = gtk_widget_get_next_sibling (current_child);
54 : 0 : gtk_list_box_remove (self->command_list, current_child);
55 : : }
56 : :
57 : 1 : settings = valent_device_preferences_group_get_settings (group);
58 : 1 : commands = g_settings_get_value (settings, "commands");
59 : :
60 : 1 : g_variant_iter_init (&iter, commands);
61 : :
62 [ - + ]: 1 : while (g_variant_iter_next (&iter, "{sv}", &uuid, &item))
63 : : {
64 : 0 : const char *name = NULL;
65 : 0 : const char *command = NULL;
66 : :
67 [ # # # # ]: 0 : if (g_variant_lookup (item, "name", "&s", &name) &&
68 : 0 : g_variant_lookup (item, "command", "&s", &command))
69 : : {
70 : 0 : GtkWidget *row;
71 : 0 : GtkWidget *icon;
72 : :
73 : 0 : row = g_object_new (ADW_TYPE_ACTION_ROW,
74 : : "name", uuid,
75 : : "title", name,
76 : : "subtitle", command,
77 : : "activatable", TRUE,
78 : : "selectable", FALSE,
79 : : "action-target", g_variant_new_string (uuid),
80 : : "action-name", "runcommand.edit",
81 : : NULL);
82 : :
83 : 0 : icon = g_object_new (GTK_TYPE_IMAGE,
84 : : "icon-name", "document-edit-symbolic",
85 : : "tooltip-text", _("Edit Command"),
86 : : NULL);
87 : 0 : gtk_widget_add_css_class (icon, "dim-label");
88 : 0 : adw_action_row_add_suffix (ADW_ACTION_ROW (row), icon);
89 : :
90 : : /* a11y: an activatable widget would change the label and description,
91 : : * but a button is unnecessary and the label should be unchanged. */
92 : 0 : gtk_accessible_update_relation (GTK_ACCESSIBLE (row),
93 : : GTK_ACCESSIBLE_RELATION_DESCRIBED_BY,
94 : : icon, NULL,
95 : : -1);
96 : :
97 : 0 : gtk_list_box_append (self->command_list, row);
98 : : }
99 : :
100 [ # # ]: 0 : g_clear_pointer (&uuid, g_free);
101 [ # # ]: 0 : g_clear_pointer (&item, g_variant_unref);
102 : : }
103 : 1 : }
104 : :
105 : : static int
106 : 0 : sort_commands (GtkListBoxRow *row1,
107 : : GtkListBoxRow *row2,
108 : : gpointer user_data)
109 : : {
110 : 0 : const char *title1;
111 : 0 : const char *title2;
112 : :
113 : 0 : title1 = adw_preferences_row_get_title (ADW_PREFERENCES_ROW (row1));
114 : 0 : title2 = adw_preferences_row_get_title (ADW_PREFERENCES_ROW (row2));
115 : :
116 : 0 : return g_utf8_collate (title1, title2);
117 : : }
118 : :
119 : : static inline GtkListBox *
120 : 1 : _adw_expander_row_get_list (AdwExpanderRow *row)
121 : : {
122 : 1 : GtkWidget *box;
123 : 1 : GtkWidget *child;
124 : :
125 : : /* First child is a GtkBox */
126 : 1 : box = gtk_widget_get_first_child (GTK_WIDGET (row));
127 : :
128 : : /* The GtkBox contains the primary AdwActionRow and a GtkRevealer */
129 : 1 : for (child = gtk_widget_get_first_child (box);
130 [ + - ]: 2 : child != NULL;
131 : 1 : child = gtk_widget_get_next_sibling (child))
132 : : {
133 [ + - + + : 2 : if (GTK_IS_REVEALER (child))
+ - ]
134 : : break;
135 : : }
136 : :
137 : : /* The GtkRevealer's child is the GtkListBox */
138 [ + - + - : 1 : if (GTK_IS_REVEALER (child))
- + - - ]
139 : 1 : return GTK_LIST_BOX (gtk_revealer_get_child (GTK_REVEALER (child)));
140 : :
141 : : return NULL;
142 : : }
143 : :
144 : : /*
145 : : * GAction
146 : : */
147 : : static void
148 : 0 : on_command_changed (ValentRuncommandEditor *editor,
149 : : GParamSpec *pspec,
150 : : ValentRuncommandPreferences *self)
151 : : {
152 : 0 : const char *uuid;
153 : 0 : GVariant *command;
154 : :
155 [ # # ]: 0 : g_assert (VALENT_IS_RUNCOMMAND_EDITOR (editor));
156 [ # # ]: 0 : g_assert (VALENT_IS_RUNCOMMAND_PREFERENCES (self));
157 : :
158 : 0 : uuid = valent_runcommand_editor_get_uuid (editor);
159 : 0 : command = valent_runcommand_editor_get_command (editor);
160 : :
161 [ # # ]: 0 : if (command != NULL)
162 : 0 : gtk_widget_activate_action (GTK_WIDGET (self), "runcommand.save", "s", uuid);
163 : : else
164 : 0 : gtk_widget_activate_action (GTK_WIDGET (self), "runcommand.remove", "s", uuid);
165 : :
166 : 0 : gtk_window_destroy (GTK_WINDOW (editor));
167 : 0 : }
168 : :
169 : : static void
170 : 0 : runcommand_add_action (GtkWidget *widget,
171 : : const char *action_name,
172 : : GVariant *parameter)
173 : : {
174 : 0 : g_autofree char *uuid = NULL;
175 : :
176 [ # # ]: 0 : g_assert (VALENT_IS_RUNCOMMAND_PREFERENCES (widget));
177 : :
178 : 0 : uuid = g_uuid_string_random ();
179 : 0 : gtk_widget_activate_action (widget, "runcommand.edit", "s", uuid);
180 : 0 : }
181 : :
182 : : static void
183 : 0 : runcommand_edit_action (GtkWidget *widget,
184 : : const char *action_name,
185 : : GVariant *parameter)
186 : : {
187 : 0 : ValentRuncommandPreferences *self = VALENT_RUNCOMMAND_PREFERENCES (widget);
188 : 0 : ValentDevicePreferencesGroup *group = VALENT_DEVICE_PREFERENCES_GROUP (self);
189 : 0 : const char *uuid = NULL;
190 : 0 : GSettings *settings;
191 : 0 : GtkRoot *window;
192 : 0 : g_autoptr (GVariant) commands = NULL;
193 [ # # ]: 0 : g_autoptr (GVariant) command = NULL;
194 : :
195 [ # # ]: 0 : g_assert (VALENT_IS_RUNCOMMAND_PREFERENCES (self));
196 : :
197 : 0 : uuid = g_variant_get_string (parameter, NULL);
198 : 0 : settings = valent_device_preferences_group_get_settings (group);
199 : 0 : commands = g_settings_get_value (settings, "commands");
200 : 0 : g_variant_lookup (commands, uuid, "@a{sv}", &command);
201 : :
202 : 0 : window = gtk_widget_get_root (GTK_WIDGET (self));
203 : 0 : self->editor = g_object_new (VALENT_TYPE_RUNCOMMAND_EDITOR,
204 : : "uuid", uuid,
205 : : "command", command,
206 : : "modal", (window != NULL),
207 : : "transient-for", window,
208 : : NULL);
209 : 0 : g_object_add_weak_pointer (G_OBJECT (self->editor),
210 : 0 : (gpointer) &self->editor);
211 : 0 : g_signal_connect_object (self->editor,
212 : : "notify::command",
213 : : G_CALLBACK (on_command_changed),
214 : : self, 0);
215 : :
216 [ # # ]: 0 : gtk_window_present (self->editor);
217 : 0 : }
218 : :
219 : : static void
220 : 0 : runcommand_save_action (GtkWidget *widget,
221 : : const char *action_name,
222 : : GVariant *parameter)
223 : : {
224 : 0 : ValentRuncommandPreferences *self = VALENT_RUNCOMMAND_PREFERENCES (widget);
225 : 0 : ValentDevicePreferencesGroup *group = VALENT_DEVICE_PREFERENCES_GROUP (self);
226 : 0 : GSettings *settings;
227 : 0 : g_autoptr (GVariant) commands = NULL;
228 : 0 : GVariant *command;
229 : 0 : const char *uuid;
230 : 0 : GVariantDict dict;
231 : 0 : GVariant *value;
232 : :
233 [ # # ]: 0 : g_assert (VALENT_IS_RUNCOMMAND_PREFERENCES (self));
234 : :
235 : 0 : settings = valent_device_preferences_group_get_settings (group);
236 : 0 : commands = g_settings_get_value (settings, "commands");
237 : :
238 : 0 : uuid = valent_runcommand_editor_get_uuid (VALENT_RUNCOMMAND_EDITOR (self->editor));
239 : 0 : command = valent_runcommand_editor_get_command (VALENT_RUNCOMMAND_EDITOR (self->editor));
240 : :
241 : 0 : g_variant_dict_init (&dict, commands);
242 : 0 : g_variant_dict_insert_value (&dict, uuid, command);
243 : 0 : value = g_variant_dict_end (&dict);
244 : :
245 [ # # ]: 0 : g_settings_set_value (settings, "commands", value);
246 : 0 : }
247 : :
248 : : static void
249 : 0 : runcommand_remove_action (GtkWidget *widget,
250 : : const char *action_name,
251 : : GVariant *parameter)
252 : : {
253 : 0 : ValentRuncommandPreferences *self = VALENT_RUNCOMMAND_PREFERENCES (widget);
254 : 0 : ValentDevicePreferencesGroup *group = VALENT_DEVICE_PREFERENCES_GROUP (self);
255 : 0 : GSettings *settings;
256 : 0 : g_autoptr (GVariant) commands = NULL;
257 : 0 : GVariantDict dict;
258 : 0 : GVariant *value;
259 : 0 : const char *uuid = NULL;
260 : :
261 [ # # ]: 0 : g_assert (VALENT_IS_RUNCOMMAND_PREFERENCES (self));
262 : :
263 : 0 : uuid = g_variant_get_string (parameter, NULL);
264 : 0 : settings = valent_device_preferences_group_get_settings (group);
265 : 0 : commands = g_settings_get_value (settings, "commands");
266 : :
267 : 0 : g_variant_dict_init (&dict, commands);
268 : 0 : g_variant_dict_remove (&dict, uuid);
269 : 0 : value = g_variant_dict_end (&dict);
270 : :
271 [ # # ]: 0 : g_settings_set_value (settings, "commands", value);
272 : 0 : }
273 : :
274 : : /*
275 : : * GObject
276 : : */
277 : : static void
278 : 1 : valent_runcommand_preferences_constructed (GObject *object)
279 : : {
280 : 1 : ValentRuncommandPreferences *self = VALENT_RUNCOMMAND_PREFERENCES (object);
281 : 1 : ValentDevicePreferencesGroup *group = VALENT_DEVICE_PREFERENCES_GROUP (self);
282 : 1 : GSettings *settings;
283 : :
284 : 1 : gtk_list_box_set_sort_func (self->command_list, sort_commands, self, NULL);
285 : :
286 : : /* Setup GSettings */
287 : 1 : settings = valent_device_preferences_group_get_settings (group);
288 : 1 : g_signal_connect_object (settings,
289 : : "changed::commands",
290 : : G_CALLBACK (valent_runcommand_preferences_populate),
291 : : self,
292 : : G_CONNECT_SWAPPED);
293 : 1 : valent_runcommand_preferences_populate (self);
294 : :
295 : 1 : G_OBJECT_CLASS (valent_runcommand_preferences_parent_class)->constructed (object);
296 : 1 : }
297 : :
298 : : static void
299 : 1 : valent_runcommand_preferences_dispose (GObject *object)
300 : : {
301 : 1 : GtkWidget *widget = GTK_WIDGET (object);
302 : :
303 : 1 : gtk_widget_dispose_template (widget, VALENT_TYPE_RUNCOMMAND_PREFERENCES);
304 : :
305 : 1 : G_OBJECT_CLASS (valent_runcommand_preferences_parent_class)->dispose (object);
306 : 1 : }
307 : :
308 : : static void
309 : 1 : valent_runcommand_preferences_finalize (GObject *object)
310 : : {
311 : 1 : ValentRuncommandPreferences *self = VALENT_RUNCOMMAND_PREFERENCES (object);
312 : :
313 [ - + ]: 1 : g_clear_pointer (&self->editor, gtk_window_destroy);
314 : :
315 : 1 : G_OBJECT_CLASS (valent_runcommand_preferences_parent_class)->finalize (object);
316 : 1 : }
317 : :
318 : : static void
319 : 1 : valent_runcommand_preferences_class_init (ValentRuncommandPreferencesClass *klass)
320 : : {
321 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
322 : 1 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
323 : :
324 : 1 : object_class->constructed = valent_runcommand_preferences_constructed;
325 : 1 : object_class->dispose = valent_runcommand_preferences_dispose;
326 : 1 : object_class->finalize = valent_runcommand_preferences_finalize;
327 : :
328 : 1 : gtk_widget_class_set_template_from_resource (widget_class, "/plugins/gnome/valent-device-preferences-commands.ui");
329 : 1 : gtk_widget_class_bind_template_child (widget_class, ValentRuncommandPreferences, command_list_row);
330 : :
331 : 1 : gtk_widget_class_install_action (widget_class, "runcommand.add", NULL, runcommand_add_action);
332 : 1 : gtk_widget_class_install_action (widget_class, "runcommand.edit", "s", runcommand_edit_action);
333 : 1 : gtk_widget_class_install_action (widget_class, "runcommand.remove", "s", runcommand_remove_action);
334 : 1 : gtk_widget_class_install_action (widget_class, "runcommand.save", "s", runcommand_save_action);
335 : 1 : }
336 : :
337 : : static void
338 : 1 : valent_runcommand_preferences_init (ValentRuncommandPreferences *self)
339 : : {
340 : 1 : gtk_widget_init_template (GTK_WIDGET (self));
341 : :
342 : 1 : self->command_list = _adw_expander_row_get_list (self->command_list_row);
343 : 1 : }
344 : :
|