diff options
author | Pavel Cisler <pavel@eazel.com> | 2000-04-18 03:13:56 +0000 |
---|---|---|
committer | Pavel Cisler <pce@src.gnome.org> | 2000-04-18 03:13:56 +0000 |
commit | a49e9119f814b03eb1c10f8900ff01518c5d178f (patch) | |
tree | b42c962b53044b04cd4607cc9e313af954765a16 | |
parent | 4393e9621451887324cc7d2c101deb7f06439c8b (diff) | |
download | nautilus-a49e9119f814b03eb1c10f8900ff01518c5d178f.tar.gz |
This checkin requires new gnome-vfs.
2000-04-17 Pavel Cisler <pavel@eazel.com>
This checkin requires new gnome-vfs.
Plumbing for making copied/moved/deleted files show up update
in their respective new locations.
* libnautilus-extensions/nautilus-file-changes-queue.h
* libnautilus-extensions/nautilus-file-changes-queue.c
* libnautilus-extensions/Makefile.am
Shared queue used by the copy engine to send update notification
requests to NautilusDirectory during file copy/move/delete operations.
* libnautilus-extensions/nautilus-directory-private.h:
* libnautilus-extensions/nautilus-directory.c:
(nautilus_directory_notify_files_added),
(nautilus_directory_notify_files_removed),
(nautilus_directory_notify_files_moved):
Stub calls that will be hooked up to the NautilusDirectory
notification calls to dispatch the notification updates.
* src/file-manager/dfos-xfer.c:
(sync_xfer_callback):
New callback that gets called in the async copy engine context
and produces change entries stuffing them into the file changes
queue.
* src/file-manager/dfos-xfer.c:
(handle_xfer_ok):
Added calls to the new nautilus_file_changes_consume_changes
from the progress update callback. This callback is called in
the user interface context and consumes the change entries
from the file changes queue, sending them in chunks to be
dispatched by to the individual Nautilus directory objects.
* src/file-manager/dfos-xfer.c:
(handle_xfer_ok):
Updated to use new progress enum values.
* src/file-manager/dfos-xfer.c:
(update_xfer_callback):
Renamed from sync_xfer_callback.
* src/file-manager/dfos-xfer.c:
(gnome_vfs_async_xfer):
Pass in new sync_xfer_callback parameters.
-rw-r--r-- | ChangeLog | 47 | ||||
-rw-r--r-- | libnautilus-extensions/Makefile.am | 1 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-directory-private.h | 10 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-directory.c | 80 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-file-changes-queue.c | 262 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-file-changes-queue.h | 43 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-file-operations.c | 53 | ||||
-rw-r--r-- | libnautilus-private/Makefile.am | 1 | ||||
-rw-r--r-- | libnautilus-private/nautilus-directory-private.h | 10 | ||||
-rw-r--r-- | libnautilus-private/nautilus-directory.c | 80 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-changes-queue.c | 262 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-changes-queue.h | 43 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-operations.c | 53 | ||||
-rw-r--r-- | src/file-manager/dfos-xfer.c | 53 |
14 files changed, 968 insertions, 30 deletions
@@ -1,3 +1,50 @@ +2000-04-17 Pavel Cisler <pavel@eazel.com> + + This checkin requires new gnome-vfs. + + Plumbing for making copied/moved/deleted files show up update + in their respective new locations. + + * libnautilus-extensions/nautilus-file-changes-queue.h + * libnautilus-extensions/nautilus-file-changes-queue.c + * libnautilus-extensions/Makefile.am + Shared queue used by the copy engine to send update notification + requests to NautilusDirectory during file copy/move/delete operations. + + * libnautilus-extensions/nautilus-directory-private.h: + * libnautilus-extensions/nautilus-directory.c: + (nautilus_directory_notify_files_added), + (nautilus_directory_notify_files_removed), + (nautilus_directory_notify_files_moved): + Stub calls that will be hooked up to the NautilusDirectory + notification calls to dispatch the notification updates. + + * src/file-manager/dfos-xfer.c: + (sync_xfer_callback): + New callback that gets called in the async copy engine context + and produces change entries stuffing them into the file changes + queue. + + * src/file-manager/dfos-xfer.c: + (handle_xfer_ok): + Added calls to the new nautilus_file_changes_consume_changes + from the progress update callback. This callback is called in + the user interface context and consumes the change entries + from the file changes queue, sending them in chunks to be + dispatched by to the individual Nautilus directory objects. + + * src/file-manager/dfos-xfer.c: + (handle_xfer_ok): + Updated to use new progress enum values. + + * src/file-manager/dfos-xfer.c: + (update_xfer_callback): + Renamed from sync_xfer_callback. + + * src/file-manager/dfos-xfer.c: + (gnome_vfs_async_xfer): + Pass in new sync_xfer_callback parameters. + 2000-04-17 Darin Adler <darin@eazel.com> * components/services/install/.cvsignore: Generated files. diff --git a/libnautilus-extensions/Makefile.am b/libnautilus-extensions/Makefile.am index b69de5305..665e9b86e 100644 --- a/libnautilus-extensions/Makefile.am +++ b/libnautilus-extensions/Makefile.am @@ -75,6 +75,7 @@ libnautilus_extensions_la_SOURCES = \ nautilus-entry.c \ nautilus-file-utilities.c \ nautilus-file.c \ + nautilus-file-changes-queue.c \ nautilus-gdk-extensions.c \ nautilus-gdk-pixbuf-extensions.c \ nautilus-glib-extensions.c \ diff --git a/libnautilus-extensions/nautilus-directory-private.h b/libnautilus-extensions/nautilus-directory-private.h index ad77b0362..f4b1743ce 100644 --- a/libnautilus-extensions/nautilus-directory-private.h +++ b/libnautilus-extensions/nautilus-directory-private.h @@ -81,6 +81,11 @@ typedef struct { gpointer callback_data; } QueuedCallback; +typedef struct { + char *from_uri; + char *to_uri; +} URIPair; + NautilusFile *nautilus_directory_find_file (NautilusDirectory *directory, const char *file_name); char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, @@ -103,5 +108,10 @@ void nautilus_directory_cancel_callback_internal (NautilusDirectory void nautilus_directory_call_when_ready_internal (NautilusDirectory *directory, const QueuedCallback *callback); +/* Change notification calls */ +void nautilus_directory_notify_files_added (GList *uris); +void nautilus_directory_notify_files_removed (GList *uris); +void nautilus_directory_notify_files_moved (GList *uri_pairs); + /* debugging functions */ int nautilus_directory_number_outstanding (void); diff --git a/libnautilus-extensions/nautilus-directory.c b/libnautilus-extensions/nautilus-directory.c index 3e12d5b21..a6aeca645 100644 --- a/libnautilus-extensions/nautilus-directory.c +++ b/libnautilus-extensions/nautilus-directory.c @@ -1658,6 +1658,86 @@ process_pending_file_attribute_requests (NautilusDirectory *directory) g_free (uri); } +void +nautilus_directory_notify_files_added (GList *uris) +{ + GList *p; + for (p = uris; p != NULL; p = p->next) { +#ifdef COPY_NOTIFY_TESTING + printf("added %s\n", (const char *)p->data); +#endif + /* + FIXME: + + Find the parent directory of uri in directory_objects. + Create a new NautilusFile and add it to the directory. + Notify all observers of directory about new NautilusFile. + */ + + } + nautilus_g_list_free_deep (uris); +} + +void +nautilus_directory_notify_files_removed (GList *uris) +{ + GList *p; + for (p = uris; p != NULL; p = p->next) { +#ifdef COPY_NOTIFY_TESTING + printf("removed %s\n", (const char *)p->data); +#endif + /* + FIXME: + + Find the parent directory of uri in directory_objects. + Look up NautilusFile for uri. + Notify all observers of directory that the NautilusFile is + being removed. + Remove the NautilusFile from directory and delete it. + */ + + } + nautilus_g_list_free_deep (uris); +} + +void +nautilus_directory_notify_files_moved (GList *uri_pairs) +{ + GList *p; + for (p = uri_pairs; p != NULL; p = p->next) { +#ifdef COPY_NOTIFY_TESTING + URIPair *pair; + + pair = p->data; + printf("moved %s to %s \n", pair->from_uri, pair->to_uri); +#endif + /* + FIXME: + + Find the parent directory of pair->from_uri in directory_objects. + Find the parent directory of pair->from_to in directory_objects. + Look up NautilusFile for pair->from_uri. + ??? + + */ + + } + + /* deep delete the list of pairs */ + for (p = uri_pairs; p != NULL; p = p->next) { + URIPair *pair; + + /* delete the strings in each pair */ + pair = p->data; + g_free (pair->from_uri); + g_free (pair->to_uri); + } + + /* delete the list and the now empty pair structs */ + nautilus_g_list_free_deep (uri_pairs); + +} + #if !defined (NAUTILUS_OMIT_SELF_CHECK) static int data_dummy; diff --git a/libnautilus-extensions/nautilus-file-changes-queue.c b/libnautilus-extensions/nautilus-file-changes-queue.c new file mode 100644 index 000000000..b69212601 --- /dev/null +++ b/libnautilus-extensions/nautilus-file-changes-queue.c @@ -0,0 +1,262 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.h: Nautilus directory model. + + Copyright (C) 1999, 2000 Eazel, 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. + +*/ + +#include "nautilus-file-changes-queue-private.h" +#include "nautilus-directory-private.h" + +#ifdef G_THREADS_ENABLED +#define MUTEX_LOCK(a) if ((a) != NULL) g_mutex_lock (a) +#define MUTEX_UNLOCK(a) if ((a) != NULL) g_mutex_unlock (a) +#else +#define MUTEX_LOCK(a) +#define MUTEX_UNLOCK(a) +#endif + +static NautilusFileChangesQueue *file_changes_queue; + +static void +nautilus_file_change_free (NautilusFileChange *change) +{ + g_free (change->from_uri); + g_free (change->to_uri); +} + +static NautilusFileChangesQueue * +nautilus_file_changes_queue_new (void) +{ + NautilusFileChangesQueue *result = g_new (NautilusFileChangesQueue, 1); + result->details = g_new0 (NautilusFileChangesQueueDetails, 1); + +#ifdef G_THREADS_ENABLED + result->details->mutex = g_mutex_new (); +#endif + return result; +} + +static NautilusFileChangesQueue * +nautilus_file_changes_queue_get (void) +{ + if (file_changes_queue == NULL) + file_changes_queue = nautilus_file_changes_queue_new(); + + return file_changes_queue; +} + +void +nautilus_file_changes_queue_free (NautilusFileChangesQueue *queue) +{ + GList *p; + if (queue == NULL) { + return; + } + +#ifdef G_THREADS_ENABLED + /* if lock on a defunct mutext were defined (returning a failure) + * we would lock here + */ +#endif + + for (p = queue->details->head; p != NULL; p = p->next) { + nautilus_file_change_free (p->data); + } + g_list_free (queue->details->head); + +#ifdef G_THREADS_ENABLED + g_mutex_free (queue->details->mutex); +#endif + g_free (queue->details); + g_free (queue); +} + +static void +nautilus_file_changes_queue_add_common (NautilusFileChangesQueue *queue, + NautilusFileChange *new_item) +{ + /* enqueue the new queue item while locking down the list */ + MUTEX_LOCK (queue->details->mutex); + + queue->details->head = g_list_prepend (queue->details->head, new_item); + if (queue->details->tail == NULL) + queue->details->tail = queue->details->head; + + MUTEX_UNLOCK (queue->details->mutex); +} + +void +nautilus_file_changes_queue_file_added (const char *uri) +{ + NautilusFileChange *new_item; + NautilusFileChangesQueue *queue; + + queue = nautilus_file_changes_queue_get(); + g_assert (queue); + + new_item = g_new0 (NautilusFileChange, 1); + new_item->kind = CHANGE_FILE_ADDED; + new_item->from_uri = g_strdup (uri); + nautilus_file_changes_queue_add_common (queue, new_item); +} + +void +nautilus_file_changes_queue_file_removed (const char *uri) +{ + NautilusFileChange *new_item; + NautilusFileChangesQueue *queue; + + queue = nautilus_file_changes_queue_get(); + g_assert (queue); + + new_item = g_new0 (NautilusFileChange, 1); + new_item->kind = CHANGE_FILE_REMOVED; + new_item->from_uri = g_strdup (uri); + nautilus_file_changes_queue_add_common (queue, new_item); +} + +void +nautilus_file_changes_queue_file_moved (const char *from, const char *to) +{ + NautilusFileChange *new_item; + NautilusFileChangesQueue *queue; + + queue = nautilus_file_changes_queue_get(); + g_assert (queue); + + new_item = g_new (NautilusFileChange, 1); + new_item->kind = CHANGE_FILE_REMOVED; + new_item->from_uri = g_strdup (from); + new_item->to_uri = g_strdup (to); + nautilus_file_changes_queue_add_common (queue, new_item); +} + +static NautilusFileChange * +nautilus_file_changes_queue_get_change (NautilusFileChangesQueue *queue) +{ + GList *new_tail; + NautilusFileChange *result; + + /* dequeue the tail item while locking down the list */ + MUTEX_LOCK (queue->details->mutex); + + if (queue->details->tail == NULL) { + result = NULL; + } else { + new_tail = queue->details->tail->prev; + result = queue->details->tail->data; + queue->details->head = g_list_remove_link (queue->details->head, + queue->details->tail); + queue->details->tail = new_tail; + } + + MUTEX_UNLOCK (queue->details->mutex); + + return result; +} + +enum { + CONSUME_CHANGES_MAX_CHUNK = 10 +}; + +/* go through changes in the change queue, send ones with the same kind + * in a list to the different nautilus_directory_notify calls + */ +void +nautilus_file_changes_consume_changes (gboolean consume_all) +{ + NautilusFileChange *change; + GList *additions; + GList *deletions; + GList *moves; + URIPair *pair; + int kind; + int chunk_count; + + additions = NULL; + deletions = NULL; + moves = NULL; + kind = CHANGE_FILE_INITIAL; + + if (file_changes_queue == NULL) + return; + + for (chunk_count = 0; ; chunk_count++) { + change = nautilus_file_changes_queue_get_change (file_changes_queue); + + + if (change == NULL + /* no changes left */ + || change->kind != kind + /* all the changes we have are different that the new one */ + || (!consume_all && chunk_count >= CONSUME_CHANGES_MAX_CHUNK)) { + /* we have reached the chunk maximum */ + + + /* send changes we collected off */ + if (additions != NULL) { + nautilus_directory_notify_files_added (additions); + additions = NULL; + } + if (deletions != NULL) { + nautilus_directory_notify_files_removed (deletions); + deletions = NULL; + } + if (moves != NULL) { + nautilus_directory_notify_files_moved (moves); + moves = NULL; + } + } + + if (change == NULL) { + /* we are done */ + break; + } + + + kind = change->kind; + + /* add the new change to the list */ + switch (kind) { + case CHANGE_FILE_ADDED: + additions = g_list_append (additions, change->from_uri); + break; + + case CHANGE_FILE_REMOVED: + deletions = g_list_append (deletions, change->from_uri); + break; + + case CHANGE_FILE_MOVED: + pair = g_new (URIPair, 1); + pair->from_uri = change->from_uri; + pair->to_uri = change->to_uri; + moves = g_list_append (moves, pair); + break; + + default: + g_assert_not_reached (); + break; + } + + change->from_uri = NULL; + change->to_uri = NULL; + } +} + diff --git a/libnautilus-extensions/nautilus-file-changes-queue.h b/libnautilus-extensions/nautilus-file-changes-queue.h new file mode 100644 index 000000000..3cedb1c09 --- /dev/null +++ b/libnautilus-extensions/nautilus-file-changes-queue.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.h: Nautilus directory model. + + Copyright (C) 1999, 2000 Eazel, 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. + +*/ + +#ifndef NAUTILUS_FILE_CHANGES_QUEUE_H +#define NAUTILUS_FILE_CHANGES_QUEUE_H + +typedef struct NautilusFileChangesQueue NautilusFileChangesQueue; +typedef struct NautilusFileChangesQueueDetails NautilusFileChangesQueueDetails; + +void nautilus_file_changes_queue_free (NautilusFileChangesQueue *queue); + +void nautilus_file_changes_queue_file_added (const char *uri); +void nautilus_file_changes_queue_file_removed (const char *uri); +void nautilus_file_changes_queue_file_moved (const char *from_uri, + const char *to_uri); + +void nautilus_file_changes_consume_changes (gboolean consume_all); + +struct NautilusFileChangesQueue { + NautilusFileChangesQueueDetails *details; +}; + +#endif diff --git a/libnautilus-extensions/nautilus-file-operations.c b/libnautilus-extensions/nautilus-file-operations.c index e3c2895c8..50bb95f90 100644 --- a/libnautilus-extensions/nautilus-file-operations.c +++ b/libnautilus-extensions/nautilus-file-operations.c @@ -27,6 +27,7 @@ #include <gnome.h> #include "dfos-xfer.h" +#include "libnautilus-extensions/nautilus-file-changes-queue.h" #include "fm-directory-view.h" @@ -122,9 +123,14 @@ handle_xfer_ok (const GnomeVFSXferProgressInfo *progress_info, progress_info->bytes_total); return TRUE; - case GNOME_VFS_XFER_PHASE_XFERRING: + case GNOME_VFS_XFER_PHASE_MOVING: + case GNOME_VFS_XFER_PHASE_DELETESOURCE: case GNOME_VFS_XFER_PHASE_OPENSOURCE: case GNOME_VFS_XFER_PHASE_OPENTARGET: + nautilus_file_changes_consume_changes (FALSE); + /* fall through */ + + case GNOME_VFS_XFER_PHASE_COPYING: if (progress_info->bytes_copied == 0) { dfos_xfer_progress_dialog_new_file (DFOS_XFER_PROGRESS_DIALOG @@ -149,6 +155,7 @@ handle_xfer_ok (const GnomeVFSXferProgressInfo *progress_info, return TRUE; case GNOME_VFS_XFER_PHASE_COMPLETED: + nautilus_file_changes_consume_changes (TRUE); gtk_widget_destroy (xfer_info->progress_dialog); g_free (xfer_info); return TRUE; @@ -249,7 +256,7 @@ handle_xfer_duplicate (GnomeVFSXferProgressInfo *progress_info, } static int -sync_xfer_callback ( +update_xfer_callback (GnomeVFSAsyncHandle *handle, GnomeVFSXferProgressInfo *progress_info, gpointer data) { @@ -269,16 +276,40 @@ sync_xfer_callback ( default: g_warning (_("Unknown GnomeVFSXferProgressStatus %d"), progress_info->status); - return FALSE; + return 0; } } +/* Low-level callback, called for every copy engine operation. + * Generates notifications about new, deleted and moved files. + */ static int -xfer_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSXferProgressInfo *progress_info, - gpointer data) +sync_xfer_callback (GnomeVFSXferProgressInfo *progress_info, gpointer data) { - return sync_xfer_callback (progress_info, data); + XferInfo *xfer_info; + + xfer_info = (XferInfo *) data; + + if (progress_info->status == GNOME_VFS_XFER_PROGRESS_STATUS_OK) { + switch (progress_info->phase) { + case GNOME_VFS_XFER_PHASE_OPENTARGET: + nautilus_file_changes_queue_file_added (progress_info->target_name); + break; + + case GNOME_VFS_XFER_PHASE_MOVING: + nautilus_file_changes_queue_file_moved (progress_info->source_name, + progress_info->target_name); + break; + + case GNOME_VFS_XFER_PHASE_DELETESOURCE: + nautilus_file_changes_queue_file_removed (progress_info->source_name); + break; + + default: + break; + } + } + return 1; } @@ -305,8 +336,9 @@ dfos_xfer (DFOS *dfos, options, GNOME_VFS_XFER_ERROR_MODE_QUERY, overwrite_mode, - xfer_callback, - xfer_info); + update_xfer_callback, + xfer_info, + NULL, NULL); if (result != GNOME_VFS_OK) { gchar *message; @@ -441,7 +473,8 @@ fs_xfer (const GList *item_uris, target_dir_uri_text, NULL, move_options, GNOME_VFS_XFER_ERROR_MODE_QUERY, GNOME_VFS_XFER_OVERWRITE_MODE_QUERY, - &xfer_callback, xfer_info); + &update_xfer_callback, xfer_info, + &sync_xfer_callback, xfer_info); if (!target_dir) g_free ((char *)target_dir_uri_text); diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am index b69de5305..665e9b86e 100644 --- a/libnautilus-private/Makefile.am +++ b/libnautilus-private/Makefile.am @@ -75,6 +75,7 @@ libnautilus_extensions_la_SOURCES = \ nautilus-entry.c \ nautilus-file-utilities.c \ nautilus-file.c \ + nautilus-file-changes-queue.c \ nautilus-gdk-extensions.c \ nautilus-gdk-pixbuf-extensions.c \ nautilus-glib-extensions.c \ diff --git a/libnautilus-private/nautilus-directory-private.h b/libnautilus-private/nautilus-directory-private.h index ad77b0362..f4b1743ce 100644 --- a/libnautilus-private/nautilus-directory-private.h +++ b/libnautilus-private/nautilus-directory-private.h @@ -81,6 +81,11 @@ typedef struct { gpointer callback_data; } QueuedCallback; +typedef struct { + char *from_uri; + char *to_uri; +} URIPair; + NautilusFile *nautilus_directory_find_file (NautilusDirectory *directory, const char *file_name); char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, @@ -103,5 +108,10 @@ void nautilus_directory_cancel_callback_internal (NautilusDirectory void nautilus_directory_call_when_ready_internal (NautilusDirectory *directory, const QueuedCallback *callback); +/* Change notification calls */ +void nautilus_directory_notify_files_added (GList *uris); +void nautilus_directory_notify_files_removed (GList *uris); +void nautilus_directory_notify_files_moved (GList *uri_pairs); + /* debugging functions */ int nautilus_directory_number_outstanding (void); diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c index 3e12d5b21..a6aeca645 100644 --- a/libnautilus-private/nautilus-directory.c +++ b/libnautilus-private/nautilus-directory.c @@ -1658,6 +1658,86 @@ process_pending_file_attribute_requests (NautilusDirectory *directory) g_free (uri); } +void +nautilus_directory_notify_files_added (GList *uris) +{ + GList *p; + for (p = uris; p != NULL; p = p->next) { +#ifdef COPY_NOTIFY_TESTING + printf("added %s\n", (const char *)p->data); +#endif + /* + FIXME: + + Find the parent directory of uri in directory_objects. + Create a new NautilusFile and add it to the directory. + Notify all observers of directory about new NautilusFile. + */ + + } + nautilus_g_list_free_deep (uris); +} + +void +nautilus_directory_notify_files_removed (GList *uris) +{ + GList *p; + for (p = uris; p != NULL; p = p->next) { +#ifdef COPY_NOTIFY_TESTING + printf("removed %s\n", (const char *)p->data); +#endif + /* + FIXME: + + Find the parent directory of uri in directory_objects. + Look up NautilusFile for uri. + Notify all observers of directory that the NautilusFile is + being removed. + Remove the NautilusFile from directory and delete it. + */ + + } + nautilus_g_list_free_deep (uris); +} + +void +nautilus_directory_notify_files_moved (GList *uri_pairs) +{ + GList *p; + for (p = uri_pairs; p != NULL; p = p->next) { +#ifdef COPY_NOTIFY_TESTING + URIPair *pair; + + pair = p->data; + printf("moved %s to %s \n", pair->from_uri, pair->to_uri); +#endif + /* + FIXME: + + Find the parent directory of pair->from_uri in directory_objects. + Find the parent directory of pair->from_to in directory_objects. + Look up NautilusFile for pair->from_uri. + ??? + + */ + + } + + /* deep delete the list of pairs */ + for (p = uri_pairs; p != NULL; p = p->next) { + URIPair *pair; + + /* delete the strings in each pair */ + pair = p->data; + g_free (pair->from_uri); + g_free (pair->to_uri); + } + + /* delete the list and the now empty pair structs */ + nautilus_g_list_free_deep (uri_pairs); + +} + #if !defined (NAUTILUS_OMIT_SELF_CHECK) static int data_dummy; diff --git a/libnautilus-private/nautilus-file-changes-queue.c b/libnautilus-private/nautilus-file-changes-queue.c new file mode 100644 index 000000000..b69212601 --- /dev/null +++ b/libnautilus-private/nautilus-file-changes-queue.c @@ -0,0 +1,262 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.h: Nautilus directory model. + + Copyright (C) 1999, 2000 Eazel, 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. + +*/ + +#include "nautilus-file-changes-queue-private.h" +#include "nautilus-directory-private.h" + +#ifdef G_THREADS_ENABLED +#define MUTEX_LOCK(a) if ((a) != NULL) g_mutex_lock (a) +#define MUTEX_UNLOCK(a) if ((a) != NULL) g_mutex_unlock (a) +#else +#define MUTEX_LOCK(a) +#define MUTEX_UNLOCK(a) +#endif + +static NautilusFileChangesQueue *file_changes_queue; + +static void +nautilus_file_change_free (NautilusFileChange *change) +{ + g_free (change->from_uri); + g_free (change->to_uri); +} + +static NautilusFileChangesQueue * +nautilus_file_changes_queue_new (void) +{ + NautilusFileChangesQueue *result = g_new (NautilusFileChangesQueue, 1); + result->details = g_new0 (NautilusFileChangesQueueDetails, 1); + +#ifdef G_THREADS_ENABLED + result->details->mutex = g_mutex_new (); +#endif + return result; +} + +static NautilusFileChangesQueue * +nautilus_file_changes_queue_get (void) +{ + if (file_changes_queue == NULL) + file_changes_queue = nautilus_file_changes_queue_new(); + + return file_changes_queue; +} + +void +nautilus_file_changes_queue_free (NautilusFileChangesQueue *queue) +{ + GList *p; + if (queue == NULL) { + return; + } + +#ifdef G_THREADS_ENABLED + /* if lock on a defunct mutext were defined (returning a failure) + * we would lock here + */ +#endif + + for (p = queue->details->head; p != NULL; p = p->next) { + nautilus_file_change_free (p->data); + } + g_list_free (queue->details->head); + +#ifdef G_THREADS_ENABLED + g_mutex_free (queue->details->mutex); +#endif + g_free (queue->details); + g_free (queue); +} + +static void +nautilus_file_changes_queue_add_common (NautilusFileChangesQueue *queue, + NautilusFileChange *new_item) +{ + /* enqueue the new queue item while locking down the list */ + MUTEX_LOCK (queue->details->mutex); + + queue->details->head = g_list_prepend (queue->details->head, new_item); + if (queue->details->tail == NULL) + queue->details->tail = queue->details->head; + + MUTEX_UNLOCK (queue->details->mutex); +} + +void +nautilus_file_changes_queue_file_added (const char *uri) +{ + NautilusFileChange *new_item; + NautilusFileChangesQueue *queue; + + queue = nautilus_file_changes_queue_get(); + g_assert (queue); + + new_item = g_new0 (NautilusFileChange, 1); + new_item->kind = CHANGE_FILE_ADDED; + new_item->from_uri = g_strdup (uri); + nautilus_file_changes_queue_add_common (queue, new_item); +} + +void +nautilus_file_changes_queue_file_removed (const char *uri) +{ + NautilusFileChange *new_item; + NautilusFileChangesQueue *queue; + + queue = nautilus_file_changes_queue_get(); + g_assert (queue); + + new_item = g_new0 (NautilusFileChange, 1); + new_item->kind = CHANGE_FILE_REMOVED; + new_item->from_uri = g_strdup (uri); + nautilus_file_changes_queue_add_common (queue, new_item); +} + +void +nautilus_file_changes_queue_file_moved (const char *from, const char *to) +{ + NautilusFileChange *new_item; + NautilusFileChangesQueue *queue; + + queue = nautilus_file_changes_queue_get(); + g_assert (queue); + + new_item = g_new (NautilusFileChange, 1); + new_item->kind = CHANGE_FILE_REMOVED; + new_item->from_uri = g_strdup (from); + new_item->to_uri = g_strdup (to); + nautilus_file_changes_queue_add_common (queue, new_item); +} + +static NautilusFileChange * +nautilus_file_changes_queue_get_change (NautilusFileChangesQueue *queue) +{ + GList *new_tail; + NautilusFileChange *result; + + /* dequeue the tail item while locking down the list */ + MUTEX_LOCK (queue->details->mutex); + + if (queue->details->tail == NULL) { + result = NULL; + } else { + new_tail = queue->details->tail->prev; + result = queue->details->tail->data; + queue->details->head = g_list_remove_link (queue->details->head, + queue->details->tail); + queue->details->tail = new_tail; + } + + MUTEX_UNLOCK (queue->details->mutex); + + return result; +} + +enum { + CONSUME_CHANGES_MAX_CHUNK = 10 +}; + +/* go through changes in the change queue, send ones with the same kind + * in a list to the different nautilus_directory_notify calls + */ +void +nautilus_file_changes_consume_changes (gboolean consume_all) +{ + NautilusFileChange *change; + GList *additions; + GList *deletions; + GList *moves; + URIPair *pair; + int kind; + int chunk_count; + + additions = NULL; + deletions = NULL; + moves = NULL; + kind = CHANGE_FILE_INITIAL; + + if (file_changes_queue == NULL) + return; + + for (chunk_count = 0; ; chunk_count++) { + change = nautilus_file_changes_queue_get_change (file_changes_queue); + + + if (change == NULL + /* no changes left */ + || change->kind != kind + /* all the changes we have are different that the new one */ + || (!consume_all && chunk_count >= CONSUME_CHANGES_MAX_CHUNK)) { + /* we have reached the chunk maximum */ + + + /* send changes we collected off */ + if (additions != NULL) { + nautilus_directory_notify_files_added (additions); + additions = NULL; + } + if (deletions != NULL) { + nautilus_directory_notify_files_removed (deletions); + deletions = NULL; + } + if (moves != NULL) { + nautilus_directory_notify_files_moved (moves); + moves = NULL; + } + } + + if (change == NULL) { + /* we are done */ + break; + } + + + kind = change->kind; + + /* add the new change to the list */ + switch (kind) { + case CHANGE_FILE_ADDED: + additions = g_list_append (additions, change->from_uri); + break; + + case CHANGE_FILE_REMOVED: + deletions = g_list_append (deletions, change->from_uri); + break; + + case CHANGE_FILE_MOVED: + pair = g_new (URIPair, 1); + pair->from_uri = change->from_uri; + pair->to_uri = change->to_uri; + moves = g_list_append (moves, pair); + break; + + default: + g_assert_not_reached (); + break; + } + + change->from_uri = NULL; + change->to_uri = NULL; + } +} + diff --git a/libnautilus-private/nautilus-file-changes-queue.h b/libnautilus-private/nautilus-file-changes-queue.h new file mode 100644 index 000000000..3cedb1c09 --- /dev/null +++ b/libnautilus-private/nautilus-file-changes-queue.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.h: Nautilus directory model. + + Copyright (C) 1999, 2000 Eazel, 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. + +*/ + +#ifndef NAUTILUS_FILE_CHANGES_QUEUE_H +#define NAUTILUS_FILE_CHANGES_QUEUE_H + +typedef struct NautilusFileChangesQueue NautilusFileChangesQueue; +typedef struct NautilusFileChangesQueueDetails NautilusFileChangesQueueDetails; + +void nautilus_file_changes_queue_free (NautilusFileChangesQueue *queue); + +void nautilus_file_changes_queue_file_added (const char *uri); +void nautilus_file_changes_queue_file_removed (const char *uri); +void nautilus_file_changes_queue_file_moved (const char *from_uri, + const char *to_uri); + +void nautilus_file_changes_consume_changes (gboolean consume_all); + +struct NautilusFileChangesQueue { + NautilusFileChangesQueueDetails *details; +}; + +#endif diff --git a/libnautilus-private/nautilus-file-operations.c b/libnautilus-private/nautilus-file-operations.c index e3c2895c8..50bb95f90 100644 --- a/libnautilus-private/nautilus-file-operations.c +++ b/libnautilus-private/nautilus-file-operations.c @@ -27,6 +27,7 @@ #include <gnome.h> #include "dfos-xfer.h" +#include "libnautilus-extensions/nautilus-file-changes-queue.h" #include "fm-directory-view.h" @@ -122,9 +123,14 @@ handle_xfer_ok (const GnomeVFSXferProgressInfo *progress_info, progress_info->bytes_total); return TRUE; - case GNOME_VFS_XFER_PHASE_XFERRING: + case GNOME_VFS_XFER_PHASE_MOVING: + case GNOME_VFS_XFER_PHASE_DELETESOURCE: case GNOME_VFS_XFER_PHASE_OPENSOURCE: case GNOME_VFS_XFER_PHASE_OPENTARGET: + nautilus_file_changes_consume_changes (FALSE); + /* fall through */ + + case GNOME_VFS_XFER_PHASE_COPYING: if (progress_info->bytes_copied == 0) { dfos_xfer_progress_dialog_new_file (DFOS_XFER_PROGRESS_DIALOG @@ -149,6 +155,7 @@ handle_xfer_ok (const GnomeVFSXferProgressInfo *progress_info, return TRUE; case GNOME_VFS_XFER_PHASE_COMPLETED: + nautilus_file_changes_consume_changes (TRUE); gtk_widget_destroy (xfer_info->progress_dialog); g_free (xfer_info); return TRUE; @@ -249,7 +256,7 @@ handle_xfer_duplicate (GnomeVFSXferProgressInfo *progress_info, } static int -sync_xfer_callback ( +update_xfer_callback (GnomeVFSAsyncHandle *handle, GnomeVFSXferProgressInfo *progress_info, gpointer data) { @@ -269,16 +276,40 @@ sync_xfer_callback ( default: g_warning (_("Unknown GnomeVFSXferProgressStatus %d"), progress_info->status); - return FALSE; + return 0; } } +/* Low-level callback, called for every copy engine operation. + * Generates notifications about new, deleted and moved files. + */ static int -xfer_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSXferProgressInfo *progress_info, - gpointer data) +sync_xfer_callback (GnomeVFSXferProgressInfo *progress_info, gpointer data) { - return sync_xfer_callback (progress_info, data); + XferInfo *xfer_info; + + xfer_info = (XferInfo *) data; + + if (progress_info->status == GNOME_VFS_XFER_PROGRESS_STATUS_OK) { + switch (progress_info->phase) { + case GNOME_VFS_XFER_PHASE_OPENTARGET: + nautilus_file_changes_queue_file_added (progress_info->target_name); + break; + + case GNOME_VFS_XFER_PHASE_MOVING: + nautilus_file_changes_queue_file_moved (progress_info->source_name, + progress_info->target_name); + break; + + case GNOME_VFS_XFER_PHASE_DELETESOURCE: + nautilus_file_changes_queue_file_removed (progress_info->source_name); + break; + + default: + break; + } + } + return 1; } @@ -305,8 +336,9 @@ dfos_xfer (DFOS *dfos, options, GNOME_VFS_XFER_ERROR_MODE_QUERY, overwrite_mode, - xfer_callback, - xfer_info); + update_xfer_callback, + xfer_info, + NULL, NULL); if (result != GNOME_VFS_OK) { gchar *message; @@ -441,7 +473,8 @@ fs_xfer (const GList *item_uris, target_dir_uri_text, NULL, move_options, GNOME_VFS_XFER_ERROR_MODE_QUERY, GNOME_VFS_XFER_OVERWRITE_MODE_QUERY, - &xfer_callback, xfer_info); + &update_xfer_callback, xfer_info, + &sync_xfer_callback, xfer_info); if (!target_dir) g_free ((char *)target_dir_uri_text); diff --git a/src/file-manager/dfos-xfer.c b/src/file-manager/dfos-xfer.c index e3c2895c8..50bb95f90 100644 --- a/src/file-manager/dfos-xfer.c +++ b/src/file-manager/dfos-xfer.c @@ -27,6 +27,7 @@ #include <gnome.h> #include "dfos-xfer.h" +#include "libnautilus-extensions/nautilus-file-changes-queue.h" #include "fm-directory-view.h" @@ -122,9 +123,14 @@ handle_xfer_ok (const GnomeVFSXferProgressInfo *progress_info, progress_info->bytes_total); return TRUE; - case GNOME_VFS_XFER_PHASE_XFERRING: + case GNOME_VFS_XFER_PHASE_MOVING: + case GNOME_VFS_XFER_PHASE_DELETESOURCE: case GNOME_VFS_XFER_PHASE_OPENSOURCE: case GNOME_VFS_XFER_PHASE_OPENTARGET: + nautilus_file_changes_consume_changes (FALSE); + /* fall through */ + + case GNOME_VFS_XFER_PHASE_COPYING: if (progress_info->bytes_copied == 0) { dfos_xfer_progress_dialog_new_file (DFOS_XFER_PROGRESS_DIALOG @@ -149,6 +155,7 @@ handle_xfer_ok (const GnomeVFSXferProgressInfo *progress_info, return TRUE; case GNOME_VFS_XFER_PHASE_COMPLETED: + nautilus_file_changes_consume_changes (TRUE); gtk_widget_destroy (xfer_info->progress_dialog); g_free (xfer_info); return TRUE; @@ -249,7 +256,7 @@ handle_xfer_duplicate (GnomeVFSXferProgressInfo *progress_info, } static int -sync_xfer_callback ( +update_xfer_callback (GnomeVFSAsyncHandle *handle, GnomeVFSXferProgressInfo *progress_info, gpointer data) { @@ -269,16 +276,40 @@ sync_xfer_callback ( default: g_warning (_("Unknown GnomeVFSXferProgressStatus %d"), progress_info->status); - return FALSE; + return 0; } } +/* Low-level callback, called for every copy engine operation. + * Generates notifications about new, deleted and moved files. + */ static int -xfer_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSXferProgressInfo *progress_info, - gpointer data) +sync_xfer_callback (GnomeVFSXferProgressInfo *progress_info, gpointer data) { - return sync_xfer_callback (progress_info, data); + XferInfo *xfer_info; + + xfer_info = (XferInfo *) data; + + if (progress_info->status == GNOME_VFS_XFER_PROGRESS_STATUS_OK) { + switch (progress_info->phase) { + case GNOME_VFS_XFER_PHASE_OPENTARGET: + nautilus_file_changes_queue_file_added (progress_info->target_name); + break; + + case GNOME_VFS_XFER_PHASE_MOVING: + nautilus_file_changes_queue_file_moved (progress_info->source_name, + progress_info->target_name); + break; + + case GNOME_VFS_XFER_PHASE_DELETESOURCE: + nautilus_file_changes_queue_file_removed (progress_info->source_name); + break; + + default: + break; + } + } + return 1; } @@ -305,8 +336,9 @@ dfos_xfer (DFOS *dfos, options, GNOME_VFS_XFER_ERROR_MODE_QUERY, overwrite_mode, - xfer_callback, - xfer_info); + update_xfer_callback, + xfer_info, + NULL, NULL); if (result != GNOME_VFS_OK) { gchar *message; @@ -441,7 +473,8 @@ fs_xfer (const GList *item_uris, target_dir_uri_text, NULL, move_options, GNOME_VFS_XFER_ERROR_MODE_QUERY, GNOME_VFS_XFER_OVERWRITE_MODE_QUERY, - &xfer_callback, xfer_info); + &update_xfer_callback, xfer_info, + &sync_xfer_callback, xfer_info); if (!target_dir) g_free ((char *)target_dir_uri_text); |