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