1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
6 * Copyright (C) 2008 Red Hat, Inc.
8 * Nautilus 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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Author: David Zeuthen <davidz@redhat.com>
27 #include <glib/gi18n.h>
31 #include <gio/gdesktopappinfo.h>
32 #include <X11/XKBlib.h>
34 #include <eel/eel-glib-extensions.h>
35 #include <eel/eel-stock-dialogs.h>
37 #include "nautilus-icon-info.h"
38 #include "nautilus-global-preferences.h"
39 #include "nautilus-file-operations.h"
40 #include "nautilus-autorun.h"
41 #include "nautilus-program-choosing.h"
42 #include "nautilus-open-with-dialog.h"
43 #include "nautilus-desktop-icon-file.h"
44 #include "nautilus-file-utilities.h"
56 COLUMN_AUTORUN_PIXBUF
,
58 COLUMN_AUTORUN_APP_INFO
,
59 COLUMN_AUTORUN_X_CONTENT_TYPE
,
60 COLUMN_AUTORUN_ITEM_TYPE
,
63 static gboolean
should_autorun_mount (GMount
*mount
);
66 nautilus_autorun_get_preferences (const char *x_content_type
,
68 gboolean
*pref_ignore
,
69 gboolean
*pref_open_folder
)
72 char **x_content_ignore
;
73 char **x_content_open_folder
;
75 g_return_if_fail (pref_ask
!= NULL
);
76 g_return_if_fail (pref_ignore
!= NULL
);
77 g_return_if_fail (pref_open_folder
!= NULL
);
81 *pref_open_folder
= FALSE
;
82 x_content_ask
= eel_preferences_get_string_array (NAUTILUS_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_ASK
);
83 x_content_ignore
= eel_preferences_get_string_array (NAUTILUS_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_IGNORE
);
84 x_content_open_folder
= eel_preferences_get_string_array (NAUTILUS_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER
);
85 if (x_content_ask
!= NULL
) {
86 *pref_ask
= eel_g_strv_find (x_content_ask
, x_content_type
) != -1;
88 if (x_content_ignore
!= NULL
) {
89 *pref_ignore
= eel_g_strv_find (x_content_ignore
, x_content_type
) != -1;
91 if (x_content_open_folder
!= NULL
) {
92 *pref_open_folder
= eel_g_strv_find (x_content_open_folder
, x_content_type
) != -1;
94 g_strfreev (x_content_ignore
);
95 g_strfreev (x_content_ask
);
100 remove_elem_from_str_array (char **v
, const char *s
)
103 for (n
= 0; v
[n
] != NULL
; n
++) {
104 if (strcmp (v
[n
], s
) == 0) {
105 for (m
= n
+ 1; v
[m
] != NULL
; m
++) {
115 add_elem_to_str_array (char **v
, const char *s
)
120 len
= g_strv_length (v
);
121 r
= g_new0 (char *, len
+ 2);
122 memcpy (r
, v
, len
* sizeof (char *));
123 r
[len
] = g_strdup (s
);
132 nautilus_autorun_set_preferences (const char *x_content_type
, gboolean pref_ask
, gboolean pref_ignore
, gboolean pref_open_folder
)
134 char **x_content_ask
;
135 char **x_content_ignore
;
136 char **x_content_open_folder
;
138 x_content_ask
= eel_preferences_get_string_array (NAUTILUS_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_ASK
);
139 x_content_ignore
= eel_preferences_get_string_array (NAUTILUS_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_IGNORE
);
140 x_content_open_folder
= eel_preferences_get_string_array (NAUTILUS_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER
);
142 remove_elem_from_str_array (x_content_ask
, x_content_type
);
144 x_content_ask
= add_elem_to_str_array (x_content_ask
, x_content_type
);
146 eel_preferences_set_string_array (NAUTILUS_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_ASK
, x_content_ask
);
148 remove_elem_from_str_array (x_content_ignore
, x_content_type
);
150 x_content_ignore
= add_elem_to_str_array (x_content_ignore
, x_content_type
);
152 eel_preferences_set_string_array (NAUTILUS_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_IGNORE
, x_content_ignore
);
154 remove_elem_from_str_array (x_content_open_folder
, x_content_type
);
155 if (pref_open_folder
) {
156 x_content_open_folder
= add_elem_to_str_array (x_content_open_folder
, x_content_type
);
158 eel_preferences_set_string_array (NAUTILUS_PREFERENCES_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER
, x_content_open_folder
);
160 g_strfreev (x_content_open_folder
);
161 g_strfreev (x_content_ignore
);
162 g_strfreev (x_content_ask
);
167 combo_box_separator_func (GtkTreeModel
*model
,
173 gtk_tree_model_get (model
, iter
,
185 guint changed_signal_id
;
186 GtkWidget
*combo_box
;
188 gboolean update_settings
;
189 NautilusAutorunComboBoxChanged changed_cb
;
191 } NautilusAutorunComboBoxData
;
194 nautilus_autorun_combobox_data_destroy (NautilusAutorunComboBoxData
*data
)
196 /* signal handler may be automatically disconnected by destroying the widget */
197 if (g_signal_handler_is_connected (G_OBJECT (data
->combo_box
), data
->changed_signal_id
)) {
198 g_signal_handler_disconnect (G_OBJECT (data
->combo_box
), data
->changed_signal_id
);
204 combo_box_changed (GtkComboBox
*combo_box
,
205 NautilusAutorunComboBoxData
*data
)
210 char *x_content_type
;
215 x_content_type
= NULL
;
217 if (!gtk_combo_box_get_active_iter (combo_box
, &iter
)) {
221 model
= gtk_combo_box_get_model (combo_box
);
226 gtk_tree_model_get (model
, &iter
,
227 COLUMN_AUTORUN_APP_INFO
, &app_info
,
228 COLUMN_AUTORUN_X_CONTENT_TYPE
, &x_content_type
,
229 COLUMN_AUTORUN_ITEM_TYPE
, &type
,
234 if (data
->changed_cb
!= NULL
) {
235 data
->changed_cb (TRUE
, FALSE
, FALSE
, NULL
, data
->user_data
);
237 if (data
->update_settings
) {
238 nautilus_autorun_set_preferences (x_content_type
, TRUE
, FALSE
, FALSE
);
242 if (data
->changed_cb
!= NULL
) {
243 data
->changed_cb (FALSE
, TRUE
, FALSE
, NULL
, data
->user_data
);
245 if (data
->update_settings
) {
246 nautilus_autorun_set_preferences (x_content_type
, FALSE
, TRUE
, FALSE
);
249 case AUTORUN_OPEN_FOLDER
:
250 if (data
->changed_cb
!= NULL
) {
251 data
->changed_cb (FALSE
, FALSE
, TRUE
, NULL
, data
->user_data
);
253 if (data
->update_settings
) {
254 nautilus_autorun_set_preferences (x_content_type
, FALSE
, FALSE
, TRUE
);
258 if (data
->changed_cb
!= NULL
) {
259 data
->changed_cb (FALSE
, FALSE
, FALSE
, app_info
, data
->user_data
);
261 if (data
->update_settings
) {
262 nautilus_autorun_set_preferences (x_content_type
, FALSE
, FALSE
, FALSE
);
263 g_app_info_set_as_default_for_type (app_info
,
271 if (app_info
!= NULL
) {
272 g_object_unref (app_info
);
275 g_object_unref (model
);
277 g_free (x_content_type
);
281 nautilus_autorun_prepare_combo_box (GtkWidget
*combo_box
,
282 const char *x_content_type
,
283 gboolean include_ask
,
284 gboolean update_settings
,
285 NautilusAutorunComboBoxChanged changed_cb
,
289 GList
*app_info_list
;
290 GAppInfo
*default_app_info
;
291 GtkListStore
*list_store
;
299 gboolean pref_ignore
;
300 gboolean pref_open_folder
;
301 NautilusAutorunComboBoxData
*data
;
302 GtkCellRenderer
*renderer
;
304 nautilus_autorun_get_preferences (x_content_type
, &pref_ask
, &pref_ignore
, &pref_open_folder
);
306 icon_size
= nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU
);
311 app_info_list
= g_app_info_get_all_for_type (x_content_type
);
312 default_app_info
= g_app_info_get_default_for_type (x_content_type
, FALSE
);
313 num_apps
= g_list_length (app_info_list
);
315 list_store
= gtk_list_store_new (5,
322 /* no apps installed */
324 gtk_list_store_append (list_store
, &iter
);
325 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
326 GTK_STOCK_DIALOG_ERROR
,
331 /* TODO: integrate with PackageKit-gnome to find applications */
333 gtk_list_store_set (list_store
, &iter
,
334 COLUMN_AUTORUN_PIXBUF
, pixbuf
,
335 COLUMN_AUTORUN_NAME
, _("No applications found"),
336 COLUMN_AUTORUN_APP_INFO
, NULL
,
337 COLUMN_AUTORUN_X_CONTENT_TYPE
, x_content_type
,
338 COLUMN_AUTORUN_ITEM_TYPE
, AUTORUN_ASK
,
340 g_object_unref (pixbuf
);
343 gtk_list_store_append (list_store
, &iter
);
344 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
345 GTK_STOCK_DIALOG_QUESTION
,
349 gtk_list_store_set (list_store
, &iter
,
350 COLUMN_AUTORUN_PIXBUF
, pixbuf
,
351 COLUMN_AUTORUN_NAME
, _("Ask what to do"),
352 COLUMN_AUTORUN_APP_INFO
, NULL
,
353 COLUMN_AUTORUN_X_CONTENT_TYPE
, x_content_type
,
354 COLUMN_AUTORUN_ITEM_TYPE
, AUTORUN_ASK
,
356 g_object_unref (pixbuf
);
359 gtk_list_store_append (list_store
, &iter
);
360 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
365 gtk_list_store_set (list_store
, &iter
,
366 COLUMN_AUTORUN_PIXBUF
, pixbuf
,
367 COLUMN_AUTORUN_NAME
, _("Do Nothing"),
368 COLUMN_AUTORUN_APP_INFO
, NULL
,
369 COLUMN_AUTORUN_X_CONTENT_TYPE
, x_content_type
,
370 COLUMN_AUTORUN_ITEM_TYPE
, AUTORUN_IGNORE
,
372 g_object_unref (pixbuf
);
374 gtk_list_store_append (list_store
, &iter
);
375 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
380 gtk_list_store_set (list_store
, &iter
,
381 COLUMN_AUTORUN_PIXBUF
, pixbuf
,
382 COLUMN_AUTORUN_NAME
, _("Open Folder"),
383 COLUMN_AUTORUN_APP_INFO
, NULL
,
384 COLUMN_AUTORUN_X_CONTENT_TYPE
, x_content_type
,
385 COLUMN_AUTORUN_ITEM_TYPE
, AUTORUN_OPEN_FOLDER
,
387 g_object_unref (pixbuf
);
389 gtk_list_store_append (list_store
, &iter
);
390 gtk_list_store_set (list_store
, &iter
,
391 COLUMN_AUTORUN_PIXBUF
, NULL
,
392 COLUMN_AUTORUN_NAME
, NULL
,
393 COLUMN_AUTORUN_APP_INFO
, NULL
,
394 COLUMN_AUTORUN_X_CONTENT_TYPE
, NULL
,
395 COLUMN_AUTORUN_ITEM_TYPE
, AUTORUN_SEP
,
398 for (l
= app_info_list
, n
= include_ask
? 4 : 3; l
!= NULL
; l
= l
->next
, n
++) {
400 NautilusIconInfo
*icon_info
;
402 GAppInfo
*app_info
= l
->data
;
404 /* we deliberately ignore should_show because some apps might want
405 * to install special handlers that should be hidden in the regular
406 * application launcher menus
409 icon
= g_app_info_get_icon (app_info
);
410 icon_info
= nautilus_icon_info_lookup (icon
, icon_size
);
411 pixbuf
= nautilus_icon_info_get_pixbuf_at_size (icon_info
, icon_size
);
412 g_object_unref (icon_info
);
414 open_string
= g_strdup_printf (_("Open %s"), g_app_info_get_name (app_info
));
416 gtk_list_store_append (list_store
, &iter
);
417 gtk_list_store_set (list_store
, &iter
,
418 COLUMN_AUTORUN_PIXBUF
, pixbuf
,
419 COLUMN_AUTORUN_NAME
, open_string
,
420 COLUMN_AUTORUN_APP_INFO
, app_info
,
421 COLUMN_AUTORUN_X_CONTENT_TYPE
, x_content_type
,
422 COLUMN_AUTORUN_ITEM_TYPE
, AUTORUN_APP
,
424 if (pixbuf
!= NULL
) {
425 g_object_unref (pixbuf
);
427 g_free (open_string
);
429 if (g_app_info_equal (app_info
, default_app_info
)) {
435 if (default_app_info
!= NULL
) {
436 g_object_unref (default_app_info
);
438 eel_g_object_list_free (app_info_list
);
440 gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box
), GTK_TREE_MODEL (list_store
));
442 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box
));
444 renderer
= gtk_cell_renderer_pixbuf_new ();
445 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box
), renderer
, FALSE
);
446 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box
), renderer
,
447 "pixbuf", COLUMN_AUTORUN_PIXBUF
,
449 renderer
= gtk_cell_renderer_text_new ();
450 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box
), renderer
, TRUE
);
451 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box
), renderer
,
452 "text", COLUMN_AUTORUN_NAME
,
454 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo_box
), combo_box_separator_func
, NULL
, NULL
);
457 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box
), 0);
458 gtk_widget_set_sensitive (combo_box
, FALSE
);
460 gtk_widget_set_sensitive (combo_box
, TRUE
);
461 if (pref_ask
&& include_ask
) {
462 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box
), 0);
463 } else if (pref_ignore
) {
464 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box
), include_ask
? 1 : 0);
465 } else if (pref_open_folder
) {
466 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box
), include_ask
? 2 : 1);
467 } else if (set_active
!= -1) {
468 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box
), set_active
);
470 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box
), include_ask
? 1 : 0);
473 data
= g_new0 (NautilusAutorunComboBoxData
, 1);
474 data
->update_settings
= update_settings
;
475 data
->changed_cb
= changed_cb
;
476 data
->user_data
= user_data
;
477 data
->combo_box
= combo_box
;
478 data
->changed_signal_id
= g_signal_connect (G_OBJECT (combo_box
),
480 G_CALLBACK (combo_box_changed
),
484 g_object_set_data_full (G_OBJECT (combo_box
),
485 "nautilus_autorun_combobox_data",
487 (GDestroyNotify
) nautilus_autorun_combobox_data_destroy
);
491 is_shift_pressed (void)
499 gdk_error_trap_push ();
500 status
= XkbGetState (GDK_DISPLAY (), XkbUseCoreKbd
, &state
);
501 gdk_error_trap_pop ();
503 if (status
== Success
) {
504 ret
= state
.mods
& ShiftMask
;
510 /*-- BEGIN MOVE TO GIO --*/
513 _check_nonempty_dir (GFile
*mount_root
, const char *dirname
)
516 GFileInfo
*file_info
;
517 GFileEnumerator
*file_enum
;
522 file
= g_file_get_child (mount_root
, dirname
);
523 file_enum
= g_file_enumerate_children (file
,
524 G_FILE_ATTRIBUTE_STANDARD_NAME
,
525 G_FILE_QUERY_INFO_NONE
,
528 if (file_enum
!= NULL
) {
529 file_info
= g_file_enumerator_next_file (file_enum
, NULL
, NULL
);
530 if (file_info
!= NULL
) {
532 g_object_unref (file_info
);
534 g_object_unref (file_enum
);
536 g_object_unref (file
);
542 _check_file_common (GFile
*file
, gboolean must_be_executable
)
544 GFileInfo
*file_info
;
549 file_info
= g_file_query_info (file
,
550 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE
,
551 G_FILE_QUERY_INFO_NONE
,
554 if (file_info
!= NULL
) {
555 if (must_be_executable
) {
556 if (g_file_info_get_attribute_boolean (file_info
, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE
))
561 g_object_unref (file_info
);
563 g_object_unref (file
);
569 _check_file (GFile
*mount_root
, const char *file_path
,
570 gboolean must_be_executable
)
572 /* Unreffed in _check_file_common() */
573 GFile
*file
= g_file_get_child (mount_root
, file_path
);
574 return _check_file_common (file
, must_be_executable
);
578 _check_file_case_insensitive (GFile
*mount_root
, const char *file_path
,
579 gboolean must_be_executable
)
581 /* Unreffed in _check_file_common() */
582 GFile
*file
= nautilus_find_file_insensitive (mount_root
, file_path
);
583 return _check_file_common (file
, must_be_executable
);
587 * _g_mount_guess_content_type:
589 * @force_rescan: Whether to force a rescan of the content. Otherwise a cached result will be used if available.
590 * @error: return location for error or %NULL to ignore.
592 * Tries to guess the type of content stored on @mount. Returns one or
593 * more textual identifiers of well-known content types (typically
594 * prefixed with "x-content/"). TODO: link to fd.o spec about this.
596 * This function may do I/O and thus may take a long time to
597 * complete. For the async version, see
598 * _g_mount_guess_content_type_async().
600 * Returns: a %NULL terminated array of content types or %NULL on
601 * error. Caller should free this array with g_strfreev() when done
605 _g_mount_guess_content_type (GMount
*mount
,
606 gboolean force_rescan
,
614 char *disc_type
= NULL
;
616 /* TODO: This cache handling isn't really threadsafe.
617 * I think this is ok for nautilus use, but not for general gio use
619 ret
= g_object_get_data (G_OBJECT (mount
), "content-type-cache");
621 return g_strdupv (ret
);
624 types
= g_ptr_array_new ();
626 root
= g_mount_get_root (mount
);
627 volume
= g_mount_get_volume (mount
);
629 /* Take advantage of information from HAL's quirk lists that maps a given
630 * make/model of (what appears to be just) a storage device to it's intended
633 * E.g. a mapping saying that a storage device is a music player, a digital
634 * camera, a videocam, a video play back device, a gps reader.. and so on...
636 if (volume
!= NULL
) {
637 char **stor_device_caps
;
639 /* See gvfs/hal/ghalvolume.c:do_update_from_hal()...
641 * This hack, using g_object_set|get_data() can be
642 * removed once g_mount_guess_content_type() is in gio
643 * and the actual code for probing media is in the
646 stor_device_caps
= (char **) g_object_get_data (G_OBJECT (volume
), "hal-storage-device-capabilities");
647 if (stor_device_caps
!= NULL
) {
648 for (n
= 0; stor_device_caps
[n
] != NULL
; n
++) {
649 if (strcmp (stor_device_caps
[n
], "portable_audio_player") == 0) {
650 g_ptr_array_add (types
, g_strdup ("x-content/audio-player"));
652 /* TODO: map other hal capabilities to x-content/ types */
656 disc_type
= (char *) g_object_get_data (G_OBJECT (volume
), "hal-volume.disc.type");
659 if (g_file_has_uri_scheme (root
, "cdda")) {
660 g_ptr_array_add (types
, g_strdup ("x-content/audio-cdda"));
664 if (g_file_has_uri_scheme (root
, "burn")) {
665 if (disc_type
!= NULL
) {
666 if (g_str_has_prefix (disc_type
, "dvd")) {
667 g_ptr_array_add (types
, g_strdup ("x-content/blank-dvd"));
668 } else if (g_str_has_prefix (disc_type
, "hddvd")) {
669 g_ptr_array_add (types
, g_strdup ("x-content/blank-hddvd"));
670 } else if (g_str_has_prefix (disc_type
, "bd")) {
671 g_ptr_array_add (types
, g_strdup ("x-content/blank-bd"));
674 g_ptr_array_add (types
, g_strdup ("x-content/blank-cd"));
680 if (_check_nonempty_dir (root
, "DCIM") ||
681 _check_nonempty_dir (root
, "dcim")) {
682 g_ptr_array_add (types
, g_strdup ("x-content/image-dcf"));
685 if (_check_nonempty_dir (root
, "VIDEO_TS") &&
687 g_ptr_array_add (types
, g_strdup ("x-content/video-dvd"));
690 if (_check_nonempty_dir (root
, "AUDIO_TS") &&
692 g_ptr_array_add (types
, g_strdup ("x-content/audio-dvd"));
696 /* see http://www.ccs.neu.edu/home/bchafy/cdb/info/info.html for various docs */
698 if (_check_nonempty_dir (root
, "SVCD") &&
699 _check_nonempty_dir (root
, "EXT") &&
700 _check_nonempty_dir (root
, "MPEG-2") &&
702 /* http://everything2.com/index.pl?node_id=1009222 */
703 g_ptr_array_add (types
, g_strdup ("x-content/video-svcd"));
706 if (_check_nonempty_dir (root
, "VCD") &&
707 _check_nonempty_dir (root
, "MPEGAV") &&
709 /* http://www.herongyang.com/CD-DVD/VCD-Movie-File-Directory-Structure.html */
710 g_ptr_array_add (types
, g_strdup ("x-content/video-vcd"));
713 if (_check_nonempty_dir (root
, "BDAV") &&
714 _check_nonempty_dir (root
, "BDMV") &&
716 /* http://www.blu-raydisc.com/Section-13470/Section-13890/Index.html */
717 g_ptr_array_add (types
, g_strdup ("x-content/video-bluray"));
720 if (_check_nonempty_dir (root
, "HVDVD_TS") && /* not a typo; should really spell HVDVD_TS */
722 /* http://www.cdfreaks.com/reviews/CDFreaks--CES-2006/Page-5.html */
723 g_ptr_array_add (types
, g_strdup ("x-content/video-hddvd"));
726 if (_check_nonempty_dir (root
, "PICTURES") &&
728 /* http://www.re.org/kristin/picturecd.html */
729 g_ptr_array_add (types
, g_strdup ("x-content/image-picturecd"));
732 if (_check_file (root
, ".autorun", TRUE
) ||
733 _check_file (root
, "autorun", TRUE
) ||
734 _check_file (root
, "autorun.sh", TRUE
) ||
735 _check_file_case_insensitive (root
, "autorun.exe", TRUE
) ||
736 _check_file_case_insensitive (root
, "autorun.inf", FALSE
)) {
737 /* http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html */
739 /* http://bugzilla.gnome.org/show_bug.cgi?id=509823#c3 for the autorun.exe and autorun.inf stuff */
740 g_ptr_array_add (types
, g_strdup ("x-content/software"));
746 g_ptr_array_add (types
, NULL
);
747 ret
= (char **) g_ptr_array_free (types
, FALSE
);
749 if (volume
!= NULL
) {
750 g_object_unref (volume
);
752 g_object_unref (root
);
754 g_object_set_data_full (G_OBJECT (mount
),
755 "content-type-cache",
757 (GDestroyNotify
)g_strfreev
);
763 char **guessed_content_type
;
764 gboolean force_rescan
;
768 guess_content_thread (GSimpleAsyncResult
*res
,
770 GCancellable
*cancellable
)
772 GuessContentData
*op
;
773 GError
*error
= NULL
;
775 op
= g_simple_async_result_get_op_res_gpointer (res
);
777 op
->guessed_content_type
= _g_mount_guess_content_type (G_MOUNT (object
), op
->force_rescan
, &error
);
780 g_simple_async_result_set_from_error (res
, error
);
781 g_error_free (error
);
786 * _g_mount_guess_content_type_async:
788 * @force_rescan: Whether to force a rescan of the content. Otherwise a cached result will be used if available.
789 * @cancellable: optional #GCancellable object, %NULL to ignore.
790 * @callback: a #GAsyncReadyCallback.
791 * @user_data: user data passed to @callback.
793 * This is an asynchronous version of _g_mount_guess_content_type(),
794 * and is finished by calling _g_mount_guess_content_type_finish() with
795 * the @mount and #GAsyncResults data returned in the @callback.
798 _g_mount_guess_content_type_async (GMount
*mount
,
799 gboolean force_rescan
,
800 GCancellable
*cancellable
,
801 GAsyncReadyCallback callback
,
804 GSimpleAsyncResult
*res
;
805 GuessContentData
*op
;
807 op
= g_new0 (GuessContentData
, 1);
808 op
->force_rescan
= force_rescan
;
809 res
= g_simple_async_result_new (G_OBJECT (mount
),
812 _g_mount_guess_content_type_async
);
813 g_simple_async_result_set_op_res_gpointer (res
, op
, g_free
);
815 g_simple_async_result_run_in_thread (res
, guess_content_thread
, G_PRIORITY_DEFAULT
, cancellable
);
816 g_object_unref (res
);
820 * _g_mount_guess_content_type_finish:
822 * @result: a #GAsyncResult.
823 * @error: a #GError location to store the error occuring, or %NULL to
826 * Finishes guessing content types of @mount. If any errors occured
827 * during the operation, @error will be set to contain the errors and
828 * %FALSE will be returned.
830 * Returns: a %NULL terminated array of content types or %NULL on
831 * error. Caller should free this array with g_strfreev() when done
835 _g_mount_guess_content_type_finish (GMount
*mount
,
836 GAsyncResult
*result
,
839 GSimpleAsyncResult
*simple
= G_SIMPLE_ASYNC_RESULT (result
);
840 GuessContentData
*op
;
842 g_warn_if_fail (g_simple_async_result_get_source_tag (simple
) == _g_mount_guess_content_type_async
);
844 op
= g_simple_async_result_get_op_res_gpointer (simple
);
845 return op
->guessed_content_type
;
849 /*- END MOVE TO GIO ---*/
856 gboolean should_eject
;
858 gboolean selected_ignore
;
859 gboolean selected_open_folder
;
860 GAppInfo
*selected_app
;
864 char *x_content_type
;
866 NautilusAutorunOpenWindow open_window_func
;
872 nautilus_autorun_launch_for_mount (GMount
*mount
, GAppInfo
*app_info
)
878 root
= g_mount_get_root (mount
);
879 file
= nautilus_file_get (root
);
880 g_object_unref (root
);
881 files
= g_list_append (NULL
, file
);
882 nautilus_launch_application (app_info
,
884 NULL
); /* TODO: what to set here? */
885 g_object_unref (file
);
889 static void autorun_dialog_mount_unmounted (GMount
*mount
, AutorunDialogData
*data
);
892 autorun_dialog_destroy (AutorunDialogData
*data
)
894 g_signal_handlers_disconnect_by_func (G_OBJECT (data
->mount
),
895 G_CALLBACK (autorun_dialog_mount_unmounted
),
898 gtk_widget_destroy (GTK_WIDGET (data
->dialog
));
899 if (data
->selected_app
!= NULL
) {
900 g_object_unref (data
->selected_app
);
902 g_object_unref (data
->mount
);
903 g_free (data
->x_content_type
);
908 autorun_dialog_mount_unmounted (GMount
*mount
, AutorunDialogData
*data
)
910 /* remove the dialog if the media is unmounted */
911 autorun_dialog_destroy (data
);
915 autorun_dialog_response (GtkDialog
*dialog
, gint response
, AutorunDialogData
*data
)
918 case GTK_RESPONSE_NONE
:
919 /* window was closed */
921 case GTK_RESPONSE_CANCEL
:
923 case GTK_RESPONSE_OK
:
924 /* do the selected action */
926 if (data
->remember
) {
927 /* make sure we don't ask again */
928 nautilus_autorun_set_preferences (data
->x_content_type
, FALSE
, data
->selected_ignore
, data
->selected_open_folder
);
929 if (!data
->selected_ignore
&& !data
->selected_open_folder
&& data
->selected_app
!= NULL
) {
930 g_app_info_set_as_default_for_type (data
->selected_app
,
931 data
->x_content_type
,
935 /* make sure we do ask again */
936 nautilus_autorun_set_preferences (data
->x_content_type
, TRUE
, FALSE
, FALSE
);
939 if (!data
->selected_ignore
&& !data
->selected_open_folder
&& data
->selected_app
!= NULL
) {
940 nautilus_autorun_launch_for_mount (data
->mount
, data
->selected_app
);
941 } else if (!data
->selected_ignore
&& data
->selected_open_folder
) {
942 if (data
->open_window_func
!= NULL
)
943 data
->open_window_func (data
->mount
, data
->user_data
);
948 autorun_dialog_destroy (data
);
952 autorun_combo_changed (gboolean selected_ask
,
953 gboolean selected_ignore
,
954 gboolean selected_open_folder
,
955 GAppInfo
*selected_app
,
958 AutorunDialogData
*data
= user_data
;
960 if (data
->selected_app
!= NULL
) {
961 g_object_unref (data
->selected_app
);
963 data
->selected_app
= selected_app
!= NULL
? g_object_ref (selected_app
) : NULL
;
964 data
->selected_ignore
= selected_ignore
;
965 data
->selected_open_folder
= selected_open_folder
;
970 autorun_always_toggled (GtkToggleButton
*togglebutton
, AutorunDialogData
*data
)
972 data
->remember
= gtk_toggle_button_get_active (togglebutton
);
976 /* returns TRUE if a folder window should be opened */
978 do_autorun_for_content_type (GMount
*mount
, const char *x_content_type
, NautilusAutorunOpenWindow open_window_func
, gpointer user_data
)
980 AutorunDialogData
*data
;
985 GtkWidget
*combo_box
;
986 GtkWidget
*always_check_button
;
987 GtkWidget
*eject_button
;
990 char *content_description
;
994 NautilusIconInfo
*icon_info
;
996 gboolean user_forced_dialog
;
998 gboolean pref_ignore
;
999 gboolean pref_open_folder
;
1000 char *media_greeting
;
1006 user_forced_dialog
= is_shift_pressed ();
1008 nautilus_autorun_get_preferences (x_content_type
, &pref_ask
, &pref_ignore
, &pref_open_folder
);
1010 if (user_forced_dialog
) {
1014 if (!pref_ask
&& !pref_ignore
&& !pref_open_folder
) {
1016 app_info
= g_app_info_get_default_for_type (x_content_type
, FALSE
);
1017 if (app_info
!= NULL
) {
1018 nautilus_autorun_launch_for_mount (mount
, app_info
);
1023 if (pref_open_folder
) {
1034 mount_name
= g_mount_get_name (mount
);
1036 dialog
= gtk_dialog_new ();
1038 gtk_dialog_set_has_separator (GTK_DIALOG (dialog
), FALSE
);
1039 hbox
= gtk_hbox_new (FALSE
, 12);
1040 gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dialog
)->vbox
), hbox
);
1041 gtk_container_set_border_width (GTK_CONTAINER (hbox
), 12);
1043 icon
= g_mount_get_icon (mount
);
1044 icon_size
= nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_DIALOG
);
1045 icon_info
= nautilus_icon_info_lookup (icon
, icon_size
);
1046 pixbuf
= nautilus_icon_info_get_pixbuf_at_size (icon_info
, icon_size
);
1047 g_object_unref (icon_info
);
1048 g_object_unref (icon
);
1049 image
= gtk_image_new_from_pixbuf (pixbuf
);
1050 gtk_misc_set_alignment (GTK_MISC (image
), 0.5, 0.0);
1051 gtk_box_pack_start_defaults (GTK_BOX (hbox
), image
);
1052 /* also use the icon on the dialog */
1053 gtk_window_set_title (GTK_WINDOW (dialog
), mount_name
);
1054 gtk_window_set_icon (GTK_WINDOW (dialog
), pixbuf
);
1055 g_object_unref (pixbuf
);
1057 vbox
= gtk_vbox_new (FALSE
, 12);
1058 gtk_box_pack_start_defaults (GTK_BOX (hbox
), vbox
);
1060 label
= gtk_label_new (NULL
);
1063 /* Customize greeting for well-known x-content types */
1064 if (strcmp (x_content_type
, "x-content/audio-cdda") == 0) {
1065 media_greeting
= _("You have just inserted an Audio CD.");
1066 } else if (strcmp (x_content_type
, "x-content/audio-dvd") == 0) {
1067 media_greeting
= _("You have just inserted an Audio DVD.");
1068 } else if (strcmp (x_content_type
, "x-content/video-dvd") == 0) {
1069 media_greeting
= _("You have just inserted a Video DVD.");
1070 } else if (strcmp (x_content_type
, "x-content/video-vcd") == 0) {
1071 media_greeting
= _("You have just inserted a Video CD.");
1072 } else if (strcmp (x_content_type
, "x-content/video-svcd") == 0) {
1073 media_greeting
= _("You have just inserted a Super Video CD.");
1074 } else if (strcmp (x_content_type
, "x-content/blank-cd") == 0) {
1075 media_greeting
= _("You have just inserted a blank CD.");
1076 } else if (strcmp (x_content_type
, "x-content/blank-dvd") == 0) {
1077 media_greeting
= _("You have just inserted a blank DVD.");
1078 } else if (strcmp (x_content_type
, "x-content/blank-cd") == 0) {
1079 media_greeting
= _("You have just inserted a blank Blu-Ray disc.");
1080 } else if (strcmp (x_content_type
, "x-content/blank-cd") == 0) {
1081 media_greeting
= _("You have just inserted a blank HD DVD.");
1082 } else if (strcmp (x_content_type
, "x-content/image-photocd") == 0) {
1083 media_greeting
= _("You have just inserted a Photo CD.");
1084 } else if (strcmp (x_content_type
, "x-content/image-picturecd") == 0) {
1085 media_greeting
= _("You have just inserted a Picture CD.");
1086 } else if (strcmp (x_content_type
, "x-content/image-dcf") == 0) {
1087 media_greeting
= _("You have just inserted media with digital photos.");
1088 } else if (strcmp (x_content_type
, "x-content/audio-player") == 0) {
1089 media_greeting
= _("You have just inserted a digital audio player.");
1090 } else if (strcmp (x_content_type
, "x-content/software") == 0) {
1091 media_greeting
= _("You have just inserted media with software intended to be automatically started.");
1093 /* fallback to generic greeting */
1094 media_greeting
= _("You have just inserted media.");
1096 markup
= g_strdup_printf ("<big><b>%s %s</b></big>", media_greeting
, _("Choose what application to launch."));
1097 gtk_label_set_markup (GTK_LABEL (label
), markup
);
1099 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
1100 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1101 gtk_box_pack_start_defaults (GTK_BOX (vbox
), label
);
1103 label
= gtk_label_new (NULL
);
1104 content_description
= g_content_type_get_description (x_content_type
);
1105 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
);
1106 g_free (content_description
);
1107 gtk_label_set_markup (GTK_LABEL (label
), markup
);
1109 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
1110 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1111 gtk_box_pack_start_defaults (GTK_BOX (vbox
), label
);
1113 data
= g_new0 (AutorunDialogData
, 1);
1114 data
->dialog
= dialog
;
1115 data
->mount
= g_object_ref (mount
);
1116 data
->remember
= !pref_ask
;
1117 data
->selected_ignore
= pref_ignore
;
1118 data
->x_content_type
= g_strdup (x_content_type
);
1119 data
->selected_app
= g_app_info_get_default_for_type (x_content_type
, FALSE
);
1120 data
->open_window_func
= open_window_func
;
1121 data
->user_data
= user_data
;
1123 combo_box
= gtk_combo_box_new ();
1124 nautilus_autorun_prepare_combo_box (combo_box
, x_content_type
, FALSE
, FALSE
, autorun_combo_changed
, data
);
1125 gtk_box_pack_start_defaults (GTK_BOX (vbox
), combo_box
);
1127 always_check_button
= gtk_check_button_new_with_mnemonic (_("_Always perform this action"));
1128 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (always_check_button
), data
->remember
);
1129 g_signal_connect (G_OBJECT (always_check_button
),
1131 G_CALLBACK (autorun_always_toggled
),
1133 gtk_box_pack_start_defaults (GTK_BOX (vbox
), always_check_button
);
1135 gtk_dialog_add_buttons (GTK_DIALOG (dialog
),
1136 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
1137 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
1139 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_OK
);
1141 if (g_mount_can_eject (mount
)) {
1142 GtkWidget
*eject_image
;
1143 eject_button
= gtk_button_new_with_mnemonic (_("_Eject"));
1144 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1146 nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_BUTTON
),
1149 eject_image
= gtk_image_new_from_pixbuf (pixbuf
);
1150 g_object_unref (pixbuf
);
1151 gtk_button_set_image (GTK_BUTTON (eject_button
), eject_image
);
1152 data
->should_eject
= TRUE
;
1154 eject_button
= gtk_button_new_with_mnemonic (_("_Unmount"));
1155 data
->should_eject
= FALSE
;
1157 gtk_dialog_add_action_widget (GTK_DIALOG (dialog
), eject_button
, 0);
1158 gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (GTK_DIALOG (dialog
)->action_area
), eject_button
, TRUE
);
1160 /* show the dialog */
1161 gtk_widget_show_all (dialog
);
1163 g_signal_connect (G_OBJECT (dialog
),
1165 G_CALLBACK (autorun_dialog_response
),
1168 g_signal_connect (G_OBJECT (data
->mount
),
1170 G_CALLBACK (autorun_dialog_mount_unmounted
),
1174 g_free (mount_name
);
1180 NautilusAutorunOpenWindow open_window_func
;
1186 autorun_open_folder_for_mount (AutorunData
*data
)
1188 if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_MEDIA_AUTOMOUNT_OPEN
) &&
1189 data
->open_window_func
!= NULL
)
1190 data
->open_window_func (data
->mount
, data
->user_data
);
1194 autorun_guessed_content_type_callback (GObject
*source_object
,
1199 char **guessed_content_type
;
1200 AutorunData
*data
= user_data
;
1201 gboolean open_folder
;
1203 open_folder
= FALSE
;
1206 guessed_content_type
= _g_mount_guess_content_type_finish (G_MOUNT (source_object
), res
, &error
);
1207 if (error
!= NULL
) {
1208 g_warning ("Unabled to guess content type for mount: %s", error
->message
);
1209 g_error_free (error
);
1211 if (guessed_content_type
!= NULL
&& g_strv_length (guessed_content_type
) > 0) {
1213 for (n
= 0; guessed_content_type
[n
] != NULL
; n
++) {
1214 if (do_autorun_for_content_type (data
->mount
, guessed_content_type
[n
],
1215 data
->open_window_func
, data
->user_data
)) {
1219 g_strfreev (guessed_content_type
);
1225 /* only open the folder once.. */
1227 autorun_open_folder_for_mount (data
);
1230 g_object_unref (data
->mount
);
1235 nautilus_autorun (GMount
*mount
, NautilusAutorunOpenWindow open_window_func
, gpointer user_data
)
1239 if (!should_autorun_mount (mount
) ||
1240 eel_preferences_get_boolean (NAUTILUS_PREFERENCES_MEDIA_AUTORUN_NEVER
)) {
1244 /* Sniff the newly added mount to generate x-content/ types;
1245 * we do this asynchronously (in another thread) since it
1246 * requires doing I/O.
1249 data
= g_new0 (AutorunData
, 1);
1250 data
->mount
= g_object_ref (mount
);
1251 data
->open_window_func
= open_window_func
;
1252 data
->user_data
= user_data
;
1254 _g_mount_guess_content_type_async (mount
,
1257 autorun_guessed_content_type_callback
,
1262 nautilus_autorun_get_x_content_types_for_mount (GMount
*mount
,
1263 gboolean force_rescan
)
1265 if (mount
== NULL
) {
1269 /* since we always guess the content type at mount type, we're guaranteed
1270 * to get the cached results
1272 * TODO: Really? what if we didn't mount the mount ourself?
1274 return _g_mount_guess_content_type (mount
, force_rescan
, NULL
);
1278 static GList
*inhibit_mount_handling_for
= NULL
;
1282 remove_inhibit_file_cb (gpointer data
)
1287 l
= g_list_find (inhibit_mount_handling_for
, file
);
1289 inhibit_mount_handling_for
= g_list_delete_link (inhibit_mount_handling_for
, l
);
1290 g_object_unref (file
);
1297 nautilus_inhibit_autorun_for_file (GFile
*file
)
1299 inhibit_mount_handling_for
= g_list_prepend (inhibit_mount_handling_for
, g_object_ref (file
));
1300 g_timeout_add_full (0,
1302 remove_inhibit_file_cb
,
1303 g_object_ref (file
),
1308 remove_inhibit_volume (gpointer data
)
1310 GVolume
*volume
= data
;
1312 g_object_set_data (G_OBJECT (volume
), "nautilus-inhibit-autorun", NULL
);
1317 nautilus_inhibit_autorun_for_volume (GVolume
*volume
)
1319 g_object_set_data (G_OBJECT (volume
), "nautilus-inhibit-autorun", GINT_TO_POINTER (1));
1320 g_timeout_add_full (0,
1322 remove_inhibit_volume
,
1323 g_object_ref (volume
),
1328 should_autorun_mount (GMount
*mount
)
1332 GVolume
*enclosing_volume
;
1333 gboolean ignore_autorun
;
1335 ignore_autorun
= FALSE
;
1336 enclosing_volume
= g_mount_get_volume (mount
);
1337 if (enclosing_volume
!= NULL
) {
1338 if (g_object_get_data (G_OBJECT (enclosing_volume
), "nautilus-inhibit-autorun") != NULL
) {
1339 ignore_autorun
= TRUE
;
1340 g_object_set_data (G_OBJECT (enclosing_volume
), "nautilus-inhibit-autorun", NULL
);
1342 g_object_unref (enclosing_volume
);
1345 if (ignore_autorun
) {
1349 root
= g_mount_get_root (mount
);
1351 for (l
= inhibit_mount_handling_for
; l
!= NULL
; l
= l
->next
) {
1353 if (g_file_contains_file (root
, file
)) {
1354 ignore_autorun
= TRUE
;
1356 inhibit_mount_handling_for
= g_list_delete_link (inhibit_mount_handling_for
, l
);
1357 g_object_unref (file
);
1363 if (!g_file_is_native (root
)) {
1364 /* only do autorun on local files */
1365 /* TODO: Maybe we should do this on some gvfs mounts? like gphoto: ? */
1366 ignore_autorun
= TRUE
;
1368 g_object_unref (root
);
1370 return !ignore_autorun
;