1 /* nemo-script-config-widget.h */
2
3 /* A widget that displays a list of scripts to enable or disable.
4 * This is usually part of a NemoPluginManagerWidget
5 */
6
7 #include <config.h>
8 #include "nemo-script-config-widget.h"
9 #include "nemo-application.h"
10 #include "nemo-view.h"
11 #include "nemo-file.h"
12 #include "nemo-global-preferences.h"
13 #include <libnemo-private/nemo-file-utilities.h>
14
15 #include <glib.h>
16
17 G_DEFINE_TYPE (NemoScriptConfigWidget, nemo_script_config_widget, NEMO_TYPE_CONFIG_BASE_WIDGET);
18
19
20 typedef struct {
21 NemoScriptConfigWidget *widget;
22
23 gchar *name;
24 } ScriptProxy;
25
26 static void
script_proxy_free(ScriptProxy * proxy)27 script_proxy_free (ScriptProxy *proxy)
28 {
29 g_clear_pointer (&proxy->name, g_free);
30 }
31
32 static GtkWidget *
get_button_for_row(GtkWidget * row)33 get_button_for_row (GtkWidget *row)
34 {
35 GtkWidget *ret;
36
37 GtkWidget *box = gtk_bin_get_child (GTK_BIN (row));
38 GList *clist = gtk_container_get_children (GTK_CONTAINER (box));
39
40 ret = clist->data;
41
42 g_list_free (clist);
43
44 return ret;
45 }
46
47 static void
on_row_activated(GtkWidget * box,GtkWidget * row,GtkWidget * widget)48 on_row_activated (GtkWidget *box, GtkWidget *row, GtkWidget *widget)
49 {
50 GtkWidget *button = get_button_for_row (row);
51
52 gtk_button_clicked (GTK_BUTTON (button));
53 }
54
55 static void
on_check_toggled(GtkWidget * button,ScriptProxy * proxy)56 on_check_toggled(GtkWidget *button, ScriptProxy *proxy)
57 {
58 gboolean enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
59
60 gchar **blacklist = g_settings_get_strv (nemo_plugin_preferences,
61 NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS);
62
63 GPtrArray *new_list = g_ptr_array_new ();
64
65 guint i;
66
67 if (enabled) {
68 for (i = 0; i < g_strv_length (blacklist); i++) {
69 if (g_strcmp0 (blacklist[i], proxy->name) == 0)
70 continue;
71 g_ptr_array_add (new_list, g_strdup (blacklist[i]));
72 }
73 } else {
74 for (i = 0; i < g_strv_length (blacklist); i++) {
75 g_ptr_array_add (new_list, g_strdup (blacklist[i]));
76 }
77
78 g_ptr_array_add (new_list, g_strdup (proxy->name));
79 }
80
81 g_ptr_array_add (new_list, NULL);
82
83 gchar **new_list_ptr = (char **) g_ptr_array_free (new_list, FALSE);
84
85 g_signal_handler_block (nemo_plugin_preferences, proxy->widget->bl_handler);
86 g_settings_set_strv (nemo_plugin_preferences,
87 NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS,
88 (const gchar * const *) new_list_ptr);
89 g_signal_handler_unblock (nemo_plugin_preferences, proxy->widget->bl_handler);
90
91 g_strfreev (blacklist);
92 g_strfreev (new_list_ptr);
93 }
94
95 static void
populate_from_directory(NemoScriptConfigWidget * widget,const gchar * path)96 populate_from_directory (NemoScriptConfigWidget *widget, const gchar *path)
97 {
98 GDir *dir;
99
100 dir = g_dir_open (path, 0, NULL);
101
102 if (dir) {
103 const char *name;
104
105 while ((name = g_dir_read_name (dir))) {
106 char *filename;
107
108 filename = g_build_filename (path, name, NULL);
109
110 if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
111 populate_from_directory (widget, filename);
112 g_free (filename);
113 continue;
114 }
115
116 ScriptProxy *p = g_slice_new0 (ScriptProxy);
117 p->name = g_strdup (name);
118 p->widget = widget;
119
120 widget->scripts = g_list_append (widget->scripts, p);
121 g_free (filename);
122 }
123
124 g_dir_close (dir);
125 }
126 }
127
128 static void
refresh_widget(NemoScriptConfigWidget * widget)129 refresh_widget (NemoScriptConfigWidget *widget)
130 {
131 if (widget->scripts != NULL) {
132 g_list_free_full (widget->scripts, (GDestroyNotify) script_proxy_free);
133 widget->scripts = NULL;
134 }
135
136 nemo_config_base_widget_clear_list (NEMO_CONFIG_BASE_WIDGET (widget));
137
138 gchar *path = NULL;
139
140 path = nemo_get_scripts_directory_path ();
141 populate_from_directory (widget, path);
142 g_clear_pointer (&path, g_free);
143
144 if (widget->scripts == NULL) {
145 GtkWidget *empty_label = gtk_label_new (NULL);
146 gchar *markup = NULL;
147
148 markup = g_strdup_printf ("<i>%s</i>", _("No scripts found"));
149
150 gtk_label_set_markup (GTK_LABEL (empty_label), markup);
151 g_free (markup);
152
153 GtkWidget *empty_row = gtk_list_box_row_new ();
154 gtk_container_add (GTK_CONTAINER (empty_row), empty_label);
155
156 gtk_widget_show_all (empty_row);
157 gtk_container_add (GTK_CONTAINER (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), empty_row);
158 gtk_widget_set_sensitive (GTK_WIDGET (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), FALSE);
159 } else {
160 GList *l;
161 gchar **blacklist = g_settings_get_strv (nemo_plugin_preferences,
162 NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS);
163
164 for (l = widget->scripts; l != NULL; l=l->next) {
165 ScriptProxy *proxy = l->data;
166
167 gboolean active = TRUE;
168 guint i = 0;
169
170 for (i = 0; i < g_strv_length (blacklist); i++) {
171 if (g_strcmp0 (blacklist[i], proxy->name) == 0) {
172 active = FALSE;
173 break;
174 }
175 }
176
177 GtkWidget *w;
178 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
179
180 GtkWidget *button = gtk_check_button_new ();
181 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), active);
182 g_signal_connect (button, "toggled", G_CALLBACK (on_check_toggled), proxy);
183 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 2);
184
185 w = gtk_label_new (proxy->name);
186 gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 2);
187
188 GtkWidget *row = gtk_list_box_row_new ();
189 gtk_container_add (GTK_CONTAINER (row), box);
190
191 gtk_widget_show_all (row);
192 gtk_container_add (GTK_CONTAINER (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), row);
193 }
194
195 gtk_widget_set_sensitive (GTK_WIDGET (NEMO_CONFIG_BASE_WIDGET (widget)->listbox), TRUE);
196
197 g_strfreev (blacklist);
198 }
199
200 nemo_config_base_widget_set_default_buttons_sensitive (NEMO_CONFIG_BASE_WIDGET (widget), widget->scripts != NULL);
201 }
202
203 static void
on_settings_changed(GSettings * settings,gchar * key,gpointer user_data)204 on_settings_changed (GSettings *settings, gchar *key, gpointer user_data)
205 {
206 NemoScriptConfigWidget *w = NEMO_SCRIPT_CONFIG_WIDGET (user_data);
207
208 refresh_widget (w);
209 }
210
211 static void
on_enable_clicked(GtkWidget * button,NemoScriptConfigWidget * widget)212 on_enable_clicked (GtkWidget *button, NemoScriptConfigWidget *widget)
213 {
214 g_settings_set_strv (nemo_plugin_preferences,
215 NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS,
216 NULL);
217 }
218
219 static void
on_disable_clicked(GtkWidget * button,NemoScriptConfigWidget * widget)220 on_disable_clicked (GtkWidget *button, NemoScriptConfigWidget *widget)
221 {
222 GPtrArray *new_list = g_ptr_array_new ();
223
224 GList *l;
225
226 for (l = widget->scripts; l != NULL; l = l->next)
227 g_ptr_array_add (new_list, g_strdup (((ScriptProxy *) l->data)->name));
228
229 g_ptr_array_add (new_list, NULL);
230
231 gchar **new_list_ptr = (char **) g_ptr_array_free (new_list, FALSE);
232 g_settings_set_strv (nemo_plugin_preferences,
233 NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS,
234 (const gchar * const *) new_list_ptr);
235
236 g_strfreev (new_list_ptr);
237 }
238
239 static void
on_open_folder_clicked(GtkWidget * button,NemoScriptConfigWidget * widget)240 on_open_folder_clicked (GtkWidget *button, NemoScriptConfigWidget *widget)
241 {
242 gchar *path = NULL;
243 path = nemo_get_scripts_directory_path ();
244 GFile *location = g_file_new_for_path (path);
245
246 nemo_application_open_location (nemo_application_get_singleton (),
247 location,
248 NULL,
249 "nemo",
250 FALSE);
251
252 g_free (path);
253 g_object_unref (location);
254 }
255
256 static void
on_dir_changed(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event_type,gpointer user_data)257 on_dir_changed (GFileMonitor *monitor,
258 GFile *file,
259 GFile *other_file,
260 GFileMonitorEvent event_type,
261 gpointer user_data)
262 {
263 NemoScriptConfigWidget *widget = NEMO_SCRIPT_CONFIG_WIDGET (user_data);
264
265 refresh_widget (widget);
266 }
267
268 static void
try_monitor_path(NemoScriptConfigWidget * widget,const gchar * path)269 try_monitor_path (NemoScriptConfigWidget *widget, const gchar *path)
270 {
271 GFile *dir = g_file_new_for_path (path);
272
273 GFileMonitor *mon = g_file_monitor_directory (dir, G_FILE_MONITOR_SEND_MOVED, NULL, NULL);
274
275 g_object_unref (dir);
276
277 if (mon != NULL) {
278 g_signal_connect (mon, "changed", G_CALLBACK (on_dir_changed), widget);
279 widget->dir_monitors = g_list_append (widget->dir_monitors, mon);
280 }
281 }
282
setup_dir_monitors(NemoScriptConfigWidget * widget)283 static void setup_dir_monitors (NemoScriptConfigWidget *widget)
284 {
285 widget->dir_monitors = NULL;
286
287 gchar **data_dirs = (gchar **) g_get_system_data_dirs ();
288
289 guint i;
290 for (i = 0; i < g_strv_length (data_dirs); i++) {
291 gchar *path = g_build_filename (data_dirs[i], "nemo", "actions", NULL);
292 try_monitor_path (widget, path);
293 g_free (path);
294 }
295
296 gchar *path = g_build_filename (g_get_user_data_dir (), "nemo", "actions", NULL);
297 try_monitor_path (widget, path);
298 g_free (path);
299 }
300
301 static void
nemo_script_config_widget_finalize(GObject * object)302 nemo_script_config_widget_finalize (GObject *object)
303 {
304 NemoScriptConfigWidget *widget = NEMO_SCRIPT_CONFIG_WIDGET (object);
305
306 if (widget->scripts != NULL) {
307 g_list_free_full (widget->scripts, (GDestroyNotify) script_proxy_free);
308 widget->scripts = NULL;
309 }
310
311 GList *l;
312
313 for (l = widget->dir_monitors; l != NULL; l = l->next) {
314 g_file_monitor_cancel (l->data);
315 g_object_unref (l->data);
316 }
317
318 g_list_free (widget->dir_monitors);
319
320 g_signal_handler_disconnect (nemo_plugin_preferences, widget->bl_handler);
321
322 G_OBJECT_CLASS (nemo_script_config_widget_parent_class)->finalize (object);
323 }
324
325 static void
nemo_script_config_widget_class_init(NemoScriptConfigWidgetClass * klass)326 nemo_script_config_widget_class_init (NemoScriptConfigWidgetClass *klass)
327 {
328 GObjectClass *oclass;
329 oclass = G_OBJECT_CLASS (klass);
330
331 oclass->finalize = nemo_script_config_widget_finalize;
332 }
333
334 static void
nemo_script_config_widget_init(NemoScriptConfigWidget * self)335 nemo_script_config_widget_init (NemoScriptConfigWidget *self)
336 {
337 self->scripts = NULL;
338
339 self->bl_handler = g_signal_connect (nemo_plugin_preferences,
340 "changed::" NEMO_PLUGIN_PREFERENCES_DISABLED_SCRIPTS,
341 G_CALLBACK (on_settings_changed), self);
342
343 GtkWidget *label = nemo_config_base_widget_get_label (NEMO_CONFIG_BASE_WIDGET (self));
344
345 gchar *title = g_strdup (_("Scripts"));
346 gchar *markup = g_strdup_printf ("<b>%s</b>", title);
347
348 gtk_label_set_markup (GTK_LABEL (label), markup);
349
350 g_free (title);
351 g_free (markup);
352
353 GtkWidget *widget = gtk_button_new_from_icon_name ("folder", GTK_ICON_SIZE_BUTTON);
354
355 GtkWidget *bb = nemo_config_base_widget_get_buttonbox (NEMO_CONFIG_BASE_WIDGET (self));
356 gtk_box_pack_end (GTK_BOX (bb),
357 widget,
358 FALSE, FALSE, 0);
359 gtk_widget_show (widget);
360
361 g_signal_connect (widget, "clicked", G_CALLBACK (on_open_folder_clicked), self);
362
363 g_signal_connect (nemo_config_base_widget_get_enable_button (NEMO_CONFIG_BASE_WIDGET (self)), "clicked",
364 G_CALLBACK (on_enable_clicked), self);
365
366 g_signal_connect (nemo_config_base_widget_get_disable_button (NEMO_CONFIG_BASE_WIDGET (self)), "clicked",
367 G_CALLBACK (on_disable_clicked), self);
368
369 g_signal_connect (NEMO_CONFIG_BASE_WIDGET (self)->listbox, "row-activated", G_CALLBACK (on_row_activated), self);
370
371 refresh_widget (self);
372
373 setup_dir_monitors (self);
374 }
375
376 GtkWidget *
nemo_script_config_widget_new(void)377 nemo_script_config_widget_new (void)
378 {
379 return g_object_new (NEMO_TYPE_SCRIPT_CONFIG_WIDGET, NULL);
380 }
381