1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /*
4 * Caja
5 *
6 * Copyright (C) 2008 Red Hat, Inc.
7 *
8 * Caja is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 * Author: David Zeuthen <davidz@redhat.com>
23 */
24
25 #include <config.h>
26 #include <string.h>
27 #include <glib/gi18n.h>
28 #include <gio/gio.h>
29 #include <gtk/gtk.h>
30 #include <gdk/gdkx.h>
31 #include <gio/gdesktopappinfo.h>
32 #include <X11/XKBlib.h>
33 #include <gdk/gdkkeysyms.h>
34 #include <cairo-gobject.h>
35
36 #include <eel/eel-glib-extensions.h>
37 #include <eel/eel-stock-dialogs.h>
38
39 #include "caja-icon-info.h"
40 #include "caja-global-preferences.h"
41 #include "caja-file-operations.h"
42 #include "caja-autorun.h"
43 #include "caja-program-choosing.h"
44 #include "caja-open-with-dialog.h"
45 #include "caja-desktop-icon-file.h"
46 #include "caja-file-utilities.h"
47
48 enum
49 {
50 AUTORUN_ASK,
51 AUTORUN_IGNORE,
52 AUTORUN_APP,
53 AUTORUN_OPEN_FOLDER,
54 AUTORUN_SEP,
55 AUTORUN_OTHER_APP,
56 };
57 enum
58 {
59 COLUMN_AUTORUN_SURFACE,
60 COLUMN_AUTORUN_NAME,
61 COLUMN_AUTORUN_APP_INFO,
62 COLUMN_AUTORUN_X_CONTENT_TYPE,
63 COLUMN_AUTORUN_ITEM_TYPE,
64 };
65
66 static gboolean should_autorun_mount (GMount *mount);
67
68 static void caja_autorun_rebuild_combo_box (GtkWidget *combo_box);
69
70 void
caja_autorun_get_preferences(const char * x_content_type,gboolean * pref_start_app,gboolean * pref_ignore,gboolean * pref_open_folder)71 caja_autorun_get_preferences (const char *x_content_type,
72 gboolean *pref_start_app,
73 gboolean *pref_ignore,
74 gboolean *pref_open_folder)
75 {
76 char **x_content_start_app;
77 char **x_content_ignore;
78 char **x_content_open_folder;
79
80 g_return_if_fail (pref_start_app != NULL);
81 g_return_if_fail (pref_ignore != NULL);
82 g_return_if_fail (pref_open_folder != NULL);
83
84 *pref_start_app = FALSE;
85 *pref_ignore = FALSE;
86 *pref_open_folder = FALSE;
87 x_content_start_app = g_settings_get_strv (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_START_APP);
88 x_content_ignore = g_settings_get_strv (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_IGNORE);
89 x_content_open_folder = g_settings_get_strv (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER);
90 if (x_content_start_app != NULL)
91 {
92 *pref_start_app = eel_g_strv_find (x_content_start_app, x_content_type) != -1;
93 }
94 if (x_content_ignore != NULL)
95 {
96 *pref_ignore = eel_g_strv_find (x_content_ignore, x_content_type) != -1;
97 }
98 if (x_content_open_folder != NULL)
99 {
100 *pref_open_folder = eel_g_strv_find (x_content_open_folder, x_content_type) != -1;
101 }
102 g_strfreev (x_content_ignore);
103 g_strfreev (x_content_start_app);
104 g_strfreev (x_content_open_folder);
105 }
106
107 static void
remove_elem_from_str_array(char ** v,const char * s)108 remove_elem_from_str_array (char **v, const char *s)
109 {
110 int n, m;
111
112 if (v == NULL)
113 {
114 return;
115 }
116
117 for (n = 0; v[n] != NULL; n++)
118 {
119 if (strcmp (v[n], s) == 0)
120 {
121 for (m = n + 1; v[m] != NULL; m++)
122 {
123 v[m - 1] = v[m];
124 }
125 v[m - 1] = NULL;
126 n--;
127 }
128 }
129 }
130
131 static char **
add_elem_to_str_array(char ** v,const char * s)132 add_elem_to_str_array (char **v, const char *s)
133 {
134 guint len;
135 char **r;
136
137 len = v != NULL ? g_strv_length (v) : 0;
138 r = g_new0 (char *, len + 2);
139
140 if (v)
141 memcpy (r, v, len * sizeof (char *));
142
143 r[len] = g_strdup (s);
144 r[len+1] = NULL;
145 g_free (v);
146
147 return r;
148 }
149
150
151 void
caja_autorun_set_preferences(const char * x_content_type,gboolean pref_start_app,gboolean pref_ignore,gboolean pref_open_folder)152 caja_autorun_set_preferences (const char *x_content_type,
153 gboolean pref_start_app,
154 gboolean pref_ignore,
155 gboolean pref_open_folder)
156 {
157 char **x_content_start_app;
158 char **x_content_ignore;
159 char **x_content_open_folder;
160
161 g_assert (x_content_type != NULL);
162
163 x_content_start_app = g_settings_get_strv (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_START_APP);
164 x_content_ignore = g_settings_get_strv (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_IGNORE);
165 x_content_open_folder = g_settings_get_strv (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER);
166
167 remove_elem_from_str_array (x_content_start_app, x_content_type);
168 if (pref_start_app)
169 {
170 x_content_start_app = add_elem_to_str_array (x_content_start_app, x_content_type);
171 }
172 g_settings_set_strv (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_START_APP, (const gchar * const*) x_content_start_app);
173
174 remove_elem_from_str_array (x_content_ignore, x_content_type);
175 if (pref_ignore)
176 {
177 x_content_ignore = add_elem_to_str_array (x_content_ignore, x_content_type);
178 }
179 g_settings_set_strv (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_IGNORE, (const gchar * const*) x_content_ignore);
180
181 remove_elem_from_str_array (x_content_open_folder, x_content_type);
182 if (pref_open_folder)
183 {
184 x_content_open_folder = add_elem_to_str_array (x_content_open_folder, x_content_type);
185 }
186 g_settings_set_strv (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER, (const gchar * const*) x_content_open_folder);
187
188 g_strfreev (x_content_open_folder);
189 g_strfreev (x_content_ignore);
190 g_strfreev (x_content_start_app);
191
192 }
193
194 static gboolean
combo_box_separator_func(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)195 combo_box_separator_func (GtkTreeModel *model,
196 GtkTreeIter *iter,
197 gpointer data)
198 {
199 char *str;
200
201 gtk_tree_model_get (model, iter,
202 1, &str,
203 -1);
204 if (str != NULL)
205 {
206 g_free (str);
207 return FALSE;
208 }
209 return TRUE;
210 }
211
212 typedef struct
213 {
214 guint changed_signal_id;
215 GtkWidget *combo_box;
216
217 char *x_content_type;
218 gboolean include_ask;
219 gboolean include_open_with_other_app;
220
221 gboolean update_settings;
222 CajaAutorunComboBoxChanged changed_cb;
223 gpointer user_data;
224
225 gboolean other_application_selected;
226 } CajaAutorunComboBoxData;
227
228 static void
caja_autorun_combobox_data_destroy(CajaAutorunComboBoxData * data)229 caja_autorun_combobox_data_destroy (CajaAutorunComboBoxData *data)
230 {
231 /* signal handler may be automatically disconnected by destroying the widget */
232 if (g_signal_handler_is_connected (G_OBJECT (data->combo_box), data->changed_signal_id))
233 {
234 g_signal_handler_disconnect (G_OBJECT (data->combo_box), data->changed_signal_id);
235 }
236 g_free (data->x_content_type);
237 g_free (data);
238 }
239
240 static void
other_application_selected(CajaOpenWithDialog * dialog,GAppInfo * app_info,CajaAutorunComboBoxData * data)241 other_application_selected (CajaOpenWithDialog *dialog,
242 GAppInfo *app_info,
243 CajaAutorunComboBoxData *data)
244 {
245 if (data->changed_cb != NULL)
246 {
247 data->changed_cb (TRUE, FALSE, FALSE, app_info, data->user_data);
248 }
249 if (data->update_settings)
250 {
251 caja_autorun_set_preferences (data->x_content_type, TRUE, FALSE, FALSE);
252 g_app_info_set_as_default_for_type (app_info,
253 data->x_content_type,
254 NULL);
255 data->other_application_selected = TRUE;
256 }
257
258 /* rebuild so we include and select the new application in the list */
259 caja_autorun_rebuild_combo_box (data->combo_box);
260 }
261
262 static void
handle_dialog_closure(CajaAutorunComboBoxData * data)263 handle_dialog_closure (CajaAutorunComboBoxData *data)
264 {
265 if (!data->other_application_selected)
266 {
267 /* reset combo box so we don't linger on "Open with other Application..." */
268 caja_autorun_rebuild_combo_box (data->combo_box);
269 }
270 }
271
272 static void
dialog_response_cb(GtkDialog * dialog,gint response,CajaAutorunComboBoxData * data)273 dialog_response_cb (GtkDialog *dialog,
274 gint response,
275 CajaAutorunComboBoxData *data)
276 {
277 handle_dialog_closure (data);
278 }
279
280 static void
dialog_destroy_cb(GtkWidget * object,CajaAutorunComboBoxData * data)281 dialog_destroy_cb (GtkWidget *object,
282 CajaAutorunComboBoxData *data)
283 {
284 handle_dialog_closure (data);
285 }
286
287 static void
combo_box_changed(GtkComboBox * combo_box,CajaAutorunComboBoxData * data)288 combo_box_changed (GtkComboBox *combo_box,
289 CajaAutorunComboBoxData *data)
290 {
291 GtkTreeIter iter;
292 GtkTreeModel *model;
293 GAppInfo *app_info;
294 char *x_content_type;
295 int type;
296
297 model = NULL;
298 app_info = NULL;
299 x_content_type = NULL;
300
301 if (!gtk_combo_box_get_active_iter (combo_box, &iter))
302 {
303 goto out;
304 }
305
306 model = gtk_combo_box_get_model (combo_box);
307 if (model == NULL)
308 {
309 goto out;
310 }
311
312 gtk_tree_model_get (model, &iter,
313 COLUMN_AUTORUN_APP_INFO, &app_info,
314 COLUMN_AUTORUN_X_CONTENT_TYPE, &x_content_type,
315 COLUMN_AUTORUN_ITEM_TYPE, &type,
316 -1);
317
318 switch (type)
319 {
320 case AUTORUN_ASK:
321 if (data->changed_cb != NULL)
322 {
323 data->changed_cb (TRUE, FALSE, FALSE, NULL, data->user_data);
324 }
325 if (data->update_settings)
326 {
327 caja_autorun_set_preferences (x_content_type, FALSE, FALSE, FALSE);
328 }
329 break;
330 case AUTORUN_IGNORE:
331 if (data->changed_cb != NULL)
332 {
333 data->changed_cb (FALSE, TRUE, FALSE, NULL, data->user_data);
334 }
335 if (data->update_settings)
336 {
337 caja_autorun_set_preferences (x_content_type, FALSE, TRUE, FALSE);
338 }
339 break;
340 case AUTORUN_OPEN_FOLDER:
341 if (data->changed_cb != NULL)
342 {
343 data->changed_cb (FALSE, FALSE, TRUE, NULL, data->user_data);
344 }
345 if (data->update_settings)
346 {
347 caja_autorun_set_preferences (x_content_type, FALSE, FALSE, TRUE);
348 }
349 break;
350
351 case AUTORUN_APP:
352 if (data->changed_cb != NULL)
353 {
354 /* TODO TODO?? */
355 data->changed_cb (TRUE, FALSE, FALSE, app_info, data->user_data);
356 }
357 if (data->update_settings)
358 {
359 caja_autorun_set_preferences (x_content_type, TRUE, FALSE, FALSE);
360 g_app_info_set_as_default_for_type (app_info,
361 x_content_type,
362 NULL);
363 }
364 break;
365
366 case AUTORUN_OTHER_APP:
367 {
368 GtkWidget *dialog;
369
370 data->other_application_selected = FALSE;
371
372 dialog = caja_add_application_dialog_new (NULL, x_content_type);
373 gtk_window_set_transient_for (GTK_WINDOW (dialog),
374 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (combo_box))));
375 g_signal_connect (dialog, "application_selected",
376 G_CALLBACK (other_application_selected),
377 data);
378 g_signal_connect (dialog, "response",
379 G_CALLBACK (dialog_response_cb), data);
380 g_signal_connect (dialog, "destroy",
381 G_CALLBACK (dialog_destroy_cb), data);
382 gtk_widget_show (GTK_WIDGET (dialog));
383
384 break;
385 }
386
387 }
388
389 out:
390 if (app_info != NULL)
391 {
392 g_object_unref (app_info);
393 }
394 g_free (x_content_type);
395 }
396
397 static void
caja_autorun_rebuild_combo_box(GtkWidget * combo_box)398 caja_autorun_rebuild_combo_box (GtkWidget *combo_box)
399 {
400 CajaAutorunComboBoxData *data;
401 char *x_content_type;
402
403 data = g_object_get_data (G_OBJECT (combo_box), "caja_autorun_combobox_data");
404 if (data == NULL)
405 {
406 g_warning ("no 'caja_autorun_combobox_data' data!");
407 return;
408 }
409
410 x_content_type = g_strdup (data->x_content_type);
411 caja_autorun_prepare_combo_box (combo_box,
412 x_content_type,
413 data->include_ask,
414 data->include_open_with_other_app,
415 data->update_settings,
416 data->changed_cb,
417 data->user_data);
418 g_free (x_content_type);
419 }
420
421 /* TODO: we need some kind of way to remove user-defined associations,
422 * e.g. the result of "Open with other Application...".
423 *
424 * However, this is a bit hard as
425 * g_app_info_can_remove_supports_type() will always return TRUE
426 * because we now have [Removed Applications] in the file
427 * ~/.local/share/applications/mimeapps.list.
428 *
429 * We need the API outlined in
430 *
431 * https://bugzilla.gnome.org/show_bug.cgi?id=545350
432 *
433 * to do this.
434 *
435 * Now, there's also the question about what the UI would look like
436 * given this API. Ideally we'd include a small button on the right
437 * side of the combo box that the user can press to delete an
438 * association, e.g.:
439 *
440 * +-------------------------------------+
441 * | Ask what to do |
442 * | Do Nothing |
443 * | Open Folder |
444 * +-------------------------------------+
445 * | Open Rhythmbox Music Player |
446 * | Open Audio CD Extractor |
447 * | Open Banshee Media Player |
448 * | Open Frobnicator App [x] |
449 * +-------------------------------------+
450 * | Open with other Application... |
451 * +-------------------------------------+
452 *
453 * where "Frobnicator App" have been set up using "Open with other
454 * Application...". However this is not accessible (which is a
455 * GTK+ issue) but probably not a big deal.
456 *
457 * And we only want show these buttons (e.g. [x]) for associations with
458 * GAppInfo instances that are deletable.
459 */
460
461 void
caja_autorun_prepare_combo_box(GtkWidget * combo_box,const char * x_content_type,gboolean include_ask,gboolean include_open_with_other_app,gboolean update_settings,CajaAutorunComboBoxChanged changed_cb,gpointer user_data)462 caja_autorun_prepare_combo_box (GtkWidget *combo_box,
463 const char *x_content_type,
464 gboolean include_ask,
465 gboolean include_open_with_other_app,
466 gboolean update_settings,
467 CajaAutorunComboBoxChanged changed_cb,
468 gpointer user_data)
469 {
470 GList *l;
471 GList *app_info_list;
472 GAppInfo *default_app_info;
473 GtkListStore *list_store;
474 GtkTreeIter iter;
475 cairo_surface_t *surface;
476 int icon_size, icon_scale;
477 int set_active;
478 int num_apps;
479 gboolean pref_ask;
480 gboolean pref_start_app;
481 gboolean pref_ignore;
482 gboolean pref_open_folder;
483 CajaAutorunComboBoxData *data;
484 GtkCellRenderer *renderer;
485 gboolean new_data;
486
487 caja_autorun_get_preferences (x_content_type, &pref_start_app, &pref_ignore, &pref_open_folder);
488 pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder;
489
490 icon_size = caja_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU);
491 icon_scale = gtk_widget_get_scale_factor (combo_box);
492
493 set_active = -1;
494 data = NULL;
495 new_data = TRUE;
496
497 app_info_list = g_app_info_get_all_for_type (x_content_type);
498 default_app_info = g_app_info_get_default_for_type (x_content_type, FALSE);
499 num_apps = g_list_length (app_info_list);
500
501 list_store = gtk_list_store_new (5,
502 CAIRO_GOBJECT_TYPE_SURFACE,
503 G_TYPE_STRING,
504 G_TYPE_APP_INFO,
505 G_TYPE_STRING,
506 G_TYPE_INT);
507
508 /* no apps installed */
509 if (num_apps == 0)
510 {
511 gtk_list_store_append (list_store, &iter);
512 surface = gtk_icon_theme_load_surface (gtk_icon_theme_get_default (),
513 "dialog-error",
514 icon_size,
515 icon_scale,
516 NULL,
517 0,
518 NULL);
519
520 /* TODO: integrate with PackageKit-mate to find applications */
521
522 gtk_list_store_set (list_store, &iter,
523 COLUMN_AUTORUN_SURFACE, surface,
524 COLUMN_AUTORUN_NAME, _("No applications found"),
525 COLUMN_AUTORUN_APP_INFO, NULL,
526 COLUMN_AUTORUN_X_CONTENT_TYPE, x_content_type,
527 COLUMN_AUTORUN_ITEM_TYPE, AUTORUN_ASK,
528 -1);
529 cairo_surface_destroy (surface);
530 }
531 else
532 {
533 if (include_ask)
534 {
535 gtk_list_store_append (list_store, &iter);
536 surface = gtk_icon_theme_load_surface (gtk_icon_theme_get_default (),
537 "dialog-question",
538 icon_size,
539 icon_scale,
540 NULL,
541 0,
542 NULL);
543 gtk_list_store_set (list_store, &iter,
544 COLUMN_AUTORUN_SURFACE, surface,
545 COLUMN_AUTORUN_NAME, _("Ask what to do"),
546 COLUMN_AUTORUN_APP_INFO, NULL,
547 COLUMN_AUTORUN_X_CONTENT_TYPE, x_content_type,
548 COLUMN_AUTORUN_ITEM_TYPE, AUTORUN_ASK,
549 -1);
550 cairo_surface_destroy (surface);
551 }
552
553 gtk_list_store_append (list_store, &iter);
554 surface = gtk_icon_theme_load_surface (gtk_icon_theme_get_default (),
555 "window-close",
556 icon_size,
557 icon_scale,
558 NULL,
559 0,
560 NULL);
561 gtk_list_store_set (list_store, &iter,
562 COLUMN_AUTORUN_SURFACE, surface,
563 COLUMN_AUTORUN_NAME, _("Do Nothing"),
564 COLUMN_AUTORUN_APP_INFO, NULL,
565 COLUMN_AUTORUN_X_CONTENT_TYPE, x_content_type,
566 COLUMN_AUTORUN_ITEM_TYPE, AUTORUN_IGNORE,
567 -1);
568 cairo_surface_destroy (surface);
569
570 gtk_list_store_append (list_store, &iter);
571 surface = gtk_icon_theme_load_surface (gtk_icon_theme_get_default (),
572 "folder-open",
573 icon_size,
574 icon_scale,
575 NULL,
576 0,
577 NULL);
578 gtk_list_store_set (list_store, &iter,
579 COLUMN_AUTORUN_SURFACE, surface,
580 COLUMN_AUTORUN_NAME, _("Open Folder"),
581 COLUMN_AUTORUN_APP_INFO, NULL,
582 COLUMN_AUTORUN_X_CONTENT_TYPE, x_content_type,
583 COLUMN_AUTORUN_ITEM_TYPE, AUTORUN_OPEN_FOLDER,
584 -1);
585 cairo_surface_destroy (surface);
586
587 gtk_list_store_append (list_store, &iter);
588 gtk_list_store_set (list_store, &iter,
589 COLUMN_AUTORUN_SURFACE, NULL,
590 COLUMN_AUTORUN_NAME, NULL,
591 COLUMN_AUTORUN_APP_INFO, NULL,
592 COLUMN_AUTORUN_X_CONTENT_TYPE, NULL,
593 COLUMN_AUTORUN_ITEM_TYPE, AUTORUN_SEP,
594 -1);
595
596 int n;
597
598 for (l = app_info_list, n = include_ask ? 4 : 3; l != NULL; l = l->next, n++)
599 {
600 GIcon *icon;
601 CajaIconInfo *icon_info;
602 char *open_string;
603 GAppInfo *app_info = l->data;
604
605 /* we deliberately ignore should_show because some apps might want
606 * to install special handlers that should be hidden in the regular
607 * application launcher menus
608 */
609
610 icon = g_app_info_get_icon (app_info);
611 icon_info = caja_icon_info_lookup (icon, icon_size, icon_scale);
612 surface = caja_icon_info_get_surface_at_size (icon_info, icon_size);
613 g_object_unref (icon_info);
614
615 open_string = g_strdup_printf (_("Open %s"), g_app_info_get_display_name (app_info));
616
617 gtk_list_store_append (list_store, &iter);
618 gtk_list_store_set (list_store, &iter,
619 COLUMN_AUTORUN_SURFACE, surface,
620 COLUMN_AUTORUN_NAME, open_string,
621 COLUMN_AUTORUN_APP_INFO, app_info,
622 COLUMN_AUTORUN_X_CONTENT_TYPE, x_content_type,
623 COLUMN_AUTORUN_ITEM_TYPE, AUTORUN_APP,
624 -1);
625 if (surface != NULL)
626 {
627 cairo_surface_destroy (surface);
628 }
629 g_free (open_string);
630
631 if (g_app_info_equal (app_info, default_app_info))
632 {
633 set_active = n;
634 }
635 }
636 }
637
638 if (include_open_with_other_app)
639 {
640 gtk_list_store_append (list_store, &iter);
641 gtk_list_store_set (list_store, &iter,
642 COLUMN_AUTORUN_SURFACE, NULL,
643 COLUMN_AUTORUN_NAME, NULL,
644 COLUMN_AUTORUN_APP_INFO, NULL,
645 COLUMN_AUTORUN_X_CONTENT_TYPE, NULL,
646 COLUMN_AUTORUN_ITEM_TYPE, AUTORUN_SEP,
647 -1);
648
649 gtk_list_store_append (list_store, &iter);
650 surface = gtk_icon_theme_load_surface (gtk_icon_theme_get_default (),
651 "application-x-executable",
652 icon_size,
653 icon_scale,
654 NULL,
655 0,
656 NULL);
657 gtk_list_store_set (list_store, &iter,
658 COLUMN_AUTORUN_SURFACE, surface,
659 COLUMN_AUTORUN_NAME, _("Open with other Application..."),
660 COLUMN_AUTORUN_APP_INFO, NULL,
661 COLUMN_AUTORUN_X_CONTENT_TYPE, x_content_type,
662 COLUMN_AUTORUN_ITEM_TYPE, AUTORUN_OTHER_APP,
663 -1);
664 cairo_surface_destroy (surface);
665 }
666
667 if (default_app_info != NULL)
668 {
669 g_object_unref (default_app_info);
670 }
671 g_list_free_full (app_info_list, g_object_unref);
672
673 gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), GTK_TREE_MODEL (list_store));
674 g_object_unref (G_OBJECT (list_store));
675
676 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box));
677
678 renderer = gtk_cell_renderer_pixbuf_new ();
679 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE);
680 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
681 "surface", COLUMN_AUTORUN_SURFACE,
682 NULL);
683 renderer = gtk_cell_renderer_text_new ();
684 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
685 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
686 "text", COLUMN_AUTORUN_NAME,
687 NULL);
688 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo_box), combo_box_separator_func, NULL, NULL);
689
690 if (num_apps == 0)
691 {
692 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
693 gtk_widget_set_sensitive (combo_box, FALSE);
694 }
695 else
696 {
697 gtk_widget_set_sensitive (combo_box, TRUE);
698 if (pref_ask && include_ask)
699 {
700 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
701 }
702 else if (pref_ignore)
703 {
704 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), include_ask ? 1 : 0);
705 }
706 else if (pref_open_folder)
707 {
708 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), include_ask ? 2 : 1);
709 }
710 else if (set_active != -1)
711 {
712 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), set_active);
713 }
714 else
715 {
716 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), include_ask ? 1 : 0);
717 }
718
719 /* See if we have an old data around */
720 data = g_object_get_data (G_OBJECT (combo_box), "caja_autorun_combobox_data");
721 if (data)
722 {
723 new_data = FALSE;
724 g_free (data->x_content_type);
725 }
726 else
727 {
728 data = g_new0 (CajaAutorunComboBoxData, 1);
729 }
730
731 data->x_content_type = g_strdup (x_content_type);
732 data->include_ask = include_ask;
733 data->include_open_with_other_app = include_open_with_other_app;
734 data->update_settings = update_settings;
735 data->changed_cb = changed_cb;
736 data->user_data = user_data;
737 data->combo_box = combo_box;
738 if (data->changed_signal_id == 0)
739 {
740 data->changed_signal_id = g_signal_connect (G_OBJECT (combo_box),
741 "changed",
742 G_CALLBACK (combo_box_changed),
743 data);
744 }
745 }
746
747 if (new_data)
748 {
749 g_object_set_data_full (G_OBJECT (combo_box),
750 "caja_autorun_combobox_data",
751 data,
752 (GDestroyNotify) caja_autorun_combobox_data_destroy);
753 }
754 }
755
756 static gboolean
is_shift_pressed(void)757 is_shift_pressed (void)
758 {
759 gboolean ret;
760 GdkDisplay *display;
761 XkbStateRec state;
762 Bool status;
763
764 ret = FALSE;
765
766 display = gdk_display_get_default ();
767 gdk_x11_display_error_trap_push (display);
768 status = XkbGetState (GDK_DISPLAY_XDISPLAY (display),
769 XkbUseCoreKbd, &state);
770 gdk_x11_display_error_trap_pop_ignored (display);
771
772 if (status == Success)
773 {
774 ret = state.mods & ShiftMask;
775 }
776
777 return ret;
778 }
779
780 enum
781 {
782 AUTORUN_DIALOG_RESPONSE_EJECT = 0
783 };
784
785 typedef struct
786 {
787 GtkWidget *dialog;
788
789 GMount *mount;
790 gboolean should_eject;
791
792 gboolean selected_ignore;
793 gboolean selected_open_folder;
794 GAppInfo *selected_app;
795
796 gboolean remember;
797
798 char *x_content_type;
799
800 CajaAutorunOpenWindow open_window_func;
801 gpointer user_data;
802 } AutorunDialogData;
803
804
805 void
caja_autorun_launch_for_mount(GMount * mount,GAppInfo * app_info)806 caja_autorun_launch_for_mount (GMount *mount, GAppInfo *app_info)
807 {
808 GFile *root;
809 CajaFile *file;
810 GList *files;
811
812 root = g_mount_get_root (mount);
813 file = caja_file_get (root);
814 g_object_unref (root);
815 files = g_list_append (NULL, file);
816 caja_launch_application (app_info,
817 files,
818 NULL); /* TODO: what to set here? */
819 g_object_unref (file);
820 g_list_free (files);
821 }
822
823 static void autorun_dialog_mount_unmounted (GMount *mount, AutorunDialogData *data);
824
825 static void
autorun_dialog_destroy(AutorunDialogData * data)826 autorun_dialog_destroy (AutorunDialogData *data)
827 {
828 g_signal_handlers_disconnect_by_func (G_OBJECT (data->mount),
829 G_CALLBACK (autorun_dialog_mount_unmounted),
830 data);
831
832 gtk_widget_destroy (GTK_WIDGET (data->dialog));
833 if (data->selected_app != NULL)
834 {
835 g_object_unref (data->selected_app);
836 }
837 g_object_unref (data->mount);
838 g_free (data->x_content_type);
839 g_free (data);
840 }
841
842 static void
autorun_dialog_mount_unmounted(GMount * mount,AutorunDialogData * data)843 autorun_dialog_mount_unmounted (GMount *mount, AutorunDialogData *data)
844 {
845 /* remove the dialog if the media is unmounted */
846 autorun_dialog_destroy (data);
847 }
848
849 static void
autorun_dialog_response(GtkDialog * dialog,gint response,AutorunDialogData * data)850 autorun_dialog_response (GtkDialog *dialog, gint response, AutorunDialogData *data)
851 {
852 switch (response)
853 {
854 case AUTORUN_DIALOG_RESPONSE_EJECT:
855 caja_file_operations_unmount_mount (GTK_WINDOW (dialog),
856 data->mount,
857 data->should_eject,
858 FALSE);
859 break;
860
861 case GTK_RESPONSE_NONE:
862 /* window was closed */
863 break;
864 case GTK_RESPONSE_CANCEL:
865 break;
866 case GTK_RESPONSE_OK:
867 /* do the selected action */
868
869 if (data->remember)
870 {
871 /* make sure we don't ask again */
872 caja_autorun_set_preferences (data->x_content_type, TRUE, data->selected_ignore, data->selected_open_folder);
873 if (!data->selected_ignore && !data->selected_open_folder && data->selected_app != NULL)
874 {
875 g_app_info_set_as_default_for_type (data->selected_app,
876 data->x_content_type,
877 NULL);
878 }
879 }
880 else
881 {
882 /* make sure we do ask again */
883 caja_autorun_set_preferences (data->x_content_type, FALSE, FALSE, FALSE);
884 }
885
886 if (!data->selected_ignore && !data->selected_open_folder && data->selected_app != NULL)
887 {
888 caja_autorun_launch_for_mount (data->mount, data->selected_app);
889 }
890 else if (!data->selected_ignore && data->selected_open_folder)
891 {
892 if (data->open_window_func != NULL)
893 data->open_window_func (data->mount, data->user_data);
894 }
895 break;
896 }
897
898 autorun_dialog_destroy (data);
899 }
900
901 static void
autorun_combo_changed(gboolean selected_ask,gboolean selected_ignore,gboolean selected_open_folder,GAppInfo * selected_app,gpointer user_data)902 autorun_combo_changed (gboolean selected_ask,
903 gboolean selected_ignore,
904 gboolean selected_open_folder,
905 GAppInfo *selected_app,
906 gpointer user_data)
907 {
908 AutorunDialogData *data = user_data;
909
910 if (data->selected_app != NULL)
911 {
912 g_object_unref (data->selected_app);
913 }
914 data->selected_app = selected_app != NULL ? g_object_ref (selected_app) : NULL;
915 data->selected_ignore = selected_ignore;
916 data->selected_open_folder = selected_open_folder;
917 }
918
919
920 static void
autorun_always_toggled(GtkToggleButton * togglebutton,AutorunDialogData * data)921 autorun_always_toggled (GtkToggleButton *togglebutton, AutorunDialogData *data)
922 {
923 data->remember = gtk_toggle_button_get_active (togglebutton);
924 }
925
926 static gboolean
combo_box_enter_ok(GtkWidget * togglebutton,GdkEventKey * event,GtkDialog * dialog)927 combo_box_enter_ok (GtkWidget *togglebutton, GdkEventKey *event, GtkDialog *dialog)
928 {
929 if (event->keyval == GDK_KEY_KP_Enter || event->keyval == GDK_KEY_Return)
930 {
931 gtk_dialog_response (dialog, GTK_RESPONSE_OK);
932 return TRUE;
933 }
934 return FALSE;
935 }
936
937 /* returns TRUE if a folder window should be opened */
938 static gboolean
do_autorun_for_content_type(GMount * mount,const char * x_content_type,CajaAutorunOpenWindow open_window_func,gpointer user_data)939 do_autorun_for_content_type (GMount *mount, const char *x_content_type, CajaAutorunOpenWindow open_window_func, gpointer user_data)
940 {
941 AutorunDialogData *data;
942 GtkWidget *dialog;
943 GtkWidget *hbox;
944 GtkWidget *vbox;
945 GtkWidget *label;
946 GtkWidget *combo_box;
947 GtkWidget *always_check_button;
948 GtkWidget *eject_button;
949 GtkWidget *image;
950 GtkWidget *action_area;
951 char *markup;
952 char *content_description;
953 char *mount_name;
954 GIcon *icon;
955 GdkPixbuf *pixbuf;
956 cairo_surface_t *surface;
957 CajaIconInfo *icon_info;
958 int icon_size, icon_scale;
959 gboolean user_forced_dialog;
960 gboolean pref_ask;
961 gboolean pref_start_app;
962 gboolean pref_ignore;
963 gboolean pref_open_folder;
964 char *media_greeting;
965 gboolean ret;
966
967 ret = FALSE;
968 mount_name = NULL;
969
970 if (g_content_type_is_a (x_content_type, "x-content/win32-software"))
971 {
972 /* don't pop up the dialog anyway if the content type says
973 * windows software.
974 */
975 goto out;
976 }
977
978 user_forced_dialog = is_shift_pressed ();
979
980 caja_autorun_get_preferences (x_content_type, &pref_start_app, &pref_ignore, &pref_open_folder);
981 pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder;
982
983 if (user_forced_dialog)
984 {
985 goto show_dialog;
986 }
987
988 if (!pref_ask && !pref_ignore && !pref_open_folder)
989 {
990 GAppInfo *app_info;
991 app_info = g_app_info_get_default_for_type (x_content_type, FALSE);
992 if (app_info != NULL)
993 {
994 caja_autorun_launch_for_mount (mount, app_info);
995 }
996 goto out;
997 }
998
999 if (pref_open_folder)
1000 {
1001 ret = TRUE;
1002 goto out;
1003 }
1004
1005 if (pref_ignore)
1006 {
1007 goto out;
1008 }
1009
1010 show_dialog:
1011
1012 mount_name = g_mount_get_name (mount);
1013
1014 dialog = gtk_dialog_new ();
1015
1016 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1017 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, TRUE, TRUE, 0);
1018 gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
1019
1020 icon = g_mount_get_icon (mount);
1021 icon_size = caja_get_icon_size_for_stock_size (GTK_ICON_SIZE_DIALOG);
1022 icon_scale = gtk_widget_get_scale_factor (dialog);
1023 icon_info = caja_icon_info_lookup (icon, icon_size, icon_scale);
1024 pixbuf = caja_icon_info_get_pixbuf_at_size (icon_info, icon_size);
1025 surface = caja_icon_info_get_surface_at_size (icon_info, icon_size);
1026 g_object_unref (icon_info);
1027 g_object_unref (icon);
1028 image = gtk_image_new_from_surface (surface);
1029 gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
1030 gtk_widget_set_valign (image, GTK_ALIGN_START);
1031 gtk_box_pack_start (GTK_BOX (hbox), image, TRUE, TRUE, 0);
1032 /* also use the icon on the dialog */
1033 gtk_window_set_title (GTK_WINDOW (dialog), mount_name);
1034 gtk_window_set_icon (GTK_WINDOW (dialog), pixbuf);
1035 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
1036 g_object_unref (pixbuf);
1037 cairo_surface_destroy (surface);
1038
1039 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1040 gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
1041
1042 label = gtk_label_new (NULL);
1043
1044
1045 /* Customize greeting for well-known x-content types */
1046 if (strcmp (x_content_type, "x-content/audio-cdda") == 0)
1047 {
1048 media_greeting = _("You have just inserted an Audio CD.");
1049 }
1050 else if (strcmp (x_content_type, "x-content/audio-dvd") == 0)
1051 {
1052 media_greeting = _("You have just inserted an Audio DVD.");
1053 }
1054 else if (strcmp (x_content_type, "x-content/video-dvd") == 0)
1055 {
1056 media_greeting = _("You have just inserted a Video DVD.");
1057 }
1058 else if (strcmp (x_content_type, "x-content/video-vcd") == 0)
1059 {
1060 media_greeting = _("You have just inserted a Video CD.");
1061 }
1062 else if (strcmp (x_content_type, "x-content/video-svcd") == 0)
1063 {
1064 media_greeting = _("You have just inserted a Super Video CD.");
1065 }
1066 else if (strcmp (x_content_type, "x-content/blank-cd") == 0)
1067 {
1068 media_greeting = _("You have just inserted a blank CD.");
1069 }
1070 else if (strcmp (x_content_type, "x-content/blank-dvd") == 0)
1071 {
1072 media_greeting = _("You have just inserted a blank DVD.");
1073 }
1074 else if (strcmp (x_content_type, "x-content/blank-bd") == 0)
1075 {
1076 media_greeting = _("You have just inserted a blank Blu-Ray disc.");
1077 }
1078 else if (strcmp (x_content_type, "x-content/blank-hddvd") == 0)
1079 {
1080 media_greeting = _("You have just inserted a blank HD DVD.");
1081 }
1082 else if (strcmp (x_content_type, "x-content/image-photocd") == 0)
1083 {
1084 media_greeting = _("You have just inserted a Photo CD.");
1085 }
1086 else if (strcmp (x_content_type, "x-content/image-picturecd") == 0)
1087 {
1088 media_greeting = _("You have just inserted a Picture CD.");
1089 }
1090 else if (strcmp (x_content_type, "x-content/image-dcf") == 0)
1091 {
1092 media_greeting = _("You have just inserted a medium with digital photos.");
1093 }
1094 else if (strcmp (x_content_type, "x-content/audio-player") == 0)
1095 {
1096 media_greeting = _("You have just inserted a digital audio player.");
1097 }
1098 else if (g_content_type_is_a (x_content_type, "x-content/software"))
1099 {
1100 media_greeting = _("You have just inserted a medium with software intended to be automatically started.");
1101 }
1102 else
1103 {
1104 /* fallback to generic greeting */
1105 media_greeting = _("You have just inserted a medium.");
1106 }
1107 markup = g_strdup_printf ("<big><b>%s %s</b></big>", media_greeting, _("Choose what application to launch."));
1108 gtk_label_set_markup (GTK_LABEL (label), markup);
1109 g_free (markup);
1110 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
1111 gtk_label_set_max_width_chars (GTK_LABEL (label), 50);
1112 gtk_label_set_xalign (GTK_LABEL (label), 0);
1113 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
1114
1115 label = gtk_label_new (NULL);
1116 content_description = g_content_type_get_description (x_content_type);
1117 markup = g_strdup_printf (_("Select how to open \"%s\" and whether to perform this action in the future for other media of type \"%s\"."), mount_name, content_description);
1118 g_free (content_description);
1119 gtk_label_set_markup (GTK_LABEL (label), markup);
1120 g_free (markup);
1121 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
1122 gtk_label_set_max_width_chars (GTK_LABEL (label), 50);
1123 gtk_label_set_xalign (GTK_LABEL (label), 0);
1124 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
1125
1126 data = g_new0 (AutorunDialogData, 1);
1127 data->dialog = dialog;
1128 data->mount = g_object_ref (mount);
1129 data->remember = !pref_ask;
1130 data->selected_ignore = pref_ignore;
1131 data->x_content_type = g_strdup (x_content_type);
1132 data->selected_app = g_app_info_get_default_for_type (x_content_type, FALSE);
1133 data->open_window_func = open_window_func;
1134 data->user_data = user_data;
1135
1136 combo_box = gtk_combo_box_new ();
1137 caja_autorun_prepare_combo_box (combo_box, x_content_type, FALSE, TRUE, FALSE, autorun_combo_changed, data);
1138 g_signal_connect (G_OBJECT (combo_box),
1139 "key-press-event",
1140 G_CALLBACK (combo_box_enter_ok),
1141 dialog);
1142
1143 gtk_box_pack_start (GTK_BOX (vbox), combo_box, TRUE, TRUE, 0);
1144
1145 always_check_button = gtk_check_button_new_with_mnemonic (_("_Always perform this action"));
1146 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (always_check_button), data->remember);
1147 g_signal_connect (G_OBJECT (always_check_button),
1148 "toggled",
1149 G_CALLBACK (autorun_always_toggled),
1150 data);
1151 gtk_box_pack_start (GTK_BOX (vbox), always_check_button, TRUE, TRUE, 0);
1152
1153 eel_dialog_add_button (GTK_DIALOG (dialog),
1154 _("_Cancel"),
1155 "process-stop",
1156 GTK_RESPONSE_CANCEL);
1157
1158 action_area = gtk_widget_get_parent (eel_dialog_add_button (GTK_DIALOG (dialog),
1159 _("_OK"),
1160 "gtk-ok",
1161 GTK_RESPONSE_OK));
1162
1163 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
1164
1165 if (g_mount_can_eject (mount))
1166 {
1167 GtkWidget *eject_image;
1168 eject_button = gtk_button_new_with_mnemonic (_("_Eject"));
1169 surface = gtk_icon_theme_load_surface (gtk_icon_theme_get_default (),
1170 "media-eject",
1171 caja_get_icon_size_for_stock_size (GTK_ICON_SIZE_BUTTON),
1172 icon_scale,
1173 NULL,
1174 0,
1175 NULL);
1176 eject_image = gtk_image_new_from_surface (surface);
1177 cairo_surface_destroy (surface);
1178 gtk_button_set_image (GTK_BUTTON (eject_button), eject_image);
1179 data->should_eject = TRUE;
1180 }
1181 else
1182 {
1183 eject_button = gtk_button_new_with_mnemonic (_("_Unmount"));
1184 data->should_eject = FALSE;
1185 }
1186 gtk_dialog_add_action_widget (GTK_DIALOG (dialog), eject_button, AUTORUN_DIALOG_RESPONSE_EJECT);
1187 gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (action_area), eject_button, TRUE);
1188
1189 /* show the dialog */
1190 gtk_widget_show_all (dialog);
1191
1192 g_signal_connect (G_OBJECT (dialog),
1193 "response",
1194 G_CALLBACK (autorun_dialog_response),
1195 data);
1196
1197 g_signal_connect (G_OBJECT (data->mount),
1198 "unmounted",
1199 G_CALLBACK (autorun_dialog_mount_unmounted),
1200 data);
1201
1202 out:
1203 g_free (mount_name);
1204 return ret;
1205 }
1206
1207 typedef struct
1208 {
1209 GMount *mount;
1210 CajaAutorunOpenWindow open_window_func;
1211 gpointer user_data;
1212 } AutorunData;
1213
1214 static void
autorun_guessed_content_type_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)1215 autorun_guessed_content_type_callback (GObject *source_object,
1216 GAsyncResult *res,
1217 gpointer user_data)
1218 {
1219 GError *error;
1220 char **guessed_content_type;
1221 AutorunData *data = user_data;
1222 gboolean open_folder;
1223
1224 open_folder = FALSE;
1225
1226 error = NULL;
1227 guessed_content_type = g_mount_guess_content_type_finish (G_MOUNT (source_object), res, &error);
1228 g_object_set_data_full (source_object,
1229 "caja-content-type-cache",
1230 g_strdupv (guessed_content_type),
1231 (GDestroyNotify)g_strfreev);
1232 if (error != NULL)
1233 {
1234 g_warning ("Unabled to guess content type for mount: %s", error->message);
1235 g_error_free (error);
1236 }
1237 else
1238 {
1239 if (guessed_content_type != NULL && g_strv_length (guessed_content_type) > 0)
1240 {
1241 int n;
1242 for (n = 0; guessed_content_type[n] != NULL; n++)
1243 {
1244 if (do_autorun_for_content_type (data->mount, guessed_content_type[n],
1245 data->open_window_func, data->user_data))
1246 {
1247 open_folder = TRUE;
1248 }
1249 }
1250 g_strfreev (guessed_content_type);
1251 }
1252 else
1253 {
1254 if (g_settings_get_boolean (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTOMOUNT_OPEN))
1255 open_folder = TRUE;
1256 }
1257 }
1258
1259 /* only open the folder once.. */
1260 if (open_folder && data->open_window_func != NULL)
1261 {
1262 data->open_window_func (data->mount, data->user_data);
1263 }
1264
1265 g_object_unref (data->mount);
1266 g_free (data);
1267 }
1268
1269 void
caja_autorun(GMount * mount,CajaAutorunOpenWindow open_window_func,gpointer user_data)1270 caja_autorun (GMount *mount, CajaAutorunOpenWindow open_window_func, gpointer user_data)
1271 {
1272 AutorunData *data;
1273
1274 if (!should_autorun_mount (mount) ||
1275 g_settings_get_boolean (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTORUN_NEVER))
1276 {
1277 return;
1278 }
1279
1280 data = g_new0 (AutorunData, 1);
1281 data->mount = g_object_ref (mount);
1282 data->open_window_func = open_window_func;
1283 data->user_data = user_data;
1284
1285 g_mount_guess_content_type (mount,
1286 FALSE,
1287 NULL,
1288 autorun_guessed_content_type_callback,
1289 data);
1290 }
1291
1292 typedef struct
1293 {
1294 CajaAutorunGetContent callback;
1295 gpointer user_data;
1296 } GetContentTypesData;
1297
1298 static void
get_types_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1299 get_types_cb (GObject *source_object,
1300 GAsyncResult *res,
1301 gpointer user_data)
1302 {
1303 GetContentTypesData *data;
1304 char **types;
1305
1306 data = user_data;
1307 types = g_mount_guess_content_type_finish (G_MOUNT (source_object), res, NULL);
1308
1309 g_object_set_data_full (source_object,
1310 "caja-content-type-cache",
1311 g_strdupv (types),
1312 (GDestroyNotify)g_strfreev);
1313
1314 if (data->callback)
1315 {
1316 data->callback (types, data->user_data);
1317 }
1318 g_strfreev (types);
1319 g_free (data);
1320 }
1321
1322 void
caja_autorun_get_x_content_types_for_mount_async(GMount * mount,CajaAutorunGetContent callback,GCancellable * cancellable,gpointer user_data)1323 caja_autorun_get_x_content_types_for_mount_async (GMount *mount,
1324 CajaAutorunGetContent callback,
1325 GCancellable *cancellable,
1326 gpointer user_data)
1327 {
1328 char **cached;
1329 GetContentTypesData *data;
1330
1331 if (mount == NULL)
1332 {
1333 if (callback)
1334 {
1335 callback (NULL, user_data);
1336 }
1337 return;
1338 }
1339
1340 cached = g_object_get_data (G_OBJECT (mount), "caja-content-type-cache");
1341 if (cached != NULL)
1342 {
1343 if (callback)
1344 {
1345 callback (cached, user_data);
1346 }
1347 return;
1348 }
1349
1350 data = g_new (GetContentTypesData, 1);
1351 data->callback = callback;
1352 data->user_data = user_data;
1353
1354 g_mount_guess_content_type (mount,
1355 FALSE,
1356 cancellable,
1357 get_types_cb,
1358 data);
1359 }
1360
1361
1362 char **
caja_autorun_get_cached_x_content_types_for_mount(GMount * mount)1363 caja_autorun_get_cached_x_content_types_for_mount (GMount *mount)
1364 {
1365 char **cached;
1366
1367 if (mount == NULL)
1368 {
1369 return NULL;
1370 }
1371
1372 cached = g_object_get_data (G_OBJECT (mount), "caja-content-type-cache");
1373 if (cached != NULL)
1374 {
1375 return g_strdupv (cached);
1376 }
1377
1378 return NULL;
1379 }
1380
1381 static gboolean
remove_allow_volume(gpointer data)1382 remove_allow_volume (gpointer data)
1383 {
1384 GVolume *volume = data;
1385
1386 g_object_set_data (G_OBJECT (volume), "caja-allow-autorun", NULL);
1387 return FALSE;
1388 }
1389
1390 void
caja_allow_autorun_for_volume(GVolume * volume)1391 caja_allow_autorun_for_volume (GVolume *volume)
1392 {
1393 g_object_set_data (G_OBJECT (volume), "caja-allow-autorun", GINT_TO_POINTER (1));
1394 }
1395
1396 #define INHIBIT_AUTORUN_SECONDS 10
1397
1398 void
caja_allow_autorun_for_volume_finish(GVolume * volume)1399 caja_allow_autorun_for_volume_finish (GVolume *volume)
1400 {
1401 if (g_object_get_data (G_OBJECT (volume), "caja-allow-autorun") != NULL)
1402 {
1403 g_timeout_add_seconds_full (0,
1404 INHIBIT_AUTORUN_SECONDS,
1405 remove_allow_volume,
1406 g_object_ref (volume),
1407 g_object_unref);
1408 }
1409 }
1410
1411 static gboolean
should_skip_native_mount_root(GFile * root)1412 should_skip_native_mount_root (GFile *root)
1413 {
1414 char *path;
1415 gboolean should_skip;
1416
1417 /* skip any mounts in hidden directory hierarchies */
1418 path = g_file_get_path (root);
1419 should_skip = strstr (path, "/.") != NULL;
1420 g_free (path);
1421
1422 return should_skip;
1423 }
1424
1425 static gboolean
should_autorun_mount(GMount * mount)1426 should_autorun_mount (GMount *mount)
1427 {
1428 GFile *root;
1429 GVolume *enclosing_volume;
1430 gboolean ignore_autorun;
1431
1432 ignore_autorun = TRUE;
1433 enclosing_volume = g_mount_get_volume (mount);
1434 if (enclosing_volume != NULL)
1435 {
1436 if (g_object_get_data (G_OBJECT (enclosing_volume), "caja-allow-autorun") != NULL)
1437 {
1438 ignore_autorun = FALSE;
1439 g_object_set_data (G_OBJECT (enclosing_volume), "caja-allow-autorun", NULL);
1440 }
1441 }
1442
1443 if (ignore_autorun)
1444 {
1445 if (enclosing_volume != NULL)
1446 {
1447 g_object_unref (enclosing_volume);
1448 }
1449 return FALSE;
1450 }
1451
1452 root = g_mount_get_root (mount);
1453
1454 /* only do autorun on local files or files where g_volume_should_automount() returns TRUE */
1455 ignore_autorun = TRUE;
1456 if ((g_file_is_native (root) && !should_skip_native_mount_root (root)) ||
1457 (enclosing_volume != NULL && g_volume_should_automount (enclosing_volume)))
1458 {
1459 ignore_autorun = FALSE;
1460 }
1461 if (enclosing_volume != NULL)
1462 {
1463 g_object_unref (enclosing_volume);
1464 }
1465 g_object_unref (root);
1466
1467 return !ignore_autorun;
1468 }
1469