diff options
36 files changed, 2256 insertions, 779 deletions
diff --git a/ChangeLog-20000414 b/ChangeLog-20000414 index faa2a99ba..fb8ae00f8 100644 --- a/ChangeLog-20000414 +++ b/ChangeLog-20000414 @@ -1,3 +1,44 @@ +2000-01-14 Darin Adler <darin@eazel.com> + + First cut at some actual saving of metadata. + Neither the interface nor the implementation is great yet. + But it's a start. + + * libnautilus/Makefile.am: + libnautilus/nautilus-directory.h: + libnautilus/nautilus-directory.c: + libnautilus/nautilus-lib-self-check-functions.h: + libnautilus/nautilus-lib-self-check-functions.c: + src/file-manager/Makefile.am: + src/file-manager/fm-directory-protected.h: + src/file-manager/fm-directory.h: + src/file-manager/fm-directory.c: + src/file-manager/fm-vfs-directory.h: + src/file-manager/fm-vfs-directory.c: + Moved the old FMDirectory class into the library and named it + NautilusDirectory. Added functions for reading and writing + metadata. + + * src/ntl-index-panel.c: Added the code to save the index panel's + background color in metadata. + + * libnautilus/Makefile.am: Added gnome-vfs and gnome-xml, + since the new code uses them. + + * libnautilus/nautilus-self-checks.h: + libnautilus/nautilus-lib-self-check-functions.h: + libnautilus/nautilus-lib-self-check-functions.c: + src/nautilus-self-check-functions.h: + src/nautilus-self-check-functions.c: + Added macros to the self-check framework so the list of self check + functions appears in exactly one place for each directory/module. + + * src/ntl-index-panel.h: src/ntl-index-panel.c: Moved the fields + of the index panel inside a private details structure so they can + change without affecting clients. + + * libnautilus/nautilus-background.c: Just some reformatting. + 2000-01-13 John Sullivan <sullivan@eazel.com> More work pushing code from FMDirectoryView into subclasses. diff --git a/libnautilus-extensions/Makefile.am b/libnautilus-extensions/Makefile.am index 2a7912af8..46d1de41d 100644 --- a/libnautilus-extensions/Makefile.am +++ b/libnautilus-extensions/Makefile.am @@ -4,8 +4,17 @@ INCLUDES=-I$(top_srcdir) -I$(top_builddir) \ $(GNOME_CFLAGS) \ $(GNORBA_CFLAGS) \ $(GDK_PIXBUF_CFLAGS) \ + $(VFS_CFLAGS) \ + $(XML_CFLAGS) \ $(WERROR) +libnautilus_la_LDFLAGS=\ + $(GNOME_LIBS) \ + $(GNORBA_LIBS) \ + $(GDK_PIXBUF_LIBS) -lcanvas_pixbuf \ + $(VFS_LIBS) \ + $(XML_LIBS) + nautilus_idl_sources=nautilus-stubs.c nautilus-skels.c nautilus.h nautilus-common.c fsextension_idl_sources=fsextension-stubs.c fsextension-skels.c fsextension-common.c fsextension.h BUILT_SOURCES=$(nautilus_idl_sources) @@ -23,6 +32,7 @@ libnautilusinclude_HEADERS= \ gtkscrollframe.h \ nautilus.h \ nautilus-background.h \ + nautilus-directory.h \ nautilus-file-utilities.h \ nautilus-gtk-extensions.h \ nautilus-lib-self-check-functions.h \ @@ -41,6 +51,7 @@ libnautilus_la_SOURCES=$(nautilus_idl_sources) \ gtkscrollframe.c \ nautilus-background.c \ nautilus-background-canvas-group.c \ + nautilus-directory.c \ nautilus-file-utilities.c \ nautilus-gtk-extensions.c \ nautilus-lib-self-check-functions.c \ @@ -51,10 +62,6 @@ libnautilus_la_SOURCES=$(nautilus_idl_sources) \ ntl-view-frame.c \ $(fsextension_idl_sources) -libnautilus_la_LDFLAGS=$(GNOME_LIBS) \ - $(GNORBA_LIBS) \ - $(GDK_PIXBUF_LIBS) -lcanvas_pixbuf - $(nautilus_idl_sources): nautilus_idl_stamp $(fsextension_idl_sources): fsextension_idl_stamp diff --git a/libnautilus-extensions/nautilus-background.c b/libnautilus-extensions/nautilus-background.c index 057f265f6..d8090881f 100644 --- a/libnautilus-extensions/nautilus-background.c +++ b/libnautilus-extensions/nautilus-background.c @@ -185,7 +185,8 @@ nautilus_gtk_style_get_default_class (void) return default_class; } -static void nautilus_gdk_window_update_sizes (GdkWindow *window, int *width, int *height) +static void +nautilus_gdk_window_update_sizes (GdkWindow *window, int *width, int *height) { g_return_if_fail (window != NULL); g_return_if_fail (width != NULL); @@ -199,17 +200,18 @@ static void nautilus_gdk_window_update_sizes (GdkWindow *window, int *width, int gdk_window_get_size (window, NULL, height); } -static void nautilus_background_draw_flat_box (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - gchar *detail, - gint x, - gint y, - gint width, - gint height) +static void +nautilus_background_draw_flat_box (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + char *detail, + int x, + int y, + int width, + int height) { gboolean call_parent; NautilusBackground *background; diff --git a/libnautilus-extensions/nautilus-directory.c b/libnautilus-extensions/nautilus-directory.c new file mode 100644 index 000000000..86b3c00f9 --- /dev/null +++ b/libnautilus-extensions/nautilus-directory.c @@ -0,0 +1,466 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.c: Mautilus 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. + + Author: Darin Adler <darin@eazel.com> +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "nautilus-directory.h" + +#include <stdlib.h> + +#include <gtk/gtkmain.h> + +#include <libgnomevfs/gnome-vfs-types.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <libgnomevfs/gnome-vfs-ops.h> +#include <libgnomevfs/gnome-vfs-async-ops.h> + +#include <gnome-xml/parser.h> +#include <gnome-xml/tree.h> +#include <gnome-xml/xmlmemory.h> + +#include "nautilus-gtk-macros.h" +#include "nautilus-lib-self-check-functions.h" +#include "nautilus-string.h" + +#define METAFILE_NAME ".nautilus.xml" +#define METAFILE_XML_VERSION "1.0" + +static void nautilus_directory_initialize_class (gpointer klass); +static void nautilus_directory_initialize (gpointer object, gpointer klass); +static void nautilus_directory_finalize (GtkObject *object); + +static NautilusDirectory *nautilus_directory_new (const char* uri); + +static void nautilus_directory_read_metafile (NautilusDirectory *directory); +static void nautilus_directory_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_request_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory); + +NAUTILUS_DEFINE_GET_TYPE_FUNCTION (NautilusDirectory, nautilus_directory, GTK_TYPE_OBJECT) + +static GtkObjectClass *parent_class; + +struct _NautilusDirectoryDetails +{ + char *uri_text; + GnomeVFSURI *uri; + + GnomeVFSURI *metafile_uri; + xmlDoc *metafile_tree; + int write_metafile_idle_id; + + NautilusFileList *files; +}; + +struct _NautilusFile +{ +}; + +static GHashTable* directory_objects; + +static void +nautilus_directory_initialize_class (gpointer klass) +{ + GtkObjectClass *object_class; + + object_class = GTK_OBJECT_CLASS (klass); + parent_class = gtk_type_class (GTK_TYPE_OBJECT); + + object_class->finalize = nautilus_directory_finalize; +} + +static void +nautilus_directory_initialize (gpointer object, gpointer klass) +{ + NautilusDirectory *directory; + + directory = NAUTILUS_DIRECTORY(object); + + directory->details = g_new0 (NautilusDirectoryDetails, 1); +} + +static void +nautilus_directory_finalize (GtkObject *object) +{ + NautilusDirectory *directory; + + directory = NAUTILUS_DIRECTORY (object); + + g_hash_table_remove (directory_objects, directory->details->uri_text); + + g_free (directory->details->uri_text); + if (directory->details->uri) + gnome_vfs_uri_unref (directory->details->uri); + if (directory->details->metafile_uri) + gnome_vfs_uri_unref (directory->details->metafile_uri); + xmlFreeDoc (directory->details->metafile_tree); + nautilus_directory_remove_write_metafile_idle (directory); + + g_free (directory->details); + + NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, finalize, (object)); +} + +/** + * nautilus_directory_get: + * @uri: URI of directory to get. + * + * Get a directory given a uri. + * Creates the appropriate subclass given the uri mappings. + * Returns a referenced object, not a floating one. Unref when finished. + * If two windows are viewing the same uri, the directory object is shared. + */ +NautilusDirectory * +nautilus_directory_get (const char *uri) +{ + NautilusDirectory *directory; + + g_return_val_if_fail (uri != NULL, NULL); + + /* FIXME: This currently ignores the issue of two uris that are not identical but point + to the same data. + */ + + /* Create the hash table first time through. */ + if (!directory_objects) + directory_objects = g_hash_table_new (g_str_hash, g_str_equal); + + /* If the object is already in the hash table, look it up. */ + directory = g_hash_table_lookup (directory_objects, uri); + if (directory != NULL) { + g_assert (NAUTILUS_IS_DIRECTORY (directory)); + gtk_object_ref (GTK_OBJECT (directory)); + } else { + /* Create a new directory object instead. */ + directory = NAUTILUS_DIRECTORY (nautilus_directory_new (uri)); + g_assert (strcmp (directory->details->uri_text, uri) == 0); + + /* Put it in the hash table. */ + gtk_object_ref (GTK_OBJECT (directory)); + gtk_object_sink (GTK_OBJECT (directory)); + g_hash_table_insert (directory_objects, directory->details->uri_text, directory); + } + + return directory; +} + +/* This reads the metafile synchronously. This must go eventually. + To do this asynchronously we'd need a way to read an entire file + with async. calls; currently you can only get the file length with + a synchronous call. +*/ +static void +nautilus_directory_read_metafile (NautilusDirectory *directory) +{ + GnomeVFSResult result; + GnomeVFSFileInfo metafile_info; + GnomeVFSHandle *metafile_handle; + char *buffer; + GnomeVFSFileSize size, actual_size; + + g_assert (directory->details->metafile_tree == NULL); + + result = gnome_vfs_get_file_info_uri (directory->details->metafile_uri, + &metafile_info, + GNOME_VFS_FILE_INFO_DEFAULT, + NULL); + if (result == GNOME_VFS_ERROR_NOTFOUND) + return; + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_read_metafile: gnome_vfs_get_file_info_uri failed"); + + metafile_handle = NULL; + if (result == GNOME_VFS_OK) { + result = gnome_vfs_open_uri (&metafile_handle, + directory->details->metafile_uri, + GNOME_VFS_OPEN_READ); + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_read_metafile: gnome_vfs_open_uri failed"); + } + + if (result == GNOME_VFS_OK) { + size = metafile_info.size; + if (size != metafile_info.size) { + g_warning ("nautilus_directory_read_metafile: metafile too large"); + result = GNOME_VFS_ERROR_TOOBIG; + } + } + + if (result == GNOME_VFS_OK) { + buffer = g_malloc (size); + + result = gnome_vfs_read (metafile_handle, buffer, size, &actual_size); + + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_read_metafile: gnome_vfs_read failed"); + else if (actual_size != size) + g_warning ("nautilus_directory_read_metafile: size changed between get_info and read"); + } + + if (metafile_handle != NULL) + gnome_vfs_close (metafile_handle); + + if (result == GNOME_VFS_OK) + directory->details->metafile_tree = xmlParseMemory (buffer, actual_size); + + g_free (buffer); +} + +static void +nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory) +{ + if (directory->details->write_metafile_idle_id != 0) { + gtk_idle_remove (directory->details->write_metafile_idle_id); + directory->details->write_metafile_idle_id = 0; + } +} + +/* This writes the metafile synchronously. This must go eventually. */ +static void +nautilus_directory_write_metafile (NautilusDirectory *directory) +{ + xmlChar *buffer; + int buffer_size; + GnomeVFSResult result; + GnomeVFSHandle *metafile_handle; + GnomeVFSFileSize actual_size; + + g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory)); + + /* We are about the write the metafile, so we can cancel the pending + request to do it. */ + nautilus_directory_remove_write_metafile_idle (directory); + + /* Don't write anything if there's nothing to write. + At some point, we might want to change this to actually delete + the metafile in this case. + */ + if (directory->details->metafile_tree == NULL) + return; + + xmlDocDumpMemory (directory->details->metafile_tree, &buffer, &buffer_size); + + metafile_handle = NULL; + result = gnome_vfs_create_uri (&metafile_handle, + directory->details->metafile_uri, + GNOME_VFS_OPEN_WRITE, + FALSE, + GNOME_VFS_PERM_USER_ALL | GNOME_VFS_PERM_GROUP_ALL | GNOME_VFS_PERM_OTHER_ALL); + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_write_metafile: gnome_vfs_create_uri failed"); + + if (result == GNOME_VFS_OK) { + result = gnome_vfs_write (metafile_handle, buffer, buffer_size, &actual_size); + + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_write_metafile: gnome_vfs_write failed"); + else if (actual_size != buffer_size) + g_warning ("nautilus_directory_read_metafile: unable to write all"); + } + + if (metafile_handle != NULL) + gnome_vfs_close (metafile_handle); + + xmlFree (buffer); +} + +static gboolean +nautilus_directory_write_metafile_on_idle (gpointer data) +{ + g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (data), FALSE); + nautilus_directory_write_metafile (data); + return FALSE; +} + +static void +nautilus_directory_request_write_metafile (NautilusDirectory *directory) +{ + /* Set up an idle task that will write the metafile. */ + if (directory->details->write_metafile_idle_id == 0) + directory->details->write_metafile_idle_id = + gtk_idle_add (nautilus_directory_write_metafile_on_idle, + directory); +} + +#if NAUTILUS_DIRECTORY_ASYNC + +static void +nautilus_directory_opened_metafile (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + gpointer callback_data) +{ +} + + result = gnome_vfs_async_open_uri (&metafile_handle, metafile_uri, GNOME_VFS_OPEN_READ, + nautilus_directory_opened_metafile, directory); +#endif + +static NautilusDirectory * +nautilus_directory_new (const char* uri) +{ + NautilusDirectory *directory; + GnomeVFSURI *vfs_uri; + GnomeVFSURI *metafile_uri; + + vfs_uri = gnome_vfs_uri_new (uri); + if (vfs_uri == NULL) + return NULL; + + metafile_uri = gnome_vfs_uri_append_path (vfs_uri, METAFILE_NAME); + if (metafile_uri == NULL) + return NULL; + + directory = gtk_type_new (NAUTILUS_TYPE_DIRECTORY); + + directory->details->uri_text = g_strdup (uri); + directory->details->uri = vfs_uri; + directory->details->metafile_uri = metafile_uri; + + nautilus_directory_read_metafile (directory); + + return directory; +} + +void +nautilus_directory_get_files (NautilusDirectory *directory, + NautilusFileListCallback callback, + gpointer callback_data) +{ + g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory)); + g_return_if_fail (callback != NULL); + + if (directory->details->files != NULL) + (* callback) (directory, + directory->details->files, + callback_data); +} + +char * +nautilus_directory_get_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata) +{ + xmlNode *root; + xmlChar *property; + char *result; + + g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL); + g_return_val_if_fail (tag, NULL); + g_return_val_if_fail (tag[0], NULL); + + root = xmlDocGetRootElement (directory->details->metafile_tree); + property = xmlGetProp (root, tag); + if (property == NULL) + result = g_strdup (default_metadata); + else + result = g_strdup (property); + g_free (property); + + return result; +} + +void +nautilus_directory_set_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata, + const char *metadata) +{ + char *old_metadata; + gboolean old_metadata_matches; + xmlNode *root; + const char *value; + xmlAttr *property_node; + + g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory)); + g_return_if_fail (tag); + g_return_if_fail (tag[0]); + + /* If the data in the metafile is already correct, do nothing. */ + old_metadata = nautilus_directory_get_metadata (directory, tag, default_metadata); + old_metadata_matches = nautilus_strcmp (old_metadata, metadata) == 0; + g_free (old_metadata); + if (old_metadata_matches) + return; + + /* Data that matches the default is represented in the tree by + the lack of an attribute. + */ + if (nautilus_strcmp (default_metadata, metadata) == 0) + value = NULL; + else + value = metadata; + + /* Get at the tree. */ + if (directory->details->metafile_tree == NULL) + directory->details->metafile_tree = xmlNewDoc (METAFILE_XML_VERSION); + root = xmlDocGetRootElement (directory->details->metafile_tree); + if (root == NULL) { + root = xmlNewDocNode (directory->details->metafile_tree, NULL, "DIRECTORY", NULL); + xmlDocSetRootElement (directory->details->metafile_tree, root); + } + + /* Add or remove an attribute node. */ + property_node = xmlSetProp (root, tag, value); + if (value == NULL) + xmlRemoveProp (property_node); + + /* Since we changed the tree, arrange for it to be written. */ + nautilus_directory_request_write_metafile (directory); +} + +#if !defined (NAUTILUS_OMIT_SELF_CHECK) + +static int data_dummy; +static guint file_count; + +static void +get_files_cb (NautilusDirectory *directory, NautilusFileList *files, gpointer data) +{ + g_assert (NAUTILUS_IS_DIRECTORY (directory)); + g_assert (files); + g_assert (data == &data_dummy); + + file_count += g_list_length (files); +} + +void +nautilus_self_check_directory (void) +{ + NautilusDirectory *directory; + + directory = nautilus_directory_get ("file:///etc"); + + g_assert (g_hash_table_size (directory_objects) == 1); + + file_count = 0; + nautilus_directory_get_files (directory, get_files_cb, &data_dummy); + + gtk_object_unref (GTK_OBJECT (directory)); + + g_assert (g_hash_table_size (directory_objects) == 0); +} + +#endif /* !NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus-extensions/nautilus-directory.h b/libnautilus-extensions/nautilus-directory.h new file mode 100644 index 000000000..eed024e0b --- /dev/null +++ b/libnautilus-extensions/nautilus-directory.h @@ -0,0 +1,166 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.h: Nautilus directory model. + + Copyright (C) 1999 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. + + Author: Darin Adler <darin@eazel.com> +*/ + +#ifndef NAUTILUS_DIRECTORY_H +#define NAUTILUS_DIRECTORY_H + +#include <gtk/gtkobject.h> + +/* NautilusDirectory is a class that manages the model for a directory, + real or virtual, for Nautilus, mainly the file-manager component. The directory is + responsible for managing both real data and cached metadata. On top of + the file system independence provided by gnome-vfs, the directory + object also provides: + + 1) A synchronization framework, which notifies via signals as the + set of known files changes. + 2) An abstract interface for getting attributes and performing + operations on files. + 3) An interface that folds together the cached information that's + kept in the metafile with "trustworthy" versions of the same + information available from other means. +*/ + +typedef struct _NautilusDirectory NautilusDirectory; +typedef struct _NautilusDirectoryClass NautilusDirectoryClass; + +#define NAUTILUS_TYPE_DIRECTORY \ + (nautilus_directory_get_type ()) +#define NAUTILUS_DIRECTORY(obj) \ + (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_DIRECTORY, NautilusDirectory)) +#define NAUTILUS_DIRECTORY_CLASS(klass) \ + (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DIRECTORY, NautilusDirectoryClass)) +#define NAUTILUS_IS_DIRECTORY(obj) \ + (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_DIRECTORY)) +#define NAUTILUS_IS_DIRECTORY_CLASS(klass) \ + (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DIRECTORY)) + +typedef struct _NautilusFile NautilusFile; +typedef GList NautilusFileList; + +typedef void (*NautilusFileListCallback) (NautilusDirectory *directory, + NautilusFileList *files, + gpointer data); + +/* Basic GtkObject requirements. */ +GtkType nautilus_directory_get_type (void); + +/* Get a directory given a uri. + Creates the appropriate subclass given the uri mappings. + Returns a referenced object, not a floating one. Unref when finished. + If two windows are viewing the same uri, the directory object is shared. +*/ +NautilusDirectory *nautilus_directory_get (const char *uri); + +/* Simple preliminary interface for getting and setting metadata. */ +char * nautilus_directory_get_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata); +char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata); +void nautilus_directory_set_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata, + const char *metadata); +void nautilus_directory_set_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata, + const char *metadata); + +/* Get the current files. + Instead of returning the list of files, this function uses a callback. + The directory guarantees that signals won't be emitted while in the + callback function. +*/ +void nautilus_directory_get_files (NautilusDirectory *directory, + NautilusFileListCallback callback, + gpointer callback_data); + +/* Return true if the directory has enough information for layout. + This will be false until the metafile is read to prevent a partial layout + from being done. +*/ +gboolean nautilus_directory_is_ready_for_layout (NautilusDirectory *directory); + +/* Basic operations on file objects. */ +void nautilus_file_ref (NautilusFile *file); +void nautilus_file_unref (NautilusFile *file); +char * nautilus_file_get_name (NautilusFile *file); + +/* Return true if this file has already been deleted. + This object will be unref'd after sending the files_removed signal, + but it could hang around longer if someone ref'd it. +*/ +gboolean nautilus_file_is_gone (NautilusFile *file); + +typedef struct _NautilusDirectoryDetails NautilusDirectoryDetails; + +struct _NautilusDirectory +{ + GtkObject object; + + /* Hidden details. */ + NautilusDirectoryDetails *details; +}; + +struct _NautilusDirectoryClass +{ + GtkObjectClass parent_class; + + /*** Notification signals for clients to connect to. ***/ + + /* The files_added and files_removed signals are emitted as + the directory model discovers new files or discovers that + old files have been deleted. In the case of files_removed, + this is the last chance to forget about these file objects + which are about to be unref'd. + */ + void (* files_added) (NautilusDirectory *directory, + NautilusFileList *added_files); + void (* files_removed) (NautilusDirectory *directory, + NautilusFileList *removed_files); + + /* The files_changed signal is emitted as changes occur to + existing files that are noticed by the synchronization framework. + The client must register which file attributes it is interested + in. Changes to other attributes are not reported via the signal. + */ + void (* files_changed) (NautilusDirectory *directory, + NautilusFileList *changed_files); + + /* The ready_for_layout signal is emitted when the directory + model judges that enough files are available for the layout + process to begin. For normal directories this is after the + metafile has been read. If there's no way to get the basic + layout information before getting the actual files, then + this signal need not be emitted as long as is_ready_for_layout + is already true. + */ + void (* ready_for_layout) (NautilusDirectory *directory); +}; + +#endif /* NAUTILUS_DIRECTORY_H */ diff --git a/libnautilus-extensions/nautilus-lib-self-check-functions.c b/libnautilus-extensions/nautilus-lib-self-check-functions.c index 8fd904042..76f06a41e 100644 --- a/libnautilus-extensions/nautilus-lib-self-check-functions.c +++ b/libnautilus-extensions/nautilus-lib-self-check-functions.c @@ -33,8 +33,7 @@ void nautilus_run_lib_self_checks () { - nautilus_self_check_background (); - nautilus_self_check_gdk_extensions (); + NAUTILUS_LIB_FOR_EACH_SELF_CHECK_FUNCTION (NAUTILUS_CALL_SELF_CHECK_FUNCTION) } #endif /* ! NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus-extensions/nautilus-lib-self-check-functions.h b/libnautilus-extensions/nautilus-lib-self-check-functions.h index 2b68bd8d6..eff8b1312 100644 --- a/libnautilus-extensions/nautilus-lib-self-check-functions.h +++ b/libnautilus-extensions/nautilus-lib-self-check-functions.h @@ -32,8 +32,17 @@ void nautilus_run_lib_self_checks (void); the self-check framework take way too long (since one file would have to include everything). - So we put the prototypes here instead. + So we put the list of functions here instead. + + Instead of just putting prototypes here, we put this macro that + can be used to do operations on the whole list of functions. */ -void nautilus_self_check_gdk_extensions (void); -void nautilus_self_check_background (void); +#define NAUTILUS_LIB_FOR_EACH_SELF_CHECK_FUNCTION(macro) \ + macro(nautilus_self_check_background) \ + macro(nautilus_self_check_directory) \ + macro(nautilus_self_check_gdk_extensions) \ +/* Add new self-check functions to the list above this line. */ + +/* Generate prototypes for all the functions. */ +NAUTILUS_LIB_FOR_EACH_SELF_CHECK_FUNCTION (NAUTILUS_SELF_CHECK_FUNCTION_PROTOTYPE) diff --git a/libnautilus-extensions/nautilus-self-checks.h b/libnautilus-extensions/nautilus-self-checks.h index bfbdd40c0..ab4b30ef3 100644 --- a/libnautilus-extensions/nautilus-self-checks.h +++ b/libnautilus-extensions/nautilus-self-checks.h @@ -51,4 +51,10 @@ G_STMT_START { \ #define NAUTILUS_CHECK_STRING_RESULT(expression, expected_value) \ NAUTILUS_CHECK_RESULT(string, expression, expected_value) +#define NAUTILUS_SELF_CHECK_FUNCTION_PROTOTYPE(function) \ + void function (void); + +#define NAUTILUS_CALL_SELF_CHECK_FUNCTION(function) \ + function (); + #endif /* NAUTILUS_SELF_CHECKS_H */ diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am index 2a7912af8..46d1de41d 100644 --- a/libnautilus-private/Makefile.am +++ b/libnautilus-private/Makefile.am @@ -4,8 +4,17 @@ INCLUDES=-I$(top_srcdir) -I$(top_builddir) \ $(GNOME_CFLAGS) \ $(GNORBA_CFLAGS) \ $(GDK_PIXBUF_CFLAGS) \ + $(VFS_CFLAGS) \ + $(XML_CFLAGS) \ $(WERROR) +libnautilus_la_LDFLAGS=\ + $(GNOME_LIBS) \ + $(GNORBA_LIBS) \ + $(GDK_PIXBUF_LIBS) -lcanvas_pixbuf \ + $(VFS_LIBS) \ + $(XML_LIBS) + nautilus_idl_sources=nautilus-stubs.c nautilus-skels.c nautilus.h nautilus-common.c fsextension_idl_sources=fsextension-stubs.c fsextension-skels.c fsextension-common.c fsextension.h BUILT_SOURCES=$(nautilus_idl_sources) @@ -23,6 +32,7 @@ libnautilusinclude_HEADERS= \ gtkscrollframe.h \ nautilus.h \ nautilus-background.h \ + nautilus-directory.h \ nautilus-file-utilities.h \ nautilus-gtk-extensions.h \ nautilus-lib-self-check-functions.h \ @@ -41,6 +51,7 @@ libnautilus_la_SOURCES=$(nautilus_idl_sources) \ gtkscrollframe.c \ nautilus-background.c \ nautilus-background-canvas-group.c \ + nautilus-directory.c \ nautilus-file-utilities.c \ nautilus-gtk-extensions.c \ nautilus-lib-self-check-functions.c \ @@ -51,10 +62,6 @@ libnautilus_la_SOURCES=$(nautilus_idl_sources) \ ntl-view-frame.c \ $(fsextension_idl_sources) -libnautilus_la_LDFLAGS=$(GNOME_LIBS) \ - $(GNORBA_LIBS) \ - $(GDK_PIXBUF_LIBS) -lcanvas_pixbuf - $(nautilus_idl_sources): nautilus_idl_stamp $(fsextension_idl_sources): fsextension_idl_stamp diff --git a/libnautilus-private/nautilus-background.c b/libnautilus-private/nautilus-background.c index 057f265f6..d8090881f 100644 --- a/libnautilus-private/nautilus-background.c +++ b/libnautilus-private/nautilus-background.c @@ -185,7 +185,8 @@ nautilus_gtk_style_get_default_class (void) return default_class; } -static void nautilus_gdk_window_update_sizes (GdkWindow *window, int *width, int *height) +static void +nautilus_gdk_window_update_sizes (GdkWindow *window, int *width, int *height) { g_return_if_fail (window != NULL); g_return_if_fail (width != NULL); @@ -199,17 +200,18 @@ static void nautilus_gdk_window_update_sizes (GdkWindow *window, int *width, int gdk_window_get_size (window, NULL, height); } -static void nautilus_background_draw_flat_box (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - gchar *detail, - gint x, - gint y, - gint width, - gint height) +static void +nautilus_background_draw_flat_box (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + char *detail, + int x, + int y, + int width, + int height) { gboolean call_parent; NautilusBackground *background; diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c new file mode 100644 index 000000000..86b3c00f9 --- /dev/null +++ b/libnautilus-private/nautilus-directory.c @@ -0,0 +1,466 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.c: Mautilus 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. + + Author: Darin Adler <darin@eazel.com> +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "nautilus-directory.h" + +#include <stdlib.h> + +#include <gtk/gtkmain.h> + +#include <libgnomevfs/gnome-vfs-types.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <libgnomevfs/gnome-vfs-ops.h> +#include <libgnomevfs/gnome-vfs-async-ops.h> + +#include <gnome-xml/parser.h> +#include <gnome-xml/tree.h> +#include <gnome-xml/xmlmemory.h> + +#include "nautilus-gtk-macros.h" +#include "nautilus-lib-self-check-functions.h" +#include "nautilus-string.h" + +#define METAFILE_NAME ".nautilus.xml" +#define METAFILE_XML_VERSION "1.0" + +static void nautilus_directory_initialize_class (gpointer klass); +static void nautilus_directory_initialize (gpointer object, gpointer klass); +static void nautilus_directory_finalize (GtkObject *object); + +static NautilusDirectory *nautilus_directory_new (const char* uri); + +static void nautilus_directory_read_metafile (NautilusDirectory *directory); +static void nautilus_directory_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_request_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory); + +NAUTILUS_DEFINE_GET_TYPE_FUNCTION (NautilusDirectory, nautilus_directory, GTK_TYPE_OBJECT) + +static GtkObjectClass *parent_class; + +struct _NautilusDirectoryDetails +{ + char *uri_text; + GnomeVFSURI *uri; + + GnomeVFSURI *metafile_uri; + xmlDoc *metafile_tree; + int write_metafile_idle_id; + + NautilusFileList *files; +}; + +struct _NautilusFile +{ +}; + +static GHashTable* directory_objects; + +static void +nautilus_directory_initialize_class (gpointer klass) +{ + GtkObjectClass *object_class; + + object_class = GTK_OBJECT_CLASS (klass); + parent_class = gtk_type_class (GTK_TYPE_OBJECT); + + object_class->finalize = nautilus_directory_finalize; +} + +static void +nautilus_directory_initialize (gpointer object, gpointer klass) +{ + NautilusDirectory *directory; + + directory = NAUTILUS_DIRECTORY(object); + + directory->details = g_new0 (NautilusDirectoryDetails, 1); +} + +static void +nautilus_directory_finalize (GtkObject *object) +{ + NautilusDirectory *directory; + + directory = NAUTILUS_DIRECTORY (object); + + g_hash_table_remove (directory_objects, directory->details->uri_text); + + g_free (directory->details->uri_text); + if (directory->details->uri) + gnome_vfs_uri_unref (directory->details->uri); + if (directory->details->metafile_uri) + gnome_vfs_uri_unref (directory->details->metafile_uri); + xmlFreeDoc (directory->details->metafile_tree); + nautilus_directory_remove_write_metafile_idle (directory); + + g_free (directory->details); + + NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, finalize, (object)); +} + +/** + * nautilus_directory_get: + * @uri: URI of directory to get. + * + * Get a directory given a uri. + * Creates the appropriate subclass given the uri mappings. + * Returns a referenced object, not a floating one. Unref when finished. + * If two windows are viewing the same uri, the directory object is shared. + */ +NautilusDirectory * +nautilus_directory_get (const char *uri) +{ + NautilusDirectory *directory; + + g_return_val_if_fail (uri != NULL, NULL); + + /* FIXME: This currently ignores the issue of two uris that are not identical but point + to the same data. + */ + + /* Create the hash table first time through. */ + if (!directory_objects) + directory_objects = g_hash_table_new (g_str_hash, g_str_equal); + + /* If the object is already in the hash table, look it up. */ + directory = g_hash_table_lookup (directory_objects, uri); + if (directory != NULL) { + g_assert (NAUTILUS_IS_DIRECTORY (directory)); + gtk_object_ref (GTK_OBJECT (directory)); + } else { + /* Create a new directory object instead. */ + directory = NAUTILUS_DIRECTORY (nautilus_directory_new (uri)); + g_assert (strcmp (directory->details->uri_text, uri) == 0); + + /* Put it in the hash table. */ + gtk_object_ref (GTK_OBJECT (directory)); + gtk_object_sink (GTK_OBJECT (directory)); + g_hash_table_insert (directory_objects, directory->details->uri_text, directory); + } + + return directory; +} + +/* This reads the metafile synchronously. This must go eventually. + To do this asynchronously we'd need a way to read an entire file + with async. calls; currently you can only get the file length with + a synchronous call. +*/ +static void +nautilus_directory_read_metafile (NautilusDirectory *directory) +{ + GnomeVFSResult result; + GnomeVFSFileInfo metafile_info; + GnomeVFSHandle *metafile_handle; + char *buffer; + GnomeVFSFileSize size, actual_size; + + g_assert (directory->details->metafile_tree == NULL); + + result = gnome_vfs_get_file_info_uri (directory->details->metafile_uri, + &metafile_info, + GNOME_VFS_FILE_INFO_DEFAULT, + NULL); + if (result == GNOME_VFS_ERROR_NOTFOUND) + return; + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_read_metafile: gnome_vfs_get_file_info_uri failed"); + + metafile_handle = NULL; + if (result == GNOME_VFS_OK) { + result = gnome_vfs_open_uri (&metafile_handle, + directory->details->metafile_uri, + GNOME_VFS_OPEN_READ); + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_read_metafile: gnome_vfs_open_uri failed"); + } + + if (result == GNOME_VFS_OK) { + size = metafile_info.size; + if (size != metafile_info.size) { + g_warning ("nautilus_directory_read_metafile: metafile too large"); + result = GNOME_VFS_ERROR_TOOBIG; + } + } + + if (result == GNOME_VFS_OK) { + buffer = g_malloc (size); + + result = gnome_vfs_read (metafile_handle, buffer, size, &actual_size); + + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_read_metafile: gnome_vfs_read failed"); + else if (actual_size != size) + g_warning ("nautilus_directory_read_metafile: size changed between get_info and read"); + } + + if (metafile_handle != NULL) + gnome_vfs_close (metafile_handle); + + if (result == GNOME_VFS_OK) + directory->details->metafile_tree = xmlParseMemory (buffer, actual_size); + + g_free (buffer); +} + +static void +nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory) +{ + if (directory->details->write_metafile_idle_id != 0) { + gtk_idle_remove (directory->details->write_metafile_idle_id); + directory->details->write_metafile_idle_id = 0; + } +} + +/* This writes the metafile synchronously. This must go eventually. */ +static void +nautilus_directory_write_metafile (NautilusDirectory *directory) +{ + xmlChar *buffer; + int buffer_size; + GnomeVFSResult result; + GnomeVFSHandle *metafile_handle; + GnomeVFSFileSize actual_size; + + g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory)); + + /* We are about the write the metafile, so we can cancel the pending + request to do it. */ + nautilus_directory_remove_write_metafile_idle (directory); + + /* Don't write anything if there's nothing to write. + At some point, we might want to change this to actually delete + the metafile in this case. + */ + if (directory->details->metafile_tree == NULL) + return; + + xmlDocDumpMemory (directory->details->metafile_tree, &buffer, &buffer_size); + + metafile_handle = NULL; + result = gnome_vfs_create_uri (&metafile_handle, + directory->details->metafile_uri, + GNOME_VFS_OPEN_WRITE, + FALSE, + GNOME_VFS_PERM_USER_ALL | GNOME_VFS_PERM_GROUP_ALL | GNOME_VFS_PERM_OTHER_ALL); + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_write_metafile: gnome_vfs_create_uri failed"); + + if (result == GNOME_VFS_OK) { + result = gnome_vfs_write (metafile_handle, buffer, buffer_size, &actual_size); + + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_write_metafile: gnome_vfs_write failed"); + else if (actual_size != buffer_size) + g_warning ("nautilus_directory_read_metafile: unable to write all"); + } + + if (metafile_handle != NULL) + gnome_vfs_close (metafile_handle); + + xmlFree (buffer); +} + +static gboolean +nautilus_directory_write_metafile_on_idle (gpointer data) +{ + g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (data), FALSE); + nautilus_directory_write_metafile (data); + return FALSE; +} + +static void +nautilus_directory_request_write_metafile (NautilusDirectory *directory) +{ + /* Set up an idle task that will write the metafile. */ + if (directory->details->write_metafile_idle_id == 0) + directory->details->write_metafile_idle_id = + gtk_idle_add (nautilus_directory_write_metafile_on_idle, + directory); +} + +#if NAUTILUS_DIRECTORY_ASYNC + +static void +nautilus_directory_opened_metafile (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + gpointer callback_data) +{ +} + + result = gnome_vfs_async_open_uri (&metafile_handle, metafile_uri, GNOME_VFS_OPEN_READ, + nautilus_directory_opened_metafile, directory); +#endif + +static NautilusDirectory * +nautilus_directory_new (const char* uri) +{ + NautilusDirectory *directory; + GnomeVFSURI *vfs_uri; + GnomeVFSURI *metafile_uri; + + vfs_uri = gnome_vfs_uri_new (uri); + if (vfs_uri == NULL) + return NULL; + + metafile_uri = gnome_vfs_uri_append_path (vfs_uri, METAFILE_NAME); + if (metafile_uri == NULL) + return NULL; + + directory = gtk_type_new (NAUTILUS_TYPE_DIRECTORY); + + directory->details->uri_text = g_strdup (uri); + directory->details->uri = vfs_uri; + directory->details->metafile_uri = metafile_uri; + + nautilus_directory_read_metafile (directory); + + return directory; +} + +void +nautilus_directory_get_files (NautilusDirectory *directory, + NautilusFileListCallback callback, + gpointer callback_data) +{ + g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory)); + g_return_if_fail (callback != NULL); + + if (directory->details->files != NULL) + (* callback) (directory, + directory->details->files, + callback_data); +} + +char * +nautilus_directory_get_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata) +{ + xmlNode *root; + xmlChar *property; + char *result; + + g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL); + g_return_val_if_fail (tag, NULL); + g_return_val_if_fail (tag[0], NULL); + + root = xmlDocGetRootElement (directory->details->metafile_tree); + property = xmlGetProp (root, tag); + if (property == NULL) + result = g_strdup (default_metadata); + else + result = g_strdup (property); + g_free (property); + + return result; +} + +void +nautilus_directory_set_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata, + const char *metadata) +{ + char *old_metadata; + gboolean old_metadata_matches; + xmlNode *root; + const char *value; + xmlAttr *property_node; + + g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory)); + g_return_if_fail (tag); + g_return_if_fail (tag[0]); + + /* If the data in the metafile is already correct, do nothing. */ + old_metadata = nautilus_directory_get_metadata (directory, tag, default_metadata); + old_metadata_matches = nautilus_strcmp (old_metadata, metadata) == 0; + g_free (old_metadata); + if (old_metadata_matches) + return; + + /* Data that matches the default is represented in the tree by + the lack of an attribute. + */ + if (nautilus_strcmp (default_metadata, metadata) == 0) + value = NULL; + else + value = metadata; + + /* Get at the tree. */ + if (directory->details->metafile_tree == NULL) + directory->details->metafile_tree = xmlNewDoc (METAFILE_XML_VERSION); + root = xmlDocGetRootElement (directory->details->metafile_tree); + if (root == NULL) { + root = xmlNewDocNode (directory->details->metafile_tree, NULL, "DIRECTORY", NULL); + xmlDocSetRootElement (directory->details->metafile_tree, root); + } + + /* Add or remove an attribute node. */ + property_node = xmlSetProp (root, tag, value); + if (value == NULL) + xmlRemoveProp (property_node); + + /* Since we changed the tree, arrange for it to be written. */ + nautilus_directory_request_write_metafile (directory); +} + +#if !defined (NAUTILUS_OMIT_SELF_CHECK) + +static int data_dummy; +static guint file_count; + +static void +get_files_cb (NautilusDirectory *directory, NautilusFileList *files, gpointer data) +{ + g_assert (NAUTILUS_IS_DIRECTORY (directory)); + g_assert (files); + g_assert (data == &data_dummy); + + file_count += g_list_length (files); +} + +void +nautilus_self_check_directory (void) +{ + NautilusDirectory *directory; + + directory = nautilus_directory_get ("file:///etc"); + + g_assert (g_hash_table_size (directory_objects) == 1); + + file_count = 0; + nautilus_directory_get_files (directory, get_files_cb, &data_dummy); + + gtk_object_unref (GTK_OBJECT (directory)); + + g_assert (g_hash_table_size (directory_objects) == 0); +} + +#endif /* !NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus-private/nautilus-directory.h b/libnautilus-private/nautilus-directory.h new file mode 100644 index 000000000..eed024e0b --- /dev/null +++ b/libnautilus-private/nautilus-directory.h @@ -0,0 +1,166 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.h: Nautilus directory model. + + Copyright (C) 1999 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. + + Author: Darin Adler <darin@eazel.com> +*/ + +#ifndef NAUTILUS_DIRECTORY_H +#define NAUTILUS_DIRECTORY_H + +#include <gtk/gtkobject.h> + +/* NautilusDirectory is a class that manages the model for a directory, + real or virtual, for Nautilus, mainly the file-manager component. The directory is + responsible for managing both real data and cached metadata. On top of + the file system independence provided by gnome-vfs, the directory + object also provides: + + 1) A synchronization framework, which notifies via signals as the + set of known files changes. + 2) An abstract interface for getting attributes and performing + operations on files. + 3) An interface that folds together the cached information that's + kept in the metafile with "trustworthy" versions of the same + information available from other means. +*/ + +typedef struct _NautilusDirectory NautilusDirectory; +typedef struct _NautilusDirectoryClass NautilusDirectoryClass; + +#define NAUTILUS_TYPE_DIRECTORY \ + (nautilus_directory_get_type ()) +#define NAUTILUS_DIRECTORY(obj) \ + (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_DIRECTORY, NautilusDirectory)) +#define NAUTILUS_DIRECTORY_CLASS(klass) \ + (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DIRECTORY, NautilusDirectoryClass)) +#define NAUTILUS_IS_DIRECTORY(obj) \ + (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_DIRECTORY)) +#define NAUTILUS_IS_DIRECTORY_CLASS(klass) \ + (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DIRECTORY)) + +typedef struct _NautilusFile NautilusFile; +typedef GList NautilusFileList; + +typedef void (*NautilusFileListCallback) (NautilusDirectory *directory, + NautilusFileList *files, + gpointer data); + +/* Basic GtkObject requirements. */ +GtkType nautilus_directory_get_type (void); + +/* Get a directory given a uri. + Creates the appropriate subclass given the uri mappings. + Returns a referenced object, not a floating one. Unref when finished. + If two windows are viewing the same uri, the directory object is shared. +*/ +NautilusDirectory *nautilus_directory_get (const char *uri); + +/* Simple preliminary interface for getting and setting metadata. */ +char * nautilus_directory_get_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata); +char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata); +void nautilus_directory_set_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata, + const char *metadata); +void nautilus_directory_set_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata, + const char *metadata); + +/* Get the current files. + Instead of returning the list of files, this function uses a callback. + The directory guarantees that signals won't be emitted while in the + callback function. +*/ +void nautilus_directory_get_files (NautilusDirectory *directory, + NautilusFileListCallback callback, + gpointer callback_data); + +/* Return true if the directory has enough information for layout. + This will be false until the metafile is read to prevent a partial layout + from being done. +*/ +gboolean nautilus_directory_is_ready_for_layout (NautilusDirectory *directory); + +/* Basic operations on file objects. */ +void nautilus_file_ref (NautilusFile *file); +void nautilus_file_unref (NautilusFile *file); +char * nautilus_file_get_name (NautilusFile *file); + +/* Return true if this file has already been deleted. + This object will be unref'd after sending the files_removed signal, + but it could hang around longer if someone ref'd it. +*/ +gboolean nautilus_file_is_gone (NautilusFile *file); + +typedef struct _NautilusDirectoryDetails NautilusDirectoryDetails; + +struct _NautilusDirectory +{ + GtkObject object; + + /* Hidden details. */ + NautilusDirectoryDetails *details; +}; + +struct _NautilusDirectoryClass +{ + GtkObjectClass parent_class; + + /*** Notification signals for clients to connect to. ***/ + + /* The files_added and files_removed signals are emitted as + the directory model discovers new files or discovers that + old files have been deleted. In the case of files_removed, + this is the last chance to forget about these file objects + which are about to be unref'd. + */ + void (* files_added) (NautilusDirectory *directory, + NautilusFileList *added_files); + void (* files_removed) (NautilusDirectory *directory, + NautilusFileList *removed_files); + + /* The files_changed signal is emitted as changes occur to + existing files that are noticed by the synchronization framework. + The client must register which file attributes it is interested + in. Changes to other attributes are not reported via the signal. + */ + void (* files_changed) (NautilusDirectory *directory, + NautilusFileList *changed_files); + + /* The ready_for_layout signal is emitted when the directory + model judges that enough files are available for the layout + process to begin. For normal directories this is after the + metafile has been read. If there's no way to get the basic + layout information before getting the actual files, then + this signal need not be emitted as long as is_ready_for_layout + is already true. + */ + void (* ready_for_layout) (NautilusDirectory *directory); +}; + +#endif /* NAUTILUS_DIRECTORY_H */ diff --git a/libnautilus-private/nautilus-lib-self-check-functions.c b/libnautilus-private/nautilus-lib-self-check-functions.c index 8fd904042..76f06a41e 100644 --- a/libnautilus-private/nautilus-lib-self-check-functions.c +++ b/libnautilus-private/nautilus-lib-self-check-functions.c @@ -33,8 +33,7 @@ void nautilus_run_lib_self_checks () { - nautilus_self_check_background (); - nautilus_self_check_gdk_extensions (); + NAUTILUS_LIB_FOR_EACH_SELF_CHECK_FUNCTION (NAUTILUS_CALL_SELF_CHECK_FUNCTION) } #endif /* ! NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus-private/nautilus-lib-self-check-functions.h b/libnautilus-private/nautilus-lib-self-check-functions.h index 2b68bd8d6..eff8b1312 100644 --- a/libnautilus-private/nautilus-lib-self-check-functions.h +++ b/libnautilus-private/nautilus-lib-self-check-functions.h @@ -32,8 +32,17 @@ void nautilus_run_lib_self_checks (void); the self-check framework take way too long (since one file would have to include everything). - So we put the prototypes here instead. + So we put the list of functions here instead. + + Instead of just putting prototypes here, we put this macro that + can be used to do operations on the whole list of functions. */ -void nautilus_self_check_gdk_extensions (void); -void nautilus_self_check_background (void); +#define NAUTILUS_LIB_FOR_EACH_SELF_CHECK_FUNCTION(macro) \ + macro(nautilus_self_check_background) \ + macro(nautilus_self_check_directory) \ + macro(nautilus_self_check_gdk_extensions) \ +/* Add new self-check functions to the list above this line. */ + +/* Generate prototypes for all the functions. */ +NAUTILUS_LIB_FOR_EACH_SELF_CHECK_FUNCTION (NAUTILUS_SELF_CHECK_FUNCTION_PROTOTYPE) diff --git a/libnautilus-private/nautilus-self-checks.h b/libnautilus-private/nautilus-self-checks.h index bfbdd40c0..ab4b30ef3 100644 --- a/libnautilus-private/nautilus-self-checks.h +++ b/libnautilus-private/nautilus-self-checks.h @@ -51,4 +51,10 @@ G_STMT_START { \ #define NAUTILUS_CHECK_STRING_RESULT(expression, expected_value) \ NAUTILUS_CHECK_RESULT(string, expression, expected_value) +#define NAUTILUS_SELF_CHECK_FUNCTION_PROTOTYPE(function) \ + void function (void); + +#define NAUTILUS_CALL_SELF_CHECK_FUNCTION(function) \ + function (); + #endif /* NAUTILUS_SELF_CHECKS_H */ diff --git a/libnautilus/Makefile.am b/libnautilus/Makefile.am index 2a7912af8..46d1de41d 100644 --- a/libnautilus/Makefile.am +++ b/libnautilus/Makefile.am @@ -4,8 +4,17 @@ INCLUDES=-I$(top_srcdir) -I$(top_builddir) \ $(GNOME_CFLAGS) \ $(GNORBA_CFLAGS) \ $(GDK_PIXBUF_CFLAGS) \ + $(VFS_CFLAGS) \ + $(XML_CFLAGS) \ $(WERROR) +libnautilus_la_LDFLAGS=\ + $(GNOME_LIBS) \ + $(GNORBA_LIBS) \ + $(GDK_PIXBUF_LIBS) -lcanvas_pixbuf \ + $(VFS_LIBS) \ + $(XML_LIBS) + nautilus_idl_sources=nautilus-stubs.c nautilus-skels.c nautilus.h nautilus-common.c fsextension_idl_sources=fsextension-stubs.c fsextension-skels.c fsextension-common.c fsextension.h BUILT_SOURCES=$(nautilus_idl_sources) @@ -23,6 +32,7 @@ libnautilusinclude_HEADERS= \ gtkscrollframe.h \ nautilus.h \ nautilus-background.h \ + nautilus-directory.h \ nautilus-file-utilities.h \ nautilus-gtk-extensions.h \ nautilus-lib-self-check-functions.h \ @@ -41,6 +51,7 @@ libnautilus_la_SOURCES=$(nautilus_idl_sources) \ gtkscrollframe.c \ nautilus-background.c \ nautilus-background-canvas-group.c \ + nautilus-directory.c \ nautilus-file-utilities.c \ nautilus-gtk-extensions.c \ nautilus-lib-self-check-functions.c \ @@ -51,10 +62,6 @@ libnautilus_la_SOURCES=$(nautilus_idl_sources) \ ntl-view-frame.c \ $(fsextension_idl_sources) -libnautilus_la_LDFLAGS=$(GNOME_LIBS) \ - $(GNORBA_LIBS) \ - $(GDK_PIXBUF_LIBS) -lcanvas_pixbuf - $(nautilus_idl_sources): nautilus_idl_stamp $(fsextension_idl_sources): fsextension_idl_stamp diff --git a/libnautilus/nautilus-background.c b/libnautilus/nautilus-background.c index 057f265f6..d8090881f 100644 --- a/libnautilus/nautilus-background.c +++ b/libnautilus/nautilus-background.c @@ -185,7 +185,8 @@ nautilus_gtk_style_get_default_class (void) return default_class; } -static void nautilus_gdk_window_update_sizes (GdkWindow *window, int *width, int *height) +static void +nautilus_gdk_window_update_sizes (GdkWindow *window, int *width, int *height) { g_return_if_fail (window != NULL); g_return_if_fail (width != NULL); @@ -199,17 +200,18 @@ static void nautilus_gdk_window_update_sizes (GdkWindow *window, int *width, int gdk_window_get_size (window, NULL, height); } -static void nautilus_background_draw_flat_box (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - gchar *detail, - gint x, - gint y, - gint width, - gint height) +static void +nautilus_background_draw_flat_box (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + char *detail, + int x, + int y, + int width, + int height) { gboolean call_parent; NautilusBackground *background; diff --git a/libnautilus/nautilus-directory.c b/libnautilus/nautilus-directory.c new file mode 100644 index 000000000..86b3c00f9 --- /dev/null +++ b/libnautilus/nautilus-directory.c @@ -0,0 +1,466 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.c: Mautilus 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. + + Author: Darin Adler <darin@eazel.com> +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "nautilus-directory.h" + +#include <stdlib.h> + +#include <gtk/gtkmain.h> + +#include <libgnomevfs/gnome-vfs-types.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <libgnomevfs/gnome-vfs-ops.h> +#include <libgnomevfs/gnome-vfs-async-ops.h> + +#include <gnome-xml/parser.h> +#include <gnome-xml/tree.h> +#include <gnome-xml/xmlmemory.h> + +#include "nautilus-gtk-macros.h" +#include "nautilus-lib-self-check-functions.h" +#include "nautilus-string.h" + +#define METAFILE_NAME ".nautilus.xml" +#define METAFILE_XML_VERSION "1.0" + +static void nautilus_directory_initialize_class (gpointer klass); +static void nautilus_directory_initialize (gpointer object, gpointer klass); +static void nautilus_directory_finalize (GtkObject *object); + +static NautilusDirectory *nautilus_directory_new (const char* uri); + +static void nautilus_directory_read_metafile (NautilusDirectory *directory); +static void nautilus_directory_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_request_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory); + +NAUTILUS_DEFINE_GET_TYPE_FUNCTION (NautilusDirectory, nautilus_directory, GTK_TYPE_OBJECT) + +static GtkObjectClass *parent_class; + +struct _NautilusDirectoryDetails +{ + char *uri_text; + GnomeVFSURI *uri; + + GnomeVFSURI *metafile_uri; + xmlDoc *metafile_tree; + int write_metafile_idle_id; + + NautilusFileList *files; +}; + +struct _NautilusFile +{ +}; + +static GHashTable* directory_objects; + +static void +nautilus_directory_initialize_class (gpointer klass) +{ + GtkObjectClass *object_class; + + object_class = GTK_OBJECT_CLASS (klass); + parent_class = gtk_type_class (GTK_TYPE_OBJECT); + + object_class->finalize = nautilus_directory_finalize; +} + +static void +nautilus_directory_initialize (gpointer object, gpointer klass) +{ + NautilusDirectory *directory; + + directory = NAUTILUS_DIRECTORY(object); + + directory->details = g_new0 (NautilusDirectoryDetails, 1); +} + +static void +nautilus_directory_finalize (GtkObject *object) +{ + NautilusDirectory *directory; + + directory = NAUTILUS_DIRECTORY (object); + + g_hash_table_remove (directory_objects, directory->details->uri_text); + + g_free (directory->details->uri_text); + if (directory->details->uri) + gnome_vfs_uri_unref (directory->details->uri); + if (directory->details->metafile_uri) + gnome_vfs_uri_unref (directory->details->metafile_uri); + xmlFreeDoc (directory->details->metafile_tree); + nautilus_directory_remove_write_metafile_idle (directory); + + g_free (directory->details); + + NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, finalize, (object)); +} + +/** + * nautilus_directory_get: + * @uri: URI of directory to get. + * + * Get a directory given a uri. + * Creates the appropriate subclass given the uri mappings. + * Returns a referenced object, not a floating one. Unref when finished. + * If two windows are viewing the same uri, the directory object is shared. + */ +NautilusDirectory * +nautilus_directory_get (const char *uri) +{ + NautilusDirectory *directory; + + g_return_val_if_fail (uri != NULL, NULL); + + /* FIXME: This currently ignores the issue of two uris that are not identical but point + to the same data. + */ + + /* Create the hash table first time through. */ + if (!directory_objects) + directory_objects = g_hash_table_new (g_str_hash, g_str_equal); + + /* If the object is already in the hash table, look it up. */ + directory = g_hash_table_lookup (directory_objects, uri); + if (directory != NULL) { + g_assert (NAUTILUS_IS_DIRECTORY (directory)); + gtk_object_ref (GTK_OBJECT (directory)); + } else { + /* Create a new directory object instead. */ + directory = NAUTILUS_DIRECTORY (nautilus_directory_new (uri)); + g_assert (strcmp (directory->details->uri_text, uri) == 0); + + /* Put it in the hash table. */ + gtk_object_ref (GTK_OBJECT (directory)); + gtk_object_sink (GTK_OBJECT (directory)); + g_hash_table_insert (directory_objects, directory->details->uri_text, directory); + } + + return directory; +} + +/* This reads the metafile synchronously. This must go eventually. + To do this asynchronously we'd need a way to read an entire file + with async. calls; currently you can only get the file length with + a synchronous call. +*/ +static void +nautilus_directory_read_metafile (NautilusDirectory *directory) +{ + GnomeVFSResult result; + GnomeVFSFileInfo metafile_info; + GnomeVFSHandle *metafile_handle; + char *buffer; + GnomeVFSFileSize size, actual_size; + + g_assert (directory->details->metafile_tree == NULL); + + result = gnome_vfs_get_file_info_uri (directory->details->metafile_uri, + &metafile_info, + GNOME_VFS_FILE_INFO_DEFAULT, + NULL); + if (result == GNOME_VFS_ERROR_NOTFOUND) + return; + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_read_metafile: gnome_vfs_get_file_info_uri failed"); + + metafile_handle = NULL; + if (result == GNOME_VFS_OK) { + result = gnome_vfs_open_uri (&metafile_handle, + directory->details->metafile_uri, + GNOME_VFS_OPEN_READ); + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_read_metafile: gnome_vfs_open_uri failed"); + } + + if (result == GNOME_VFS_OK) { + size = metafile_info.size; + if (size != metafile_info.size) { + g_warning ("nautilus_directory_read_metafile: metafile too large"); + result = GNOME_VFS_ERROR_TOOBIG; + } + } + + if (result == GNOME_VFS_OK) { + buffer = g_malloc (size); + + result = gnome_vfs_read (metafile_handle, buffer, size, &actual_size); + + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_read_metafile: gnome_vfs_read failed"); + else if (actual_size != size) + g_warning ("nautilus_directory_read_metafile: size changed between get_info and read"); + } + + if (metafile_handle != NULL) + gnome_vfs_close (metafile_handle); + + if (result == GNOME_VFS_OK) + directory->details->metafile_tree = xmlParseMemory (buffer, actual_size); + + g_free (buffer); +} + +static void +nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory) +{ + if (directory->details->write_metafile_idle_id != 0) { + gtk_idle_remove (directory->details->write_metafile_idle_id); + directory->details->write_metafile_idle_id = 0; + } +} + +/* This writes the metafile synchronously. This must go eventually. */ +static void +nautilus_directory_write_metafile (NautilusDirectory *directory) +{ + xmlChar *buffer; + int buffer_size; + GnomeVFSResult result; + GnomeVFSHandle *metafile_handle; + GnomeVFSFileSize actual_size; + + g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory)); + + /* We are about the write the metafile, so we can cancel the pending + request to do it. */ + nautilus_directory_remove_write_metafile_idle (directory); + + /* Don't write anything if there's nothing to write. + At some point, we might want to change this to actually delete + the metafile in this case. + */ + if (directory->details->metafile_tree == NULL) + return; + + xmlDocDumpMemory (directory->details->metafile_tree, &buffer, &buffer_size); + + metafile_handle = NULL; + result = gnome_vfs_create_uri (&metafile_handle, + directory->details->metafile_uri, + GNOME_VFS_OPEN_WRITE, + FALSE, + GNOME_VFS_PERM_USER_ALL | GNOME_VFS_PERM_GROUP_ALL | GNOME_VFS_PERM_OTHER_ALL); + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_write_metafile: gnome_vfs_create_uri failed"); + + if (result == GNOME_VFS_OK) { + result = gnome_vfs_write (metafile_handle, buffer, buffer_size, &actual_size); + + if (result != GNOME_VFS_OK) + g_warning ("nautilus_directory_write_metafile: gnome_vfs_write failed"); + else if (actual_size != buffer_size) + g_warning ("nautilus_directory_read_metafile: unable to write all"); + } + + if (metafile_handle != NULL) + gnome_vfs_close (metafile_handle); + + xmlFree (buffer); +} + +static gboolean +nautilus_directory_write_metafile_on_idle (gpointer data) +{ + g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (data), FALSE); + nautilus_directory_write_metafile (data); + return FALSE; +} + +static void +nautilus_directory_request_write_metafile (NautilusDirectory *directory) +{ + /* Set up an idle task that will write the metafile. */ + if (directory->details->write_metafile_idle_id == 0) + directory->details->write_metafile_idle_id = + gtk_idle_add (nautilus_directory_write_metafile_on_idle, + directory); +} + +#if NAUTILUS_DIRECTORY_ASYNC + +static void +nautilus_directory_opened_metafile (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + gpointer callback_data) +{ +} + + result = gnome_vfs_async_open_uri (&metafile_handle, metafile_uri, GNOME_VFS_OPEN_READ, + nautilus_directory_opened_metafile, directory); +#endif + +static NautilusDirectory * +nautilus_directory_new (const char* uri) +{ + NautilusDirectory *directory; + GnomeVFSURI *vfs_uri; + GnomeVFSURI *metafile_uri; + + vfs_uri = gnome_vfs_uri_new (uri); + if (vfs_uri == NULL) + return NULL; + + metafile_uri = gnome_vfs_uri_append_path (vfs_uri, METAFILE_NAME); + if (metafile_uri == NULL) + return NULL; + + directory = gtk_type_new (NAUTILUS_TYPE_DIRECTORY); + + directory->details->uri_text = g_strdup (uri); + directory->details->uri = vfs_uri; + directory->details->metafile_uri = metafile_uri; + + nautilus_directory_read_metafile (directory); + + return directory; +} + +void +nautilus_directory_get_files (NautilusDirectory *directory, + NautilusFileListCallback callback, + gpointer callback_data) +{ + g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory)); + g_return_if_fail (callback != NULL); + + if (directory->details->files != NULL) + (* callback) (directory, + directory->details->files, + callback_data); +} + +char * +nautilus_directory_get_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata) +{ + xmlNode *root; + xmlChar *property; + char *result; + + g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL); + g_return_val_if_fail (tag, NULL); + g_return_val_if_fail (tag[0], NULL); + + root = xmlDocGetRootElement (directory->details->metafile_tree); + property = xmlGetProp (root, tag); + if (property == NULL) + result = g_strdup (default_metadata); + else + result = g_strdup (property); + g_free (property); + + return result; +} + +void +nautilus_directory_set_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata, + const char *metadata) +{ + char *old_metadata; + gboolean old_metadata_matches; + xmlNode *root; + const char *value; + xmlAttr *property_node; + + g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory)); + g_return_if_fail (tag); + g_return_if_fail (tag[0]); + + /* If the data in the metafile is already correct, do nothing. */ + old_metadata = nautilus_directory_get_metadata (directory, tag, default_metadata); + old_metadata_matches = nautilus_strcmp (old_metadata, metadata) == 0; + g_free (old_metadata); + if (old_metadata_matches) + return; + + /* Data that matches the default is represented in the tree by + the lack of an attribute. + */ + if (nautilus_strcmp (default_metadata, metadata) == 0) + value = NULL; + else + value = metadata; + + /* Get at the tree. */ + if (directory->details->metafile_tree == NULL) + directory->details->metafile_tree = xmlNewDoc (METAFILE_XML_VERSION); + root = xmlDocGetRootElement (directory->details->metafile_tree); + if (root == NULL) { + root = xmlNewDocNode (directory->details->metafile_tree, NULL, "DIRECTORY", NULL); + xmlDocSetRootElement (directory->details->metafile_tree, root); + } + + /* Add or remove an attribute node. */ + property_node = xmlSetProp (root, tag, value); + if (value == NULL) + xmlRemoveProp (property_node); + + /* Since we changed the tree, arrange for it to be written. */ + nautilus_directory_request_write_metafile (directory); +} + +#if !defined (NAUTILUS_OMIT_SELF_CHECK) + +static int data_dummy; +static guint file_count; + +static void +get_files_cb (NautilusDirectory *directory, NautilusFileList *files, gpointer data) +{ + g_assert (NAUTILUS_IS_DIRECTORY (directory)); + g_assert (files); + g_assert (data == &data_dummy); + + file_count += g_list_length (files); +} + +void +nautilus_self_check_directory (void) +{ + NautilusDirectory *directory; + + directory = nautilus_directory_get ("file:///etc"); + + g_assert (g_hash_table_size (directory_objects) == 1); + + file_count = 0; + nautilus_directory_get_files (directory, get_files_cb, &data_dummy); + + gtk_object_unref (GTK_OBJECT (directory)); + + g_assert (g_hash_table_size (directory_objects) == 0); +} + +#endif /* !NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus/nautilus-directory.h b/libnautilus/nautilus-directory.h new file mode 100644 index 000000000..eed024e0b --- /dev/null +++ b/libnautilus/nautilus-directory.h @@ -0,0 +1,166 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.h: Nautilus directory model. + + Copyright (C) 1999 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. + + Author: Darin Adler <darin@eazel.com> +*/ + +#ifndef NAUTILUS_DIRECTORY_H +#define NAUTILUS_DIRECTORY_H + +#include <gtk/gtkobject.h> + +/* NautilusDirectory is a class that manages the model for a directory, + real or virtual, for Nautilus, mainly the file-manager component. The directory is + responsible for managing both real data and cached metadata. On top of + the file system independence provided by gnome-vfs, the directory + object also provides: + + 1) A synchronization framework, which notifies via signals as the + set of known files changes. + 2) An abstract interface for getting attributes and performing + operations on files. + 3) An interface that folds together the cached information that's + kept in the metafile with "trustworthy" versions of the same + information available from other means. +*/ + +typedef struct _NautilusDirectory NautilusDirectory; +typedef struct _NautilusDirectoryClass NautilusDirectoryClass; + +#define NAUTILUS_TYPE_DIRECTORY \ + (nautilus_directory_get_type ()) +#define NAUTILUS_DIRECTORY(obj) \ + (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_DIRECTORY, NautilusDirectory)) +#define NAUTILUS_DIRECTORY_CLASS(klass) \ + (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_DIRECTORY, NautilusDirectoryClass)) +#define NAUTILUS_IS_DIRECTORY(obj) \ + (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_DIRECTORY)) +#define NAUTILUS_IS_DIRECTORY_CLASS(klass) \ + (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DIRECTORY)) + +typedef struct _NautilusFile NautilusFile; +typedef GList NautilusFileList; + +typedef void (*NautilusFileListCallback) (NautilusDirectory *directory, + NautilusFileList *files, + gpointer data); + +/* Basic GtkObject requirements. */ +GtkType nautilus_directory_get_type (void); + +/* Get a directory given a uri. + Creates the appropriate subclass given the uri mappings. + Returns a referenced object, not a floating one. Unref when finished. + If two windows are viewing the same uri, the directory object is shared. +*/ +NautilusDirectory *nautilus_directory_get (const char *uri); + +/* Simple preliminary interface for getting and setting metadata. */ +char * nautilus_directory_get_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata); +char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata); +void nautilus_directory_set_metadata (NautilusDirectory *directory, + const char *tag, + const char *default_metadata, + const char *metadata); +void nautilus_directory_set_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata, + const char *metadata); + +/* Get the current files. + Instead of returning the list of files, this function uses a callback. + The directory guarantees that signals won't be emitted while in the + callback function. +*/ +void nautilus_directory_get_files (NautilusDirectory *directory, + NautilusFileListCallback callback, + gpointer callback_data); + +/* Return true if the directory has enough information for layout. + This will be false until the metafile is read to prevent a partial layout + from being done. +*/ +gboolean nautilus_directory_is_ready_for_layout (NautilusDirectory *directory); + +/* Basic operations on file objects. */ +void nautilus_file_ref (NautilusFile *file); +void nautilus_file_unref (NautilusFile *file); +char * nautilus_file_get_name (NautilusFile *file); + +/* Return true if this file has already been deleted. + This object will be unref'd after sending the files_removed signal, + but it could hang around longer if someone ref'd it. +*/ +gboolean nautilus_file_is_gone (NautilusFile *file); + +typedef struct _NautilusDirectoryDetails NautilusDirectoryDetails; + +struct _NautilusDirectory +{ + GtkObject object; + + /* Hidden details. */ + NautilusDirectoryDetails *details; +}; + +struct _NautilusDirectoryClass +{ + GtkObjectClass parent_class; + + /*** Notification signals for clients to connect to. ***/ + + /* The files_added and files_removed signals are emitted as + the directory model discovers new files or discovers that + old files have been deleted. In the case of files_removed, + this is the last chance to forget about these file objects + which are about to be unref'd. + */ + void (* files_added) (NautilusDirectory *directory, + NautilusFileList *added_files); + void (* files_removed) (NautilusDirectory *directory, + NautilusFileList *removed_files); + + /* The files_changed signal is emitted as changes occur to + existing files that are noticed by the synchronization framework. + The client must register which file attributes it is interested + in. Changes to other attributes are not reported via the signal. + */ + void (* files_changed) (NautilusDirectory *directory, + NautilusFileList *changed_files); + + /* The ready_for_layout signal is emitted when the directory + model judges that enough files are available for the layout + process to begin. For normal directories this is after the + metafile has been read. If there's no way to get the basic + layout information before getting the actual files, then + this signal need not be emitted as long as is_ready_for_layout + is already true. + */ + void (* ready_for_layout) (NautilusDirectory *directory); +}; + +#endif /* NAUTILUS_DIRECTORY_H */ diff --git a/libnautilus/nautilus-lib-self-check-functions.c b/libnautilus/nautilus-lib-self-check-functions.c index 8fd904042..76f06a41e 100644 --- a/libnautilus/nautilus-lib-self-check-functions.c +++ b/libnautilus/nautilus-lib-self-check-functions.c @@ -33,8 +33,7 @@ void nautilus_run_lib_self_checks () { - nautilus_self_check_background (); - nautilus_self_check_gdk_extensions (); + NAUTILUS_LIB_FOR_EACH_SELF_CHECK_FUNCTION (NAUTILUS_CALL_SELF_CHECK_FUNCTION) } #endif /* ! NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus/nautilus-lib-self-check-functions.h b/libnautilus/nautilus-lib-self-check-functions.h index 2b68bd8d6..eff8b1312 100644 --- a/libnautilus/nautilus-lib-self-check-functions.h +++ b/libnautilus/nautilus-lib-self-check-functions.h @@ -32,8 +32,17 @@ void nautilus_run_lib_self_checks (void); the self-check framework take way too long (since one file would have to include everything). - So we put the prototypes here instead. + So we put the list of functions here instead. + + Instead of just putting prototypes here, we put this macro that + can be used to do operations on the whole list of functions. */ -void nautilus_self_check_gdk_extensions (void); -void nautilus_self_check_background (void); +#define NAUTILUS_LIB_FOR_EACH_SELF_CHECK_FUNCTION(macro) \ + macro(nautilus_self_check_background) \ + macro(nautilus_self_check_directory) \ + macro(nautilus_self_check_gdk_extensions) \ +/* Add new self-check functions to the list above this line. */ + +/* Generate prototypes for all the functions. */ +NAUTILUS_LIB_FOR_EACH_SELF_CHECK_FUNCTION (NAUTILUS_SELF_CHECK_FUNCTION_PROTOTYPE) diff --git a/libnautilus/nautilus-self-checks.h b/libnautilus/nautilus-self-checks.h index bfbdd40c0..ab4b30ef3 100644 --- a/libnautilus/nautilus-self-checks.h +++ b/libnautilus/nautilus-self-checks.h @@ -51,4 +51,10 @@ G_STMT_START { \ #define NAUTILUS_CHECK_STRING_RESULT(expression, expected_value) \ NAUTILUS_CHECK_RESULT(string, expression, expected_value) +#define NAUTILUS_SELF_CHECK_FUNCTION_PROTOTYPE(function) \ + void function (void); + +#define NAUTILUS_CALL_SELF_CHECK_FUNCTION(function) \ + function (); + #endif /* NAUTILUS_SELF_CHECKS_H */ diff --git a/src/file-manager/Makefile.am b/src/file-manager/Makefile.am index e99b3e10a..8be362170 100644 --- a/src/file-manager/Makefile.am +++ b/src/file-manager/Makefile.am @@ -44,10 +44,6 @@ ntl_file_manager_SOURCES= \ fm-directory-view-icons.c \ fm-directory-view-list.h \ fm-directory-view-list.c \ - fm-directory.h \ - fm-directory.c \ - fm-vfs-directory.h \ - fm-vfs-directory.c \ fm-main.c # noinst_PROGRAMS=gnome-desktop diff --git a/src/file-manager/fm-directory-protected.h b/src/file-manager/fm-directory-protected.h deleted file mode 100644 index adea65f16..000000000 --- a/src/file-manager/fm-directory-protected.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- - - fm-directory-protected.h: GNOME file manager directory model, - details for child classes only. - - Copyright (C) 1999 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. - - Author: Darin Adler <darin@eazel.com> -*/ - -#ifndef FM_DIRECTORY_PROTECTED_H -#define FM_DIRECTORY_PROTECTED_H - -#include "fm-directory.h" - -/* The word "protected" in the name of this file means that these are details of the - FMDirectory class that need to be known to concrete child classes of FMDirectory, - but not to clients of FMDirectory. - - The terminology is stolen from C++. -*/ - -struct _FMDirectoryDetails -{ - char *hash_table_key; /* Could change this "URI" if we want to use it that way. */ -}; - -struct _FMFile -{ -}; - -#endif /* FM_DIRECTORY_PROTECTED_H */ diff --git a/src/file-manager/fm-directory.c b/src/file-manager/fm-directory.c deleted file mode 100644 index db359585a..000000000 --- a/src/file-manager/fm-directory.c +++ /dev/null @@ -1,196 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- - - fm-directory.c: GNOME file manager 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. - - Author: Darin Adler <darin@eazel.com> -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "fm-directory.h" - -#include "fm-directory-protected.h" -#include "fm-vfs-directory.h" -#include <gtk/gtksignal.h> -#include <libnautilus/nautilus-gtk-macros.h> -#include "../nautilus-self-check-functions.h" - -static void fm_directory_destroy (GtkObject *object); -static void fm_directory_finalize (GtkObject *object); - -enum { - GET_FILES, - LAST_SIGNAL -}; - -static GtkObjectClass *parent_class; -static guint signals[LAST_SIGNAL]; - -static GHashTable* directory_objects; - -static void -fm_directory_initialize_class (gpointer klass) -{ - GtkObjectClass *object_class; - - object_class = GTK_OBJECT_CLASS (klass); - parent_class = gtk_type_class (GTK_TYPE_OBJECT); - - signals[GET_FILES] = - gtk_signal_new ("get_files", - GTK_RUN_FIRST, - object_class->type, - GTK_SIGNAL_OFFSET (FMDirectoryClass, get_files), - gtk_marshal_NONE__POINTER_POINTER, - GTK_TYPE_NONE, - 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER); - - gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); - - object_class->destroy = fm_directory_destroy; - object_class->finalize = fm_directory_finalize; -} - -static void -fm_directory_initialize (gpointer object, gpointer klass) -{ - FMDirectory *directory; - - directory = FM_DIRECTORY(object); - - directory->details = g_new0 (FMDirectoryDetails, 1); -} - -static void -fm_directory_destroy (GtkObject *object) -{ - FMDirectory *directory; - - directory = FM_DIRECTORY (object); - g_hash_table_remove (directory_objects, directory->details->hash_table_key); - - NAUTILUS_CALL_PARENT_CLASS(GTK_OBJECT_CLASS, destroy, (object)); -} - -static void -fm_directory_finalize (GtkObject *object) -{ - FMDirectory *directory; - - directory = FM_DIRECTORY (object); - g_free (directory->details->hash_table_key); - g_free (directory->details); - - NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, finalize, (object)); -} - -NAUTILUS_DEFINE_GET_TYPE_FUNCTION (FMDirectory, fm_directory, GTK_TYPE_OBJECT) - -/** - * fm_directory_get: - * @uri: URI of directory to get. - * - * Get a directory given a uri. - * Creates the appropriate subclass given the uri mappings. - * Returns a referenced object, not a floating one. Unref when finished. - * If two windows are viewing the same uri, the directory object is shared. - */ -FMDirectory * -fm_directory_get (const char *uri) -{ - FMDirectory *directory; - - g_return_val_if_fail (uri != NULL, NULL); - - /* FIXME: This currently ignores the issue of two uris that are not identical but point - to the same data. - */ - - /* Create the hash table first time through. */ - if (!directory_objects) - directory_objects = g_hash_table_new (g_str_hash, g_str_equal); - - /* If the object is already in the hash table, look it up. */ - directory = g_hash_table_lookup (directory_objects, uri); - if (directory != NULL) { - g_assert (FM_IS_DIRECTORY (directory)); - gtk_object_ref (GTK_OBJECT (directory)); - } else { - /* Create a new directory object instead. */ - directory = FM_DIRECTORY (fm_vfs_directory_new (uri)); - g_assert (strcmp (directory->details->hash_table_key, uri) == 0); - - /* Put it in the hash table. */ - gtk_object_ref (GTK_OBJECT (directory)); - gtk_object_sink (GTK_OBJECT (directory)); - g_hash_table_insert (directory_objects, directory->details->hash_table_key, directory); - } - - return directory; -} - -void -fm_directory_get_files (FMDirectory *directory, - FMFileListCallback callback, - gpointer callback_data) -{ - g_return_if_fail (FM_IS_DIRECTORY (directory)); - g_return_if_fail (callback); - - gtk_signal_emit (GTK_OBJECT (directory), signals[GET_FILES], callback, callback_data); -} - -/* self check code */ - -#if !defined (NAUTILUS_OMIT_SELF_CHECK) - -static int data_dummy; -static guint file_count; - -static void -get_files_cb (FMDirectory *directory, FMFileList *files, gpointer data) -{ - g_assert (FM_IS_DIRECTORY (directory)); - g_assert (files); - g_assert (data == &data_dummy); - - file_count += g_list_length (files); -} - -void -nautilus_self_check_fm_directory (void) -{ - FMDirectory *directory; - - directory = fm_directory_get ("file:///etc"); - - g_assert (g_hash_table_size (directory_objects) == 1); - - file_count = 0; - fm_directory_get_files (directory, get_files_cb, &data_dummy); - - gtk_object_unref (GTK_OBJECT (directory)); - - g_assert (g_hash_table_size (directory_objects) == 0); -} - -#endif /* !NAUTILUS_OMIT_SELF_CHECK */ diff --git a/src/file-manager/fm-directory.h b/src/file-manager/fm-directory.h deleted file mode 100644 index d9fbd225e..000000000 --- a/src/file-manager/fm-directory.h +++ /dev/null @@ -1,163 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- - - fm-directory.h: GNOME file manager directory model - - Copyright (C) 1999 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. - - Author: Darin Adler <darin@eazel.com> -*/ - -#ifndef FM_DIRECTORY_H -#define FM_DIRECTORY_H - -#include <gtk/gtkobject.h> - -/* FMDirectory is an abstract class that manages the model for a directory, - real or virtual, for the GNOME file manager. The directory is - responsible for managing both real data and cached metadata. On top of - the file system independence provided by GNOME VFS, the directory - object also provides: - - 1) A synchronization framework, which notifies via signals as the - set of known files changes. - 2) An abstract interface for getting attributes and performing - operations on files. - 3) An interface that folds together the cached information that's - kept in the metafile with "trustworthy" versions of the same - information available from other means. - - In addition, none of the GnomeVFS interface is exposed directly, to - help ensure that subclasses that are not based on GnomeVFS are possible. -*/ - -typedef struct _FMDirectory FMDirectory; -typedef struct _FMDirectoryClass FMDirectoryClass; - -#define FM_TYPE_DIRECTORY \ - (fm_directory_get_type ()) -#define FM_DIRECTORY(obj) \ - (GTK_CHECK_CAST ((obj), FM_TYPE_DIRECTORY, FMDirectory)) -#define FM_DIRECTORY_CLASS(klass) \ - (GTK_CHECK_CLASS_CAST ((klass), FM_TYPE_DIRECTORY, FMDirectoryClass)) -#define FM_IS_DIRECTORY(obj) \ - (GTK_CHECK_TYPE ((obj), FM_TYPE_DIRECTORY)) -#define FM_IS_DIRECTORY_CLASS(klass) \ - (GTK_CHECK_CLASS_TYPE ((klass), FM_TYPE_DIRECTORY)) - -typedef struct _FMFile FMFile; -typedef GList FMFileList; - -typedef void (*FMFileListCallback) (FMDirectory *directory, - FMFileList *files, - gpointer data); - -/* Basic GtkObject requirements. */ -GtkType fm_directory_get_type (void); - -/* Get a directory given a uri. - Creates the appropriate subclass given the uri mappings. - Returns a referenced object, not a floating one. Unref when finished. - If two windows are viewing the same uri, the directory object is shared. -*/ -FMDirectory *fm_directory_get (const char *uri); - -/* Get the current files. - Instead of returning the list of files, this function uses a callback. - The directory guarantees that signals won't be emitted while in the - callback function. -*/ -void fm_directory_get_files (FMDirectory *directory, - FMFileListCallback callback, - gpointer callback_data); - -/* Return true if the directory has enough information for layout. - This will be false until the metafile is read to prevent a partial layout - from being done. -*/ -gboolean fm_directory_is_ready_for_layout (FMDirectory *directory); - -/* Basic operations on file objects. */ -void fm_file_ref (FMFile *file); -void fm_file_unref (FMFile *file); -char * fm_file_get_name (FMFile *file); - -/* Return true if this file has already been deleted. - This object will be unref'd after sending the files_removed signal, - but it could hang around longer if someone ref'd it. -*/ -gboolean fm_file_is_gone (FMFile *file); - -typedef struct _FMDirectoryDetails FMDirectoryDetails; - -struct _FMDirectory -{ - GtkObject object; - - /* Hidden details. */ - FMDirectoryDetails *details; -}; - -struct _FMDirectoryClass -{ - GtkObjectClass parent_class; - - /*** Notification signals for clients to connect to. ***/ - - /* The files_added and files_removed signals are emitted as - the directory model discovers new files or discovers that - old files have been deleted. In the case of files_removed, - this is the last chance to forget about these file objects - which are about to be unref'd. - */ - void (* files_added) (FMDirectory *directory, - FMFileList *added_files); - void (* files_removed) (FMDirectory *directory, - FMFileList *removed_files); - - /* The files_changed signal is emitted as changes occur to - existing files that are noticed by the synchronization framework. - The client must register which file attributes it is interested - in. Changes to other attributes are not reported via the signal. - */ - void (* files_changed) (FMDirectory *directory, - FMFileList *changed_files); - - /* The ready_for_layout signal is emitted when the directory - model judges that enough files are available for the layout - process to begin. For normal directories this is after the - metafile has been read. If there's no way to get the basic - layout information before getting the actual files, then - this signal need not be emitted as long as is_ready_for_layout - is already true. - */ - void (* ready_for_layout) (FMDirectory *directory); - - /*** Interface for FMDirectory subclasses to implement. ***/ - - /* Implementation of fm_get_files. */ - void (* get_files) (FMDirectory *directory, - FMFileListCallback callback, - gpointer data); - - /* Implementation of destruction for an FMFile for an item - in this directory. - */ - void (* finalize_file) (FMFile *file); -}; - -#endif /* FM_DIRECTORY_H */ diff --git a/src/file-manager/fm-vfs-directory.c b/src/file-manager/fm-vfs-directory.c deleted file mode 100644 index 8cfe3812b..000000000 --- a/src/file-manager/fm-vfs-directory.c +++ /dev/null @@ -1,153 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- - - fm-vfs-directory.c: GNOME file manager directory model, VFS implementation. - - 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. - - Author: Darin Adler <darin@eazel.com> -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "fm-vfs-directory.h" - -#include "fm-directory-protected.h" -#include <libnautilus/nautilus-gtk-macros.h> -#include <libgnomevfs/gnome-vfs.h> - -struct _FMVFSDirectoryDetails { - GnomeVFSURI *uri; - - FMFileList *files; -}; - -static void fm_vfs_directory_destroy (GtkObject *object); -static void fm_vfs_directory_finalize (GtkObject *object); -static void fm_vfs_directory_get_files (FMDirectory *directory, - FMFileListCallback callback, - gpointer callback_data); - -static GtkObjectClass *parent_class; - -#define METAFILE_NAME ".gnomad.xml" - -/* The process of reading a directory: - - 1) Read and parse the metafile. - 2) Read the directory to notice changes. -*/ - -static void -fm_vfs_directory_initialize_class (gpointer klass) -{ - GtkObjectClass *object_class; - FMDirectoryClass *abstract_directory_class; - - object_class = GTK_OBJECT_CLASS (klass); - abstract_directory_class = FM_DIRECTORY_CLASS (klass); - parent_class = gtk_type_class (FM_TYPE_DIRECTORY); - - object_class->destroy = fm_vfs_directory_destroy; - object_class->finalize = fm_vfs_directory_finalize; - - abstract_directory_class->get_files = fm_vfs_directory_get_files; -} - -static void -fm_vfs_directory_initialize (gpointer object, gpointer klass) -{ - FMVFSDirectory *directory; - - directory = FM_VFS_DIRECTORY (object); - - directory->details = g_new0 (FMVFSDirectoryDetails, 1); -} - -static void -fm_vfs_directory_destroy (GtkObject *object) -{ - NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object)); -} - -static void -fm_vfs_directory_finalize (GtkObject *object) -{ - FMVFSDirectory *directory; - - directory = FM_VFS_DIRECTORY (object); - g_free (directory->details); - - NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, finalize, (object)); -} - -NAUTILUS_DEFINE_GET_TYPE_FUNCTION(FMVFSDirectory, fm_vfs_directory, FM_TYPE_DIRECTORY) - -static void -fm_vfs_opened_metafile (GnomeVFSAsyncHandle *handle, - GnomeVFSResult result, - gpointer callback_data) -{ -} - -FMVFSDirectory * -fm_vfs_directory_new (const char* uri) -{ - FMVFSDirectory *directory; - GnomeVFSURI *vfs_uri; - GnomeVFSURI *metafile_uri; - GnomeVFSAsyncHandle *metafile_handle; - GnomeVFSResult result; - - vfs_uri = gnome_vfs_uri_new (uri); - if (vfs_uri == NULL) - return NULL; - - metafile_uri = gnome_vfs_uri_append_path (vfs_uri, METAFILE_NAME); - if (metafile_uri == NULL) - return NULL; - - directory = gtk_type_new (FM_TYPE_VFS_DIRECTORY); - - FM_DIRECTORY (directory)->details->hash_table_key = g_strdup (uri); - - directory->details->uri = vfs_uri; - - result = gnome_vfs_async_open_uri (&metafile_handle, metafile_uri, GNOME_VFS_OPEN_READ, - fm_vfs_opened_metafile, directory); - - return directory; -} - -static void -fm_vfs_directory_get_files (FMDirectory *abstract_directory, - FMFileListCallback callback, - gpointer callback_data) -{ - FMVFSDirectory *directory; - - g_return_if_fail (FM_IS_VFS_DIRECTORY (abstract_directory)); - g_return_if_fail (callback != NULL); - - directory = FM_VFS_DIRECTORY (abstract_directory); - if (directory->details->files != NULL) - (* callback) (abstract_directory, - directory->details->files, - callback_data); -} diff --git a/src/file-manager/fm-vfs-directory.h b/src/file-manager/fm-vfs-directory.h deleted file mode 100644 index a9627c0c1..000000000 --- a/src/file-manager/fm-vfs-directory.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- - - fm-vfs-directory.c: GNOME file manager directory model, VFS implementation. - - Copyright (C) 1999 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. - - Author: Darin Adler <darin@eazel.com> - */ - -#ifndef FM_VFS_DIRECTORY_H -#define FM_VFS_DIRECTORY_H - -#include "fm-directory.h" - -/* FMVFSDirectory is the concrete VFS implementation of FMDirectory. */ - -typedef struct _FMVFSDirectory FMVFSDirectory; -typedef struct _FMVFSDirectoryClass FMVFSDirectoryClass; - -#define FM_TYPE_VFS_DIRECTORY \ - (fm_vfs_directory_get_type ()) -#define FM_VFS_DIRECTORY(obj) \ - (GTK_CHECK_CAST ((obj), FM_TYPE_VFS_DIRECTORY, FMVFSDirectory)) -#define FM_VFS_DIRECTORY_CLASS(klass) \ - (GTK_CHECK_CLASS_CAST ((klass), FM_TYPE_VFS_DIRECTORY, FMVFSDirectoryClass)) -#define FM_IS_VFS_DIRECTORY(obj) \ - (GTK_CHECK_TYPE ((obj), FM_TYPE_VFS_DIRECTORY)) -#define FM_IS_VFS_DIRECTORY_CLASS(klass) \ - (GTK_CHECK_CLASS_TYPE ((klass), FM_TYPE_VFS_DIRECTORY)) - -typedef struct _FMVFSDirectoryDetails FMVFSDirectoryDetails; - -struct _FMVFSDirectory -{ - FMDirectory abstract_directory; - - FMVFSDirectoryDetails *details; -}; - -struct _FMVFSDirectoryClass -{ - FMDirectoryClass parent_class; -}; - -/* Basic GtkObject requirements. */ -GtkType fm_vfs_directory_get_type (void); -FMVFSDirectory *fm_vfs_directory_new (const char *uri); - -#endif /* FM_VFS_DIRECTORY_H */ diff --git a/src/nautilus-information-panel.c b/src/nautilus-information-panel.c index f580100a3..2a68ecdbe 100644 --- a/src/nautilus-information-panel.c +++ b/src/nautilus-information-panel.c @@ -29,12 +29,21 @@ #include "ntl-meta-view.h" #include <libgnomevfs/gnome-vfs-uri.h> #include <libnautilus/nautilus-background.h> +#include <libnautilus/nautilus-directory.h> #include <libnautilus/nautilus-gtk-macros.h> #include <libnautilus/nautilus-string.h> #define ARRAY_LENGTH(array) \ (sizeof (array) / sizeof ((array)[0])) +struct _NautilusIndexPanelDetails { + GtkWidget *index_container; + GtkWidget *per_uri_container; + GtkWidget *meta_tabs; + gchar *uri; + NautilusDirectory *directory; +}; + static void nautilus_index_panel_initialize_class (gpointer klass); static void nautilus_index_panel_initialize (gpointer object, gpointer klass); static void nautilus_index_panel_destroy (GtkObject *object); @@ -53,6 +62,8 @@ static GdkFont *select_font(const gchar *text_to_format, gint width, const gchar static GtkObjectClass *parent_class; +#define DEFAULT_BACKGROUND_COLOR "rgb:DDDD/DDDD/FFFF" + /* drag and drop definitions */ enum dnd_targets_enum @@ -87,10 +98,11 @@ nautilus_index_panel_initialize_class (gpointer klass) static void make_per_uri_container(NautilusIndexPanel *index_panel) { - index_panel->per_uri_container = gtk_vbox_new (FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (index_panel->per_uri_container), 0); - gtk_widget_show (index_panel->per_uri_container); - gtk_box_pack_start (GTK_BOX (index_panel->index_container), index_panel->per_uri_container, FALSE, FALSE, 0); + index_panel->details->per_uri_container = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (index_panel->details->per_uri_container), 0); + gtk_widget_show (index_panel->details->per_uri_container); + gtk_box_pack_start (GTK_BOX (index_panel->details->index_container), + index_panel->details->per_uri_container, FALSE, FALSE, 0); } /* initialize the instance's fields, create the necessary subviews, etc. */ @@ -103,25 +115,27 @@ nautilus_index_panel_initialize (gpointer object, gpointer klass) index_panel = NAUTILUS_INDEX_PANEL (object); widget = GTK_WIDGET (object); + + index_panel->details = g_new0 (NautilusIndexPanelDetails, 1); /* set the size of the index panel */ gtk_widget_set_usize (widget, 136, 400); /* create the container box */ - index_panel->index_container = gtk_vbox_new (FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (index_panel->index_container), 0); - gtk_widget_show (index_panel->index_container); - gtk_container_add (GTK_CONTAINER (index_panel), index_panel->index_container); + index_panel->details->index_container = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (index_panel->details->index_container), 0); + gtk_widget_show (index_panel->details->index_container); + gtk_container_add (GTK_CONTAINER (index_panel), index_panel->details->index_container); /* allocate and install the vbox to hold the per-uri information */ make_per_uri_container (index_panel); /* allocate and install the meta-tabs (for now it's a notebook) */ - index_panel->meta_tabs = gtk_notebook_new (); - gtk_widget_set_usize (index_panel->meta_tabs, 136, 200); - gtk_widget_show (index_panel->meta_tabs); - gtk_box_pack_end (GTK_BOX (index_panel->index_container), index_panel->meta_tabs, FALSE, FALSE, 0); + index_panel->details->meta_tabs = gtk_notebook_new (); + gtk_widget_set_usize (index_panel->details->meta_tabs, 136, 200); + gtk_widget_show (index_panel->details->meta_tabs); + gtk_box_pack_end (GTK_BOX (index_panel->details->index_container), index_panel->details->meta_tabs, FALSE, FALSE, 0); /* prepare ourselves to receive dropped objects */ gtk_drag_dest_set (GTK_WIDGET (index_panel), @@ -146,7 +160,8 @@ nautilus_index_panel_finalize (GtkObject *object) index_panel = NAUTILUS_INDEX_PANEL (object); - g_free (index_panel->uri); + g_free (index_panel->details->uri); + g_free (index_panel->details); NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, finalize, (object)); } @@ -190,8 +205,14 @@ nautilus_index_panel_drag_data_received (GtkWidget *widget, GdkDragContext *cont case TARGET_COLOR: data = (guint16 *)selection_data->data; color_spec = g_strdup_printf ("rgb:%04hX/%04hX/%04hX", data[0], data[1], data[2]); + + nautilus_directory_set_metadata (NAUTILUS_INDEX_PANEL (widget)->details->directory, + "index_panel_background_color", + DEFAULT_BACKGROUND_COLOR, + color_spec); background = nautilus_get_widget_background (widget); nautilus_background_set_color (background, color_spec); + g_free (color_spec); break; @@ -224,7 +245,7 @@ void nautilus_index_panel_add_meta_view (NautilusIndexPanel *index_panel, Nautil GTK_SIGNAL_FUNC(nautilus_window_send_show_properties), meta_view); */ - gtk_notebook_prepend_page (GTK_NOTEBOOK (index_panel->meta_tabs), GTK_WIDGET (meta_view), label); + gtk_notebook_prepend_page (GTK_NOTEBOOK (index_panel->details->meta_tabs), GTK_WIDGET (meta_view), label); gtk_widget_show (GTK_WIDGET (meta_view)); } @@ -233,9 +254,9 @@ void nautilus_index_panel_remove_meta_view (NautilusIndexPanel *index_panel, Nau { gint page_num; - page_num = gtk_notebook_page_num (GTK_NOTEBOOK (index_panel->meta_tabs), GTK_WIDGET (meta_view)); + page_num = gtk_notebook_page_num (GTK_NOTEBOOK (index_panel->details->meta_tabs), GTK_WIDGET (meta_view)); g_return_if_fail (page_num >= 0); - gtk_notebook_remove_page (GTK_NOTEBOOK (index_panel->meta_tabs), page_num); + gtk_notebook_remove_page (GTK_NOTEBOOK (index_panel->details->meta_tabs), page_num); } /* set up the logo image */ @@ -247,7 +268,7 @@ void nautilus_index_panel_set_up_logo (NautilusIndexPanel *index_panel, const gc file_name = gnome_pixmap_file (logo_path); pix_widget = GTK_WIDGET (gnome_pixmap_new_from_file (file_name)); gtk_widget_show (pix_widget); - gtk_box_pack_start (GTK_BOX (index_panel->per_uri_container), pix_widget, 0, 0, 0); + gtk_box_pack_start (GTK_BOX (index_panel->details->per_uri_container), pix_widget, 0, 0, 0); g_free (file_name); } @@ -326,7 +347,7 @@ nautilus_index_panel_set_up_label (NautilusIndexPanel *index_panel, const gchar return; label_widget = gtk_label_new (file_name); - gtk_box_pack_start (GTK_BOX (index_panel->per_uri_container), label_widget, 0, 0, 0); + gtk_box_pack_start (GTK_BOX (index_panel->details->per_uri_container), label_widget, 0, 0, 0); label_font = select_font(file_name, GTK_WIDGET (index_panel)->allocation.width - 4, "-bitstream-courier-medium-r-normal-*-%d-*-*-*-*-*-*-*"); @@ -348,11 +369,22 @@ nautilus_index_panel_set_up_label (NautilusIndexPanel *index_panel, const gchar void nautilus_index_panel_set_up_info (NautilusIndexPanel *index_panel, const gchar* new_uri) { + NautilusDirectory *directory; NautilusBackground *background; + char *background_color; + + directory = nautilus_directory_get (new_uri); + if (index_panel->details->directory != NULL) + gtk_object_unref (GTK_OBJECT (index_panel->details->directory)); + index_panel->details->directory = directory; - /* set up the background from the metadata. At first, just use hardwired backgrounds */ + /* Set up the background from the metadata. */ background = nautilus_get_widget_background (GTK_WIDGET (index_panel)); - nautilus_background_set_color (background, "rgb:DDDD/DDDD/FFFF"); + background_color = nautilus_directory_get_metadata (directory, + "index_panel_background_color", + DEFAULT_BACKGROUND_COLOR); + nautilus_background_set_color (background, background_color); + g_free (background_color); /* next, install the logo image. */ /* For now, just use a fixed folder image */ @@ -375,14 +407,14 @@ void nautilus_index_panel_set_uri (NautilusIndexPanel *index_panel, const gchar* { /* there's nothing to do if the uri is the same as the current one */ - if (nautilus_strcmp (index_panel->uri, new_uri) == 0) + if (nautilus_strcmp (index_panel->details->uri, new_uri) == 0) return; - g_free (index_panel->uri); - index_panel->uri = g_strdup (new_uri); + g_free (index_panel->details->uri); + index_panel->details->uri = g_strdup (new_uri); /* get rid of the old widgets in the per_uri container */ - gtk_widget_destroy (index_panel->per_uri_container); + gtk_widget_destroy (index_panel->details->per_uri_container); make_per_uri_container (index_panel); /* populate the per-uri box with the info */ diff --git a/src/nautilus-information-panel.h b/src/nautilus-information-panel.h index f2fb10325..24c2a4373 100644 --- a/src/nautilus-information-panel.h +++ b/src/nautilus-information-panel.h @@ -43,13 +43,12 @@ typedef struct _NautilusIndexPanelClass NautilusIndexPanelClass; #define NAUTILUS_IS_INDEX_PANEL_CLASS(klass) \ (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_INDEX_PANEL)) +typedef struct _NautilusIndexPanelDetails NautilusIndexPanelDetails; + struct _NautilusIndexPanel { GtkEventBox event_box; - GtkWidget *index_container; - GtkWidget *per_uri_container; - GtkWidget *meta_tabs; - gchar *uri; + NautilusIndexPanelDetails *details; }; struct _NautilusIndexPanelClass diff --git a/src/nautilus-self-check-functions.c b/src/nautilus-self-check-functions.c index 14d8dffe1..11248bc9b 100644 --- a/src/nautilus-self-check-functions.c +++ b/src/nautilus-self-check-functions.c @@ -33,9 +33,7 @@ void nautilus_run_self_checks() { -#if 0 - nautilus_self_check_fm_directory(); -#endif + NAUTILUS_FOR_EACH_SELF_CHECK_FUNCTION (NAUTILUS_CALL_SELF_CHECK_FUNCTION) } #endif /* ! NAUTILUS_OMIT_SELF_CHECK */ diff --git a/src/nautilus-self-check-functions.h b/src/nautilus-self-check-functions.h index 6c11cf9bc..7c0479212 100644 --- a/src/nautilus-self-check-functions.h +++ b/src/nautilus-self-check-functions.h @@ -30,7 +30,14 @@ void nautilus_run_self_checks (void); the self-check framework take way too long (since one file would have to include everything). - So we put the prototypes here instead. + So we put the list of functions here instead. + + Instead of just putting prototypes here, we put this macro that + can be used to do operations on the whole list of functions. */ -void nautilus_self_check_fm_directory (void); +#define NAUTILUS_FOR_EACH_SELF_CHECK_FUNCTION(macro) \ +/* Add new self-check functions to the list above this line. */ + +/* Generate prototypes for all the functions. */ +NAUTILUS_FOR_EACH_SELF_CHECK_FUNCTION (NAUTILUS_SELF_CHECK_FUNCTION_PROTOTYPE) diff --git a/src/nautilus-sidebar.c b/src/nautilus-sidebar.c index f580100a3..2a68ecdbe 100644 --- a/src/nautilus-sidebar.c +++ b/src/nautilus-sidebar.c @@ -29,12 +29,21 @@ #include "ntl-meta-view.h" #include <libgnomevfs/gnome-vfs-uri.h> #include <libnautilus/nautilus-background.h> +#include <libnautilus/nautilus-directory.h> #include <libnautilus/nautilus-gtk-macros.h> #include <libnautilus/nautilus-string.h> #define ARRAY_LENGTH(array) \ (sizeof (array) / sizeof ((array)[0])) +struct _NautilusIndexPanelDetails { + GtkWidget *index_container; + GtkWidget *per_uri_container; + GtkWidget *meta_tabs; + gchar *uri; + NautilusDirectory *directory; +}; + static void nautilus_index_panel_initialize_class (gpointer klass); static void nautilus_index_panel_initialize (gpointer object, gpointer klass); static void nautilus_index_panel_destroy (GtkObject *object); @@ -53,6 +62,8 @@ static GdkFont *select_font(const gchar *text_to_format, gint width, const gchar static GtkObjectClass *parent_class; +#define DEFAULT_BACKGROUND_COLOR "rgb:DDDD/DDDD/FFFF" + /* drag and drop definitions */ enum dnd_targets_enum @@ -87,10 +98,11 @@ nautilus_index_panel_initialize_class (gpointer klass) static void make_per_uri_container(NautilusIndexPanel *index_panel) { - index_panel->per_uri_container = gtk_vbox_new (FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (index_panel->per_uri_container), 0); - gtk_widget_show (index_panel->per_uri_container); - gtk_box_pack_start (GTK_BOX (index_panel->index_container), index_panel->per_uri_container, FALSE, FALSE, 0); + index_panel->details->per_uri_container = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (index_panel->details->per_uri_container), 0); + gtk_widget_show (index_panel->details->per_uri_container); + gtk_box_pack_start (GTK_BOX (index_panel->details->index_container), + index_panel->details->per_uri_container, FALSE, FALSE, 0); } /* initialize the instance's fields, create the necessary subviews, etc. */ @@ -103,25 +115,27 @@ nautilus_index_panel_initialize (gpointer object, gpointer klass) index_panel = NAUTILUS_INDEX_PANEL (object); widget = GTK_WIDGET (object); + + index_panel->details = g_new0 (NautilusIndexPanelDetails, 1); /* set the size of the index panel */ gtk_widget_set_usize (widget, 136, 400); /* create the container box */ - index_panel->index_container = gtk_vbox_new (FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (index_panel->index_container), 0); - gtk_widget_show (index_panel->index_container); - gtk_container_add (GTK_CONTAINER (index_panel), index_panel->index_container); + index_panel->details->index_container = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (index_panel->details->index_container), 0); + gtk_widget_show (index_panel->details->index_container); + gtk_container_add (GTK_CONTAINER (index_panel), index_panel->details->index_container); /* allocate and install the vbox to hold the per-uri information */ make_per_uri_container (index_panel); /* allocate and install the meta-tabs (for now it's a notebook) */ - index_panel->meta_tabs = gtk_notebook_new (); - gtk_widget_set_usize (index_panel->meta_tabs, 136, 200); - gtk_widget_show (index_panel->meta_tabs); - gtk_box_pack_end (GTK_BOX (index_panel->index_container), index_panel->meta_tabs, FALSE, FALSE, 0); + index_panel->details->meta_tabs = gtk_notebook_new (); + gtk_widget_set_usize (index_panel->details->meta_tabs, 136, 200); + gtk_widget_show (index_panel->details->meta_tabs); + gtk_box_pack_end (GTK_BOX (index_panel->details->index_container), index_panel->details->meta_tabs, FALSE, FALSE, 0); /* prepare ourselves to receive dropped objects */ gtk_drag_dest_set (GTK_WIDGET (index_panel), @@ -146,7 +160,8 @@ nautilus_index_panel_finalize (GtkObject *object) index_panel = NAUTILUS_INDEX_PANEL (object); - g_free (index_panel->uri); + g_free (index_panel->details->uri); + g_free (index_panel->details); NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, finalize, (object)); } @@ -190,8 +205,14 @@ nautilus_index_panel_drag_data_received (GtkWidget *widget, GdkDragContext *cont case TARGET_COLOR: data = (guint16 *)selection_data->data; color_spec = g_strdup_printf ("rgb:%04hX/%04hX/%04hX", data[0], data[1], data[2]); + + nautilus_directory_set_metadata (NAUTILUS_INDEX_PANEL (widget)->details->directory, + "index_panel_background_color", + DEFAULT_BACKGROUND_COLOR, + color_spec); background = nautilus_get_widget_background (widget); nautilus_background_set_color (background, color_spec); + g_free (color_spec); break; @@ -224,7 +245,7 @@ void nautilus_index_panel_add_meta_view (NautilusIndexPanel *index_panel, Nautil GTK_SIGNAL_FUNC(nautilus_window_send_show_properties), meta_view); */ - gtk_notebook_prepend_page (GTK_NOTEBOOK (index_panel->meta_tabs), GTK_WIDGET (meta_view), label); + gtk_notebook_prepend_page (GTK_NOTEBOOK (index_panel->details->meta_tabs), GTK_WIDGET (meta_view), label); gtk_widget_show (GTK_WIDGET (meta_view)); } @@ -233,9 +254,9 @@ void nautilus_index_panel_remove_meta_view (NautilusIndexPanel *index_panel, Nau { gint page_num; - page_num = gtk_notebook_page_num (GTK_NOTEBOOK (index_panel->meta_tabs), GTK_WIDGET (meta_view)); + page_num = gtk_notebook_page_num (GTK_NOTEBOOK (index_panel->details->meta_tabs), GTK_WIDGET (meta_view)); g_return_if_fail (page_num >= 0); - gtk_notebook_remove_page (GTK_NOTEBOOK (index_panel->meta_tabs), page_num); + gtk_notebook_remove_page (GTK_NOTEBOOK (index_panel->details->meta_tabs), page_num); } /* set up the logo image */ @@ -247,7 +268,7 @@ void nautilus_index_panel_set_up_logo (NautilusIndexPanel *index_panel, const gc file_name = gnome_pixmap_file (logo_path); pix_widget = GTK_WIDGET (gnome_pixmap_new_from_file (file_name)); gtk_widget_show (pix_widget); - gtk_box_pack_start (GTK_BOX (index_panel->per_uri_container), pix_widget, 0, 0, 0); + gtk_box_pack_start (GTK_BOX (index_panel->details->per_uri_container), pix_widget, 0, 0, 0); g_free (file_name); } @@ -326,7 +347,7 @@ nautilus_index_panel_set_up_label (NautilusIndexPanel *index_panel, const gchar return; label_widget = gtk_label_new (file_name); - gtk_box_pack_start (GTK_BOX (index_panel->per_uri_container), label_widget, 0, 0, 0); + gtk_box_pack_start (GTK_BOX (index_panel->details->per_uri_container), label_widget, 0, 0, 0); label_font = select_font(file_name, GTK_WIDGET (index_panel)->allocation.width - 4, "-bitstream-courier-medium-r-normal-*-%d-*-*-*-*-*-*-*"); @@ -348,11 +369,22 @@ nautilus_index_panel_set_up_label (NautilusIndexPanel *index_panel, const gchar void nautilus_index_panel_set_up_info (NautilusIndexPanel *index_panel, const gchar* new_uri) { + NautilusDirectory *directory; NautilusBackground *background; + char *background_color; + + directory = nautilus_directory_get (new_uri); + if (index_panel->details->directory != NULL) + gtk_object_unref (GTK_OBJECT (index_panel->details->directory)); + index_panel->details->directory = directory; - /* set up the background from the metadata. At first, just use hardwired backgrounds */ + /* Set up the background from the metadata. */ background = nautilus_get_widget_background (GTK_WIDGET (index_panel)); - nautilus_background_set_color (background, "rgb:DDDD/DDDD/FFFF"); + background_color = nautilus_directory_get_metadata (directory, + "index_panel_background_color", + DEFAULT_BACKGROUND_COLOR); + nautilus_background_set_color (background, background_color); + g_free (background_color); /* next, install the logo image. */ /* For now, just use a fixed folder image */ @@ -375,14 +407,14 @@ void nautilus_index_panel_set_uri (NautilusIndexPanel *index_panel, const gchar* { /* there's nothing to do if the uri is the same as the current one */ - if (nautilus_strcmp (index_panel->uri, new_uri) == 0) + if (nautilus_strcmp (index_panel->details->uri, new_uri) == 0) return; - g_free (index_panel->uri); - index_panel->uri = g_strdup (new_uri); + g_free (index_panel->details->uri); + index_panel->details->uri = g_strdup (new_uri); /* get rid of the old widgets in the per_uri container */ - gtk_widget_destroy (index_panel->per_uri_container); + gtk_widget_destroy (index_panel->details->per_uri_container); make_per_uri_container (index_panel); /* populate the per-uri box with the info */ diff --git a/src/nautilus-sidebar.h b/src/nautilus-sidebar.h index f2fb10325..24c2a4373 100644 --- a/src/nautilus-sidebar.h +++ b/src/nautilus-sidebar.h @@ -43,13 +43,12 @@ typedef struct _NautilusIndexPanelClass NautilusIndexPanelClass; #define NAUTILUS_IS_INDEX_PANEL_CLASS(klass) \ (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_INDEX_PANEL)) +typedef struct _NautilusIndexPanelDetails NautilusIndexPanelDetails; + struct _NautilusIndexPanel { GtkEventBox event_box; - GtkWidget *index_container; - GtkWidget *per_uri_container; - GtkWidget *meta_tabs; - gchar *uri; + NautilusIndexPanelDetails *details; }; struct _NautilusIndexPanelClass diff --git a/src/ntl-index-panel.c b/src/ntl-index-panel.c index f580100a3..2a68ecdbe 100644 --- a/src/ntl-index-panel.c +++ b/src/ntl-index-panel.c @@ -29,12 +29,21 @@ #include "ntl-meta-view.h" #include <libgnomevfs/gnome-vfs-uri.h> #include <libnautilus/nautilus-background.h> +#include <libnautilus/nautilus-directory.h> #include <libnautilus/nautilus-gtk-macros.h> #include <libnautilus/nautilus-string.h> #define ARRAY_LENGTH(array) \ (sizeof (array) / sizeof ((array)[0])) +struct _NautilusIndexPanelDetails { + GtkWidget *index_container; + GtkWidget *per_uri_container; + GtkWidget *meta_tabs; + gchar *uri; + NautilusDirectory *directory; +}; + static void nautilus_index_panel_initialize_class (gpointer klass); static void nautilus_index_panel_initialize (gpointer object, gpointer klass); static void nautilus_index_panel_destroy (GtkObject *object); @@ -53,6 +62,8 @@ static GdkFont *select_font(const gchar *text_to_format, gint width, const gchar static GtkObjectClass *parent_class; +#define DEFAULT_BACKGROUND_COLOR "rgb:DDDD/DDDD/FFFF" + /* drag and drop definitions */ enum dnd_targets_enum @@ -87,10 +98,11 @@ nautilus_index_panel_initialize_class (gpointer klass) static void make_per_uri_container(NautilusIndexPanel *index_panel) { - index_panel->per_uri_container = gtk_vbox_new (FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (index_panel->per_uri_container), 0); - gtk_widget_show (index_panel->per_uri_container); - gtk_box_pack_start (GTK_BOX (index_panel->index_container), index_panel->per_uri_container, FALSE, FALSE, 0); + index_panel->details->per_uri_container = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (index_panel->details->per_uri_container), 0); + gtk_widget_show (index_panel->details->per_uri_container); + gtk_box_pack_start (GTK_BOX (index_panel->details->index_container), + index_panel->details->per_uri_container, FALSE, FALSE, 0); } /* initialize the instance's fields, create the necessary subviews, etc. */ @@ -103,25 +115,27 @@ nautilus_index_panel_initialize (gpointer object, gpointer klass) index_panel = NAUTILUS_INDEX_PANEL (object); widget = GTK_WIDGET (object); + + index_panel->details = g_new0 (NautilusIndexPanelDetails, 1); /* set the size of the index panel */ gtk_widget_set_usize (widget, 136, 400); /* create the container box */ - index_panel->index_container = gtk_vbox_new (FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (index_panel->index_container), 0); - gtk_widget_show (index_panel->index_container); - gtk_container_add (GTK_CONTAINER (index_panel), index_panel->index_container); + index_panel->details->index_container = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (index_panel->details->index_container), 0); + gtk_widget_show (index_panel->details->index_container); + gtk_container_add (GTK_CONTAINER (index_panel), index_panel->details->index_container); /* allocate and install the vbox to hold the per-uri information */ make_per_uri_container (index_panel); /* allocate and install the meta-tabs (for now it's a notebook) */ - index_panel->meta_tabs = gtk_notebook_new (); - gtk_widget_set_usize (index_panel->meta_tabs, 136, 200); - gtk_widget_show (index_panel->meta_tabs); - gtk_box_pack_end (GTK_BOX (index_panel->index_container), index_panel->meta_tabs, FALSE, FALSE, 0); + index_panel->details->meta_tabs = gtk_notebook_new (); + gtk_widget_set_usize (index_panel->details->meta_tabs, 136, 200); + gtk_widget_show (index_panel->details->meta_tabs); + gtk_box_pack_end (GTK_BOX (index_panel->details->index_container), index_panel->details->meta_tabs, FALSE, FALSE, 0); /* prepare ourselves to receive dropped objects */ gtk_drag_dest_set (GTK_WIDGET (index_panel), @@ -146,7 +160,8 @@ nautilus_index_panel_finalize (GtkObject *object) index_panel = NAUTILUS_INDEX_PANEL (object); - g_free (index_panel->uri); + g_free (index_panel->details->uri); + g_free (index_panel->details); NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, finalize, (object)); } @@ -190,8 +205,14 @@ nautilus_index_panel_drag_data_received (GtkWidget *widget, GdkDragContext *cont case TARGET_COLOR: data = (guint16 *)selection_data->data; color_spec = g_strdup_printf ("rgb:%04hX/%04hX/%04hX", data[0], data[1], data[2]); + + nautilus_directory_set_metadata (NAUTILUS_INDEX_PANEL (widget)->details->directory, + "index_panel_background_color", + DEFAULT_BACKGROUND_COLOR, + color_spec); background = nautilus_get_widget_background (widget); nautilus_background_set_color (background, color_spec); + g_free (color_spec); break; @@ -224,7 +245,7 @@ void nautilus_index_panel_add_meta_view (NautilusIndexPanel *index_panel, Nautil GTK_SIGNAL_FUNC(nautilus_window_send_show_properties), meta_view); */ - gtk_notebook_prepend_page (GTK_NOTEBOOK (index_panel->meta_tabs), GTK_WIDGET (meta_view), label); + gtk_notebook_prepend_page (GTK_NOTEBOOK (index_panel->details->meta_tabs), GTK_WIDGET (meta_view), label); gtk_widget_show (GTK_WIDGET (meta_view)); } @@ -233,9 +254,9 @@ void nautilus_index_panel_remove_meta_view (NautilusIndexPanel *index_panel, Nau { gint page_num; - page_num = gtk_notebook_page_num (GTK_NOTEBOOK (index_panel->meta_tabs), GTK_WIDGET (meta_view)); + page_num = gtk_notebook_page_num (GTK_NOTEBOOK (index_panel->details->meta_tabs), GTK_WIDGET (meta_view)); g_return_if_fail (page_num >= 0); - gtk_notebook_remove_page (GTK_NOTEBOOK (index_panel->meta_tabs), page_num); + gtk_notebook_remove_page (GTK_NOTEBOOK (index_panel->details->meta_tabs), page_num); } /* set up the logo image */ @@ -247,7 +268,7 @@ void nautilus_index_panel_set_up_logo (NautilusIndexPanel *index_panel, const gc file_name = gnome_pixmap_file (logo_path); pix_widget = GTK_WIDGET (gnome_pixmap_new_from_file (file_name)); gtk_widget_show (pix_widget); - gtk_box_pack_start (GTK_BOX (index_panel->per_uri_container), pix_widget, 0, 0, 0); + gtk_box_pack_start (GTK_BOX (index_panel->details->per_uri_container), pix_widget, 0, 0, 0); g_free (file_name); } @@ -326,7 +347,7 @@ nautilus_index_panel_set_up_label (NautilusIndexPanel *index_panel, const gchar return; label_widget = gtk_label_new (file_name); - gtk_box_pack_start (GTK_BOX (index_panel->per_uri_container), label_widget, 0, 0, 0); + gtk_box_pack_start (GTK_BOX (index_panel->details->per_uri_container), label_widget, 0, 0, 0); label_font = select_font(file_name, GTK_WIDGET (index_panel)->allocation.width - 4, "-bitstream-courier-medium-r-normal-*-%d-*-*-*-*-*-*-*"); @@ -348,11 +369,22 @@ nautilus_index_panel_set_up_label (NautilusIndexPanel *index_panel, const gchar void nautilus_index_panel_set_up_info (NautilusIndexPanel *index_panel, const gchar* new_uri) { + NautilusDirectory *directory; NautilusBackground *background; + char *background_color; + + directory = nautilus_directory_get (new_uri); + if (index_panel->details->directory != NULL) + gtk_object_unref (GTK_OBJECT (index_panel->details->directory)); + index_panel->details->directory = directory; - /* set up the background from the metadata. At first, just use hardwired backgrounds */ + /* Set up the background from the metadata. */ background = nautilus_get_widget_background (GTK_WIDGET (index_panel)); - nautilus_background_set_color (background, "rgb:DDDD/DDDD/FFFF"); + background_color = nautilus_directory_get_metadata (directory, + "index_panel_background_color", + DEFAULT_BACKGROUND_COLOR); + nautilus_background_set_color (background, background_color); + g_free (background_color); /* next, install the logo image. */ /* For now, just use a fixed folder image */ @@ -375,14 +407,14 @@ void nautilus_index_panel_set_uri (NautilusIndexPanel *index_panel, const gchar* { /* there's nothing to do if the uri is the same as the current one */ - if (nautilus_strcmp (index_panel->uri, new_uri) == 0) + if (nautilus_strcmp (index_panel->details->uri, new_uri) == 0) return; - g_free (index_panel->uri); - index_panel->uri = g_strdup (new_uri); + g_free (index_panel->details->uri); + index_panel->details->uri = g_strdup (new_uri); /* get rid of the old widgets in the per_uri container */ - gtk_widget_destroy (index_panel->per_uri_container); + gtk_widget_destroy (index_panel->details->per_uri_container); make_per_uri_container (index_panel); /* populate the per-uri box with the info */ diff --git a/src/ntl-index-panel.h b/src/ntl-index-panel.h index f2fb10325..24c2a4373 100644 --- a/src/ntl-index-panel.h +++ b/src/ntl-index-panel.h @@ -43,13 +43,12 @@ typedef struct _NautilusIndexPanelClass NautilusIndexPanelClass; #define NAUTILUS_IS_INDEX_PANEL_CLASS(klass) \ (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_INDEX_PANEL)) +typedef struct _NautilusIndexPanelDetails NautilusIndexPanelDetails; + struct _NautilusIndexPanel { GtkEventBox event_box; - GtkWidget *index_container; - GtkWidget *per_uri_container; - GtkWidget *meta_tabs; - gchar *uri; + NautilusIndexPanelDetails *details; }; struct _NautilusIndexPanelClass |