diff options
author | Alexander Larsson <alexl@redhat.com> | 2003-05-15 17:19:27 +0000 |
---|---|---|
committer | Alexander Larsson <alexl@src.gnome.org> | 2003-05-15 17:19:27 +0000 |
commit | 119586813a7a7be9a0fd9fd6f2b654ee53779c38 (patch) | |
tree | 7e12c677652f3454f79a79823b3963207713d14b /libnautilus-private | |
parent | 3d670f0cda514118e0762ed4ed170c2ae9659810 (diff) | |
download | nautilus-119586813a7a7be9a0fd9fd6f2b654ee53779c38.tar.gz |
Added new files.
2003-05-15 Alexander Larsson <alexl@redhat.com>
* libnautilus-private/Makefile.am:
Added new files.
* libnautilus-private/apps_nautilus_preferences.schemas.in:
* libnautilus-private/nautilus-global-preferences.[ch]:
New prefs for home and trash links.
* libnautilus-private/nautilus-desktop-directory.[ch]:
New files. Implements the NautilusDesktop object for the
virtual x-nautilus-desktop: uri. The directory merges the contents
of the directory with the real desktop directory.
* libnautilus-private/nautilus-desktop-directory-file.[ch]:
New files. Implements the Nautilusfile corresponding to
NautilusDestkopDirectory.
* libnautilus-private/nautilus-desktop-icon-file.[ch]:
New files.
Implement NautilusFile for a virtual file in a NautilusDesktopDirectory.
Gets all the actual file data from a NautilusDesktopLink.
* libnautilus-private/nautilus-desktop-link-monitor.[ch]:
New files.
Keep track of home and trash visibility prefs and mounted volumes and
create/destroy corresponding NautilusDesktopLink object.
* libnautilus-private/nautilus-desktop-link.[ch]:
New files.
Keeps track of all the real information in a desktop icon link.
These are home, trash and volume links at the moment.
* libnautilus-private/nautilus-directory-async.c:
Indentation correction.
* libnautilus-private/nautilus-directory.c:
(nautilus_directory_new):
Create NautilusDesktopDirectory objects for x-nautilus-desktop: uris
* libnautilus-private/nautilus-dnd.c: (nautilus_drag_items_local):
Handle NULL GnomeVFSURIs.
(nautilus_drag_items_on_desktop): New function to check if items
are on the desktop.
(nautilus_drag_default_drop_action_for_icons):
Special case desktop uris.
(nautilus_drag_selection_includes_special_link):
Convert from old-style special links to current.
* libnautilus-private/nautilus-dnd.h:
New function nautilus_drag_items_on_desktop.
* libnautilus-private/nautilus-file-operations.c:
(is_special_link), (nautilus_file_operations_copy_move):
Convert from old-style special links to current.
(nautilus_file_operations_delete):
Special case desktop links
* libnautilus-private/nautilus-file-utilities.[ch]:
(nautilus_get_desktop_directory):
(nautilus_get_gmc_desktop_directory):
Change desktop dir to ~/Desktop
(nautilus_get_desktop_directory_uri):
New function to return desktop dir as a uri.
* libnautilus-private/nautilus-file.c:
(nautilus_file_new_from_relative_uri),
(nautilus_file_get_internal):
Handle creation of desktop icon files.
(nautilus_file_can_rename), (rename_guts),
(nautilus_file_get_drop_target_uri):
Update for new special links.
(nautilus_file_is_in_desktop):
Update for new desktop dir.
(nautilus_file_get_uri):
Fix uris for self owned files. This changed due to
the new canonicalization rules for foo:
* libnautilus-private/nautilus-icon-dnd.c:
(nautilus_icon_container_selection_items_local),
(handle_nonlocal_move):
Handle desktop uri.
* src/Nautilus_shell.server.in:
icon view handles x-nautilus-desktop: uris
* src/nautilus-application.c: (finish_startup):
Initialize the desktop link monitor
* src/nautilus-desktop-window.c:
(nautilus_desktop_window_update_directory):
Show x-nautilus-desktop:
* src/file-manager/fm-desktop-icon-view.c:
(fm_desktop_icon_view_finalize), (fm_desktop_icon_view_init),
(volume_ops_callback), (trash_link_is_selection),
(volume_link_is_selection), (volume_link_device_type),
(real_supports_zooming):
* src/file-manager/fm-directory-view.c:
Remove lots of old support for desktop icon.
Reimplement some of it with the new desktop icon support.
* src/file-manager/fm-directory-view.h:
New function fm_directory_view_get_backing_uri
* src/file-manager/fm-icon-container.c:
(fm_icon_container_get_icon_text):
Don't show extra text for desktop icons
(get_sort_category): Update for new desktop icons
* src/file-manager/fm-icon-view.c: (icon_view_handle_uri_list):
Use get_backing_uri()
* src/file-manager/fm-properties-window.c: (get_target_file):
Use the new desktop icon support.
* libnautilus-private/nautilus-icon-container.c:
(lay_down_icons_tblr):
Don't loop forever if icon doesn't in the height of the container.
Diffstat (limited to 'libnautilus-private')
24 files changed, 2826 insertions, 111 deletions
diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am index ec2311410..65a256f69 100644 --- a/libnautilus-private/Makefile.am +++ b/libnautilus-private/Makefile.am @@ -56,6 +56,16 @@ libnautilus_private_la_SOURCES = \ nautilus-customization-data.h \ nautilus-default-file-icon.c \ nautilus-default-file-icon.h \ + nautilus-desktop-directory.c \ + nautilus-desktop-directory.h \ + nautilus-desktop-directory-file.c \ + nautilus-desktop-directory-file.h \ + nautilus-desktop-icon-file.c \ + nautilus-desktop-icon-file.h \ + nautilus-desktop-link.c \ + nautilus-desktop-link.h \ + nautilus-desktop-link-monitor.c \ + nautilus-desktop-link-monitor.h \ nautilus-directory-async.c \ nautilus-directory-background.c \ nautilus-directory-background.h \ diff --git a/libnautilus-private/apps_nautilus_preferences.schemas.in b/libnautilus-private/apps_nautilus_preferences.schemas.in index a12eed0fc..283c8b888 100644 --- a/libnautilus-private/apps_nautilus_preferences.schemas.in +++ b/libnautilus-private/apps_nautilus_preferences.schemas.in @@ -700,6 +700,64 @@ </long> </locale> </schema> - + + <schema> + <key>/schemas/apps/nautilus/desktop/home_icon_visible</key> + <applyto>/apps/nautilus/desktop/home_icon_visible</applyto> + <owner>nautilus</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Home icon visible on desktop</short> + <long> + If this is set to true, an icon linking to the home directory + will be put on the desktop. + </long> + </locale> + </schema> + + <schema> + <key>/schemas/apps/nautilus/desktop/trash_icon_visible</key> + <applyto>/apps/nautilus/desktop/trash_icon_visible</applyto> + <owner>nautilus</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Trash icon visible on desktop</short> + <long> + If this is set to true, an icon linking to the trash + will be put on the desktop. + </long> + </locale> + </schema> + + <schema> + <key>/schemas/apps/nautilus/desktop/home_icon_name</key> + <applyto>/apps/nautilus/desktop/home_icon_name</applyto> + <owner>nautilus</owner> + <type>string</type> + <locale name="C"> + <short>Desktop home icon name</short> + <long> + This name can be set if you want a custom name + for the home link icon on the desktop. + </long> + </locale> + </schema> + + <schema> + <key>/schemas/apps/nautilus/desktop/trash_icon_name</key> + <applyto>/apps/nautilus/desktop/trash_icon_name</applyto> + <owner>nautilus</owner> + <type>string</type> + <locale name="C"> + <short>Desktop trash icon name</short> + <long> + This name can be set if you want a custom name + for the trash icon on the desktop. + </long> + </locale> + </schema> + </schemalist> </gconfschemafile> diff --git a/libnautilus-private/nautilus-desktop-directory-file.c b/libnautilus-private/nautilus-desktop-directory-file.c new file mode 100644 index 000000000..49bd4d84c --- /dev/null +++ b/libnautilus-private/nautilus-desktop-directory-file.c @@ -0,0 +1,549 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-desktop-directory-file.c: Subclass of NautilusFile to help implement the + virtual desktop. + + Copyright (C) 2003 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Alexander Larsson <alexl@redhat.com> +*/ + +#include <config.h> +#include "nautilus-desktop-directory-file.h" + +#include "nautilus-directory-notify.h" +#include "nautilus-directory-private.h" +#include "nautilus-file-attributes.h" +#include "nautilus-file-private.h" +#include "nautilus-file-utilities.h" +#include <eel/eel-glib-extensions.h> +#include <eel/eel-gtk-macros.h> +#include "nautilus-desktop-directory.h" +#include <gtk/gtksignal.h> +#include <libgnome/gnome-i18n.h> +#include <string.h> + +struct NautilusDesktopDirectoryFileDetails { + NautilusDesktopDirectory *desktop_directory; + + NautilusFile *real_dir_file; + + GHashTable *callbacks; + GHashTable *monitors; +}; + +typedef struct { + NautilusDesktopDirectoryFile *desktop_file; + NautilusFileCallback callback; + gpointer callback_data; + + NautilusFileAttributes delegated_attributes; + NautilusFileAttributes non_delegated_attributes; + + GList *non_ready_files; + + gboolean initializing; +} DesktopCallback; + +typedef struct { + NautilusDesktopDirectoryFile *desktop_file; + + NautilusFileAttributes delegated_attributes; + NautilusFileAttributes non_delegated_attributes; +} DesktopMonitor; + + +static void nautilus_desktop_directory_file_init (gpointer object, + gpointer klass); +static void nautilus_desktop_directory_file_class_init (gpointer klass); + +EEL_CLASS_BOILERPLATE (NautilusDesktopDirectoryFile, + nautilus_desktop_directory_file, + NAUTILUS_TYPE_FILE) + +static guint +desktop_callback_hash (gconstpointer desktop_callback_as_pointer) +{ + const DesktopCallback *desktop_callback; + + desktop_callback = desktop_callback_as_pointer; + return GPOINTER_TO_UINT (desktop_callback->callback) + ^ GPOINTER_TO_UINT (desktop_callback->callback_data); +} + +static gboolean +desktop_callback_equal (gconstpointer desktop_callback_as_pointer, + gconstpointer desktop_callback_as_pointer_2) +{ + const DesktopCallback *desktop_callback, *desktop_callback_2; + + desktop_callback = desktop_callback_as_pointer; + desktop_callback_2 = desktop_callback_as_pointer_2; + + return desktop_callback->callback == desktop_callback_2->callback + && desktop_callback->callback_data == desktop_callback_2->callback_data; +} + + +static void +real_file_changed_callback (NautilusFile *real_file, + gpointer callback_data) +{ + NautilusDesktopDirectoryFile *desktop_file; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (callback_data); + nautilus_file_changed (NAUTILUS_FILE (desktop_file)); +} + +static NautilusFileAttributes +get_delegated_attributes_mask (void) +{ + return NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS | + NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | + NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES; +} + +static void +partition_attributes (NautilusFileAttributes attributes, + NautilusFileAttributes *delegated_attributes, + NautilusFileAttributes *non_delegated_attributes) +{ + NautilusFileAttributes mask; + + mask = get_delegated_attributes_mask (); + + *delegated_attributes = attributes & mask; + *non_delegated_attributes = attributes & ~mask; +} + +static void +desktop_directory_file_monitor_add (NautilusFile *file, + gconstpointer client, + NautilusFileAttributes attributes) +{ + NautilusDesktopDirectoryFile *desktop_file; + DesktopMonitor *monitor; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file); + + /* Map the client to a unique value so this doesn't interfere + * with direct monitoring of the file by the same client. + */ + monitor = g_hash_table_lookup (desktop_file->details->monitors, client); + if (monitor != NULL) { + g_assert (monitor->desktop_file == desktop_file); + } else { + monitor = g_new0 (DesktopMonitor, 1); + monitor->desktop_file = desktop_file; + g_hash_table_insert (desktop_file->details->monitors, + (gpointer) client, monitor); + } + + partition_attributes (attributes, + &monitor->delegated_attributes, + &monitor->non_delegated_attributes); + + /* Pawn off partioned attributes to real dir file */ + nautilus_file_monitor_add (desktop_file->details->real_dir_file, + monitor, monitor->delegated_attributes); + + /* Do the rest ourself */ + nautilus_directory_monitor_add_internal + (file->details->directory, file, + monitor, TRUE, TRUE, + monitor->non_delegated_attributes, + NULL, NULL); +} + +static void +desktop_directory_file_monitor_remove (NautilusFile *file, + gconstpointer client) +{ + NautilusDesktopDirectoryFile *desktop_file; + DesktopMonitor *monitor; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file); + + /* Map the client to the value used by the earlier add call. */ + monitor = g_hash_table_lookup (desktop_file->details->monitors, client); + if (monitor == NULL) { + return; + } + + /* Call through to the real file remove calls. */ + g_hash_table_remove (desktop_file->details->monitors, client); + + /* Remove the locally handled parts */ + nautilus_directory_monitor_remove_internal + (file->details->directory, file, client); +} + +static void +desktop_callback_destroy (DesktopCallback *desktop_callback) +{ + g_assert (desktop_callback != NULL); + g_assert (NAUTILUS_IS_DESKTOP_DIRECTORY_FILE (desktop_callback->desktop_file)); + + nautilus_file_unref (NAUTILUS_FILE (desktop_callback->desktop_file)); + g_list_free (desktop_callback->non_ready_files); + g_free (desktop_callback); +} + +static void +desktop_callback_check_done (DesktopCallback *desktop_callback) +{ + /* Check if we are ready. */ + if (desktop_callback->initializing || + desktop_callback->non_ready_files != NULL) { + return; + } + + /* Remove from the hash table before sending it. */ + g_hash_table_remove (desktop_callback->desktop_file->details->callbacks, + desktop_callback); + + /* We are ready, so do the real callback. */ + (* desktop_callback->callback) (NAUTILUS_FILE (desktop_callback->desktop_file), + desktop_callback->callback_data); + + /* And we are done. */ + desktop_callback_destroy (desktop_callback); +} + +static void +desktop_callback_remove_file (DesktopCallback *desktop_callback, + NautilusFile *file) +{ + desktop_callback->non_ready_files = g_list_remove + (desktop_callback->non_ready_files, file); + desktop_callback_check_done (desktop_callback); +} + +static void +ready_callback (NautilusFile *file, + gpointer callback_data) +{ + DesktopCallback *desktop_callback; + + g_assert (NAUTILUS_IS_FILE (file)); + g_assert (callback_data != NULL); + + desktop_callback = callback_data; + g_assert (g_list_find (desktop_callback->non_ready_files, file) != NULL); + + desktop_callback_remove_file (desktop_callback, file); +} + +static void +desktop_directory_file_call_when_ready (NautilusFile *file, + NautilusFileAttributes attributes, + NautilusFileCallback callback, + gpointer callback_data) + +{ + NautilusDesktopDirectoryFile *desktop_file; + DesktopCallback search_key, *desktop_callback; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file); + + /* Check to be sure we aren't overwriting. */ + search_key.callback = callback; + search_key.callback_data = callback_data; + if (g_hash_table_lookup (desktop_file->details->callbacks, &search_key) != NULL) { + g_warning ("tried to add a new callback while an old one was pending"); + return; + } + + /* Create a desktop_callback record. */ + desktop_callback = g_new0 (DesktopCallback, 1); + nautilus_file_ref (file); + desktop_callback->desktop_file = desktop_file; + desktop_callback->callback = callback; + desktop_callback->callback_data = callback_data; + desktop_callback->initializing = TRUE; + + partition_attributes (attributes, + &desktop_callback->delegated_attributes, + &desktop_callback->non_delegated_attributes); + + desktop_callback->non_ready_files = g_list_prepend + (desktop_callback->non_ready_files, file); + desktop_callback->non_ready_files = g_list_prepend + (desktop_callback->non_ready_files, desktop_file->details->real_dir_file); + + /* Put it in the hash table. */ + g_hash_table_insert (desktop_file->details->callbacks, + desktop_callback, desktop_callback); + + /* Now connect to each file's call_when_ready. */ + nautilus_directory_call_when_ready_internal + (file->details->directory, file, + desktop_callback->non_delegated_attributes, + FALSE, NULL, ready_callback, desktop_callback); + nautilus_file_call_when_ready + (desktop_file->details->real_dir_file, + desktop_callback->delegated_attributes, + ready_callback, desktop_callback); + + desktop_callback->initializing = FALSE; + + /* Check if any files became read while we were connecting up + * the call_when_ready callbacks (also handles the pathological + * case where there are no files at all). + */ + desktop_callback_check_done (desktop_callback); + +} + +static void +desktop_directory_file_cancel_call_when_ready (NautilusFile *file, + NautilusFileCallback callback, + gpointer callback_data) +{ + NautilusDesktopDirectoryFile *desktop_file; + DesktopCallback search_key, *desktop_callback; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file); + + /* Find the entry in the table. */ + search_key.callback = callback; + search_key.callback_data = callback_data; + desktop_callback = g_hash_table_lookup (desktop_file->details->callbacks, &search_key); + if (desktop_callback == NULL) { + return; + } + + /* Remove from the hash table before working with it. */ + g_hash_table_remove (desktop_callback->desktop_file->details->callbacks, desktop_callback); + + /* Tell the real directory to cancel the call. */ + nautilus_directory_cancel_callback_internal + (file->details->directory, file, + NULL, ready_callback, desktop_callback); + + nautilus_file_cancel_call_when_ready + (desktop_file->details->real_dir_file, + ready_callback, desktop_callback); + + desktop_callback_destroy (desktop_callback); +} + +static gboolean +real_check_if_ready (NautilusFile *file, + NautilusFileAttributes attributes) +{ + return nautilus_directory_check_if_ready_internal + (file->details->directory, file, + attributes); +} + +static gboolean +desktop_directory_file_check_if_ready (NautilusFile *file, + NautilusFileAttributes attributes) +{ + NautilusFileAttributes delegated_attributes, non_delegated_attributes; + NautilusDesktopDirectoryFile *desktop_file; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file); + + partition_attributes (attributes, + &delegated_attributes, + &non_delegated_attributes); + + return real_check_if_ready (file, non_delegated_attributes) && + nautilus_file_check_if_ready (desktop_file->details->real_dir_file, + delegated_attributes); +} + +static GnomeVFSFileType +desktop_directory_file_get_file_type (NautilusFile *file) +{ + return GNOME_VFS_FILE_TYPE_DIRECTORY; +} + +static gboolean +desktop_directory_file_get_item_count (NautilusFile *file, + guint *count, + gboolean *count_unreadable) +{ + NautilusDesktopDirectoryFile *desktop_file; + gboolean got_count; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file); + + got_count = nautilus_file_get_directory_item_count (desktop_file->details->real_dir_file, + count, + count_unreadable); + + if (count) { + *count += g_list_length (file->details->directory->details->file_list); + } + + return got_count; +} + +static NautilusRequestStatus +desktop_directory_file_get_deep_counts (NautilusFile *file, + guint *directory_count, + guint *file_count, + guint *unreadable_directory_count, + GnomeVFSFileSize *total_size) +{ + NautilusDesktopDirectoryFile *desktop_file; + NautilusRequestStatus status; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file); + + status = nautilus_file_get_deep_counts (desktop_file->details->real_dir_file, + directory_count, + file_count, + unreadable_directory_count, + total_size); + + if (file_count) { + *file_count += g_list_length (file->details->directory->details->file_list); + } + + return status; +} + +static gboolean +desktop_directory_file_get_date (NautilusFile *file, + NautilusDateType date_type, + time_t *date) +{ + NautilusDesktopDirectoryFile *desktop_file; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (file); + + return nautilus_file_get_date (desktop_file->details->real_dir_file, + date_type, + date); +} + +static char * +desktop_directory_file_get_where_string (NautilusFile *file) +{ + return g_strdup (_("on the desktop")); +} + + +static void +monitor_destroy (gpointer data) +{ + DesktopMonitor *monitor = data; + + nautilus_file_monitor_remove + (NAUTILUS_FILE (monitor->desktop_file->details->real_dir_file), monitor); + g_free (monitor); +} + +static void +nautilus_desktop_directory_file_init (gpointer object, gpointer klass) +{ + NautilusDesktopDirectoryFile *desktop_file; + NautilusDesktopDirectory *desktop_directory; + NautilusDirectory *real_dir; + NautilusFile *real_dir_file; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (object); + + desktop_directory = NAUTILUS_DESKTOP_DIRECTORY (nautilus_directory_get (EEL_DESKTOP_URI)); + + desktop_file->details = g_new0 (NautilusDesktopDirectoryFileDetails, 1); + desktop_file->details->desktop_directory = desktop_directory; + + desktop_file->details->callbacks = g_hash_table_new + (desktop_callback_hash, desktop_callback_equal); + desktop_file->details->monitors = g_hash_table_new_full (NULL, NULL, + NULL, monitor_destroy); + + real_dir = nautilus_desktop_directory_get_real_directory (desktop_directory); + real_dir_file = nautilus_directory_get_corresponding_file (real_dir); + nautilus_directory_unref (real_dir); + + desktop_file->details->real_dir_file = real_dir_file; + + g_signal_connect_object (real_dir_file, "changed", + G_CALLBACK (real_file_changed_callback), desktop_file, 0); +} + + +static void +desktop_callback_remove_file_cover (gpointer key, + gpointer value, + gpointer callback_data) +{ + desktop_callback_remove_file + (value, NAUTILUS_FILE (callback_data)); +} + + +static void +desktop_finalize (GObject *object) +{ + NautilusDesktopDirectoryFile *desktop_file; + NautilusDesktopDirectory *desktop_directory; + + desktop_file = NAUTILUS_DESKTOP_DIRECTORY_FILE (object); + desktop_directory = desktop_file->details->desktop_directory; + + /* Todo: ghash now safe? */ + eel_g_hash_table_safe_for_each + (desktop_file->details->callbacks, + desktop_callback_remove_file_cover, + desktop_file->details->real_dir_file); + + if (g_hash_table_size (desktop_file->details->callbacks) != 0) { + g_warning ("call_when_ready still pending when desktop virtual file is destroyed"); + } + + g_hash_table_destroy (desktop_file->details->callbacks); + g_hash_table_destroy (desktop_file->details->monitors); + + nautilus_file_unref (desktop_file->details->real_dir_file); + + g_free (desktop_file->details); + + nautilus_directory_unref (NAUTILUS_DIRECTORY (desktop_directory)); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +nautilus_desktop_directory_file_class_init (gpointer klass) +{ + GObjectClass *object_class; + NautilusFileClass *file_class; + + object_class = G_OBJECT_CLASS (klass); + file_class = NAUTILUS_FILE_CLASS (klass); + + object_class->finalize = desktop_finalize; + + file_class->monitor_add = desktop_directory_file_monitor_add; + file_class->monitor_remove = desktop_directory_file_monitor_remove; + file_class->call_when_ready = desktop_directory_file_call_when_ready; + file_class->cancel_call_when_ready = desktop_directory_file_cancel_call_when_ready; + file_class->check_if_ready = desktop_directory_file_check_if_ready; + file_class->get_file_type = desktop_directory_file_get_file_type; + file_class->get_item_count = desktop_directory_file_get_item_count; + file_class->get_deep_counts = desktop_directory_file_get_deep_counts; + file_class->get_date = desktop_directory_file_get_date; + file_class->get_where_string = desktop_directory_file_get_where_string; +} diff --git a/libnautilus-private/nautilus-desktop-directory-file.h b/libnautilus-private/nautilus-desktop-directory-file.h new file mode 100644 index 000000000..9f264b227 --- /dev/null +++ b/libnautilus-private/nautilus-desktop-directory-file.h @@ -0,0 +1,55 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-desktop-directory-file.h: Subclass of NautilusFile to implement the + the case of the desktop directory + + Copyright (C) 2003 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Alexander Larsson <alexl@redhat.com> +*/ + +#ifndef NAUTILUS_DESKTOP_DIRECTORY_FILE_H +#define NAUTILUS_DESKTOP_DIRECTORY_FILE_H + +#include <libnautilus-private/nautilus-file.h> + +#define NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE \ + (nautilus_desktop_directory_file_get_type ()) +#define NAUTILUS_DESKTOP_DIRECTORY_FILE(obj) \ + (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE, NautilusDesktopDirectoryFile)) +#define NAUTILUS_DESKTOP_DIRECTORY_FILE_CLASS(klass) \ + (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE, NautilusDesktopDirectoryFileClass)) +#define NAUTILUS_IS_DESKTOP_DIRECTORY_FILE(obj) \ + (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE)) +#define NAUTILUS_IS_DESKTOP_DIRECTORY_FILE_CLASS(klass) \ + (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE)) + +typedef struct NautilusDesktopDirectoryFileDetails NautilusDesktopDirectoryFileDetails; + +typedef struct { + NautilusFile parent_slot; + NautilusDesktopDirectoryFileDetails *details; +} NautilusDesktopDirectoryFile; + +typedef struct { + NautilusFileClass parent_slot; +} NautilusDesktopDirectoryFileClass; + +GType nautilus_desktop_directory_file_get_type (void); + +#endif /* NAUTILUS_DESKTOP_DIRECTORY_FILE_H */ diff --git a/libnautilus-private/nautilus-desktop-directory.c b/libnautilus-private/nautilus-desktop-directory.c new file mode 100644 index 000000000..94d8e624c --- /dev/null +++ b/libnautilus-private/nautilus-desktop-directory.c @@ -0,0 +1,496 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-desktop-directory.c: Subclass of NautilusDirectory to implement + a virtual directory consisting of the desktop directory and the desktop + icons + + Copyright (C) 2003 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Alexander Larsson <alexl@redhat.com> +*/ + +#include <config.h> +#include "nautilus-desktop-directory.h" + +#include "nautilus-directory-private.h" +#include "nautilus-file.h" +#include "nautilus-file-private.h" +#include "nautilus-file-utilities.h" +#include <eel/eel-glib-extensions.h> +#include <libgnomevfs/gnome-vfs-utils.h> +#include <gtk/gtksignal.h> +#include <libgnome/gnome-macros.h> + +struct NautilusDesktopDirectoryDetails { + NautilusDirectory *real_directory; + GHashTable *callbacks; + GHashTable *monitors; +}; + +typedef struct { + NautilusDesktopDirectory *desktop_dir; + NautilusDirectoryCallback callback; + gpointer callback_data; + + NautilusFileAttributes wait_for_attributes; + gboolean wait_for_file_list; + + GList *non_ready_directories; + GList *merged_file_list; +} MergedCallback; + + +typedef struct { + NautilusDesktopDirectory *desktop_dir; + + gboolean monitor_hidden_files; + gboolean monitor_backup_files; + NautilusFileAttributes monitor_attributes; +} MergedMonitor; + + +GNOME_CLASS_BOILERPLATE (NautilusDesktopDirectory, nautilus_desktop_directory, + NautilusDirectory, NAUTILUS_TYPE_DIRECTORY) + + +static gboolean +desktop_contains_file (NautilusDirectory *directory, + NautilusFile *file) +{ + NautilusDesktopDirectory *desktop; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); + + if (nautilus_directory_contains_file (desktop->details->real_directory, file)) { + return TRUE; + } + + return file->details->directory == directory; +} + +static guint +merged_callback_hash (gconstpointer merged_callback_as_pointer) +{ + const MergedCallback *merged_callback; + + merged_callback = merged_callback_as_pointer; + return GPOINTER_TO_UINT (merged_callback->callback) + ^ GPOINTER_TO_UINT (merged_callback->callback_data); +} + +static gboolean +merged_callback_equal (gconstpointer merged_callback_as_pointer, + gconstpointer merged_callback_as_pointer_2) +{ + const MergedCallback *merged_callback, *merged_callback_2; + + merged_callback = merged_callback_as_pointer; + merged_callback_2 = merged_callback_as_pointer_2; + + return merged_callback->callback == merged_callback_2->callback + && merged_callback->callback_data == merged_callback_2->callback_data; +} + +static void +merged_callback_destroy (MergedCallback *merged_callback) +{ + g_assert (merged_callback != NULL); + g_assert (NAUTILUS_IS_DESKTOP_DIRECTORY (merged_callback->desktop_dir)); + + g_list_free (merged_callback->non_ready_directories); + nautilus_file_list_free (merged_callback->merged_file_list); + g_free (merged_callback); +} + +static void +merged_callback_check_done (MergedCallback *merged_callback) +{ + /* Check if we are ready. */ + if (merged_callback->non_ready_directories != NULL) { + return; + } + + /* Remove from the hash table before sending it. */ + g_hash_table_steal (merged_callback->desktop_dir->details->callbacks, merged_callback); + + /* We are ready, so do the real callback. */ + (* merged_callback->callback) (NAUTILUS_DIRECTORY (merged_callback->desktop_dir), + merged_callback->merged_file_list, + merged_callback->callback_data); + + /* And we are done. */ + merged_callback_destroy (merged_callback); +} + +static void +merged_callback_remove_directory (MergedCallback *merged_callback, + NautilusDirectory *directory) +{ + merged_callback->non_ready_directories = g_list_remove + (merged_callback->non_ready_directories, directory); + merged_callback_check_done (merged_callback); +} + +static void +directory_ready_callback (NautilusDirectory *directory, + GList *files, + gpointer callback_data) +{ + MergedCallback *merged_callback; + + g_assert (NAUTILUS_IS_DIRECTORY (directory)); + g_assert (callback_data != NULL); + + merged_callback = callback_data; + g_assert (g_list_find (merged_callback->non_ready_directories, directory) != NULL); + + /* Update based on this call. */ + merged_callback->merged_file_list = g_list_concat + (merged_callback->merged_file_list, + nautilus_file_list_copy (files)); + + /* Check if we are ready. */ + merged_callback_remove_directory (merged_callback, directory); +} + +static void +desktop_call_when_ready (NautilusDirectory *directory, + NautilusFileAttributes file_attributes, + gboolean wait_for_file_list, + NautilusDirectoryCallback callback, + gpointer callback_data) +{ + NautilusDesktopDirectory *desktop; + MergedCallback search_key, *merged_callback; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); + + /* Check to be sure we aren't overwriting. */ + search_key.callback = callback; + search_key.callback_data = callback_data; + if (g_hash_table_lookup (desktop->details->callbacks, &search_key) != NULL) { + g_warning ("tried to add a new callback while an old one was pending"); + return; + } + + /* Create a merged_callback record. */ + merged_callback = g_new0 (MergedCallback, 1); + merged_callback->desktop_dir = desktop; + merged_callback->callback = callback; + merged_callback->callback_data = callback_data; + merged_callback->wait_for_attributes = file_attributes; + merged_callback->wait_for_file_list = wait_for_file_list; + merged_callback->non_ready_directories = g_list_prepend + (merged_callback->non_ready_directories, directory); + merged_callback->non_ready_directories = g_list_prepend + (merged_callback->non_ready_directories, desktop->details->real_directory); + + + merged_callback->merged_file_list = g_list_concat (NULL, + nautilus_file_list_copy (directory->details->file_list)); + + /* Put it in the hash table. */ + g_hash_table_insert (desktop->details->callbacks, + merged_callback, merged_callback); + + /* Now tell all the directories about it. */ + nautilus_directory_call_when_ready + (desktop->details->real_directory, + merged_callback->wait_for_attributes, + merged_callback->wait_for_file_list, + directory_ready_callback, merged_callback); + nautilus_directory_call_when_ready_internal + (directory, + NULL, + merged_callback->wait_for_attributes, + merged_callback->wait_for_file_list, + directory_ready_callback, + NULL, + merged_callback); + +} + +static void +desktop_cancel_callback (NautilusDirectory *directory, + NautilusDirectoryCallback callback, + gpointer callback_data) +{ + NautilusDesktopDirectory *desktop; + MergedCallback search_key, *merged_callback; + GList *node; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); + + /* Find the entry in the table. */ + search_key.callback = callback; + search_key.callback_data = callback_data; + merged_callback = g_hash_table_lookup (desktop->details->callbacks, &search_key); + if (merged_callback == NULL) { + return; + } + + /* Remove from the hash table before working with it. */ + g_hash_table_steal (merged_callback->desktop_dir->details->callbacks, merged_callback); + + /* Tell all the directories to cancel the call. */ + for (node = merged_callback->non_ready_directories; node != NULL; node = node->next) { + nautilus_directory_cancel_callback + (node->data, + directory_ready_callback, merged_callback); + } + merged_callback_destroy (merged_callback); +} + +static void +merged_monitor_destroy (MergedMonitor *monitor) +{ + NautilusDesktopDirectory *desktop; + + desktop = monitor->desktop_dir; + + /* Call through to the real directory remove calls. */ + nautilus_directory_file_monitor_remove (desktop->details->real_directory, monitor); + + nautilus_directory_monitor_remove_internal (NAUTILUS_DIRECTORY (desktop), NULL, monitor); + + g_free (monitor); +} + +static void +build_merged_callback_list (NautilusDirectory *directory, + GList *file_list, + gpointer callback_data) +{ + GList **merged_list; + + merged_list = callback_data; + *merged_list = g_list_concat (*merged_list, + nautilus_file_list_copy (file_list)); +} + +static void +desktop_monitor_add (NautilusDirectory *directory, + gconstpointer client, + gboolean monitor_hidden_files, + gboolean monitor_backup_files, + NautilusFileAttributes file_attributes, + NautilusDirectoryCallback callback, + gpointer callback_data) +{ + NautilusDesktopDirectory *desktop; + MergedMonitor *monitor; + GList *merged_callback_list; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); + + /* Map the client to a unique value so this doesn't interfere + * with direct monitoring of the directory by the same client. + */ + monitor = g_hash_table_lookup (desktop->details->monitors, client); + if (monitor != NULL) { + g_assert (monitor->desktop_dir == desktop); + } else { + monitor = g_new0 (MergedMonitor, 1); + monitor->desktop_dir = desktop; + g_hash_table_insert (desktop->details->monitors, + (gpointer) client, monitor); + } + monitor->monitor_hidden_files = monitor_hidden_files; + monitor->monitor_backup_files = monitor_backup_files; + monitor->monitor_attributes = file_attributes; + + /* Call through to the real directory add calls. */ + merged_callback_list = NULL; + + /* Call up to real dir */ + nautilus_directory_file_monitor_add + (desktop->details->real_directory, monitor, + monitor_hidden_files, monitor_backup_files, + file_attributes, + build_merged_callback_list, &merged_callback_list); + + /* Handle the desktop part */ + merged_callback_list = g_list_concat (merged_callback_list, + nautilus_file_list_copy (directory->details->file_list)); + + + if (callback != NULL) { + (* callback) (directory, merged_callback_list, callback_data); + } + nautilus_file_list_free (merged_callback_list); +} + +static void +desktop_monitor_remove (NautilusDirectory *directory, + gconstpointer client) +{ + NautilusDesktopDirectory *desktop; + MergedMonitor *monitor; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); + + monitor = g_hash_table_lookup (desktop->details->monitors, client); + if (monitor == NULL) { + return; + } + + g_hash_table_remove (desktop->details->monitors, client); +} + +static void +desktop_force_reload (NautilusDirectory *directory) +{ + NautilusDesktopDirectory *desktop; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); + + nautilus_directory_force_reload (desktop->details->real_directory); + + /* We don't invalidate the files in desktop, since they are always + up to date. (And we don't ever want to mark them invalid.) */ +} + +static gboolean +desktop_are_all_files_seen (NautilusDirectory *directory) +{ + NautilusDesktopDirectory *desktop; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); + + if (!nautilus_directory_are_all_files_seen (desktop->details->real_directory)) { + return FALSE; + } + + return TRUE; +} + +static gboolean +desktop_is_not_empty (NautilusDirectory *directory) +{ + NautilusDesktopDirectory *desktop; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (directory); + + if (nautilus_directory_is_not_empty (desktop->details->real_directory)) { + return TRUE; + } + + return directory->details->file_list != NULL; +} + +NautilusDirectory * +nautilus_desktop_directory_get_real_directory (NautilusDesktopDirectory *desktop) +{ + nautilus_directory_ref (desktop->details->real_directory); + return desktop->details->real_directory; +} + + +static void +desktop_finalize (GObject *object) +{ + NautilusDesktopDirectory *desktop; + + desktop = NAUTILUS_DESKTOP_DIRECTORY (object); + + nautilus_directory_unref (desktop->details->real_directory); + g_free (desktop->details); + + g_hash_table_destroy (desktop->details->callbacks); + g_hash_table_destroy (desktop->details->monitors); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +done_loading_callback (NautilusDirectory *real_directory, + NautilusDesktopDirectory *desktop) +{ + nautilus_directory_emit_done_loading (NAUTILUS_DIRECTORY (desktop)); +} + + +static void +forward_files_added_cover (NautilusDirectory *real_directory, + GList *files, + gpointer callback_data) +{ + nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (callback_data), files); +} + +static void +forward_files_changed_cover (NautilusDirectory *real_directory, + GList *files, + gpointer callback_data) +{ + nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (callback_data), files); +} + + +static void +nautilus_desktop_directory_instance_init (NautilusDesktopDirectory *desktop) +{ + char *desktop_path; + char *desktop_uri; + NautilusDirectory *real_directory; + + desktop->details = g_new0 (NautilusDesktopDirectoryDetails, 1); + + desktop_path = nautilus_get_desktop_directory (); + desktop_uri = gnome_vfs_get_uri_from_local_path (desktop_path); + desktop->details->real_directory = nautilus_directory_get (desktop_uri); + g_free (desktop_uri); + g_free (desktop_path); + + desktop->details->callbacks = g_hash_table_new_full + (merged_callback_hash, merged_callback_equal, + NULL, (GDestroyNotify)merged_callback_destroy); + desktop->details->monitors = g_hash_table_new_full (NULL, NULL, + NULL, (GDestroyNotify)merged_monitor_destroy); + + real_directory = desktop->details->real_directory; + + g_signal_connect_object (real_directory, "done_loading", + G_CALLBACK (done_loading_callback), desktop, 0); + + g_signal_connect_object (real_directory, "files_added", + G_CALLBACK (forward_files_added_cover), desktop, 0); + g_signal_connect_object (real_directory, "files_changed", + G_CALLBACK (forward_files_changed_cover), desktop, 0); + +} + +static void +nautilus_desktop_directory_class_init (NautilusDesktopDirectoryClass *class) +{ + NautilusDirectoryClass *directory_class; + + directory_class = NAUTILUS_DIRECTORY_CLASS (class); + + G_OBJECT_CLASS (class)->finalize = desktop_finalize; + + directory_class->contains_file = desktop_contains_file; + directory_class->call_when_ready = desktop_call_when_ready; + directory_class->cancel_callback = desktop_cancel_callback; + directory_class->file_monitor_add = desktop_monitor_add; + directory_class->file_monitor_remove = desktop_monitor_remove; + directory_class->force_reload = desktop_force_reload; + directory_class->are_all_files_seen = desktop_are_all_files_seen; + directory_class->is_not_empty = desktop_is_not_empty; +} + diff --git a/libnautilus-private/nautilus-desktop-directory.h b/libnautilus-private/nautilus-desktop-directory.h new file mode 100644 index 000000000..0256c4972 --- /dev/null +++ b/libnautilus-private/nautilus-desktop-directory.h @@ -0,0 +1,58 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-desktop-directory.h: Subclass of NautilusDirectory to implement + a virtual directory consisting of the desktop directory and the desktop + icons + + Copyright (C) 2003 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Alexander Larsson <alexl@redhat.com> +*/ + +#ifndef NAUTILUS_DESKTOP_DIRECTORY_H +#define NAUTILUS_DESKTOP_DIRECTORY_H + +#include <libnautilus-private/nautilus-directory.h> + +#define NAUTILUS_TYPE_DESKTOP_DIRECTORY \ + (nautilus_desktop_directory_get_type ()) +#define NAUTILUS_DESKTOP_DIRECTORY(obj) \ + (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_DESKTOP_DIRECTORY, NautilusDesktopDirectory)) +#define NAUTILUS_DESKTOP_DIRECTORY_CLASS(klass) \ + (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_DIRECTORY, NautilusDesktopDirectoryClass)) +#define NAUTILUS_IS_DESKTOP_DIRECTORY(obj) \ + (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_DIRECTORY)) +#define NAUTILUS_IS_DESKTOP_DIRECTORY_CLASS(klass) \ + (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_DIRECTORY)) + +typedef struct NautilusDesktopDirectoryDetails NautilusDesktopDirectoryDetails; + +typedef struct { + NautilusDirectory parent_slot; + NautilusDesktopDirectoryDetails *details; +} NautilusDesktopDirectory; + +typedef struct { + NautilusDirectoryClass parent_slot; + +} NautilusDesktopDirectoryClass; + +GType nautilus_desktop_directory_get_type (void); +NautilusDirectory * nautilus_desktop_directory_get_real_directory (NautilusDesktopDirectory *desktop_directory); + +#endif /* NAUTILUS_DESKTOP_DIRECTORY_H */ diff --git a/libnautilus-private/nautilus-desktop-icon-file.c b/libnautilus-private/nautilus-desktop-icon-file.c new file mode 100644 index 000000000..79a4cf195 --- /dev/null +++ b/libnautilus-private/nautilus-desktop-icon-file.c @@ -0,0 +1,344 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-desktop-icon-file.c: Subclass of NautilusFile to help implement the + virtual desktop icons. + + Copyright (C) 2003 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Alexander Larsson <alexl@redhat.com> +*/ + +#include <config.h> +#include "nautilus-desktop-icon-file.h" + +#include "nautilus-directory-notify.h" +#include "nautilus-directory-private.h" +#include "nautilus-file-attributes.h" +#include "nautilus-file-private.h" +#include "nautilus-file-utilities.h" +#include <eel/eel-glib-extensions.h> +#include <eel/eel-gtk-macros.h> +#include "nautilus-desktop-directory.h" +#include <gtk/gtksignal.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomevfs/gnome-vfs.h> +#include <string.h> + +struct NautilusDesktopIconFileDetails { + NautilusDesktopLink *link; +}; + +static void nautilus_desktop_icon_file_init (gpointer object, + gpointer klass); +static void nautilus_desktop_icon_file_class_init (gpointer klass); + +EEL_CLASS_BOILERPLATE (NautilusDesktopIconFile, + nautilus_desktop_icon_file, + NAUTILUS_TYPE_FILE) + +static void +desktop_icon_file_monitor_add (NautilusFile *file, + gconstpointer client, + NautilusFileAttributes attributes) +{ + nautilus_directory_monitor_add_internal + (file->details->directory, file, + client, TRUE, TRUE, attributes, NULL, NULL); +} + +static void +desktop_icon_file_monitor_remove (NautilusFile *file, + gconstpointer client) +{ + nautilus_directory_monitor_remove_internal + (file->details->directory, file, client); +} + + +static void +desktop_icon_file_call_when_ready (NautilusFile *file, + NautilusFileAttributes attributes, + NautilusFileCallback callback, + gpointer callback_data) + +{ + nautilus_directory_call_when_ready_internal + (file->details->directory, file, + attributes, FALSE, NULL, callback, callback_data); +} + +static void +desktop_icon_file_cancel_call_when_ready (NautilusFile *file, + NautilusFileCallback callback, + gpointer callback_data) +{ + nautilus_directory_cancel_callback_internal + (file->details->directory, file, + NULL, callback, callback_data); +} + +static gboolean +desktop_icon_file_check_if_ready (NautilusFile *file, + NautilusFileAttributes attributes) +{ + return nautilus_directory_check_if_ready_internal + (file->details->directory, file, + attributes); +} + +static GnomeVFSFileType +desktop_icon_file_get_file_type (NautilusFile *file) +{ + return GNOME_VFS_FILE_TYPE_REGULAR; +} + +static gboolean +desktop_icon_file_get_item_count (NautilusFile *file, + guint *count, + gboolean *count_unreadable) +{ + if (count != NULL) { + *count = 0; + } + if (count_unreadable != NULL) { + *count_unreadable = FALSE; + } + return TRUE; +} + +static NautilusRequestStatus +desktop_icon_file_get_deep_counts (NautilusFile *file, + guint *directory_count, + guint *file_count, + guint *unreadable_directory_count, + GnomeVFSFileSize *total_size) +{ + if (directory_count != NULL) { + *directory_count = 0; + } + if (file_count != NULL) { + *file_count = 0; + } + if (unreadable_directory_count != NULL) { + *unreadable_directory_count = 0; + } + if (total_size != NULL) { + *total_size = 0; + } + + return NAUTILUS_REQUEST_DONE; +} + +static gboolean +desktop_icon_file_get_date (NautilusFile *file, + NautilusDateType date_type, + time_t *date) +{ + NautilusDesktopIconFile *desktop_file; + + desktop_file = NAUTILUS_DESKTOP_ICON_FILE (file); + + return nautilus_desktop_link_get_date (desktop_file->details->link, + date_type, date); +} + +static char * +desktop_icon_file_get_where_string (NautilusFile *file) +{ + return g_strdup (_("on the desktop")); +} + +static void +nautilus_desktop_icon_file_init (gpointer object, gpointer klass) +{ + NautilusDesktopIconFile *desktop_file; + + desktop_file = NAUTILUS_DESKTOP_ICON_FILE (object); + + desktop_file->details = g_new0 (NautilusDesktopIconFileDetails, 1); +} + +static void +update_info_from_link (NautilusDesktopIconFile *icon_file) +{ + NautilusFile *file; + GnomeVFSFileInfo *file_info; + NautilusDesktopLink *link; + + file = NAUTILUS_FILE (icon_file); + + link = icon_file->details->link; + + if (link == NULL) { + return; + } + + file_info = file->details->info; + + gnome_vfs_file_info_clear (file_info); + + file_info->name = nautilus_desktop_link_get_file_name (link); + file_info->mime_type = g_strdup ("application/x-nautilus-link"); + file_info->type = GNOME_VFS_FILE_TYPE_REGULAR; + file_info->flags = GNOME_VFS_FILE_FLAGS_NONE; + file_info->link_count = 1; + file_info->size = 0; + + file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE | + GNOME_VFS_FILE_INFO_FIELDS_FLAGS | + GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE | + GNOME_VFS_FILE_INFO_FIELDS_SIZE | + GNOME_VFS_FILE_INFO_FIELDS_LINK_COUNT; + + file->details->file_info_is_up_to_date = TRUE; + + g_free (file->details->display_name); + file->details->display_name = nautilus_desktop_link_get_display_name (link); + g_free (file->details->custom_icon); + file->details->custom_icon = nautilus_desktop_link_get_icon (link); + g_free (file->details->activation_uri); + file->details->activation_uri = nautilus_desktop_link_get_activation_uri (link); + file->details->got_link_info = TRUE; + file->details->link_info_is_up_to_date = TRUE; + + file->details->directory_count = 0; + file->details->got_directory_count = TRUE; + file->details->directory_count_is_up_to_date = TRUE; +} + +void +nautilus_desktop_icon_file_update (NautilusDesktopIconFile *icon_file) +{ + NautilusFile *file; + + update_info_from_link (icon_file); + file = NAUTILUS_FILE (icon_file); + nautilus_file_clear_cached_display_name (file); + nautilus_file_changed (file); +} + +void +nautilus_desktop_icon_file_remove (NautilusDesktopIconFile *icon_file) +{ + NautilusFile *file; + GList list; + + icon_file->details->link = NULL; + + file = NAUTILUS_FILE (icon_file); + + /* ref here because we might be removing the last ref when we + * mark the file gone below, but we need to keep a ref at + * least long enough to send the change notification. + */ + nautilus_file_ref (file); + + file->details->is_gone = TRUE; + + list.data = file; + list.next = NULL; + list.prev = NULL; + + nautilus_directory_remove_file (file->details->directory, file); + nautilus_directory_emit_change_signals (file->details->directory, &list); + + nautilus_file_unref (file); +} + + +NautilusDesktopIconFile * +nautilus_desktop_icon_file_new (NautilusDesktopLink *link) +{ + NautilusFile *file; + NautilusDirectory *directory; + NautilusDesktopIconFile *icon_file; + char *name; + GList list; + + directory = nautilus_directory_get (EEL_DESKTOP_URI); + + file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_DESKTOP_ICON_FILE, NULL)); + +#ifdef NAUTILUS_FILE_DEBUG_REF + printf("%10p ref'd\n", file); + eazel_dump_stack_trace ("\t", 10); +#endif + + nautilus_directory_ref (directory); + file->details->directory = directory; + + icon_file = NAUTILUS_DESKTOP_ICON_FILE (file); + icon_file->details->link = link; + + file->details->info = gnome_vfs_file_info_new (); + name = nautilus_desktop_link_get_file_name (link); + file->details->relative_uri = gnome_vfs_escape_string (name); + g_free (name); + + update_info_from_link (icon_file); + + nautilus_directory_add_file (directory, file); + + list.data = file; + list.next = NULL; + list.prev = NULL; + nautilus_directory_emit_files_added (directory, &list); + + return icon_file; +} + +NautilusDesktopLink * +nautilus_desktop_icon_file_get_link (NautilusDesktopIconFile *icon_file) +{ + return g_object_ref (icon_file->details->link); +} + +static void +desktop_finalize (GObject *object) +{ + NautilusDesktopIconFile *desktop_file; + + desktop_file = NAUTILUS_DESKTOP_ICON_FILE (object); + + g_free (desktop_file->details); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +nautilus_desktop_icon_file_class_init (gpointer klass) +{ + GObjectClass *object_class; + NautilusFileClass *file_class; + + object_class = G_OBJECT_CLASS (klass); + file_class = NAUTILUS_FILE_CLASS (klass); + + object_class->finalize = desktop_finalize; + + file_class->monitor_add = desktop_icon_file_monitor_add; + file_class->monitor_remove = desktop_icon_file_monitor_remove; + file_class->call_when_ready = desktop_icon_file_call_when_ready; + file_class->cancel_call_when_ready = desktop_icon_file_cancel_call_when_ready; + file_class->check_if_ready = desktop_icon_file_check_if_ready; + file_class->get_file_type = desktop_icon_file_get_file_type; + file_class->get_item_count = desktop_icon_file_get_item_count; + file_class->get_deep_counts = desktop_icon_file_get_deep_counts; + file_class->get_date = desktop_icon_file_get_date; + file_class->get_where_string = desktop_icon_file_get_where_string; +} diff --git a/libnautilus-private/nautilus-desktop-icon-file.h b/libnautilus-private/nautilus-desktop-icon-file.h new file mode 100644 index 000000000..276411c56 --- /dev/null +++ b/libnautilus-private/nautilus-desktop-icon-file.h @@ -0,0 +1,61 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-desktop-file.h: Subclass of NautilusFile to implement the + the case of a desktop icon file + + Copyright (C) 2003 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Alexander Larsson <alexl@redhat.com> +*/ + +#ifndef NAUTILUS_DESKTOP_ICON_FILE_H +#define NAUTILUS_DESKTOP_ICON_FILE_H + +#include <libnautilus-private/nautilus-file.h> +#include <libnautilus-private/nautilus-desktop-link.h> + +#define NAUTILUS_TYPE_DESKTOP_ICON_FILE \ + (nautilus_desktop_icon_file_get_type ()) +#define NAUTILUS_DESKTOP_ICON_FILE(obj) \ + (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_DESKTOP_ICON_FILE, NautilusDesktopIconFile)) +#define NAUTILUS_DESKTOP_ICON_FILE_CLASS(klass) \ + (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_ICON_FILE, NautilusDesktopIconFileClass)) +#define NAUTILUS_IS_DESKTOP_ICON_FILE(obj) \ + (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_ICON_FILE)) +#define NAUTILUS_IS_DESKTOP_ICON_FILE_CLASS(klass) \ + (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_ICON_FILE)) + +typedef struct NautilusDesktopIconFileDetails NautilusDesktopIconFileDetails; + +typedef struct { + NautilusFile parent_slot; + NautilusDesktopIconFileDetails *details; +} NautilusDesktopIconFile; + +typedef struct { + NautilusFileClass parent_slot; +} NautilusDesktopIconFileClass; + +GType nautilus_desktop_icon_file_get_type (void); + +NautilusDesktopIconFile *nautilus_desktop_icon_file_new (NautilusDesktopLink *link); +void nautilus_desktop_icon_file_update (NautilusDesktopIconFile *icon_file); +void nautilus_desktop_icon_file_remove (NautilusDesktopIconFile *icon_file); +NautilusDesktopLink *nautilus_desktop_icon_file_get_link (NautilusDesktopIconFile *icon_file); + +#endif /* NAUTILUS_DESKTOP_ICON_FILE_H */ diff --git a/libnautilus-private/nautilus-desktop-link-monitor.c b/libnautilus-private/nautilus-desktop-link-monitor.c new file mode 100644 index 000000000..0cadff766 --- /dev/null +++ b/libnautilus-private/nautilus-desktop-link-monitor.c @@ -0,0 +1,354 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-desktop-link-monitor.c: singleton thatn manages the links + + Copyright (C) 2003 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Alexander Larsson <alexl@redhat.com> +*/ + +#include <config.h> +#include "nautilus-desktop-link-monitor.h" +#include "nautilus-desktop-link.h" +#include "nautilus-desktop-icon-file.h" +#include "nautilus-directory.h" +#include "nautilus-desktop-directory.h" +#include "nautilus-global-preferences.h" + +#include <eel/eel-gtk-macros.h> +#include <eel/eel-glib-extensions.h> +#include <eel/eel-vfs-extensions.h> +#include <eel/eel-stock-dialogs.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkstock.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomevfs/gnome-vfs.h> +#include <libnautilus-private/nautilus-trash-monitor.h> +#include <string.h> + +struct NautilusDesktopLinkMonitorDetails { + NautilusDirectory *desktop_dir; + + NautilusDesktopLink *home_link; + NautilusDesktopLink *trash_link; + + GList *volume_links; + + GList *mount_black_list; +}; + + +static void nautilus_desktop_link_monitor_init (gpointer object, + gpointer klass); +static void nautilus_desktop_link_monitor_class_init (gpointer klass); + +EEL_CLASS_BOILERPLATE (NautilusDesktopLinkMonitor, + nautilus_desktop_link_monitor, + G_TYPE_OBJECT) + +static NautilusDesktopLinkMonitor *link_monitor = NULL; + +NautilusDesktopLinkMonitor * +nautilus_desktop_link_monitor_get (void) +{ + if (link_monitor == NULL) { + link_monitor = NAUTILUS_DESKTOP_LINK_MONITOR (g_object_new (NAUTILUS_TYPE_DESKTOP_LINK_MONITOR, NULL)); + } + return link_monitor; +} + +void +nautilus_desktop_link_monitor_delete_link (NautilusDesktopLinkMonitor *monitor, + NautilusDesktopLink *link, + GtkWidget *parent_view) +{ + /* FIXME: Is this right? How to get them back? + * Do we disallow this, or add a prefs ui to get them back? */ + + switch (nautilus_desktop_link_get_link_type (link)) { + case NAUTILUS_DESKTOP_LINK_HOME: + eel_preferences_set_boolean (NAUTILUS_PREFERENCES_DESKTOP_HOME_VISIBLE, FALSE); + break; + case NAUTILUS_DESKTOP_LINK_TRASH: + eel_preferences_set_boolean (NAUTILUS_PREFERENCES_DESKTOP_TRASH_VISIBLE, FALSE); + break; + default: + eel_run_simple_dialog + (parent_view, + FALSE, + _("You cannot delete a volume icon. If you want to eject " + "the volume, please use Eject in the right-click menu of " + "the volume."), + _("Can't delete volume"), + GTK_STOCK_OK, NULL); + break; + } +} + + +static gboolean +volume_in_black_list (NautilusDesktopLinkMonitor *monitor, + const NautilusVolume *volume) +{ + GList *p; + + g_return_val_if_fail (NAUTILUS_IS_DESKTOP_LINK_MONITOR (monitor), TRUE); + + for (p = monitor->details->mount_black_list; p != NULL; p = p->next) { + if (strcmp ((char *) p->data, nautilus_volume_get_mount_path (volume)) == 0) { + return TRUE; + } + } + + return FALSE; +} + +static gboolean +volume_name_exists (NautilusDesktopLinkMonitor *monitor, + const char *name) +{ + GList *l; + char *other_name; + + for (l = monitor->details->volume_links; l != NULL; l = l->next) { + other_name = nautilus_desktop_link_get_display_name (l->data); + if (strcmp (name, other_name) == 0) { + g_free (other_name); + return TRUE; + } + g_free (other_name); + } + return FALSE; +} + +static void +create_volume_link (NautilusDesktopLinkMonitor *monitor, + const NautilusVolume *volume) +{ + NautilusDesktopLink *link; + char *volume_name; + char *unique_name; + int index; + + if (volume_in_black_list (monitor, volume)) { + return; + } + + /* FIXME bugzilla.gnome.org 45412: Design a comprehensive desktop mounting strategy */ + if (!nautilus_volume_is_removable (volume)) { + return; + } + + volume_name = nautilus_volume_get_name (volume); + index = 1; + + unique_name = g_strdup (volume_name); + while (volume_name_exists (monitor, volume_name)) { + g_free (unique_name); + unique_name = g_strdup_printf ("%s (%d)", volume_name, index); + } + + if (index != 1) { + nautilus_volume_monitor_set_volume_name (nautilus_volume_monitor_get (), + volume, unique_name); + } + g_free (volume_name); + g_free (unique_name); + + link = nautilus_desktop_link_new_from_volume (volume); + monitor->details->volume_links = g_list_prepend (monitor->details->volume_links, link); +} + +static gboolean +create_one_volume_link (const NautilusVolume *volume, gpointer callback_data) +{ + create_volume_link (NAUTILUS_DESKTOP_LINK_MONITOR (callback_data), + volume); + return TRUE; +} + + +static void +volume_mounted_callback (NautilusVolumeMonitor *volume_monitor, + NautilusVolume *volume, + NautilusDesktopLinkMonitor *monitor) +{ + create_volume_link (monitor, volume); +} + + +static void +volume_unmounted_callback (NautilusVolumeMonitor *volume_monitor, + NautilusVolume *volume, + NautilusDesktopLinkMonitor *monitor) +{ + GList *l; + NautilusDesktopLink *link; + char *mount_path; + + link = NULL; + for (l = monitor->details->volume_links; l != NULL; l = l->next) { + mount_path = nautilus_desktop_link_get_mount_path (l->data); + + if (strcmp (mount_path, nautilus_volume_get_mount_path (volume)) == 0) { + link = l->data; + g_free (mount_path); + break; + } + g_free (mount_path); + } + + if (link) { + g_object_unref (link); + monitor->details->volume_links = g_list_remove (monitor->details->volume_links, link); + } +} + + +static void +desktop_home_visible_changed (gpointer callback_data) +{ + NautilusDesktopLinkMonitor *monitor; + + monitor = NAUTILUS_DESKTOP_LINK_MONITOR (callback_data); + + if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_HOME_VISIBLE)) { + if (monitor->details->home_link == NULL) { + monitor->details->home_link = nautilus_desktop_link_new (NAUTILUS_DESKTOP_LINK_HOME); + } + } else { + if (monitor->details->home_link != NULL) { + g_object_unref (monitor->details->home_link); + monitor->details->home_link = NULL; + } + } +} + +static void +desktop_trash_visible_changed (gpointer callback_data) +{ + NautilusDesktopLinkMonitor *monitor; + + monitor = NAUTILUS_DESKTOP_LINK_MONITOR (callback_data); + + if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_TRASH_VISIBLE)) { + if (monitor->details->trash_link == NULL) { + monitor->details->trash_link = nautilus_desktop_link_new (NAUTILUS_DESKTOP_LINK_TRASH); + } + } else { + if (monitor->details->trash_link != NULL) { + g_object_unref (monitor->details->trash_link); + monitor->details->trash_link = NULL; + } + } +} + +static void +nautilus_desktop_link_monitor_init (gpointer object, gpointer klass) +{ + NautilusDesktopLinkMonitor *monitor; + GList *list; + + monitor = NAUTILUS_DESKTOP_LINK_MONITOR (object); + + monitor->details = g_new0 (NautilusDesktopLinkMonitorDetails, 1); + + /* Set up default mount black list */ + list = g_list_prepend (NULL, g_strdup ("/proc")); + list = g_list_prepend (list, g_strdup ("/boot")); + monitor->details->mount_black_list = list; + + /* We keep around a ref to the desktop dir */ + monitor->details->desktop_dir = nautilus_directory_get (EEL_DESKTOP_URI); + + if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_HOME_VISIBLE)) { + monitor->details->home_link = nautilus_desktop_link_new (NAUTILUS_DESKTOP_LINK_HOME); + } + + if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_TRASH_VISIBLE)) { + monitor->details->trash_link = nautilus_desktop_link_new (NAUTILUS_DESKTOP_LINK_TRASH); + } + + nautilus_volume_monitor_each_mounted_volume (nautilus_volume_monitor_get (), + create_one_volume_link, + monitor); + + eel_preferences_add_callback (NAUTILUS_PREFERENCES_DESKTOP_HOME_VISIBLE, + desktop_home_visible_changed, + monitor); + eel_preferences_add_callback (NAUTILUS_PREFERENCES_DESKTOP_TRASH_VISIBLE, + desktop_trash_visible_changed, + monitor); + + + g_signal_connect_object (nautilus_volume_monitor_get (), "volume_mounted", + G_CALLBACK (volume_mounted_callback), monitor, 0); + g_signal_connect_object (nautilus_volume_monitor_get (), "volume_unmounted", + G_CALLBACK (volume_unmounted_callback), monitor, 0); + +} + +static void +desktop_link_monitor_finalize (GObject *object) +{ + NautilusDesktopLinkMonitor *monitor; + + monitor = NAUTILUS_DESKTOP_LINK_MONITOR (object); + + if (monitor->details->home_link != NULL) { + g_object_unref (monitor->details->home_link); + monitor->details->home_link = NULL; + } + + if (monitor->details->trash_link != NULL) { + g_object_unref (monitor->details->home_link); + monitor->details->trash_link = NULL; + } + + g_list_foreach (monitor->details->volume_links, (GFunc)g_object_unref, NULL); + g_list_free (monitor->details->volume_links); + monitor->details->volume_links = NULL; + + nautilus_directory_unref (monitor->details->desktop_dir); + monitor->details->desktop_dir = NULL; + + eel_g_list_free_deep (monitor->details->mount_black_list); + monitor->details->mount_black_list = NULL; + + eel_preferences_remove_callback (NAUTILUS_PREFERENCES_DESKTOP_HOME_VISIBLE, + desktop_home_visible_changed, + monitor); + eel_preferences_remove_callback (NAUTILUS_PREFERENCES_DESKTOP_TRASH_VISIBLE, + desktop_trash_visible_changed, + monitor); + + g_free (monitor->details); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +nautilus_desktop_link_monitor_class_init (gpointer klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = desktop_link_monitor_finalize; + +} diff --git a/libnautilus-private/nautilus-desktop-link-monitor.h b/libnautilus-private/nautilus-desktop-link-monitor.h new file mode 100644 index 000000000..965f7cc7b --- /dev/null +++ b/libnautilus-private/nautilus-desktop-link-monitor.h @@ -0,0 +1,60 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-desktop-link-monitor.h: singleton thatn manages the links + + Copyright (C) 2003 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Alexander Larsson <alexl@redhat.com> +*/ + +#ifndef NAUTILUS_DESKTOP_LINK_MONITOR_H +#define NAUTILUS_DESKTOP_LINK_MONITOR_H + +#include <gtk/gtkwidget.h> +#include <libnautilus-private/nautilus-desktop-link.h> + +#define NAUTILUS_TYPE_DESKTOP_LINK_MONITOR \ + (nautilus_desktop_link_monitor_get_type ()) +#define NAUTILUS_DESKTOP_LINK_MONITOR(obj) \ + (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_DESKTOP_LINK_MONITOR, NautilusDesktopLinkMonitor)) +#define NAUTILUS_DESKTOP_LINK_MONITOR_CLASS(klass) \ + (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_LINK_MONITOR, NautilusDesktopLinkMonitor)) +#define NAUTILUS_IS_DESKTOP_LINK_MONITOR(obj) \ + (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_LINK_MONITOR)) +#define NAUTILUS_IS_DESKTOP_LINK_MONITOR_CLASS(klass) \ + (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_LINK_MONITOR)) + +typedef struct NautilusDesktopLinkMonitorDetails NautilusDesktopLinkMonitorDetails; + +typedef struct { + GObject parent_slot; + NautilusDesktopLinkMonitorDetails *details; +} NautilusDesktopLinkMonitor; + +typedef struct { + GObjectClass parent_slot; +} NautilusDesktopLinkMonitorClass; + +GType nautilus_desktop_link_monitor_get_type (void); + +NautilusDesktopLinkMonitor * nautilus_desktop_link_monitor_get (void); +void nautilus_desktop_link_monitor_delete_link (NautilusDesktopLinkMonitor *monitor, + NautilusDesktopLink *link, + GtkWidget *parent_view); + +#endif /* NAUTILUS_DESKTOP_LINK_MONITOR_H */ diff --git a/libnautilus-private/nautilus-desktop-link.c b/libnautilus-private/nautilus-desktop-link.c new file mode 100644 index 000000000..f97209612 --- /dev/null +++ b/libnautilus-private/nautilus-desktop-link.c @@ -0,0 +1,428 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-desktop-link.c: Class that handles the links on the desktop + + Copyright (C) 2003 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Alexander Larsson <alexl@redhat.com> +*/ + +#include <config.h> +#include "nautilus-desktop-link.h" +#include "nautilus-desktop-icon-file.h" +#include "nautilus-directory-private.h" +#include "nautilus-desktop-directory.h" + +#include <eel/eel-gtk-macros.h> +#include <eel/eel-vfs-extensions.h> +#include <gtk/gtksignal.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomevfs/gnome-vfs.h> +#include <libnautilus-private/nautilus-trash-monitor.h> +#include <libnautilus-private/nautilus-global-preferences.h> +#include <string.h> + +#define TRASH_EMPTY_ICON "gnome-fs-trash-empty" +#define TRASH_FULL_ICON "gnome-fs-trash-full" + +struct NautilusDesktopLinkDetails { + NautilusDesktopLinkType type; + char *filename; + char *display_name; + char *activation_uri; + char *icon; + + NautilusDesktopIconFile *icon_file; + + /* Just for trash icons: */ + gulong trash_state_handler; + + /* Just for volume icons: */ + char *mount_path; +}; + +static void nautilus_desktop_link_init (gpointer object, + gpointer klass); +static void nautilus_desktop_link_class_init (gpointer klass); +static void trash_state_changed_callback (NautilusTrashMonitor *trash_monitor, + gboolean state, + gpointer callback_data); +static void nautilus_desktop_link_changed (NautilusDesktopLink *link); +static void home_uri_changed (gpointer callback_data); + +EEL_CLASS_BOILERPLATE (NautilusDesktopLink, + nautilus_desktop_link, + G_TYPE_OBJECT) + +static void +create_icon_file (NautilusDesktopLink *link) +{ + link->details->icon_file = nautilus_desktop_icon_file_new (link); +} + +static void +home_name_changed (gpointer callback_data) +{ + NautilusDesktopLink *link; + + link = NAUTILUS_DESKTOP_LINK (callback_data); + g_assert (link->details->type == NAUTILUS_DESKTOP_LINK_HOME); + + g_free (link->details->display_name); + link->details->display_name = eel_preferences_get (NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME); + + nautilus_desktop_link_changed (link); +} + +static void +trash_name_changed (gpointer callback_data) +{ + NautilusDesktopLink *link; + + link = NAUTILUS_DESKTOP_LINK (callback_data); + g_assert (link->details->type == NAUTILUS_DESKTOP_LINK_TRASH); + + + g_free (link->details->display_name); + link->details->display_name = eel_preferences_get (NAUTILUS_PREFERENCES_DESKTOP_TRASH_NAME); + nautilus_desktop_link_changed (link); +} + + + +NautilusDesktopLink * +nautilus_desktop_link_new (NautilusDesktopLinkType type) +{ + NautilusDesktopLink *link; + + link = NAUTILUS_DESKTOP_LINK (g_object_new (NAUTILUS_TYPE_DESKTOP_LINK, NULL)); + + link->details->type = type; + switch (type) { + case NAUTILUS_DESKTOP_LINK_HOME: + link->details->filename = g_strdup ("home"); + + link->details->display_name = eel_preferences_get (NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME); + +#ifdef WEB_NAVIGATION_ENABLED + link->details->activation_uri = eel_preferences_get (NAUTILUS_PREFERENCES_HOME_URI); +#else + link->details->activation_uri = gnome_vfs_get_uri_from_local_path (g_get_home_dir ()); +#endif + link->details->icon = g_strdup ("gnome-fs-home"); + + eel_preferences_add_callback (NAUTILUS_PREFERENCES_HOME_URI, + home_uri_changed, + link); + eel_preferences_add_callback (NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME, + home_name_changed, + link); + + break; + case NAUTILUS_DESKTOP_LINK_TRASH: + link->details->filename = g_strdup ("trash"); + link->details->display_name = g_strdup (_("Trash")); + link->details->activation_uri = g_strdup (EEL_TRASH_URI); + if (nautilus_trash_monitor_is_empty ()) { + link->details->icon = g_strdup (TRASH_EMPTY_ICON); + } else { + link->details->icon = g_strdup (TRASH_FULL_ICON); + } + + eel_preferences_add_callback (NAUTILUS_PREFERENCES_DESKTOP_TRASH_NAME, + trash_name_changed, + link); + link->details->trash_state_handler = + g_signal_connect_object (nautilus_trash_monitor_get (), "trash_state_changed", + G_CALLBACK (trash_state_changed_callback), link, 0); + break; + default: + case NAUTILUS_DESKTOP_LINK_VOLUME: + g_assert_not_reached(); + } + + create_icon_file (link); + + return link; +} + +static char * +get_icon_for_volume (const NautilusVolume *volume) +{ + char *icon_name; + + icon_name = "gnome-dev-harddisk"; + switch (nautilus_volume_get_device_type (volume)) { + case NAUTILUS_DEVICE_AUDIO_CD: + case NAUTILUS_DEVICE_CDROM_DRIVE: + icon_name = "gnome-dev-cdrom"; + break; + + case NAUTILUS_DEVICE_FLOPPY_DRIVE: + icon_name = "gnome-dev-floppy"; + break; + + case NAUTILUS_DEVICE_JAZ_DRIVE: + icon_name = "gnome-dev-jazdisk"; + break; + + case NAUTILUS_DEVICE_MEMORY_STICK: + icon_name = "gnome-dev-memory"; + break; + + case NAUTILUS_DEVICE_NFS: + icon_name = "gnome-fs-nfs"; + break; + + case NAUTILUS_DEVICE_SMB: + icon_name = "gnome-fs-smb"; + break; + + case NAUTILUS_DEVICE_ZIP_DRIVE: + icon_name = "gnome-dev-zipdisk"; + break; + + case NAUTILUS_DEVICE_APPLE: + case NAUTILUS_DEVICE_WINDOWS: + case NAUTILUS_DEVICE_CAMERA: + case NAUTILUS_DEVICE_UNKNOWN: + break; + } + + return g_strdup (icon_name); +} + +NautilusDesktopLink * +nautilus_desktop_link_new_from_volume (const NautilusVolume *volume) +{ + NautilusDesktopLink *link; + const char *mount_path; + char *underscore_mount_path, *p; + + link = NAUTILUS_DESKTOP_LINK (g_object_new (NAUTILUS_TYPE_DESKTOP_LINK, NULL)); + + link->details->type = NAUTILUS_DESKTOP_LINK_VOLUME; + + mount_path = nautilus_volume_get_mount_path (volume); + link->details->mount_path = g_strdup (mount_path); + + /* Convert slashes in the mount path to underscores and skip + first slash */ + while (*mount_path == '/') { + mount_path ++; + } + underscore_mount_path = g_strdup (mount_path); + for (p = underscore_mount_path; *p != 0; p++) { + if (*p == '/') { + *p = '_'; + } + } + + link->details->filename = g_strconcat ("mount_", underscore_mount_path, NULL); + g_free (underscore_mount_path); + + link->details->display_name = nautilus_volume_get_name (volume); + + link->details->activation_uri = nautilus_volume_get_target_uri (volume); + link->details->icon = get_icon_for_volume (volume); + + create_icon_file (link); + + return link; +} + +char * +nautilus_desktop_link_get_mount_path (NautilusDesktopLink *link) +{ + g_assert (link->details->type == NAUTILUS_DESKTOP_LINK_VOLUME); + return g_strdup (link->details->mount_path); +} + + +NautilusDesktopLinkType +nautilus_desktop_link_get_link_type (NautilusDesktopLink *link) +{ + return link->details->type; +} + +char * +nautilus_desktop_link_get_file_name (NautilusDesktopLink *link) +{ + return g_strdup (link->details->filename); +} + +char * +nautilus_desktop_link_get_display_name (NautilusDesktopLink *link) +{ + return g_strdup (link->details->display_name); +} + +char * +nautilus_desktop_link_get_icon (NautilusDesktopLink *link) +{ + return g_strdup (link->details->icon); +} + +char * +nautilus_desktop_link_get_activation_uri (NautilusDesktopLink *link) +{ + return g_strdup (link->details->activation_uri); +} + +gboolean +nautilus_desktop_link_get_date (NautilusDesktopLink *link, + NautilusDateType date_type, + time_t *date) +{ + return FALSE; +} + +static void +nautilus_desktop_link_changed (NautilusDesktopLink *link) +{ + if (link->details->icon_file != NULL) { + nautilus_desktop_icon_file_update (link->details->icon_file); + } +} + +static void +trash_state_changed_callback (NautilusTrashMonitor *trash_monitor, + gboolean state, + gpointer callback_data) +{ + NautilusDesktopLink *link; + + link = NAUTILUS_DESKTOP_LINK (callback_data); + g_assert (link->details->type == NAUTILUS_DESKTOP_LINK_TRASH); + + g_free (link->details->icon); + + if (state) { + link->details->icon = g_strdup (TRASH_EMPTY_ICON); + } else { + link->details->icon = g_strdup (TRASH_FULL_ICON); + } + + nautilus_desktop_link_changed (link); +} + +static void +home_uri_changed (gpointer callback_data) +{ + NautilusDesktopLink *link; + + link = NAUTILUS_DESKTOP_LINK (callback_data); + + g_free (link->details->activation_uri); +#ifdef WEB_NAVIGATION_ENABLED + link->details->activation_uri = eel_preferences_get (NAUTILUS_PREFERENCES_HOME_URI); +#else + link->details->activation_uri = gnome_vfs_get_uri_from_local_path (g_get_home_dir ()); +#endif + + nautilus_desktop_link_changed (link); +} + + +gboolean +nautilus_desktop_link_can_rename (NautilusDesktopLink *link) +{ + return (link->details->type == NAUTILUS_DESKTOP_LINK_HOME || + link->details->type == NAUTILUS_DESKTOP_LINK_TRASH); +} + +gboolean +nautilus_desktop_link_rename (NautilusDesktopLink *link, + const char *name) +{ + switch (link->details->type) { + case NAUTILUS_DESKTOP_LINK_HOME: + eel_preferences_set (NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME, + name); + break; + case NAUTILUS_DESKTOP_LINK_TRASH: + eel_preferences_set (NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME, + name); + break; + default: + g_assert_not_reached (); + /* FIXME: Do we want volume renaming? + * We didn't support that before. */ + break; + } + + return TRUE; +} + + +static void +nautilus_desktop_link_init (gpointer object, gpointer klass) +{ + NautilusDesktopLink *link; + + link = NAUTILUS_DESKTOP_LINK (object); + + link->details = g_new0 (NautilusDesktopLinkDetails, 1); +} + +static void +desktop_link_finalize (GObject *object) +{ + NautilusDesktopLink *link; + + link = NAUTILUS_DESKTOP_LINK (object); + + if (link->details->trash_state_handler != 0) { + g_signal_handler_disconnect (nautilus_trash_monitor_get (), + link->details->trash_state_handler); + } + + if (link->details->icon_file != NULL) { + nautilus_desktop_icon_file_remove (link->details->icon_file); + } + + if (link->details->type == NAUTILUS_DESKTOP_LINK_HOME) { + eel_preferences_remove_callback (NAUTILUS_PREFERENCES_HOME_URI, + home_uri_changed, + link); + eel_preferences_remove_callback (NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME, + home_name_changed, + link); + } + + if (link->details->type == NAUTILUS_DESKTOP_LINK_TRASH) { + eel_preferences_remove_callback (NAUTILUS_PREFERENCES_DESKTOP_TRASH_NAME, + trash_name_changed, + link); + } + + g_free (link->details); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +nautilus_desktop_link_class_init (gpointer klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = desktop_link_finalize; + +} diff --git a/libnautilus-private/nautilus-desktop-link.h b/libnautilus-private/nautilus-desktop-link.h new file mode 100644 index 000000000..b5cf379cf --- /dev/null +++ b/libnautilus-private/nautilus-desktop-link.h @@ -0,0 +1,77 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-desktop-link.h: Class that handles the links on the desktop + + Copyright (C) 2003 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Alexander Larsson <alexl@redhat.com> +*/ + +#ifndef NAUTILUS_DESKTOP_LINK_H +#define NAUTILUS_DESKTOP_LINK_H + +#include <libnautilus-private/nautilus-file.h> +#include <libnautilus-private/nautilus-volume-monitor.h> + +#define NAUTILUS_TYPE_DESKTOP_LINK \ + (nautilus_desktop_link_get_type ()) +#define NAUTILUS_DESKTOP_LINK(obj) \ + (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_DESKTOP_LINK, NautilusDesktopLink)) +#define NAUTILUS_DESKTOP_LINK_CLASS(klass) \ + (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DESKTOP_LINK, NautilusDesktopLink)) +#define NAUTILUS_IS_DESKTOP_LINK(obj) \ + (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_DESKTOP_LINK)) +#define NAUTILUS_IS_DESKTOP_LINK_CLASS(klass) \ + (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DESKTOP_LINK)) + +typedef struct NautilusDesktopLinkDetails NautilusDesktopLinkDetails; + +typedef struct { + GObject parent_slot; + NautilusDesktopLinkDetails *details; +} NautilusDesktopLink; + +typedef struct { + GObjectClass parent_slot; +} NautilusDesktopLinkClass; + +typedef enum { + NAUTILUS_DESKTOP_LINK_HOME, + NAUTILUS_DESKTOP_LINK_TRASH, + NAUTILUS_DESKTOP_LINK_VOLUME +} NautilusDesktopLinkType; + +GType nautilus_desktop_link_get_type (void); + +NautilusDesktopLink * nautilus_desktop_link_new (NautilusDesktopLinkType type); +NautilusDesktopLink * nautilus_desktop_link_new_from_volume (const NautilusVolume *volume); +NautilusDesktopLinkType nautilus_desktop_link_get_link_type (NautilusDesktopLink *link); +char * nautilus_desktop_link_get_file_name (NautilusDesktopLink *link); +char * nautilus_desktop_link_get_display_name (NautilusDesktopLink *link); +char * nautilus_desktop_link_get_icon (NautilusDesktopLink *link); +char * nautilus_desktop_link_get_activation_uri (NautilusDesktopLink *link); +gboolean nautilus_desktop_link_get_date (NautilusDesktopLink *link, + NautilusDateType date_type, + time_t *date); +char * nautilus_desktop_link_get_mount_path (NautilusDesktopLink *link); + +gboolean nautilus_desktop_link_can_rename (NautilusDesktopLink *link); +gboolean nautilus_desktop_link_rename (NautilusDesktopLink *link, + const char *name); + +#endif /* NAUTILUS_DESKTOP_LINK_H */ diff --git a/libnautilus-private/nautilus-directory-async.c b/libnautilus-private/nautilus-directory-async.c index 7ab4c5ce3..6910b456c 100644 --- a/libnautilus-private/nautilus-directory-async.c +++ b/libnautilus-private/nautilus-directory-async.c @@ -3305,7 +3305,7 @@ nautilus_directory_add_file_to_work_queue (NautilusDirectory *directory, } nautilus_file_queue_enqueue (directory->details->high_priority_queue, - file); + file); } diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c index 6e08e2500..1161da7b8 100644 --- a/libnautilus-private/nautilus-directory.c +++ b/libnautilus-private/nautilus-directory.c @@ -34,6 +34,7 @@ #include "nautilus-lib-self-check-functions.h" #include "nautilus-metadata.h" #include "nautilus-metafile.h" +#include "nautilus-desktop-directory.h" #include "nautilus-trash-directory.h" #include "nautilus-vfs-directory.h" #include <eel/eel-glib-extensions.h> @@ -501,6 +502,8 @@ nautilus_directory_new (const char *uri) if (eel_uri_is_trash (uri)) { directory = NAUTILUS_DIRECTORY (g_object_new (NAUTILUS_TYPE_TRASH_DIRECTORY, NULL)); + } else if (eel_uri_is_desktop (uri)) { + directory = NAUTILUS_DIRECTORY (g_object_new (NAUTILUS_TYPE_DESKTOP_DIRECTORY, NULL)); } else { directory = NAUTILUS_DIRECTORY (g_object_new (NAUTILUS_TYPE_VFS_DIRECTORY, NULL)); } diff --git a/libnautilus-private/nautilus-dnd.c b/libnautilus-private/nautilus-dnd.c index 265387037..4612d8ccf 100644 --- a/libnautilus-private/nautilus-dnd.c +++ b/libnautilus-private/nautilus-dnd.c @@ -44,6 +44,7 @@ #include <libgnomevfs/gnome-vfs-types.h> #include <libgnomevfs/gnome-vfs-uri.h> #include <libgnomevfs/gnome-vfs-utils.h> +#include <libnautilus-private/nautilus-file-utilities.h> #include <stdio.h> #include <string.h> @@ -219,12 +220,19 @@ nautilus_drag_items_local (const char *target_uri_string, const GList *selection target_uri = gnome_vfs_uri_new (target_uri_string); - /* get the parent URI of the first item in the selection */ - item_uri = gnome_vfs_uri_new (((NautilusDragSelectionItem *)selection_list->data)->uri); - result = gnome_vfs_uri_is_parent (target_uri, item_uri, FALSE); - - gnome_vfs_uri_unref (item_uri); - gnome_vfs_uri_unref (target_uri); + if (target_uri != NULL) { + /* get the parent URI of the first item in the selection */ + item_uri = gnome_vfs_uri_new (((NautilusDragSelectionItem *)selection_list->data)->uri); + + if (item_uri != NULL) { + result = gnome_vfs_uri_is_parent (target_uri, item_uri, FALSE); + + gnome_vfs_uri_unref (item_uri); + } + + gnome_vfs_uri_unref (target_uri); + } + return result; } @@ -240,6 +248,39 @@ nautilus_drag_items_in_trash (const GList *selection_list) return eel_uri_is_in_trash (((NautilusDragSelectionItem *)selection_list->data)->uri); } +gboolean +nautilus_drag_items_on_desktop (const GList *selection_list) +{ + char *uri; + GnomeVFSURI *vfs_uri, *desktop_vfs_uri; + char *desktop_uri; + gboolean result; + + /* check if the first item on the list is in trash. + * FIXME: + * we should really test each item but that would be slow for large selections + * and currently dropped items can only be from the same container + */ + uri = ((NautilusDragSelectionItem *)selection_list->data)->uri; + if (eel_uri_is_desktop (uri)) { + return TRUE; + } + + vfs_uri = gnome_vfs_uri_new (uri); + desktop_uri = nautilus_get_desktop_directory_uri (); + desktop_vfs_uri = gnome_vfs_uri_new (desktop_uri); + g_free (desktop_uri); + + result = gnome_vfs_uri_is_parent (desktop_vfs_uri, vfs_uri, FALSE); + + gnome_vfs_uri_unref (desktop_vfs_uri); + gnome_vfs_uri_unref (vfs_uri); + + return result; + +} + + void nautilus_drag_default_drop_action_for_icons (GdkDragContext *context, const char *target_uri_string, const GList *items, @@ -293,10 +334,17 @@ nautilus_drag_default_drop_action_for_icons (GdkDragContext *context, return; - } else if (eel_str_has_prefix (target_uri_string, NAUTILUS_COMMAND_SPECIFIER) - || eel_str_has_prefix (target_uri_string, NAUTILUS_DESKTOP_COMMAND_SPECIFIER)) { + } else if (g_str_has_prefix (target_uri_string, NAUTILUS_COMMAND_SPECIFIER) + || g_str_has_prefix (target_uri_string, NAUTILUS_DESKTOP_COMMAND_SPECIFIER)) { + if (actions & GDK_ACTION_MOVE) { + *action = GDK_ACTION_MOVE; + } + return; + } else if (eel_uri_is_desktop (target_uri_string)) { if (actions & GDK_ACTION_MOVE) { *action = GDK_ACTION_MOVE; + } else { + *action = context->suggested_action; } return; } else { @@ -312,8 +360,10 @@ nautilus_drag_default_drop_action_for_icons (GdkDragContext *context, dropped_uri = gnome_vfs_uri_new (((NautilusDragSelectionItem *)items->data)->uri); same_fs = TRUE; - gnome_vfs_check_same_fs_uris (dropped_uri, target_uri, &same_fs); - gnome_vfs_uri_unref (dropped_uri); + if (dropped_uri != NULL) { + gnome_vfs_check_same_fs_uris (dropped_uri, target_uri, &same_fs); + gnome_vfs_uri_unref (dropped_uri); + } gnome_vfs_uri_unref (target_uri); if (same_fs) { @@ -790,36 +840,15 @@ gboolean nautilus_drag_selection_includes_special_link (GList *selection_list) { GList *node; - char *uri, *local_path; - gboolean link_in_selection; - GnomeVFSFileInfo *info; - - link_in_selection = FALSE; + char *uri; for (node = selection_list; node != NULL; node = node->next) { uri = ((NautilusDragSelectionItem *) node->data)->uri; - /* FIXME bugzilla.gnome.org 43020: This does sync. I/O and works only locally. */ - local_path = gnome_vfs_get_local_path_from_uri (uri); - - if (local_path) { - info = gnome_vfs_file_info_new (); - gnome_vfs_get_file_info - (local_path, info, - GNOME_VFS_FILE_INFO_GET_MIME_TYPE | - GNOME_VFS_FILE_INFO_FOLLOW_LINKS); - /* assume info is blank on failure */ - link_in_selection = (nautilus_link_local_is_trash_link (local_path, info) || - nautilus_link_local_is_home_link (local_path, info) || - nautilus_link_local_is_volume_link (local_path, info)); - gnome_vfs_file_info_unref (info); - g_free (local_path); - } - - if (link_in_selection) { - break; + if (eel_uri_is_desktop (uri)) { + return TRUE; } } - return link_in_selection; + return FALSE; } diff --git a/libnautilus-private/nautilus-dnd.h b/libnautilus-private/nautilus-dnd.h index 80048b611..53fab627e 100644 --- a/libnautilus-private/nautilus-dnd.h +++ b/libnautilus-private/nautilus-dnd.h @@ -114,6 +114,7 @@ GList *nautilus_drag_build_selection_list (GtkSelectionDat gboolean nautilus_drag_items_local (const char *target_uri, const GList *selection_list); gboolean nautilus_drag_items_in_trash (const GList *selection_list); +gboolean nautilus_drag_items_on_desktop (const GList *selection_list); void nautilus_drag_default_drop_action_for_icons (GdkDragContext *context, const char *target_uri, const GList *items, diff --git a/libnautilus-private/nautilus-file-operations.c b/libnautilus-private/nautilus-file-operations.c index 021172575..6f70b0b4a 100644 --- a/libnautilus-private/nautilus-file-operations.c +++ b/libnautilus-private/nautilus-file-operations.c @@ -46,6 +46,9 @@ #include <libgnomevfs/gnome-vfs-uri.h> #include <libgnomevfs/gnome-vfs-utils.h> #include "nautilus-file-changes-queue.h" +#include "nautilus-file-private.h" +#include "nautilus-desktop-icon-file.h" +#include "nautilus-desktop-link-monitor.h" #include "nautilus-global-preferences.h" #include "nautilus-link.h" #include "nautilus-trash-monitor.h" @@ -991,17 +994,8 @@ handle_transfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, static gboolean is_special_link (const char *uri) { - char *local_path; - gboolean is_special; - local_path = gnome_vfs_get_local_path_from_uri (uri); - if (local_path == NULL) { - return FALSE; - } - is_special = nautilus_link_local_is_special_link (local_path); - g_free (local_path); - - return is_special; + return eel_uri_is_desktop (uri); } static int @@ -1691,19 +1685,6 @@ append_basename (const GnomeVFSURI *target_directory, return gnome_vfs_uri_dup (target_directory); } -static gboolean -vfs_uri_is_special_link (GnomeVFSURI *vfs_uri) -{ - char *uri; - gboolean is_special; - - uri = gnome_vfs_uri_to_string (vfs_uri, GNOME_VFS_URI_HIDE_NONE); - is_special = is_special_link (uri); - g_free (uri); - - return is_special; -} - void nautilus_file_operations_copy_move (const GList *item_uris, GArray *relative_item_points, @@ -1725,7 +1706,6 @@ nautilus_file_operations_copy_move (const GList *item_uris, SyncTransferInfo *sync_transfer_info; GnomeVFSResult result; gboolean target_is_trash; - gboolean is_desktop_trash_link; gboolean duplicate; gboolean target_is_mapping; gboolean have_nonlocal_source; @@ -1945,21 +1925,13 @@ nautilus_file_operations_copy_move (const GList *item_uris, /* Distinguish Trash file on desktop from other trash folders for * message purposes. */ - /* FIXME: is_special_link finds more than just trash links, - * so these messages are wrong. - */ - is_desktop_trash_link = vfs_uri_is_special_link (uri); eel_run_simple_dialog (parent_view, FALSE, ((move_options & GNOME_VFS_XFER_REMOVESOURCE) != 0) - ? (is_desktop_trash_link - ? _("The Trash must remain on the desktop.") - : _("You cannot move this trash folder.")) - : (is_desktop_trash_link - ? _("You cannot copy the Trash.") - : _("You cannot copy this trash folder.")), + ? _("You cannot move this trash folder.") + : _("You cannot copy this trash folder."), ((move_options & GNOME_VFS_XFER_REMOVESOURCE) != 0) ? _("Can't Change Trash Location") : _("Can't Copy Trash"), @@ -2176,15 +2148,41 @@ nautilus_file_operations_delete (const GList *item_uris, { GList *uri_list; const GList *p; + const char *item_uri; + NautilusFile *file; TransferInfo *transfer_info; uri_list = NULL; for (p = item_uris; p != NULL; p = p->next) { - uri_list = g_list_prepend (uri_list, - gnome_vfs_uri_new ((const char *) p->data)); + item_uri = (const char *) p->data; + + if (eel_uri_is_desktop (item_uri)) { + file = nautilus_file_get_existing (item_uri); + if (file != NULL) { + if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) { + NautilusDesktopLink *link; + + link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file)); + + nautilus_desktop_link_monitor_delete_link (nautilus_desktop_link_monitor_get (), + link, + parent_view); + + g_object_unref (link); + } + nautilus_file_unref (file); + } + } else { + uri_list = g_list_prepend (uri_list, + gnome_vfs_uri_new (item_uri)); + } } uri_list = g_list_reverse (uri_list); + if (uri_list == NULL) { + return; + } + transfer_info = transfer_info_new (parent_view); /* localizers: progress dialog title */ diff --git a/libnautilus-private/nautilus-file-utilities.c b/libnautilus-private/nautilus-file-utilities.c index a47c8eb69..8fbb360a8 100644 --- a/libnautilus-private/nautilus-file-utilities.c +++ b/libnautilus-private/nautilus-file-utilities.c @@ -40,7 +40,8 @@ #define NAUTILUS_USER_DIRECTORY_NAME ".nautilus" #define DEFAULT_NAUTILUS_DIRECTORY_MODE (0755) -#define DESKTOP_DIRECTORY_NAME ".gnome-desktop" +#define DESKTOP_DIRECTORY_NAME "Desktop" +#define LEGACY_DESKTOP_DIRECTORY_NAME ".gnome-desktop" #define DEFAULT_DESKTOP_DIRECTORY_MODE (0755) gboolean @@ -74,7 +75,7 @@ nautilus_get_user_directory (void) user_directory = g_build_filename (g_get_home_dir (), NAUTILUS_USER_DIRECTORY_NAME, NULL); - + if (!g_file_test (user_directory, G_FILE_TEST_EXISTS)) { mkdir (user_directory, DEFAULT_NAUTILUS_DIRECTORY_MODE); /* FIXME bugzilla.gnome.org 41286: @@ -104,7 +105,7 @@ nautilus_get_desktop_directory (void) if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR)) { desktop_directory = g_strdup (g_get_home_dir()); } else { - desktop_directory = nautilus_get_gmc_desktop_directory (); + desktop_directory = g_build_filename (g_get_home_dir (), DESKTOP_DIRECTORY_NAME, NULL); if (!g_file_test (desktop_directory, G_FILE_TEST_EXISTS)) { mkdir (desktop_directory, DEFAULT_DESKTOP_DIRECTORY_MODE); /* FIXME bugzilla.gnome.org 41286: @@ -120,6 +121,28 @@ nautilus_get_desktop_directory (void) return desktop_directory; } + +/** + * nautilus_get_desktop_directory_uri: + * + * Get the uri for the directory containing files on the desktop. + * + * Return value: the directory path. + **/ +char * +nautilus_get_desktop_directory_uri (void) +{ + char *desktop_path; + char *desktop_uri; + + desktop_path = nautilus_get_desktop_directory (); + desktop_uri = gnome_vfs_get_uri_from_local_path (desktop_path); + g_free (desktop_path); + + return desktop_uri; +} + + /** * nautilus_get_gmc_desktop_directory: * @@ -130,7 +153,7 @@ nautilus_get_desktop_directory (void) char * nautilus_get_gmc_desktop_directory (void) { - return g_build_filename (g_get_home_dir (), DESKTOP_DIRECTORY_NAME, NULL); + return g_build_filename (g_get_home_dir (), LEGACY_DESKTOP_DIRECTORY_NAME, NULL); } /** diff --git a/libnautilus-private/nautilus-file-utilities.h b/libnautilus-private/nautilus-file-utilities.h index 3a9d6ebb3..9abc480d6 100644 --- a/libnautilus-private/nautilus-file-utilities.h +++ b/libnautilus-private/nautilus-file-utilities.h @@ -36,6 +36,7 @@ gboolean nautilus_file_name_matches_backup_pattern (const char *name_or_relati */ char * nautilus_get_user_directory (void); char * nautilus_get_desktop_directory (void); +char * nautilus_get_desktop_directory_uri (void); char * nautilus_get_gmc_desktop_directory (void); char * nautilus_get_pixmap_directory (void); diff --git a/libnautilus-private/nautilus-file.c b/libnautilus-private/nautilus-file.c index 12388fa6d..be801d3d9 100644 --- a/libnautilus-private/nautilus-file.c +++ b/libnautilus-private/nautilus-file.c @@ -28,6 +28,9 @@ #include "nautilus-directory-metafile.h" #include "nautilus-directory-notify.h" #include "nautilus-directory-private.h" +#include "nautilus-desktop-directory.h" +#include "nautilus-desktop-directory-file.h" +#include "nautilus-desktop-icon-file.h" #include "nautilus-file-attributes.h" #include "nautilus-file-private.h" #include "nautilus-file-utilities.h" @@ -136,6 +139,13 @@ nautilus_file_new_from_relative_uri (NautilusDirectory *directory, if (self_owned && NAUTILUS_IS_TRASH_DIRECTORY (directory)) { file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_TRASH_FILE, NULL)); + } else if (NAUTILUS_IS_DESKTOP_DIRECTORY (directory)) { + if (self_owned) { + file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE, NULL)); + } else { + file = NULL; + g_assert_not_reached (); + } } else { file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL)); } @@ -272,6 +282,7 @@ static NautilusFile * nautilus_file_get_internal (const char *uri, gboolean create) { char *canonical_uri, *directory_uri, *relative_uri, *file_name; + const char *relative_uri_tmp; gboolean self_owned; GnomeVFSURI *vfs_uri, *directory_vfs_uri; NautilusDirectory *directory; @@ -302,24 +313,29 @@ nautilus_file_get_internal (const char *uri, gboolean create) } } + self_owned = FALSE; + directory_uri = NULL; + /* Make VFS version of directory URI. */ if (vfs_uri == NULL) { - directory_vfs_uri = NULL; + if (eel_uri_is_desktop (uri) && + strcmp (uri, EEL_DESKTOP_URI) != 0) { + directory_uri = g_strdup (EEL_DESKTOP_URI); + } } else { directory_vfs_uri = gnome_vfs_uri_get_parent (vfs_uri); + if (directory_vfs_uri != NULL) { + directory_uri = gnome_vfs_uri_to_string + (directory_vfs_uri, + GNOME_VFS_URI_HIDE_NONE); + gnome_vfs_uri_unref (directory_vfs_uri); + } gnome_vfs_uri_unref (vfs_uri); } - - self_owned = directory_vfs_uri == NULL; - if (self_owned) { - /* Use the item itself if we have no parent. */ + + if (directory_uri == NULL) { + self_owned = TRUE; directory_uri = g_strdup (canonical_uri); - } else { - /* Make text version of directory URI. */ - directory_uri = gnome_vfs_uri_to_string - (directory_vfs_uri, - GNOME_VFS_URI_HIDE_NONE); - gnome_vfs_uri_unref (directory_vfs_uri); } /* Get object that represents the directory. */ @@ -328,11 +344,19 @@ nautilus_file_get_internal (const char *uri, gboolean create) /* Get the name for the file. */ if (vfs_uri == NULL) { - g_assert (self_owned); - if (directory != NULL) { + if (self_owned && directory != NULL) { file_name = nautilus_directory_get_name_for_self_as_new_file (directory); relative_uri = gnome_vfs_escape_string (file_name); g_free (file_name); + } else if (eel_uri_is_desktop (uri)) { + /* Special case desktop files here. They have no vfs_uri */ + relative_uri_tmp = uri + strlen (EEL_DESKTOP_URI); + while (*relative_uri_tmp == '/') { + relative_uri_tmp++; + } + relative_uri = strdup (relative_uri_tmp); + } else { + g_assert_not_reached (); } } @@ -746,7 +770,7 @@ nautilus_file_can_rename (NautilusFile *file) { NautilusFile *parent; gboolean can_rename; - char *uri, *path; + char *uri; g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE); @@ -767,23 +791,15 @@ nautilus_file_can_rename (NautilusFile *file) can_rename = TRUE; uri = nautilus_file_get_uri (file); - path = gnome_vfs_get_local_path_from_uri (uri); /* Certain types of links can't be renamed */ - if (path != NULL && nautilus_file_is_nautilus_link (file)) { - /* FIXME: This reads the link file every time -- seems - * bad to do that even though it's known to be local. - */ - switch (nautilus_link_local_get_link_type (path, file->details->info)) { - case NAUTILUS_LINK_TRASH: - case NAUTILUS_LINK_MOUNT: - can_rename = FALSE; - break; + if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) { + NautilusDesktopLink *link; - case NAUTILUS_LINK_HOME: - case NAUTILUS_LINK_GENERIC: - break; - } + link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file)); + + can_rename = nautilus_desktop_link_can_rename (link); + g_object_unref (link); } /* Nautilus trash directories cannot be renamed */ @@ -792,7 +808,6 @@ nautilus_file_can_rename (NautilusFile *file) } g_free (uri); - g_free (path); if (!can_rename) { return FALSE; @@ -1047,6 +1062,22 @@ rename_guts (NautilusFile *file, (* callback) (file, GNOME_VFS_ERROR_NOT_SUPPORTED, callback_data); return; } + + + if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) { + NautilusDesktopLink *link; + + link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file)); + + if (nautilus_desktop_link_rename (link, new_name)) { + (* callback) (file, GNOME_VFS_OK, callback_data); + } else { + (* callback) (file, GNOME_VFS_ERROR_GENERIC, callback_data); + } + + g_object_unref (link); + return; + } if (is_local_desktop_file) { /* Don't actually change the name if the new name is the same. @@ -2069,7 +2100,7 @@ nautilus_file_is_in_desktop (NautilusFile *file) /* This handles visiting other people's desktops, but it can arguably * be said that this might break and that we should lookup the passwd table. */ - return strstr (file->details->directory->details->uri, "/.gnome-desktop") != NULL; + return strstr (file->details->directory->details->uri, "/Desktop") != NULL; } static gboolean @@ -2451,11 +2482,22 @@ char * nautilus_file_get_drop_target_uri (NautilusFile *file) { char *uri, *target_uri; + NautilusDesktopLink *link; g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL); + if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) { + link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file)); + + uri = nautilus_desktop_link_get_activation_uri (link); + g_object_unref (link); + if (uri != NULL) { + return uri; + } + } + uri = nautilus_file_get_uri (file); - + /* Check for Nautilus link */ if (nautilus_file_is_nautilus_link (file)) { /* FIXME bugzilla.gnome.org 43020: This does sync. I/O and works only locally. */ @@ -2512,7 +2554,6 @@ nautilus_file_get_uri (NautilusFile *file) } return g_strconcat (file->details->directory->details->uri, - "/", file->details->relative_uri, NULL); } diff --git a/libnautilus-private/nautilus-global-preferences.c b/libnautilus-private/nautilus-global-preferences.c index 3d0ed75e3..55aaac15c 100644 --- a/libnautilus-private/nautilus-global-preferences.c +++ b/libnautilus-private/nautilus-global-preferences.c @@ -55,6 +55,8 @@ static gpointer default_font_callback (void); static gpointer default_home_location_callback (void); static gpointer default_default_folder_viewer_callback (void); static void import_old_preferences_if_needed (void); +static gpointer default_home_link_name (void); +static gpointer default_trash_link_name (void); /* An enumeration used for installing type specific preferences defaults. */ typedef enum @@ -491,6 +493,29 @@ static const PreferenceDefault preference_defaults[] = { "default_zoom_level" }, + /* Desktop Preferences */ + { NAUTILUS_PREFERENCES_DESKTOP_HOME_VISIBLE, + PREFERENCE_BOOLEAN, + GINT_TO_POINTER (TRUE) + }, + + { NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME, + PREFERENCE_STRING, + NULL, + default_home_link_name, g_free, + }, + + { NAUTILUS_PREFERENCES_DESKTOP_TRASH_VISIBLE, + PREFERENCE_BOOLEAN, + GINT_TO_POINTER (TRUE) + }, + + { NAUTILUS_PREFERENCES_DESKTOP_TRASH_NAME, + PREFERENCE_STRING, + NULL, + default_trash_link_name, g_free, + }, + /* non-visible preferences */ { NAUTILUS_PREFERENCES_ADD_TO_SESSION, PREFERENCE_BOOLEAN, @@ -500,6 +525,28 @@ static const PreferenceDefault preference_defaults[] = { { NULL } }; +static gpointer +default_home_link_name (void) +{ + /* Note to translators: If it's hard to compose a good home + * icon name from the user name, you can use a string without + * an "%s" here, in which case the home icon name will not + * include the user's name, which should be fine. To avoid a + * warning, put "%.0s" somewhere in the string, which will + * match the user name string passed by the C code, but not + * put the user name in the final string. + */ + return g_strdup_printf (_("%s's Home"), g_get_user_name ()); +} + +static gpointer +default_trash_link_name (void) +{ + return g_strdup (_("Trash")); +} + + + /** * global_preferences_register_enumerations * diff --git a/libnautilus-private/nautilus-global-preferences.h b/libnautilus-private/nautilus-global-preferences.h index 19abe6c4a..4b51ab493 100644 --- a/libnautilus-private/nautilus-global-preferences.h +++ b/libnautilus-private/nautilus-global-preferences.h @@ -167,6 +167,11 @@ typedef enum /* Gnome session management */ #define NAUTILUS_PREFERENCES_ADD_TO_SESSION "preferences/add_to_session" +#define NAUTILUS_PREFERENCES_DESKTOP_HOME_VISIBLE "desktop/home_icon_visible" +#define NAUTILUS_PREFERENCES_DESKTOP_HOME_NAME "desktop/home_icon_name" +#define NAUTILUS_PREFERENCES_DESKTOP_TRASH_VISIBLE "desktop/trash_icon_visible" +#define NAUTILUS_PREFERENCES_DESKTOP_TRASH_NAME "desktop/trash_icon_name" + void nautilus_global_preferences_init (void); void nautilus_global_preferences_init_with_folder_browsing (void); void nautilus_global_preferences_set_default_folder_viewer (const char *iid); diff --git a/libnautilus-private/nautilus-icon-container.c b/libnautilus-private/nautilus-icon-container.c index 19b8a0d83..50f8ca551 100644 --- a/libnautilus-private/nautilus-icon-container.c +++ b/libnautilus-private/nautilus-icon-container.c @@ -1477,7 +1477,9 @@ lay_down_icons_tblr (NautilusIconContainer *container, GList *icons) } /* Check and see if we need to move to a new column */ - if (y != DESKTOP_PAD_VERTICAL && y > height - icon_height) { + if (y != DESKTOP_PAD_VERTICAL && y > height - icon_height && + /* Make sure we lay out at least one icon per column, to make progress */ + p != icons) { x += column_width + DESKTOP_PAD_HORIZONTAL; break; } diff --git a/libnautilus-private/nautilus-icon-dnd.c b/libnautilus-private/nautilus-icon-dnd.c index 0c461e97e..33dfefc5a 100644 --- a/libnautilus-private/nautilus-icon-dnd.c +++ b/libnautilus-private/nautilus-icon-dnd.c @@ -57,6 +57,7 @@ #include <libgnomevfs/gnome-vfs-uri.h> #include <libgnomevfs/gnome-vfs-utils.h> #include <libgnomevfs/gnome-vfs-mime-utils.h> +#include <libnautilus-private/nautilus-file-utilities.h> #include <stdio.h> #include <string.h> @@ -513,6 +514,8 @@ nautilus_icon_container_selection_items_local (NautilusIconContainer *container, * would not work for it. */ result = nautilus_drag_items_in_trash (items); + } else if (eel_uri_is_desktop (container_uri_string)) { + result = nautilus_drag_items_on_desktop (items); } else { result = nautilus_drag_items_local (container_uri_string, items); } @@ -831,6 +834,7 @@ handle_nonlocal_move (NautilusIconContainer *container, { GList *source_uris, *p; GArray *source_item_locations; + gboolean free_target_uri; int index; if (container->details->dnd_info->drag_info.selection_list == NULL) { @@ -860,7 +864,14 @@ handle_nonlocal_move (NautilusIconContainer *container, ((NautilusDragSelectionItem *)p->data)->icon_y; } } - + + free_target_uri = FALSE; + /* Rewrite internal desktop URIs to the normal target uri */ + if (eel_uri_is_desktop (target_uri)) { + target_uri = nautilus_get_desktop_directory_uri (); + free_target_uri = TRUE; + } + /* start the copy */ g_signal_emit_by_name (container, "move_copy_items", source_uris, @@ -869,6 +880,10 @@ handle_nonlocal_move (NautilusIconContainer *container, context->action, x, y); + if (free_target_uri) { + g_free ((char *)target_uri); + } + g_list_free (source_uris); g_array_free (source_item_locations, TRUE); } |