1 /* -*- Mode: C; indent-tabs-mode: f; c-basic-offset: 4; tab-width: 4 -*-
2
3 nemo-file.c: Nemo file model.
4
5 Copyright (C) 1999, 2000, 2001 Eazel, Inc.
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU 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 This program 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 General Public License for more details.
16
17 You should have received a copy of the GNU General Public
18 License along with this program; if not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
20 Boston, MA 02110-1335, USA.
21
22 Author: Darin Adler <darin@bentspoon.com>
23 */
24
25 #include <config.h>
26 #include "nemo-file.h"
27
28 #include "nemo-directory-notify.h"
29 #include "nemo-directory-private.h"
30 #include "nemo-signaller.h"
31 #include "nemo-desktop-directory.h"
32 #include "nemo-desktop-directory-file.h"
33 #include "nemo-desktop-icon-file.h"
34 #include "nemo-file-attributes.h"
35 #include "nemo-file-private.h"
36 #include "nemo-file-operations.h"
37 #include "nemo-file-utilities.h"
38 #include "nemo-global-preferences.h"
39 #include "nemo-icon-names.h"
40 #include "nemo-lib-self-check-functions.h"
41 #include "nemo-link.h"
42 #include "nemo-metadata.h"
43 #include "nemo-module.h"
44 #include "nemo-search-directory.h"
45 #include "nemo-search-directory-file.h"
46 #include "nemo-thumbnails.h"
47 #include "nemo-trash-monitor.h"
48 #include "nemo-vfs-file.h"
49 #include "nemo-file-undo-operations.h"
50 #include "nemo-file-undo-manager.h"
51 #include "nemo-saved-search-file.h"
52 #include <eel/eel-debug.h>
53 #include <eel/eel-glib-extensions.h>
54 #include <eel/eel-gtk-extensions.h>
55 #include <eel/eel-vfs-extensions.h>
56 #include <eel/eel-string.h>
57 #include <grp.h>
58 #include <gtk/gtk.h>
59 #include <glib/gi18n.h>
60 #include <glib/gstdio.h>
61 #include <gio/gio.h>
62 #include <glib.h>
63 #include <libnemo-extension/nemo-file-info.h>
64 #include <libnemo-extension/nemo-extension-private.h>
65 #include <libxapp/xapp-favorites.h>
66 #include <libxml/parser.h>
67 #include <pwd.h>
68 #include <stdlib.h>
69 #include <sys/time.h>
70 #include <time.h>
71 #include <unistd.h>
72 #include <sys/stat.h>
73 #include <errno.h>
74
75 #ifdef HAVE_SELINUX
76 #include <selinux/selinux.h>
77 #endif
78
79 #define DEBUG_FLAG NEMO_DEBUG_FILE
80 #include <libnemo-private/nemo-debug.h>
81
82 /* Time in seconds to cache getpwuid results */
83 #define GETPWUID_CACHE_TIME (5*60)
84
85 #define ICON_NAME_THUMBNAIL_LOADING "image-loading"
86
87 #undef NEMO_FILE_DEBUG_REF
88 #undef NEMO_FILE_DEBUG_REF_VALGRIND
89
90 #ifdef NEMO_FILE_DEBUG_REF_VALGRIND
91 #include <valgrind/valgrind.h>
92 #define DEBUG_REF_PRINTF VALGRIND_PRINTF_BACKTRACE
93 #else
94 #define DEBUG_REF_PRINTF printf
95 #endif
96
97 /* Files that start with these characters sort after files that don't. */
98 #define SORT_LAST_CHAR1 '.'
99 #define SORT_LAST_CHAR2 '#'
100
101 /* Name of Nemo trash directories */
102 #define TRASH_DIRECTORY_NAME ".Trash"
103
104 #define METADATA_ID_IS_LIST_MASK (1<<31)
105
106 #define MAX_THUMBNAIL_TRIES 2
107
108 typedef enum {
109 SHOW_HIDDEN = 1 << 0,
110 } FilterOptions;
111
112 typedef enum {
113 NEMO_DATE_FORMAT_REGULAR = 0,
114 NEMO_DATE_FORMAT_REGULAR_WITH_TIME = 1,
115 NEMO_DATE_FORMAT_FULL = 2,
116 } NemoDateCompactFormat;
117
118 typedef void (* ModifyListFunction) (GList **list, NemoFile *file);
119
120 enum {
121 CHANGED,
122 UPDATED_DEEP_COUNT_IN_PROGRESS,
123 LAST_SIGNAL
124 };
125
126 static guint signals[LAST_SIGNAL] = { 0 };
127
128 static GHashTable *symbolic_links;
129
130 static GQuark attribute_name_q,
131 attribute_size_q,
132 attribute_type_q,
133 attribute_detailed_type_q,
134 attribute_modification_date_q,
135 attribute_date_modified_q,
136 attribute_date_modified_full_q,
137 attribute_date_modified_with_time_q,
138 attribute_accessed_date_q,
139 attribute_date_accessed_q,
140 attribute_date_accessed_full_q,
141 attribute_creation_date_q,
142 attribute_date_created_q,
143 attribute_date_created_full_q,
144 attribute_date_created_with_time_q,
145 attribute_mime_type_q,
146 attribute_size_detail_q,
147 attribute_deep_size_q,
148 attribute_deep_file_count_q,
149 attribute_deep_directory_count_q,
150 attribute_deep_total_count_q,
151 attribute_date_changed_q,
152 attribute_date_changed_full_q,
153 attribute_trashed_on_q,
154 attribute_trashed_on_full_q,
155 attribute_trash_orig_path_q,
156 attribute_date_permissions_q,
157 attribute_date_permissions_full_q,
158 attribute_permissions_q,
159 attribute_selinux_context_q,
160 attribute_octal_permissions_q,
161 attribute_owner_q,
162 attribute_group_q,
163 attribute_uri_q,
164 attribute_where_q,
165 attribute_link_target_q,
166 attribute_volume_q,
167 attribute_free_space_q;
168
169 static void nemo_file_info_iface_init (NemoFileInfoInterface *iface);
170
171 static gboolean update_info_and_name (NemoFile *file,
172 GFileInfo *info);
173 static const char * nemo_file_peek_display_name (NemoFile *file);
174 static const char * nemo_file_peek_display_name_collation_key (NemoFile *file);
175 static void file_mount_unmounted (GMount *mount, gpointer data);
176 static void metadata_hash_free (GHashTable *hash);
177 static void invalidate_thumbnail (NemoFile *file);
178
179 G_DEFINE_TYPE_WITH_CODE (NemoFile, nemo_file, G_TYPE_OBJECT,
180 G_IMPLEMENT_INTERFACE (NEMO_TYPE_FILE_INFO,
181 nemo_file_info_iface_init));
182
183 static void
nemo_file_init(NemoFile * file)184 nemo_file_init (NemoFile *file)
185 {
186 file->details = G_TYPE_INSTANCE_GET_PRIVATE ((file), NEMO_TYPE_FILE, NemoFileDetails);
187
188 file->details->desktop_monitor = -1;
189 file->details->cached_position_x = -1;
190 file->details->cached_position_y = -1;
191 file->details->pinning = FILE_META_STATE_INIT;
192 file->details->favorite = FILE_META_STATE_INIT;
193 file->details->load_deferred_attrs = NEMO_FILE_LOAD_DEFERRED_ATTRS_NO;
194
195 nemo_file_clear_info (file);
196 nemo_file_invalidate_extension_info_internal (file);
197
198 file->details->free_space = -1;
199 }
200
201 static GObject*
nemo_file_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_params)202 nemo_file_constructor (GType type,
203 guint n_construct_properties,
204 GObjectConstructParam *construct_params)
205 {
206 GObject *object;
207 NemoFile *file;
208
209 object = (* G_OBJECT_CLASS (nemo_file_parent_class)->constructor) (type,
210 n_construct_properties,
211 construct_params);
212
213 file = NEMO_FILE (object);
214
215 /* Set to default type after full construction */
216 if (NEMO_FILE_GET_CLASS (file)->default_file_type != G_FILE_TYPE_UNKNOWN) {
217 file->details->type = NEMO_FILE_GET_CLASS (file)->default_file_type;
218 }
219
220 return object;
221 }
222
223 gboolean
nemo_file_set_display_name(NemoFile * file,const char * display_name,const char * edit_name,gboolean custom)224 nemo_file_set_display_name (NemoFile *file,
225 const char *display_name,
226 const char *edit_name,
227 gboolean custom)
228 {
229 gboolean changed;
230
231 if (custom && display_name == NULL) {
232 /* We're re-setting a custom display name, invalidate it if
233 we already set it so that the old one is re-read */
234 if (file->details->got_custom_display_name) {
235 file->details->got_custom_display_name = FALSE;
236 nemo_file_invalidate_attributes (file,
237 NEMO_FILE_ATTRIBUTE_INFO);
238 }
239 return FALSE;
240 }
241
242 if (display_name == NULL || *display_name == 0) {
243 return FALSE;
244 }
245
246 if (!custom && file->details->got_custom_display_name) {
247 return FALSE;
248 }
249
250 if (edit_name == NULL) {
251 edit_name = display_name;
252 }
253
254 changed = FALSE;
255
256 if (g_strcmp0 (eel_ref_str_peek (file->details->display_name), display_name) != 0) {
257 changed = TRUE;
258
259 eel_ref_str_unref (file->details->display_name);
260
261 if (g_strcmp0 (eel_ref_str_peek (file->details->name), display_name) == 0) {
262 file->details->display_name = eel_ref_str_ref (file->details->name);
263 } else {
264 file->details->display_name = eel_ref_str_new (display_name);
265 }
266
267 g_free (file->details->display_name_collation_key);
268 file->details->display_name_collation_key = g_utf8_collate_key_for_filename (display_name, -1);
269 }
270
271 if (g_strcmp0 (eel_ref_str_peek (file->details->edit_name), edit_name) != 0) {
272 changed = TRUE;
273
274 eel_ref_str_unref (file->details->edit_name);
275 if (g_strcmp0 (eel_ref_str_peek (file->details->display_name), edit_name) == 0) {
276 file->details->edit_name = eel_ref_str_ref (file->details->display_name);
277 } else {
278 file->details->edit_name = eel_ref_str_new (edit_name);
279 }
280 }
281
282 file->details->got_custom_display_name = custom;
283 return changed;
284 }
285
286 static void
nemo_file_clear_display_name(NemoFile * file)287 nemo_file_clear_display_name (NemoFile *file)
288 {
289 eel_ref_str_unref (file->details->display_name);
290 file->details->display_name = NULL;
291 g_free (file->details->display_name_collation_key);
292 file->details->display_name_collation_key = NULL;
293 eel_ref_str_unref (file->details->edit_name);
294 file->details->edit_name = NULL;
295 }
296
297 static gboolean
foreach_metadata_free(gpointer key,gpointer value,gpointer user_data)298 foreach_metadata_free (gpointer key,
299 gpointer value,
300 gpointer user_data)
301 {
302 guint id;
303
304 id = GPOINTER_TO_UINT (key);
305
306 if (id & METADATA_ID_IS_LIST_MASK) {
307 g_strfreev ((char **)value);
308 } else {
309 g_free ((char *)value);
310 }
311 return TRUE;
312 }
313
314
315 static void
metadata_hash_free(GHashTable * hash)316 metadata_hash_free (GHashTable *hash)
317 {
318 g_hash_table_foreach_remove (hash,
319 foreach_metadata_free,
320 NULL);
321 g_hash_table_destroy (hash);
322 }
323
324 static gboolean
metadata_hash_equal(GHashTable * hash1,GHashTable * hash2)325 metadata_hash_equal (GHashTable *hash1,
326 GHashTable *hash2)
327 {
328 GHashTableIter iter;
329 gpointer key1, value1, value2;
330 guint id;
331
332 if (hash1 == NULL && hash2 == NULL) {
333 return TRUE;
334 }
335
336 if (hash1 == NULL || hash2 == NULL) {
337 return FALSE;
338 }
339
340 if (g_hash_table_size (hash1) !=
341 g_hash_table_size (hash2)) {
342 return FALSE;
343 }
344
345 g_hash_table_iter_init (&iter, hash1);
346 while (g_hash_table_iter_next (&iter, &key1, &value1)) {
347 value2 = g_hash_table_lookup (hash2, key1);
348 if (value2 == NULL) {
349 return FALSE;
350 }
351 id = GPOINTER_TO_UINT (key1);
352 if (id & METADATA_ID_IS_LIST_MASK) {
353 if (!eel_g_strv_equal ((char **)value1, (char **)value2)) {
354 return FALSE;
355 }
356 } else {
357 if (strcmp ((char *)value1, (char *)value2) != 0) {
358 return FALSE;
359 }
360 }
361 }
362
363 return TRUE;
364 }
365
366 static void
clear_metadata(NemoFile * file)367 clear_metadata (NemoFile *file)
368 {
369 if (file->details->metadata) {
370 metadata_hash_free (file->details->metadata);
371 file->details->metadata = NULL;
372 }
373 }
374
375 static GHashTable *
get_metadata_from_info(GFileInfo * info)376 get_metadata_from_info (GFileInfo *info)
377 {
378 GHashTable *metadata;
379 char **attrs;
380 guint id;
381 int i;
382 GFileAttributeType type;
383 gpointer value;
384
385 attrs = g_file_info_list_attributes (info, "metadata");
386
387 metadata = g_hash_table_new (NULL, NULL);
388
389 for (i = 0; attrs[i] != NULL; i++) {
390 id = nemo_metadata_get_id (attrs[i] + strlen ("metadata::"));
391 if (id == 0) {
392 continue;
393 }
394
395 if (!g_file_info_get_attribute_data (info, attrs[i],
396 &type, &value, NULL)) {
397 continue;
398 }
399
400 if (type == G_FILE_ATTRIBUTE_TYPE_STRING) {
401 g_hash_table_insert (metadata, GUINT_TO_POINTER (id),
402 g_strdup ((char *)value));
403 } else if (type == G_FILE_ATTRIBUTE_TYPE_STRINGV) {
404 id |= METADATA_ID_IS_LIST_MASK;
405 g_hash_table_insert (metadata, GUINT_TO_POINTER (id),
406 g_strdupv ((char **)value));
407 }
408 }
409
410 g_strfreev (attrs);
411
412 return metadata;
413 }
414
415 gboolean
nemo_file_update_metadata_from_info(NemoFile * file,GFileInfo * info)416 nemo_file_update_metadata_from_info (NemoFile *file,
417 GFileInfo *info)
418 {
419 gboolean changed = FALSE;
420
421 if (g_file_info_has_namespace (info, "metadata")) {
422 GHashTable *metadata;
423
424 metadata = get_metadata_from_info (info);
425 if (!metadata_hash_equal (metadata,
426 file->details->metadata)) {
427 changed = TRUE;
428 clear_metadata (file);
429 file->details->metadata = metadata;
430 } else {
431 metadata_hash_free (metadata);
432 }
433 } else if (file->details->metadata) {
434 changed = TRUE;
435 clear_metadata (file);
436 }
437
438 return changed;
439 }
440
441 void
nemo_file_clear_info(NemoFile * file)442 nemo_file_clear_info (NemoFile *file)
443 {
444 file->details->got_file_info = FALSE;
445 if (file->details->get_info_error) {
446 g_error_free (file->details->get_info_error);
447 file->details->get_info_error = NULL;
448 }
449 /* Reset to default type, which might be other than unknown for
450 special kinds of files like the desktop or a search directory */
451 file->details->type = NEMO_FILE_GET_CLASS (file)->default_file_type;
452
453 if (!file->details->got_custom_display_name) {
454 nemo_file_clear_display_name (file);
455 }
456
457 if (!file->details->got_custom_activation_uri &&
458 file->details->activation_uri != NULL) {
459 g_free (file->details->activation_uri);
460 file->details->activation_uri = NULL;
461 }
462
463 if (file->details->icon != NULL) {
464 g_object_unref (file->details->icon);
465 file->details->icon = NULL;
466 }
467
468 g_clear_object (&file->details->thumbnail);
469
470 g_free (file->details->thumbnail_path);
471 file->details->thumbnail_path = NULL;
472 file->details->thumbnailing_failed = FALSE;
473 file->details->thumbnail_throttle_count = 1;
474 file->details->last_thumbnail_try_mtime = 0;
475
476 file->details->is_launcher = FALSE;
477 file->details->is_foreign_link = FALSE;
478 file->details->is_trusted_link = FALSE;
479 file->details->is_symlink = FALSE;
480 file->details->is_hidden = FALSE;
481 file->details->is_mountpoint = FALSE;
482 file->details->uid = -1;
483 file->details->gid = -1;
484 file->details->can_read = TRUE;
485 file->details->can_write = TRUE;
486 file->details->can_execute = TRUE;
487 file->details->can_delete = TRUE;
488 file->details->can_trash = TRUE;
489 file->details->can_rename = TRUE;
490 file->details->can_mount = FALSE;
491 file->details->can_unmount = FALSE;
492 file->details->can_eject = FALSE;
493 file->details->can_start = FALSE;
494 file->details->can_start_degraded = FALSE;
495 file->details->can_stop = FALSE;
496 file->details->start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
497 file->details->can_poll_for_media = FALSE;
498 file->details->is_media_check_automatic = FALSE;
499 file->details->has_permissions = FALSE;
500 file->details->permissions = 0;
501 file->details->size = -1;
502 file->details->sort_order = 0;
503 file->details->mtime = 0;
504 file->details->atime = 0;
505 file->details->ctime = 0;
506 file->details->btime = 0;
507 file->details->trash_time = 0;
508 file->details->load_deferred_attrs = NEMO_FILE_LOAD_DEFERRED_ATTRS_NO;
509 g_free (file->details->symlink_name);
510 file->details->symlink_name = NULL;
511 eel_ref_str_unref (file->details->mime_type);
512 file->details->mime_type = NULL;
513 g_free (file->details->selinux_context);
514 file->details->selinux_context = NULL;
515 g_free (file->details->description);
516 file->details->description = NULL;
517 eel_ref_str_unref (file->details->owner);
518 file->details->owner = NULL;
519 eel_ref_str_unref (file->details->owner_real);
520 file->details->owner_real = NULL;
521 eel_ref_str_unref (file->details->group);
522 file->details->group = NULL;
523
524 eel_ref_str_unref (file->details->filesystem_id);
525 file->details->filesystem_id = NULL;
526
527 file->details->is_desktop_orphan = FALSE;
528
529 file->details->desktop_monitor = -1;
530
531 clear_metadata (file);
532 }
533
534 static NemoFile *
nemo_file_new_from_filename(NemoDirectory * directory,const char * filename,gboolean self_owned)535 nemo_file_new_from_filename (NemoDirectory *directory,
536 const char *filename,
537 gboolean self_owned)
538 {
539 NemoFile *file;
540
541 g_assert (NEMO_IS_DIRECTORY (directory));
542 g_assert (filename != NULL);
543 g_assert (filename[0] != '\0');
544
545 if (NEMO_IS_DESKTOP_DIRECTORY (directory)) {
546 if (self_owned) {
547 file = NEMO_FILE (g_object_new (NEMO_TYPE_DESKTOP_DIRECTORY_FILE, NULL));
548 } else {
549 /* This doesn't normally happen, unless the user somehow types in a uri
550 * that references a file like this. (See #349840) */
551 file = NEMO_FILE (g_object_new (NEMO_TYPE_VFS_FILE, NULL));
552 }
553 } else if (NEMO_IS_SEARCH_DIRECTORY (directory)) {
554 if (self_owned) {
555 file = NEMO_FILE (g_object_new (NEMO_TYPE_SEARCH_DIRECTORY_FILE, NULL));
556 } else {
557 /* This doesn't normally happen, unless the user somehow types in a uri
558 * that references a file like this. (See #349840) */
559 file = NEMO_FILE (g_object_new (NEMO_TYPE_VFS_FILE, NULL));
560 }
561 } else if (g_str_has_suffix (filename, NEMO_SAVED_SEARCH_EXTENSION)) {
562 file = NEMO_FILE (g_object_new (NEMO_TYPE_SAVED_SEARCH_FILE, NULL));
563 } else {
564 file = NEMO_FILE (g_object_new (NEMO_TYPE_VFS_FILE, NULL));
565 }
566
567 file->details->directory = nemo_directory_ref (directory);
568
569 file->details->name = eel_ref_str_new (filename);
570
571 #ifdef NEMO_FILE_DEBUG_REF
572 DEBUG_REF_PRINTF("%10p ref'd\n", file);
573 #endif
574
575 return file;
576 }
577
578 static void
modify_link_hash_table(NemoFile * file,ModifyListFunction modify_function)579 modify_link_hash_table (NemoFile *file,
580 ModifyListFunction modify_function)
581 {
582 char *target_uri;
583 gboolean found;
584 gpointer original_key;
585 GList **list_ptr;
586
587 /* Check if there is a symlink name. If none, we are OK. */
588 if (file->details->symlink_name == NULL) {
589 return;
590 }
591
592 /* Create the hash table first time through. */
593 if (symbolic_links == NULL) {
594 symbolic_links = g_hash_table_new (g_str_hash, g_str_equal);
595 }
596
597 target_uri = nemo_file_get_symbolic_link_target_uri (file);
598
599 /* Find the old contents of the hash table. */
600 found = g_hash_table_lookup_extended
601 (symbolic_links, target_uri,
602 &original_key, (gpointer *)&list_ptr);
603 if (!found) {
604 list_ptr = g_new0 (GList *, 1);
605 original_key = g_strdup (target_uri);
606 g_hash_table_insert (symbolic_links, original_key, list_ptr);
607 }
608 (* modify_function) (list_ptr, file);
609 if (*list_ptr == NULL) {
610 g_hash_table_remove (symbolic_links, target_uri);
611 g_free (list_ptr);
612 g_free (original_key);
613 }
614 g_free (target_uri);
615 }
616
617 static void
symbolic_link_weak_notify(gpointer data,GObject * where_the_object_was)618 symbolic_link_weak_notify (gpointer data,
619 GObject *where_the_object_was)
620 {
621 GList **list = data;
622 /* This really shouldn't happen, but we're seeing some strange things in
623 bug #358172 where the symlink hashtable isn't correctly updated. */
624 *list = g_list_remove (*list, where_the_object_was);
625 }
626
627 static void
add_to_link_hash_table_list(GList ** list,NemoFile * file)628 add_to_link_hash_table_list (GList **list, NemoFile *file)
629 {
630 if (g_list_find (*list, file) != NULL) {
631 g_warning ("Adding file to symlink_table multiple times. "
632 "Please add feedback of what you were doing at http://bugzilla.gnome.org/show_bug.cgi?id=358172\n");
633 return;
634 }
635 g_object_weak_ref (G_OBJECT (file), symbolic_link_weak_notify, list);
636 *list = g_list_prepend (*list, file);
637 }
638
639 static void
add_to_link_hash_table(NemoFile * file)640 add_to_link_hash_table (NemoFile *file)
641 {
642 modify_link_hash_table (file, add_to_link_hash_table_list);
643 }
644
645 static void
remove_from_link_hash_table_list(GList ** list,NemoFile * file)646 remove_from_link_hash_table_list (GList **list, NemoFile *file)
647 {
648 if (g_list_find (*list, file) != NULL) {
649 g_object_weak_unref (G_OBJECT (file), symbolic_link_weak_notify, list);
650 *list = g_list_remove (*list, file);
651 }
652 }
653
654 static void
remove_from_link_hash_table(NemoFile * file)655 remove_from_link_hash_table (NemoFile *file)
656 {
657 modify_link_hash_table (file, remove_from_link_hash_table_list);
658 }
659
660 NemoFile *
nemo_file_new_from_info(NemoDirectory * directory,GFileInfo * info)661 nemo_file_new_from_info (NemoDirectory *directory,
662 GFileInfo *info)
663 {
664 NemoFile *file;
665 const char *mime_type;
666
667 g_return_val_if_fail (NEMO_IS_DIRECTORY (directory), NULL);
668 g_return_val_if_fail (info != NULL, NULL);
669
670 mime_type = g_file_info_get_content_type (info);
671 if (mime_type &&
672 strcmp (mime_type, NEMO_SAVED_SEARCH_MIMETYPE) == 0) {
673 g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
674 file = NEMO_FILE (g_object_new (NEMO_TYPE_SAVED_SEARCH_FILE, NULL));
675 } else {
676 file = NEMO_FILE (g_object_new (NEMO_TYPE_VFS_FILE, NULL));
677 }
678
679 file->details->directory = nemo_directory_ref (directory);
680
681 update_info_and_name (file, info);
682
683 #ifdef NEMO_FILE_DEBUG_REF
684 DEBUG_REF_PRINTF("%10p ref'd\n", file);
685 #endif
686
687 return file;
688 }
689
690 static NemoFile *
nemo_file_get_internal(GFile * location,gboolean create)691 nemo_file_get_internal (GFile *location, gboolean create)
692 {
693 gboolean self_owned;
694 NemoDirectory *directory;
695 NemoFile *file;
696 GFile *parent;
697 char *basename;
698
699 g_assert (location != NULL);
700
701 parent = g_file_get_parent (location);
702
703 self_owned = FALSE;
704 if (parent == NULL) {
705 self_owned = TRUE;
706 parent = g_object_ref (location);
707 }
708
709 /* Get object that represents the directory. */
710 directory = nemo_directory_get_internal (parent, create);
711
712 g_object_unref (parent);
713
714 /* Get the name for the file. */
715 if (self_owned && directory != NULL) {
716 basename = nemo_directory_get_name_for_self_as_new_file (directory);
717 } else {
718 basename = g_file_get_basename (location);
719 }
720 /* Check to see if it's a file that's already known. */
721 if (directory == NULL) {
722 file = NULL;
723 } else if (self_owned) {
724 file = directory->details->as_file;
725 } else {
726 file = nemo_directory_find_file_by_name (directory, basename);
727 }
728
729 /* Ref or create the file. */
730 if (file != NULL) {
731 nemo_file_ref (file);
732 } else if (create && directory != NULL) {
733 file = nemo_file_new_from_filename (directory, basename, self_owned);
734 if (self_owned) {
735 g_assert (directory->details->as_file == NULL);
736 directory->details->as_file = file;
737 } else {
738 nemo_directory_add_file (directory, file);
739 }
740 }
741
742 g_free (basename);
743 nemo_directory_unref (directory);
744
745 return file;
746 }
747
748 NemoFile *
nemo_file_get(GFile * location)749 nemo_file_get (GFile *location)
750 {
751 return nemo_file_get_internal (location, TRUE);
752 }
753
754 NemoFile *
nemo_file_get_existing(GFile * location)755 nemo_file_get_existing (GFile *location)
756 {
757 return nemo_file_get_internal (location, FALSE);
758 }
759
760 NemoFile *
nemo_file_get_existing_by_uri(const char * uri)761 nemo_file_get_existing_by_uri (const char *uri)
762 {
763 GFile *location;
764 NemoFile *file;
765
766 location = g_file_new_for_uri (uri);
767 file = nemo_file_get_internal (location, FALSE);
768 g_object_unref (location);
769
770 return file;
771 }
772
773 NemoFile *
nemo_file_get_by_uri(const char * uri)774 nemo_file_get_by_uri (const char *uri)
775 {
776 GFile *location;
777 NemoFile *file;
778
779 location = g_file_new_for_uri (uri);
780 file = nemo_file_get_internal (location, TRUE);
781 g_object_unref (location);
782
783 return file;
784 }
785
786 gboolean
nemo_file_is_self_owned(NemoFile * file)787 nemo_file_is_self_owned (NemoFile *file)
788 {
789 return file->details->directory->details->as_file == file;
790 }
791
792 static void
finalize(GObject * object)793 finalize (GObject *object)
794 {
795 NemoDirectory *directory;
796 NemoFile *file;
797 char *uri;
798
799 file = NEMO_FILE (object);
800
801 g_assert (file->details->operations_in_progress == NULL);
802
803 if (file->details->is_thumbnailing) {
804 uri = nemo_file_get_uri (file);
805 nemo_thumbnail_remove_from_queue (uri);
806 g_free (uri);
807 }
808
809 nemo_async_destroying_file (file);
810
811 remove_from_link_hash_table (file);
812
813 directory = file->details->directory;
814
815 if (nemo_file_is_self_owned (file)) {
816 directory->details->as_file = NULL;
817 } else {
818 if (!file->details->is_gone) {
819 nemo_directory_remove_file (directory, file);
820 }
821 }
822
823 if (file->details->get_info_error) {
824 g_error_free (file->details->get_info_error);
825 }
826
827 nemo_directory_unref (directory);
828 eel_ref_str_unref (file->details->name);
829 eel_ref_str_unref (file->details->display_name);
830 g_free (file->details->display_name_collation_key);
831 eel_ref_str_unref (file->details->edit_name);
832 if (file->details->icon) {
833 g_object_unref (file->details->icon);
834 }
835 g_free (file->details->thumbnail_path);
836 g_free (file->details->symlink_name);
837 eel_ref_str_unref (file->details->mime_type);
838 eel_ref_str_unref (file->details->owner);
839 eel_ref_str_unref (file->details->owner_real);
840 eel_ref_str_unref (file->details->group);
841 g_free (file->details->selinux_context);
842 g_free (file->details->description);
843 g_free (file->details->activation_uri);
844 g_clear_object (&file->details->custom_icon);
845
846 g_clear_object (&file->details->thumbnail);
847
848 if (file->details->mount) {
849 g_signal_handlers_disconnect_by_func (file->details->mount, file_mount_unmounted, file);
850 g_object_unref (file->details->mount);
851 }
852
853 eel_ref_str_unref (file->details->filesystem_id);
854 g_free (file->details->trash_orig_path);
855
856 g_list_free_full (file->details->mime_list, g_free);
857 g_list_free_full (file->details->pending_extension_emblems, g_free);
858 g_list_free_full (file->details->extension_emblems, g_free);
859 g_list_free_full (file->details->pending_info_providers, g_object_unref);
860
861 if (file->details->pending_extension_attributes) {
862 g_hash_table_destroy (file->details->pending_extension_attributes);
863 }
864
865 if (file->details->extension_attributes) {
866 g_hash_table_destroy (file->details->extension_attributes);
867 }
868
869 if (file->details->metadata) {
870 metadata_hash_free (file->details->metadata);
871 }
872
873 G_OBJECT_CLASS (nemo_file_parent_class)->finalize (object);
874 }
875
876 NemoFile *
nemo_file_ref(NemoFile * file)877 nemo_file_ref (NemoFile *file)
878 {
879 if (file == NULL) {
880 return NULL;
881 }
882 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
883
884 #ifdef NEMO_FILE_DEBUG_REF
885 DEBUG_REF_PRINTF("%10p ref'd\n", file);
886 #endif
887
888 return g_object_ref (file);
889 }
890
891 void
nemo_file_unref(NemoFile * file)892 nemo_file_unref (NemoFile *file)
893 {
894 if (file == NULL) {
895 return;
896 }
897
898 g_return_if_fail (NEMO_IS_FILE (file));
899
900 #ifdef NEMO_FILE_DEBUG_REF
901 DEBUG_REF_PRINTF("%10p unref'd\n", file);
902 #endif
903
904 g_object_unref (file);
905 }
906
907 /**
908 * nemo_file_get_parent_uri_for_display:
909 *
910 * Get the uri for the parent directory.
911 *
912 * @file: The file in question.
913 *
914 * Return value: A string representing the parent's location,
915 * formatted for user display (including stripping "file://").
916 * If the parent is NULL, returns the empty string.
917 */
918 char *
nemo_file_get_parent_uri_for_display(NemoFile * file)919 nemo_file_get_parent_uri_for_display (NemoFile *file)
920 {
921 GFile *parent;
922 char *result;
923
924 g_assert (NEMO_IS_FILE (file));
925
926 parent = nemo_file_get_parent_location (file);
927 if (parent) {
928 result = g_file_get_parse_name (parent);
929 g_object_unref (parent);
930 } else {
931 result = g_strdup ("");
932 }
933
934 return result;
935 }
936
937 /**
938 * nemo_file_get_parent_uri:
939 *
940 * Get the uri for the parent directory.
941 *
942 * @file: The file in question.
943 *
944 * Return value: A string for the parent's location, in "raw URI" form.
945 * Use nemo_file_get_parent_uri_for_display instead if the
946 * result is to be displayed on-screen.
947 * If the parent is NULL, returns the empty string.
948 */
949 char *
nemo_file_get_parent_uri(NemoFile * file)950 nemo_file_get_parent_uri (NemoFile *file)
951 {
952 g_assert (NEMO_IS_FILE (file));
953
954 if (nemo_file_is_self_owned (file)) {
955 /* Callers expect an empty string, not a NULL. */
956 return g_strdup ("");
957 }
958
959 return nemo_directory_get_uri (file->details->directory);
960 }
961
962 GFile *
nemo_file_get_parent_location(NemoFile * file)963 nemo_file_get_parent_location (NemoFile *file)
964 {
965 g_assert (NEMO_IS_FILE (file));
966
967 if (nemo_file_is_self_owned (file)) {
968 /* Callers expect an empty string, not a NULL. */
969 return NULL;
970 }
971
972 return nemo_directory_get_location (file->details->directory);
973 }
974
975 NemoFile *
nemo_file_get_parent(NemoFile * file)976 nemo_file_get_parent (NemoFile *file)
977 {
978 g_assert (NEMO_IS_FILE (file));
979
980 if (nemo_file_is_self_owned (file)) {
981 return NULL;
982 }
983
984 return nemo_directory_get_corresponding_file (file->details->directory);
985 }
986
987 /**
988 * nemo_file_can_read:
989 *
990 * Check whether the user is allowed to read the contents of this file.
991 *
992 * @file: The file to check.
993 *
994 * Return value: FALSE if the user is definitely not allowed to read
995 * the contents of the file. If the user has read permission, or
996 * the code can't tell whether the user has read permission,
997 * returns TRUE (so failures must always be handled).
998 */
999 gboolean
nemo_file_can_read(NemoFile * file)1000 nemo_file_can_read (NemoFile *file)
1001 {
1002 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1003
1004 return file->details->can_read;
1005 }
1006
1007 /**
1008 * nemo_file_can_write:
1009 *
1010 * Check whether the user is allowed to write to this file.
1011 *
1012 * @file: The file to check.
1013 *
1014 * Return value: FALSE if the user is definitely not allowed to write
1015 * to the file. If the user has write permission, or
1016 * the code can't tell whether the user has write permission,
1017 * returns TRUE (so failures must always be handled).
1018 */
1019 gboolean
nemo_file_can_write(NemoFile * file)1020 nemo_file_can_write (NemoFile *file)
1021 {
1022 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1023
1024 return file->details->can_write;
1025 }
1026
1027 /**
1028 * nemo_file_can_execute:
1029 *
1030 * Check whether the user is allowed to execute this file.
1031 *
1032 * @file: The file to check.
1033 *
1034 * Return value: FALSE if the user is definitely not allowed to execute
1035 * the file. If the user has execute permission, or
1036 * the code can't tell whether the user has execute permission,
1037 * returns TRUE (so failures must always be handled).
1038 */
1039 gboolean
nemo_file_can_execute(NemoFile * file)1040 nemo_file_can_execute (NemoFile *file)
1041 {
1042 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1043
1044 return file->details->can_execute;
1045 }
1046
1047 gboolean
nemo_file_can_mount(NemoFile * file)1048 nemo_file_can_mount (NemoFile *file)
1049 {
1050 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1051
1052 return file->details->can_mount;
1053 }
1054
1055 gboolean
nemo_file_can_unmount(NemoFile * file)1056 nemo_file_can_unmount (NemoFile *file)
1057 {
1058 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1059
1060 if (getenv("LTSP_CLIENT")) {
1061 return FALSE;
1062 }
1063
1064 return file->details->can_unmount ||
1065 (file->details->mount != NULL &&
1066 g_mount_can_unmount (file->details->mount));
1067 }
1068
1069 gboolean
nemo_file_can_eject(NemoFile * file)1070 nemo_file_can_eject (NemoFile *file)
1071 {
1072 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1073
1074 if (getenv("LTSP_CLIENT")) {
1075 return FALSE;
1076 }
1077
1078 return file->details->can_eject ||
1079 (file->details->mount != NULL &&
1080 g_mount_can_eject (file->details->mount));
1081 }
1082
1083 gboolean
nemo_file_can_start(NemoFile * file)1084 nemo_file_can_start (NemoFile *file)
1085 {
1086 gboolean ret;
1087 GDrive *drive;
1088
1089 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1090
1091 ret = FALSE;
1092
1093 if (file->details->can_start) {
1094 ret = TRUE;
1095 goto out;
1096 }
1097
1098 if (file->details->mount != NULL) {
1099 drive = g_mount_get_drive (file->details->mount);
1100 if (drive != NULL) {
1101 ret = g_drive_can_start (drive);
1102 g_object_unref (drive);
1103 }
1104 }
1105
1106 out:
1107 return ret;
1108 }
1109
1110 gboolean
nemo_file_can_start_degraded(NemoFile * file)1111 nemo_file_can_start_degraded (NemoFile *file)
1112 {
1113 gboolean ret;
1114 GDrive *drive;
1115
1116 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1117
1118 ret = FALSE;
1119
1120 if (file->details->can_start_degraded) {
1121 ret = TRUE;
1122 goto out;
1123 }
1124
1125 if (file->details->mount != NULL) {
1126 drive = g_mount_get_drive (file->details->mount);
1127 if (drive != NULL) {
1128 ret = g_drive_can_start_degraded (drive);
1129 g_object_unref (drive);
1130 }
1131 }
1132
1133 out:
1134 return ret;
1135 }
1136
1137 gboolean
nemo_file_can_poll_for_media(NemoFile * file)1138 nemo_file_can_poll_for_media (NemoFile *file)
1139 {
1140 gboolean ret;
1141 GDrive *drive;
1142
1143 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1144
1145 ret = FALSE;
1146
1147 if (file->details->can_poll_for_media) {
1148 ret = TRUE;
1149 goto out;
1150 }
1151
1152 if (file->details->mount != NULL) {
1153 drive = g_mount_get_drive (file->details->mount);
1154 if (drive != NULL) {
1155 ret = g_drive_can_poll_for_media (drive);
1156 g_object_unref (drive);
1157 }
1158 }
1159
1160 out:
1161 return ret;
1162 }
1163
1164 gboolean
nemo_file_is_media_check_automatic(NemoFile * file)1165 nemo_file_is_media_check_automatic (NemoFile *file)
1166 {
1167 gboolean ret;
1168 GDrive *drive;
1169
1170 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1171
1172 ret = FALSE;
1173
1174 if (file->details->is_media_check_automatic) {
1175 ret = TRUE;
1176 goto out;
1177 }
1178
1179 if (file->details->mount != NULL) {
1180 drive = g_mount_get_drive (file->details->mount);
1181 if (drive != NULL) {
1182 ret = g_drive_is_media_check_automatic (drive);
1183 g_object_unref (drive);
1184 }
1185 }
1186
1187 out:
1188 return ret;
1189 }
1190
1191
1192 gboolean
nemo_file_can_stop(NemoFile * file)1193 nemo_file_can_stop (NemoFile *file)
1194 {
1195 gboolean ret;
1196 GDrive *drive;
1197
1198 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1199
1200 ret = FALSE;
1201
1202 if (file->details->can_stop) {
1203 ret = TRUE;
1204 goto out;
1205 }
1206
1207 if (file->details->mount != NULL) {
1208 drive = g_mount_get_drive (file->details->mount);
1209 if (drive != NULL) {
1210 ret = g_drive_can_stop (drive);
1211 g_object_unref (drive);
1212 }
1213 }
1214
1215 out:
1216 return ret;
1217 }
1218
1219 GDriveStartStopType
nemo_file_get_start_stop_type(NemoFile * file)1220 nemo_file_get_start_stop_type (NemoFile *file)
1221 {
1222 GDriveStartStopType ret;
1223 GDrive *drive;
1224
1225 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1226
1227 ret = file->details->start_stop_type;
1228 if (ret != G_DRIVE_START_STOP_TYPE_UNKNOWN)
1229 goto out;
1230
1231 if (file->details->mount != NULL) {
1232 drive = g_mount_get_drive (file->details->mount);
1233 if (drive != NULL) {
1234 ret = g_drive_get_start_stop_type (drive);
1235 g_object_unref (drive);
1236 }
1237 }
1238
1239 out:
1240 return ret;
1241 }
1242
1243 void
nemo_file_mount(NemoFile * file,GMountOperation * mount_op,GCancellable * cancellable,NemoFileOperationCallback callback,gpointer callback_data)1244 nemo_file_mount (NemoFile *file,
1245 GMountOperation *mount_op,
1246 GCancellable *cancellable,
1247 NemoFileOperationCallback callback,
1248 gpointer callback_data)
1249 {
1250 GError *error;
1251
1252 if (NEMO_FILE_GET_CLASS (file)->mount == NULL) {
1253 if (callback) {
1254 error = NULL;
1255 g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1256 _("This file cannot be mounted"));
1257 callback (file, NULL, error, callback_data);
1258 g_error_free (error);
1259 }
1260 } else {
1261 NEMO_FILE_GET_CLASS (file)->mount (file, mount_op, cancellable, callback, callback_data);
1262 }
1263 }
1264
1265 typedef struct {
1266 NemoFile *file;
1267 NemoFileOperationCallback callback;
1268 gpointer callback_data;
1269 } UnmountData;
1270
1271 static void
unmount_done(void * callback_data)1272 unmount_done (void *callback_data)
1273 {
1274 UnmountData *data;
1275
1276 data = (UnmountData *)callback_data;
1277 if (data->callback) {
1278 data->callback (data->file, NULL, NULL, data->callback_data);
1279 }
1280 nemo_file_unref (data->file);
1281 g_free (data);
1282 }
1283
1284 void
nemo_file_unmount(NemoFile * file,GMountOperation * mount_op,GCancellable * cancellable,NemoFileOperationCallback callback,gpointer callback_data)1285 nemo_file_unmount (NemoFile *file,
1286 GMountOperation *mount_op,
1287 GCancellable *cancellable,
1288 NemoFileOperationCallback callback,
1289 gpointer callback_data)
1290 {
1291 GError *error;
1292 UnmountData *data;
1293
1294 if (file->details->can_unmount) {
1295 if (NEMO_FILE_GET_CLASS (file)->unmount != NULL) {
1296 NEMO_FILE_GET_CLASS (file)->unmount (file, mount_op, cancellable, callback, callback_data);
1297 } else {
1298 if (callback) {
1299 error = NULL;
1300 g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1301 _("This file cannot be unmounted"));
1302 callback (file, NULL, error, callback_data);
1303 g_error_free (error);
1304 }
1305 }
1306 } else if (file->details->mount != NULL &&
1307 g_mount_can_unmount (file->details->mount)) {
1308 data = g_new0 (UnmountData, 1);
1309 data->file = nemo_file_ref (file);
1310 data->callback = callback;
1311 data->callback_data = callback_data;
1312 nemo_file_operations_unmount_mount_full (NULL, file->details->mount, NULL, FALSE, TRUE, unmount_done, data);
1313 } else if (callback) {
1314 callback (file, NULL, NULL, callback_data);
1315 }
1316 }
1317
1318 void
nemo_file_eject(NemoFile * file,GMountOperation * mount_op,GCancellable * cancellable,NemoFileOperationCallback callback,gpointer callback_data)1319 nemo_file_eject (NemoFile *file,
1320 GMountOperation *mount_op,
1321 GCancellable *cancellable,
1322 NemoFileOperationCallback callback,
1323 gpointer callback_data)
1324 {
1325 GError *error;
1326 UnmountData *data;
1327
1328 if (file->details->can_eject) {
1329 if (NEMO_FILE_GET_CLASS (file)->eject != NULL) {
1330 NEMO_FILE_GET_CLASS (file)->eject (file, mount_op, cancellable, callback, callback_data);
1331 } else {
1332 if (callback) {
1333 error = NULL;
1334 g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1335 _("This file cannot be ejected"));
1336 callback (file, NULL, error, callback_data);
1337 g_error_free (error);
1338 }
1339 }
1340 } else if (file->details->mount != NULL &&
1341 g_mount_can_eject (file->details->mount)) {
1342 data = g_new0 (UnmountData, 1);
1343 data->file = nemo_file_ref (file);
1344 data->callback = callback;
1345 data->callback_data = callback_data;
1346 nemo_file_operations_unmount_mount_full (NULL, file->details->mount, NULL, TRUE, TRUE, unmount_done, data);
1347 } else if (callback) {
1348 callback (file, NULL, NULL, callback_data);
1349 }
1350 }
1351
1352 void
nemo_file_start(NemoFile * file,GMountOperation * start_op,GCancellable * cancellable,NemoFileOperationCallback callback,gpointer callback_data)1353 nemo_file_start (NemoFile *file,
1354 GMountOperation *start_op,
1355 GCancellable *cancellable,
1356 NemoFileOperationCallback callback,
1357 gpointer callback_data)
1358 {
1359 GError *error;
1360
1361 if ((file->details->can_start || file->details->can_start_degraded) &&
1362 NEMO_FILE_GET_CLASS (file)->start != NULL) {
1363 NEMO_FILE_GET_CLASS (file)->start (file, start_op, cancellable, callback, callback_data);
1364 } else {
1365 if (callback) {
1366 error = NULL;
1367 g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1368 _("This file cannot be started"));
1369 callback (file, NULL, error, callback_data);
1370 g_error_free (error);
1371 }
1372 }
1373 }
1374
1375 static void
file_stop_callback(GObject * source_object,GAsyncResult * res,gpointer callback_data)1376 file_stop_callback (GObject *source_object,
1377 GAsyncResult *res,
1378 gpointer callback_data)
1379 {
1380 NemoFileOperation *op;
1381 gboolean stopped;
1382 GError *error;
1383
1384 op = callback_data;
1385
1386 error = NULL;
1387 stopped = g_drive_stop_finish (G_DRIVE (source_object),
1388 res, &error);
1389
1390 if (!stopped &&
1391 error->domain == G_IO_ERROR &&
1392 (error->code == G_IO_ERROR_FAILED_HANDLED ||
1393 error->code == G_IO_ERROR_CANCELLED)) {
1394 g_error_free (error);
1395 error = NULL;
1396 }
1397
1398 nemo_file_operation_complete (op, NULL, error);
1399 if (error) {
1400 g_error_free (error);
1401 }
1402 }
1403
1404 void
nemo_file_stop(NemoFile * file,GMountOperation * mount_op,GCancellable * cancellable,NemoFileOperationCallback callback,gpointer callback_data)1405 nemo_file_stop (NemoFile *file,
1406 GMountOperation *mount_op,
1407 GCancellable *cancellable,
1408 NemoFileOperationCallback callback,
1409 gpointer callback_data)
1410 {
1411 GError *error;
1412
1413 if (NEMO_FILE_GET_CLASS (file)->stop != NULL) {
1414 if (file->details->can_stop) {
1415 NEMO_FILE_GET_CLASS (file)->stop (file, mount_op, cancellable, callback, callback_data);
1416 } else {
1417 if (callback) {
1418 error = NULL;
1419 g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1420 _("This file cannot be stopped"));
1421 callback (file, NULL, error, callback_data);
1422 g_error_free (error);
1423 }
1424 }
1425 } else {
1426 GDrive *drive;
1427
1428 drive = NULL;
1429 if (file->details->mount != NULL)
1430 drive = g_mount_get_drive (file->details->mount);
1431
1432 if (drive != NULL && g_drive_can_stop (drive)) {
1433 NemoFileOperation *op;
1434
1435 op = nemo_file_operation_new (file, callback, callback_data);
1436 if (cancellable) {
1437 g_object_unref (op->cancellable);
1438 op->cancellable = g_object_ref (cancellable);
1439 }
1440
1441 g_drive_stop (drive,
1442 G_MOUNT_UNMOUNT_NONE,
1443 mount_op,
1444 op->cancellable,
1445 file_stop_callback,
1446 op);
1447 } else {
1448 if (callback) {
1449 error = NULL;
1450 g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1451 _("This file cannot be stopped"));
1452 callback (file, NULL, error, callback_data);
1453 g_error_free (error);
1454 }
1455 }
1456
1457 if (drive != NULL) {
1458 g_object_unref (drive);
1459 }
1460 }
1461 }
1462
1463 void
nemo_file_poll_for_media(NemoFile * file)1464 nemo_file_poll_for_media (NemoFile *file)
1465 {
1466 if (file->details->can_poll_for_media) {
1467 if (NEMO_FILE_GET_CLASS (file)->stop != NULL) {
1468 NEMO_FILE_GET_CLASS (file)->poll_for_media (file);
1469 }
1470 } else if (file->details->mount != NULL) {
1471 GDrive *drive;
1472 drive = g_mount_get_drive (file->details->mount);
1473 if (drive != NULL) {
1474 g_drive_poll_for_media (drive,
1475 NULL, /* cancellable */
1476 NULL, /* GAsyncReadyCallback */
1477 NULL); /* user_data */
1478 g_object_unref (drive);
1479 }
1480 }
1481 }
1482
1483 /**
1484 * nemo_file_is_desktop_directory:
1485 *
1486 * Check whether this file is the desktop directory.
1487 *
1488 * @file: The file to check.
1489 *
1490 * Return value: TRUE if this is the physical desktop directory.
1491 */
1492 gboolean
nemo_file_is_desktop_directory(NemoFile * file)1493 nemo_file_is_desktop_directory (NemoFile *file)
1494 {
1495 GFile *dir;
1496
1497 dir = file->details->directory->details->location;
1498
1499 if (dir == NULL) {
1500 return FALSE;
1501 }
1502
1503 return nemo_is_desktop_directory_file (dir, eel_ref_str_peek (file->details->name));
1504 }
1505
1506 static gboolean
is_desktop_file(NemoFile * file)1507 is_desktop_file (NemoFile *file)
1508 {
1509 return nemo_file_is_mime_type (file, "application/x-desktop");
1510 }
1511
1512 static gboolean
can_rename_desktop_file(NemoFile * file)1513 can_rename_desktop_file (NemoFile *file)
1514 {
1515 GFile *location;
1516 gboolean res;
1517
1518 location = nemo_file_get_location (file);
1519 res = g_file_is_native (location);
1520 g_object_unref (location);
1521 return res;
1522 }
1523
1524 /**
1525 * nemo_file_can_rename:
1526 *
1527 * Check whether the user is allowed to change the name of the file.
1528 *
1529 * @file: The file to check.
1530 *
1531 * Return value: FALSE if the user is definitely not allowed to change
1532 * the name of the file. If the user is allowed to change the name, or
1533 * the code can't tell whether the user is allowed to change the name,
1534 * returns TRUE (so rename failures must always be handled).
1535 */
1536 gboolean
nemo_file_can_rename(NemoFile * file)1537 nemo_file_can_rename (NemoFile *file)
1538 {
1539 gboolean can_rename;
1540
1541 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1542
1543 /* Nonexistent files can't be renamed. */
1544 if (nemo_file_is_gone (file)) {
1545 return FALSE;
1546 }
1547
1548 /* Self-owned files can't be renamed */
1549 if (nemo_file_is_self_owned (file)) {
1550 return FALSE;
1551 }
1552
1553 if ((is_desktop_file (file) && !can_rename_desktop_file (file)) ||
1554 nemo_file_is_home (file)) {
1555 return FALSE;
1556 }
1557
1558 can_rename = TRUE;
1559
1560 /* Certain types of links can't be renamed */
1561 if (NEMO_IS_DESKTOP_ICON_FILE (file)) {
1562 NemoDesktopLink *link;
1563
1564 link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (file));
1565
1566 if (link != NULL) {
1567 can_rename = nemo_desktop_link_can_rename (link);
1568 g_object_unref (link);
1569 }
1570 }
1571
1572 if (!can_rename) {
1573 return FALSE;
1574 }
1575
1576 return file->details->can_rename;
1577 }
1578
1579 gboolean
nemo_file_can_delete(NemoFile * file)1580 nemo_file_can_delete (NemoFile *file)
1581 {
1582 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1583
1584 /* Nonexistent files can't be deleted. */
1585 if (nemo_file_is_gone (file)) {
1586 return FALSE;
1587 }
1588
1589 /* Self-owned files can't be deleted */
1590 if (nemo_file_is_self_owned (file)) {
1591 return FALSE;
1592 }
1593
1594 return file->details->can_delete;
1595 }
1596
1597 gboolean
nemo_file_can_trash(NemoFile * file)1598 nemo_file_can_trash (NemoFile *file)
1599 {
1600 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
1601
1602 /* Nonexistent files can't be deleted. */
1603 if (nemo_file_is_gone (file)) {
1604 return FALSE;
1605 }
1606
1607 /* Self-owned files can't be deleted */
1608 if (nemo_file_is_self_owned (file)) {
1609 return FALSE;
1610 }
1611
1612 return file->details->can_trash;
1613 }
1614
1615 GFile *
nemo_file_get_location(NemoFile * file)1616 nemo_file_get_location (NemoFile *file)
1617 {
1618 GFile *dir;
1619
1620 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
1621
1622 dir = file->details->directory->details->location;
1623
1624 if (nemo_file_is_self_owned (file)) {
1625 return g_object_ref (dir);
1626 }
1627
1628 return g_file_get_child (dir, eel_ref_str_peek (file->details->name));
1629 }
1630
1631 /* Return the actual uri associated with the passed-in file. */
1632 char *
nemo_file_get_uri(NemoFile * file)1633 nemo_file_get_uri (NemoFile *file)
1634 {
1635 char *uri;
1636 GFile *loc;
1637
1638 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
1639
1640 loc = nemo_file_get_location (file);
1641 uri = g_file_get_uri (loc);
1642 g_object_unref (loc);
1643
1644 return uri;
1645 }
1646
1647 /* Return the actual path associated with the passed-in file. */
1648 char *
nemo_file_get_path(NemoFile * file)1649 nemo_file_get_path (NemoFile *file)
1650 {
1651 char *path;
1652 GFile *loc;
1653
1654 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
1655
1656 loc = nemo_file_get_location (file);
1657 path = g_file_get_path (loc);
1658 g_object_unref (loc);
1659
1660 return path;
1661 }
1662
1663 char *
nemo_file_get_uri_scheme(NemoFile * file)1664 nemo_file_get_uri_scheme (NemoFile *file)
1665 {
1666 GFile *loc;
1667 char *scheme;
1668
1669 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
1670
1671 if (file->details->directory == NULL ||
1672 file->details->directory->details->location == NULL) {
1673 return NULL;
1674 }
1675
1676 loc = nemo_directory_get_location (file->details->directory);
1677 scheme = g_file_get_uri_scheme (loc);
1678 g_object_unref (loc);
1679
1680 return scheme;
1681 }
1682
1683 NemoFileOperation *
nemo_file_operation_new(NemoFile * file,NemoFileOperationCallback callback,gpointer callback_data)1684 nemo_file_operation_new (NemoFile *file,
1685 NemoFileOperationCallback callback,
1686 gpointer callback_data)
1687 {
1688 NemoFileOperation *op;
1689
1690 op = g_new0 (NemoFileOperation, 1);
1691 op->file = nemo_file_ref (file);
1692 op->callback = callback;
1693 op->callback_data = callback_data;
1694 op->cancellable = g_cancellable_new ();
1695
1696 op->file->details->operations_in_progress = g_list_prepend
1697 (op->file->details->operations_in_progress, op);
1698
1699 return op;
1700 }
1701
1702 static void
nemo_file_operation_remove(NemoFileOperation * op)1703 nemo_file_operation_remove (NemoFileOperation *op)
1704 {
1705 op->file->details->operations_in_progress = g_list_remove
1706 (op->file->details->operations_in_progress, op);
1707 }
1708
1709 void
nemo_file_operation_free(NemoFileOperation * op)1710 nemo_file_operation_free (NemoFileOperation *op)
1711 {
1712 nemo_file_operation_remove (op);
1713 nemo_file_unref (op->file);
1714 g_object_unref (op->cancellable);
1715 if (op->free_data) {
1716 op->free_data (op->data);
1717 }
1718
1719 if (op->undo_info != NULL) {
1720 nemo_file_undo_manager_set_action (op->undo_info);
1721 }
1722
1723 g_free (op);
1724 }
1725
1726 void
nemo_file_operation_complete(NemoFileOperation * op,GFile * result_file,GError * error)1727 nemo_file_operation_complete (NemoFileOperation *op, GFile *result_file, GError *error)
1728 {
1729 /* Claim that something changed even if the operation failed.
1730 * This makes it easier for some clients who see the "reverting"
1731 * as "changing back".
1732 */
1733 nemo_file_operation_remove (op);
1734 nemo_file_changed (op->file);
1735 if (op->callback) {
1736 (* op->callback) (op->file, result_file, error, op->callback_data);
1737 }
1738 nemo_file_operation_free (op);
1739 }
1740
1741 void
nemo_file_operation_cancel(NemoFileOperation * op)1742 nemo_file_operation_cancel (NemoFileOperation *op)
1743 {
1744 /* Cancel the operation if it's still in progress. */
1745 g_cancellable_cancel (op->cancellable);
1746 }
1747
1748 static void
rename_get_info_callback(GObject * source_object,GAsyncResult * res,gpointer callback_data)1749 rename_get_info_callback (GObject *source_object,
1750 GAsyncResult *res,
1751 gpointer callback_data)
1752 {
1753 NemoFileOperation *op;
1754 NemoDirectory *directory;
1755 NemoFile *existing_file;
1756 char *old_name;
1757 char *old_uri;
1758 char *new_uri;
1759 const char *new_name;
1760 GFileInfo *new_info;
1761 GError *error;
1762
1763 op = callback_data;
1764
1765 error = NULL;
1766 new_info = g_file_query_info_finish (G_FILE (source_object), res, &error);
1767 if (new_info != NULL) {
1768 directory = op->file->details->directory;
1769
1770 new_name = g_file_info_get_name (new_info);
1771
1772 /* If there was another file by the same name in this
1773 * directory and it is not the same file that we are
1774 * renaming, mark it gone.
1775 */
1776 existing_file = nemo_directory_find_file_by_name (directory, new_name);
1777 if (existing_file != NULL && existing_file != op->file) {
1778 nemo_file_mark_gone (existing_file);
1779 nemo_file_changed (existing_file);
1780 }
1781
1782 old_uri = nemo_file_get_uri (op->file);
1783 old_name = g_strdup (eel_ref_str_peek (op->file->details->name));
1784
1785 update_info_and_name (op->file, new_info);
1786
1787 g_free (old_name);
1788
1789 new_uri = nemo_file_get_uri (op->file);
1790 nemo_directory_moved (old_uri, new_uri);
1791
1792 xapp_favorites_rename (xapp_favorites_get_default (),
1793 old_uri,
1794 new_uri);
1795
1796 g_free (new_uri);
1797 g_free (old_uri);
1798
1799 /* the rename could have affected the display name if e.g.
1800 * we're in a vfolder where the name comes from a desktop file
1801 * and a rename affects the contents of the desktop file.
1802 */
1803 if (op->file->details->got_custom_display_name) {
1804 nemo_file_invalidate_attributes (op->file,
1805 NEMO_FILE_ATTRIBUTE_INFO |
1806 NEMO_FILE_ATTRIBUTE_LINK_INFO);
1807 }
1808
1809 g_object_unref (new_info);
1810 }
1811 nemo_file_operation_complete (op, NULL, error);
1812 if (error) {
1813 g_error_free (error);
1814 }
1815 }
1816
1817 static void
rename_callback(GObject * source_object,GAsyncResult * res,gpointer callback_data)1818 rename_callback (GObject *source_object,
1819 GAsyncResult *res,
1820 gpointer callback_data)
1821 {
1822 NemoFileOperation *op;
1823 GFile *new_file;
1824 GError *error;
1825
1826 op = callback_data;
1827
1828 error = NULL;
1829 new_file = g_file_set_display_name_finish (G_FILE (source_object),
1830 res, &error);
1831
1832 if (new_file != NULL) {
1833 if (op->undo_info != NULL) {
1834 nemo_file_undo_info_rename_set_data_post (NEMO_FILE_UNDO_INFO_RENAME (op->undo_info),
1835 new_file);
1836 }
1837
1838 g_file_query_info_async (new_file,
1839 NEMO_FILE_DEFAULT_ATTRIBUTES,
1840 0,
1841 G_PRIORITY_DEFAULT,
1842 op->cancellable,
1843 rename_get_info_callback, op);
1844 } else {
1845 nemo_file_operation_complete (op, NULL, error);
1846 g_error_free (error);
1847 }
1848 }
1849
1850 static gboolean
name_is(NemoFile * file,const char * new_name)1851 name_is (NemoFile *file, const char *new_name)
1852 {
1853 const char *old_name;
1854 old_name = eel_ref_str_peek (file->details->name);
1855 return strcmp (new_name, old_name) == 0;
1856 }
1857
1858 void
nemo_file_rename(NemoFile * file,const char * new_name,NemoFileOperationCallback callback,gpointer callback_data)1859 nemo_file_rename (NemoFile *file,
1860 const char *new_name,
1861 NemoFileOperationCallback callback,
1862 gpointer callback_data)
1863 {
1864 NemoFileOperation *op;
1865 char *uri;
1866 char *old_name;
1867 char *new_file_name;
1868 gboolean success, name_changed;
1869 gboolean is_renameable_desktop_file;
1870 GFile *location;
1871 GError *error;
1872
1873 g_return_if_fail (NEMO_IS_FILE (file));
1874 g_return_if_fail (new_name != NULL);
1875 g_return_if_fail (callback != NULL);
1876
1877 is_renameable_desktop_file =
1878 is_desktop_file (file) && can_rename_desktop_file (file);
1879
1880 /* Return an error for incoming names containing path separators.
1881 * But not for .desktop files as '/' are allowed for them */
1882 if (strstr (new_name, "/") != NULL && !is_renameable_desktop_file) {
1883 error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
1884 _("Slashes are not allowed in filenames"));
1885 (* callback) (file, NULL, error, callback_data);
1886 g_error_free (error);
1887 return;
1888 }
1889
1890 /* Can't rename a file that's already gone.
1891 * We need to check this here because there may be a new
1892 * file with the same name.
1893 */
1894 if (nemo_file_is_gone (file)) {
1895 /* Claim that something changed even if the rename
1896 * failed. This makes it easier for some clients who
1897 * see the "reverting" to the old name as "changing
1898 * back".
1899 */
1900 nemo_file_changed (file);
1901 error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1902 _("File not found"));
1903 (* callback) (file, NULL, error, callback_data);
1904 g_error_free (error);
1905 return;
1906 }
1907
1908 /* Test the name-hasn't-changed case explicitly, for two reasons.
1909 * (1) rename returns an error if new & old are same.
1910 * (2) We don't want to send file-changed signal if nothing changed.
1911 */
1912 if (!NEMO_IS_DESKTOP_ICON_FILE (file) &&
1913 !is_renameable_desktop_file &&
1914 name_is (file, new_name)) {
1915 (* callback) (file, NULL, NULL, callback_data);
1916 return;
1917 }
1918
1919 /* Self-owned files can't be renamed. Test the name-not-actually-changing
1920 * case before this case.
1921 */
1922 if (nemo_file_is_self_owned (file)) {
1923 /* Claim that something changed even if the rename
1924 * failed. This makes it easier for some clients who
1925 * see the "reverting" to the old name as "changing
1926 * back".
1927 */
1928 nemo_file_changed (file);
1929 error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1930 _("Toplevel files cannot be renamed"));
1931
1932 (* callback) (file, NULL, error, callback_data);
1933 g_error_free (error);
1934 return;
1935 }
1936
1937 if (NEMO_IS_DESKTOP_ICON_FILE (file)) {
1938 NemoDesktopLink *link;
1939
1940 link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (file));
1941 old_name = nemo_file_get_display_name (file);
1942
1943 if ((old_name != NULL && strcmp (new_name, old_name) == 0)) {
1944 success = TRUE;
1945 } else {
1946 success = (link != NULL && nemo_desktop_link_rename (link, new_name));
1947 }
1948
1949 if (success) {
1950 (* callback) (file, NULL, NULL, callback_data);
1951 } else {
1952 error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
1953 _("Unable to rename desktop icon"));
1954 (* callback) (file, NULL, error, callback_data);
1955 g_error_free (error);
1956 }
1957
1958 g_free (old_name);
1959 g_object_unref (link);
1960 return;
1961 }
1962
1963 if (is_renameable_desktop_file) {
1964 /* Don't actually change the name if the new name is the same.
1965 * This helps for the vfolder method where this can happen and
1966 * we want to minimize actual changes
1967 */
1968 uri = nemo_file_get_uri (file);
1969 old_name = nemo_link_local_get_text (uri);
1970 if (old_name != NULL && strcmp (new_name, old_name) == 0) {
1971 success = TRUE;
1972 name_changed = FALSE;
1973 } else {
1974 success = nemo_link_local_set_text (uri, new_name);
1975 name_changed = TRUE;
1976 }
1977 g_free (old_name);
1978 g_free (uri);
1979
1980 if (!success) {
1981 error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
1982 _("Unable to rename desktop file"));
1983 (* callback) (file, NULL, error, callback_data);
1984 g_error_free (error);
1985 return;
1986 }
1987
1988 if (g_str_has_suffix (new_name, ".desktop")) {
1989 new_file_name = g_strdup (new_name);
1990 } else {
1991 new_file_name = g_strdup_printf ("%s.desktop", new_name);
1992 }
1993
1994 new_file_name = g_strdelimit (new_file_name, "/", '-');
1995
1996 if (name_is (file, new_file_name)) {
1997 if (name_changed) {
1998 nemo_file_invalidate_attributes (file,
1999 NEMO_FILE_ATTRIBUTE_INFO |
2000 NEMO_FILE_ATTRIBUTE_LINK_INFO);
2001 }
2002
2003 (* callback) (file, NULL, NULL, callback_data);
2004 g_free (new_file_name);
2005 return;
2006 }
2007 } else {
2008 new_file_name = g_strdup (new_name);
2009 }
2010
2011 /* Set up a renaming operation. */
2012 op = nemo_file_operation_new (file, callback, callback_data);
2013 op->is_rename = TRUE;
2014 location = nemo_file_get_location (file);
2015
2016 /* Tell the undo manager a rename is taking place */
2017 if (!nemo_file_undo_manager_pop_flag ()) {
2018 op->undo_info = nemo_file_undo_info_rename_new ();
2019
2020 old_name = nemo_file_get_display_name (file);
2021 nemo_file_undo_info_rename_set_data_pre (NEMO_FILE_UNDO_INFO_RENAME (op->undo_info),
2022 location, old_name, new_file_name);
2023 g_free (old_name);
2024 }
2025
2026 /* Do the renaming. */
2027 g_file_set_display_name_async (location,
2028 new_file_name,
2029 G_PRIORITY_DEFAULT,
2030 op->cancellable,
2031 rename_callback,
2032 op);
2033 g_free (new_file_name);
2034 g_object_unref (location);
2035 }
2036
2037 gboolean
nemo_file_rename_in_progress(NemoFile * file)2038 nemo_file_rename_in_progress (NemoFile *file)
2039 {
2040 GList *node;
2041 NemoFileOperation *op;
2042
2043 for (node = file->details->operations_in_progress; node != NULL; node = node->next) {
2044 op = node->data;
2045 if (op->is_rename) {
2046 return TRUE;
2047 }
2048 }
2049 return FALSE;
2050 }
2051
2052 void
nemo_file_cancel(NemoFile * file,NemoFileOperationCallback callback,gpointer callback_data)2053 nemo_file_cancel (NemoFile *file,
2054 NemoFileOperationCallback callback,
2055 gpointer callback_data)
2056 {
2057 GList *node, *next;
2058 NemoFileOperation *op;
2059
2060 for (node = file->details->operations_in_progress; node != NULL; node = next) {
2061 next = node->next;
2062 op = node->data;
2063
2064 g_assert (op->file == file);
2065 if (op->callback == callback && op->callback_data == callback_data) {
2066 nemo_file_operation_cancel (op);
2067 }
2068 }
2069 }
2070
2071 gboolean
nemo_file_matches_uri(NemoFile * file,const char * match_uri)2072 nemo_file_matches_uri (NemoFile *file, const char *match_uri)
2073 {
2074 GFile *match_file, *location;
2075 gboolean result;
2076
2077 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
2078 g_return_val_if_fail (match_uri != NULL, FALSE);
2079
2080 location = nemo_file_get_location (file);
2081 match_file = g_file_new_for_uri (match_uri);
2082 result = g_file_equal (location, match_file);
2083 g_object_unref (location);
2084 g_object_unref (match_file);
2085
2086 return result;
2087 }
2088
2089 int
nemo_file_compare_location(NemoFile * file_1,NemoFile * file_2)2090 nemo_file_compare_location (NemoFile *file_1,
2091 NemoFile *file_2)
2092 {
2093 GFile *loc_a, *loc_b;
2094 gboolean res;
2095
2096 loc_a = nemo_file_get_location (file_1);
2097 loc_b = nemo_file_get_location (file_2);
2098
2099 res = !g_file_equal (loc_a, loc_b);
2100
2101 g_object_unref (loc_a);
2102 g_object_unref (loc_b);
2103
2104 return (gint) res;
2105 }
2106
2107 gboolean
nemo_file_is_local(NemoFile * file)2108 nemo_file_is_local (NemoFile *file)
2109 {
2110 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
2111
2112 return nemo_directory_is_local (file->details->directory);
2113 }
2114
2115 static void
update_link(NemoFile * link_file,NemoFile * target_file)2116 update_link (NemoFile *link_file, NemoFile *target_file)
2117 {
2118 g_assert (NEMO_IS_FILE (link_file));
2119 g_assert (NEMO_IS_FILE (target_file));
2120
2121 /* FIXME bugzilla.gnome.org 42044: If we don't put any code
2122 * here then the hash table is a waste of time.
2123 */
2124 }
2125
2126 static GList *
get_link_files(NemoFile * target_file)2127 get_link_files (NemoFile *target_file)
2128 {
2129 char *uri;
2130 GList **link_files;
2131
2132 if (symbolic_links == NULL) {
2133 link_files = NULL;
2134 } else {
2135 uri = nemo_file_get_uri (target_file);
2136 link_files = g_hash_table_lookup (symbolic_links, uri);
2137 g_free (uri);
2138
2139 if (link_files) {
2140 if (!nemo_file_is_symbolic_link (target_file)) {
2141 return nemo_file_list_copy (*link_files);
2142 } else {
2143 /* We keep a hash table of uri keys with lists of NemoFiles attached, to keep
2144 * track of what files point to a particular uri.
2145 *
2146 * When a file gets updated, it fetches the potential list of any files that
2147 * are actually links to itself. If our original file is also actually a symbolic
2148 * link that points to to one of these link files, we'll end up triggering a cyclic
2149 * update - one file triggers an update for the other, which in turn triggers an update
2150 * back to the original file, and so on.
2151 *
2152 * So we check if target_file is itself a link. If it is, we compare its symbolic
2153 * target location with the location of the returned link_files. We skip any that match
2154 * (meaning, any link-back files that are themselves the target of the current symbolic link
2155 * file.
2156 */
2157 GList *derecursed = NULL;
2158 GList *l;
2159
2160 l = *link_files;
2161
2162 while (l != NULL) {
2163 NemoFile *link_file;
2164 gboolean add;
2165
2166 add = TRUE;
2167
2168 link_file = NEMO_FILE (l->data);
2169
2170 if (nemo_file_is_symbolic_link (target_file)) {
2171 gchar *target_symlink_uri = nemo_file_get_symbolic_link_target_uri (target_file);
2172 gchar *link_uri = nemo_file_get_uri (link_file);
2173
2174 GFile *target_symlink_gfile = g_file_new_for_uri (target_symlink_uri);
2175 GFile *link_gfile = g_file_new_for_uri (link_uri);
2176
2177 if (g_file_equal (target_symlink_gfile, link_gfile)) {
2178 add = FALSE;
2179 }
2180
2181 g_object_unref (target_symlink_gfile);
2182 g_object_unref (link_gfile);
2183 g_free (target_symlink_uri);
2184 g_free (link_uri);
2185 }
2186
2187 if (add) {
2188 derecursed = g_list_prepend (derecursed, nemo_file_ref (link_file));
2189 }
2190
2191 l = l->next;
2192 }
2193
2194 return derecursed;
2195 }
2196 }
2197 }
2198
2199 return NULL;
2200 }
2201
2202 static void
update_links_if_target(NemoFile * target_file)2203 update_links_if_target (NemoFile *target_file)
2204 {
2205 GList *link_files, *p;
2206
2207 link_files = get_link_files (target_file);
2208 for (p = link_files; p != NULL; p = p->next) {
2209 update_link (NEMO_FILE (p->data), target_file);
2210 }
2211 nemo_file_list_free (link_files);
2212 }
2213
2214
2215 static guint64 cached_thumbnail_limit;
2216 int cached_thumbnail_size;
2217 double scaled_cached_thumbnail_size;
2218 static int show_image_thumbs;
2219
2220 static gboolean
access_ok(const gchar * path)2221 access_ok (const gchar *path)
2222 {
2223 if (g_access (path, R_OK|W_OK) != 0) {
2224 if (errno != ENOENT && errno != EFAULT) {
2225 return FALSE;
2226 }
2227 }
2228
2229 return TRUE;
2230 }
2231
2232 static gboolean
update_info_internal(NemoFile * file,GFileInfo * info,gboolean update_name)2233 update_info_internal (NemoFile *file,
2234 GFileInfo *info,
2235 gboolean update_name)
2236 {
2237 GList *node;
2238 gboolean changed;
2239 gboolean is_symlink, is_hidden, is_mountpoint;
2240 gboolean has_permissions;
2241 guint32 permissions;
2242 gboolean can_read, can_write, can_execute, can_delete, can_trash, can_rename, can_mount, can_unmount, can_eject;
2243 gboolean can_start, can_start_degraded, can_stop, can_poll_for_media, is_media_check_automatic;
2244 GDriveStartStopType start_stop_type;
2245 gboolean thumbnailing_failed;
2246 int uid, gid;
2247 goffset size;
2248 int sort_order;
2249 time_t atime, mtime, ctime;
2250 time_t trash_time;
2251 GTimeVal g_trash_time;
2252 const char * time_string;
2253 const char *symlink_name, *selinux_context, *name, *thumbnail_path;
2254 char *mime_type;
2255 GFileType file_type;
2256 GIcon *icon;
2257 char *old_activation_uri;
2258 const char *activation_uri;
2259 const char *description;
2260 const char *filesystem_id;
2261 const char *trash_orig_path;
2262 const char *group, *owner, *owner_real;
2263 gboolean free_owner, free_group;
2264
2265 if (file->details->is_gone) {
2266 return FALSE;
2267 }
2268
2269 if (info == NULL) {
2270 nemo_file_mark_gone (file);
2271 return TRUE;
2272 }
2273
2274 file->details->file_info_is_up_to_date = TRUE;
2275
2276 file->details->thumbnail_access_problem = FALSE;
2277
2278 file->details->pinning = FILE_META_STATE_INIT;
2279 file->details->favorite = FILE_META_STATE_INIT;
2280
2281 /* FIXME bugzilla.gnome.org 42044: Need to let links that
2282 * point to the old name know that the file has been renamed.
2283 */
2284
2285 remove_from_link_hash_table (file);
2286
2287 changed = FALSE;
2288
2289 if (!file->details->got_file_info) {
2290 changed = TRUE;
2291 }
2292 file->details->got_file_info = TRUE;
2293
2294 changed |= nemo_file_set_display_name (file,
2295 g_file_info_get_display_name (info),
2296 g_file_info_get_edit_name (info),
2297 FALSE);
2298
2299 file_type = g_file_info_get_file_type (info);
2300 if (file->details->type != file_type) {
2301 changed = TRUE;
2302 }
2303 file->details->type = file_type;
2304
2305 if (!file->details->got_custom_activation_uri && !nemo_file_is_in_trash (file)) {
2306 activation_uri = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
2307 if (activation_uri == NULL) {
2308 if (file->details->activation_uri) {
2309 g_free (file->details->activation_uri);
2310 file->details->activation_uri = NULL;
2311 changed = TRUE;
2312 }
2313 } else {
2314 old_activation_uri = file->details->activation_uri;
2315 file->details->activation_uri = g_strdup (activation_uri);
2316
2317 if (old_activation_uri) {
2318 if (strcmp (old_activation_uri,
2319 file->details->activation_uri) != 0) {
2320 changed = TRUE;
2321 }
2322 g_free (old_activation_uri);
2323 } else {
2324 changed = TRUE;
2325 }
2326 }
2327 }
2328
2329 is_symlink = g_file_info_get_is_symlink (info);
2330 if (file->details->is_symlink != is_symlink) {
2331 changed = TRUE;
2332 }
2333 file->details->is_symlink = is_symlink;
2334
2335 is_hidden = g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info);
2336 if (file->details->is_hidden != is_hidden) {
2337 changed = TRUE;
2338 }
2339 file->details->is_hidden = is_hidden;
2340
2341 is_mountpoint = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT);
2342 if (file->details->is_mountpoint != is_mountpoint) {
2343 changed = TRUE;
2344 }
2345 file->details->is_mountpoint = is_mountpoint;
2346
2347 has_permissions = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE);
2348 permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);;
2349 if (file->details->has_permissions != has_permissions ||
2350 file->details->permissions != permissions) {
2351 changed = TRUE;
2352 }
2353 file->details->has_permissions = has_permissions;
2354 file->details->permissions = permissions;
2355
2356 /* We default to TRUE for this if we can't know */
2357 can_read = TRUE;
2358 can_write = TRUE;
2359 can_execute = TRUE;
2360 can_delete = TRUE;
2361 can_trash = TRUE;
2362 can_rename = TRUE;
2363 can_mount = FALSE;
2364 can_unmount = FALSE;
2365 can_eject = FALSE;
2366 can_start = FALSE;
2367 can_start_degraded = FALSE;
2368 can_stop = FALSE;
2369 can_poll_for_media = FALSE;
2370 is_media_check_automatic = FALSE;
2371 start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
2372 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ)) {
2373 can_read = g_file_info_get_attribute_boolean (info,
2374 G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
2375 }
2376 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) {
2377 can_write = g_file_info_get_attribute_boolean (info,
2378 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
2379 }
2380 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) {
2381 can_execute = g_file_info_get_attribute_boolean (info,
2382 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE);
2383 }
2384 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE)) {
2385 can_delete = g_file_info_get_attribute_boolean (info,
2386 G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE);
2387 }
2388 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH)) {
2389 can_trash = g_file_info_get_attribute_boolean (info,
2390 G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH);
2391 }
2392 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME)) {
2393 can_rename = g_file_info_get_attribute_boolean (info,
2394 G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME);
2395 }
2396 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT)) {
2397 can_mount = g_file_info_get_attribute_boolean (info,
2398 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT);
2399 }
2400 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT)) {
2401 can_unmount = g_file_info_get_attribute_boolean (info,
2402 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT);
2403 }
2404 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT)) {
2405 can_eject = g_file_info_get_attribute_boolean (info,
2406 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT);
2407 }
2408 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START)) {
2409 can_start = g_file_info_get_attribute_boolean (info,
2410 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START);
2411 }
2412 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START_DEGRADED)) {
2413 can_start_degraded = g_file_info_get_attribute_boolean (info,
2414 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START_DEGRADED);
2415 }
2416 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP)) {
2417 can_stop = g_file_info_get_attribute_boolean (info,
2418 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP);
2419 }
2420 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE)) {
2421 start_stop_type = g_file_info_get_attribute_uint32 (info,
2422 G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE);
2423 }
2424 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL)) {
2425 can_poll_for_media = g_file_info_get_attribute_boolean (info,
2426 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL);
2427 }
2428 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC)) {
2429 is_media_check_automatic = g_file_info_get_attribute_boolean (info,
2430 G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC);
2431 }
2432 if (file->details->can_read != can_read ||
2433 file->details->can_write != can_write ||
2434 file->details->can_execute != can_execute ||
2435 file->details->can_delete != can_delete ||
2436 file->details->can_trash != can_trash ||
2437 file->details->can_rename != can_rename ||
2438 file->details->can_mount != can_mount ||
2439 file->details->can_unmount != can_unmount ||
2440 file->details->can_eject != can_eject ||
2441 file->details->can_start != can_start ||
2442 file->details->can_start_degraded != can_start_degraded ||
2443 file->details->can_stop != can_stop ||
2444 file->details->start_stop_type != start_stop_type ||
2445 file->details->can_poll_for_media != can_poll_for_media ||
2446 file->details->is_media_check_automatic != is_media_check_automatic) {
2447 changed = TRUE;
2448 }
2449
2450 file->details->can_read = can_read;
2451 file->details->can_write = can_write;
2452 file->details->can_execute = can_execute;
2453 file->details->can_delete = can_delete;
2454 file->details->can_trash = can_trash;
2455 file->details->can_rename = can_rename;
2456 file->details->can_mount = can_mount;
2457 file->details->can_unmount = can_unmount;
2458 file->details->can_eject = can_eject;
2459 file->details->can_start = can_start;
2460 file->details->can_start_degraded = can_start_degraded;
2461 file->details->can_stop = can_stop;
2462 file->details->start_stop_type = start_stop_type;
2463 file->details->can_poll_for_media = can_poll_for_media;
2464 file->details->is_media_check_automatic = is_media_check_automatic;
2465
2466 file->details->favorite_checked = FALSE;
2467
2468 free_owner = FALSE;
2469 owner = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER);
2470 owner_real = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER_REAL);
2471 free_group = FALSE;
2472 group = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_GROUP);
2473
2474 uid = -1;
2475 gid = -1;
2476 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_UID)) {
2477 uid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID);
2478 if (owner == NULL) {
2479 free_owner = TRUE;
2480 owner = g_strdup_printf ("%d", uid);
2481 }
2482 }
2483 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_GID)) {
2484 gid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID);
2485 if (group == NULL) {
2486 free_group = TRUE;
2487 group = g_strdup_printf ("%d", gid);
2488 }
2489 }
2490 if (file->details->uid != uid ||
2491 file->details->gid != gid) {
2492 changed = TRUE;
2493 }
2494 file->details->uid = uid;
2495 file->details->gid = gid;
2496
2497 if (g_strcmp0 (eel_ref_str_peek (file->details->owner), owner) != 0) {
2498 changed = TRUE;
2499 eel_ref_str_unref (file->details->owner);
2500 file->details->owner = eel_ref_str_get_unique (owner);
2501 }
2502
2503 if (g_strcmp0 (eel_ref_str_peek (file->details->owner_real), owner_real) != 0) {
2504 changed = TRUE;
2505 eel_ref_str_unref (file->details->owner_real);
2506 file->details->owner_real = eel_ref_str_get_unique (owner_real);
2507 }
2508
2509 if (g_strcmp0 (eel_ref_str_peek (file->details->group), group) != 0) {
2510 changed = TRUE;
2511 eel_ref_str_unref (file->details->group);
2512 file->details->group = eel_ref_str_get_unique (group);
2513 }
2514
2515 if (free_owner) {
2516 g_free ((char *)owner);
2517 }
2518 if (free_group) {
2519 g_free ((char *)group);
2520 }
2521
2522 size = -1;
2523 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE)) {
2524 size = g_file_info_get_size (info);
2525 }
2526 if (file->details->size != size) {
2527 changed = TRUE;
2528 }
2529 file->details->size = size;
2530
2531 sort_order = g_file_info_get_sort_order (info);
2532 if (file->details->sort_order != sort_order) {
2533 changed = TRUE;
2534 }
2535 file->details->sort_order = sort_order;
2536
2537 atime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
2538 ctime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CHANGED);
2539 mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
2540 if (file->details->atime != atime ||
2541 file->details->mtime != mtime ||
2542 file->details->ctime != ctime) {
2543 if (file->details->thumbnail == NULL) {
2544 file->details->thumbnail_is_up_to_date = FALSE;
2545 }
2546
2547 changed = TRUE;
2548 }
2549 file->details->atime = atime;
2550 file->details->ctime = ctime;
2551 file->details->mtime = mtime;
2552
2553 if (file->details->thumbnail != NULL &&
2554 file->details->thumbnail_mtime != 0 &&
2555 file->details->thumbnail_mtime != mtime) {
2556 file->details->thumbnail_is_up_to_date = FALSE;
2557 changed = TRUE;
2558 }
2559
2560 icon = g_file_info_get_icon (info);
2561 if (!g_icon_equal (icon, file->details->icon)) {
2562 changed = TRUE;
2563
2564 if (file->details->icon) {
2565 g_object_unref (file->details->icon);
2566 }
2567 file->details->icon = g_object_ref (icon);
2568 }
2569
2570 thumbnail_path = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
2571
2572 if (g_strcmp0 (file->details->thumbnail_path, thumbnail_path) != 0) {
2573 changed = TRUE;
2574 g_free (file->details->thumbnail_path);
2575
2576 if (show_image_thumbs != NEMO_SPEED_TRADEOFF_NEVER && thumbnail_path != NULL && !access_ok (thumbnail_path)) {
2577 file->details->thumbnail_access_problem = TRUE;
2578 file->details->thumbnail_path = NULL;
2579 } else {
2580 file->details->thumbnail_path = g_strdup (thumbnail_path);
2581 }
2582 }
2583
2584 thumbnailing_failed = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED);
2585 if (file->details->thumbnailing_failed != thumbnailing_failed) {
2586 changed = TRUE;
2587 file->details->thumbnailing_failed = thumbnailing_failed;
2588 }
2589
2590 symlink_name = g_file_info_get_symlink_target (info);
2591 if (g_strcmp0 (file->details->symlink_name, symlink_name) != 0) {
2592 changed = TRUE;
2593 g_free (file->details->symlink_name);
2594 file->details->symlink_name = g_strdup (symlink_name);
2595 }
2596
2597 selinux_context = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_SELINUX_CONTEXT);
2598 if (g_strcmp0 (file->details->selinux_context, selinux_context) != 0) {
2599 changed = TRUE;
2600 g_free (file->details->selinux_context);
2601 file->details->selinux_context = g_strdup (selinux_context);
2602 }
2603
2604 description = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION);
2605 if (g_strcmp0 (file->details->description, description) != 0) {
2606 changed = TRUE;
2607 g_free (file->details->description);
2608 file->details->description = g_strdup (description);
2609 }
2610
2611 filesystem_id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM);
2612 if (g_strcmp0 (eel_ref_str_peek (file->details->filesystem_id), filesystem_id) != 0) {
2613 changed = TRUE;
2614 eel_ref_str_unref (file->details->filesystem_id);
2615 file->details->filesystem_id = eel_ref_str_get_unique (filesystem_id);
2616 }
2617
2618 trash_time = 0;
2619 time_string = g_file_info_get_attribute_string (info, "trash::deletion-date");
2620 if (time_string != NULL) {
2621 g_time_val_from_iso8601 (time_string, &g_trash_time);
2622 trash_time = g_trash_time.tv_sec;
2623 }
2624 if (file->details->trash_time != trash_time) {
2625 changed = TRUE;
2626 file->details->trash_time = trash_time;
2627 }
2628
2629 trash_orig_path = g_file_info_get_attribute_byte_string (info, "trash::orig-path");
2630 if (g_strcmp0 (file->details->trash_orig_path, trash_orig_path) != 0) {
2631 changed = TRUE;
2632 g_free (file->details->trash_orig_path);
2633 file->details->trash_orig_path = g_strdup (trash_orig_path);
2634 }
2635
2636 changed |=
2637 nemo_file_update_metadata_from_info (file, info);
2638
2639 if (update_name) {
2640 name = g_file_info_get_name (info);
2641 if (file->details->name == NULL ||
2642 strcmp (eel_ref_str_peek (file->details->name), name) != 0) {
2643 changed = TRUE;
2644
2645 node = nemo_directory_begin_file_name_change
2646 (file->details->directory, file);
2647
2648 eel_ref_str_unref (file->details->name);
2649 if (g_strcmp0 (eel_ref_str_peek (file->details->display_name),
2650 name) == 0) {
2651 file->details->name = eel_ref_str_ref (file->details->display_name);
2652 } else {
2653 file->details->name = eel_ref_str_new (name);
2654 }
2655
2656 if (!file->details->got_custom_display_name &&
2657 g_file_info_get_display_name (info) == NULL) {
2658 /* If the file info's display name is NULL,
2659 * nemo_file_set_display_name() did
2660 * not unset the display name.
2661 */
2662 nemo_file_clear_display_name (file);
2663 }
2664
2665 nemo_directory_end_file_name_change
2666 (file->details->directory, file, node);
2667 }
2668 }
2669
2670 mime_type = nemo_get_best_guess_file_mimetype (file->details->name, info, size);
2671
2672 if (g_strcmp0 (eel_ref_str_peek (file->details->mime_type), eel_ref_str_peek (mime_type)) != 0) {
2673 changed = TRUE;
2674 eel_ref_str_unref (file->details->mime_type);
2675 file->details->mime_type = mime_type;
2676 }
2677
2678 if (changed) {
2679 add_to_link_hash_table (file);
2680
2681 update_links_if_target (file);
2682 }
2683
2684 return changed;
2685 }
2686
2687 static gboolean
update_info_and_name(NemoFile * file,GFileInfo * info)2688 update_info_and_name (NemoFile *file,
2689 GFileInfo *info)
2690 {
2691 return update_info_internal (file, info, TRUE);
2692 }
2693
2694 gboolean
nemo_file_update_info(NemoFile * file,GFileInfo * info)2695 nemo_file_update_info (NemoFile *file,
2696 GFileInfo *info)
2697 {
2698 return update_info_internal (file, info, FALSE);
2699 }
2700
2701 static gboolean
update_name_internal(NemoFile * file,const char * name,gboolean in_directory)2702 update_name_internal (NemoFile *file,
2703 const char *name,
2704 gboolean in_directory)
2705 {
2706 GList *node;
2707
2708 g_assert (name != NULL);
2709
2710 if (file->details->is_gone) {
2711 return FALSE;
2712 }
2713
2714 if (name_is (file, name)) {
2715 return FALSE;
2716 }
2717
2718 node = NULL;
2719 if (in_directory) {
2720 node = nemo_directory_begin_file_name_change
2721 (file->details->directory, file);
2722 }
2723
2724 eel_ref_str_unref (file->details->name);
2725 file->details->name = eel_ref_str_new (name);
2726
2727 if (!file->details->got_custom_display_name) {
2728 nemo_file_clear_display_name (file);
2729 }
2730
2731 if (in_directory) {
2732 nemo_directory_end_file_name_change
2733 (file->details->directory, file, node);
2734 }
2735
2736 return TRUE;
2737 }
2738
2739 gboolean
nemo_file_update_name(NemoFile * file,const char * name)2740 nemo_file_update_name (NemoFile *file, const char *name)
2741 {
2742 gboolean ret;
2743
2744 ret = update_name_internal (file, name, TRUE);
2745
2746 if (ret) {
2747 update_links_if_target (file);
2748 }
2749
2750 return ret;
2751 }
2752
2753 gboolean
nemo_file_update_name_and_directory(NemoFile * file,const char * name,NemoDirectory * new_directory)2754 nemo_file_update_name_and_directory (NemoFile *file,
2755 const char *name,
2756 NemoDirectory *new_directory)
2757 {
2758 NemoDirectory *old_directory;
2759 FileMonitors *monitors;
2760
2761 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
2762 g_return_val_if_fail (NEMO_IS_DIRECTORY (file->details->directory), FALSE);
2763 g_return_val_if_fail (!file->details->is_gone, FALSE);
2764 g_return_val_if_fail (!nemo_file_is_self_owned (file), FALSE);
2765 g_return_val_if_fail (NEMO_IS_DIRECTORY (new_directory), FALSE);
2766
2767 old_directory = file->details->directory;
2768 if (old_directory == new_directory) {
2769 if (name) {
2770 return update_name_internal (file, name, TRUE);
2771 } else {
2772 return FALSE;
2773 }
2774 }
2775
2776 nemo_file_ref (file);
2777
2778 /* FIXME bugzilla.gnome.org 42044: Need to let links that
2779 * point to the old name know that the file has been moved.
2780 */
2781
2782 remove_from_link_hash_table (file);
2783
2784 monitors = nemo_directory_remove_file_monitors (old_directory, file);
2785 nemo_directory_remove_file (old_directory, file);
2786
2787 file->details->directory = nemo_directory_ref (new_directory);
2788 nemo_directory_unref (old_directory);
2789
2790 if (name) {
2791 update_name_internal (file, name, FALSE);
2792 }
2793
2794 nemo_directory_add_file (new_directory, file);
2795 nemo_directory_add_file_monitors (new_directory, file, monitors);
2796
2797 add_to_link_hash_table (file);
2798
2799 update_links_if_target (file);
2800
2801 nemo_file_unref (file);
2802
2803 return TRUE;
2804 }
2805
2806 void
nemo_file_set_directory(NemoFile * file,NemoDirectory * new_directory)2807 nemo_file_set_directory (NemoFile *file,
2808 NemoDirectory *new_directory)
2809 {
2810 nemo_file_update_name_and_directory (file, NULL, new_directory);
2811 }
2812
2813 static Knowledge
get_item_count(NemoFile * file,guint * count)2814 get_item_count (NemoFile *file,
2815 guint *count)
2816 {
2817 gboolean known, unreadable;
2818
2819 known = nemo_file_get_directory_item_count
2820 (file, count, &unreadable);
2821 if (!known) {
2822 return UNKNOWN;
2823 }
2824 if (unreadable) {
2825 return UNKNOWABLE;
2826 }
2827 return KNOWN;
2828 }
2829
2830 static Knowledge
get_size(NemoFile * file,goffset * size)2831 get_size (NemoFile *file,
2832 goffset *size)
2833 {
2834 /* If we tried and failed, then treat it like there is no size
2835 * to know.
2836 */
2837 if (file->details->get_info_failed) {
2838 return UNKNOWABLE;
2839 }
2840
2841 /* If the info is NULL that means we haven't even tried yet,
2842 * so it's just unknown, not unknowable.
2843 */
2844 if (!file->details->got_file_info) {
2845 return UNKNOWN;
2846 }
2847
2848 /* If we got info with no size in it, it means there is no
2849 * such thing as a size as far as gnome-vfs is concerned,
2850 * so "unknowable".
2851 */
2852 if (file->details->size == -1) {
2853 return UNKNOWABLE;
2854 }
2855
2856 /* We have a size! */
2857 *size = file->details->size;
2858 return KNOWN;
2859 }
2860
2861 static Knowledge
get_time(NemoFile * file,time_t * time_out,NemoDateType type)2862 get_time (NemoFile *file,
2863 time_t *time_out,
2864 NemoDateType type)
2865 {
2866 time_t time;
2867
2868 /* If we tried and failed, then treat it like there is no size
2869 * to know.
2870 */
2871 if (file->details->get_info_failed) {
2872 return UNKNOWABLE;
2873 }
2874
2875 /* If the info is NULL that means we haven't even tried yet,
2876 * so it's just unknown, not unknowable.
2877 */
2878 if (!file->details->got_file_info) {
2879 return UNKNOWN;
2880 }
2881
2882 time = 0;
2883 switch (type) {
2884 case NEMO_DATE_TYPE_MODIFIED:
2885 time = file->details->mtime;
2886 break;
2887 case NEMO_DATE_TYPE_ACCESSED:
2888 time = file->details->atime;
2889 break;
2890 case NEMO_DATE_TYPE_CREATED:
2891 time = file->details->btime;
2892 break;
2893 case NEMO_DATE_TYPE_TRASHED:
2894 time = file->details->trash_time;
2895 break;
2896 case NEMO_DATE_TYPE_CHANGED:
2897 case NEMO_DATE_TYPE_PERMISSIONS_CHANGED:
2898 /* FIXME is some logic needed here ?
2899 */
2900 default:
2901 g_assert_not_reached ();
2902 break;
2903 }
2904
2905 *time_out = time;
2906
2907 /* If we got info with no modification time in it, it means
2908 * there is no such thing as a modification time as far as
2909 * gnome-vfs is concerned, so "unknowable".
2910 */
2911 if (time == 0) {
2912 return UNKNOWABLE;
2913 }
2914 return KNOWN;
2915 }
2916
2917 static int
compare_directories_by_count(NemoFile * file_1,NemoFile * file_2)2918 compare_directories_by_count (NemoFile *file_1, NemoFile *file_2)
2919 {
2920 /* Sort order:
2921 * Directories with unknown # of items
2922 * Directories with "unknowable" # of items
2923 * Directories with 0 items
2924 * Directories with n items
2925 */
2926
2927 Knowledge count_known_1, count_known_2;
2928 guint count_1, count_2;
2929
2930 count_known_1 = get_item_count (file_1, &count_1);
2931 count_known_2 = get_item_count (file_2, &count_2);
2932
2933 if (count_known_1 > count_known_2) {
2934 return -1;
2935 }
2936 if (count_known_1 < count_known_2) {
2937 return +1;
2938 }
2939
2940 /* count_known_1 and count_known_2 are equal now. Check if count
2941 * details are UNKNOWABLE or UNKNOWN.
2942 */
2943 if (count_known_1 == UNKNOWABLE || count_known_1 == UNKNOWN) {
2944 return 0;
2945 }
2946
2947 if (count_1 < count_2) {
2948 return -1;
2949 }
2950 if (count_1 > count_2) {
2951 return +1;
2952 }
2953
2954 return 0;
2955 }
2956
2957 static int
compare_files_by_size(NemoFile * file_1,NemoFile * file_2)2958 compare_files_by_size (NemoFile *file_1, NemoFile *file_2)
2959 {
2960 /* Sort order:
2961 * Files with unknown size.
2962 * Files with "unknowable" size.
2963 * Files with smaller sizes.
2964 * Files with large sizes.
2965 */
2966
2967 Knowledge size_known_1, size_known_2;
2968 goffset size_1 = 0, size_2 = 0;
2969
2970 size_known_1 = get_size (file_1, &size_1);
2971 size_known_2 = get_size (file_2, &size_2);
2972
2973 if (size_known_1 > size_known_2) {
2974 return -1;
2975 }
2976 if (size_known_1 < size_known_2) {
2977 return +1;
2978 }
2979
2980 /* size_known_1 and size_known_2 are equal now. Check if size
2981 * details are UNKNOWABLE or UNKNOWN
2982 */
2983 if (size_known_1 == UNKNOWABLE || size_known_1 == UNKNOWN) {
2984 return 0;
2985 }
2986
2987 if (size_1 < size_2) {
2988 return -1;
2989 }
2990 if (size_1 > size_2) {
2991 return +1;
2992 }
2993
2994 return 0;
2995 }
2996
2997 static int
compare_by_size(NemoFile * file_1,NemoFile * file_2)2998 compare_by_size (NemoFile *file_1, NemoFile *file_2)
2999 {
3000 /* Sort order:
3001 * Directories with n items
3002 * Directories with 0 items
3003 * Directories with "unknowable" # of items
3004 * Directories with unknown # of items
3005 * Files with large sizes.
3006 * Files with smaller sizes.
3007 * Files with "unknowable" size.
3008 * Files with unknown size.
3009 */
3010
3011 gboolean is_directory_1, is_directory_2;
3012
3013 is_directory_1 = nemo_file_is_directory (file_1);
3014 is_directory_2 = nemo_file_is_directory (file_2);
3015
3016 if (is_directory_1 && !is_directory_2) {
3017 return -1;
3018 }
3019 if (is_directory_2 && !is_directory_1) {
3020 return +1;
3021 }
3022
3023 if (is_directory_1) {
3024 return compare_directories_by_count (file_1, file_2);
3025 } else {
3026 return compare_files_by_size (file_1, file_2);
3027 }
3028 }
3029
3030 static int
compare_by_display_name(NemoFile * file_1,NemoFile * file_2)3031 compare_by_display_name (NemoFile *file_1, NemoFile *file_2)
3032 {
3033 const char *name_1, *name_2;
3034 const char *key_1, *key_2;
3035 gboolean sort_last_1, sort_last_2;
3036 int compare=0;
3037
3038 name_1 = nemo_file_peek_display_name (file_1);
3039 name_2 = nemo_file_peek_display_name (file_2);
3040
3041 sort_last_1 = name_1 && (name_1[0] == SORT_LAST_CHAR1 || name_1[0] == SORT_LAST_CHAR2);
3042 sort_last_2 = name_2 && (name_2[0] == SORT_LAST_CHAR1 || name_2[0] == SORT_LAST_CHAR2);
3043
3044 if (sort_last_1 && !sort_last_2) {
3045 compare = +1;
3046 } else if (!sort_last_1 && sort_last_2) {
3047 compare = -1;
3048 } else if (name_1 == NULL || name_2 == NULL) {
3049 if (name_1 && !name_2)
3050 compare = +1;
3051 else if (!name_1 && name_2)
3052 compare = -1;
3053 } else {
3054 key_1 = nemo_file_peek_display_name_collation_key (file_1);
3055 key_2 = nemo_file_peek_display_name_collation_key (file_2);
3056 compare = g_strcmp0 (key_1, key_2);
3057 }
3058
3059 return compare;
3060 }
3061
3062 static int
compare_by_directory_name(NemoFile * file_1,NemoFile * file_2)3063 compare_by_directory_name (NemoFile *file_1, NemoFile *file_2)
3064 {
3065 char *directory_1, *directory_2;
3066 int compare;
3067
3068 if (file_1->details->directory == file_2->details->directory) {
3069 return 0;
3070 }
3071
3072 directory_1 = nemo_file_get_parent_uri_for_display (file_1);
3073 directory_2 = nemo_file_get_parent_uri_for_display (file_2);
3074
3075 compare = g_utf8_collate (directory_1, directory_2);
3076
3077 g_free (directory_1);
3078 g_free (directory_2);
3079
3080 return compare;
3081 }
3082
3083 static gboolean
file_has_note(NemoFile * file)3084 file_has_note (NemoFile *file)
3085 {
3086 char *note;
3087 gboolean res;
3088
3089 note = nemo_file_get_metadata (file, NEMO_METADATA_KEY_ANNOTATION, NULL);
3090 res = note != NULL && note[0] != 0;
3091 g_free (note);
3092
3093 return res;
3094 }
3095
3096 static GList *
prepend_automatic_keywords(NemoFile * file,NemoFile * view_file,GList * names)3097 prepend_automatic_keywords (NemoFile *file,
3098 NemoFile *view_file,
3099 GList *names)
3100 {
3101 /* Prepend in reverse order. */
3102
3103 if (file_has_note (file)) {
3104 names = g_list_prepend
3105 (names, g_strdup (NEMO_FILE_EMBLEM_NAME_NOTE));
3106 }
3107
3108 if (!nemo_file_can_read (file)) {
3109 names = g_list_prepend
3110 (names, g_strdup (NEMO_FILE_EMBLEM_NAME_CANT_READ));
3111 }
3112 if (nemo_file_is_symbolic_link (file) && !nemo_file_is_in_favorites (file)) {
3113 names = g_list_prepend
3114 (names, g_strdup (NEMO_FILE_EMBLEM_NAME_SYMBOLIC_LINK));
3115 }
3116 if (nemo_file_get_is_favorite (file) && !nemo_file_is_in_favorites (file)) {
3117 names = g_list_prepend
3118 (names, g_strdup (NEMO_FILE_EMBLEM_NAME_FAVORITE));
3119 }
3120
3121 return names;
3122 }
3123
3124 static int
compare_by_type(NemoFile * file_1,NemoFile * file_2,gboolean detailed)3125 compare_by_type (NemoFile *file_1, NemoFile *file_2, gboolean detailed)
3126 {
3127 gboolean is_directory_1;
3128 gboolean is_directory_2;
3129 char *type_string_1;
3130 char *type_string_2;
3131 int result;
3132
3133 /* Directories go first. Then, if mime types are identical,
3134 * don't bother getting strings (for speed). This assumes
3135 * that the string is dependent entirely on the mime type,
3136 * which is true now but might not be later.
3137 */
3138 is_directory_1 = nemo_file_is_directory (file_1);
3139 is_directory_2 = nemo_file_is_directory (file_2);
3140
3141 if (is_directory_1 && is_directory_2) {
3142 return 0;
3143 }
3144
3145 if (is_directory_1) {
3146 return -1;
3147 }
3148
3149 if (is_directory_2) {
3150 return +1;
3151 }
3152
3153 if (detailed) {
3154 type_string_1 = nemo_file_get_detailed_type_as_string (file_1);
3155 type_string_2 = nemo_file_get_detailed_type_as_string (file_2);
3156 } else {
3157 type_string_1 = nemo_file_get_type_as_string (file_1);
3158 type_string_2 = nemo_file_get_type_as_string (file_2);
3159 }
3160
3161 if (type_string_1 == NULL || type_string_2 == NULL) {
3162 if (type_string_1 != NULL) {
3163 return -1;
3164 }
3165
3166 if (type_string_2 != NULL) {
3167 return 1;
3168 }
3169
3170 return 0;
3171 }
3172
3173 result = g_utf8_collate (type_string_1, type_string_2);
3174
3175 g_free (type_string_1);
3176 g_free (type_string_2);
3177
3178 return result;
3179 }
3180
3181 static int
compare_by_time(NemoFile * file_1,NemoFile * file_2,NemoDateType type)3182 compare_by_time (NemoFile *file_1, NemoFile *file_2, NemoDateType type)
3183 {
3184 /* Sort order:
3185 * Files with unknown times.
3186 * Files with "unknowable" times.
3187 * Files with older times.
3188 * Files with newer times.
3189 */
3190
3191 Knowledge time_known_1, time_known_2;
3192 time_t time_1, time_2;
3193
3194 time_1 = 0;
3195 time_2 = 0;
3196
3197 time_known_1 = get_time (file_1, &time_1, type);
3198 time_known_2 = get_time (file_2, &time_2, type);
3199
3200 if (time_known_1 > time_known_2) {
3201 return -1;
3202 }
3203 if (time_known_1 < time_known_2) {
3204 return +1;
3205 }
3206
3207 /* Now time_known_1 is equal to time_known_2. Check whether
3208 * we failed to get modification times for files
3209 */
3210 if(time_known_1 == UNKNOWABLE || time_known_1 == UNKNOWN) {
3211 return 0;
3212 }
3213
3214 if (time_1 < time_2) {
3215 return -1;
3216 }
3217 if (time_1 > time_2) {
3218 return +1;
3219 }
3220
3221 return 0;
3222 }
3223
3224 static int
compare_by_full_path(NemoFile * file_1,NemoFile * file_2)3225 compare_by_full_path (NemoFile *file_1, NemoFile *file_2)
3226 {
3227 int compare;
3228
3229 compare = compare_by_directory_name (file_1, file_2);
3230 if (compare != 0) {
3231 return compare;
3232 }
3233 return compare_by_display_name (file_1, file_2);
3234 }
3235
3236 static int
nemo_file_compare_for_sort_internal(NemoFile * file_1,NemoFile * file_2,gboolean directories_first,gboolean reversed)3237 nemo_file_compare_for_sort_internal (NemoFile *file_1,
3238 NemoFile *file_2,
3239 gboolean directories_first,
3240 gboolean reversed)
3241 {
3242 gboolean is_directory_1, is_directory_2;
3243 gboolean pinned_1, pinned_2;
3244 gboolean favorite_1, favorite_2;
3245
3246 favorite_1 = nemo_file_get_is_favorite (file_1);
3247 favorite_2 = nemo_file_get_is_favorite (file_2);
3248
3249 pinned_1 = nemo_file_get_pinning (file_1);
3250 pinned_2 = nemo_file_get_pinning (file_2);
3251
3252 if (favorite_1 && !favorite_2) {
3253 return -1;
3254 }
3255
3256 if (favorite_2 && !favorite_1) {
3257 return +1;
3258 }
3259
3260 if (pinned_1 && !pinned_2) {
3261 return -1;
3262 }
3263
3264 if (pinned_2 && !pinned_1) {
3265 return +1;
3266 }
3267
3268 if (directories_first) {
3269 is_directory_1 = nemo_file_is_directory (file_1);
3270 is_directory_2 = nemo_file_is_directory (file_2);
3271
3272 if (is_directory_1 && !is_directory_2) {
3273 return -1;
3274 }
3275
3276 if (is_directory_2 && !is_directory_1) {
3277 return +1;
3278 }
3279 }
3280
3281 if (file_1->details->sort_order < file_2->details->sort_order) {
3282 return reversed ? 1 : -1;
3283 } else if (file_1->details->sort_order > file_2->details->sort_order) {
3284 return reversed ? -1 : 1;
3285 }
3286
3287 return 0;
3288 }
3289
3290 /**
3291 * nemo_file_compare_for_sort:
3292 * @file_1: A file object
3293 * @file_2: Another file object
3294 * @sort_type: Sort criterion
3295 * @directories_first: Put all directories before any non-directories
3296 * @reversed: Reverse the order of the items, except that
3297 * the directories_first flag is still respected.
3298 *
3299 * Return value: int < 0 if @file_1 should come before file_2 in a
3300 * sorted list; int > 0 if @file_2 should come before file_1 in a
3301 * sorted list; 0 if @file_1 and @file_2 are equal for this sort criterion. Note
3302 * that each named sort type may actually break ties several ways, with the name
3303 * of the sort criterion being the primary but not only differentiator.
3304 **/
3305 int
nemo_file_compare_for_sort(NemoFile * file_1,NemoFile * file_2,NemoFileSortType sort_type,gboolean directories_first,gboolean reversed)3306 nemo_file_compare_for_sort (NemoFile *file_1,
3307 NemoFile *file_2,
3308 NemoFileSortType sort_type,
3309 gboolean directories_first,
3310 gboolean reversed)
3311 {
3312 int result;
3313
3314 if (file_1 == file_2) {
3315 return 0;
3316 }
3317
3318 result = nemo_file_compare_for_sort_internal (file_1, file_2, directories_first, reversed);
3319
3320 if (result == 0) {
3321 switch (sort_type) {
3322 case NEMO_FILE_SORT_BY_DISPLAY_NAME:
3323 result = compare_by_display_name (file_1, file_2);
3324 if (result == 0) {
3325 result = compare_by_directory_name (file_1, file_2);
3326 }
3327 break;
3328 case NEMO_FILE_SORT_BY_SIZE:
3329 /* Compare directory sizes ourselves, then if necessary
3330 * use GnomeVFS to compare file sizes.
3331 */
3332 result = compare_by_size (file_1, file_2);
3333 if (result == 0) {
3334 result = compare_by_full_path (file_1, file_2);
3335 }
3336 break;
3337 case NEMO_FILE_SORT_BY_TYPE:
3338 result = compare_by_type (file_1, file_2, FALSE);
3339 if (result == 0) {
3340 result = compare_by_full_path (file_1, file_2);
3341 }
3342 break;
3343 case NEMO_FILE_SORT_BY_DETAILED_TYPE:
3344 result = compare_by_type (file_1, file_2, TRUE);
3345 if (result == 0) {
3346 result = compare_by_full_path (file_1, file_2);
3347 }
3348 break;
3349 case NEMO_FILE_SORT_BY_MTIME:
3350 result = compare_by_time (file_1, file_2, NEMO_DATE_TYPE_MODIFIED);
3351 if (result == 0) {
3352 result = compare_by_full_path (file_1, file_2);
3353 }
3354 break;
3355 case NEMO_FILE_SORT_BY_ATIME:
3356 result = compare_by_time (file_1, file_2, NEMO_DATE_TYPE_ACCESSED);
3357 if (result == 0) {
3358 result = compare_by_full_path (file_1, file_2);
3359 }
3360 break;
3361 case NEMO_FILE_SORT_BY_BTIME:
3362 result = compare_by_time (file_1, file_2, NEMO_DATE_TYPE_CREATED);
3363 if (result == 0) {
3364 result = compare_by_full_path (file_1, file_2);
3365 }
3366 break;
3367 case NEMO_FILE_SORT_BY_TRASHED_TIME:
3368 result = compare_by_time (file_1, file_2, NEMO_DATE_TYPE_TRASHED);
3369 if (result == 0) {
3370 result = compare_by_full_path (file_1, file_2);
3371 }
3372 break;
3373 case NEMO_FILE_SORT_NONE:
3374 default:
3375 g_return_val_if_reached (0);
3376 }
3377
3378 if (reversed) {
3379 result = -result;
3380 }
3381 }
3382
3383 return result;
3384 }
3385
3386 int
nemo_file_compare_for_sort_by_attribute_q(NemoFile * file_1,NemoFile * file_2,GQuark attribute,gboolean directories_first,gboolean reversed)3387 nemo_file_compare_for_sort_by_attribute_q (NemoFile *file_1,
3388 NemoFile *file_2,
3389 GQuark attribute,
3390 gboolean directories_first,
3391 gboolean reversed)
3392 {
3393 int result;
3394
3395 if (file_1 == file_2) {
3396 return 0;
3397 }
3398
3399 /* Convert certain attributes into NemoFileSortTypes and use
3400 * nemo_file_compare_for_sort()
3401 */
3402 if (attribute == 0 || attribute == attribute_name_q) {
3403 return nemo_file_compare_for_sort (file_1, file_2,
3404 NEMO_FILE_SORT_BY_DISPLAY_NAME,
3405 directories_first,
3406 reversed);
3407 } else if (attribute == attribute_size_q) {
3408 return nemo_file_compare_for_sort (file_1, file_2,
3409 NEMO_FILE_SORT_BY_SIZE,
3410 directories_first,
3411 reversed);
3412 } else if (attribute == attribute_type_q) {
3413 return nemo_file_compare_for_sort (file_1, file_2,
3414 NEMO_FILE_SORT_BY_TYPE,
3415 directories_first,
3416 reversed);
3417 } else if (attribute == attribute_detailed_type_q) {
3418 return nemo_file_compare_for_sort (file_1, file_2,
3419 NEMO_FILE_SORT_BY_DETAILED_TYPE,
3420 directories_first,
3421 reversed);
3422 } else if (attribute == attribute_modification_date_q ||
3423 attribute == attribute_date_modified_q ||
3424 attribute == attribute_date_modified_with_time_q ||
3425 attribute == attribute_date_modified_full_q) {
3426 return nemo_file_compare_for_sort (file_1, file_2,
3427 NEMO_FILE_SORT_BY_MTIME,
3428 directories_first,
3429 reversed);
3430 } else if (attribute == attribute_accessed_date_q ||
3431 attribute == attribute_date_accessed_q ||
3432 attribute == attribute_date_accessed_full_q) {
3433 return nemo_file_compare_for_sort (file_1, file_2,
3434 NEMO_FILE_SORT_BY_ATIME,
3435 directories_first,
3436 reversed);
3437 } else if (attribute == attribute_creation_date_q ||
3438 attribute == attribute_date_created_q ||
3439 attribute == attribute_date_created_with_time_q ||
3440 attribute == attribute_date_created_full_q) {
3441 return nemo_file_compare_for_sort (file_1, file_2,
3442 NEMO_FILE_SORT_BY_BTIME,
3443 directories_first,
3444 reversed);
3445 } else if (attribute == attribute_trashed_on_q ||
3446 attribute == attribute_trashed_on_full_q) {
3447 return nemo_file_compare_for_sort (file_1, file_2,
3448 NEMO_FILE_SORT_BY_TRASHED_TIME,
3449 directories_first,
3450 reversed);
3451 }
3452
3453 /* it is a normal attribute, compare by strings */
3454
3455 result = nemo_file_compare_for_sort_internal (file_1, file_2, directories_first, reversed);
3456
3457 if (result == 0) {
3458 char *value_1;
3459 char *value_2;
3460
3461 value_1 = nemo_file_get_string_attribute_q (file_1,
3462 attribute);
3463 value_2 = nemo_file_get_string_attribute_q (file_2,
3464 attribute);
3465
3466 if (value_1 != NULL && value_2 != NULL) {
3467 result = strcmp (value_1, value_2);
3468 }
3469
3470 g_free (value_1);
3471 g_free (value_2);
3472
3473 if (reversed) {
3474 result = -result;
3475 }
3476 }
3477
3478 return result;
3479 }
3480
3481 int
nemo_file_compare_for_sort_by_attribute(NemoFile * file_1,NemoFile * file_2,const char * attribute,gboolean directories_first,gboolean reversed)3482 nemo_file_compare_for_sort_by_attribute (NemoFile *file_1,
3483 NemoFile *file_2,
3484 const char *attribute,
3485 gboolean directories_first,
3486 gboolean reversed)
3487 {
3488 return nemo_file_compare_for_sort_by_attribute_q (file_1, file_2,
3489 g_quark_from_string (attribute),
3490 directories_first,
3491 reversed);
3492 }
3493
3494
3495 /**
3496 * nemo_file_compare_name:
3497 * @file: A file object
3498 * @pattern: A string we are comparing it with
3499 *
3500 * Return value: result of a comparison of the file name and the given pattern,
3501 * using the same sorting order as sort by name.
3502 **/
3503 int
nemo_file_compare_display_name(NemoFile * file,const char * pattern)3504 nemo_file_compare_display_name (NemoFile *file,
3505 const char *pattern)
3506 {
3507 const char *name;
3508 int result;
3509
3510 g_return_val_if_fail (pattern != NULL, -1);
3511
3512 name = nemo_file_peek_display_name (file);
3513 result = g_utf8_collate (name, pattern);
3514 return result;
3515 }
3516
3517
3518 gboolean
nemo_file_is_hidden_file(NemoFile * file)3519 nemo_file_is_hidden_file (NemoFile *file)
3520 {
3521 return file->details->is_hidden;
3522 }
3523
3524 /**
3525 * nemo_file_should_show:
3526 * @file: the file to check.
3527 * @show_hidden: whether we want to show hidden files or not.
3528 *
3529 * Determines if a #NemoFile should be shown. Note that when browsing
3530 * a trash directory, this function will always return %TRUE.
3531 *
3532 * Returns: %TRUE if the file should be shown, %FALSE if it shouldn't.
3533 */
3534 gboolean
nemo_file_should_show(NemoFile * file,gboolean show_hidden,gboolean show_foreign)3535 nemo_file_should_show (NemoFile *file,
3536 gboolean show_hidden,
3537 gboolean show_foreign)
3538 {
3539 /* Never hide any files in trash. */
3540 if (nemo_file_is_in_trash (file)) {
3541 return TRUE;
3542 } else {
3543 return (show_hidden || !nemo_file_is_hidden_file (file)) &&
3544 (show_foreign || !(nemo_file_is_in_desktop (file) && nemo_file_is_foreign_link (file)));
3545 }
3546 }
3547
3548 gboolean
nemo_file_is_home(NemoFile * file)3549 nemo_file_is_home (NemoFile *file)
3550 {
3551 GFile *dir;
3552
3553 dir = file->details->directory->details->location;
3554 if (dir == NULL) {
3555 return FALSE;
3556 }
3557
3558 return nemo_is_home_directory_file (dir,
3559 eel_ref_str_peek (file->details->name));
3560 }
3561
3562 gboolean
nemo_file_is_in_desktop(NemoFile * file)3563 nemo_file_is_in_desktop (NemoFile *file)
3564 {
3565 if (file->details->directory->details->location) {
3566 return nemo_is_desktop_directory (file->details->directory->details->location);
3567 }
3568 return FALSE;
3569 }
3570
3571 static gboolean
filter_hidden_partition_callback(gpointer data,gpointer callback_data)3572 filter_hidden_partition_callback (gpointer data,
3573 gpointer callback_data)
3574 {
3575 NemoFile *file;
3576 FilterOptions options;
3577
3578 file = NEMO_FILE (data);
3579 options = GPOINTER_TO_INT (callback_data);
3580
3581 return nemo_file_should_show (file,
3582 options & SHOW_HIDDEN,
3583 TRUE);
3584 }
3585
3586 GList *
nemo_file_list_filter_hidden(GList * files,gboolean show_hidden)3587 nemo_file_list_filter_hidden (GList *files,
3588 gboolean show_hidden)
3589 {
3590 GList *filtered_files;
3591 GList *removed_files;
3592
3593 /* FIXME bugzilla.gnome.org 40653:
3594 * Eventually this should become a generic filtering thingy.
3595 */
3596
3597 filtered_files = nemo_file_list_copy (files);
3598 filtered_files = eel_g_list_partition (filtered_files,
3599 filter_hidden_partition_callback,
3600 GINT_TO_POINTER ((show_hidden ? SHOW_HIDDEN : 0)),
3601 &removed_files);
3602 nemo_file_list_free (removed_files);
3603
3604 return filtered_files;
3605 }
3606
3607 char *
nemo_file_get_metadata(NemoFile * file,const char * key,const char * default_metadata)3608 nemo_file_get_metadata (NemoFile *file,
3609 const char *key,
3610 const char *default_metadata)
3611 {
3612 guint id;
3613 char *value;
3614
3615 g_return_val_if_fail (key != NULL, g_strdup (default_metadata));
3616 g_return_val_if_fail (key[0] != '\0', g_strdup (default_metadata));
3617
3618 if (file == NULL ||
3619 file->details->metadata == NULL) {
3620 return g_strdup (default_metadata);
3621 }
3622
3623 g_return_val_if_fail (NEMO_IS_FILE (file), g_strdup (default_metadata));
3624
3625 if (NEMO_FILE_GET_CLASS (file)->get_metadata) {
3626 value = NEMO_FILE_GET_CLASS (file)->get_metadata (file, key);
3627 if (value) {
3628 return value;
3629 } else {
3630 return g_strdup (default_metadata);
3631 }
3632 }
3633
3634 id = nemo_metadata_get_id (key);
3635 value = g_hash_table_lookup (file->details->metadata, GUINT_TO_POINTER (id));
3636
3637 if (value) {
3638 return g_strdup (value);
3639 }
3640 return g_strdup (default_metadata);
3641 }
3642
3643 GList *
nemo_file_get_metadata_list(NemoFile * file,const char * key)3644 nemo_file_get_metadata_list (NemoFile *file,
3645 const char *key)
3646 {
3647 GList *res;
3648 guint id;
3649 char **value;
3650
3651 g_return_val_if_fail (key != NULL, NULL);
3652 g_return_val_if_fail (key[0] != '\0', NULL);
3653
3654 if (file == NULL ||
3655 file->details->metadata == NULL) {
3656 return NULL;
3657 }
3658
3659 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
3660
3661 if (NEMO_FILE_GET_CLASS (file)->get_metadata_as_list) {
3662 gchar **meta_strv = NEMO_FILE_GET_CLASS (file)->get_metadata_as_list (file, key);
3663
3664 res = eel_strv_to_glist (meta_strv);
3665
3666 g_strfreev (meta_strv);
3667 return res;
3668 }
3669
3670 id = nemo_metadata_get_id (key);
3671 id |= METADATA_ID_IS_LIST_MASK;
3672
3673 value = g_hash_table_lookup (file->details->metadata, GUINT_TO_POINTER (id));
3674
3675 if (value) {
3676 return eel_strv_to_glist (value);
3677 }
3678
3679 return NULL;
3680 }
3681
3682 void
nemo_file_set_metadata(NemoFile * file,const char * key,const char * default_metadata,const char * metadata)3683 nemo_file_set_metadata (NemoFile *file,
3684 const char *key,
3685 const char *default_metadata,
3686 const char *metadata)
3687 {
3688 const char *val;
3689
3690 g_return_if_fail (NEMO_IS_FILE (file));
3691 g_return_if_fail (key != NULL);
3692 g_return_if_fail (key[0] != '\0');
3693
3694 val = metadata;
3695 if (val == NULL) {
3696 val = default_metadata;
3697 }
3698
3699 NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->set_metadata (file, key, val);
3700 }
3701
3702 void
nemo_file_set_metadata_list(NemoFile * file,const char * key,GList * list)3703 nemo_file_set_metadata_list (NemoFile *file,
3704 const char *key,
3705 GList *list)
3706 {
3707 char **val;
3708 int len, i;
3709 GList *l;
3710
3711 g_return_if_fail (NEMO_IS_FILE (file));
3712 g_return_if_fail (key != NULL);
3713 g_return_if_fail (key[0] != '\0');
3714
3715 len = g_list_length (list);
3716 val = g_new (char *, len + 1);
3717 for (l = list, i = 0; l != NULL; l = l->next, i++) {
3718 val[i] = l->data;
3719 }
3720 val[i] = NULL;
3721
3722 NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->set_metadata_as_list (file, key, val);
3723
3724 g_free (val);
3725 }
3726
3727 void
nemo_file_set_desktop_grid_adjusts(NemoFile * file,const char * key,int int_a,int int_b)3728 nemo_file_set_desktop_grid_adjusts (NemoFile *file,
3729 const char *key,
3730 int int_a,
3731 int int_b)
3732 {
3733 char **val;
3734
3735 g_return_if_fail (NEMO_IS_FILE (file));
3736 g_return_if_fail (key != NULL);
3737 g_return_if_fail (key[0] != '\0');
3738
3739 val = g_new (char *, 3);
3740
3741 val[0] = g_strdup_printf ("%d", int_a);
3742 val[1] = g_strdup_printf ("%d", int_b);
3743 val[2] = NULL;
3744
3745 NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->set_metadata_as_list (file, key, val);
3746
3747 g_strfreev ((gchar **) val);
3748 }
3749
3750 void
nemo_file_get_desktop_grid_adjusts(NemoFile * file,const char * key,int * int_a,int * int_b)3751 nemo_file_get_desktop_grid_adjusts (NemoFile *file,
3752 const char *key,
3753 int *int_a,
3754 int *int_b)
3755 {
3756 char c;
3757 gint result;
3758
3759 g_return_if_fail (key != NULL);
3760 g_return_if_fail (key[0] != '\0');
3761
3762 if (file == NULL ||
3763 file->details->metadata == NULL) {
3764 return;
3765 }
3766
3767 g_return_if_fail (NEMO_IS_FILE (file));
3768
3769 if (NEMO_FILE_GET_CLASS (file)->get_metadata_as_list) {
3770 gchar **meta_strv = NEMO_FILE_GET_CLASS (file)->get_metadata_as_list (file, key);
3771
3772 if (!meta_strv) {
3773 if (int_a)
3774 *int_a = 100;
3775 if (int_b)
3776 *int_b = 100;
3777
3778 return;
3779 }
3780
3781 if (int_a) {
3782 if (sscanf (meta_strv[0], " %d %c", &result, &c) == 1) {
3783 *int_a = result;
3784 }
3785 }
3786
3787 if (int_b) {
3788 if (sscanf (meta_strv[1], " %d %c", &result, &c) == 1) {
3789 *int_b = result;
3790 }
3791 }
3792
3793 g_strfreev (meta_strv);
3794 }
3795 }
3796
3797 gboolean
nemo_file_get_boolean_metadata(NemoFile * file,const char * key,gboolean default_metadata)3798 nemo_file_get_boolean_metadata (NemoFile *file,
3799 const char *key,
3800 gboolean default_metadata)
3801 {
3802 char *result_as_string;
3803 gboolean result;
3804
3805 g_return_val_if_fail (key != NULL, default_metadata);
3806 g_return_val_if_fail (key[0] != '\0', default_metadata);
3807
3808 if (file == NULL) {
3809 return default_metadata;
3810 }
3811
3812 g_return_val_if_fail (NEMO_IS_FILE (file), default_metadata);
3813
3814 result_as_string = nemo_file_get_metadata
3815 (file, key, default_metadata ? "true" : "false");
3816 g_assert (result_as_string != NULL);
3817
3818 if (g_ascii_strcasecmp (result_as_string, "true") == 0) {
3819 result = TRUE;
3820 } else if (g_ascii_strcasecmp (result_as_string, "false") == 0) {
3821 result = FALSE;
3822 } else {
3823 g_error ("boolean metadata with value other than true or false");
3824 result = default_metadata;
3825 }
3826
3827 g_free (result_as_string);
3828 return result;
3829 }
3830
3831 int
nemo_file_get_integer_metadata(NemoFile * file,const char * key,int default_metadata)3832 nemo_file_get_integer_metadata (NemoFile *file,
3833 const char *key,
3834 int default_metadata)
3835 {
3836 char *result_as_string;
3837 char default_as_string[32];
3838 int result;
3839 char c;
3840
3841 g_return_val_if_fail (key != NULL, default_metadata);
3842 g_return_val_if_fail (key[0] != '\0', default_metadata);
3843
3844 if (file == NULL) {
3845 return default_metadata;
3846 }
3847 g_return_val_if_fail (NEMO_IS_FILE (file), default_metadata);
3848
3849 g_snprintf (default_as_string, sizeof (default_as_string), "%d", default_metadata);
3850 result_as_string = nemo_file_get_metadata
3851 (file, key, default_as_string);
3852
3853 /* Normally we can't get a a NULL, but we check for it here to
3854 * handle the oddball case of a non-existent directory.
3855 */
3856 if (result_as_string == NULL) {
3857 result = default_metadata;
3858 } else {
3859 if (sscanf (result_as_string, " %d %c", &result, &c) != 1) {
3860 result = default_metadata;
3861 }
3862 g_free (result_as_string);
3863 }
3864
3865 return result;
3866 }
3867
3868 static gboolean
get_time_from_time_string(const char * time_string,time_t * time)3869 get_time_from_time_string (const char *time_string,
3870 time_t *time)
3871 {
3872 long scanned_time;
3873 char c;
3874
3875 g_assert (time != NULL);
3876
3877 /* Only accept string if it has one integer with nothing
3878 * afterwards.
3879 */
3880 if (time_string == NULL ||
3881 sscanf (time_string, "%ld%c", &scanned_time, &c) != 1) {
3882 return FALSE;
3883 }
3884 *time = (time_t) scanned_time;
3885 return TRUE;
3886 }
3887
3888 time_t
nemo_file_get_time_metadata(NemoFile * file,const char * key)3889 nemo_file_get_time_metadata (NemoFile *file,
3890 const char *key)
3891 {
3892 time_t time;
3893 char *time_string;
3894
3895 time_string = nemo_file_get_metadata (file, key, NULL);
3896 if (!get_time_from_time_string (time_string, &time)) {
3897 time = UNDEFINED_TIME;
3898 }
3899 g_free (time_string);
3900
3901 return time;
3902 }
3903
3904 void
nemo_file_set_time_metadata(NemoFile * file,const char * key,time_t time)3905 nemo_file_set_time_metadata (NemoFile *file,
3906 const char *key,
3907 time_t time)
3908 {
3909 char time_str[21];
3910 char *metadata;
3911
3912 if (time != UNDEFINED_TIME) {
3913 /* 2^64 turns out to be 20 characters */
3914 g_snprintf (time_str, 20, "%ld", (long int)time);
3915 time_str[20] = '\0';
3916 metadata = time_str;
3917 } else {
3918 metadata = NULL;
3919 }
3920
3921 nemo_file_set_metadata (file, key, NULL, metadata);
3922 }
3923
3924
3925 void
nemo_file_set_boolean_metadata(NemoFile * file,const char * key,gboolean default_metadata,gboolean metadata)3926 nemo_file_set_boolean_metadata (NemoFile *file,
3927 const char *key,
3928 gboolean default_metadata,
3929 gboolean metadata)
3930 {
3931 g_return_if_fail (NEMO_IS_FILE (file));
3932 g_return_if_fail (key != NULL);
3933 g_return_if_fail (key[0] != '\0');
3934
3935 nemo_file_set_metadata (file, key,
3936 default_metadata ? "true" : "false",
3937 metadata ? "true" : "false");
3938 }
3939
3940 void
nemo_file_set_integer_metadata(NemoFile * file,const char * key,int default_metadata,int metadata)3941 nemo_file_set_integer_metadata (NemoFile *file,
3942 const char *key,
3943 int default_metadata,
3944 int metadata)
3945 {
3946 char value_as_string[32];
3947 char default_as_string[32];
3948
3949 g_return_if_fail (NEMO_IS_FILE (file));
3950 g_return_if_fail (key != NULL);
3951 g_return_if_fail (key[0] != '\0');
3952
3953 g_snprintf (value_as_string, sizeof (value_as_string), "%d", metadata);
3954 g_snprintf (default_as_string, sizeof (default_as_string), "%d", default_metadata);
3955
3956 nemo_file_set_metadata (file, key,
3957 default_as_string, value_as_string);
3958 }
3959
3960 static const char *
nemo_file_peek_display_name_collation_key(NemoFile * file)3961 nemo_file_peek_display_name_collation_key (NemoFile *file)
3962 {
3963 const char *res;
3964
3965 res = file->details->display_name_collation_key;
3966 if (res == NULL)
3967 res = "";
3968
3969 return res;
3970 }
3971
3972 static const char *
nemo_file_peek_display_name(NemoFile * file)3973 nemo_file_peek_display_name (NemoFile *file)
3974 {
3975 const char *name;
3976 char *escaped_name;
3977
3978 /* FIXME: for some reason we can get a NemoFile instance which is
3979 * no longer valid or could be freed somewhere else in the same time.
3980 * There's race condition somewhere. See bug 602500.
3981 */
3982 if (file == NULL || nemo_file_is_gone (file))
3983 return "";
3984
3985 /* Default to display name based on filename if its not set yet */
3986
3987 if (file->details->display_name == NULL) {
3988 name = eel_ref_str_peek (file->details->name);
3989 if (g_utf8_validate (name, -1, NULL)) {
3990 nemo_file_set_display_name (file,
3991 name,
3992 NULL,
3993 FALSE);
3994 } else {
3995 escaped_name = g_uri_escape_string (name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
3996 nemo_file_set_display_name (file,
3997 escaped_name,
3998 NULL,
3999 FALSE);
4000 g_free (escaped_name);
4001 }
4002 }
4003
4004 return eel_ref_str_peek (file->details->display_name);
4005 }
4006
4007 char *
nemo_file_get_display_name(NemoFile * file)4008 nemo_file_get_display_name (NemoFile *file)
4009 {
4010 return g_strdup (nemo_file_peek_display_name (file));
4011 }
4012
4013 char *
nemo_file_get_edit_name(NemoFile * file)4014 nemo_file_get_edit_name (NemoFile *file)
4015 {
4016 const char *res;
4017
4018 res = eel_ref_str_peek (file->details->edit_name);
4019 if (res == NULL)
4020 res = "";
4021
4022 return g_strdup (res);
4023 }
4024
4025 const char *
nemo_file_peek_name(NemoFile * file)4026 nemo_file_peek_name (NemoFile *file)
4027 {
4028 return file->details->name;
4029 }
4030
4031 char *
nemo_file_get_name(NemoFile * file)4032 nemo_file_get_name (NemoFile *file)
4033 {
4034 return g_strdup (eel_ref_str_peek (file->details->name));
4035 }
4036
4037 /**
4038 * nemo_file_get_description:
4039 * @file: a #NemoFile.
4040 *
4041 * Gets the standard::description key from @file, if
4042 * it has been cached.
4043 *
4044 * Returns: a string containing the value of the standard::description
4045 * key, or %NULL.
4046 */
4047 char *
nemo_file_get_description(NemoFile * file)4048 nemo_file_get_description (NemoFile *file)
4049 {
4050 return g_strdup (file->details->description);
4051 }
4052
4053 void
nemo_file_monitor_add(NemoFile * file,gconstpointer client,NemoFileAttributes attributes)4054 nemo_file_monitor_add (NemoFile *file,
4055 gconstpointer client,
4056 NemoFileAttributes attributes)
4057 {
4058 g_return_if_fail (NEMO_IS_FILE (file));
4059 g_return_if_fail (client != NULL);
4060
4061 NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->monitor_add (file, client, attributes);
4062 }
4063
4064 void
nemo_file_monitor_remove(NemoFile * file,gconstpointer client)4065 nemo_file_monitor_remove (NemoFile *file,
4066 gconstpointer client)
4067 {
4068 g_return_if_fail (NEMO_IS_FILE (file));
4069 g_return_if_fail (client != NULL);
4070
4071 NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->monitor_remove (file, client);
4072 }
4073
4074 gboolean
nemo_file_is_launcher(NemoFile * file)4075 nemo_file_is_launcher (NemoFile *file)
4076 {
4077 return file->details->is_launcher;
4078 }
4079
4080 gboolean
nemo_file_is_foreign_link(NemoFile * file)4081 nemo_file_is_foreign_link (NemoFile *file)
4082 {
4083 return file->details->is_foreign_link;
4084 }
4085
4086 gboolean
nemo_file_is_trusted_link(NemoFile * file)4087 nemo_file_is_trusted_link (NemoFile *file)
4088 {
4089 return file->details->is_trusted_link;
4090 }
4091
4092 gboolean
nemo_file_has_activation_uri(NemoFile * file)4093 nemo_file_has_activation_uri (NemoFile *file)
4094 {
4095 return file->details->activation_uri != NULL;
4096 }
4097
4098
4099 /* Return the uri associated with the passed-in file, which may not be
4100 * the actual uri if the file is an desktop file or a nemo
4101 * xml link file.
4102 */
4103 char *
nemo_file_get_activation_uri(NemoFile * file)4104 nemo_file_get_activation_uri (NemoFile *file)
4105 {
4106 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
4107
4108 if (file->details->activation_uri != NULL) {
4109 return g_strdup (file->details->activation_uri);
4110 }
4111
4112 return nemo_file_get_uri (file);
4113 }
4114
4115 GFile *
nemo_file_get_activation_location(NemoFile * file)4116 nemo_file_get_activation_location (NemoFile *file)
4117 {
4118 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
4119
4120 if (file->details->activation_uri != NULL) {
4121 return g_file_new_for_uri (file->details->activation_uri);
4122 }
4123
4124 return nemo_file_get_location (file);
4125 }
4126
4127
4128 char *
nemo_file_get_drop_target_uri(NemoFile * file)4129 nemo_file_get_drop_target_uri (NemoFile *file)
4130 {
4131 char *uri, *target_uri;
4132 GFile *location;
4133 NemoDesktopLink *link;
4134
4135 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
4136
4137 if (NEMO_IS_DESKTOP_ICON_FILE (file)) {
4138 link = nemo_desktop_icon_file_get_link (NEMO_DESKTOP_ICON_FILE (file));
4139
4140 if (link != NULL) {
4141 location = nemo_desktop_link_get_activation_location (link);
4142 g_object_unref (link);
4143 if (location != NULL) {
4144 uri = g_file_get_uri (location);
4145 g_object_unref (location);
4146 return uri;
4147 }
4148 }
4149 }
4150
4151 uri = nemo_file_get_uri (file);
4152
4153 /* Check for Nemo link */
4154 if (nemo_file_is_nemo_link (file)) {
4155 location = nemo_file_get_location (file);
4156 /* FIXME bugzilla.gnome.org 43020: This does sync. I/O and works only locally. */
4157 if (g_file_is_native (location)) {
4158 target_uri = nemo_link_local_get_link_uri (uri);
4159 if (target_uri != NULL) {
4160 g_free (uri);
4161 uri = target_uri;
4162 }
4163 }
4164 g_object_unref (location);
4165 }
4166
4167 return uri;
4168 }
4169
4170 static gboolean
is_uri_relative(const char * uri)4171 is_uri_relative (const char *uri)
4172 {
4173 char *scheme;
4174 gboolean ret;
4175
4176 scheme = g_uri_parse_scheme (uri);
4177 ret = (scheme == NULL);
4178 g_free (scheme);
4179 return ret;
4180 }
4181
4182 static char *
get_custom_icon_metadata_uri(NemoFile * file)4183 get_custom_icon_metadata_uri (NemoFile *file)
4184 {
4185 char *custom_icon_uri;
4186 char *uri;
4187 char *dir_uri;
4188
4189 uri = nemo_file_get_metadata (file, NEMO_METADATA_KEY_CUSTOM_ICON, NULL);
4190 if (uri != NULL &&
4191 nemo_file_is_directory (file) &&
4192 is_uri_relative (uri)) {
4193 dir_uri = nemo_file_get_uri (file);
4194 custom_icon_uri = g_build_filename (dir_uri, uri, NULL);
4195 g_free (dir_uri);
4196 g_free (uri);
4197 } else {
4198 custom_icon_uri = uri;
4199 }
4200 return custom_icon_uri;
4201 }
4202
4203 static char *
get_custom_icon_metadata_name(NemoFile * file)4204 get_custom_icon_metadata_name (NemoFile *file)
4205 {
4206 char *icon_name;
4207
4208 icon_name = nemo_file_get_metadata (file,
4209 NEMO_METADATA_KEY_CUSTOM_ICON_NAME, NULL);
4210
4211 return icon_name;
4212 }
4213
4214 static GIcon *
get_custom_icon(NemoFile * file)4215 get_custom_icon (NemoFile *file)
4216 {
4217 char *custom_icon_uri, *custom_icon_name;
4218 GFile *icon_file;
4219 GIcon *icon;
4220
4221 if (file == NULL) {
4222 return NULL;
4223 }
4224
4225 icon = NULL;
4226
4227 /* Metadata takes precedence; first we look at the custom
4228 * icon URI, then at the custom icon name.
4229 */
4230 custom_icon_uri = get_custom_icon_metadata_uri (file);
4231
4232 if (custom_icon_uri) {
4233 icon_file = g_file_new_for_uri (custom_icon_uri);
4234 icon = g_file_icon_new (icon_file);
4235 g_object_unref (icon_file);
4236 g_free (custom_icon_uri);
4237 }
4238
4239 if (icon == NULL) {
4240 custom_icon_name = get_custom_icon_metadata_name (file);
4241
4242 if (custom_icon_name != NULL) {
4243 icon = g_themed_icon_new (custom_icon_name);
4244 g_free (custom_icon_name);
4245 }
4246 }
4247
4248 if (icon == NULL && file->details->got_link_info && file->details->custom_icon != NULL) {
4249 icon = g_object_ref (file->details->custom_icon);
4250 }
4251
4252 return icon;
4253 }
4254
4255 GFilesystemPreviewType
nemo_file_get_filesystem_use_preview(NemoFile * file)4256 nemo_file_get_filesystem_use_preview (NemoFile *file)
4257 {
4258 GFilesystemPreviewType use_preview;
4259 NemoFile *parent;
4260
4261 parent = nemo_file_get_parent (file);
4262 if (parent != NULL) {
4263 use_preview = parent->details->filesystem_use_preview;
4264 g_object_unref (parent);
4265 } else {
4266 use_preview = 0;
4267 }
4268
4269 return use_preview;
4270 }
4271
4272 static gboolean
is_local_favorite(NemoFile * file)4273 is_local_favorite (NemoFile *file)
4274 {
4275 GFile *fav_file = nemo_file_get_location (file);
4276 gboolean ret;
4277
4278 // This will be a FavoriteVfsFile - its native check checks the target file.
4279 ret = g_file_is_native (fav_file);
4280 g_object_unref (fav_file);
4281
4282 return ret;
4283 }
4284
4285 gboolean
nemo_file_should_show_thumbnail(NemoFile * file)4286 nemo_file_should_show_thumbnail (NemoFile *file)
4287 {
4288 GFilesystemPreviewType use_preview;
4289 NemoFile *dir;
4290 char* metadata_str = NULL;
4291
4292 if (!NEMO_IS_FILE (file)) {
4293 return FALSE;
4294 }
4295
4296 use_preview = nemo_file_get_filesystem_use_preview (file);
4297 if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
4298 /* file system says to never thumbnail anything */
4299 return FALSE;
4300 }
4301
4302 /* Only care about the file size, if the thumbnail has not been created yet */
4303 if (file->details->thumbnail_path == NULL &&
4304 nemo_file_get_size (file) > cached_thumbnail_limit) {
4305 return FALSE;
4306 }
4307
4308 if (file->details->thumbnail_access_problem) {
4309 return FALSE;
4310 }
4311
4312 if (!nemo_global_preferences_get_ignore_view_metadata ()) {
4313 dir = nemo_file_is_directory(file) ? file : nemo_file_get_parent(file);
4314 if (nemo_global_preferences_get_inherit_show_thumbnails_preference ()) {
4315 while (dir != NULL) {
4316 metadata_str = nemo_file_get_metadata(dir,
4317 NEMO_METADATA_KEY_SHOW_THUMBNAILS,
4318 NULL);
4319 if (metadata_str == NULL) { // do this here to avoid string comparisons with a NULL string
4320 dir = nemo_file_get_parent(dir);
4321 }
4322 else if (g_ascii_strcasecmp (metadata_str, "true") == 0) {
4323 g_free(metadata_str);
4324 return TRUE;
4325 }
4326 else if (g_ascii_strcasecmp (metadata_str, "false") == 0) {
4327 g_free(metadata_str);
4328 return FALSE;
4329 }
4330 else {
4331 g_free(metadata_str);
4332 dir = nemo_file_get_parent(dir);
4333 }
4334 }
4335 } else {
4336 metadata_str = nemo_file_get_metadata(dir,
4337 NEMO_METADATA_KEY_SHOW_THUMBNAILS,
4338 NULL);
4339 if (metadata_str != NULL ) {
4340 if (g_ascii_strcasecmp (metadata_str, "true") == 0) {
4341 g_free(metadata_str);
4342 return TRUE;
4343 }
4344 else if (g_ascii_strcasecmp (metadata_str, "false") == 0) {
4345 g_free(metadata_str);
4346 return FALSE;
4347 }
4348 }
4349 }
4350 }
4351
4352 /* Use global preference */
4353 if (show_image_thumbs == NEMO_SPEED_TRADEOFF_ALWAYS) {
4354 return TRUE;
4355 }
4356 if (show_image_thumbs == NEMO_SPEED_TRADEOFF_NEVER) {
4357 return FALSE;
4358 }
4359 if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL) {
4360 // favorites:/// can have local and non-local files.
4361 // we check if each individual file is local (nemo_file_is_local()
4362 // checks if the parent is native, which for favorites:///
4363 // is false.)
4364 if (nemo_file_is_in_favorites (file)) {
4365 return is_local_favorite (file);
4366 }
4367
4368 /* file system says we should treat file as if it's local */
4369 return TRUE;
4370 }
4371 /* local files is the only left to check */
4372 return nemo_file_is_local (file);
4373 }
4374
4375 void
nemo_file_delete_thumbnail(NemoFile * file)4376 nemo_file_delete_thumbnail (NemoFile *file)
4377 {
4378 if (file->details->thumbnail_path == NULL) {
4379 return;
4380 }
4381
4382 gint success;
4383
4384 nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_THUMBNAIL);
4385 g_clear_object (&file->details->thumbnail);
4386
4387 success = g_unlink (file->details->thumbnail_path);
4388
4389 if (success != 0) {
4390 g_warning ("Could not remove thumb for '%s'. The thumbnail path is '%s'",
4391 file->details->display_name,
4392 file->details->thumbnail_path);
4393 }
4394 }
4395
4396 gboolean
nemo_file_has_loaded_thumbnail(NemoFile * file)4397 nemo_file_has_loaded_thumbnail (NemoFile *file)
4398 {
4399 return file->details->thumbnail_is_up_to_date;
4400 }
4401
4402 static void
prepend_icon_name(const char * name,GThemedIcon * icon)4403 prepend_icon_name (const char *name,
4404 GThemedIcon *icon)
4405 {
4406 g_themed_icon_prepend_name(icon, name);
4407 }
4408
4409 GIcon *
nemo_file_get_gicon(NemoFile * file,NemoFileIconFlags flags)4410 nemo_file_get_gicon (NemoFile *file,
4411 NemoFileIconFlags flags)
4412 {
4413 const char * const * names;
4414 const char *name;
4415 GPtrArray *prepend_array;
4416 GMount *mount;
4417 GIcon *icon, *mount_icon = NULL, *emblemed_icon;
4418 GEmblem *emblem;
4419 int i;
4420 gboolean is_folder = FALSE, is_inode_directory = FALSE;
4421
4422 if (file == NULL) {
4423 return NULL;
4424 }
4425
4426 icon = get_custom_icon (file);
4427
4428 if (icon != NULL) {
4429 return icon;
4430 }
4431
4432 if (file->details->icon) {
4433 icon = NULL;
4434
4435 /* fetch the mount icon here, we'll use it later */
4436 if (flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON ||
4437 flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM) {
4438 mount = nemo_file_get_mount (file);
4439
4440 if (mount != NULL) {
4441 mount_icon = g_mount_get_icon (mount);
4442 g_object_unref (mount);
4443 }
4444 }
4445
4446 if (((flags & NEMO_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT) ||
4447 (flags & NEMO_FILE_ICON_FLAGS_FOR_OPEN_FOLDER) ||
4448 (flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON) ||
4449 (flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM) ||
4450 ((flags & NEMO_FILE_ICON_FLAGS_IGNORE_VISITING) == 0 &&
4451 nemo_file_has_open_window (file))) &&
4452 G_IS_THEMED_ICON (file->details->icon)) {
4453 names = g_themed_icon_get_names (G_THEMED_ICON (file->details->icon));
4454 prepend_array = g_ptr_array_new ();
4455
4456 for (i = 0; names[i] != NULL; i++) {
4457 name = names[i];
4458
4459 if (strcmp (name, "folder") == 0) {
4460 is_folder = TRUE;
4461 }
4462 if (strcmp (name, "inode-directory") == 0) {
4463 is_inode_directory = TRUE;
4464 }
4465 }
4466
4467 /* Here, we add icons in reverse order of precedence,
4468 * because they are later prepended */
4469
4470 /* "folder" should override "inode-directory", not the other way around */
4471 if (is_inode_directory) {
4472 g_ptr_array_add (prepend_array, (char *)"folder");
4473 }
4474 if (is_folder && (flags & NEMO_FILE_ICON_FLAGS_FOR_OPEN_FOLDER)) {
4475 g_ptr_array_add (prepend_array, (char *)"folder-open");
4476 }
4477 if (is_folder &&
4478 (flags & NEMO_FILE_ICON_FLAGS_IGNORE_VISITING) == 0 &&
4479 nemo_file_has_open_window (file)) {
4480 g_ptr_array_add (prepend_array, (char *)"folder-visiting");
4481 }
4482 if (is_folder &&
4483 (flags & NEMO_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT)) {
4484 g_ptr_array_add (prepend_array, (char *)"folder-drag-accept");
4485 }
4486
4487 if (prepend_array->len) {
4488 /* When constructing GThemed Icon, pointers from the array
4489 * are reused, but not the array itself, so the cast is safe */
4490 icon = g_themed_icon_new_from_names ((char**) names, -1);
4491 g_ptr_array_foreach (prepend_array, (GFunc) prepend_icon_name, icon);
4492 }
4493
4494 g_ptr_array_free (prepend_array, TRUE);
4495 }
4496
4497 if (icon == NULL) {
4498 icon = g_object_ref (file->details->icon);
4499 }
4500
4501 if ((flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON) &&
4502 mount_icon != NULL) {
4503 g_object_unref (icon);
4504 icon = mount_icon;
4505 } else if ((flags & NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM) &&
4506 mount_icon != NULL && !g_icon_equal (mount_icon, icon)) {
4507
4508 emblem = g_emblem_new (mount_icon);
4509 emblemed_icon = g_emblemed_icon_new (icon, emblem);
4510
4511 g_object_unref (emblem);
4512 g_object_unref (icon);
4513 g_object_unref (mount_icon);
4514
4515 icon = emblemed_icon;
4516 } else if (mount_icon != NULL) {
4517 g_object_unref (mount_icon);
4518 }
4519
4520 return icon;
4521 }
4522
4523 return g_themed_icon_new ("text-x-generic");
4524 }
4525
4526
4527 static const gchar *
get_symbolic_icon_name_for_file(NemoFile * file)4528 get_symbolic_icon_name_for_file (NemoFile *file)
4529 {
4530 if (nemo_file_is_home (file)) {
4531 return NEMO_ICON_SYMBOLIC_HOME;
4532 }
4533
4534 // Special folders (XDG)
4535 if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_DESKTOP)) {
4536 return NEMO_ICON_SYMBOLIC_DESKTOP;
4537 }
4538
4539 if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_DOCUMENTS)) {
4540 return NEMO_ICON_SYMBOLIC_FOLDER_DOCUMENTS;
4541 }
4542
4543 if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_DOWNLOAD)) {
4544 return NEMO_ICON_SYMBOLIC_FOLDER_DOWNLOAD;
4545 }
4546
4547 if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_MUSIC)) {
4548 return NEMO_ICON_SYMBOLIC_FOLDER_MUSIC;
4549 }
4550
4551 if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_PICTURES)) {
4552 return NEMO_ICON_SYMBOLIC_FOLDER_PICTURES;
4553 }
4554
4555 if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_PUBLIC_SHARE)) {
4556 return NEMO_ICON_SYMBOLIC_FOLDER_PUBLIC_SHARE;
4557 }
4558
4559 if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_TEMPLATES)) {
4560 return NEMO_ICON_SYMBOLIC_FOLDER_TEMPLATES;
4561 }
4562
4563 if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_VIDEOS)) {
4564 return NEMO_ICON_SYMBOLIC_FOLDER_VIDEOS;
4565 }
4566
4567 if (nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_TEMPLATES)) {
4568 return NEMO_ICON_SYMBOLIC_FOLDER_TEMPLATES;
4569 }
4570
4571 return NULL;
4572 }
4573
4574 gchar *
nemo_file_get_control_icon_name(NemoFile * file)4575 nemo_file_get_control_icon_name (NemoFile *file)
4576 {
4577 gchar *uri;
4578 gchar *icon_name;
4579
4580 icon_name = NULL;
4581
4582 uri = nemo_file_get_uri (file);
4583
4584 if (eel_uri_is_search (uri)) {
4585 icon_name = g_strdup (NEMO_ICON_SYMBOLIC_FOLDER_SAVED_SEARCH);
4586 } else if (eel_uri_is_trash (uri)) {
4587 icon_name = nemo_trash_monitor_get_symbolic_icon_name ();
4588 } else if (eel_uri_is_recent (uri)) {
4589 icon_name = g_strdup (NEMO_ICON_SYMBOLIC_FOLDER_RECENT);
4590 } else if (eel_uri_is_favorite (uri)) {
4591 icon_name = g_strdup (NEMO_ICON_SYMBOLIC_FOLDER_FAVORITES);
4592 } else if (eel_uri_is_network (uri)) {
4593 icon_name = g_strdup (NEMO_ICON_SYMBOLIC_NETWORK);
4594 } else {
4595 const gchar *static_name;
4596
4597 static_name = get_symbolic_icon_name_for_file (file);
4598
4599 if (static_name != NULL) {
4600 icon_name = g_strdup (static_name);
4601 } else {
4602 GFile *location;
4603
4604 location = nemo_file_get_location (file);
4605
4606 if (!g_file_is_native (location)) {
4607 icon_name = g_strdup (NEMO_ICON_SYMBOLIC_FOLDER_REMOTE);
4608 } else if (file->details->mime_type != NULL) {
4609 GIcon *gicon;
4610
4611 gicon = g_content_type_get_symbolic_icon (file->details->mime_type);
4612
4613 if (G_IS_THEMED_ICON (gicon)) {
4614 icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
4615 }
4616
4617 g_object_unref (gicon);
4618 }
4619
4620 g_object_unref (location);
4621 }
4622 }
4623
4624 g_free (uri);
4625
4626 if (icon_name == NULL) {
4627 icon_name = g_strdup ("text-x-generic");
4628 }
4629
4630 return icon_name;
4631 }
4632
4633 gboolean
nemo_file_get_pinning(NemoFile * file)4634 nemo_file_get_pinning (NemoFile *file)
4635 {
4636 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
4637
4638 if (file->details->pinning == FILE_META_STATE_INIT) {
4639 file->details->pinning = nemo_file_get_boolean_metadata (file, NEMO_METADATA_KEY_PINNED, FALSE);
4640 }
4641
4642 return file->details->pinning;
4643 }
4644
4645 void
nemo_file_set_pinning(NemoFile * file,gboolean pin)4646 nemo_file_set_pinning (NemoFile *file,
4647 gboolean pin)
4648 {
4649 g_return_if_fail (NEMO_IS_FILE (file));
4650
4651 nemo_file_set_boolean_metadata (file, NEMO_METADATA_KEY_PINNED, TRUE, pin);
4652 }
4653
4654 gboolean
nemo_file_get_is_favorite(NemoFile * file)4655 nemo_file_get_is_favorite (NemoFile *file)
4656 {
4657 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
4658
4659 if (file->details->favorite == FILE_META_STATE_INIT) {
4660 gboolean meta_bool = nemo_file_get_boolean_metadata (file, NEMO_METADATA_KEY_FAVORITE, FALSE);
4661 file->details->favorite = meta_bool ? FILE_META_STATE_TRUE : FILE_META_STATE_FALSE;
4662 }
4663
4664 return file->details->favorite;
4665 }
4666
4667 void
nemo_file_set_is_favorite(NemoFile * file,gboolean favorite)4668 nemo_file_set_is_favorite (NemoFile *file,
4669 gboolean favorite)
4670 {
4671 g_return_if_fail (NEMO_IS_FILE (file));
4672 NemoFile *real_file;
4673 gchar *uri;
4674
4675 if (nemo_file_is_in_favorites (file) && !nemo_file_is_broken_symbolic_link (file)) {
4676 uri = nemo_file_get_symbolic_link_target_uri (file);
4677 real_file = nemo_file_get_existing_by_uri (uri);
4678 } else {
4679 uri = nemo_file_get_uri (file);
4680 real_file = nemo_file_ref (file);
4681 }
4682
4683 nemo_file_set_boolean_metadata (real_file, NEMO_METADATA_KEY_FAVORITE, FALSE, favorite);
4684
4685 if (favorite)
4686 {
4687 xapp_favorites_add (xapp_favorites_get_default (), uri);
4688 }
4689 else
4690 {
4691 xapp_favorites_remove (xapp_favorites_get_default (), uri);
4692 }
4693
4694 nemo_file_unref (real_file);
4695 g_free (uri);
4696 }
4697
4698 static gint
get_throttle_count(NemoFile * file)4699 get_throttle_count (NemoFile *file)
4700 {
4701 NemoFileDetails *details = file->details;
4702
4703 gint diff = (gint)(details->mtime - details->last_thumbnail_try_mtime);
4704
4705 if (diff != 0 && diff <= (THUMBNAIL_CREATION_DELAY_SECS * (details->thumbnail_throttle_count + 1))) {
4706 details->thumbnail_throttle_count++;
4707 } else {
4708 details->thumbnail_throttle_count = 1;
4709 }
4710
4711 details->last_thumbnail_try_mtime = details->mtime;
4712
4713 return details->thumbnail_throttle_count;
4714 }
4715
4716 NemoIconInfo *
nemo_file_get_icon(NemoFile * file,int size,int max_width,int scale,NemoFileIconFlags flags)4717 nemo_file_get_icon (NemoFile *file,
4718 int size,
4719 int max_width,
4720 int scale,
4721 NemoFileIconFlags flags)
4722 {
4723 NemoIconInfo *icon;
4724 GIcon *gicon;
4725 GdkPixbuf *raw_pixbuf, *scaled_pixbuf;
4726 int modified_size;
4727
4728 if (file == NULL) {
4729 return NULL;
4730 }
4731
4732 gicon = get_custom_icon (file);
4733 if (gicon != NULL) {
4734 icon = nemo_icon_info_lookup (gicon, size, scale);
4735 g_object_unref (gicon);
4736 return icon;
4737 }
4738
4739 DEBUG ("Called file_get_icon(), at size %d, force thumbnail %d", size,
4740 flags & NEMO_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE);
4741
4742 if ((flags & NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS) &&
4743 nemo_file_should_show_thumbnail (file)) {
4744
4745 if (flags & NEMO_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE) {
4746 modified_size = size * scale;
4747 } else {
4748 modified_size = size * scale * scaled_cached_thumbnail_size;
4749 DEBUG ("Modifying icon size to %d, as our cached thumbnail size is %d",
4750 modified_size, cached_thumbnail_size);
4751 }
4752
4753 if (file->details->thumbnail) {
4754 int w, h, s;
4755 double thumb_scale;
4756
4757 raw_pixbuf = g_object_ref (file->details->thumbnail);
4758
4759 w = gdk_pixbuf_get_width (raw_pixbuf);
4760 h = gdk_pixbuf_get_height (raw_pixbuf);
4761
4762 if (flags & NEMO_FILE_ICON_FLAGS_PIN_HEIGHT_FOR_DESKTOP) {
4763 g_assert (max_width > 0);
4764
4765 thumb_scale = (gdouble) modified_size / h;
4766
4767 if (w * thumb_scale > max_width) {
4768 thumb_scale = (gdouble) max_width / w;
4769 }
4770
4771 s = thumb_scale * h;
4772 } else {
4773 s = MAX (w, h);
4774 /* Don't scale up small thumbnails in the standard view */
4775 if (s <= cached_thumbnail_size) {
4776 thumb_scale = (double)size / NEMO_ICON_SIZE_STANDARD;
4777 }
4778 else {
4779 thumb_scale = (double)modified_size / s;
4780 }
4781 /* Make sure that icons don't get smaller than NEMO_ICON_SIZE_SMALLEST */
4782 if (s*thumb_scale <= NEMO_ICON_SIZE_SMALLEST) {
4783 thumb_scale = (double) NEMO_ICON_SIZE_SMALLEST / s;
4784 }
4785 }
4786
4787 scaled_pixbuf = gdk_pixbuf_scale_simple (raw_pixbuf,
4788 MAX (w * thumb_scale, 1),
4789 MAX (h * thumb_scale, 1),
4790 GDK_INTERP_BILINEAR);
4791
4792 /* We don't want frames around small icons */
4793 if (!gdk_pixbuf_get_has_alpha (raw_pixbuf) || s >= 128 * scale) {
4794 nemo_thumbnail_frame_image (&scaled_pixbuf);
4795 }
4796
4797 if (flags & NEMO_FILE_ICON_FLAGS_PIN_HEIGHT_FOR_DESKTOP) {
4798 gint check_height;
4799
4800 check_height = gdk_pixbuf_get_height (scaled_pixbuf);
4801
4802 if (check_height < size) {
4803 nemo_thumbnail_pad_top_and_bottom (&scaled_pixbuf, size - check_height);
4804 }
4805 }
4806
4807 g_object_unref (raw_pixbuf);
4808
4809 /* Don't scale up if more than 25%, then read the original
4810 image instead. We don't want to compare to exactly 100%,
4811 since the zoom level 150% gives thumbnails at 144, which is
4812 ok to scale up from 128. */
4813 if (modified_size > 128 * 1.25 * scale &&
4814 !file->details->thumbnail_wants_original &&
4815 nemo_can_thumbnail_internally (file)) {
4816 /* Invalidate if we resize upward */
4817 file->details->thumbnail_wants_original = TRUE;
4818 nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_THUMBNAIL);
4819 }
4820
4821 DEBUG ("Returning thumbnailed image, at size %d %d",
4822 (int) (w * thumb_scale), (int) (h * thumb_scale));
4823
4824 icon = nemo_icon_info_new_for_pixbuf (scaled_pixbuf, scale);
4825 g_object_unref (scaled_pixbuf);
4826
4827 return icon;
4828 } else if (file->details->thumbnail_path == NULL &&
4829 file->details->can_read &&
4830 !file->details->is_thumbnailing &&
4831 !file->details->thumbnailing_failed) {
4832 if (nemo_can_thumbnail (file)) {
4833 nemo_create_thumbnail (file, get_throttle_count (file), TRUE);
4834 }
4835 }
4836 }
4837
4838 if (file->details->is_thumbnailing &&
4839 flags & NEMO_FILE_ICON_FLAGS_USE_THUMBNAILS)
4840 gicon = g_themed_icon_new (ICON_NAME_THUMBNAIL_LOADING);
4841 else
4842 gicon = nemo_file_get_gicon (file, flags);
4843
4844 if (gicon) {
4845 icon = nemo_icon_info_lookup (gicon, size, scale);
4846 g_object_unref (gicon);
4847 return icon;
4848 } else {
4849 /* This is inefficient, but *very* unlikely to be hit */
4850 GIcon *generic = g_themed_icon_new ("text-x-generic");
4851 icon = nemo_icon_info_lookup (generic, size, scale);
4852 g_object_unref (generic);
4853
4854 return icon;
4855 }
4856 }
4857
4858 GdkPixbuf *
nemo_file_get_icon_pixbuf(NemoFile * file,int size,gboolean force_size,int scale,NemoFileIconFlags flags)4859 nemo_file_get_icon_pixbuf (NemoFile *file,
4860 int size,
4861 gboolean force_size,
4862 int scale,
4863 NemoFileIconFlags flags)
4864 {
4865 NemoIconInfo *info;
4866 GdkPixbuf *pixbuf;
4867
4868 info = nemo_file_get_icon (file, size, 0, scale, flags);
4869 if (force_size) {
4870 pixbuf = nemo_icon_info_get_pixbuf_at_size (info, size);
4871 } else {
4872 pixbuf = nemo_icon_info_get_pixbuf (info);
4873 }
4874 nemo_icon_info_unref (info);
4875
4876 return pixbuf;
4877 }
4878
4879 gboolean
nemo_file_get_date(NemoFile * file,NemoDateType date_type,time_t * date)4880 nemo_file_get_date (NemoFile *file,
4881 NemoDateType date_type,
4882 time_t *date)
4883 {
4884 if (date != NULL) {
4885 *date = 0;
4886 }
4887
4888 g_return_val_if_fail (date_type == NEMO_DATE_TYPE_CHANGED
4889 || date_type == NEMO_DATE_TYPE_ACCESSED
4890 || date_type == NEMO_DATE_TYPE_MODIFIED
4891 || date_type == NEMO_DATE_TYPE_CREATED
4892 || date_type == NEMO_DATE_TYPE_TRASHED
4893 || date_type == NEMO_DATE_TYPE_PERMISSIONS_CHANGED, FALSE);
4894
4895 if (file == NULL) {
4896 return FALSE;
4897 }
4898
4899 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
4900
4901 return NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_date (file, date_type, date);
4902 }
4903
4904 static char *
nemo_file_get_where_string(NemoFile * file)4905 nemo_file_get_where_string (NemoFile *file)
4906 {
4907 if (file == NULL) {
4908 return NULL;
4909 }
4910
4911 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
4912
4913 return NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_where_string (file);
4914 }
4915
4916 static char *
nemo_file_get_trash_original_file_parent_as_string(NemoFile * file)4917 nemo_file_get_trash_original_file_parent_as_string (NemoFile *file)
4918 {
4919 NemoFile *orig_file, *parent;
4920 GFile *location;
4921 char *filename;
4922
4923 if (file->details->trash_orig_path != NULL) {
4924 orig_file = nemo_file_get_trash_original_file (file);
4925 parent = nemo_file_get_parent (orig_file);
4926 location = nemo_file_get_location (parent);
4927
4928 filename = g_file_get_parse_name (location);
4929
4930 g_object_unref (location);
4931 nemo_file_unref (parent);
4932 nemo_file_unref (orig_file);
4933
4934 return filename;
4935 }
4936
4937 return NULL;
4938 }
4939
4940 static const gchar *
nemo_date_type_to_string(NemoDateType type)4941 nemo_date_type_to_string (NemoDateType type)
4942 {
4943 switch (type) {
4944 case NEMO_DATE_TYPE_MODIFIED:
4945 return "NEMO_DATE_TYPE_MODIFIED";
4946 case NEMO_DATE_TYPE_CHANGED:
4947 return "NEMO_DATE_TYPE_CHANGED";
4948 case NEMO_DATE_TYPE_ACCESSED:
4949 return "NEMO_DATE_TYPE_ACCESSED";
4950 case NEMO_DATE_TYPE_PERMISSIONS_CHANGED:
4951 return "NEMO_DATE_TYPE_PERMISSIONS_CHANGED";
4952 case NEMO_DATE_TYPE_TRASHED:
4953 return "NEMO_DATE_TYPE_TRASHED";
4954 case NEMO_DATE_TYPE_CREATED:
4955 return "NEMO_DATE_TYPE_CREATED";
4956 }
4957
4958 return "(unknown)";
4959 }
4960
4961 /**
4962 * nemo_file_get_date_as_string:
4963 *
4964 * Get a user-displayable string representing a file modification date.
4965 * The caller is responsible for g_free-ing this string.
4966 * @file: NemoFile representing the file in question.
4967 *
4968 * Returns: Newly allocated string ready to display to the user.
4969 *
4970 **/
4971 static char *
nemo_file_get_date_as_string(NemoFile * file,NemoDateType date_type,NemoDateCompactFormat date_format)4972 nemo_file_get_date_as_string (NemoFile *file,
4973 NemoDateType date_type,
4974 NemoDateCompactFormat date_format)
4975 {
4976 time_t file_time_raw;
4977 GDateTime *file_date_time, *file_date_time_utc;
4978 GDateTime *today_midnight, *now;
4979 GTimeZone *current_timezone;
4980 gint days_ago;
4981 gboolean use_24;
4982 const gchar *format;
4983 gchar *result;
4984 int date_format_pref;
4985
4986 if (!nemo_file_get_date (file, date_type, &file_time_raw))
4987 return NULL;
4988
4989 current_timezone = prefs_current_timezone;
4990
4991 file_date_time_utc = g_date_time_new_from_unix_utc (file_time_raw);
4992
4993 if (!file_date_time_utc) {
4994 DEBUG ("File '%s' has invalid time for %s",
4995 nemo_file_peek_name (file),
4996 nemo_date_type_to_string (date_type));
4997 return NULL;
4998 }
4999
5000 file_date_time = g_date_time_to_timezone (file_date_time_utc, current_timezone);
5001 g_date_time_unref (file_date_time_utc);
5002
5003 date_format_pref = prefs_current_date_format;
5004
5005 if (date_format_pref == NEMO_DATE_FORMAT_LOCALE) {
5006 result = g_date_time_format (file_date_time, "%c");
5007 goto out;
5008 } else if (date_format_pref == NEMO_DATE_FORMAT_ISO) {
5009 result = g_date_time_format (file_date_time, "%Y-%m-%d %H:%M:%S");
5010 goto out;
5011 }
5012
5013 if (date_format != NEMO_DATE_FORMAT_FULL) {
5014 GDateTime *file_date;
5015
5016 now = g_date_time_new_now (current_timezone);
5017
5018 today_midnight = g_date_time_new (current_timezone,
5019 g_date_time_get_year (now),
5020 g_date_time_get_month (now),
5021 g_date_time_get_day_of_month (now),
5022 0, 0, 0);
5023
5024 file_date = g_date_time_new (current_timezone,
5025 g_date_time_get_year (file_date_time),
5026 g_date_time_get_month (file_date_time),
5027 g_date_time_get_day_of_month (file_date_time),
5028 0, 0, 0);
5029
5030 days_ago = g_date_time_difference (today_midnight, file_date) / G_TIME_SPAN_DAY;
5031
5032 use_24 = prefs_current_24h_time_format;
5033
5034 // Show only the time if date is on today
5035 if (days_ago < 1) {
5036 if (use_24) {
5037 /* Translators: Time in 24h format */
5038 format = _("%H:%M");
5039 } else {
5040 /* Translators: Time in 12h format */
5041 format = _("%l:%M %p");
5042 }
5043 }
5044 // Show the word "Yesterday" and time if date is on yesterday
5045 else if (days_ago < 2) {
5046 if (date_format == NEMO_DATE_FORMAT_REGULAR) {
5047 // xgettext:no-c-format
5048 format = _("Yesterday");
5049 } else {
5050 if (use_24) {
5051 /* Translators: this is the word Yesterday followed by
5052 * a time in 24h format. i.e. "Yesterday 23:04" */
5053 // xgettext:no-c-format
5054 format = _("Yesterday %H:%M");
5055 } else {
5056 /* Translators: this is the word Yesterday followed by
5057 * a time in 12h format. i.e. "Yesterday 9:04 PM" */
5058 // xgettext:no-c-format
5059 format = _("Yesterday %l:%M %p");
5060 }
5061 }
5062 }
5063 // Show a week day and time if date is in the last week
5064 else if (days_ago < 7) {
5065 if (date_format == NEMO_DATE_FORMAT_REGULAR) {
5066 // xgettext:no-c-format
5067 format = _("%A");
5068 } else {
5069 if (use_24) {
5070 /* Translators: this is the name of the week day followed by
5071 * a time in 24h format. i.e. "Monday 23:04" */
5072 // xgettext:no-c-format
5073 format = _("%A %H:%M");
5074 } else {
5075 /* Translators: this is the week day name followed by
5076 * a time in 12h format. i.e. "Monday 9:04 PM" */
5077 // xgettext:no-c-format
5078 format = _("%A %l:%M %p");
5079 }
5080 }
5081 } else if (g_date_time_get_year (file_date) == g_date_time_get_year (now)) {
5082 if (date_format == NEMO_DATE_FORMAT_REGULAR) {
5083 /* Translators: this is the day of the month followed
5084 * by the abbreviated month name i.e. "3 February" */
5085 // xgettext:no-c-format
5086 format = _("%-e %B");
5087 } else {
5088 if (use_24) {
5089 /* Translators: this is the day of the month followed
5090 * by the abbreviated month name followed by a time in
5091 * 24h format i.e. "3 February 23:04" */
5092 // xgettext:no-c-format
5093 format = _("%-e %B %H:%M");
5094 } else {
5095 /* Translators: this is the day of the month followed
5096 * by the abbreviated month name followed by a time in
5097 * 12h format i.e. "3 February 9:04" */
5098 // xgettext:no-c-format
5099 format = _("%-e %B %l:%M %p");
5100 }
5101 }
5102 } else {
5103 if (date_format == NEMO_DATE_FORMAT_REGULAR) {
5104 /* Translators: this is the day of the month followed by the abbreviated
5105 * month name followed by the year i.e. "3 Feb 2015" */
5106 // xgettext:no-c-format
5107 format = _("%-e %b %Y");
5108 } else {
5109 if (use_24) {
5110 /* Translators: this is the day number followed
5111 * by the abbreviated month name followed by the year followed
5112 * by a time in 24h format i.e. "3 Feb 2015 23:04" */
5113 // xgettext:no-c-format
5114 format = _("%-e %b %Y %H:%M");
5115 } else {
5116 /* Translators: this is the day number followed
5117 * by the abbreviated month name followed by the year followed
5118 * by a time in 12h format i.e. "3 Feb 2015 9:04 PM" */
5119 // xgettext:no-c-format
5120 format = _("%-e %b %Y %l:%M %p");
5121 }
5122 }
5123 }
5124
5125 g_date_time_unref (file_date);
5126 g_date_time_unref (now);
5127 g_date_time_unref (today_midnight);
5128 } else {
5129 // xgettext:no-c-format
5130 format = _("%c");
5131 }
5132
5133 result = g_date_time_format (file_date_time, format);
5134
5135 out:
5136 g_date_time_unref (file_date_time);
5137
5138 return result;
5139 }
5140
5141 static NemoSpeedTradeoffValue show_directory_item_count;
5142
5143 static void
show_directory_item_count_changed_callback(gpointer callback_data)5144 show_directory_item_count_changed_callback (gpointer callback_data)
5145 {
5146 show_directory_item_count = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS);
5147 }
5148
5149 static gboolean
get_speed_tradeoff_preference_for_file(NemoFile * file,NemoSpeedTradeoffValue value)5150 get_speed_tradeoff_preference_for_file (NemoFile *file, NemoSpeedTradeoffValue value)
5151 {
5152 GFilesystemPreviewType use_preview;
5153
5154 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
5155
5156 use_preview = nemo_file_get_filesystem_use_preview (file);
5157
5158 if (value == NEMO_SPEED_TRADEOFF_ALWAYS) {
5159 if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
5160 return FALSE;
5161 } else {
5162 return TRUE;
5163 }
5164 }
5165
5166 if (value == NEMO_SPEED_TRADEOFF_NEVER) {
5167 return FALSE;
5168 }
5169
5170 g_assert (value == NEMO_SPEED_TRADEOFF_LOCAL_ONLY);
5171
5172 if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
5173 /* file system says to never preview anything */
5174 return FALSE;
5175 } else if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL) {
5176 /* file system says we should treat file as if it's local */
5177 return TRUE;
5178 } else {
5179 /* only local files */
5180 return nemo_file_is_local (file);
5181 }
5182 }
5183
5184 gboolean
nemo_file_should_show_directory_item_count(NemoFile * file)5185 nemo_file_should_show_directory_item_count (NemoFile *file)
5186 {
5187 static gboolean show_directory_item_count_callback_added = FALSE;
5188
5189 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
5190
5191 if (file->details->mime_type &&
5192 strcmp (eel_ref_str_peek (file->details->mime_type), "x-directory/smb-share") == 0) {
5193 return FALSE;
5194 }
5195
5196 /* Add the callback once for the life of our process */
5197 if (!show_directory_item_count_callback_added) {
5198 g_signal_connect_swapped (nemo_preferences,
5199 "changed::" NEMO_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS,
5200 G_CALLBACK(show_directory_item_count_changed_callback),
5201 NULL);
5202 show_directory_item_count_callback_added = TRUE;
5203
5204 /* Peek for the first time */
5205 show_directory_item_count_changed_callback (NULL);
5206 }
5207
5208 return get_speed_tradeoff_preference_for_file (file, show_directory_item_count);
5209 }
5210
5211 gboolean
nemo_file_should_show_type(NemoFile * file)5212 nemo_file_should_show_type (NemoFile *file)
5213 {
5214 char *uri;
5215 gboolean ret;
5216
5217 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
5218
5219 uri = nemo_file_get_uri (file);
5220 ret = ((strcmp (uri, "computer:///") != 0) &&
5221 (strcmp (uri, "network:///") != 0) &&
5222 (strcmp (uri, "smb:///") != 0));
5223 g_free (uri);
5224
5225 return ret;
5226 }
5227
5228 /**
5229 * nemo_file_get_directory_item_count
5230 *
5231 * Get the number of items in a directory.
5232 * @file: NemoFile representing a directory.
5233 * @count: Place to put count.
5234 * @count_unreadable: Set to TRUE (if non-NULL) if permissions prevent
5235 * the item count from being read on this directory. Otherwise set to FALSE.
5236 *
5237 * Returns: TRUE if count is available.
5238 *
5239 **/
5240 gboolean
nemo_file_get_directory_item_count(NemoFile * file,guint * count,gboolean * count_unreadable)5241 nemo_file_get_directory_item_count (NemoFile *file,
5242 guint *count,
5243 gboolean *count_unreadable)
5244 {
5245 if (count != NULL) {
5246 *count = 0;
5247 }
5248 if (count_unreadable != NULL) {
5249 *count_unreadable = FALSE;
5250 }
5251
5252 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
5253
5254 if (!nemo_file_is_directory (file)) {
5255 return FALSE;
5256 }
5257
5258 if (!nemo_file_should_show_directory_item_count (file)) {
5259 return FALSE;
5260 }
5261
5262 return NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_item_count
5263 (file, count, count_unreadable);
5264 }
5265
5266 /**
5267 * nemo_file_get_deep_counts
5268 *
5269 * Get the statistics about items inside a directory.
5270 * @file: NemoFile representing a directory or file.
5271 * @directory_count: Place to put count of directories inside.
5272 * @files_count: Place to put count of files inside.
5273 * @unreadable_directory_count: Number of directories encountered
5274 * that were unreadable.
5275 * @total_size: Total size of all files and directories visited.
5276 * @force: Whether the deep counts should even be collected if
5277 * nemo_file_should_show_directory_item_count returns FALSE
5278 * for this file.
5279 *
5280 * Returns: Status to indicate whether sizes are available.
5281 *
5282 **/
5283 NemoRequestStatus
nemo_file_get_deep_counts(NemoFile * file,guint * directory_count,guint * file_count,guint * unreadable_directory_count,guint * hidden_count,goffset * total_size,gboolean force)5284 nemo_file_get_deep_counts (NemoFile *file,
5285 guint *directory_count,
5286 guint *file_count,
5287 guint *unreadable_directory_count,
5288 guint *hidden_count,
5289 goffset *total_size,
5290 gboolean force)
5291 {
5292 if (directory_count != NULL) {
5293 *directory_count = 0;
5294 }
5295 if (file_count != NULL) {
5296 *file_count = 0;
5297 }
5298 if (unreadable_directory_count != NULL) {
5299 *unreadable_directory_count = 0;
5300 }
5301 if (total_size != NULL) {
5302 *total_size = 0;
5303 }
5304
5305 if (hidden_count != NULL) {
5306 *hidden_count = 0;
5307 }
5308
5309 g_return_val_if_fail (NEMO_IS_FILE (file), NEMO_REQUEST_DONE);
5310
5311 if (!force && !nemo_file_should_show_directory_item_count (file)) {
5312 /* Set field so an existing value isn't treated as up-to-date
5313 * when preference changes later.
5314 */
5315 file->details->deep_counts_status = NEMO_REQUEST_NOT_STARTED;
5316 return file->details->deep_counts_status;
5317 }
5318
5319 return NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_deep_counts
5320 (file, directory_count, file_count,
5321 unreadable_directory_count, hidden_count, total_size);
5322 }
5323
5324 void
nemo_file_recompute_deep_counts(NemoFile * file)5325 nemo_file_recompute_deep_counts (NemoFile *file)
5326 {
5327 if (file->details->deep_counts_status != NEMO_REQUEST_IN_PROGRESS) {
5328 file->details->deep_counts_status = NEMO_REQUEST_NOT_STARTED;
5329 if (file->details->directory != NULL) {
5330 nemo_directory_add_file_to_work_queue (file->details->directory, file);
5331 nemo_directory_async_state_changed (file->details->directory);
5332 }
5333 }
5334 }
5335
5336
5337 /**
5338 * nemo_file_get_directory_item_mime_types
5339 *
5340 * Get the list of mime-types present in a directory.
5341 * @file: NemoFile representing a directory. It is an error to
5342 * call this function on a file that is not a directory.
5343 * @mime_list: Place to put the list of mime-types.
5344 *
5345 * Returns: TRUE if mime-type list is available.
5346 *
5347 **/
5348 gboolean
nemo_file_get_directory_item_mime_types(NemoFile * file,GList ** mime_list)5349 nemo_file_get_directory_item_mime_types (NemoFile *file,
5350 GList **mime_list)
5351 {
5352 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
5353 g_return_val_if_fail (mime_list != NULL, FALSE);
5354
5355 if (!nemo_file_is_directory (file)
5356 || !file->details->got_mime_list) {
5357 *mime_list = NULL;
5358 return FALSE;
5359 }
5360
5361 *mime_list = eel_g_str_list_copy (file->details->mime_list);
5362 return TRUE;
5363 }
5364
5365 gboolean
nemo_file_can_get_size(NemoFile * file)5366 nemo_file_can_get_size (NemoFile *file)
5367 {
5368 return file->details->size == -1;
5369 }
5370
5371
5372 /**
5373 * nemo_file_get_size
5374 *
5375 * Get the file size.
5376 * @file: NemoFile representing the file in question.
5377 *
5378 * Returns: Size in bytes.
5379 *
5380 **/
5381 goffset
nemo_file_get_size(NemoFile * file)5382 nemo_file_get_size (NemoFile *file)
5383 {
5384 /* Before we have info on the file, we don't know the size. */
5385 if (file->details->size == -1)
5386 return 0;
5387 return file->details->size;
5388 }
5389
5390 time_t
nemo_file_get_mtime(NemoFile * file)5391 nemo_file_get_mtime (NemoFile *file)
5392 {
5393 return file->details->mtime;
5394 }
5395
5396 time_t
nemo_file_get_ctime(NemoFile * file)5397 nemo_file_get_ctime (NemoFile *file)
5398 {
5399 return file->details->ctime;
5400 }
5401
5402
5403 static void
set_attributes_get_info_callback(GObject * source_object,GAsyncResult * res,gpointer callback_data)5404 set_attributes_get_info_callback (GObject *source_object,
5405 GAsyncResult *res,
5406 gpointer callback_data)
5407 {
5408 NemoFileOperation *op;
5409 GFileInfo *new_info;
5410 GError *error;
5411
5412 op = callback_data;
5413
5414 error = NULL;
5415 new_info = g_file_query_info_finish (G_FILE (source_object), res, &error);
5416 if (new_info != NULL) {
5417 if (nemo_file_update_info (op->file, new_info)) {
5418 nemo_file_changed (op->file);
5419 }
5420 g_object_unref (new_info);
5421 }
5422 nemo_file_operation_complete (op, NULL, error);
5423 if (error) {
5424 g_error_free (error);
5425 }
5426 }
5427
5428
5429 static void
set_attributes_callback(GObject * source_object,GAsyncResult * result,gpointer callback_data)5430 set_attributes_callback (GObject *source_object,
5431 GAsyncResult *result,
5432 gpointer callback_data)
5433 {
5434 NemoFileOperation *op;
5435 GError *error;
5436 gboolean res;
5437
5438 op = callback_data;
5439
5440 error = NULL;
5441 res = g_file_set_attributes_finish (G_FILE (source_object),
5442 result,
5443 NULL,
5444 &error);
5445
5446 if (res) {
5447 g_file_query_info_async (G_FILE (source_object),
5448 NEMO_FILE_DEFAULT_ATTRIBUTES,
5449 0,
5450 G_PRIORITY_DEFAULT,
5451 op->cancellable,
5452 set_attributes_get_info_callback, op);
5453 } else {
5454 nemo_file_operation_complete (op, NULL, error);
5455 g_error_free (error);
5456 }
5457 }
5458
5459 void
nemo_file_set_attributes(NemoFile * file,GFileInfo * attributes,NemoFileOperationCallback callback,gpointer callback_data)5460 nemo_file_set_attributes (NemoFile *file,
5461 GFileInfo *attributes,
5462 NemoFileOperationCallback callback,
5463 gpointer callback_data)
5464 {
5465 NemoFileOperation *op;
5466 GFile *location;
5467
5468 op = nemo_file_operation_new (file, callback, callback_data);
5469
5470 location = nemo_file_get_location (file);
5471 g_file_set_attributes_async (location,
5472 attributes,
5473 0,
5474 G_PRIORITY_DEFAULT,
5475 op->cancellable,
5476 set_attributes_callback,
5477 op);
5478 g_object_unref (location);
5479 }
5480
5481
5482 /**
5483 * nemo_file_can_get_permissions:
5484 *
5485 * Check whether the permissions for a file are determinable.
5486 * This might not be the case for files on non-UNIX file systems.
5487 *
5488 * @file: The file in question.
5489 *
5490 * Return value: TRUE if the permissions are valid.
5491 */
5492 gboolean
nemo_file_can_get_permissions(NemoFile * file)5493 nemo_file_can_get_permissions (NemoFile *file)
5494 {
5495 return file->details->has_permissions;
5496 }
5497
5498 /**
5499 * nemo_file_can_set_permissions:
5500 *
5501 * Check whether the current user is allowed to change
5502 * the permissions of a file.
5503 *
5504 * @file: The file in question.
5505 *
5506 * Return value: TRUE if the current user can change the
5507 * permissions of @file, FALSE otherwise. It's always possible
5508 * that when you actually try to do it, you will fail.
5509 */
5510 gboolean
nemo_file_can_set_permissions(NemoFile * file)5511 nemo_file_can_set_permissions (NemoFile *file)
5512 {
5513 uid_t user_id;
5514
5515 if (file == NULL)
5516 {
5517 return FALSE;
5518 }
5519
5520 if (file->details->uid != -1 &&
5521 nemo_file_is_local (file)) {
5522 /* Check the user. */
5523 user_id = geteuid();
5524
5525 /* Owner is allowed to set permissions. */
5526 if (user_id == (uid_t) file->details->uid) {
5527 return TRUE;
5528 }
5529
5530 /* Root is also allowed to set permissions. */
5531 if (user_id == 0) {
5532 return TRUE;
5533 }
5534
5535 /* Nobody else is allowed. */
5536 return FALSE;
5537 }
5538
5539 /* pretend to have full chmod rights when no info is available, relevant when
5540 * the FS can't provide ownership info, for instance for FTP */
5541 return TRUE;
5542 }
5543
5544 guint
nemo_file_get_permissions(NemoFile * file)5545 nemo_file_get_permissions (NemoFile *file)
5546 {
5547 g_return_val_if_fail (nemo_file_can_get_permissions (file), 0);
5548
5549 return file->details->permissions;
5550 }
5551
5552 /**
5553 * nemo_file_set_permissions:
5554 *
5555 * Change a file's permissions. This should only be called if
5556 * nemo_file_can_set_permissions returned TRUE.
5557 *
5558 * @file: NemoFile representing the file in question.
5559 * @new_permissions: New permissions value. This is the whole
5560 * set of permissions, not a delta.
5561 **/
5562 void
nemo_file_set_permissions(NemoFile * file,guint32 new_permissions,NemoFileOperationCallback callback,gpointer callback_data)5563 nemo_file_set_permissions (NemoFile *file,
5564 guint32 new_permissions,
5565 NemoFileOperationCallback callback,
5566 gpointer callback_data)
5567 {
5568 GFileInfo *info;
5569 GError *error;
5570
5571 if (!nemo_file_can_set_permissions (file)) {
5572 /* Claim that something changed even if the permission change failed.
5573 * This makes it easier for some clients who see the "reverting"
5574 * to the old permissions as "changing back".
5575 */
5576 nemo_file_changed (file);
5577 error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
5578 _("Not allowed to set permissions"));
5579 (* callback) (file, NULL, error, callback_data);
5580 g_error_free (error);
5581 return;
5582 }
5583
5584 /* Test the permissions-haven't-changed case explicitly
5585 * because we don't want to send the file-changed signal if
5586 * nothing changed.
5587 */
5588 if (new_permissions == file->details->permissions) {
5589 (* callback) (file, NULL, NULL, callback_data);
5590 return;
5591 }
5592
5593 if (!nemo_file_undo_manager_pop_flag ()) {
5594 NemoFileUndoInfo *undo_info;
5595
5596 undo_info = nemo_file_undo_info_permissions_new (nemo_file_get_location (file),
5597 file->details->permissions,
5598 new_permissions);
5599 nemo_file_undo_manager_set_action (undo_info);
5600 }
5601
5602 info = g_file_info_new ();
5603 g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE, new_permissions);
5604 nemo_file_set_attributes (file, info, callback, callback_data);
5605
5606 g_object_unref (info);
5607 }
5608
5609 /**
5610 * nemo_file_can_get_selinux_context:
5611 *
5612 * Check whether the selinux context for a file are determinable.
5613 * This might not be the case for files on non-UNIX file systems,
5614 * files without a context or systems that don't support selinux.
5615 *
5616 * @file: The file in question.
5617 *
5618 * Return value: TRUE if the permissions are valid.
5619 */
5620 gboolean
nemo_file_can_get_selinux_context(NemoFile * file)5621 nemo_file_can_get_selinux_context (NemoFile *file)
5622 {
5623 return file->details->selinux_context != NULL;
5624 }
5625
5626
5627 /**
5628 * nemo_file_get_selinux_context:
5629 *
5630 * Get a user-displayable string representing a file's selinux
5631 * context
5632 * @file: NemoFile representing the file in question.
5633 *
5634 * Returns: Newly allocated string ready to display to the user.
5635 *
5636 **/
5637 char *
nemo_file_get_selinux_context(NemoFile * file)5638 nemo_file_get_selinux_context (NemoFile *file)
5639 {
5640 char *translated;
5641 char *raw;
5642
5643 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
5644
5645 if (!nemo_file_can_get_selinux_context (file)) {
5646 return NULL;
5647 }
5648
5649 raw = file->details->selinux_context;
5650
5651 #ifdef HAVE_SELINUX
5652 if (selinux_raw_to_trans_context (raw, &translated) == 0) {
5653 char *tmp;
5654 tmp = g_strdup (translated);
5655 freecon (translated);
5656 translated = tmp;
5657 }
5658 else
5659 #endif
5660 {
5661 translated = g_strdup (raw);
5662 }
5663
5664 return translated;
5665 }
5666
5667 static char *
get_real_name(const char * name,const char * gecos)5668 get_real_name (const char *name, const char *gecos)
5669 {
5670 char *locale_string, *part_before_comma, *capitalized_login_name, *real_name;
5671
5672 if (gecos == NULL) {
5673 return NULL;
5674 }
5675
5676 locale_string = eel_str_strip_substring_and_after (gecos, ",");
5677 if (!g_utf8_validate (locale_string, -1, NULL)) {
5678 part_before_comma = g_locale_to_utf8 (locale_string, -1, NULL, NULL, NULL);
5679 g_free (locale_string);
5680 } else {
5681 part_before_comma = locale_string;
5682 }
5683
5684 if (!g_utf8_validate (name, -1, NULL)) {
5685 locale_string = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
5686 } else {
5687 locale_string = g_strdup (name);
5688 }
5689
5690 capitalized_login_name = eel_str_capitalize (locale_string);
5691 g_free (locale_string);
5692
5693 if (capitalized_login_name == NULL) {
5694 real_name = part_before_comma;
5695 } else {
5696 real_name = eel_str_replace_substring
5697 (part_before_comma, "&", capitalized_login_name);
5698 g_free (part_before_comma);
5699 }
5700
5701
5702 if (g_strcmp0 (real_name, NULL) == 0
5703 || g_strcmp0 (name, real_name) == 0
5704 || g_strcmp0 (capitalized_login_name, real_name) == 0) {
5705 g_free (real_name);
5706 real_name = NULL;
5707 }
5708
5709 g_free (capitalized_login_name);
5710
5711 return real_name;
5712 }
5713
5714 static gboolean
get_group_id_from_group_name(const char * group_name,uid_t * gid)5715 get_group_id_from_group_name (const char *group_name, uid_t *gid)
5716 {
5717 struct group *group;
5718
5719 g_assert (gid != NULL);
5720
5721 group = getgrnam (group_name);
5722
5723 if (group == NULL) {
5724 return FALSE;
5725 }
5726
5727 *gid = group->gr_gid;
5728
5729 return TRUE;
5730 }
5731
5732 static gboolean
get_ids_from_user_name(const char * user_name,uid_t * uid,uid_t * gid)5733 get_ids_from_user_name (const char *user_name, uid_t *uid, uid_t *gid)
5734 {
5735 struct passwd *password_info;
5736
5737 g_assert (uid != NULL || gid != NULL);
5738
5739 password_info = getpwnam (user_name);
5740
5741 if (password_info == NULL) {
5742 return FALSE;
5743 }
5744
5745 if (uid != NULL) {
5746 *uid = password_info->pw_uid;
5747 }
5748
5749 if (gid != NULL) {
5750 *gid = password_info->pw_gid;
5751 }
5752
5753 return TRUE;
5754 }
5755
5756 static gboolean
get_user_id_from_user_name(const char * user_name,uid_t * id)5757 get_user_id_from_user_name (const char *user_name, uid_t *id)
5758 {
5759 return get_ids_from_user_name (user_name, id, NULL);
5760 }
5761
5762 static gboolean
get_id_from_digit_string(const char * digit_string,uid_t * id)5763 get_id_from_digit_string (const char *digit_string, uid_t *id)
5764 {
5765 long scanned_id;
5766 char c;
5767
5768 g_assert (id != NULL);
5769
5770 /* Only accept string if it has one integer with nothing
5771 * afterwards.
5772 */
5773 if (sscanf (digit_string, "%ld%c", &scanned_id, &c) != 1) {
5774 return FALSE;
5775 }
5776 *id = scanned_id;
5777 return TRUE;
5778 }
5779
5780 /**
5781 * nemo_file_can_get_owner:
5782 *
5783 * Check whether the owner a file is determinable.
5784 * This might not be the case for files on non-UNIX file systems.
5785 *
5786 * @file: The file in question.
5787 *
5788 * Return value: TRUE if the owner is valid.
5789 */
5790 gboolean
nemo_file_can_get_owner(NemoFile * file)5791 nemo_file_can_get_owner (NemoFile *file)
5792 {
5793 /* Before we have info on a file, the owner is unknown. */
5794 return file->details->uid != -1;
5795 }
5796
5797 /**
5798 * nemo_file_get_owner_name:
5799 *
5800 * Get the user name of the file's owner. If the owner has no
5801 * name, returns the userid as a string. The caller is responsible
5802 * for g_free-ing this string.
5803 *
5804 * @file: The file in question.
5805 *
5806 * Return value: A newly-allocated string.
5807 */
5808 char *
nemo_file_get_owner_name(NemoFile * file)5809 nemo_file_get_owner_name (NemoFile *file)
5810 {
5811 return nemo_file_get_owner_as_string (file, FALSE);
5812 }
5813
5814 /**
5815 * nemo_file_can_set_owner:
5816 *
5817 * Check whether the current user is allowed to change
5818 * the owner of a file.
5819 *
5820 * @file: The file in question.
5821 *
5822 * Return value: TRUE if the current user can change the
5823 * owner of @file, FALSE otherwise. It's always possible
5824 * that when you actually try to do it, you will fail.
5825 */
5826 gboolean
nemo_file_can_set_owner(NemoFile * file)5827 nemo_file_can_set_owner (NemoFile *file)
5828 {
5829 /* Not allowed to set the owner if we can't
5830 * even read it. This can happen on non-UNIX file
5831 * systems.
5832 */
5833 if (!nemo_file_can_get_owner (file)) {
5834 return FALSE;
5835 }
5836
5837 /* Only root is also allowed to set the owner. */
5838 return geteuid() == 0;
5839 }
5840
5841 /**
5842 * nemo_file_set_owner:
5843 *
5844 * Set the owner of a file. This will only have any effect if
5845 * nemo_file_can_set_owner returns TRUE.
5846 *
5847 * @file: The file in question.
5848 * @user_name_or_id: The user name to set the owner to.
5849 * If the string does not match any user name, and the
5850 * string is an integer, the owner will be set to the
5851 * userid represented by that integer.
5852 * @callback: Function called when asynch owner change succeeds or fails.
5853 * @callback_data: Parameter passed back with callback function.
5854 */
5855 void
nemo_file_set_owner(NemoFile * file,const char * user_name_or_id,NemoFileOperationCallback callback,gpointer callback_data)5856 nemo_file_set_owner (NemoFile *file,
5857 const char *user_name_or_id,
5858 NemoFileOperationCallback callback,
5859 gpointer callback_data)
5860 {
5861 GError *error;
5862 GFileInfo *info;
5863 uid_t new_id;
5864
5865 if (!nemo_file_can_set_owner (file)) {
5866 /* Claim that something changed even if the permission
5867 * change failed. This makes it easier for some
5868 * clients who see the "reverting" to the old owner as
5869 * "changing back".
5870 */
5871 nemo_file_changed (file);
5872 error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
5873 _("Not allowed to set owner"));
5874 (* callback) (file, NULL, error, callback_data);
5875 g_error_free (error);
5876 return;
5877 }
5878
5879 /* If no match treating user_name_or_id as name, try treating
5880 * it as id.
5881 */
5882 if (!get_user_id_from_user_name (user_name_or_id, &new_id)
5883 && !get_id_from_digit_string (user_name_or_id, &new_id)) {
5884 /* Claim that something changed even if the permission
5885 * change failed. This makes it easier for some
5886 * clients who see the "reverting" to the old owner as
5887 * "changing back".
5888 */
5889 nemo_file_changed (file);
5890 error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
5891 _("Specified owner '%s' doesn't exist"), user_name_or_id);
5892 (* callback) (file, NULL, error, callback_data);
5893 g_error_free (error);
5894 return;
5895 }
5896
5897 /* Test the owner-hasn't-changed case explicitly because we
5898 * don't want to send the file-changed signal if nothing
5899 * changed.
5900 */
5901 if (new_id == (uid_t) file->details->uid) {
5902 (* callback) (file, NULL, NULL, callback_data);
5903 return;
5904 }
5905
5906 if (!nemo_file_undo_manager_pop_flag ()) {
5907 NemoFileUndoInfo *undo_info;
5908 char* current_owner;
5909
5910 current_owner = nemo_file_get_owner_as_string (file, FALSE);
5911
5912 undo_info = nemo_file_undo_info_ownership_new (NEMO_FILE_UNDO_OP_CHANGE_OWNER,
5913 nemo_file_get_location (file),
5914 current_owner,
5915 user_name_or_id);
5916 nemo_file_undo_manager_set_action (undo_info);
5917
5918 g_free (current_owner);
5919 }
5920
5921 info = g_file_info_new ();
5922 g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID, new_id);
5923 nemo_file_set_attributes (file, info, callback, callback_data);
5924 g_object_unref (info);
5925 }
5926
5927 /**
5928 * nemo_get_user_names:
5929 *
5930 * Get a list of user names. For users with a different associated
5931 * "real name", the real name follows the standard user name, separated
5932 * by a carriage return. The caller is responsible for freeing this list
5933 * and its contents.
5934 */
5935 GList *
nemo_get_user_names(void)5936 nemo_get_user_names (void)
5937 {
5938 GList *list;
5939 char *real_name, *name;
5940 struct passwd *user;
5941
5942 list = NULL;
5943
5944 setpwent ();
5945
5946 while ((user = getpwent ()) != NULL) {
5947 real_name = get_real_name (user->pw_name, user->pw_gecos);
5948 if (real_name != NULL) {
5949 name = g_strconcat (user->pw_name, "\n", real_name, NULL);
5950 } else {
5951 name = g_strdup (user->pw_name);
5952 }
5953 g_free (real_name);
5954 list = g_list_prepend (list, name);
5955 }
5956
5957 endpwent ();
5958
5959 return g_list_sort (list, (GCompareFunc) g_utf8_collate);
5960 }
5961
5962 /**
5963 * nemo_file_can_get_group:
5964 *
5965 * Check whether the group a file is determinable.
5966 * This might not be the case for files on non-UNIX file systems.
5967 *
5968 * @file: The file in question.
5969 *
5970 * Return value: TRUE if the group is valid.
5971 */
5972 gboolean
nemo_file_can_get_group(NemoFile * file)5973 nemo_file_can_get_group (NemoFile *file)
5974 {
5975 /* Before we have info on a file, the group is unknown. */
5976 return file->details->gid != -1;
5977 }
5978
5979 /**
5980 * nemo_file_get_group_name:
5981 *
5982 * Get the name of the file's group. If the group has no
5983 * name, returns the groupid as a string. The caller is responsible
5984 * for g_free-ing this string.
5985 *
5986 * @file: The file in question.
5987 *
5988 * Return value: A newly-allocated string.
5989 **/
5990 char *
nemo_file_get_group_name(NemoFile * file)5991 nemo_file_get_group_name (NemoFile *file)
5992 {
5993 return g_strdup (eel_ref_str_peek (file->details->group));
5994 }
5995
5996 /**
5997 * nemo_file_can_set_group:
5998 *
5999 * Check whether the current user is allowed to change
6000 * the group of a file.
6001 *
6002 * @file: The file in question.
6003 *
6004 * Return value: TRUE if the current user can change the
6005 * group of @file, FALSE otherwise. It's always possible
6006 * that when you actually try to do it, you will fail.
6007 */
6008 gboolean
nemo_file_can_set_group(NemoFile * file)6009 nemo_file_can_set_group (NemoFile *file)
6010 {
6011 uid_t user_id;
6012
6013 /* Not allowed to set the permissions if we can't
6014 * even read them. This can happen on non-UNIX file
6015 * systems.
6016 */
6017 if (!nemo_file_can_get_group (file)) {
6018 return FALSE;
6019 }
6020
6021 /* Check the user. */
6022 user_id = geteuid();
6023
6024 /* Owner is allowed to set group (with restrictions). */
6025 if (user_id == (uid_t) file->details->uid) {
6026 return TRUE;
6027 }
6028
6029 /* Root is also allowed to set group. */
6030 if (user_id == 0) {
6031 return TRUE;
6032 }
6033
6034 /* Nobody else is allowed. */
6035 return FALSE;
6036 }
6037
6038 /* Get a list of group names, filtered to only the ones
6039 * that contain the given username. If the username is
6040 * NULL, returns a list of all group names.
6041 */
6042 static GList *
nemo_get_group_names_for_user(void)6043 nemo_get_group_names_for_user (void)
6044 {
6045 GList *list;
6046 struct group *group;
6047 int count, i;
6048 gid_t gid_list[NGROUPS_MAX + 1];
6049
6050
6051 list = NULL;
6052
6053 count = getgroups (NGROUPS_MAX + 1, gid_list);
6054 for (i = 0; i < count; i++) {
6055 group = getgrgid (gid_list[i]);
6056 if (group == NULL)
6057 break;
6058
6059 list = g_list_prepend (list, g_strdup (group->gr_name));
6060 }
6061
6062 return g_list_sort (list, (GCompareFunc) g_utf8_collate);
6063 }
6064
6065 /**
6066 * nemo_get_group_names:
6067 *
6068 * Get a list of all group names.
6069 */
6070 GList *
nemo_get_all_group_names(void)6071 nemo_get_all_group_names (void)
6072 {
6073 GList *list;
6074 struct group *group;
6075
6076 list = NULL;
6077
6078 setgrent ();
6079
6080 while ((group = getgrent ()) != NULL)
6081 list = g_list_prepend (list, g_strdup (group->gr_name));
6082
6083 endgrent ();
6084
6085 return g_list_sort (list, (GCompareFunc) g_utf8_collate);
6086 }
6087
6088 /**
6089 * nemo_file_get_settable_group_names:
6090 *
6091 * Get a list of all group names that the current user
6092 * can set the group of a specific file to.
6093 *
6094 * @file: The NemoFile in question.
6095 */
6096 GList *
nemo_file_get_settable_group_names(NemoFile * file)6097 nemo_file_get_settable_group_names (NemoFile *file)
6098 {
6099 uid_t user_id;
6100 GList *result;
6101
6102 if (!nemo_file_can_set_group (file)) {
6103 return NULL;
6104 }
6105
6106 /* Check the user. */
6107 user_id = geteuid();
6108
6109 if (user_id == 0) {
6110 /* Root is allowed to set group to anything. */
6111 result = nemo_get_all_group_names ();
6112 } else if (user_id == (uid_t) file->details->uid) {
6113 /* Owner is allowed to set group to any that owner is member of. */
6114 result = nemo_get_group_names_for_user ();
6115 } else {
6116 g_warning ("unhandled case in nemo_get_settable_group_names");
6117 result = NULL;
6118 }
6119
6120 return result;
6121 }
6122
6123 /**
6124 * nemo_file_set_group:
6125 *
6126 * Set the group of a file. This will only have any effect if
6127 * nemo_file_can_set_group returns TRUE.
6128 *
6129 * @file: The file in question.
6130 * @group_name_or_id: The group name to set the owner to.
6131 * If the string does not match any group name, and the
6132 * string is an integer, the group will be set to the
6133 * group id represented by that integer.
6134 * @callback: Function called when asynch group change succeeds or fails.
6135 * @callback_data: Parameter passed back with callback function.
6136 */
6137 void
nemo_file_set_group(NemoFile * file,const char * group_name_or_id,NemoFileOperationCallback callback,gpointer callback_data)6138 nemo_file_set_group (NemoFile *file,
6139 const char *group_name_or_id,
6140 NemoFileOperationCallback callback,
6141 gpointer callback_data)
6142 {
6143 GError *error;
6144 GFileInfo *info;
6145 uid_t new_id;
6146
6147 if (!nemo_file_can_set_group (file)) {
6148 /* Claim that something changed even if the group
6149 * change failed. This makes it easier for some
6150 * clients who see the "reverting" to the old group as
6151 * "changing back".
6152 */
6153 nemo_file_changed (file);
6154 error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
6155 _("Not allowed to set group"));
6156 (* callback) (file, NULL, error, callback_data);
6157 g_error_free (error);
6158 return;
6159 }
6160
6161 /* If no match treating group_name_or_id as name, try treating
6162 * it as id.
6163 */
6164 if (!get_group_id_from_group_name (group_name_or_id, &new_id)
6165 && !get_id_from_digit_string (group_name_or_id, &new_id)) {
6166 /* Claim that something changed even if the group
6167 * change failed. This makes it easier for some
6168 * clients who see the "reverting" to the old group as
6169 * "changing back".
6170 */
6171 nemo_file_changed (file);
6172 error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
6173 _("Specified group '%s' doesn't exist"), group_name_or_id);
6174 (* callback) (file, NULL, error, callback_data);
6175 g_error_free (error);
6176 return;
6177 }
6178
6179 if (new_id == (gid_t) file->details->gid) {
6180 (* callback) (file, NULL, NULL, callback_data);
6181 return;
6182 }
6183
6184 if (!nemo_file_undo_manager_pop_flag ()) {
6185 NemoFileUndoInfo *undo_info;
6186 char *current_group;
6187
6188 current_group = nemo_file_get_group_name (file);
6189 undo_info = nemo_file_undo_info_ownership_new (NEMO_FILE_UNDO_OP_CHANGE_GROUP,
6190 nemo_file_get_location (file),
6191 current_group,
6192 group_name_or_id);
6193 nemo_file_undo_manager_set_action (undo_info);
6194
6195 g_free (current_group);
6196 }
6197
6198 info = g_file_info_new ();
6199 g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID, new_id);
6200 nemo_file_set_attributes (file, info, callback, callback_data);
6201 g_object_unref (info);
6202 }
6203
6204 /**
6205 * nemo_file_get_octal_permissions_as_string:
6206 *
6207 * Get a user-displayable string representing a file's permissions
6208 * as an octal number. The caller
6209 * is responsible for g_free-ing this string.
6210 * @file: NemoFile representing the file in question.
6211 *
6212 * Returns: Newly allocated string ready to display to the user.
6213 *
6214 **/
6215 static char *
nemo_file_get_octal_permissions_as_string(NemoFile * file)6216 nemo_file_get_octal_permissions_as_string (NemoFile *file)
6217 {
6218 guint32 permissions;
6219
6220 g_assert (NEMO_IS_FILE (file));
6221
6222 if (!nemo_file_can_get_permissions (file)) {
6223 return NULL;
6224 }
6225
6226 permissions = file->details->permissions;
6227 return g_strdup_printf ("%03o", permissions);
6228 }
6229
6230 /**
6231 * nemo_file_get_permissions_as_string:
6232 *
6233 * Get a user-displayable string representing a file's permissions. The caller
6234 * is responsible for g_free-ing this string.
6235 * @file: NemoFile representing the file in question.
6236 *
6237 * Returns: Newly allocated string ready to display to the user.
6238 *
6239 **/
6240 static char *
nemo_file_get_permissions_as_string(NemoFile * file)6241 nemo_file_get_permissions_as_string (NemoFile *file)
6242 {
6243 guint32 permissions;
6244 gboolean is_directory;
6245 gboolean is_link;
6246 gboolean suid, sgid, sticky;
6247
6248 if (!nemo_file_can_get_permissions (file)) {
6249 return NULL;
6250 }
6251
6252 g_assert (NEMO_IS_FILE (file));
6253
6254 permissions = file->details->permissions;
6255 is_directory = nemo_file_is_directory (file);
6256 is_link = nemo_file_is_symbolic_link (file);
6257
6258 /* We use ls conventions for displaying these three obscure flags */
6259 suid = permissions & S_ISUID;
6260 sgid = permissions & S_ISGID;
6261 sticky = permissions & S_ISVTX;
6262
6263 return g_strdup_printf ("%c%c%c%c%c%c%c%c%c%c",
6264 is_link ? 'l' : is_directory ? 'd' : '-',
6265 permissions & S_IRUSR ? 'r' : '-',
6266 permissions & S_IWUSR ? 'w' : '-',
6267 permissions & S_IXUSR
6268 ? (suid ? 's' : 'x')
6269 : (suid ? 'S' : '-'),
6270 permissions & S_IRGRP ? 'r' : '-',
6271 permissions & S_IWGRP ? 'w' : '-',
6272 permissions & S_IXGRP
6273 ? (sgid ? 's' : 'x')
6274 : (sgid ? 'S' : '-'),
6275 permissions & S_IROTH ? 'r' : '-',
6276 permissions & S_IWOTH ? 'w' : '-',
6277 permissions & S_IXOTH
6278 ? (sticky ? 't' : 'x')
6279 : (sticky ? 'T' : '-'));
6280 }
6281
6282 /**
6283 * nemo_file_get_owner_as_string:
6284 *
6285 * Get a user-displayable string representing a file's owner. The caller
6286 * is responsible for g_free-ing this string.
6287 * @file: NemoFile representing the file in question.
6288 * @include_real_name: Whether or not to append the real name (if any)
6289 * for this user after the user name.
6290 *
6291 * Returns: Newly allocated string ready to display to the user.
6292 *
6293 **/
6294 char *
nemo_file_get_owner_as_string(NemoFile * file,gboolean include_real_name)6295 nemo_file_get_owner_as_string (NemoFile *file, gboolean include_real_name)
6296 {
6297 char *user_name;
6298
6299 /* Before we have info on a file, the owner is unknown. */
6300 if (file->details->owner == NULL &&
6301 file->details->owner_real == NULL) {
6302 return NULL;
6303 }
6304
6305 if (file->details->owner_real == NULL) {
6306 user_name = g_strdup (eel_ref_str_peek (file->details->owner));
6307 } else if (file->details->owner == NULL) {
6308 user_name = g_strdup (eel_ref_str_peek (file->details->owner_real));
6309 } else if (include_real_name &&
6310 strcmp (eel_ref_str_peek (file->details->owner), eel_ref_str_peek (file->details->owner_real)) != 0) {
6311 user_name = g_strdup_printf ("%s - %s",
6312 eel_ref_str_peek (file->details->owner),
6313 eel_ref_str_peek (file->details->owner_real));
6314 } else {
6315 user_name = g_strdup (eel_ref_str_peek (file->details->owner));
6316 }
6317
6318 return user_name;
6319 }
6320
6321 static char *
format_item_count_for_display(guint item_count,gboolean includes_directories,gboolean includes_files)6322 format_item_count_for_display (guint item_count,
6323 gboolean includes_directories,
6324 gboolean includes_files)
6325 {
6326 g_assert (includes_directories || includes_files);
6327
6328 return g_strdup_printf (includes_directories
6329 ? (includes_files
6330 ? ngettext ("%'u item", "%'u items", item_count)
6331 : ngettext ("%'u folder", "%'u folders", item_count))
6332 : ngettext ("%'u file", "%'u files", item_count), item_count);
6333 }
6334
6335 /**
6336 * nemo_file_get_size_as_string:
6337 *
6338 * Get a user-displayable string representing a file size. The caller
6339 * is responsible for g_free-ing this string. The string is an item
6340 * count for directories.
6341 * @file: NemoFile representing the file in question.
6342 *
6343 * Returns: Newly allocated string ready to display to the user.
6344 *
6345 **/
6346 static char *
nemo_file_get_size_as_string(NemoFile * file)6347 nemo_file_get_size_as_string (NemoFile *file)
6348 {
6349 guint item_count;
6350 gboolean count_unreadable;
6351
6352 if (file == NULL) {
6353 return NULL;
6354 }
6355
6356 g_assert (NEMO_IS_FILE (file));
6357
6358 if (nemo_file_is_directory (file)) {
6359 if (!nemo_file_get_directory_item_count (file, &item_count, &count_unreadable)) {
6360 return NULL;
6361 }
6362 return format_item_count_for_display (item_count, TRUE, TRUE);
6363 }
6364
6365 if (file->details->size == -1) {
6366 return NULL;
6367 }
6368
6369 return g_format_size_full (file->details->size, nemo_global_preferences_get_size_prefix_preference ());
6370 }
6371
6372 /**
6373 * nemo_file_get_size_as_string_with_real_size:
6374 *
6375 * Get a user-displayable string representing a file size. The caller
6376 * is responsible for g_free-ing this string. The string is an item
6377 * count for directories.
6378 * This function adds the real size in the string.
6379 * @file: NemoFile representing the file in question.
6380 *
6381 * Returns: Newly allocated string ready to display to the user.
6382 *
6383 **/
6384 static char *
nemo_file_get_size_as_string_with_real_size(NemoFile * file)6385 nemo_file_get_size_as_string_with_real_size (NemoFile *file)
6386 {
6387 guint item_count;
6388 gboolean count_unreadable;
6389 int prefix;
6390
6391 if (file == NULL) {
6392 return NULL;
6393 }
6394
6395 g_assert (NEMO_IS_FILE (file));
6396
6397 if (nemo_file_is_directory (file)) {
6398 if (!nemo_file_get_directory_item_count (file, &item_count, &count_unreadable)) {
6399 return NULL;
6400 }
6401 return format_item_count_for_display (item_count, TRUE, TRUE);
6402 }
6403
6404 if (file->details->size == -1) {
6405 return NULL;
6406 }
6407
6408 prefix = nemo_global_preferences_get_size_prefix_preference ();
6409 return g_format_size_full (file->details->size, prefix);
6410 }
6411
6412
6413 static char *
nemo_file_get_deep_count_as_string_internal(NemoFile * file,gboolean report_size,gboolean report_directory_count,gboolean report_file_count)6414 nemo_file_get_deep_count_as_string_internal (NemoFile *file,
6415 gboolean report_size,
6416 gboolean report_directory_count,
6417 gboolean report_file_count)
6418 {
6419 NemoRequestStatus status;
6420 guint directory_count;
6421 guint file_count;
6422 guint unreadable_count;
6423 guint hidden_count;
6424 guint total_count;
6425 goffset total_size;
6426 int prefix;
6427
6428 /* Must ask for size or some kind of count, but not both. */
6429 g_assert (!report_size || (!report_directory_count && !report_file_count));
6430 g_assert (report_size || report_directory_count || report_file_count);
6431
6432 if (file == NULL) {
6433 return NULL;
6434 }
6435
6436 g_assert (NEMO_IS_FILE (file));
6437 g_assert (nemo_file_is_directory (file));
6438
6439 status = nemo_file_get_deep_counts
6440 (file, &directory_count, &file_count, &unreadable_count, &hidden_count, &total_size, FALSE);
6441
6442 /* Check whether any info is available. */
6443 if (status == NEMO_REQUEST_NOT_STARTED) {
6444 return NULL;
6445 }
6446
6447 total_count = file_count + directory_count;
6448
6449 if (total_count == 0) {
6450 switch (status) {
6451 case NEMO_REQUEST_IN_PROGRESS:
6452 /* Don't return confident "zero" until we're finished looking,
6453 * because of next case.
6454 */
6455 return NULL;
6456 case NEMO_REQUEST_DONE:
6457 /* Don't return "zero" if we there were contents but we couldn't read them. */
6458 if (unreadable_count != 0) {
6459 return NULL;
6460 }
6461 case NEMO_REQUEST_NOT_STARTED:
6462 default:
6463 break;
6464 }
6465 }
6466
6467 /* Note that we don't distinguish the "everything was readable" case
6468 * from the "some things but not everything was readable" case here.
6469 * Callers can distinguish them using nemo_file_get_deep_counts
6470 * directly if desired.
6471 */
6472 if (report_size) {
6473 prefix = nemo_global_preferences_get_size_prefix_preference ();
6474 return g_format_size_full (total_size, prefix);
6475 }
6476
6477 return format_item_count_for_display (report_directory_count
6478 ? (report_file_count ? total_count : directory_count)
6479 : file_count,
6480 report_directory_count, report_file_count);
6481 }
6482
6483 /**
6484 * nemo_file_get_deep_size_as_string:
6485 *
6486 * Get a user-displayable string representing the size of all contained
6487 * items (only makes sense for directories). The caller
6488 * is responsible for g_free-ing this string.
6489 * @file: NemoFile representing the file in question.
6490 *
6491 * Returns: Newly allocated string ready to display to the user.
6492 *
6493 **/
6494 static char *
nemo_file_get_deep_size_as_string(NemoFile * file)6495 nemo_file_get_deep_size_as_string (NemoFile *file)
6496 {
6497 return nemo_file_get_deep_count_as_string_internal (file, TRUE, FALSE, FALSE);
6498 }
6499
6500 /**
6501 * nemo_file_get_deep_total_count_as_string:
6502 *
6503 * Get a user-displayable string representing the count of all contained
6504 * items (only makes sense for directories). The caller
6505 * is responsible for g_free-ing this string.
6506 * @file: NemoFile representing the file in question.
6507 *
6508 * Returns: Newly allocated string ready to display to the user.
6509 *
6510 **/
6511 static char *
nemo_file_get_deep_total_count_as_string(NemoFile * file)6512 nemo_file_get_deep_total_count_as_string (NemoFile *file)
6513 {
6514 return nemo_file_get_deep_count_as_string_internal (file, FALSE, TRUE, TRUE);
6515 }
6516
6517 /**
6518 * nemo_file_get_deep_file_count_as_string:
6519 *
6520 * Get a user-displayable string representing the count of all contained
6521 * items, not including directories. It only makes sense to call this
6522 * function on a directory. The caller
6523 * is responsible for g_free-ing this string.
6524 * @file: NemoFile representing the file in question.
6525 *
6526 * Returns: Newly allocated string ready to display to the user.
6527 *
6528 **/
6529 static char *
nemo_file_get_deep_file_count_as_string(NemoFile * file)6530 nemo_file_get_deep_file_count_as_string (NemoFile *file)
6531 {
6532 return nemo_file_get_deep_count_as_string_internal (file, FALSE, FALSE, TRUE);
6533 }
6534
6535 /**
6536 * nemo_file_get_deep_directory_count_as_string:
6537 *
6538 * Get a user-displayable string representing the count of all contained
6539 * directories. It only makes sense to call this
6540 * function on a directory. The caller
6541 * is responsible for g_free-ing this string.
6542 * @file: NemoFile representing the file in question.
6543 *
6544 * Returns: Newly allocated string ready to display to the user.
6545 *
6546 **/
6547 static char *
nemo_file_get_deep_directory_count_as_string(NemoFile * file)6548 nemo_file_get_deep_directory_count_as_string (NemoFile *file)
6549 {
6550 return nemo_file_get_deep_count_as_string_internal (file, FALSE, TRUE, FALSE);
6551 }
6552
6553 /**
6554 * nemo_file_get_string_attribute:
6555 *
6556 * Get a user-displayable string from a named attribute. Use g_free to
6557 * free this string. If the value is unknown, returns NULL. You can call
6558 * nemo_file_get_string_attribute_with_default if you want a non-NULL
6559 * default.
6560 *
6561 * @file: NemoFile representing the file in question.
6562 * @attribute_name: The name of the desired attribute. The currently supported
6563 * set includes "name", "type", "detailed_type", "mime_type", "size", "deep_size", "deep_directory_count",
6564 * "deep_file_count", "deep_total_count", "date_modified", "date_changed", "date_accessed",
6565 * "date_permissions", "owner", "group", "permissions", "octal_permissions", "uri", "where",
6566 * "link_target", "volume", "free_space", "selinux_context", "trashed_on", "trashed_orig_path"
6567 *
6568 * Returns: Newly allocated string ready to display to the user, or NULL
6569 * if the value is unknown or @attribute_name is not supported.
6570 *
6571 **/
6572 char *
nemo_file_get_string_attribute_q(NemoFile * file,GQuark attribute_q)6573 nemo_file_get_string_attribute_q (NemoFile *file, GQuark attribute_q)
6574 {
6575 char *extension_attribute;
6576
6577 if (attribute_q == attribute_name_q) {
6578 return nemo_file_get_display_name (file);
6579 }
6580 if (attribute_q == attribute_type_q) {
6581 return nemo_file_get_type_as_string (file);
6582 }
6583 if (attribute_q == attribute_detailed_type_q) {
6584 return nemo_file_get_detailed_type_as_string (file);
6585 }
6586 if (attribute_q == attribute_mime_type_q) {
6587 return nemo_file_get_mime_type (file);
6588 }
6589 if (attribute_q == attribute_size_q) {
6590 return nemo_file_get_size_as_string (file);
6591 }
6592 if (attribute_q == attribute_size_detail_q) {
6593 return nemo_file_get_size_as_string_with_real_size (file);
6594 }
6595 if (attribute_q == attribute_deep_size_q) {
6596 return nemo_file_get_deep_size_as_string (file);
6597 }
6598 if (attribute_q == attribute_deep_file_count_q) {
6599 return nemo_file_get_deep_file_count_as_string (file);
6600 }
6601 if (attribute_q == attribute_deep_directory_count_q) {
6602 return nemo_file_get_deep_directory_count_as_string (file);
6603 }
6604 if (attribute_q == attribute_deep_total_count_q) {
6605 return nemo_file_get_deep_total_count_as_string (file);
6606 }
6607 if (attribute_q == attribute_trash_orig_path_q) {
6608 return nemo_file_get_trash_original_file_parent_as_string (file);
6609 }
6610 if (attribute_q == attribute_date_modified_q) {
6611 return nemo_file_get_date_as_string (file,
6612 NEMO_DATE_TYPE_MODIFIED,
6613 NEMO_DATE_FORMAT_REGULAR);
6614 }
6615 if (attribute_q == attribute_date_modified_full_q) {
6616 return nemo_file_get_date_as_string (file,
6617 NEMO_DATE_TYPE_MODIFIED,
6618 NEMO_DATE_FORMAT_FULL);
6619 }
6620 if (attribute_q == attribute_date_modified_with_time_q) {
6621 return nemo_file_get_date_as_string (file,
6622 NEMO_DATE_TYPE_MODIFIED,
6623 NEMO_DATE_FORMAT_REGULAR_WITH_TIME);
6624 }
6625 if (attribute_q == attribute_date_changed_q) {
6626 return nemo_file_get_date_as_string (file,
6627 NEMO_DATE_TYPE_CHANGED,
6628 NEMO_DATE_FORMAT_REGULAR);
6629 }
6630 if (attribute_q == attribute_date_changed_full_q) {
6631 return nemo_file_get_date_as_string (file,
6632 NEMO_DATE_TYPE_CHANGED,
6633 NEMO_DATE_FORMAT_FULL);
6634 }
6635 if (attribute_q == attribute_date_accessed_q) {
6636 return nemo_file_get_date_as_string (file,
6637 NEMO_DATE_TYPE_ACCESSED,
6638 NEMO_DATE_FORMAT_REGULAR);
6639 }
6640 if (attribute_q == attribute_date_accessed_full_q) {
6641 return nemo_file_get_date_as_string (file,
6642 NEMO_DATE_TYPE_ACCESSED,
6643 NEMO_DATE_FORMAT_FULL);
6644 }
6645 if (attribute_q == attribute_date_created_q) {
6646 return nemo_file_get_date_as_string (file,
6647 NEMO_DATE_TYPE_CREATED,
6648 NEMO_DATE_FORMAT_REGULAR);
6649 }
6650 if (attribute_q == attribute_date_created_full_q) {
6651 return nemo_file_get_date_as_string (file,
6652 NEMO_DATE_TYPE_CREATED,
6653 NEMO_DATE_FORMAT_FULL);
6654 }
6655 if (attribute_q == attribute_date_created_with_time_q) {
6656 return nemo_file_get_date_as_string (file,
6657 NEMO_DATE_TYPE_CREATED,
6658 NEMO_DATE_FORMAT_REGULAR_WITH_TIME);
6659 }
6660 if (attribute_q == attribute_trashed_on_q) {
6661 return nemo_file_get_date_as_string (file,
6662 NEMO_DATE_TYPE_TRASHED,
6663 NEMO_DATE_FORMAT_FULL);
6664 }
6665 if (attribute_q == attribute_trashed_on_full_q) {
6666 return nemo_file_get_date_as_string (file,
6667 NEMO_DATE_TYPE_TRASHED,
6668 NEMO_DATE_FORMAT_REGULAR);
6669 }
6670 if (attribute_q == attribute_date_permissions_q) {
6671 return nemo_file_get_date_as_string (file,
6672 NEMO_DATE_TYPE_PERMISSIONS_CHANGED,
6673 NEMO_DATE_FORMAT_FULL);
6674 }
6675 if (attribute_q == attribute_date_permissions_full_q) {
6676 return nemo_file_get_date_as_string (file,
6677 NEMO_DATE_TYPE_PERMISSIONS_CHANGED,
6678 NEMO_DATE_FORMAT_REGULAR);
6679 }
6680 if (attribute_q == attribute_permissions_q) {
6681 return nemo_file_get_permissions_as_string (file);
6682 }
6683 if (attribute_q == attribute_selinux_context_q) {
6684 return nemo_file_get_selinux_context (file);
6685 }
6686 if (attribute_q == attribute_octal_permissions_q) {
6687 return nemo_file_get_octal_permissions_as_string (file);
6688 }
6689 if (attribute_q == attribute_owner_q) {
6690 return nemo_file_get_owner_as_string (file, TRUE);
6691 }
6692 if (attribute_q == attribute_group_q) {
6693 return nemo_file_get_group_name (file);
6694 }
6695 if (attribute_q == attribute_uri_q) {
6696 return nemo_file_get_uri (file);
6697 }
6698 if (attribute_q == attribute_where_q) {
6699 return nemo_file_get_where_string (file);
6700 }
6701 if (attribute_q == attribute_link_target_q) {
6702 return nemo_file_get_symbolic_link_target_path (file);
6703 }
6704 if (attribute_q == attribute_volume_q) {
6705 return nemo_file_get_volume_name (file);
6706 }
6707 if (attribute_q == attribute_free_space_q) {
6708 return nemo_file_get_volume_free_space (file);
6709 }
6710
6711 extension_attribute = NULL;
6712
6713 if (file->details->pending_extension_attributes) {
6714 extension_attribute = g_hash_table_lookup (file->details->pending_extension_attributes,
6715 GINT_TO_POINTER (attribute_q));
6716 }
6717
6718 if (extension_attribute == NULL && file->details->extension_attributes) {
6719 extension_attribute = g_hash_table_lookup (file->details->extension_attributes,
6720 GINT_TO_POINTER (attribute_q));
6721 }
6722
6723 return g_strdup (extension_attribute);
6724 }
6725
6726 char *
nemo_file_get_string_attribute(NemoFile * file,const char * attribute_name)6727 nemo_file_get_string_attribute (NemoFile *file, const char *attribute_name)
6728 {
6729 return nemo_file_get_string_attribute_q (file, g_quark_from_string (attribute_name));
6730 }
6731
6732
6733 /**
6734 * nemo_file_get_string_attribute_with_default:
6735 *
6736 * Get a user-displayable string from a named attribute. Use g_free to
6737 * free this string. If the value is unknown, returns a string representing
6738 * the unknown value, which varies with attribute. You can call
6739 * nemo_file_get_string_attribute if you want NULL instead of a default
6740 * result.
6741 *
6742 * @file: NemoFile representing the file in question.
6743 * @attribute_name: The name of the desired attribute. See the description of
6744 * nemo_file_get_string for the set of available attributes.
6745 *
6746 * Returns: Newly allocated string ready to display to the user, or a string
6747 * such as "unknown" if the value is unknown or @attribute_name is not supported.
6748 *
6749 **/
6750 char *
nemo_file_get_string_attribute_with_default_q(NemoFile * file,GQuark attribute_q)6751 nemo_file_get_string_attribute_with_default_q (NemoFile *file, GQuark attribute_q)
6752 {
6753 char *result;
6754 guint item_count;
6755 gboolean count_unreadable;
6756 NemoRequestStatus status;
6757
6758 result = nemo_file_get_string_attribute_q (file, attribute_q);
6759 if (result != NULL) {
6760 return result;
6761 }
6762
6763 /* Supply default values for the ones we know about. */
6764 /* FIXME bugzilla.gnome.org 40646:
6765 * Use hash table and switch statement or function pointers for speed?
6766 */
6767 if (attribute_q == attribute_size_q) {
6768 if (!nemo_file_should_show_directory_item_count (file)) {
6769 return g_strdup ("--");
6770 }
6771 count_unreadable = FALSE;
6772 if (nemo_file_is_directory (file)) {
6773 nemo_file_get_directory_item_count (file, &item_count, &count_unreadable);
6774 }
6775 return g_strdup (count_unreadable ? _("? items") : "...");
6776 }
6777 if (attribute_q == attribute_deep_size_q) {
6778 status = nemo_file_get_deep_counts (file, NULL, NULL, NULL, NULL, NULL, FALSE);
6779 if (status == NEMO_REQUEST_DONE) {
6780 /* This means no contents at all were readable */
6781 return g_strdup (_("? bytes"));
6782 }
6783 return g_strdup ("...");
6784 }
6785 if (attribute_q == attribute_deep_file_count_q
6786 || attribute_q == attribute_deep_directory_count_q
6787 || attribute_q == attribute_deep_total_count_q) {
6788 status = nemo_file_get_deep_counts (file, NULL, NULL, NULL, NULL, NULL, FALSE);
6789 if (status == NEMO_REQUEST_DONE) {
6790 /* This means no contents at all were readable */
6791 return g_strdup (_("? items"));
6792 }
6793 return g_strdup ("...");
6794 }
6795 if (attribute_q == attribute_type_q
6796 || attribute_q == attribute_detailed_type_q
6797 || attribute_q == attribute_mime_type_q) {
6798 return g_strdup (_("Unknown"));
6799 }
6800 if (attribute_q == attribute_trashed_on_q) {
6801 /* If n/a */
6802 return g_strdup ("");
6803 }
6804 if (attribute_q == attribute_trash_orig_path_q) {
6805 /* If n/a */
6806 return g_strdup ("");
6807 }
6808
6809 /* Fallback, use for both unknown attributes and attributes
6810 * for which we have no more appropriate default.
6811 */
6812 return g_strdup (_("unknown"));
6813 }
6814
6815 char *
nemo_file_get_string_attribute_with_default(NemoFile * file,const char * attribute_name)6816 nemo_file_get_string_attribute_with_default (NemoFile *file, const char *attribute_name)
6817 {
6818 return nemo_file_get_string_attribute_with_default_q (file, g_quark_from_string (attribute_name));
6819 }
6820
6821 gboolean
nemo_file_is_date_sort_attribute_q(GQuark attribute_q)6822 nemo_file_is_date_sort_attribute_q (GQuark attribute_q)
6823 {
6824 if (attribute_q == attribute_modification_date_q ||
6825 attribute_q == attribute_date_modified_q ||
6826 attribute_q == attribute_date_modified_full_q ||
6827 attribute_q == attribute_date_modified_with_time_q ||
6828 attribute_q == attribute_accessed_date_q ||
6829 attribute_q == attribute_date_accessed_q ||
6830 attribute_q == attribute_date_accessed_full_q ||
6831 attribute_q == attribute_date_changed_q ||
6832 attribute_q == attribute_date_changed_full_q ||
6833 attribute_q == attribute_trashed_on_q ||
6834 attribute_q == attribute_trashed_on_full_q ||
6835 attribute_q == attribute_date_permissions_q ||
6836 attribute_q == attribute_date_permissions_full_q ||
6837 attribute_q == attribute_creation_date_q ||
6838 attribute_q == attribute_date_created_q ||
6839 attribute_q == attribute_date_created_full_q ||
6840 attribute_q == attribute_date_created_with_time_q) {
6841 return TRUE;
6842 }
6843
6844 return FALSE;
6845 }
6846
6847 struct {
6848 const char *icon_name;
6849 const char *display_name;
6850 } mime_type_map[] = {
6851 { "application-x-executable", N_("Program") },
6852 { "audio-x-generic", N_("Audio") },
6853 { "font-x-generic", N_("Font") },
6854 { "image-x-generic", N_("Image") },
6855 { "package-x-generic", N_("Archive") },
6856 { "text-html", N_("Markup") },
6857 { "text-x-generic", N_("Text") },
6858 { "text-x-generic-template", N_("Text") },
6859 { "text-x-script", N_("Program") },
6860 { "video-x-generic", N_("Video") },
6861 { "x-office-address-book", N_("Contacts") },
6862 { "x-office-calendar", N_("Calendar") },
6863 { "x-office-document", N_("Document") },
6864 { "x-office-presentation", N_("Presentation") },
6865 { "x-office-spreadsheet", N_("Spreadsheet") },
6866 };
6867
6868 static char *
get_basic_type_for_mime_type(const char * mime_type)6869 get_basic_type_for_mime_type (const char *mime_type)
6870 {
6871 char *icon_name;
6872 char *basic_type = NULL;
6873
6874 icon_name = g_content_type_get_generic_icon_name (mime_type);
6875 if (icon_name != NULL) {
6876 guint i;
6877
6878 for (i = 0; i < G_N_ELEMENTS (mime_type_map); i++) {
6879 if (strcmp (mime_type_map[i].icon_name, icon_name) == 0) {
6880 basic_type = g_strdup (gettext (mime_type_map[i].display_name));
6881 break;
6882 }
6883 }
6884 }
6885
6886 g_free (icon_name);
6887
6888 return basic_type;
6889 }
6890
6891 static char *
get_description(NemoFile * file,gboolean detailed)6892 get_description (NemoFile *file,
6893 gboolean detailed)
6894 {
6895 const char *mime_type;
6896
6897 g_assert (NEMO_IS_FILE (file));
6898
6899 mime_type = eel_ref_str_peek (file->details->mime_type);
6900
6901 if (mime_type == NULL) {
6902 return NULL;
6903 }
6904
6905 if (g_content_type_is_unknown (mime_type)) {
6906 if (nemo_file_is_executable (file)) {
6907 return g_strdup (_("Program"));
6908 }
6909 return g_strdup (_("Binary"));
6910 }
6911
6912 if (strcmp (mime_type, "inode/directory") == 0) {
6913 return g_strdup (_("Folder"));
6914 }
6915
6916 if (detailed) {
6917 char *description;
6918
6919 description = g_content_type_get_description (mime_type);
6920 if (description != NULL) {
6921 return description;
6922 }
6923 } else {
6924 char *category;
6925
6926 category = get_basic_type_for_mime_type (mime_type);
6927 if (category != NULL) {
6928 return category;
6929 }
6930
6931 if (category == NULL) {
6932 return g_content_type_get_description (mime_type);
6933 }
6934 }
6935
6936 return g_strdup (mime_type);
6937 }
6938
6939 /* Takes ownership of string */
6940 static char *
update_description_for_link(NemoFile * file,char * string)6941 update_description_for_link (NemoFile *file, char *string)
6942 {
6943 char *res;
6944
6945 if (nemo_file_is_symbolic_link (file) && !nemo_file_is_in_favorites (file)) {
6946 g_assert (!nemo_file_is_broken_symbolic_link (file));
6947 if (string == NULL) {
6948 return g_strdup (_("link"));
6949 }
6950 /* Note to localizers: convert file type string for file
6951 * (e.g. "folder", "plain text") to file type for symbolic link
6952 * to that kind of file (e.g. "link to folder").
6953 */
6954 res = g_strdup_printf (_("Link to %s"), string);
6955 g_free (string);
6956 return res;
6957 }
6958
6959 return string;
6960 }
6961
6962 char *
nemo_file_get_type_as_string(NemoFile * file)6963 nemo_file_get_type_as_string (NemoFile *file)
6964 {
6965 if (file == NULL) {
6966 return NULL;
6967 }
6968
6969 if (nemo_file_is_broken_symbolic_link (file)) {
6970 return g_strdup (_("link (broken)"));
6971 }
6972
6973 return update_description_for_link (file, get_description (file, FALSE));
6974 }
6975
6976 char *
nemo_file_get_detailed_type_as_string(NemoFile * file)6977 nemo_file_get_detailed_type_as_string (NemoFile *file)
6978 {
6979 if (file == NULL) {
6980 return NULL;
6981 }
6982
6983 if (nemo_file_is_broken_symbolic_link (file)) {
6984 return g_strdup (_("link (broken)"));
6985 }
6986
6987 return update_description_for_link (file, get_description (file, TRUE));
6988 }
6989
6990 /**
6991 * nemo_file_get_file_type
6992 *
6993 * Return this file's type.
6994 * @file: NemoFile representing the file in question.
6995 *
6996 * Returns: The type.
6997 *
6998 **/
6999 GFileType
nemo_file_get_file_type(NemoFile * file)7000 nemo_file_get_file_type (NemoFile *file)
7001 {
7002 if (file == NULL) {
7003 return G_FILE_TYPE_UNKNOWN;
7004 }
7005
7006 return file->details->type;
7007 }
7008
7009 /**
7010 * nemo_file_get_mime_type
7011 *
7012 * Return this file's default mime type.
7013 * @file: NemoFile representing the file in question.
7014 *
7015 * Returns: The mime type.
7016 *
7017 **/
7018 char *
nemo_file_get_mime_type(NemoFile * file)7019 nemo_file_get_mime_type (NemoFile *file)
7020 {
7021 if (file != NULL) {
7022 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
7023 if (file->details->mime_type != NULL) {
7024 return g_strdup (eel_ref_str_peek (file->details->mime_type));
7025 }
7026 }
7027 return g_strdup ("application/octet-stream");
7028 }
7029
7030 /**
7031 * nemo_file_is_mime_type
7032 *
7033 * Check whether a file is of a particular MIME type, or inherited
7034 * from it.
7035 * @file: NemoFile representing the file in question.
7036 * @mime_type: The MIME-type string to test (e.g. "text/plain")
7037 *
7038 * Return value: TRUE if @mime_type exactly matches the
7039 * file's MIME type.
7040 *
7041 **/
7042 gboolean
nemo_file_is_mime_type(NemoFile * file,const char * mime_type)7043 nemo_file_is_mime_type (NemoFile *file, const char *mime_type)
7044 {
7045 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
7046 g_return_val_if_fail (mime_type != NULL, FALSE);
7047
7048 if (file->details->mime_type == NULL) {
7049 return FALSE;
7050 }
7051 return g_content_type_is_a (eel_ref_str_peek (file->details->mime_type),
7052 mime_type);
7053 }
7054
7055 gboolean
nemo_file_is_launchable(NemoFile * file)7056 nemo_file_is_launchable (NemoFile *file)
7057 {
7058 gboolean type_can_be_executable;
7059
7060 type_can_be_executable = FALSE;
7061 if (file->details->mime_type != NULL) {
7062 type_can_be_executable =
7063 g_content_type_can_be_executable (eel_ref_str_peek (file->details->mime_type));
7064 }
7065
7066 return type_can_be_executable &&
7067 nemo_file_can_get_permissions (file) &&
7068 nemo_file_can_execute (file) &&
7069 nemo_file_is_executable (file) &&
7070 !nemo_file_is_directory (file);
7071 }
7072
7073
7074 /**
7075 * nemo_file_get_emblem_icons
7076 *
7077 * Return the list of names of emblems that this file should display,
7078 * in canonical order.
7079 * @file: NemoFile representing the file in question.
7080 * @view_file: NemoFile representing the view's directory_as_file.
7081 *
7082 * Returns: A list of emblem names.
7083 *
7084 **/
7085 GList *
nemo_file_get_emblem_icons(NemoFile * file,NemoFile * view_file)7086 nemo_file_get_emblem_icons (NemoFile *file,
7087 NemoFile *view_file)
7088 {
7089 GList *keywords, *l;
7090 GList *icons;
7091 char *icon_names[2];
7092 char *keyword;
7093 GIcon *icon;
7094
7095 if (file == NULL) {
7096 return NULL;
7097 }
7098
7099 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
7100
7101 keywords = nemo_file_get_keywords (file);
7102 keywords = prepend_automatic_keywords (file, view_file, keywords);
7103
7104 if (view_file && nemo_file_can_write (view_file)) {
7105 if (!nemo_file_can_write (file) && !nemo_file_is_in_trash (file)) {
7106 keywords = g_list_prepend (keywords, g_strdup (NEMO_FILE_EMBLEM_NAME_CANT_WRITE));
7107 }
7108 }
7109
7110 icons = NULL;
7111 for (l = keywords; l != NULL; l = l->next) {
7112 keyword = l->data;
7113
7114 icon_names[0] = g_strconcat ("emblem-", keyword, NULL);
7115 icon_names[1] = keyword;
7116 icon = g_themed_icon_new_from_names (icon_names, 2);
7117 g_free (icon_names[0]);
7118
7119 icons = g_list_prepend (icons, icon);
7120 }
7121
7122 g_list_free_full (keywords, g_free);
7123
7124 return icons;
7125 }
7126
7127 static GList *
sort_keyword_list_and_remove_duplicates(GList * keywords)7128 sort_keyword_list_and_remove_duplicates (GList *keywords)
7129 {
7130 GList *p;
7131 GList *duplicate_link;
7132
7133 if (keywords != NULL) {
7134 keywords = g_list_sort (keywords, (GCompareFunc) g_utf8_collate);
7135
7136 p = keywords;
7137 while (p->next != NULL) {
7138 if (strcmp ((const char *) p->data, (const char *) p->next->data) == 0) {
7139 duplicate_link = p->next;
7140 keywords = g_list_remove_link (keywords, duplicate_link);
7141 g_list_free_full (duplicate_link, g_free);
7142 } else {
7143 p = p->next;
7144 }
7145 }
7146 }
7147
7148 return keywords;
7149 }
7150
7151 /**
7152 * nemo_file_get_keywords
7153 *
7154 * Return this file's keywords.
7155 * @file: NemoFile representing the file in question.
7156 *
7157 * Returns: A list of keywords.
7158 *
7159 **/
7160 GList *
nemo_file_get_keywords(NemoFile * file)7161 nemo_file_get_keywords (NemoFile *file)
7162 {
7163 GList *keywords;
7164
7165 if (file == NULL) {
7166 return NULL;
7167 }
7168
7169 g_return_val_if_fail (NEMO_IS_FILE (file), NULL);
7170
7171 keywords = eel_g_str_list_copy (file->details->extension_emblems);
7172 keywords = g_list_concat (keywords, eel_g_str_list_copy (file->details->pending_extension_emblems));
7173 keywords = g_list_concat (keywords, nemo_file_get_metadata_list (file, NEMO_METADATA_KEY_EMBLEMS));
7174
7175 return sort_keyword_list_and_remove_duplicates (keywords);
7176 }
7177
7178 /**
7179 * nemo_file_is_symbolic_link
7180 *
7181 * Check if this file is a symbolic link.
7182 * @file: NemoFile representing the file in question.
7183 *
7184 * Returns: True if the file is a symbolic link.
7185 *
7186 **/
7187 gboolean
nemo_file_is_symbolic_link(NemoFile * file)7188 nemo_file_is_symbolic_link (NemoFile *file)
7189 {
7190 return file->details->is_symlink;
7191 }
7192
7193 gboolean
nemo_file_is_mountpoint(NemoFile * file)7194 nemo_file_is_mountpoint (NemoFile *file)
7195 {
7196 return file->details->is_mountpoint;
7197 }
7198
7199 GMount *
nemo_file_get_mount(NemoFile * file)7200 nemo_file_get_mount (NemoFile *file)
7201 {
7202 if (file->details->mount) {
7203 return g_object_ref (file->details->mount);
7204 }
7205 return NULL;
7206 }
7207
7208 static void
file_mount_unmounted(GMount * mount,gpointer data)7209 file_mount_unmounted (GMount *mount,
7210 gpointer data)
7211 {
7212 NemoFile *file;
7213
7214 file = NEMO_FILE (data);
7215
7216 nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_MOUNT);
7217 }
7218
7219 void
nemo_file_set_mount(NemoFile * file,GMount * mount)7220 nemo_file_set_mount (NemoFile *file,
7221 GMount *mount)
7222 {
7223 if (file->details->mount) {
7224 g_signal_handlers_disconnect_by_func (file->details->mount, file_mount_unmounted, file);
7225 g_object_unref (file->details->mount);
7226 file->details->mount = NULL;
7227 }
7228
7229 if (mount) {
7230 file->details->mount = g_object_ref (mount);
7231 g_signal_connect (mount, "unmounted",
7232 G_CALLBACK (file_mount_unmounted), file);
7233 }
7234 }
7235
7236 /**
7237 * nemo_file_is_broken_symbolic_link
7238 *
7239 * Check if this file is a symbolic link with a missing target.
7240 * @file: NemoFile representing the file in question.
7241 *
7242 * Returns: True if the file is a symbolic link with a missing target.
7243 *
7244 **/
7245 gboolean
nemo_file_is_broken_symbolic_link(NemoFile * file)7246 nemo_file_is_broken_symbolic_link (NemoFile *file)
7247 {
7248 if (file == NULL) {
7249 return FALSE;
7250 }
7251
7252 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
7253
7254 /* Non-broken symbolic links return the target's type for get_file_type. */
7255 return nemo_file_get_file_type (file) == G_FILE_TYPE_SYMBOLIC_LINK;
7256 }
7257
7258 static void
get_fs_free_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)7259 get_fs_free_cb (GObject *source_object,
7260 GAsyncResult *res,
7261 gpointer user_data)
7262 {
7263 NemoFile *file;
7264 guint64 free_space;
7265 GFileInfo *info;
7266
7267 file = NEMO_FILE (user_data);
7268
7269 free_space = (guint64)-1;
7270 info = g_file_query_filesystem_info_finish (G_FILE (source_object),
7271 res, NULL);
7272 if (info) {
7273 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE)) {
7274 free_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
7275 }
7276 g_object_unref (info);
7277 }
7278
7279 if (file->details->free_space != free_space) {
7280 file->details->free_space = free_space;
7281 nemo_file_emit_changed (file);
7282 }
7283
7284 nemo_file_unref (file);
7285 }
7286
7287 /**
7288 * nemo_file_get_volume_free_space
7289 * Get a nicely formatted char with free space on the file's volume
7290 * @file: NemoFile representing the file in question.
7291 *
7292 * Returns: newly-allocated copy of file size in a formatted string
7293 */
7294 char *
nemo_file_get_volume_free_space(NemoFile * file)7295 nemo_file_get_volume_free_space (NemoFile *file)
7296 {
7297 GFile *location;
7298 char *res;
7299 time_t now;
7300 int prefix;
7301
7302 now = time (NULL);
7303 /* Update first time and then every 2 seconds */
7304 if (file->details->free_space_read == 0 ||
7305 (now - file->details->free_space_read) > 2) {
7306 file->details->free_space_read = now;
7307 location = nemo_file_get_location (file);
7308 g_file_query_filesystem_info_async (location,
7309 G_FILE_ATTRIBUTE_FILESYSTEM_FREE,
7310 0, NULL,
7311 get_fs_free_cb,
7312 nemo_file_ref (file));
7313 g_object_unref (location);
7314 }
7315
7316 res = NULL;
7317 if (file->details->free_space != (guint64)-1) {
7318 prefix = nemo_global_preferences_get_size_prefix_preference ();
7319 res = g_format_size_full (file->details->free_space, prefix);
7320 }
7321
7322 return res;
7323 }
7324
7325 /**
7326 * nemo_file_get_volume_name
7327 * Get the path of the volume the file resides on
7328 * @file: NemoFile representing the file in question.
7329 *
7330 * Returns: newly-allocated copy of the volume name of the target file,
7331 * if the volume name isn't set, it returns the mount path of the volume
7332 */
7333 char *
nemo_file_get_volume_name(NemoFile * file)7334 nemo_file_get_volume_name (NemoFile *file)
7335 {
7336 GFile *location;
7337 char *res;
7338 GMount *mount;
7339
7340 res = NULL;
7341
7342 location = nemo_file_get_location (file);
7343 mount = g_file_find_enclosing_mount (location, NULL, NULL);
7344 if (mount) {
7345 res = g_strdup (g_mount_get_name (mount));
7346 g_object_unref (mount);
7347 }
7348 g_object_unref (location);
7349
7350 return res;
7351 }
7352
7353 /**
7354 * nemo_file_get_symbolic_link_target_path
7355 *
7356 * Get the file path of the target of a symbolic link. It is an error
7357 * to call this function on a file that isn't a symbolic link.
7358 * @file: NemoFile representing the symbolic link in question.
7359 *
7360 * Returns: newly-allocated copy of the file path of the target of the symbolic link.
7361 */
7362 char *
nemo_file_get_symbolic_link_target_path(NemoFile * file)7363 nemo_file_get_symbolic_link_target_path (NemoFile *file)
7364 {
7365 if (!nemo_file_is_symbolic_link (file)) {
7366 g_warning ("File has symlink target, but is not marked as symlink");
7367 }
7368
7369 return g_strdup (file->details->symlink_name);
7370 }
7371
7372 /**
7373 * nemo_file_get_symbolic_link_target_uri
7374 *
7375 * Get the uri of the target of a symbolic link. It is an error
7376 * to call this function on a file that isn't a symbolic link.
7377 * @file: NemoFile representing the symbolic link in question.
7378 *
7379 * Returns: newly-allocated copy of the uri of the target of the symbolic link.
7380 */
7381 char *
nemo_file_get_symbolic_link_target_uri(NemoFile * file)7382 nemo_file_get_symbolic_link_target_uri (NemoFile *file)
7383 {
7384 GFile *location, *parent, *target;
7385 char *target_uri;
7386
7387 if (!nemo_file_is_symbolic_link (file)) {
7388 g_warning ("File has symlink target, but is not marked as symlink");
7389 }
7390
7391 if (file->details->symlink_name == NULL) {
7392 return NULL;
7393 } else {
7394 target = NULL;
7395
7396 location = nemo_file_get_location (file);
7397 parent = g_file_get_parent (location);
7398 g_object_unref (location);
7399 if (parent) {
7400 target = g_file_resolve_relative_path (parent, file->details->symlink_name);
7401 g_object_unref (parent);
7402 }
7403
7404 target_uri = NULL;
7405 if (target) {
7406 target_uri = g_file_get_uri (target);
7407 g_object_unref (target);
7408 }
7409 return target_uri;
7410 }
7411 }
7412
7413 /**
7414 * nemo_file_is_nemo_link
7415 *
7416 * Check if this file is a "nemo link", meaning a historical
7417 * nemo xml link file or a desktop file.
7418 * @file: NemoFile representing the file in question.
7419 *
7420 * Returns: True if the file is a nemo link.
7421 *
7422 **/
7423 gboolean
nemo_file_is_nemo_link(NemoFile * file)7424 nemo_file_is_nemo_link (NemoFile *file)
7425 {
7426 if (file->details->mime_type == NULL) {
7427 return FALSE;
7428 }
7429 return g_content_type_equals (eel_ref_str_peek (file->details->mime_type),
7430 "application/x-desktop");
7431 }
7432
7433 /**
7434 * nemo_file_is_directory
7435 *
7436 * Check if this file is a directory.
7437 * @file: NemoFile representing the file in question.
7438 *
7439 * Returns: TRUE if @file is a directory.
7440 *
7441 **/
7442 gboolean
nemo_file_is_directory(NemoFile * file)7443 nemo_file_is_directory (NemoFile *file)
7444 {
7445 return nemo_file_get_file_type (file) == G_FILE_TYPE_DIRECTORY;
7446 }
7447
7448 /**
7449 * nemo_file_is_user_special_directory
7450 *
7451 * Check if this file is a special platform directory.
7452 * @file: NemoFile representing the file in question.
7453 * @special_directory: GUserDirectory representing the type to test for
7454 *
7455 * Returns: TRUE if @file is a special directory of the given kind.
7456 */
7457 gboolean
nemo_file_is_user_special_directory(NemoFile * file,GUserDirectory special_directory)7458 nemo_file_is_user_special_directory (NemoFile *file,
7459 GUserDirectory special_directory)
7460 {
7461 gboolean is_special_dir;
7462 const gchar *special_dir;
7463
7464 special_dir = g_get_user_special_dir (special_directory);
7465 is_special_dir = FALSE;
7466
7467 if (special_dir) {
7468 GFile *loc;
7469 GFile *special_gfile;
7470
7471 loc = nemo_file_get_location (file);
7472 special_gfile = g_file_new_for_path (special_dir);
7473 is_special_dir = g_file_equal (loc, special_gfile);
7474 g_object_unref (special_gfile);
7475 g_object_unref (loc);
7476 }
7477
7478 return is_special_dir;
7479 }
7480
7481 static const char * fallback_mime_types[] = { "application/x-gtar",
7482 "application/x-zip",
7483 "application/x-zip-compressed",
7484 "application/zip",
7485 "application/x-zip",
7486 "application/x-tar",
7487 "application/x-7z-compressed",
7488 "application/x-rar",
7489 "application/x-rar-compressed",
7490 "application/x-jar",
7491 "application/x-java-archive",
7492 "application/x-war",
7493 "application/x-ear",
7494 "application/x-arj",
7495 "application/x-gzip",
7496 "application/x-bzip-compressed-tar",
7497 "application/x-compressed-tar",
7498 "application/x-xz-compressed-tar" };
7499
7500 gboolean
nemo_file_is_archive(NemoFile * file)7501 nemo_file_is_archive (NemoFile *file)
7502 {
7503 gchar *mime_type;
7504 gchar **file_roller_mimetypes;
7505 guint i;
7506
7507 g_return_val_if_fail (file != NULL, FALSE);
7508
7509 mime_type = nemo_file_get_mime_type (file);
7510
7511 file_roller_mimetypes = nemo_global_preferences_get_fileroller_mimetypes ();
7512
7513 if (file_roller_mimetypes != NULL) {
7514 for (i = 0; i < g_strv_length (file_roller_mimetypes); i++) {
7515 if (!strcmp (mime_type, file_roller_mimetypes[i])) {
7516 g_free (mime_type);
7517 return TRUE;
7518 }
7519 }
7520 } else {
7521 for (i = 0; i < G_N_ELEMENTS (fallback_mime_types); i++) {
7522 if (!strcmp (mime_type, fallback_mime_types[i])) {
7523 g_free (mime_type);
7524 return TRUE;
7525 }
7526 }
7527 }
7528
7529 g_free (mime_type);
7530
7531 return FALSE;
7532 }
7533
7534
7535 /**
7536 * nemo_file_is_in_trash
7537 *
7538 * Check if this file is a file in trash.
7539 * @file: NemoFile representing the file in question.
7540 *
7541 * Returns: TRUE if @file is in a trash.
7542 *
7543 **/
7544 gboolean
nemo_file_is_in_trash(NemoFile * file)7545 nemo_file_is_in_trash (NemoFile *file)
7546 {
7547 g_assert (NEMO_IS_FILE (file));
7548
7549 return nemo_directory_is_in_trash (file->details->directory);
7550 }
7551
7552 /**
7553 * nemo_file_is_in_recent
7554 *
7555 * Check if this file is a file in Recent.
7556 * @file: NemoFile representing the file in question.
7557 *
7558 * Returns: TRUE if @file is in Recent.
7559 *
7560 **/
7561 gboolean
nemo_file_is_in_recent(NemoFile * file)7562 nemo_file_is_in_recent (NemoFile *file)
7563 {
7564 g_assert (NEMO_IS_FILE (file));
7565
7566 return nemo_directory_is_in_recent (file->details->directory);
7567 }
7568
7569 /**
7570 * nemo_file_is_in_favorites
7571 *
7572 * Check if this file is a Favorite file.
7573 * @file: NemoFile representing the file in question.
7574 *
7575 * Returns: TRUE if @file is a Favorite.
7576 *
7577 **/
7578 gboolean
nemo_file_is_in_favorites(NemoFile * file)7579 nemo_file_is_in_favorites (NemoFile *file)
7580 {
7581 g_assert (NEMO_IS_FILE (file));
7582
7583 return nemo_directory_is_in_favorites (file->details->directory);
7584 }
7585
7586 /**
7587 * nemo_file_is_unavailable_favorite
7588 *
7589 * Check if this file is currently an unreachable Favorite file. This is useful
7590 * for the NemoView classes to set an appropriate font weight for unavailable files
7591 * like unmounted locations.
7592 * @file: NemoFile representing the file in question.
7593 *
7594 * Returns: TRUE if @file is a Favorite and is available.
7595 *
7596 **/
7597 gboolean
nemo_file_is_unavailable_favorite(NemoFile * file)7598 nemo_file_is_unavailable_favorite (NemoFile *file)
7599 {
7600 g_assert (NEMO_IS_FILE (file));
7601
7602 if (!nemo_directory_is_in_favorites (file->details->directory)) {
7603 return FALSE;
7604 }
7605
7606 return !nemo_file_get_boolean_metadata (file, NEMO_METADATA_KEY_FAVORITE_AVAILABLE, TRUE);
7607 }
7608
7609 /**
7610 * nemo_file_is_in_admin
7611 *
7612 * Check if this file is using admin backend.
7613 * @file: NemoFile representing the file in question.
7614 *
7615 * Returns: TRUE if @file is using admin backend.
7616 *
7617 **/
7618 gboolean
nemo_file_is_in_admin(NemoFile * file)7619 nemo_file_is_in_admin (NemoFile *file)
7620 {
7621 g_assert (NEMO_IS_FILE (file));
7622
7623 return nemo_directory_is_in_admin (file->details->directory);
7624 }
7625
7626 GError *
nemo_file_get_file_info_error(NemoFile * file)7627 nemo_file_get_file_info_error (NemoFile *file)
7628 {
7629 if (!file->details->get_info_failed) {
7630 return NULL;
7631 }
7632
7633 return file->details->get_info_error;
7634 }
7635
7636 /**
7637 * nemo_file_contains_text
7638 *
7639 * Check if this file contains text.
7640 * This is private and is used to decide whether or not to read the top left text.
7641 * @file: NemoFile representing the file in question.
7642 *
7643 * Returns: TRUE if @file has a text MIME type.
7644 *
7645 **/
7646 gboolean
nemo_file_contains_text(NemoFile * file)7647 nemo_file_contains_text (NemoFile *file)
7648 {
7649 if (file == NULL) {
7650 return FALSE;
7651 }
7652
7653 /* All text files inherit from text/plain */
7654 return nemo_file_is_mime_type (file, "text/plain");
7655 }
7656
7657 /**
7658 * nemo_file_is_executable
7659 *
7660 * Check if this file is executable at all.
7661 * @file: NemoFile representing the file in question.
7662 *
7663 * Returns: TRUE if any of the execute bits are set. FALSE if
7664 * not, or if the permissions are unknown.
7665 *
7666 **/
7667 gboolean
nemo_file_is_executable(NemoFile * file)7668 nemo_file_is_executable (NemoFile *file)
7669 {
7670 if (!file->details->has_permissions) {
7671 /* File's permissions field is not valid.
7672 * Can't access specific permissions, so return FALSE.
7673 */
7674 return FALSE;
7675 }
7676
7677 return file->details->can_execute;
7678 }
7679
7680 char *
nemo_file_get_filesystem_id(NemoFile * file)7681 nemo_file_get_filesystem_id (NemoFile *file)
7682 {
7683 return g_strdup (eel_ref_str_peek (file->details->filesystem_id));
7684 }
7685
7686 NemoFile *
nemo_file_get_trash_original_file(NemoFile * file)7687 nemo_file_get_trash_original_file (NemoFile *file)
7688 {
7689 GFile *location;
7690 NemoFile *original_file;
7691
7692 original_file = NULL;
7693
7694 if (file->details->trash_orig_path != NULL) {
7695 location = g_file_new_for_path (file->details->trash_orig_path);
7696 original_file = nemo_file_get (location);
7697 g_object_unref (location);
7698 }
7699
7700 return original_file;
7701
7702 }
7703
7704 void
nemo_file_mark_gone(NemoFile * file)7705 nemo_file_mark_gone (NemoFile *file)
7706 {
7707 NemoDirectory *directory;
7708
7709 if (file->details->is_gone)
7710 return;
7711
7712 file->details->is_gone = TRUE;
7713
7714 update_links_if_target (file);
7715
7716 /* Drop it from the symlink hash ! */
7717 remove_from_link_hash_table (file);
7718
7719 /* Let the directory know it's gone. */
7720 directory = file->details->directory;
7721 if (!nemo_file_is_self_owned (file)) {
7722 nemo_directory_remove_file (directory, file);
7723 }
7724
7725 nemo_file_clear_info (file);
7726
7727 /* FIXME bugzilla.gnome.org 42429:
7728 * Maybe we can get rid of the name too eventually, but
7729 * for now that would probably require too many if statements
7730 * everywhere anyone deals with the name. Maybe we can give it
7731 * a hard-coded "<deleted>" name or something.
7732 */
7733 }
7734
7735 /**
7736 * nemo_file_changed
7737 *
7738 * Notify the user that this file has changed.
7739 * @file: NemoFile representing the file in question.
7740 **/
7741 void
nemo_file_changed(NemoFile * file)7742 nemo_file_changed (NemoFile *file)
7743 {
7744 GList fake_list;
7745
7746 g_return_if_fail (NEMO_IS_FILE (file));
7747
7748 if (nemo_file_is_self_owned (file)) {
7749 nemo_file_emit_changed (file);
7750 } else {
7751 fake_list.data = file;
7752 fake_list.next = NULL;
7753 fake_list.prev = NULL;
7754 nemo_directory_emit_change_signals
7755 (file->details->directory, &fake_list);
7756 }
7757 }
7758
7759 /**
7760 * nemo_file_updated_deep_count_in_progress
7761 *
7762 * Notify clients that a newer deep count is available for
7763 * the directory in question.
7764 */
7765 void
nemo_file_updated_deep_count_in_progress(NemoFile * file)7766 nemo_file_updated_deep_count_in_progress (NemoFile *file) {
7767 GList *link_files, *node;
7768
7769 g_assert (NEMO_IS_FILE (file));
7770 g_assert (nemo_file_is_directory (file));
7771
7772 /* Send out a signal. */
7773 g_signal_emit (file, signals[UPDATED_DEEP_COUNT_IN_PROGRESS], 0, file);
7774
7775 /* Tell link files pointing to this object about the change. */
7776 link_files = get_link_files (file);
7777 for (node = link_files; node != NULL; node = node->next) {
7778 nemo_file_updated_deep_count_in_progress (NEMO_FILE (node->data));
7779 }
7780 nemo_file_list_free (link_files);
7781 }
7782
7783 /**
7784 * nemo_file_emit_changed
7785 *
7786 * Emit a file changed signal.
7787 * This can only be called by the directory, since the directory
7788 * also has to emit a files_changed signal.
7789 *
7790 * @file: NemoFile representing the file in question.
7791 **/
7792 void
nemo_file_emit_changed(NemoFile * file)7793 nemo_file_emit_changed (NemoFile *file)
7794 {
7795 GList *link_files, *p;
7796
7797 g_assert (NEMO_IS_FILE (file));
7798
7799 /* Send out a signal. */
7800 g_signal_emit (file, signals[CHANGED], 0, file);
7801
7802 /* Tell link files pointing to this object about the change. */
7803 link_files = get_link_files (file);
7804 for (p = link_files; p != NULL; p = p->next) {
7805 if (p->data != file) {
7806 nemo_file_changed (NEMO_FILE (p->data));
7807 }
7808 }
7809 nemo_file_list_free (link_files);
7810 }
7811
7812 /**
7813 * nemo_file_is_gone
7814 *
7815 * Check if a file has already been deleted.
7816 * @file: NemoFile representing the file in question.
7817 *
7818 * Returns: TRUE if the file is already gone.
7819 **/
7820 gboolean
nemo_file_is_gone(NemoFile * file)7821 nemo_file_is_gone (NemoFile *file)
7822 {
7823 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
7824
7825 return file->details->is_gone;
7826 }
7827
7828 /**
7829 * nemo_file_is_not_yet_confirmed
7830 *
7831 * Check if we're in a state where we don't know if a file really
7832 * exists or not, before the initial I/O is complete.
7833 * @file: NemoFile representing the file in question.
7834 *
7835 * Returns: TRUE if the file is already gone.
7836 **/
7837 gboolean
nemo_file_is_not_yet_confirmed(NemoFile * file)7838 nemo_file_is_not_yet_confirmed (NemoFile *file)
7839 {
7840 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
7841
7842 return !file->details->got_file_info;
7843 }
7844
7845 /**
7846 * nemo_file_check_if_ready
7847 *
7848 * Check whether the values for a set of file attributes are
7849 * currently available, without doing any additional work. This
7850 * is useful for callers that want to reflect updated information
7851 * when it is ready but don't want to force the work required to
7852 * obtain the information, which might be slow network calls, e.g.
7853 *
7854 * @file: The file being queried.
7855 * @file_attributes: A bit-mask with the desired information.
7856 *
7857 * Return value: TRUE if all of the specified attributes are currently readable.
7858 */
7859 gboolean
nemo_file_check_if_ready(NemoFile * file,NemoFileAttributes file_attributes)7860 nemo_file_check_if_ready (NemoFile *file,
7861 NemoFileAttributes file_attributes)
7862 {
7863 /* To be parallel with call_when_ready, return
7864 * TRUE for NULL file.
7865 */
7866 if (file == NULL) {
7867 return TRUE;
7868 }
7869
7870 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
7871
7872 return NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->check_if_ready (file, file_attributes);
7873 }
7874
7875 void
nemo_file_call_when_ready(NemoFile * file,NemoFileAttributes file_attributes,NemoFileCallback callback,gpointer callback_data)7876 nemo_file_call_when_ready (NemoFile *file,
7877 NemoFileAttributes file_attributes,
7878 NemoFileCallback callback,
7879 gpointer callback_data)
7880
7881 {
7882 if (file == NULL) {
7883 (* callback) (file, callback_data);
7884 return;
7885 }
7886
7887 g_return_if_fail (NEMO_IS_FILE (file));
7888
7889 NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->call_when_ready
7890 (file, file_attributes, callback, callback_data);
7891 }
7892
7893 void
nemo_file_cancel_call_when_ready(NemoFile * file,NemoFileCallback callback,gpointer callback_data)7894 nemo_file_cancel_call_when_ready (NemoFile *file,
7895 NemoFileCallback callback,
7896 gpointer callback_data)
7897 {
7898 g_return_if_fail (callback != NULL);
7899
7900 if (file == NULL) {
7901 return;
7902 }
7903
7904 g_return_if_fail (NEMO_IS_FILE (file));
7905
7906 NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->cancel_call_when_ready
7907 (file, callback, callback_data);
7908 }
7909
7910 static GString *
add_line(GString * string,const gchar * add,gboolean prefix_newline)7911 add_line (GString *string, const gchar *add, gboolean prefix_newline)
7912 {
7913 if (prefix_newline)
7914 string = g_string_append (string, "\n");
7915 return g_string_append (string, add);
7916 }
7917
7918 gchar *
nemo_file_construct_tooltip(NemoFile * file,NemoFileTooltipFlags flags)7919 nemo_file_construct_tooltip (NemoFile *file, NemoFileTooltipFlags flags)
7920 {
7921 gchar *scheme = nemo_file_get_uri_scheme (file);
7922 gchar *nice = NULL;
7923 gchar *tmp = NULL;
7924 gchar *date;
7925 gchar *ret;
7926
7927 if (g_strcmp0 (scheme, "x-nemo-desktop") == 0) {
7928 g_free (scheme);
7929 return NULL;
7930 }
7931
7932 GString *string = g_string_new ("");
7933
7934 tmp = nemo_file_get_display_name (file);
7935 nice = g_strdup_printf (_("Name: %s"), tmp);
7936 string = add_line (string, nice, FALSE);
7937 g_free (nice);
7938 g_free (tmp);
7939
7940 if (flags & NEMO_FILE_TOOLTIP_FLAGS_FILE_TYPE) {
7941 tmp = nemo_file_get_detailed_type_as_string (file);
7942 nice = g_strdup_printf (_("Type: %s"), tmp);
7943 string = add_line (string, nice, TRUE);
7944 g_free (tmp);
7945 g_free (nice);
7946 }
7947
7948 if (nemo_file_is_directory (file)) {
7949 guint item_count;
7950 if (nemo_file_get_directory_item_count (file, &item_count, NULL)) {
7951 gchar *launchpad_sucks = THOU_TO_STR (item_count);
7952 gchar *count = g_strdup_printf (ngettext ("%s item", "%s items", item_count), launchpad_sucks);
7953 g_free (launchpad_sucks);
7954 nice = g_strdup_printf (_("Contains: %s"), count);
7955 string = add_line (string, nice, TRUE);
7956 g_free (count);
7957 g_free (nice);
7958 }
7959 } else {
7960 gchar *size_string;
7961 gint prefix;
7962 prefix = nemo_global_preferences_get_size_prefix_preference ();
7963 size_string = g_format_size_full (nemo_file_get_size (file), prefix);
7964 nice = g_strdup_printf (_("Size: %s"), size_string);
7965 string = add_line (string, nice, TRUE);
7966 g_free (size_string);
7967 g_free (nice);
7968 }
7969
7970 if (flags & NEMO_FILE_TOOLTIP_FLAGS_ACCESS_DATE) {
7971 date = nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_ACCESSED, TRUE);
7972 tmp = g_strdup_printf (_("Accessed: %s"), date);
7973 g_free (date);
7974 string = add_line (string, tmp, TRUE);
7975 g_free (tmp);
7976 }
7977
7978 if (flags & NEMO_FILE_TOOLTIP_FLAGS_MOD_DATE) {
7979 date = nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_MODIFIED, TRUE);
7980 tmp = g_strdup_printf (_("Modified: %s"), date);
7981 g_free (date);
7982 string = add_line (string, tmp, TRUE);
7983 g_free (tmp);
7984 }
7985
7986 if (flags & NEMO_FILE_TOOLTIP_FLAGS_CREATED_DATE) {
7987 date = nemo_file_get_date_as_string (file, NEMO_DATE_TYPE_CREATED, TRUE);
7988 tmp = g_strdup_printf (_("Created: %s"), date);
7989 g_free (date);
7990 string = add_line (string, tmp, TRUE);
7991 g_free (tmp);
7992 }
7993
7994 if (flags & NEMO_FILE_TOOLTIP_FLAGS_PATH) {
7995 gchar *truncated;
7996 tmp = nemo_file_get_where_string (file);
7997 truncated = eel_str_middle_truncate (tmp, 60);
7998 nice = g_strdup_printf (_("Location: %s"), truncated);
7999 string = add_line (string, nice, TRUE);
8000 g_free (tmp);
8001 g_free (truncated);
8002 g_free (nice);
8003
8004 if (nemo_file_is_symbolic_link (file) && !nemo_file_is_in_favorites (file)) {
8005 tmp = nemo_file_get_symbolic_link_target_path (file);
8006 const gchar *existing_i18n = _("Link target:");
8007 nice = g_strdup_printf ("%s %s", existing_i18n, tmp);
8008 string = add_line (string, nice, TRUE);
8009 g_free (tmp);
8010 g_free (nice);
8011 }
8012 }
8013
8014 ret = string->str;
8015
8016 g_string_free (string, FALSE);
8017 g_free (scheme);
8018
8019 return ret;
8020 }
8021
8022 gint
nemo_file_get_monitor_number(NemoFile * file)8023 nemo_file_get_monitor_number (NemoFile *file)
8024 {
8025 if (file->details->desktop_monitor == -1) {
8026 file->details->desktop_monitor = nemo_file_get_integer_metadata (file, NEMO_METADATA_KEY_MONITOR, -1);
8027 }
8028
8029 return file->details->desktop_monitor;
8030 }
8031
8032 void
nemo_file_set_monitor_number(NemoFile * file,gint monitor)8033 nemo_file_set_monitor_number (NemoFile *file, gint monitor)
8034 {
8035 nemo_file_set_integer_metadata (file, NEMO_METADATA_KEY_MONITOR, -1, monitor);
8036 file->details->desktop_monitor = monitor;
8037 }
8038
8039 void
nemo_file_get_position(NemoFile * file,GdkPoint * point)8040 nemo_file_get_position (NemoFile *file, GdkPoint *point)
8041 {
8042 gint x, y;
8043
8044 if (file->details->cached_position_x == -1) {
8045 char *position_string;
8046 gboolean position_good;
8047 char c;
8048
8049 /* Get the current position of this icon from the metadata. */
8050 position_string = nemo_file_get_metadata (file, NEMO_METADATA_KEY_ICON_POSITION, "");
8051
8052 position_good = sscanf (position_string, " %d , %d %c", &x, &y, &c) == 2;
8053 g_free (position_string);
8054
8055 if (position_good) {
8056 point->x = x;
8057 point->y = y;
8058 } else {
8059 point->x = -1;
8060 point->y = -1;
8061 }
8062
8063 file->details->cached_position_x = x;
8064 file->details->cached_position_y = y;
8065 } else {
8066 point->x = file->details->cached_position_x;
8067 point->y = file->details->cached_position_y;
8068 }
8069 }
8070
8071 void
nemo_file_set_position(NemoFile * file,gint x,gint y)8072 nemo_file_set_position (NemoFile *file, gint x, gint y)
8073 {
8074 gchar *position_string;
8075
8076 if (x > -1 && y > -1) {
8077 position_string = g_strdup_printf ("%d,%d", x, y);
8078 } else {
8079 position_string = NULL;
8080 }
8081 nemo_file_set_metadata (file, NEMO_METADATA_KEY_ICON_POSITION, NULL, position_string);
8082
8083 file->details->cached_position_x = x;
8084 file->details->cached_position_y = y;
8085
8086 g_free (position_string);
8087 }
8088
8089 gboolean
nemo_file_get_is_desktop_orphan(NemoFile * file)8090 nemo_file_get_is_desktop_orphan (NemoFile *file)
8091 {
8092 return file->details->is_desktop_orphan;
8093 }
8094
8095 void
nemo_file_set_is_desktop_orphan(NemoFile * file,gboolean is_desktop_orphan)8096 nemo_file_set_is_desktop_orphan (NemoFile *file,
8097 gboolean is_desktop_orphan)
8098 {
8099 file->details->is_desktop_orphan = is_desktop_orphan;
8100 }
8101
8102 gboolean
nemo_file_has_thumbnail_access_problem(NemoFile * file)8103 nemo_file_has_thumbnail_access_problem (NemoFile *file)
8104 {
8105 return file->details->thumbnail_access_problem;
8106 }
8107
8108 static void
invalidate_directory_count(NemoFile * file)8109 invalidate_directory_count (NemoFile *file)
8110 {
8111 file->details->directory_count_is_up_to_date = FALSE;
8112 }
8113
8114 static void
invalidate_deep_counts(NemoFile * file)8115 invalidate_deep_counts (NemoFile *file)
8116 {
8117 file->details->deep_counts_status = NEMO_REQUEST_NOT_STARTED;
8118 }
8119
8120 static void
invalidate_mime_list(NemoFile * file)8121 invalidate_mime_list (NemoFile *file)
8122 {
8123 file->details->mime_list_is_up_to_date = FALSE;
8124 }
8125
8126 static void
invalidate_file_info(NemoFile * file)8127 invalidate_file_info (NemoFile *file)
8128 {
8129 file->details->file_info_is_up_to_date = FALSE;
8130 }
8131
8132 static void
invalidate_btime(NemoFile * file)8133 invalidate_btime (NemoFile *file)
8134 {
8135 file->details->btime_is_up_to_date = FALSE;
8136 }
8137
8138 static void
invalidate_link_info(NemoFile * file)8139 invalidate_link_info (NemoFile *file)
8140 {
8141 file->details->link_info_is_up_to_date = FALSE;
8142 }
8143
8144 static void
invalidate_thumbnail(NemoFile * file)8145 invalidate_thumbnail (NemoFile *file)
8146 {
8147 file->details->thumbnail_is_up_to_date = FALSE;
8148 }
8149
8150 static void
invalidate_mount(NemoFile * file)8151 invalidate_mount (NemoFile *file)
8152 {
8153 file->details->mount_is_up_to_date = FALSE;
8154 }
8155
8156 static void
invalidate_favorite_check(NemoFile * file)8157 invalidate_favorite_check (NemoFile *file)
8158 {
8159 file->details->favorite_checked = FALSE;
8160 }
8161
8162 void
nemo_file_invalidate_extension_info_internal(NemoFile * file)8163 nemo_file_invalidate_extension_info_internal (NemoFile *file)
8164 {
8165 if (file->details->pending_info_providers)
8166 g_list_free_full (file->details->pending_info_providers, g_object_unref);
8167
8168 file->details->pending_info_providers =
8169 nemo_module_get_extensions_for_type (NEMO_TYPE_INFO_PROVIDER);
8170 }
8171
8172 void
nemo_file_set_load_deferred_attrs(NemoFile * file,NemoFileLoadDeferredAttrs load_deferred)8173 nemo_file_set_load_deferred_attrs (NemoFile *file,
8174 NemoFileLoadDeferredAttrs load_deferred)
8175 {
8176 file->details->load_deferred_attrs = load_deferred;
8177 }
8178
8179 NemoFileLoadDeferredAttrs
nemo_file_get_load_deferred_attrs(NemoFile * file)8180 nemo_file_get_load_deferred_attrs (NemoFile *file)
8181 {
8182 return file->details->load_deferred_attrs;
8183 }
8184
8185 void
nemo_file_invalidate_attributes_internal(NemoFile * file,NemoFileAttributes file_attributes)8186 nemo_file_invalidate_attributes_internal (NemoFile *file,
8187 NemoFileAttributes file_attributes)
8188 {
8189 Request request;
8190
8191 if (file == NULL) {
8192 return;
8193 }
8194
8195 if (NEMO_IS_DESKTOP_ICON_FILE (file)) {
8196 /* Desktop icon files are always up to date.
8197 * If we invalidate their attributes they
8198 * will lose data, so we just ignore them.
8199 */
8200 return;
8201 }
8202
8203 request = nemo_directory_set_up_request (file_attributes);
8204
8205 if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) {
8206 invalidate_directory_count (file);
8207 }
8208 if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) {
8209 invalidate_deep_counts (file);
8210 }
8211 if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) {
8212 invalidate_mime_list (file);
8213 }
8214 if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) {
8215 invalidate_file_info (file);
8216 }
8217 if (REQUEST_WANTS_TYPE (request, REQUEST_BTIME)) {
8218 invalidate_btime (file);
8219 }
8220 if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) {
8221 invalidate_link_info (file);
8222 }
8223 if (REQUEST_WANTS_TYPE (request, REQUEST_EXTENSION_INFO)) {
8224 nemo_file_invalidate_extension_info_internal (file);
8225 }
8226 if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) {
8227 invalidate_thumbnail (file);
8228 }
8229 if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
8230 invalidate_mount (file);
8231 }
8232 if (REQUEST_WANTS_TYPE (request, REQUEST_FAVORITE_CHECK)) {
8233 invalidate_favorite_check (file);
8234 }
8235 /* FIXME bugzilla.gnome.org 45075: implement invalidating metadata */
8236 }
8237
8238 gboolean
nemo_file_has_open_window(NemoFile * file)8239 nemo_file_has_open_window (NemoFile *file)
8240 {
8241 return file->details->has_open_window;
8242 }
8243
8244 void
nemo_file_set_has_open_window(NemoFile * file,gboolean has_open_window)8245 nemo_file_set_has_open_window (NemoFile *file,
8246 gboolean has_open_window)
8247 {
8248 has_open_window = (has_open_window != FALSE);
8249
8250 if (file->details->has_open_window != has_open_window) {
8251 file->details->has_open_window = has_open_window;
8252 nemo_file_changed (file);
8253 }
8254 }
8255
8256
8257 gboolean
nemo_file_is_thumbnailing(NemoFile * file)8258 nemo_file_is_thumbnailing (NemoFile *file)
8259 {
8260 g_return_val_if_fail (NEMO_IS_FILE (file), FALSE);
8261
8262 return file->details->is_thumbnailing;
8263 }
8264
8265 void
nemo_file_set_is_thumbnailing(NemoFile * file,gboolean is_thumbnailing)8266 nemo_file_set_is_thumbnailing (NemoFile *file,
8267 gboolean is_thumbnailing)
8268 {
8269 g_return_if_fail (NEMO_IS_FILE (file));
8270
8271 file->details->is_thumbnailing = is_thumbnailing;
8272 }
8273
8274 /**
8275 * nemo_file_invalidate_attributes
8276 *
8277 * Invalidate the specified attributes and force a reload.
8278 * @file: NemoFile representing the file in question.
8279 * @file_attributes: attributes to froget.
8280 **/
8281
8282 void
nemo_file_invalidate_attributes(NemoFile * file,NemoFileAttributes file_attributes)8283 nemo_file_invalidate_attributes (NemoFile *file,
8284 NemoFileAttributes file_attributes)
8285 {
8286 /* Cancel possible in-progress loads of any of these attributes */
8287 nemo_directory_cancel_loading_file_attributes (file->details->directory,
8288 file,
8289 file_attributes);
8290
8291 /* Actually invalidate the values */
8292 nemo_file_invalidate_attributes_internal (file, file_attributes);
8293
8294 nemo_directory_add_file_to_work_queue (file->details->directory, file);
8295
8296 /* Kick off I/O if necessary */
8297 nemo_directory_async_state_changed (file->details->directory);
8298 }
8299
8300 NemoFileAttributes
nemo_file_get_all_attributes(void)8301 nemo_file_get_all_attributes (void)
8302 {
8303 return NEMO_FILE_ATTRIBUTE_INFO |
8304 NEMO_FILE_ATTRIBUTE_LINK_INFO |
8305 NEMO_FILE_ATTRIBUTE_DEEP_COUNTS |
8306 NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
8307 NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES |
8308 NEMO_FILE_ATTRIBUTE_EXTENSION_INFO |
8309 NEMO_FILE_ATTRIBUTE_THUMBNAIL |
8310 NEMO_FILE_ATTRIBUTE_MOUNT |
8311 NEMO_FILE_ATTRIBUTE_BTIME |
8312 NEMO_FILE_ATTRIBUTE_FAVORITE_CHECK;
8313 }
8314
8315 void
nemo_file_invalidate_all_attributes(NemoFile * file)8316 nemo_file_invalidate_all_attributes (NemoFile *file)
8317 {
8318 NemoFileAttributes all_attributes;
8319 all_attributes = nemo_file_get_all_attributes ();
8320 nemo_file_invalidate_attributes (file, all_attributes);
8321 }
8322
8323
8324 /**
8325 * nemo_file_dump
8326 *
8327 * Debugging call, prints out the contents of the file
8328 * fields.
8329 *
8330 * @file: file to dump.
8331 **/
8332 void
nemo_file_dump(NemoFile * file)8333 nemo_file_dump (NemoFile *file)
8334 {
8335 long size = file->details->deep_size;
8336 char *uri;
8337 const char *file_kind;
8338
8339 uri = nemo_file_get_uri (file);
8340 g_print ("uri: %s \n", uri);
8341 if (!file->details->got_file_info) {
8342 g_print ("no file info \n");
8343 } else if (file->details->get_info_failed) {
8344 g_print ("failed to get file info \n");
8345 } else {
8346 g_print ("size: %ld \n", size);
8347 switch (file->details->type) {
8348 case G_FILE_TYPE_REGULAR:
8349 file_kind = "regular file";
8350 break;
8351 case G_FILE_TYPE_DIRECTORY:
8352 file_kind = "folder";
8353 break;
8354 case G_FILE_TYPE_SPECIAL:
8355 file_kind = "special";
8356 break;
8357 case G_FILE_TYPE_SYMBOLIC_LINK:
8358 file_kind = "symbolic link";
8359 break;
8360 case G_FILE_TYPE_UNKNOWN:
8361 case G_FILE_TYPE_MOUNTABLE:
8362 case G_FILE_TYPE_SHORTCUT:
8363 /* FIXME should probably show details for these file types */
8364 default:
8365 file_kind = "unknown";
8366 break;
8367 }
8368 g_print ("kind: %s \n", file_kind);
8369 if (file->details->type == G_FILE_TYPE_SYMBOLIC_LINK) {
8370 g_print ("link to %s \n", file->details->symlink_name);
8371 /* FIXME bugzilla.gnome.org 42430: add following of symlinks here */
8372 }
8373 /* FIXME bugzilla.gnome.org 42431: add permissions and other useful stuff here */
8374 }
8375 g_free (uri);
8376 }
8377
8378 /**
8379 * nemo_file_list_ref
8380 *
8381 * Ref all the files in a list.
8382 * @list: GList of files.
8383 **/
8384 GList *
nemo_file_list_ref(GList * list)8385 nemo_file_list_ref (GList *list)
8386 {
8387 g_list_foreach (list, (GFunc) nemo_file_ref, NULL);
8388 return list;
8389 }
8390
8391 /**
8392 * nemo_file_list_unref
8393 *
8394 * Unref all the files in a list.
8395 * @list: GList of files.
8396 **/
8397 void
nemo_file_list_unref(GList * list)8398 nemo_file_list_unref (GList *list)
8399 {
8400 g_list_foreach (list, (GFunc) nemo_file_unref, NULL);
8401 }
8402
8403 /**
8404 * nemo_file_list_free
8405 *
8406 * Free a list of files after unrefing them.
8407 * @list: GList of files.
8408 **/
8409 void
nemo_file_list_free(GList * list)8410 nemo_file_list_free (GList *list)
8411 {
8412 nemo_file_list_unref (list);
8413 g_list_free (list);
8414 }
8415
8416 /**
8417 * nemo_file_list_copy
8418 *
8419 * Copy the list of files, making a new ref of each,
8420 * @list: GList of files.
8421 **/
8422 GList *
nemo_file_list_copy(GList * list)8423 nemo_file_list_copy (GList *list)
8424 {
8425 return g_list_copy (nemo_file_list_ref (list));
8426 }
8427
8428 GList *
nemo_file_list_from_uris(GList * uri_list)8429 nemo_file_list_from_uris (GList *uri_list)
8430 {
8431 GList *l, *file_list;
8432 const char *uri;
8433 GFile *file;
8434
8435 file_list = NULL;
8436
8437 for (l = uri_list; l != NULL; l = l->next) {
8438 uri = l->data;
8439 file = g_file_new_for_uri (uri);
8440 file_list = g_list_prepend (file_list, file);
8441 }
8442 return g_list_reverse (file_list);
8443 }
8444
8445 static gboolean
get_attributes_for_default_sort_type(NemoFile * file,gboolean * is_recent,gboolean * is_download,gboolean * is_trash)8446 get_attributes_for_default_sort_type (NemoFile *file,
8447 gboolean *is_recent,
8448 gboolean *is_download,
8449 gboolean *is_trash)
8450 {
8451 gboolean is_recent_dir, is_download_dir, is_desktop_dir, is_trash_dir, retval;
8452
8453 *is_recent = FALSE;
8454 *is_download = FALSE;
8455 *is_trash = FALSE;
8456 retval = FALSE;
8457
8458 /* special handling for certain directories */
8459 if (file && nemo_file_is_directory (file)) {
8460 is_recent_dir =
8461 nemo_file_is_in_recent (file);
8462 is_download_dir =
8463 nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_DOWNLOAD);
8464 is_desktop_dir =
8465 nemo_file_is_user_special_directory (file, G_USER_DIRECTORY_DESKTOP);
8466 is_trash_dir =
8467 nemo_file_is_in_trash (file);
8468
8469 if (is_download_dir && !is_desktop_dir) {
8470 *is_download = TRUE;
8471 retval = TRUE;
8472 } else if (is_trash_dir) {
8473 *is_trash = TRUE;
8474 retval = TRUE;
8475 } else if (is_recent_dir) {
8476 *is_recent = TRUE;
8477 retval = TRUE;
8478 }
8479 }
8480
8481 return retval;
8482 }
8483
8484 NemoFileSortType
nemo_file_get_default_sort_type(NemoFile * file,gboolean * reversed)8485 nemo_file_get_default_sort_type (NemoFile *file,
8486 gboolean *reversed)
8487 {
8488 NemoFileSortType retval;
8489 gboolean is_recent, is_download, is_trash, res;
8490
8491 retval = NEMO_FILE_SORT_NONE;
8492
8493 is_recent = is_download = is_trash = FALSE;
8494 res = get_attributes_for_default_sort_type (file, &is_recent, &is_download, &is_trash);
8495
8496 if (res) {
8497 if (is_recent) {
8498 retval = NEMO_FILE_SORT_BY_ATIME;
8499 } else if (is_download) {
8500 retval = NEMO_FILE_SORT_BY_MTIME;
8501 } else if (is_trash) {
8502 retval = NEMO_FILE_SORT_BY_TRASHED_TIME;
8503 }
8504
8505 if (reversed != NULL) {
8506 *reversed = res;
8507 }
8508 }
8509
8510 return retval;
8511 }
8512
8513 const gchar *
nemo_file_get_default_sort_attribute(NemoFile * file,gboolean * reversed)8514 nemo_file_get_default_sort_attribute (NemoFile *file,
8515 gboolean *reversed)
8516 {
8517 const gchar *retval;
8518 gboolean is_recent, is_download, is_trash, res;
8519
8520 retval = NULL;
8521 is_download = is_trash = FALSE;
8522 res = get_attributes_for_default_sort_type (file, &is_recent, &is_download, &is_trash);
8523
8524 if (res) {
8525 if (is_recent || is_download) {
8526 retval = g_quark_to_string (attribute_date_modified_q);
8527 } else if (is_trash) {
8528 retval = g_quark_to_string (attribute_trashed_on_q);
8529 }
8530
8531 if (reversed != NULL) {
8532 *reversed = res;
8533 }
8534 }
8535
8536 return retval;
8537 }
8538
8539 static int
compare_by_display_name_cover(gconstpointer a,gconstpointer b)8540 compare_by_display_name_cover (gconstpointer a, gconstpointer b)
8541 {
8542 return compare_by_display_name (NEMO_FILE (a), NEMO_FILE (b));
8543 }
8544
8545 /**
8546 * nemo_file_list_sort_by_display_name
8547 *
8548 * Sort the list of files by file name.
8549 * @list: GList of files.
8550 **/
8551 GList *
nemo_file_list_sort_by_display_name(GList * list)8552 nemo_file_list_sort_by_display_name (GList *list)
8553 {
8554 return g_list_sort (list, compare_by_display_name_cover);
8555 }
8556
8557 static GList *ready_data_list = NULL;
8558
8559 typedef struct
8560 {
8561 GList *file_list;
8562 GList *remaining_files;
8563 NemoFileListCallback callback;
8564 gpointer callback_data;
8565 } FileListReadyData;
8566
8567 static void
file_list_ready_data_free(FileListReadyData * data)8568 file_list_ready_data_free (FileListReadyData *data)
8569 {
8570 GList *l;
8571
8572 l = g_list_find (ready_data_list, data);
8573 if (l != NULL) {
8574 ready_data_list = g_list_delete_link (ready_data_list, l);
8575
8576 nemo_file_list_free (data->file_list);
8577 g_list_free (data->remaining_files);
8578 g_free (data);
8579 }
8580 }
8581
8582 static FileListReadyData *
file_list_ready_data_new(GList * file_list,NemoFileListCallback callback,gpointer callback_data)8583 file_list_ready_data_new (GList *file_list,
8584 NemoFileListCallback callback,
8585 gpointer callback_data)
8586 {
8587 FileListReadyData *data;
8588
8589 data = g_new0 (FileListReadyData, 1);
8590 data->file_list = nemo_file_list_copy (file_list);
8591 data->remaining_files = g_list_copy (file_list);
8592 data->callback = callback;
8593 data->callback_data = callback_data;
8594
8595 ready_data_list = g_list_prepend (ready_data_list, data);
8596
8597 return data;
8598 }
8599
8600 static void
file_list_file_ready_callback(NemoFile * file,gpointer user_data)8601 file_list_file_ready_callback (NemoFile *file,
8602 gpointer user_data)
8603 {
8604 FileListReadyData *data;
8605
8606 data = user_data;
8607 data->remaining_files = g_list_remove (data->remaining_files, file);
8608
8609 if (data->remaining_files == NULL) {
8610 if (data->callback) {
8611 (*data->callback) (data->file_list, data->callback_data);
8612 }
8613
8614 file_list_ready_data_free (data);
8615 }
8616 }
8617
8618 void
nemo_file_list_call_when_ready(GList * file_list,NemoFileAttributes attributes,NemoFileListHandle ** handle,NemoFileListCallback callback,gpointer callback_data)8619 nemo_file_list_call_when_ready (GList *file_list,
8620 NemoFileAttributes attributes,
8621 NemoFileListHandle **handle,
8622 NemoFileListCallback callback,
8623 gpointer callback_data)
8624 {
8625 GList *l;
8626 FileListReadyData *data;
8627 NemoFile *file;
8628
8629 g_return_if_fail (file_list != NULL);
8630
8631 data = file_list_ready_data_new
8632 (file_list, callback, callback_data);
8633
8634 if (handle) {
8635 *handle = (NemoFileListHandle *) data;
8636 }
8637
8638
8639 l = file_list;
8640 while (l != NULL) {
8641 file = NEMO_FILE (l->data);
8642 /* Need to do this here, as the list can be modified by this call */
8643 l = l->next;
8644 nemo_file_call_when_ready (file,
8645 attributes,
8646 file_list_file_ready_callback,
8647 data);
8648 }
8649 }
8650
8651 void
nemo_file_list_cancel_call_when_ready(NemoFileListHandle * handle)8652 nemo_file_list_cancel_call_when_ready (NemoFileListHandle *handle)
8653 {
8654 GList *l;
8655 NemoFile *file;
8656 FileListReadyData *data;
8657
8658 g_return_if_fail (handle != NULL);
8659
8660 data = (FileListReadyData *) handle;
8661
8662 l = g_list_find (ready_data_list, data);
8663 if (l != NULL) {
8664 for (l = data->remaining_files; l != NULL; l = l->next) {
8665 file = NEMO_FILE (l->data);
8666
8667 NEMO_FILE_CLASS (G_OBJECT_GET_CLASS (file))->cancel_call_when_ready
8668 (file, file_list_file_ready_callback, data);
8669 }
8670
8671 file_list_ready_data_free (data);
8672 }
8673 }
8674
8675 static void
thumbnail_limit_changed_callback(gpointer user_data)8676 thumbnail_limit_changed_callback (gpointer user_data)
8677 {
8678 g_settings_get (nemo_preferences,
8679 NEMO_PREFERENCES_IMAGE_FILE_THUMBNAIL_LIMIT,
8680 "t", &cached_thumbnail_limit);
8681
8682 /* Tell the world that icons might have changed. We could invent a narrower-scope
8683 * signal to mean only "thumbnails might have changed" if this ends up being slow
8684 * for some reason.
8685 */
8686 emit_change_signals_for_all_files_in_all_directories ();
8687 }
8688
8689 static void
thumbnail_size_changed_callback(gpointer user_data)8690 thumbnail_size_changed_callback (gpointer user_data)
8691 {
8692 cached_thumbnail_size = g_settings_get_int (nemo_icon_view_preferences,
8693 NEMO_PREFERENCES_ICON_VIEW_THUMBNAIL_SIZE);
8694
8695 scaled_cached_thumbnail_size = (double) cached_thumbnail_size / (double) NEMO_ICON_SIZE_STANDARD;
8696 /* Tell the world that icons might have changed. We could invent a narrower-scope
8697 * signal to mean only "thumbnails might have changed" if this ends up being slow
8698 * for some reason.
8699 */
8700 emit_change_signals_for_all_files_in_all_directories ();
8701 }
8702
8703 static void
show_thumbnails_changed_callback(gpointer user_data)8704 show_thumbnails_changed_callback (gpointer user_data)
8705 {
8706 show_image_thumbs = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS);
8707
8708 /* Tell the world that icons might have changed. We could invent a narrower-scope
8709 * signal to mean only "thumbnails might have changed" if this ends up being slow
8710 * for some reason.
8711 */
8712 emit_change_signals_for_all_files_in_all_directories ();
8713 }
8714
8715 static void
mime_type_data_changed_callback(GObject * signaller,gpointer user_data)8716 mime_type_data_changed_callback (GObject *signaller, gpointer user_data)
8717 {
8718 /* Tell the world that icons might have changed. We could invent a narrower-scope
8719 * signal to mean only "thumbnails might have changed" if this ends up being slow
8720 * for some reason.
8721 */
8722 emit_change_signals_for_all_files_in_all_directories ();
8723 }
8724
8725 static void
icon_theme_changed_callback(GtkIconTheme * icon_theme,gpointer user_data)8726 icon_theme_changed_callback (GtkIconTheme *icon_theme,
8727 gpointer user_data)
8728 {
8729 /* Clear all pixmap caches as the icon => pixmap lookup changed */
8730 nemo_icon_info_clear_caches ();
8731
8732 /* Tell the world that icons might have changed. We could invent a narrower-scope
8733 * signal to mean only "thumbnails might have changed" if this ends up being slow
8734 * for some reason.
8735 */
8736 emit_change_signals_for_all_files_in_all_directories ();
8737 }
8738
8739 static void
real_set_metadata(NemoFile * file,const char * key,const char * value)8740 real_set_metadata (NemoFile *file,
8741 const char *key,
8742 const char *value)
8743 {
8744 /* Dummy default impl */
8745 }
8746
8747 static void
real_set_metadata_as_list(NemoFile * file,const char * key,char ** value)8748 real_set_metadata_as_list (NemoFile *file,
8749 const char *key,
8750 char **value)
8751 {
8752 /* Dummy default impl */
8753 }
8754
8755 static void
nemo_file_class_init(NemoFileClass * class)8756 nemo_file_class_init (NemoFileClass *class)
8757 {
8758 GtkIconTheme *icon_theme;
8759
8760 nemo_file_info_getter = nemo_file_get_internal;
8761
8762 attribute_name_q = g_quark_from_static_string ("name");
8763 attribute_size_q = g_quark_from_static_string ("size");
8764 attribute_type_q = g_quark_from_static_string ("type");
8765 attribute_detailed_type_q = g_quark_from_static_string ("detailed_type");
8766 attribute_modification_date_q = g_quark_from_static_string ("modification_date");
8767 attribute_date_modified_q = g_quark_from_static_string ("date_modified");
8768 attribute_date_modified_full_q = g_quark_from_static_string ("date_modified_full");
8769 attribute_date_modified_with_time_q = g_quark_from_static_string ("date_modified_with_time");
8770 attribute_accessed_date_q = g_quark_from_static_string ("accessed_date");
8771 attribute_date_accessed_q = g_quark_from_static_string ("date_accessed");
8772 attribute_date_accessed_full_q = g_quark_from_static_string ("date_accessed_full");
8773 attribute_creation_date_q = g_quark_from_static_string ("creation_date");
8774 attribute_date_created_q = g_quark_from_static_string ("date_created");
8775 attribute_date_created_full_q = g_quark_from_static_string ("date_created_full");
8776 attribute_date_created_with_time_q = g_quark_from_static_string ("date_created_with_time");
8777 attribute_mime_type_q = g_quark_from_static_string ("mime_type");
8778 attribute_size_detail_q = g_quark_from_static_string ("size_detail");
8779 attribute_deep_size_q = g_quark_from_static_string ("deep_size");
8780 attribute_deep_file_count_q = g_quark_from_static_string ("deep_file_count");
8781 attribute_deep_directory_count_q = g_quark_from_static_string ("deep_directory_count");
8782 attribute_deep_total_count_q = g_quark_from_static_string ("deep_total_count");
8783 attribute_date_changed_q = g_quark_from_static_string ("date_changed");
8784 attribute_date_changed_full_q = g_quark_from_static_string ("date_changed_full");
8785 attribute_trashed_on_q = g_quark_from_static_string ("trashed_on");
8786 attribute_trashed_on_full_q = g_quark_from_static_string ("trashed_on_full");
8787 attribute_trash_orig_path_q = g_quark_from_static_string ("trash_orig_path");
8788 attribute_date_permissions_q = g_quark_from_static_string ("date_permissions");
8789 attribute_date_permissions_full_q = g_quark_from_static_string ("date_permissions_full");
8790 attribute_permissions_q = g_quark_from_static_string ("permissions");
8791 attribute_selinux_context_q = g_quark_from_static_string ("selinux_context");
8792 attribute_octal_permissions_q = g_quark_from_static_string ("octal_permissions");
8793 attribute_owner_q = g_quark_from_static_string ("owner");
8794 attribute_group_q = g_quark_from_static_string ("group");
8795 attribute_uri_q = g_quark_from_static_string ("uri");
8796 attribute_where_q = g_quark_from_static_string ("where");
8797 attribute_link_target_q = g_quark_from_static_string ("link_target");
8798 attribute_volume_q = g_quark_from_static_string ("volume");
8799 attribute_free_space_q = g_quark_from_static_string ("free_space");
8800
8801 G_OBJECT_CLASS (class)->finalize = finalize;
8802 G_OBJECT_CLASS (class)->constructor = nemo_file_constructor;
8803
8804 class->set_metadata = real_set_metadata;
8805 class->set_metadata_as_list = real_set_metadata_as_list;
8806 class->get_metadata = NULL;
8807 class->get_metadata_as_list = NULL;
8808
8809 signals[CHANGED] =
8810 g_signal_new ("changed",
8811 G_TYPE_FROM_CLASS (class),
8812 G_SIGNAL_RUN_LAST,
8813 G_STRUCT_OFFSET (NemoFileClass, changed),
8814 NULL, NULL,
8815 g_cclosure_marshal_VOID__VOID,
8816 G_TYPE_NONE, 0);
8817
8818 signals[UPDATED_DEEP_COUNT_IN_PROGRESS] =
8819 g_signal_new ("updated_deep_count_in_progress",
8820 G_TYPE_FROM_CLASS (class),
8821 G_SIGNAL_RUN_LAST,
8822 G_STRUCT_OFFSET (NemoFileClass, updated_deep_count_in_progress),
8823 NULL, NULL,
8824 g_cclosure_marshal_VOID__VOID,
8825 G_TYPE_NONE, 0);
8826
8827 g_type_class_add_private (class, sizeof (NemoFileDetails));
8828
8829 thumbnail_limit_changed_callback (NULL);
8830 g_signal_connect_swapped (nemo_preferences,
8831 "changed::" NEMO_PREFERENCES_IMAGE_FILE_THUMBNAIL_LIMIT,
8832 G_CALLBACK (thumbnail_limit_changed_callback),
8833 NULL);
8834 thumbnail_size_changed_callback (NULL);
8835 g_signal_connect_swapped (nemo_preferences,
8836 "changed::" NEMO_PREFERENCES_ICON_VIEW_THUMBNAIL_SIZE,
8837 G_CALLBACK (thumbnail_size_changed_callback),
8838 NULL);
8839 show_thumbnails_changed_callback (NULL);
8840 g_signal_connect_swapped (nemo_preferences,
8841 "changed::" NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS,
8842 G_CALLBACK (show_thumbnails_changed_callback),
8843 NULL);
8844 g_signal_connect_swapped (nemo_preferences,
8845 "changed::" NEMO_PREFERENCES_INHERIT_SHOW_THUMBNAILS,
8846 G_CALLBACK (show_thumbnails_changed_callback),
8847 NULL);
8848
8849 icon_theme = gtk_icon_theme_get_default ();
8850 g_signal_connect_object (icon_theme,
8851 "changed",
8852 G_CALLBACK (icon_theme_changed_callback),
8853 NULL, 0);
8854
8855 g_signal_connect (nemo_signaller_get_current (),
8856 "mime_data_changed",
8857 G_CALLBACK (mime_type_data_changed_callback),
8858 NULL);
8859 }
8860
8861 static void
nemo_file_add_emblem(NemoFile * file,const char * emblem_name)8862 nemo_file_add_emblem (NemoFile *file,
8863 const char *emblem_name)
8864 {
8865 if (file->details->pending_info_providers) {
8866 file->details->pending_extension_emblems = g_list_prepend (file->details->pending_extension_emblems,
8867 g_strdup (emblem_name));
8868 } else {
8869 file->details->extension_emblems = g_list_prepend (file->details->extension_emblems,
8870 g_strdup (emblem_name));
8871 }
8872
8873 nemo_file_changed (file);
8874 }
8875
8876 static void
nemo_file_add_string_attribute(NemoFile * file,const char * attribute_name,const char * value)8877 nemo_file_add_string_attribute (NemoFile *file,
8878 const char *attribute_name,
8879 const char *value)
8880 {
8881 if (file->details->pending_info_providers) {
8882 /* Lazily create hashtable */
8883 if (!file->details->pending_extension_attributes) {
8884 file->details->pending_extension_attributes =
8885 g_hash_table_new_full (g_direct_hash, g_direct_equal,
8886 NULL,
8887 (GDestroyNotify)g_free);
8888 }
8889 g_hash_table_insert (file->details->pending_extension_attributes,
8890 GINT_TO_POINTER (g_quark_from_string (attribute_name)),
8891 g_strdup (value));
8892 } else {
8893 if (!file->details->extension_attributes) {
8894 file->details->extension_attributes =
8895 g_hash_table_new_full (g_direct_hash, g_direct_equal,
8896 NULL,
8897 (GDestroyNotify)g_free);
8898 }
8899 g_hash_table_insert (file->details->extension_attributes,
8900 GINT_TO_POINTER (g_quark_from_string (attribute_name)),
8901 g_strdup (value));
8902 }
8903
8904 nemo_file_changed (file);
8905 }
8906
8907 static void
nemo_file_invalidate_extension_info(NemoFile * file)8908 nemo_file_invalidate_extension_info (NemoFile *file)
8909 {
8910 nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_EXTENSION_INFO);
8911 }
8912
8913 void
nemo_file_info_providers_done(NemoFile * file)8914 nemo_file_info_providers_done (NemoFile *file)
8915 {
8916 g_list_free_full (file->details->extension_emblems, g_free);
8917 file->details->extension_emblems = file->details->pending_extension_emblems;
8918 file->details->pending_extension_emblems = NULL;
8919
8920 if (file->details->extension_attributes) {
8921 g_hash_table_destroy (file->details->extension_attributes);
8922 }
8923
8924 file->details->extension_attributes = file->details->pending_extension_attributes;
8925 file->details->pending_extension_attributes = NULL;
8926
8927 nemo_file_changed (file);
8928 }
8929
8930 static void
nemo_file_info_iface_init(NemoFileInfoInterface * iface)8931 nemo_file_info_iface_init (NemoFileInfoInterface *iface)
8932 {
8933 iface->is_gone = nemo_file_is_gone;
8934 iface->get_name = nemo_file_get_name;
8935 iface->get_file_type = nemo_file_get_file_type;
8936 iface->get_location = nemo_file_get_location;
8937 iface->get_uri = nemo_file_get_uri;
8938 iface->get_parent_location = nemo_file_get_parent_location;
8939 iface->get_parent_uri = nemo_file_get_parent_uri;
8940 iface->get_parent_info = nemo_file_get_parent;
8941 iface->get_mount = nemo_file_get_mount;
8942 iface->get_uri_scheme = nemo_file_get_uri_scheme;
8943 iface->get_activation_uri = nemo_file_get_activation_uri;
8944 iface->get_mime_type = nemo_file_get_mime_type;
8945 iface->is_mime_type = nemo_file_is_mime_type;
8946 iface->is_directory = nemo_file_is_directory;
8947 iface->can_write = nemo_file_can_write;
8948 iface->add_emblem = nemo_file_add_emblem;
8949 iface->get_string_attribute = nemo_file_get_string_attribute;
8950 iface->add_string_attribute = nemo_file_add_string_attribute;
8951 iface->invalidate_extension_info = nemo_file_invalidate_extension_info;
8952 }
8953
8954 #if !defined (NEMO_OMIT_SELF_CHECK)
8955
8956 void
nemo_self_check_file(void)8957 nemo_self_check_file (void)
8958 {
8959 NemoFile *file_1;
8960 NemoFile *file_2;
8961 GList *list;
8962
8963 /* refcount checks */
8964
8965 EEL_CHECK_INTEGER_RESULT (nemo_directory_number_outstanding (), 0);
8966
8967 file_1 = nemo_file_get_by_uri ("file:///home/");
8968
8969 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1);
8970 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1->details->directory)->ref_count, 1);
8971 EEL_CHECK_INTEGER_RESULT (nemo_directory_number_outstanding (), 1);
8972
8973 nemo_file_unref (file_1);
8974
8975 EEL_CHECK_INTEGER_RESULT (nemo_directory_number_outstanding (), 0);
8976
8977 file_1 = nemo_file_get_by_uri ("file:///etc");
8978 file_2 = nemo_file_get_by_uri ("file:///usr");
8979
8980 list = NULL;
8981 list = g_list_prepend (list, file_1);
8982 list = g_list_prepend (list, file_2);
8983
8984 nemo_file_list_ref (list);
8985
8986 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 2);
8987 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 2);
8988
8989 nemo_file_list_unref (list);
8990
8991 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1);
8992 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 1);
8993
8994 nemo_file_list_free (list);
8995
8996 EEL_CHECK_INTEGER_RESULT (nemo_directory_number_outstanding (), 0);
8997
8998
8999 /* name checks */
9000 file_1 = nemo_file_get_by_uri ("file:///home/");
9001
9002 EEL_CHECK_STRING_RESULT (nemo_file_get_name (file_1), "home");
9003
9004 EEL_CHECK_BOOLEAN_RESULT (nemo_file_get_by_uri ("file:///home/") == file_1, TRUE);
9005 nemo_file_unref (file_1);
9006
9007 EEL_CHECK_BOOLEAN_RESULT (nemo_file_get_by_uri ("file:///home") == file_1, TRUE);
9008 nemo_file_unref (file_1);
9009
9010 nemo_file_unref (file_1);
9011
9012 file_1 = nemo_file_get_by_uri ("file:///home");
9013 EEL_CHECK_STRING_RESULT (nemo_file_get_name (file_1), "home");
9014 nemo_file_unref (file_1);
9015
9016 #if 0
9017 /* ALEX: I removed this, because it was breaking distchecks.
9018 * It used to work, but when canonical uris changed from
9019 * foo: to foo:/// it broke. I don't expect it to matter
9020 * in real life */
9021 file_1 = nemo_file_get_by_uri (":");
9022 EEL_CHECK_STRING_RESULT (nemo_file_get_name (file_1), ":");
9023 nemo_file_unref (file_1);
9024 #endif
9025
9026 file_1 = nemo_file_get_by_uri ("eazel:");
9027 EEL_CHECK_STRING_RESULT (nemo_file_get_name (file_1), "eazel");
9028 nemo_file_unref (file_1);
9029
9030 /* sorting */
9031 file_1 = nemo_file_get_by_uri ("file:///etc");
9032 file_2 = nemo_file_get_by_uri ("file:///usr");
9033
9034 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1);
9035 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 1);
9036
9037 EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_DISPLAY_NAME, FALSE, FALSE) < 0, TRUE);
9038 EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_2, NEMO_FILE_SORT_BY_DISPLAY_NAME, FALSE, TRUE) > 0, TRUE);
9039 EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_1, NEMO_FILE_SORT_BY_DISPLAY_NAME, FALSE, FALSE) == 0, TRUE);
9040 EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_1, NEMO_FILE_SORT_BY_DISPLAY_NAME, TRUE, FALSE) == 0, TRUE);
9041 EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_1, NEMO_FILE_SORT_BY_DISPLAY_NAME, FALSE, TRUE) == 0, TRUE);
9042 EEL_CHECK_BOOLEAN_RESULT (nemo_file_compare_for_sort (file_1, file_1, NEMO_FILE_SORT_BY_DISPLAY_NAME, TRUE, TRUE) == 0, TRUE);
9043
9044 nemo_file_unref (file_1);
9045 nemo_file_unref (file_2);
9046 }
9047
9048 #endif /* !NEMO_OMIT_SELF_CHECK */
9049