1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* nemo-file-utilities.c - implementation of file manipulation routines.
4
5 Copyright (C) 1999, 2000, 2001 Eazel, Inc.
6
7 The Gnome Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 The Gnome Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with the Gnome Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
20 Boston, MA 02110-1335, USA.
21
22 Authors: John Sullivan <sullivan@eazel.com>
23 */
24
25 #include <config.h>
26 #include "nemo-file-utilities.h"
27
28 #include "nemo-global-preferences.h"
29 #include "nemo-lib-self-check-functions.h"
30 #include "nemo-metadata.h"
31 #include "nemo-file.h"
32 #include "nemo-file-operations.h"
33 #include "nemo-search-directory.h"
34 #include "nemo-signaller.h"
35 #include "nemo-statx.h"
36 #include <eel/eel-glib-extensions.h>
37 #include <eel/eel-stock-dialogs.h>
38 #include <eel/eel-string.h>
39 #include <eel/eel-debug.h>
40 #include <glib.h>
41 #include <glib/gi18n.h>
42 #include <glib/gstdio.h>
43 #include <gio/gio.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46
47 #define NEMO_USER_DIRECTORY_NAME "nemo"
48
49 #define DESKTOP_DIRECTORY_NAME "Desktop"
50 #define LEGACY_DESKTOP_DIRECTORY_NAME ".gnome-desktop"
51
52 static void update_xdg_dir_cache (void);
53 static void schedule_user_dirs_changed (void);
54 static void desktop_dir_changed (void);
55 static GFile *nemo_find_file_insensitive_next (GFile *parent, const gchar *name);
56
57 char *
nemo_compute_title_for_location(GFile * location)58 nemo_compute_title_for_location (GFile *location)
59 {
60 NemoFile *file;
61 char *title;
62 char *builder;
63 /* TODO-gio: This doesn't really work all that great if the
64 info about the file isn't known atm... */
65
66 if (nemo_is_home_directory (location)) {
67 return g_strdup (_("Home"));
68 }
69
70 builder = NULL;
71 if (location) {
72 file = nemo_file_get (location);
73 builder = nemo_file_get_description (file);
74 if (builder == NULL) {
75 builder = nemo_file_get_display_name (file);
76 }
77 nemo_file_unref (file);
78 }
79
80 if (builder == NULL) {
81 builder = g_file_get_basename (location);
82 }
83
84 if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_FULL_PATH_TITLES)) {
85 gchar *uri, *path;
86 file = nemo_file_get (location);
87
88 uri = nemo_file_get_uri (file);
89 path = g_filename_from_uri (uri, NULL, NULL);
90
91 if (path != NULL) {
92 title = g_strdup_printf("%s - %s", builder, path);
93 } else {
94 title = g_strdup_printf("%s - %s", builder, uri);
95 }
96 nemo_file_unref (file);
97 g_free (uri);
98 g_free (path);
99 g_free (builder);
100 } else {
101 title = g_strdup(builder);
102 g_free (builder);
103 }
104 return title;
105 }
106
107 // TODO: Maybe this can replace nemo_compute_title_for_location() all around?
108 char *
nemo_compute_search_title_for_location(GFile * location)109 nemo_compute_search_title_for_location (GFile *location)
110 {
111 GFile *home_file;
112 gchar *location_string;
113
114 if (nemo_is_home_directory (location)) {
115 return g_strdup (_("Home"));
116 }
117
118 home_file = g_file_new_for_path (g_get_home_dir ());
119
120 location_string = NULL;
121
122 location_string = g_file_get_relative_path (home_file, location);
123
124 if (location_string == NULL) {
125 if (g_file_is_native (location)) {
126 location_string = g_file_get_path (location);
127 } else {
128 location_string = g_file_get_uri (location);
129 }
130 }
131
132 g_object_unref (home_file);
133
134 return location_string;
135 }
136
137 /**
138 * nemo_get_user_directory:
139 *
140 * Get the path for the directory containing nemo settings.
141 *
142 * Return value: the directory path.
143 **/
144 char *
nemo_get_user_directory(void)145 nemo_get_user_directory (void)
146 {
147 char *user_directory = NULL;
148
149 user_directory = g_build_filename (g_get_user_config_dir (),
150 NEMO_USER_DIRECTORY_NAME,
151 NULL);
152
153 if (!g_file_test (user_directory, G_FILE_TEST_EXISTS)) {
154 g_mkdir_with_parents (user_directory, DEFAULT_NEMO_DIRECTORY_MODE);
155 /* FIXME bugzilla.gnome.org 41286:
156 * How should we handle the case where this mkdir fails?
157 * Note that nemo_application_startup will refuse to launch if this
158 * directory doesn't get created, so that case is OK. But the directory
159 * could be deleted after Nemo was launched, and perhaps
160 * there is some bad side-effect of not handling that case.
161 */
162 }
163
164 return user_directory;
165 }
166
167 /**
168 * nemo_get_accel_map_file:
169 *
170 * Get the path for the filename containing nemo accelerator map.
171 * The filename need not exist.
172 *
173 * Return value: the filename path, or NULL if the home directory could not be found
174 **/
175 char *
nemo_get_accel_map_file(void)176 nemo_get_accel_map_file (void)
177 {
178 const gchar *override;
179
180 override = g_getenv ("GNOME22_USER_DIR");
181
182 if (override) {
183 return g_build_filename (override, "accels/nemo", NULL);
184 } else {
185 return g_build_filename (g_get_home_dir (), ".gnome2/accels/nemo", NULL);
186 }
187 }
188
189 /**
190 * nemo_get_scripts_directory_path:
191 *
192 * Get the path for the directory containing nemo scripts.
193 *
194 * Return value: the directory path containing nemo scripts
195 **/
196 char *
nemo_get_scripts_directory_path(void)197 nemo_get_scripts_directory_path (void)
198 {
199 return g_build_filename (g_get_user_data_dir (), "nemo", "scripts", NULL);
200 }
201
202 typedef struct {
203 char *type;
204 char *path;
205 NemoFile *file;
206 } XdgDirEntry;
207
208
209 static XdgDirEntry *
parse_xdg_dirs(const char * config_file)210 parse_xdg_dirs (const char *config_file)
211 {
212 GArray *array;
213 char *config_file_free = NULL;
214 XdgDirEntry dir;
215 char *data;
216 char **lines;
217 char *p, *d;
218 int i;
219 char *type_start, *type_end;
220 char *value, *unescaped;
221 gboolean relative;
222
223 array = g_array_new (TRUE, TRUE, sizeof (XdgDirEntry));
224
225 if (config_file == NULL)
226 {
227 config_file_free = g_build_filename (g_get_user_config_dir (),
228 "user-dirs.dirs", NULL);
229 config_file = (const char *)config_file_free;
230 }
231
232 if (g_file_get_contents (config_file, &data, NULL, NULL))
233 {
234 lines = g_strsplit (data, "\n", 0);
235 g_free (data);
236 for (i = 0; lines[i] != NULL; i++)
237 {
238 p = lines[i];
239 while (g_ascii_isspace (*p))
240 p++;
241
242 if (*p == '#')
243 continue;
244
245 value = strchr (p, '=');
246 if (value == NULL)
247 continue;
248 *value++ = 0;
249
250 g_strchug (g_strchomp (p));
251 if (!g_str_has_prefix (p, "XDG_"))
252 continue;
253 if (!g_str_has_suffix (p, "_DIR"))
254 continue;
255 type_start = p + 4;
256 type_end = p + strlen (p) - 4;
257
258 while (g_ascii_isspace (*value))
259 value++;
260
261 if (*value != '"')
262 continue;
263 value++;
264
265 relative = FALSE;
266 if (g_str_has_prefix (value, "$HOME"))
267 {
268 relative = TRUE;
269 value += 5;
270 while (*value == '/')
271 value++;
272 }
273 else if (*value != '/')
274 continue;
275
276 d = unescaped = g_malloc (strlen (value) + 1);
277 while (*value && *value != '"')
278 {
279 if ((*value == '\\') && (*(value + 1) != 0))
280 value++;
281 *d++ = *value++;
282 }
283 *d = 0;
284
285 *type_end = 0;
286 dir.type = g_strdup (type_start);
287 if (relative)
288 {
289 dir.path = g_build_filename (g_get_home_dir (), unescaped, NULL);
290 g_free (unescaped);
291 }
292 else
293 dir.path = unescaped;
294
295 g_array_append_val (array, dir);
296 }
297
298 g_strfreev (lines);
299 }
300
301 g_free (config_file_free);
302
303 return (XdgDirEntry *)g_array_free (array, FALSE);
304 }
305
306 static XdgDirEntry *cached_xdg_dirs = NULL;
307 static GFileMonitor *cached_xdg_dirs_monitor = NULL;
308
309 static void
xdg_dir_changed(NemoFile * file,XdgDirEntry * dir)310 xdg_dir_changed (NemoFile *file,
311 XdgDirEntry *dir)
312 {
313 GFile *location, *dir_location;
314 char *path;
315
316 location = nemo_file_get_location (file);
317 dir_location = g_file_new_for_path (dir->path);
318 if (!g_file_equal (location, dir_location)) {
319 path = g_file_get_path (location);
320
321 if (path) {
322 char *argv[5];
323 int i;
324
325 g_free (dir->path);
326 dir->path = path;
327
328 i = 0;
329 argv[i++] = (char *)"xdg-user-dirs-update";
330 argv[i++] = (char *)"--set";
331 argv[i++] = dir->type;
332 argv[i++] = dir->path;
333 argv[i++] = NULL;
334
335 /* We do this sync, to avoid possible race-conditions
336 if multiple dirs change at the same time. Its
337 blocking the main thread, but these updates should
338 be very rare and very fast. */
339 g_spawn_sync (NULL,
340 argv, NULL,
341 G_SPAWN_SEARCH_PATH |
342 G_SPAWN_STDOUT_TO_DEV_NULL |
343 G_SPAWN_STDERR_TO_DEV_NULL,
344 NULL, NULL,
345 NULL, NULL, NULL, NULL);
346 g_reload_user_special_dirs_cache ();
347 schedule_user_dirs_changed ();
348 desktop_dir_changed ();
349 /* Icon might have changed */
350 nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_INFO);
351 }
352 }
353 g_object_unref (location);
354 g_object_unref (dir_location);
355 }
356
357 static void
xdg_dir_cache_changed_cb(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event_type)358 xdg_dir_cache_changed_cb (GFileMonitor *monitor,
359 GFile *file,
360 GFile *other_file,
361 GFileMonitorEvent event_type)
362 {
363 if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
364 event_type == G_FILE_MONITOR_EVENT_CREATED) {
365 update_xdg_dir_cache ();
366 }
367 }
368
369 static int user_dirs_changed_tag = 0;
370
371 static gboolean
emit_user_dirs_changed_idle(gpointer data)372 emit_user_dirs_changed_idle (gpointer data)
373 {
374 g_signal_emit_by_name (nemo_signaller_get_current (),
375 "user_dirs_changed");
376 user_dirs_changed_tag = 0;
377 return FALSE;
378 }
379
380 static void
schedule_user_dirs_changed(void)381 schedule_user_dirs_changed (void)
382 {
383 if (user_dirs_changed_tag == 0) {
384 user_dirs_changed_tag = g_idle_add (emit_user_dirs_changed_idle, NULL);
385 }
386 }
387
388 static void
unschedule_user_dirs_changed(void)389 unschedule_user_dirs_changed (void)
390 {
391 if (user_dirs_changed_tag != 0) {
392 g_source_remove (user_dirs_changed_tag);
393 user_dirs_changed_tag = 0;
394 }
395 }
396
397 static void
free_xdg_dir_cache(void)398 free_xdg_dir_cache (void)
399 {
400 int i;
401
402 if (cached_xdg_dirs != NULL) {
403 for (i = 0; cached_xdg_dirs[i].type != NULL; i++) {
404 if (cached_xdg_dirs[i].file != NULL) {
405 nemo_file_monitor_remove (cached_xdg_dirs[i].file,
406 &cached_xdg_dirs[i]);
407 g_signal_handlers_disconnect_by_func (cached_xdg_dirs[i].file,
408 G_CALLBACK (xdg_dir_changed),
409 &cached_xdg_dirs[i]);
410 nemo_file_unref (cached_xdg_dirs[i].file);
411 }
412 g_free (cached_xdg_dirs[i].type);
413 g_free (cached_xdg_dirs[i].path);
414 }
415 g_free (cached_xdg_dirs);
416 }
417 }
418
419 static void
destroy_xdg_dir_cache(void)420 destroy_xdg_dir_cache (void)
421 {
422 free_xdg_dir_cache ();
423 unschedule_user_dirs_changed ();
424 desktop_dir_changed ();
425
426 if (cached_xdg_dirs_monitor != NULL) {
427 g_object_unref (cached_xdg_dirs_monitor);
428 cached_xdg_dirs_monitor = NULL;
429 }
430 }
431
432 static void
update_xdg_dir_cache(void)433 update_xdg_dir_cache (void)
434 {
435 GFile *file;
436 char *config_file, *uri;
437 int i;
438
439 free_xdg_dir_cache ();
440 g_reload_user_special_dirs_cache ();
441 schedule_user_dirs_changed ();
442 desktop_dir_changed ();
443
444 cached_xdg_dirs = parse_xdg_dirs (NULL);
445
446 for (i = 0 ; cached_xdg_dirs[i].type != NULL; i++) {
447 cached_xdg_dirs[i].file = NULL;
448 if (strcmp (cached_xdg_dirs[i].path, g_get_home_dir ()) != 0) {
449 uri = g_filename_to_uri (cached_xdg_dirs[i].path, NULL, NULL);
450 cached_xdg_dirs[i].file = nemo_file_get_by_uri (uri);
451 nemo_file_monitor_add (cached_xdg_dirs[i].file,
452 &cached_xdg_dirs[i],
453 NEMO_FILE_ATTRIBUTE_INFO);
454 g_signal_connect (cached_xdg_dirs[i].file,
455 "changed", G_CALLBACK (xdg_dir_changed), &cached_xdg_dirs[i]);
456 g_free (uri);
457 }
458 }
459
460 if (cached_xdg_dirs_monitor == NULL) {
461 config_file = g_build_filename (g_get_user_config_dir (),
462 "user-dirs.dirs", NULL);
463 file = g_file_new_for_path (config_file);
464 cached_xdg_dirs_monitor = g_file_monitor_file (file, 0, NULL, NULL);
465 g_signal_connect (cached_xdg_dirs_monitor, "changed",
466 G_CALLBACK (xdg_dir_cache_changed_cb), NULL);
467 g_object_unref (file);
468 g_free (config_file);
469
470 eel_debug_call_at_shutdown (destroy_xdg_dir_cache);
471 }
472 }
473
474 char *
nemo_get_xdg_dir(const char * type)475 nemo_get_xdg_dir (const char *type)
476 {
477 int i;
478
479 if (cached_xdg_dirs == NULL) {
480 update_xdg_dir_cache ();
481 }
482
483 for (i = 0 ; cached_xdg_dirs != NULL && cached_xdg_dirs[i].type != NULL; i++) {
484 if (strcmp (cached_xdg_dirs[i].type, type) == 0) {
485 return g_strdup (cached_xdg_dirs[i].path);
486 }
487 }
488 if (strcmp ("DESKTOP", type) == 0) {
489 return g_build_filename (g_get_home_dir (), DESKTOP_DIRECTORY_NAME, NULL);
490 }
491 if (strcmp ("TEMPLATES", type) == 0) {
492 return g_build_filename (g_get_home_dir (), "Templates", NULL);
493 }
494
495 return g_strdup (g_get_home_dir ());
496 }
497
498 static char *
get_desktop_path(void)499 get_desktop_path (void)
500 {
501 if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR)) {
502 return g_strdup (g_get_home_dir());
503 } else {
504 return nemo_get_xdg_dir ("DESKTOP");
505 }
506 }
507
508 /**
509 * nemo_get_desktop_directory:
510 *
511 * Get the path for the directory containing files on the desktop.
512 *
513 * Return value: the directory path.
514 **/
515 char *
nemo_get_desktop_directory(void)516 nemo_get_desktop_directory (void)
517 {
518 char *desktop_directory;
519
520 desktop_directory = get_desktop_path ();
521
522 /* Don't try to create a home directory */
523 if (!g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR)) {
524 if (!g_file_test (desktop_directory, G_FILE_TEST_EXISTS)) {
525 g_mkdir (desktop_directory, DEFAULT_DESKTOP_DIRECTORY_MODE);
526 /* FIXME bugzilla.gnome.org 41286:
527 * How should we handle the case where this mkdir fails?
528 * Note that nemo_application_startup will refuse to launch if this
529 * directory doesn't get created, so that case is OK. But the directory
530 * could be deleted after Nemo was launched, and perhaps
531 * there is some bad side-effect of not handling that case.
532 */
533 }
534 }
535
536 return desktop_directory;
537 }
538
539 GFile *
nemo_get_desktop_location(void)540 nemo_get_desktop_location (void)
541 {
542 char *desktop_directory;
543 GFile *res;
544
545 desktop_directory = get_desktop_path ();
546
547 res = g_file_new_for_path (desktop_directory);
548 g_free (desktop_directory);
549 return res;
550 }
551
552
553 /**
554 * nemo_get_desktop_directory_uri:
555 *
556 * Get the uri for the directory containing files on the desktop.
557 *
558 * Return value: the directory path.
559 **/
560 char *
nemo_get_desktop_directory_uri(void)561 nemo_get_desktop_directory_uri (void)
562 {
563 char *desktop_path;
564 char *desktop_uri;
565
566 desktop_path = nemo_get_desktop_directory ();
567 desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL);
568 g_free (desktop_path);
569
570 return desktop_uri;
571 }
572
573 char *
nemo_get_desktop_directory_uri_no_create(void)574 nemo_get_desktop_directory_uri_no_create (void)
575 {
576 char *desktop_path;
577 char *desktop_uri;
578
579 desktop_path = get_desktop_path ();
580 desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL);
581 g_free (desktop_path);
582
583 return desktop_uri;
584 }
585
586 char *
nemo_get_home_directory_uri(void)587 nemo_get_home_directory_uri (void)
588 {
589 return g_filename_to_uri (g_get_home_dir (), NULL, NULL);
590 }
591
592
593 gboolean
nemo_should_use_templates_directory(void)594 nemo_should_use_templates_directory (void)
595 {
596 char *dir;
597 gboolean res;
598
599 dir = nemo_get_xdg_dir ("TEMPLATES");
600 res = strcmp (dir, g_get_home_dir ()) != 0;
601 g_free (dir);
602 return res;
603 }
604
605 char *
nemo_get_templates_directory(void)606 nemo_get_templates_directory (void)
607 {
608 return nemo_get_xdg_dir ("TEMPLATES");
609 }
610
611 void
nemo_create_templates_directory(void)612 nemo_create_templates_directory (void)
613 {
614 char *dir;
615
616 dir = nemo_get_templates_directory ();
617 if (!g_file_test (dir, G_FILE_TEST_EXISTS)) {
618 g_mkdir (dir, DEFAULT_NEMO_DIRECTORY_MODE);
619 }
620 g_free (dir);
621 }
622
623 char *
nemo_get_templates_directory_uri(void)624 nemo_get_templates_directory_uri (void)
625 {
626 char *directory, *uri;
627
628 directory = nemo_get_templates_directory ();
629 uri = g_filename_to_uri (directory, NULL, NULL);
630 g_free (directory);
631 return uri;
632 }
633
634 char *
nemo_get_searches_directory(void)635 nemo_get_searches_directory (void)
636 {
637 char *user_dir;
638 char *searches_dir;
639
640 user_dir = nemo_get_user_directory ();
641 searches_dir = g_build_filename (user_dir, "searches", NULL);
642 g_free (user_dir);
643
644 if (!g_file_test (searches_dir, G_FILE_TEST_EXISTS))
645 g_mkdir (searches_dir, DEFAULT_NEMO_DIRECTORY_MODE);
646
647 return searches_dir;
648 }
649
650 /* These need to be reset to NULL when desktop_is_home_dir changes */
651 static GFile *desktop_dir = NULL;
652 static GFile *desktop_dir_dir = NULL;
653 static char *desktop_dir_filename = NULL;
654 static gboolean desktop_dir_changed_callback_installed = FALSE;
655
656
657 static void
desktop_dir_changed(void)658 desktop_dir_changed (void)
659 {
660 if (desktop_dir) {
661 g_object_unref (desktop_dir);
662 }
663 if (desktop_dir_dir) {
664 g_object_unref (desktop_dir_dir);
665 }
666 g_free (desktop_dir_filename);
667 desktop_dir = NULL;
668 desktop_dir_dir = NULL;
669 desktop_dir_filename = NULL;
670 }
671
672 static void
desktop_dir_changed_callback(gpointer callback_data)673 desktop_dir_changed_callback (gpointer callback_data)
674 {
675 desktop_dir_changed ();
676 }
677
678 static void
update_desktop_dir(void)679 update_desktop_dir (void)
680 {
681 char *path;
682 char *dirname;
683
684 path = get_desktop_path ();
685 desktop_dir = g_file_new_for_path (path);
686
687 dirname = g_path_get_dirname (path);
688 desktop_dir_dir = g_file_new_for_path (dirname);
689 g_free (dirname);
690 desktop_dir_filename = g_path_get_basename (path);
691 g_free (path);
692 }
693
694 gboolean
nemo_is_home_directory_file(GFile * dir,const char * filename)695 nemo_is_home_directory_file (GFile *dir,
696 const char *filename)
697 {
698 char *dirname;
699 static GFile *home_dir_dir = NULL;
700 static char *home_dir_filename = NULL;
701
702 if (home_dir_dir == NULL) {
703 dirname = g_path_get_dirname (g_get_home_dir ());
704 home_dir_dir = g_file_new_for_path (dirname);
705 g_free (dirname);
706 home_dir_filename = g_path_get_basename (g_get_home_dir ());
707 }
708
709 return (g_file_equal (dir, home_dir_dir) &&
710 strcmp (filename, home_dir_filename) == 0);
711 }
712
713 gboolean
nemo_is_home_directory(GFile * dir)714 nemo_is_home_directory (GFile *dir)
715 {
716 static GFile *home_dir = NULL;
717
718 if (home_dir == NULL) {
719 home_dir = g_file_new_for_path (g_get_home_dir ());
720 }
721
722 return g_file_equal (dir, home_dir);
723 }
724
725 gboolean
nemo_is_root_directory(GFile * dir)726 nemo_is_root_directory (GFile *dir)
727 {
728 static GFile *root_dir = NULL;
729
730 if (root_dir == NULL) {
731 root_dir = g_file_new_for_path ("/");
732 }
733
734 return g_file_equal (dir, root_dir);
735 }
736
737
738 gboolean
nemo_is_desktop_directory_file(GFile * dir,const char * file)739 nemo_is_desktop_directory_file (GFile *dir,
740 const char *file)
741 {
742
743 if (!desktop_dir_changed_callback_installed) {
744 g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR,
745 G_CALLBACK(desktop_dir_changed_callback),
746 NULL);
747 desktop_dir_changed_callback_installed = TRUE;
748 }
749
750 if (desktop_dir == NULL) {
751 update_desktop_dir ();
752 }
753
754 return (g_file_equal (dir, desktop_dir_dir) &&
755 strcmp (file, desktop_dir_filename) == 0);
756 }
757
758 gboolean
nemo_is_desktop_directory(GFile * dir)759 nemo_is_desktop_directory (GFile *dir)
760 {
761
762 if (!desktop_dir_changed_callback_installed) {
763 g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR,
764 G_CALLBACK(desktop_dir_changed_callback),
765 NULL);
766 desktop_dir_changed_callback_installed = TRUE;
767 }
768
769 if (desktop_dir == NULL) {
770 update_desktop_dir ();
771 }
772
773 return g_file_equal (dir, desktop_dir);
774 }
775
776
777 /**
778 * nemo_get_gmc_desktop_directory:
779 *
780 * Get the path for the directory containing the legacy gmc desktop.
781 *
782 * Return value: the directory path.
783 **/
784 char *
nemo_get_gmc_desktop_directory(void)785 nemo_get_gmc_desktop_directory (void)
786 {
787 return g_build_filename (g_get_home_dir (), LEGACY_DESKTOP_DIRECTORY_NAME, NULL);
788 }
789
790 char *
nemo_get_data_file_path(const char * partial_path)791 nemo_get_data_file_path (const char *partial_path)
792 {
793 char *path;
794 char *user_directory;
795
796 /* first try the user's home directory */
797 user_directory = nemo_get_user_directory ();
798 path = g_build_filename (user_directory, partial_path, NULL);
799 g_free (user_directory);
800 if (g_file_test (path, G_FILE_TEST_EXISTS)) {
801 return path;
802 }
803 g_free (path);
804
805 /* next try the shared directory */
806 path = g_build_filename (NEMO_DATADIR, partial_path, NULL);
807 if (g_file_test (path, G_FILE_TEST_EXISTS)) {
808 return path;
809 }
810 g_free (path);
811
812 return NULL;
813 }
814
815 char *
nemo_ensure_unique_file_name(const char * directory_uri,const char * base_name,const char * extension)816 nemo_ensure_unique_file_name (const char *directory_uri,
817 const char *base_name,
818 const char *extension)
819 {
820 GFileInfo *info;
821 char *filename;
822 GFile *dir, *child;
823 int copy;
824 char *res;
825
826 dir = g_file_new_for_uri (directory_uri);
827
828 info = g_file_query_info (dir, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL);
829 if (info == NULL) {
830 g_object_unref (dir);
831 return NULL;
832 }
833 g_object_unref (info);
834
835 filename = g_strdup_printf ("%s%s",
836 base_name,
837 extension);
838 child = g_file_get_child (dir, filename);
839 g_free (filename);
840
841 copy = 1;
842 while ((info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL)) != NULL) {
843 g_object_unref (info);
844 g_object_unref (child);
845
846 filename = g_strdup_printf ("%s-%d%s",
847 base_name,
848 copy,
849 extension);
850 child = g_file_get_child (dir, filename);
851 g_free (filename);
852
853 copy++;
854 }
855
856 res = g_file_get_uri (child);
857 g_object_unref (child);
858 g_object_unref (dir);
859
860 return res;
861 }
862
863 char *
nemo_unique_temporary_file_name(void)864 nemo_unique_temporary_file_name (void)
865 {
866 const char *prefix = "/tmp/nemo-temp-file";
867 char *file_name;
868 int fd;
869
870 file_name = g_strdup_printf ("%sXXXXXX", prefix);
871
872 fd = g_mkstemp (file_name);
873 if (fd == -1) {
874 g_free (file_name);
875 file_name = NULL;
876 } else {
877 close (fd);
878 }
879
880 return file_name;
881 }
882
883 GFile *
nemo_find_existing_uri_in_hierarchy(GFile * location)884 nemo_find_existing_uri_in_hierarchy (GFile *location)
885 {
886 GFileInfo *info;
887 GFile *tmp;
888
889 g_assert (location != NULL);
890
891 location = g_object_ref (location);
892 while (location != NULL) {
893 info = g_file_query_info (location,
894 G_FILE_ATTRIBUTE_STANDARD_NAME,
895 0, NULL, NULL);
896 g_object_unref (info);
897 if (info != NULL) {
898 return location;
899 }
900 tmp = location;
901 location = g_file_get_parent (location);
902 g_object_unref (tmp);
903 }
904
905 return location;
906 }
907
908 /**
909 * nemo_find_file_insensitive
910 *
911 * Attempt to find a file case-insentively. If the path can be found, the
912 * returned file maps directly to it. Otherwise, a file using the
913 * originally-cased path is returned. This function performs might perform
914 * I/O.
915 *
916 * Return value: a #GFile to a child specified by @name.
917 **/
918 GFile *
nemo_find_file_insensitive(GFile * parent,const gchar * name)919 nemo_find_file_insensitive (GFile *parent, const gchar *name)
920 {
921 gchar **split_path;
922 gchar *component;
923 GFile *file, *next;
924 gint i;
925
926 split_path = g_strsplit (name, G_DIR_SEPARATOR_S, -1);
927
928 file = g_object_ref (parent);
929
930 for (i = 0; (component = split_path[i]) != NULL; i++) {
931 if (!(next = nemo_find_file_insensitive_next (file,
932 component))) {
933 /* File does not exist */
934 g_object_unref (file);
935 file = NULL;
936 break;
937 }
938 g_object_unref (file);
939 file = next;
940 }
941 g_strfreev (split_path);
942
943 if (file) {
944 return file;
945 }
946 return g_file_get_child (parent, name);
947 }
948
949 static GFile *
nemo_find_file_insensitive_next(GFile * parent,const gchar * name)950 nemo_find_file_insensitive_next (GFile *parent, const gchar *name)
951 {
952 GFileEnumerator *children;
953 GFileInfo *info;
954 gboolean use_utf8, found;
955 char *filename, *case_folded_name, *utf8_collation_key, *ascii_collation_key, *child_key;
956 GFile *file;
957 const char *child_name, *compare_key;
958
959 /* First check the given version */
960 file = g_file_get_child (parent, name);
961 if (g_file_query_exists (file, NULL)) {
962 return file;
963 }
964 g_object_unref (file);
965
966 ascii_collation_key = g_ascii_strdown (name, -1);
967 use_utf8 = g_utf8_validate (name, -1, NULL);
968 utf8_collation_key = NULL;
969 if (use_utf8) {
970 case_folded_name = g_utf8_casefold (name, -1);
971 utf8_collation_key = g_utf8_collate_key (case_folded_name, -1);
972 g_free (case_folded_name);
973 }
974
975 /* Enumerate and compare insensitive */
976 filename = NULL;
977 children = g_file_enumerate_children (parent,
978 G_FILE_ATTRIBUTE_STANDARD_NAME,
979 0, NULL, NULL);
980 if (children != NULL) {
981 while ((info = g_file_enumerator_next_file (children, NULL, NULL))) {
982 child_name = g_file_info_get_name (info);
983
984 if (use_utf8 && g_utf8_validate (child_name, -1, NULL)) {
985 gchar *case_folded;
986
987 case_folded = g_utf8_casefold (child_name, -1);
988 child_key = g_utf8_collate_key (case_folded, -1);
989 g_free (case_folded);
990 compare_key = utf8_collation_key;
991 } else {
992 child_key = g_ascii_strdown (child_name, -1);
993 compare_key = ascii_collation_key;
994 }
995
996 found = strcmp (child_key, compare_key) == 0;
997 g_free (child_key);
998 if (found) {
999 filename = g_strdup (child_name);
1000 break;
1001 }
1002 }
1003 g_file_enumerator_close (children, NULL, NULL);
1004 g_object_unref (children);
1005 }
1006
1007 g_free (ascii_collation_key);
1008 g_free (utf8_collation_key);
1009
1010 if (filename) {
1011 file = g_file_get_child (parent, filename);
1012 g_free (filename);
1013 return file;
1014 }
1015
1016 return NULL;
1017 }
1018
1019 static gboolean
have_program_in_path(const char * name)1020 have_program_in_path (const char *name)
1021 {
1022 char *path;
1023 gboolean result;
1024
1025 path = g_find_program_in_path (name);
1026 result = (path != NULL);
1027 g_free (path);
1028 return result;
1029 }
1030
1031 gboolean
nemo_is_file_roller_installed(void)1032 nemo_is_file_roller_installed (void)
1033 {
1034 static int installed = - 1;
1035
1036 if (installed < 0) {
1037 if (have_program_in_path ("file-roller")) {
1038 installed = 1;
1039 } else {
1040 installed = 0;
1041 }
1042 }
1043
1044 return installed > 0 ? TRUE : FALSE;
1045 }
1046
1047 #define GSM_NAME "org.gnome.SessionManager"
1048 #define GSM_PATH "/org/gnome/SessionManager"
1049 #define GSM_INTERFACE "org.gnome.SessionManager"
1050
1051 /* The following values come from
1052 * http://www.gnome.org/~mccann/gnome-session/docs/gnome-session.html#org.gnome.SessionManager.Inhibit
1053 */
1054 #define INHIBIT_LOGOUT (1U)
1055 #define INHIBIT_SUSPEND (4U)
1056
1057 static GDBusConnection *
get_dbus_connection(void)1058 get_dbus_connection (void)
1059 {
1060 static GDBusConnection *conn = NULL;
1061
1062 if (conn == NULL) {
1063 GError *error = NULL;
1064
1065 conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1066
1067 if (conn == NULL) {
1068 g_warning ("Could not connect to session bus: %s", error->message);
1069 g_error_free (error);
1070 }
1071 }
1072
1073 return conn;
1074 }
1075
1076 /**
1077 * nemo_inhibit_power_manager:
1078 * @message: a human readable message for the reason why power management
1079 * is being suspended.
1080 *
1081 * Inhibits the power manager from logging out or suspending the machine
1082 * (e.g. whenever Nemo is doing file operations).
1083 *
1084 * Returns: an integer cookie, which must be passed to
1085 * nemo_uninhibit_power_manager() to resume
1086 * normal power management.
1087 */
1088 int
nemo_inhibit_power_manager(const char * message)1089 nemo_inhibit_power_manager (const char *message)
1090 {
1091 GDBusConnection *connection;
1092 GVariant *result;
1093 GError *error = NULL;
1094 guint cookie = 0;
1095
1096 g_return_val_if_fail (message != NULL, -1);
1097
1098 connection = get_dbus_connection ();
1099
1100 if (connection == NULL) {
1101 return -1;
1102 }
1103
1104 result = g_dbus_connection_call_sync (connection,
1105 GSM_NAME,
1106 GSM_PATH,
1107 GSM_INTERFACE,
1108 "Inhibit",
1109 g_variant_new ("(susu)",
1110 "Nemo",
1111 (guint) 0,
1112 message,
1113 (guint) (INHIBIT_LOGOUT | INHIBIT_SUSPEND)),
1114 G_VARIANT_TYPE ("(u)"),
1115 G_DBUS_CALL_FLAGS_NO_AUTO_START,
1116 -1,
1117 NULL,
1118 &error);
1119
1120 if (error != NULL) {
1121 g_warning ("Could not inhibit power management: %s", error->message);
1122 g_error_free (error);
1123 return -1;
1124 }
1125
1126 g_variant_get (result, "(u)", &cookie);
1127 g_variant_unref (result);
1128
1129 return (int) cookie;
1130 }
1131
1132 /**
1133 * nemo_uninhibit_power_manager:
1134 * @cookie: the cookie value returned by nemo_inhibit_power_manager()
1135 *
1136 * Uninhibits power management. This function must be called after the task
1137 * which inhibited power management has finished, or the system will not
1138 * return to normal power management.
1139 */
1140 void
nemo_uninhibit_power_manager(gint cookie)1141 nemo_uninhibit_power_manager (gint cookie)
1142 {
1143 GDBusConnection *connection;
1144 GVariant *result;
1145 GError *error = NULL;
1146
1147 g_return_if_fail (cookie > 0);
1148
1149 connection = get_dbus_connection ();
1150
1151 if (connection == NULL) {
1152 return;
1153 }
1154
1155 result = g_dbus_connection_call_sync (connection,
1156 GSM_NAME,
1157 GSM_PATH,
1158 GSM_INTERFACE,
1159 "Uninhibit",
1160 g_variant_new ("(u)", (guint) cookie),
1161 NULL,
1162 G_DBUS_CALL_FLAGS_NO_AUTO_START,
1163 -1,
1164 NULL,
1165 &error);
1166
1167 if (result == NULL) {
1168 g_warning ("Could not uninhibit power management: %s", error->message);
1169 g_error_free (error);
1170 return;
1171 }
1172
1173 g_variant_unref (result);
1174 }
1175
1176 /* Returns TRUE if the file is in XDG_DATA_DIRS or
1177 in "~/.gnome2/". This is used for deciding
1178 if a desktop file is "trusted" based on the path */
1179 gboolean
nemo_is_in_system_dir(GFile * file)1180 nemo_is_in_system_dir (GFile *file)
1181 {
1182 const char * const * data_dirs;
1183 char *path, *gnome2;
1184 int i;
1185 gboolean res;
1186
1187 if (!g_file_is_native (file)) {
1188 return FALSE;
1189 }
1190
1191 path = g_file_get_path (file);
1192
1193 res = FALSE;
1194
1195 data_dirs = g_get_system_data_dirs ();
1196 for (i = 0; path != NULL && data_dirs[i] != NULL; i++) {
1197 if (g_str_has_prefix (path, data_dirs[i])) {
1198 res = TRUE;
1199 break;
1200 }
1201
1202 }
1203
1204 if (!res) {
1205 /* Panel desktop files are here, trust them */
1206 gnome2 = g_build_filename (g_get_home_dir (), ".gnome2", NULL);
1207 if (g_str_has_prefix (path, gnome2)) {
1208 res = TRUE;
1209 }
1210 g_free (gnome2);
1211 }
1212 g_free (path);
1213
1214 return res;
1215 }
1216
1217 GHashTable *
nemo_trashed_files_get_original_directories(GList * files,GList ** unhandled_files)1218 nemo_trashed_files_get_original_directories (GList *files,
1219 GList **unhandled_files)
1220 {
1221 GHashTable *directories;
1222 NemoFile *file, *original_file, *original_dir;
1223 GList *l, *m;
1224
1225 directories = NULL;
1226
1227 if (unhandled_files != NULL) {
1228 *unhandled_files = NULL;
1229 }
1230
1231 for (l = files; l != NULL; l = l->next) {
1232 file = NEMO_FILE (l->data);
1233 original_file = nemo_file_get_trash_original_file (file);
1234
1235 original_dir = NULL;
1236 if (original_file != NULL) {
1237 original_dir = nemo_file_get_parent (original_file);
1238 }
1239
1240 if (original_dir != NULL) {
1241 if (directories == NULL) {
1242 directories = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1243 (GDestroyNotify) nemo_file_unref,
1244 (GDestroyNotify) nemo_file_list_free);
1245 }
1246 nemo_file_ref (original_dir);
1247 m = g_hash_table_lookup (directories, original_dir);
1248 if (m != NULL) {
1249 g_hash_table_steal (directories, original_dir);
1250 nemo_file_unref (original_dir);
1251 }
1252 m = g_list_append (m, nemo_file_ref (file));
1253 g_hash_table_insert (directories, original_dir, m);
1254 } else if (unhandled_files != NULL) {
1255 *unhandled_files = g_list_append (*unhandled_files, nemo_file_ref (file));
1256 }
1257
1258 if (original_file != NULL) {
1259 nemo_file_unref (original_file);
1260 }
1261
1262 if (original_dir != NULL) {
1263 nemo_file_unref (original_dir);
1264 }
1265 }
1266
1267 return directories;
1268 }
1269
1270 static GList *
locations_from_file_list(GList * file_list)1271 locations_from_file_list (GList *file_list)
1272 {
1273 NemoFile *file;
1274 GList *l, *ret;
1275
1276 ret = NULL;
1277
1278 for (l = file_list; l != NULL; l = l->next) {
1279 file = NEMO_FILE (l->data);
1280 ret = g_list_prepend (ret, nemo_file_get_location (file));
1281 }
1282
1283 return g_list_reverse (ret);
1284 }
1285
1286 typedef struct {
1287 GHashTable *original_dirs_hash;
1288 GtkWindow *parent_window;
1289 } RestoreFilesData;
1290
1291 static void
ensure_dirs_task_ready_cb(GObject * _source,GAsyncResult * res,gpointer user_data)1292 ensure_dirs_task_ready_cb (GObject *_source,
1293 GAsyncResult *res,
1294 gpointer user_data)
1295 {
1296 NemoFile *original_dir;
1297 GFile *original_dir_location;
1298 GList *original_dirs, *files, *locations, *l;
1299 RestoreFilesData *data = user_data;
1300
1301 original_dirs = g_hash_table_get_keys (data->original_dirs_hash);
1302 for (l = original_dirs; l != NULL; l = l->next) {
1303 original_dir = NEMO_FILE (l->data);
1304 original_dir_location = nemo_file_get_location (original_dir);
1305
1306 files = g_hash_table_lookup (data->original_dirs_hash, original_dir);
1307 locations = locations_from_file_list (files);
1308
1309 nemo_file_operations_move
1310 (locations, NULL,
1311 original_dir_location,
1312 data->parent_window,
1313 NULL, NULL);
1314
1315 g_list_free_full (locations, g_object_unref);
1316 g_object_unref (original_dir_location);
1317 }
1318
1319 g_list_free (original_dirs);
1320
1321 g_hash_table_unref (data->original_dirs_hash);
1322 g_slice_free (RestoreFilesData, data);
1323 }
1324
1325 static void
ensure_dirs_task_thread_func(GTask * task,gpointer source,gpointer task_data,GCancellable * cancellable)1326 ensure_dirs_task_thread_func (GTask *task,
1327 gpointer source,
1328 gpointer task_data,
1329 GCancellable *cancellable)
1330 {
1331 RestoreFilesData *data = task_data;
1332 NemoFile *original_dir;
1333 GFile *original_dir_location;
1334 GList *original_dirs, *l;
1335
1336 original_dirs = g_hash_table_get_keys (data->original_dirs_hash);
1337 for (l = original_dirs; l != NULL; l = l->next) {
1338 original_dir = NEMO_FILE (l->data);
1339 original_dir_location = nemo_file_get_location (original_dir);
1340
1341 g_file_make_directory_with_parents (original_dir_location, cancellable, NULL);
1342 g_object_unref (original_dir_location);
1343 }
1344
1345 g_task_return_pointer (task, NULL, NULL);
1346 }
1347
1348 static void
restore_files_ensure_parent_directories(GHashTable * original_dirs_hash,GtkWindow * parent_window)1349 restore_files_ensure_parent_directories (GHashTable *original_dirs_hash,
1350 GtkWindow *parent_window)
1351 {
1352 RestoreFilesData *data;
1353 GTask *ensure_dirs_task;
1354
1355 data = g_slice_new0 (RestoreFilesData);
1356 data->parent_window = parent_window;
1357 data->original_dirs_hash = g_hash_table_ref (original_dirs_hash);
1358
1359 ensure_dirs_task = g_task_new (NULL, NULL, ensure_dirs_task_ready_cb, data);
1360 g_task_set_task_data (ensure_dirs_task, data, NULL);
1361 g_task_run_in_thread (ensure_dirs_task, ensure_dirs_task_thread_func);
1362 g_object_unref (ensure_dirs_task);
1363 }
1364
1365 void
nemo_restore_files_from_trash(GList * files,GtkWindow * parent_window)1366 nemo_restore_files_from_trash (GList *files,
1367 GtkWindow *parent_window)
1368 {
1369 NemoFile *file;
1370 GHashTable *original_dirs_hash;
1371 GList *unhandled_files, *l;
1372 char *message, *file_name;
1373
1374 original_dirs_hash = nemo_trashed_files_get_original_directories (files, &unhandled_files);
1375
1376 for (l = unhandled_files; l != NULL; l = l->next) {
1377 file = NEMO_FILE (l->data);
1378 file_name = nemo_file_get_display_name (file);
1379 message = g_strdup_printf (_("Could not determine original location of \"%s\" "), file_name);
1380 g_free (file_name);
1381
1382 eel_show_warning_dialog (message,
1383 _("The item cannot be restored from trash"),
1384 parent_window);
1385 g_free (message);
1386 }
1387
1388 if (original_dirs_hash != NULL) {
1389 restore_files_ensure_parent_directories (original_dirs_hash, parent_window);
1390 g_hash_table_unref (original_dirs_hash);
1391 }
1392
1393 nemo_file_list_unref (unhandled_files);
1394 }
1395
1396 typedef struct {
1397 NemoMountGetContent callback;
1398 gpointer user_data;
1399 } GetContentTypesData;
1400
1401 static void
get_types_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1402 get_types_cb (GObject *source_object,
1403 GAsyncResult *res,
1404 gpointer user_data)
1405 {
1406 GetContentTypesData *data;
1407 char **types;
1408
1409 data = user_data;
1410 types = g_mount_guess_content_type_finish (G_MOUNT (source_object), res, NULL);
1411
1412 g_object_set_data_full (source_object,
1413 "nemo-content-type-cache",
1414 g_strdupv (types),
1415 (GDestroyNotify)g_strfreev);
1416
1417 if (data->callback) {
1418 data->callback ((const char **) types, data->user_data);
1419 }
1420 g_strfreev (types);
1421 g_slice_free (GetContentTypesData, data);
1422 }
1423
1424 void
nemo_get_x_content_types_for_mount_async(GMount * mount,NemoMountGetContent callback,GCancellable * cancellable,gpointer user_data)1425 nemo_get_x_content_types_for_mount_async (GMount *mount,
1426 NemoMountGetContent callback,
1427 GCancellable *cancellable,
1428 gpointer user_data)
1429 {
1430 char **cached;
1431 GetContentTypesData *data;
1432
1433 if (mount == NULL) {
1434 if (callback) {
1435 callback (NULL, user_data);
1436 }
1437 return;
1438 }
1439
1440 cached = g_object_get_data (G_OBJECT (mount), "nemo-content-type-cache");
1441 if (cached != NULL) {
1442 if (callback) {
1443 callback ((const char **) cached, user_data);
1444 }
1445 return;
1446 }
1447
1448 data = g_slice_new0 (GetContentTypesData);
1449 data->callback = callback;
1450 data->user_data = user_data;
1451
1452 g_mount_guess_content_type (mount,
1453 FALSE,
1454 cancellable,
1455 get_types_cb,
1456 data);
1457 }
1458
1459 char **
nemo_get_cached_x_content_types_for_mount(GMount * mount)1460 nemo_get_cached_x_content_types_for_mount (GMount *mount)
1461 {
1462 char **cached;
1463
1464 if (mount == NULL) {
1465 return NULL;
1466 }
1467
1468 cached = g_object_get_data (G_OBJECT (mount), "nemo-content-type-cache");
1469 if (cached != NULL) {
1470 return g_strdupv (cached);
1471 }
1472
1473 return NULL;
1474 }
1475
1476 static void
debug_icon_names(const gchar * format,...)1477 debug_icon_names (const gchar *format, ...)
1478 {
1479 static gboolean debug_removable_device_icons = FALSE;
1480 static gsize once_init = 0;
1481
1482 if (g_once_init_enter (&once_init)) {
1483 debug_removable_device_icons = g_getenv ("NEMO_DEBUG_DEVICE_ICONS") != NULL;
1484
1485 g_once_init_leave (&once_init, 1);
1486 }
1487
1488 if (!debug_removable_device_icons) {
1489 return;
1490 }
1491
1492 va_list args;
1493 va_start (args, format);
1494 g_logv (NULL, G_LOG_LEVEL_MESSAGE, format, args);
1495 va_end(args);
1496 }
1497
1498 static gboolean
icon_name_is_non_specific(const gchar * icon_name)1499 icon_name_is_non_specific (const gchar *icon_name)
1500 {
1501 gint i;
1502
1503 static const char * non_specific_icon_names[] = { "drive-harddisk-usb-symbolic" };
1504
1505 for (i = 0; i < G_N_ELEMENTS (non_specific_icon_names); i++) {
1506 if (g_strcmp0 (icon_name, non_specific_icon_names[i]) == 0) {
1507 return TRUE;
1508 }
1509 }
1510
1511 return FALSE;
1512 }
1513
1514 gchar *
nemo_get_mount_icon_name(GMount * mount)1515 nemo_get_mount_icon_name (GMount *mount)
1516 {
1517 GDrive *drive;
1518 GIcon *gicon;
1519 gchar *icon_name;
1520 gchar *mount_icon_name;
1521 gchar *dev_name;
1522
1523 g_return_val_if_fail (mount != NULL, NULL);
1524
1525 dev_name = g_mount_get_name (mount);
1526 icon_name = NULL;
1527 mount_icon_name = NULL;
1528
1529 gicon = g_mount_get_symbolic_icon (mount);
1530
1531 if (G_IS_THEMED_ICON (gicon)) {
1532 mount_icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
1533
1534 if (icon_name_is_non_specific (mount_icon_name)) {
1535 debug_icon_names ("mount %s: icon name '%s' too non-specific", dev_name, mount_icon_name);
1536 } else {
1537 icon_name = g_strdup (mount_icon_name);
1538 }
1539 }
1540
1541 g_clear_object (&gicon);
1542
1543 if (icon_name != NULL) {
1544 debug_icon_names ("mount %s: icon name '%s' is being used", dev_name, icon_name);
1545
1546 g_free (dev_name);
1547 g_free (mount_icon_name);
1548
1549 return icon_name;
1550 }
1551
1552 drive = g_mount_get_drive (mount);
1553
1554 if (drive != NULL) {
1555 gicon = g_drive_get_symbolic_icon (drive);
1556 g_object_unref (drive);
1557
1558 if (G_IS_THEMED_ICON (gicon)) {
1559 icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
1560 }
1561
1562 g_object_unref (gicon);
1563 }
1564
1565 if (icon_name == NULL) {
1566 if (mount_icon_name) {
1567 icon_name = g_strdup (mount_icon_name);
1568 } else {
1569 icon_name = g_strdup ("folder-symbolic"); // any theme will have at least this?...
1570 }
1571
1572 debug_icon_names ("mount %s: no other good icon name found, using fallback of '%s'", dev_name, icon_name);
1573 }
1574
1575 g_free (dev_name);
1576 g_free (mount_icon_name);
1577
1578 return icon_name;
1579 }
1580
1581 gchar *
nemo_get_volume_icon_name(GVolume * volume)1582 nemo_get_volume_icon_name (GVolume *volume)
1583 {
1584 GDrive *drive;
1585 GIcon *gicon;
1586 gchar *icon_name;
1587 gchar *dev_name;
1588 gchar *volume_icon_name;
1589
1590 g_return_val_if_fail (volume != NULL, NULL);
1591
1592 dev_name = g_volume_get_name (volume);
1593 icon_name = NULL;
1594 volume_icon_name = NULL;
1595
1596 gicon = g_volume_get_symbolic_icon (volume);
1597
1598 if (G_IS_THEMED_ICON (gicon)) {
1599 volume_icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
1600
1601 if (icon_name_is_non_specific (volume_icon_name)) {
1602 debug_icon_names ("volume %s: icon name '%s' too non-specific", dev_name, volume_icon_name);
1603 } else {
1604 icon_name = g_strdup (volume_icon_name);
1605 }
1606 }
1607
1608 g_clear_object (&gicon);
1609
1610 if (icon_name != NULL) {
1611 debug_icon_names ("volume %s: icon name '%s' is being used", dev_name, icon_name);
1612
1613 g_free (dev_name);
1614 g_free (volume_icon_name);
1615
1616 return icon_name;
1617 }
1618
1619 drive = g_volume_get_drive (volume);
1620
1621 if (drive != NULL) {
1622 gicon = g_drive_get_symbolic_icon (drive);
1623 g_object_unref (drive);
1624
1625 if (G_IS_THEMED_ICON (gicon)) {
1626 icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
1627 }
1628
1629 g_object_unref (gicon);
1630 }
1631
1632 if (icon_name == NULL) {
1633 if (volume_icon_name) {
1634 icon_name = g_strdup (volume_icon_name);
1635 } else {
1636 icon_name = g_strdup ("folder-symbolic"); // any theme will have at least this?...
1637
1638 }
1639
1640 debug_icon_names ("volume %s: no good icon name found, using fallback of '%s'", dev_name, icon_name);
1641 }
1642
1643 g_free (dev_name);
1644 g_free (volume_icon_name);
1645
1646 return icon_name;
1647 }
1648
1649 gchar *
nemo_get_drive_icon_name(GDrive * drive)1650 nemo_get_drive_icon_name (GDrive *drive)
1651 {
1652 GIcon *gicon;
1653 gchar *icon_name;
1654 gchar *dev_name;
1655
1656 g_return_val_if_fail (drive != NULL, NULL);
1657
1658 dev_name = g_drive_get_name (drive);
1659
1660 gicon = g_drive_get_symbolic_icon (drive);
1661
1662 if (G_IS_THEMED_ICON (gicon)) {
1663 icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
1664 } else {
1665 icon_name = g_strdup ("folder-symbolic"); // any theme will have at least this?...
1666 }
1667
1668 g_object_unref (gicon);
1669
1670 debug_icon_names ("drive %s: returning icon '%s'", dev_name, icon_name);
1671
1672 g_free (dev_name);
1673
1674 return icon_name;
1675 }
1676
1677 gchar *
nemo_get_best_guess_file_mimetype(const gchar * filename,GFileInfo * info,goffset size)1678 nemo_get_best_guess_file_mimetype (const gchar *filename,
1679 GFileInfo *info,
1680 goffset size)
1681 {
1682 /* This is an attempt to do a better job at identifying file types than
1683 * the current gio implementation.
1684 *
1685 * The current behavior for empty (0 size) size files, is to return
1686 * "text/plain" so users can touch a file, or create an empty one in their
1687 * file manager, and immediately edit it.
1688 *
1689 * This behavior currently applies regardless of whether or not a file has
1690 * an extension.
1691 *
1692 * More discussion: https://bugzilla.gnome.org/show_bug.cgi?id=755795
1693 *
1694 * What we do here instead is take a file's extension into account if the file
1695 * is zero-length. If, by doing so, we have a high confidence that a file is
1696 * a certain type, we go ahead and use that type. We only fall back to Gio's
1697 * zero-length implementation if the extension is unknown, or it has none.
1698 *
1699 * - Files that are NOT zero-length are treated the same as before.
1700 * - Files that we are not certain about are treated the same as before.
1701 *
1702 * Again, this only has an effect on zero-length, known-extension files. My
1703 * argument for this differing from the standing implementation is that if I
1704 * create a file with a particular extension, I did so for a reason, and I'm not
1705 * going to do something silly like make foo.mp3 and attempt to open it with my
1706 * media player. I do, however, expect that if I touch a foo.h file and open it,
1707 * it will open up in my source code editor, and *not* my general purpose plain-
1708 * text handler.
1709 */
1710
1711 g_return_val_if_fail (filename != NULL, g_strdup ("application/octet-stream"));
1712 g_return_val_if_fail (info != NULL, g_strdup ("application/octet-stream"));
1713
1714 gchar *mime_type = NULL;
1715
1716 if (size > 0) {
1717 /* Default behavior */
1718 mime_type = eel_ref_str_get_unique (g_file_info_get_content_type (info));
1719 } else {
1720 gboolean uncertain;
1721 gchar *guessed_type = NULL;
1722
1723 /* Only give the file basename, not the full path. a) We may not have it yet, and
1724 * b) we don't want g_content_type_guess to keep going and snoop the file. This will
1725 * keep the guess based entirely on the extension, if there is one.
1726 */
1727 guessed_type = g_content_type_guess (filename, NULL, 0, &uncertain);
1728
1729 /* Uncertain means, it's not a registered extension, so we fall back to our (gio's)
1730 * normal behavior - text/plain (currently at least.) */
1731 if (!uncertain) {
1732 mime_type = eel_ref_str_get_unique (guessed_type);
1733 } else {
1734 mime_type = eel_ref_str_get_unique (g_file_info_get_content_type (info));
1735 }
1736
1737 g_free (guessed_type);
1738 }
1739
1740 return mime_type;
1741 }
1742
1743 static void
query_btime_async_thread(GTask * task,gpointer object,gpointer task_data,GCancellable * cancellable)1744 query_btime_async_thread (GTask *task,
1745 gpointer object,
1746 gpointer task_data,
1747 GCancellable *cancellable)
1748 {
1749 gchar *path;
1750 time_t btime;
1751
1752 btime = 0;
1753
1754 path = g_file_get_path (G_FILE (object));
1755
1756 if (path != NULL) {
1757 btime = get_file_btime (path);
1758 g_free (path);
1759 }
1760
1761 if (btime > 0) {
1762 /* Conveniently, gssize is the same as time_t */
1763 g_task_return_int (task, (gssize) btime);
1764 } else {
1765 g_task_return_error (task,
1766 g_error_new (G_FILE_ERROR,
1767 G_FILE_ERROR_FAILED,
1768 "statx failed or not supported"));
1769 }
1770 }
1771
1772 void
nemo_query_btime_async(GFile * file,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1773 nemo_query_btime_async (GFile *file,
1774 GCancellable *cancellable,
1775 GAsyncReadyCallback callback,
1776 gpointer user_data)
1777 {
1778 GTask *task;
1779
1780 task = g_task_new (file, cancellable, callback, user_data);
1781 g_task_set_priority (task, G_PRIORITY_DEFAULT);
1782 g_task_run_in_thread (task, query_btime_async_thread);
1783 g_object_unref (task);
1784 }
1785
1786 time_t
nemo_query_btime_finish(GFile * file,GAsyncResult * res,GError ** error)1787 nemo_query_btime_finish (GFile *file,
1788 GAsyncResult *res,
1789 GError **error)
1790 {
1791 g_return_val_if_fail (g_task_is_valid (res, file), -1);
1792
1793 return (time_t) g_task_propagate_int (G_TASK (res), error);
1794 }
1795
1796 /* End copied section */
1797
1798 #if !defined (NEMO_OMIT_SELF_CHECK)
1799
1800 void
nemo_self_check_file_utilities(void)1801 nemo_self_check_file_utilities (void)
1802 {
1803 }
1804
1805 #endif /* !NEMO_OMIT_SELF_CHECK */
1806