summaryrefslogtreecommitdiff
path: root/libnautilus-private
diff options
context:
space:
mode:
authorDave Camp <dave@ximian.com>2004-01-11 20:35:02 +0000
committerDave Camp <campd@src.gnome.org>2004-01-11 20:35:02 +0000
commit7cb9107c85bef29b5b8edc5fb7b06b52a041cc04 (patch)
tree6f1044bdbab09b99a8e595be0d4d8d16d27a1d47 /libnautilus-private
parentb92ee1501d6afcd2993f468aa21e2976accd8519 (diff)
downloadnautilus-7cb9107c85bef29b5b8edc5fb7b06b52a041cc04.tar.gz
Merged from nautilus-extensions-branch.
2004-01-11 Dave Camp <dave@ximian.com> * Merged from nautilus-extensions-branch.
Diffstat (limited to 'libnautilus-private')
-rw-r--r--libnautilus-private/Makefile.am11
-rw-r--r--libnautilus-private/apps_nautilus_preferences.schemas.in30
-rw-r--r--libnautilus-private/nautilus-bonobo-extensions.c161
-rw-r--r--libnautilus-private/nautilus-bonobo-extensions.h153
-rw-r--r--libnautilus-private/nautilus-column-chooser.c652
-rw-r--r--libnautilus-private/nautilus-column-chooser.h61
-rw-r--r--libnautilus-private/nautilus-column-utilities.c228
-rw-r--r--libnautilus-private/nautilus-column-utilities.h38
-rw-r--r--libnautilus-private/nautilus-directory-async.c231
-rw-r--r--libnautilus-private/nautilus-directory-private.h7
-rw-r--r--libnautilus-private/nautilus-directory.c3
-rw-r--r--libnautilus-private/nautilus-file-attributes.h1
-rw-r--r--libnautilus-private/nautilus-file-private.h29
-rw-r--r--libnautilus-private/nautilus-file.c386
-rw-r--r--libnautilus-private/nautilus-file.h5
-rw-r--r--libnautilus-private/nautilus-global-preferences.c16
-rw-r--r--libnautilus-private/nautilus-global-preferences.h2
-rw-r--r--libnautilus-private/nautilus-marshal.list1
-rw-r--r--libnautilus-private/nautilus-metadata.h3
-rw-r--r--libnautilus-private/nautilus-module.c258
-rw-r--r--libnautilus-private/nautilus-module.h42
21 files changed, 2140 insertions, 178 deletions
diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am
index d6e826190..430176ca7 100644
--- a/libnautilus-private/Makefile.am
+++ b/libnautilus-private/Makefile.am
@@ -2,7 +2,9 @@ include $(top_srcdir)/Makefile.shared
lib_LTLIBRARIES=libnautilus-private.la
-libnautilus_private_la_LIBADD = ../libnautilus/libnautilus.la
+libnautilus_private_la_LIBADD = \
+ ../libnautilus/libnautilus.la \
+ ../libnautilus-extension/libnautilus-extension.la
INCLUDES = \
-I$(top_srcdir) \
@@ -13,6 +15,7 @@ INCLUDES = \
-DDATADIR=\""$(datadir)"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
-DNAUTILUS_DATADIR=\""$(datadir)/nautilus"\" \
+ -DNAUTILUS_EXTENSIONDIR=\""$(libdir)/nautilus/extensions-1.0"\" \
$(NULL)
dependency_static_libs = \
@@ -52,6 +55,10 @@ libnautilus_private_la_SOURCES = \
nautilus-cell-renderer-pixbuf-emblem.c \
nautilus-cell-renderer-pixbuf-emblem.h \
nautilus-cdrom-extensions.h \
+ nautilus-column-chooser.c \
+ nautilus-column-chooser.h \
+ nautilus-column-utilities.c \
+ nautilus-column-utilities.h \
nautilus-customization-data.c \
nautilus-customization-data.h \
nautilus-default-file-icon.c \
@@ -140,6 +147,8 @@ libnautilus_private_la_SOURCES = \
nautilus-metafile.h \
nautilus-mime-actions.c \
nautilus-mime-actions.h \
+ nautilus-module.c \
+ nautilus-module.h \
nautilus-monitor.c \
nautilus-monitor.h \
nautilus-program-chooser.c \
diff --git a/libnautilus-private/apps_nautilus_preferences.schemas.in b/libnautilus-private/apps_nautilus_preferences.schemas.in
index 3671bc39b..8bea57ce7 100644
--- a/libnautilus-private/apps_nautilus_preferences.schemas.in
+++ b/libnautilus-private/apps_nautilus_preferences.schemas.in
@@ -584,6 +584,36 @@
</schema>
<schema>
+ <key>/schemas/apps/nautilus/list_view/default_visible_columns</key>
+ <applyto>/apps/nautilus/list_view/default_visible_columns</applyto>
+ <owner>nautilus</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <default>[name,size,type,date_modified]</default>
+ <locale name="C">
+ <short>Default list of columns visible in the list view</short>
+ <long>
+ Default list of columns visible in the list view.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/nautilus/list_view/default_column_order</key>
+ <applyto>/apps/nautilus/list_view/default_column_order</applyto>
+ <owner>nautilus</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <default>[name,size,type,date_modified]</default>
+ <locale name="C">
+ <short>Default column order in the list view</short>
+ <long>
+ Default column order in the list view.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
<key>/schemas/apps/nautilus/preferences/hide_built_in_bookmarks</key>
<applyto>/apps/nautilus/preferences/hide_built_in_bookmarks</applyto>
<owner>nautilus</owner>
diff --git a/libnautilus-private/nautilus-bonobo-extensions.c b/libnautilus-private/nautilus-bonobo-extensions.c
index 6a363ce77..c9d1946a4 100644
--- a/libnautilus-private/nautilus-bonobo-extensions.c
+++ b/libnautilus-private/nautilus-bonobo-extensions.c
@@ -28,6 +28,8 @@
#include <config.h>
#include "nautilus-bonobo-extensions.h"
+#include "nautilus-icon-factory.h"
+
#include <eel/eel-string.h>
#include <eel/eel-gnome-extensions.h>
#include <eel/eel-debug.h>
@@ -487,6 +489,165 @@ nautilus_bonobo_set_label_for_toolitem_and_command (BonoboUIComponent *ui,
g_free (label_no_underscore);
}
+static char *
+get_extension_menu_item_xml (NautilusMenuItem *item)
+{
+ GString *ui_xml;
+ char *pixbuf_data;
+ GdkPixbuf *pixbuf;
+ char *name;
+ char *icon;
+
+ ui_xml = g_string_new ("");
+
+ g_object_get (G_OBJECT (item), "name", &name, "icon", &icon, NULL);
+
+ g_string_append_printf (ui_xml,
+ "<menuitem name=\"%s\" verb=\"%s\"",
+ name, name);
+
+ if (icon) {
+ pixbuf = nautilus_icon_factory_get_pixbuf_from_name
+ (icon,
+ NULL,
+ NAUTILUS_ICON_SIZE_FOR_MENUS,
+ NULL);
+ if (pixbuf) {
+ pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
+ g_string_append_printf (ui_xml, " pixtype=\"pixbuf\" pixname=\"%s\"", pixbuf_data);
+ g_free (pixbuf_data);
+ g_object_unref (pixbuf);
+ }
+ }
+ g_string_append (ui_xml, "/>");
+
+ g_free (name);
+ g_free (icon);
+
+ return g_string_free (ui_xml, FALSE);
+}
+
+static void
+extension_action_callback (BonoboUIComponent *component,
+ gpointer callback_data, const char *path)
+{
+ nautilus_menu_item_activate (NAUTILUS_MENU_ITEM (callback_data));
+}
+
+void
+nautilus_bonobo_add_extension_item_command (BonoboUIComponent *ui,
+ NautilusMenuItem *item)
+{
+ GString *ui_xml;
+ GClosure *closure;
+ char *name;
+ char *label;
+ char *tip;
+ char *sensitive;
+
+ ui_xml = g_string_new ("<Root><commands>");
+
+ g_object_get (G_OBJECT (item),
+ "name", &name, "label", &label,
+ "tip", &tip, "sensitive", &sensitive,
+ NULL);
+
+ g_string_append_printf (ui_xml,
+ "<cmd name=\"%s\" label=\"%s\" tip=\"%s\" sensitive=\"%s\"/>",
+ name, label, tip, sensitive ? "1" : "0");
+
+ ui_xml = g_string_append (ui_xml, "</commands></Root>");
+
+ bonobo_ui_component_set (ui, "/", ui_xml->str, NULL);
+ g_string_free (ui_xml, TRUE);
+
+
+ closure = g_cclosure_new
+ (G_CALLBACK (extension_action_callback),
+ g_object_ref (item),
+ (GClosureNotify)g_object_unref);
+
+ bonobo_ui_component_add_verb_full (ui, name, closure);
+
+ g_free (name);
+ g_free (label);
+ g_free (tip);
+}
+
+void
+nautilus_bonobo_add_extension_item (BonoboUIComponent *ui,
+ const char *path,
+ NautilusMenuItem *item)
+{
+ char *item_xml;
+
+ item_xml = get_extension_menu_item_xml (item);
+
+ bonobo_ui_component_set (ui, path, item_xml, NULL);
+
+ g_free (item_xml);
+}
+
+static char *
+get_extension_toolbar_item_xml (NautilusMenuItem *item)
+{
+ GString *ui_xml;
+ char *pixbuf_data;
+ GdkPixbuf *pixbuf;
+ char *name;
+ char *icon;
+ gboolean priority;
+
+ ui_xml = g_string_new ("");
+
+
+ g_object_get (item,
+ "name", &name, "priority", &priority,
+ "icon", &icon,
+ NULL);
+ g_string_append_printf (ui_xml,
+ "<toolitem name=\"%s\" verb=\"%s\"",
+ name, name);
+
+ if (priority) {
+ g_string_append (ui_xml, " priority=\"1\"");
+ }
+
+ if (icon) {
+ pixbuf = nautilus_icon_factory_get_pixbuf_from_name
+ (icon,
+ NULL,
+ NAUTILUS_ICON_SIZE_FOR_MENUS,
+ NULL);
+ if (pixbuf) {
+ pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
+ g_string_append_printf (ui_xml, " pixtype=\"pixbuf\" pixname=\"%s\"", pixbuf_data);
+ g_free (pixbuf_data);
+ g_object_unref (pixbuf);
+ }
+ }
+ g_string_append (ui_xml, "/>");
+
+ g_free (name);
+ g_free (icon);
+
+ return g_string_free (ui_xml, FALSE);
+}
+
+void
+nautilus_bonobo_add_extension_toolbar_item (BonoboUIComponent *ui,
+ const char *path,
+ NautilusMenuItem *item)
+{
+ char *item_xml;
+
+ item_xml = get_extension_toolbar_item_xml (item);
+
+ bonobo_ui_component_set (ui, path, item_xml, NULL);
+
+ g_free (item_xml);
+}
+
static void
activation_handle_done (NautilusBonoboActivationHandle *handle)
{
diff --git a/libnautilus-private/nautilus-bonobo-extensions.h b/libnautilus-private/nautilus-bonobo-extensions.h
index 3f3396192..f780761d6 100644
--- a/libnautilus-private/nautilus-bonobo-extensions.h
+++ b/libnautilus-private/nautilus-bonobo-extensions.h
@@ -32,6 +32,8 @@
#include <bonobo/bonobo-generic-factory.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <libnautilus-extension/nautilus-menu-item.h>
+
typedef struct NautilusBonoboActivationHandle NautilusBonoboActivationHandle;
typedef void (*NautilusBonoboActivationCallback) (NautilusBonoboActivationHandle *handle,
@@ -41,78 +43,87 @@ typedef void (*NautilusBonoboActivationCallback) (NautilusBonoboActivationHandle
typedef CORBA_Object (*NautilusBonoboCreateObject) (const char *iid,
gpointer callback_data);
-void nautilus_bonobo_set_accelerator (BonoboUIComponent *ui,
- const char *path,
- const char *accelerator);
-char * nautilus_bonobo_get_label (BonoboUIComponent *ui,
- const char *path);
-void nautilus_bonobo_set_label (BonoboUIComponent *ui,
- const char *path,
- const char *label);
-void nautilus_bonobo_set_tip (BonoboUIComponent *ui,
- const char *path,
- const char *tip);
-void nautilus_bonobo_set_sensitive (BonoboUIComponent *ui,
- const char *path,
- gboolean sensitive);
-void nautilus_bonobo_set_toggle_state (BonoboUIComponent *ui,
- const char *path,
- gboolean state);
-void nautilus_bonobo_set_hidden (BonoboUIComponent *ui,
- const char *path,
- gboolean hidden);
-gboolean nautilus_bonobo_get_hidden (BonoboUIComponent *ui,
- const char *path);
-void nautilus_bonobo_add_numbered_menu_item (BonoboUIComponent *ui,
- const char *container_path,
- guint index,
- const char *label,
- GdkPixbuf *pixbuf);
-void nautilus_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui,
- const char *container_path,
- guint index,
- const char *label);
-void nautilus_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui,
- const char *container_path,
- guint index,
- const char *label,
- const char *radio_group_name);
-char * nautilus_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui,
- const char *container_path,
- guint index);
-char * nautilus_bonobo_get_numbered_menu_item_path (BonoboUIComponent *ui,
- const char *container_path,
- guint index);
+void nautilus_bonobo_set_accelerator (BonoboUIComponent *ui,
+ const char *path,
+ const char *accelerator);
+char * nautilus_bonobo_get_label (BonoboUIComponent *ui,
+ const char *path);
+void nautilus_bonobo_set_label (BonoboUIComponent *ui,
+ const char *path,
+ const char *label);
+void nautilus_bonobo_set_tip (BonoboUIComponent *ui,
+ const char *path,
+ const char *tip);
+void nautilus_bonobo_set_sensitive (BonoboUIComponent *ui,
+ const char *path,
+ gboolean sensitive);
+void nautilus_bonobo_set_toggle_state (BonoboUIComponent *ui,
+ const char *path,
+ gboolean state);
+void nautilus_bonobo_set_hidden (BonoboUIComponent *ui,
+ const char *path,
+ gboolean hidden);
+gboolean nautilus_bonobo_get_hidden (BonoboUIComponent *ui,
+ const char *path);
+void nautilus_bonobo_add_numbered_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ GdkPixbuf *pixbuf);
+void nautilus_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label);
+void nautilus_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ const char *radio_group_name);
+char * nautilus_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+char * nautilus_bonobo_get_numbered_menu_item_path (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index);
+
guint nautilus_bonobo_get_numbered_menu_item_index_from_command
- (const char *command);
+(const char *command);
char * nautilus_bonobo_get_numbered_menu_item_container_path_from_command
- (const char *command);
-void nautilus_bonobo_add_submenu (BonoboUIComponent *ui,
- const char *container_path,
- const char *label,
- GdkPixbuf *pixbuf);
-void nautilus_bonobo_add_menu_separator (BonoboUIComponent *ui,
- const char *path);
-void nautilus_bonobo_remove_menu_items_and_commands (BonoboUIComponent *ui,
- const char *container_path);
-void nautilus_bonobo_set_label_for_toolitem_and_command (BonoboUIComponent *ui,
- const char *toolitem_path,
- const char *command_path,
- const char *label_with_underscore);
-void nautilus_bonobo_set_icon (BonoboUIComponent *ui,
- const char *path,
- const char *icon_relative_path);
-
-void nautilus_bonobo_register_activation_shortcut (const char *iid,
- NautilusBonoboCreateObject create_object_callback,
- gpointer callback_data);
-void nautilus_bonobo_unregister_activation_shortcut (const char *iid);
-NautilusBonoboActivationHandle *nautilus_bonobo_activate_from_id (const char *iid,
- NautilusBonoboActivationCallback callback,
- gpointer callback_data);
-void nautilus_bonobo_activate_cancel (NautilusBonoboActivationHandle *handle);
-
-Bonobo_RegistrationResult nautilus_bonobo_activation_register_for_display (const char *iid,
- Bonobo_Unknown ref);
+(const char *command);
+void nautilus_bonobo_add_submenu (BonoboUIComponent *ui,
+ const char *container_path,
+ const char *label,
+ GdkPixbuf *pixbuf);
+void nautilus_bonobo_add_menu_separator (BonoboUIComponent *ui,
+ const char *path);
+void nautilus_bonobo_remove_menu_items_and_commands (BonoboUIComponent *ui,
+ const char *container_path);
+void nautilus_bonobo_set_label_for_toolitem_and_command (BonoboUIComponent *ui,
+ const char *toolitem_path,
+ const char *command_path,
+ const char *label_with_underscore);
+void nautilus_bonobo_set_icon (BonoboUIComponent *ui,
+ const char *path,
+ const char *icon_relative_path);
+void nautilus_bonobo_add_extension_item_command (BonoboUIComponent *ui,
+ NautilusMenuItem *item);
+void nautilus_bonobo_add_extension_item (BonoboUIComponent *ui,
+ const char *path,
+ NautilusMenuItem *item);
+void nautilus_bonobo_add_extension_toolbar_item (BonoboUIComponent *ui,
+ const char *path,
+ NautilusMenuItem *item);
+void nautilus_bonobo_register_activation_shortcut (const char *iid,
+ NautilusBonoboCreateObject create_object_callback,
+ gpointer callback_data);
+void nautilus_bonobo_unregister_activation_shortcut (const char *iid);
+NautilusBonoboActivationHandle *nautilus_bonobo_activate_from_id (const char *iid,
+ NautilusBonoboActivationCallback callback,
+ gpointer callback_data);
+void nautilus_bonobo_activate_cancel (NautilusBonoboActivationHandle *handle);
+Bonobo_RegistrationResult nautilus_bonobo_activation_register_for_display (const char *iid,
+ Bonobo_Unknown ref);
+
+
#endif /* NAUTILUS_BONOBO_EXTENSIONS_H */
diff --git a/libnautilus-private/nautilus-column-chooser.c b/libnautilus-private/nautilus-column-chooser.c
new file mode 100644
index 000000000..74f0ee3e3
--- /dev/null
+++ b/libnautilus-private/nautilus-column-chooser.c
@@ -0,0 +1,652 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* nautilus-column-chooser.h - A column chooser widget
+
+ Copyright (C) 2004 Novell, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the column COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: Dave Camp <dave@ximian.com>
+*/
+
+#include <config.h>
+#include "nautilus-column-chooser.h"
+
+#include <string.h>
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-gtk-macros.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkcellrenderertoggle.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkhseparator.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkvbox.h>
+#include <libgnome/gnome-i18n.h>
+
+#include "nautilus-column-utilities.h"
+
+struct _NautilusColumnChooserDetails
+{
+ GtkTreeView *view;
+ GtkListStore *store;
+
+ GtkWidget *move_up_button;
+ GtkWidget *move_down_button;
+ GtkWidget *show_button;
+ GtkWidget *hide_button;
+ GtkWidget *use_default_button;
+};
+
+enum {
+ COLUMN_VISIBLE,
+ COLUMN_LABEL,
+ COLUMN_NAME,
+ NUM_COLUMNS
+};
+
+enum {
+ CHANGED,
+ USE_DEFAULT,
+ LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL];
+
+static void nautilus_column_chooser_class_init (NautilusColumnChooserClass *chooser_class);
+static void nautilus_column_chooser_init (NautilusColumnChooser *chooser);
+static void nautilus_column_chooser_destroy (GtkObject *object);
+static void nautilus_column_chooser_finalize (GObject *object);
+
+EEL_CLASS_BOILERPLATE (NautilusColumnChooser, nautilus_column_chooser, GTK_TYPE_HBOX);
+
+static void
+nautilus_column_chooser_class_init (NautilusColumnChooserClass *chooser_class)
+{
+ G_OBJECT_CLASS (chooser_class)->finalize = nautilus_column_chooser_finalize;
+ GTK_OBJECT_CLASS (chooser_class)->destroy = nautilus_column_chooser_destroy;
+
+ signals[CHANGED] = g_signal_new
+ ("changed",
+ G_TYPE_FROM_CLASS (chooser_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (NautilusColumnChooserClass,
+ changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[USE_DEFAULT] = g_signal_new
+ ("use_default",
+ G_TYPE_FROM_CLASS (chooser_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (NautilusColumnChooserClass,
+ use_default),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private (chooser_class, sizeof (NautilusColumnChooserDetails));
+}
+
+static void
+update_buttons (NautilusColumnChooser *chooser)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (chooser->details->view);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ gboolean visible;
+ gboolean top;
+ gboolean bottom;
+ GtkTreePath *first;
+ GtkTreePath *path;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store),
+ &iter,
+ COLUMN_VISIBLE, &visible,
+ -1);
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (chooser->details->store),
+ &iter);
+ first = gtk_tree_path_new_first ();
+
+ top = (gtk_tree_path_compare (path, first) == 0);
+
+ gtk_tree_path_free (path);
+ gtk_tree_path_free (first);
+
+ bottom = !gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store),
+ &iter);
+
+ gtk_widget_set_sensitive (chooser->details->move_up_button,
+ !top);
+ gtk_widget_set_sensitive (chooser->details->move_down_button,
+ !bottom);
+ gtk_widget_set_sensitive (chooser->details->show_button,
+ !visible);
+ gtk_widget_set_sensitive (chooser->details->hide_button,
+ visible);
+ } else {
+ gtk_widget_set_sensitive (chooser->details->move_up_button,
+ FALSE);
+ gtk_widget_set_sensitive (chooser->details->move_down_button,
+ FALSE);
+ gtk_widget_set_sensitive (chooser->details->show_button,
+ FALSE);
+ gtk_widget_set_sensitive (chooser->details->hide_button,
+ FALSE);
+ }
+}
+
+static void
+list_changed (NautilusColumnChooser *chooser)
+{
+ update_buttons (chooser);
+ g_signal_emit (chooser, signals[CHANGED], 0);
+}
+
+static void
+visible_toggled_callback (GtkCellRendererToggle *cell,
+ char *path_string,
+ gpointer user_data)
+{
+ NautilusColumnChooser *chooser;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean visible;
+
+ chooser = NAUTILUS_COLUMN_CHOOSER (user_data);
+
+ path = gtk_tree_path_new_from_string (path_string);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->details->store),
+ &iter, path);
+ gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store),
+ &iter, COLUMN_VISIBLE, &visible, -1);
+ gtk_list_store_set (chooser->details->store,
+ &iter, COLUMN_VISIBLE, !visible, -1);
+ gtk_tree_path_free (path);
+ list_changed (chooser);
+}
+
+static void
+selection_changed_callback (GtkTreeSelection *selection, gpointer user_data)
+{
+ update_buttons (NAUTILUS_COLUMN_CHOOSER (user_data));
+}
+
+static void
+row_deleted_callback (GtkTreeModel *model,
+ GtkTreePath *path,
+ gpointer user_data)
+{
+ list_changed (NAUTILUS_COLUMN_CHOOSER (user_data));
+}
+
+static void
+add_tree_view (NautilusColumnChooser *chooser)
+{
+ GtkWidget *scrolled;
+ GtkWidget *view;
+ GtkListStore *store;
+ GtkCellRenderer *cell;
+ GtkTreeSelection *selection;
+
+ view = gtk_tree_view_new ();
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
+
+ store = gtk_list_store_new (NUM_COLUMNS,
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (view),
+ GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+ gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), TRUE);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (selection_changed_callback), chooser);
+
+ cell = gtk_cell_renderer_toggle_new ();
+
+ g_signal_connect (G_OBJECT (cell), "toggled",
+ G_CALLBACK (visible_toggled_callback), chooser);
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
+ -1, NULL,
+ cell,
+ "active", COLUMN_VISIBLE,
+ NULL);
+
+ cell = gtk_cell_renderer_text_new ();
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
+ -1, NULL,
+ cell,
+ "text", COLUMN_LABEL,
+ NULL);
+
+ chooser->details->view = GTK_TREE_VIEW (view);
+ chooser->details->store = store;
+
+ gtk_widget_show (view);
+
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
+ GTK_SHADOW_IN);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_show (GTK_WIDGET (scrolled));
+
+ gtk_container_add (GTK_CONTAINER (scrolled), view);
+ gtk_box_pack_start (GTK_BOX (chooser), scrolled, TRUE, TRUE, 0);
+}
+
+static void
+set_selection_visible (NautilusColumnChooser *chooser, gboolean visible)
+{
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (chooser->details->view);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ gtk_list_store_set (chooser->details->store,
+ &iter,
+ COLUMN_VISIBLE, visible,
+ -1);
+ }
+
+ list_changed (chooser);
+}
+
+static void
+move_up_clicked_callback (GtkWidget *button, gpointer user_data)
+{
+ NautilusColumnChooser *chooser;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ chooser = NAUTILUS_COLUMN_CHOOSER (user_data);
+
+ selection = gtk_tree_view_get_selection (chooser->details->view);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ GtkTreePath *path;
+ GtkTreeIter prev;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (chooser->details->store), &iter);
+ gtk_tree_path_prev (path);
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->details->store), &prev, path)) {
+ gtk_list_store_move_before (chooser->details->store,
+ &iter,
+ &prev);
+ }
+ gtk_tree_path_free (path);
+ }
+
+ list_changed (chooser);
+}
+
+static void
+move_down_clicked_callback (GtkWidget *button, gpointer user_data)
+{
+ NautilusColumnChooser *chooser;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ chooser = NAUTILUS_COLUMN_CHOOSER (user_data);
+
+ selection = gtk_tree_view_get_selection (chooser->details->view);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ GtkTreeIter next;
+
+ next = iter;
+
+ if (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), &next)) {
+ gtk_list_store_move_after (chooser->details->store,
+ &iter,
+ &next);
+ }
+ }
+
+ list_changed (chooser);
+}
+
+static void
+show_clicked_callback (GtkWidget *button, gpointer user_data)
+{
+ set_selection_visible (NAUTILUS_COLUMN_CHOOSER (user_data), TRUE);
+}
+
+static void
+hide_clicked_callback (GtkWidget *button, gpointer user_data)
+{
+ set_selection_visible (NAUTILUS_COLUMN_CHOOSER (user_data), FALSE);
+}
+
+static void
+use_default_clicked_callback (GtkWidget *button, gpointer user_data)
+{
+ g_signal_emit (NAUTILUS_COLUMN_CHOOSER (user_data),
+ signals[USE_DEFAULT], 0);
+}
+
+static void
+add_buttons (NautilusColumnChooser *chooser)
+{
+ GtkWidget *box;
+ GtkWidget *separator;
+
+ box = gtk_vbox_new (FALSE, 8);
+ gtk_widget_show (box);
+
+ chooser->details->move_up_button = gtk_button_new_with_mnemonic ("Move _Up");
+ g_signal_connect (chooser->details->move_up_button,
+ "clicked", G_CALLBACK (move_up_clicked_callback),
+ chooser);
+ gtk_widget_show (chooser->details->move_up_button);
+ gtk_widget_set_sensitive (chooser->details->move_up_button, FALSE);
+ gtk_box_pack_start (GTK_BOX (box), chooser->details->move_up_button,
+ FALSE, FALSE, 0);
+
+ chooser->details->move_down_button = gtk_button_new_with_mnemonic ("Move _Down");
+ g_signal_connect (chooser->details->move_down_button,
+ "clicked", G_CALLBACK (move_down_clicked_callback),
+ chooser);
+ gtk_widget_show (chooser->details->move_down_button);
+ gtk_widget_set_sensitive (chooser->details->move_down_button, FALSE);
+ gtk_box_pack_start (GTK_BOX (box), chooser->details->move_down_button,
+ FALSE, FALSE, 0);
+
+ chooser->details->show_button = gtk_button_new_with_mnemonic ("_Show");
+ g_signal_connect (chooser->details->show_button,
+ "clicked", G_CALLBACK (show_clicked_callback),
+ chooser);
+
+ gtk_widget_set_sensitive (chooser->details->show_button, FALSE);
+ gtk_widget_show (chooser->details->show_button);
+ gtk_box_pack_start (GTK_BOX (box), chooser->details->show_button,
+ FALSE, FALSE, 0);
+
+ chooser->details->hide_button = gtk_button_new_with_mnemonic ("_Hide");
+ g_signal_connect (chooser->details->hide_button,
+ "clicked", G_CALLBACK (hide_clicked_callback),
+ chooser);
+ gtk_widget_set_sensitive (chooser->details->hide_button, FALSE);
+ gtk_widget_show (chooser->details->hide_button);
+ gtk_box_pack_start (GTK_BOX (box), chooser->details->hide_button,
+ FALSE, FALSE, 0);
+
+ separator = gtk_hseparator_new ();
+ gtk_widget_show (separator);
+ gtk_box_pack_start (GTK_BOX (box), separator, FALSE, FALSE, 0);
+
+ chooser->details->use_default_button = gtk_button_new_with_mnemonic ("_Use Default");
+ g_signal_connect (chooser->details->use_default_button,
+ "clicked", G_CALLBACK (use_default_clicked_callback),
+ chooser);
+ gtk_widget_show (chooser->details->use_default_button);
+ gtk_box_pack_start (GTK_BOX (box), chooser->details->use_default_button,
+ FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (chooser), box,
+ FALSE, FALSE, 0);
+}
+
+static void
+populate_tree (NautilusColumnChooser *chooser)
+{
+ GList *columns;
+ GList *l;
+
+ columns = nautilus_get_all_columns ();
+
+ for (l = columns; l != NULL; l = l->next) {
+ GtkTreeIter iter;
+ NautilusColumn *column;
+ char *name;
+ char *label;
+
+ column = NAUTILUS_COLUMN (l->data);
+
+ g_object_get (G_OBJECT (column),
+ "name", &name, "label", &label,
+ NULL);
+
+ gtk_list_store_append (chooser->details->store, &iter);
+ gtk_list_store_set (chooser->details->store, &iter,
+ COLUMN_VISIBLE, FALSE,
+ COLUMN_LABEL, label,
+ COLUMN_NAME, name,
+ -1);
+
+ g_free (name);
+ g_free (label);
+ }
+
+ nautilus_column_list_free (columns);
+}
+
+static void
+nautilus_column_chooser_init (NautilusColumnChooser *chooser)
+{
+ chooser->details = G_TYPE_INSTANCE_GET_PRIVATE ((chooser), NAUTILUS_TYPE_COLUMN_CHOOSER, NautilusColumnChooserDetails);
+
+ g_object_set (G_OBJECT (chooser),
+ "homogeneous", FALSE,
+ "spacing", 8,
+ NULL);
+
+ add_tree_view (chooser);
+ add_buttons (chooser);
+
+ populate_tree (chooser);
+
+ g_signal_connect (chooser->details->store, "row_deleted",
+ G_CALLBACK (row_deleted_callback), chooser);
+}
+
+static void
+nautilus_column_chooser_destroy (GtkObject *object)
+{
+ NautilusColumnChooser *chooser;
+
+ chooser = NAUTILUS_COLUMN_CHOOSER (object);
+}
+
+static void
+nautilus_column_chooser_finalize (GObject *object)
+{
+}
+
+static void
+set_visible_columns (NautilusColumnChooser *chooser,
+ GList *visible_columns)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->details->store),
+ &iter)) {
+ do {
+ char *name;
+ gboolean visible;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store),
+ &iter,
+ COLUMN_NAME, &name,
+ -1);
+
+ visible = (eel_g_str_list_index (visible_columns, name) != -1);
+
+ gtk_list_store_set (chooser->details->store,
+ &iter,
+ COLUMN_VISIBLE, visible,
+ -1);
+ g_free (name);
+
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), &iter));
+ }
+}
+
+static GList *
+get_column_names (NautilusColumnChooser *chooser, gboolean only_visible)
+{
+
+ GList *ret;
+ GtkTreeIter iter;
+
+ ret = NULL;
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->details->store),
+ &iter)) {
+ do {
+ char *name;
+ gboolean visible;
+ gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store),
+ &iter,
+ COLUMN_VISIBLE, &visible,
+ COLUMN_NAME, &name,
+ -1);
+ if (!only_visible || visible) {
+ /* give ownership to the list */
+ ret = g_list_prepend (ret, name);
+ }
+
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), &iter));
+ }
+
+ return g_list_reverse (ret);
+}
+
+static gboolean
+get_column_iter (NautilusColumnChooser *chooser,
+ NautilusColumn *column,
+ GtkTreeIter *iter)
+{
+ char *column_name;
+
+ g_object_get (NAUTILUS_COLUMN (column), "name", &column_name, NULL);
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->details->store),
+ iter)) {
+ do {
+ char *name;
+
+
+ gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store),
+ iter,
+ COLUMN_NAME, &name,
+ -1);
+ if (!strcmp (name, column_name)) {
+ g_free (column_name);
+ g_free (name);
+ return TRUE;
+ }
+
+ g_free (name);
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), iter));
+ }
+ g_free (column_name);
+ return FALSE;
+}
+
+static void
+set_column_order (NautilusColumnChooser *chooser,
+ GList *column_order)
+
+{
+ GList *columns;
+ GList *l;
+ GtkTreePath *path;
+
+ columns = nautilus_get_all_columns ();
+ columns = nautilus_sort_columns (columns, column_order);
+
+ g_signal_handlers_block_by_func (chooser->details->store,
+ G_CALLBACK (row_deleted_callback),
+ chooser);
+
+ path = gtk_tree_path_new_first ();
+ for (l = columns; l != NULL; l = l->next) {
+ GtkTreeIter iter;
+
+ if (get_column_iter (chooser, NAUTILUS_COLUMN (l->data), &iter)) {
+ GtkTreeIter before;
+ if (path) {
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->details->store),
+ &before, path);
+ gtk_list_store_move_after (chooser->details->store,
+ &iter, &before);
+ gtk_tree_path_next (path);
+
+ } else {
+ gtk_list_store_move_after (chooser->details->store,
+ &iter, NULL);
+ }
+ }
+ }
+ gtk_tree_path_free (path);
+ g_signal_handlers_unblock_by_func (chooser->details->store,
+ G_CALLBACK (row_deleted_callback),
+ chooser);
+
+ nautilus_column_list_free (columns);
+}
+
+void
+nautilus_column_chooser_set_settings (NautilusColumnChooser *chooser,
+ GList *visible_columns,
+ GList *column_order)
+{
+ g_return_if_fail (NAUTILUS_IS_COLUMN_CHOOSER (chooser));
+ g_return_if_fail (visible_columns != NULL);
+ g_return_if_fail (column_order != NULL);
+
+ set_visible_columns (chooser, visible_columns);
+ set_column_order (chooser, column_order);
+
+ list_changed (chooser);
+}
+
+void
+nautilus_column_chooser_get_settings (NautilusColumnChooser *chooser,
+ GList **visible_columns,
+ GList **column_order)
+{
+ g_return_if_fail (NAUTILUS_IS_COLUMN_CHOOSER (chooser));
+ g_return_if_fail (visible_columns != NULL);
+ g_return_if_fail (column_order != NULL);
+
+ *visible_columns = get_column_names (chooser, TRUE);
+ *column_order = get_column_names (chooser, FALSE);
+}
+
+GtkWidget *
+nautilus_column_chooser_new (void)
+{
+ return g_object_new (NAUTILUS_TYPE_COLUMN_CHOOSER, NULL);
+}
+
+
+
diff --git a/libnautilus-private/nautilus-column-chooser.h b/libnautilus-private/nautilus-column-chooser.h
new file mode 100644
index 000000000..677f15280
--- /dev/null
+++ b/libnautilus-private/nautilus-column-chooser.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* nautilus-column-choose.h - A column chooser widget
+
+ Copyright (C) 2004 Novell, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the column COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: Dave Camp <dave@ximian.com>
+*/
+
+#ifndef NAUTILUS_COLUMN_CHOOSER_H
+#define NAUTILUS_COLUMN_CHOOSER_H
+
+#include <gtk/gtkhbox.h>
+
+#define NAUTILUS_TYPE_COLUMN_CHOOSER (nautilus_column_chooser_get_type ())
+#define NAUTILUS_COLUMN_CHOOSER(obj) (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_COLUMN_CHOOSER, NautilusColumnChooser))
+#define NAUTILUS_COLUMN_CHOOSER_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_COLUMN_CHOOSER, NautilusColumnChooserClass))
+#define NAUTILUS_IS_COLUMN_CHOOSER(obj) (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_COLUMN_CHOOSER))
+#define NAUTILUS_IS_COLUMN_CHOOSER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_COLUMN_CHOOSER))
+
+typedef struct _NautilusColumnChooserDetails NautilusColumnChooserDetails;
+
+typedef struct {
+ GtkHBox parent;
+
+ NautilusColumnChooserDetails *details;
+} NautilusColumnChooser;
+
+typedef struct {
+ GtkHBoxClass parent_slot;
+
+ void (*changed) (NautilusColumnChooser *chooser);
+ void (*use_default) (NautilusColumnChooser *chooser);
+} NautilusColumnChooserClass;
+
+GType nautilus_column_chooser_get_type (void);
+GtkWidget *nautilus_column_chooser_new (void);
+void nautilus_column_chooser_set_settings (NautilusColumnChooser *chooser,
+ GList *visible_columns,
+ GList *column_order);
+void nautilus_column_chooser_get_settings (NautilusColumnChooser *chooser,
+ GList **visible_columns,
+ GList **column_order);
+
+
+#endif /* NAUTILUS_COLUMN_CHOOSER_H */
diff --git a/libnautilus-private/nautilus-column-utilities.c b/libnautilus-private/nautilus-column-utilities.c
new file mode 100644
index 000000000..a233db721
--- /dev/null
+++ b/libnautilus-private/nautilus-column-utilities.c
@@ -0,0 +1,228 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* nautilus-column-utilities.h - Utilities related to column specifications
+
+ Copyright (C) 2004 Novell, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the column COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: Dave Camp <dave@ximian.com>
+*/
+
+#include <config.h>
+#include "nautilus-column-utilities.h"
+
+#include <string.h>
+#include <eel/eel-glib-extensions.h>
+#include <libgnome/gnome-i18n.h>
+#include <libnautilus-extension/nautilus-column-provider.h>
+#include <libnautilus-private/nautilus-module.h>
+
+static GList *
+get_builtin_columns (void)
+{
+ GList *columns;
+
+ columns = g_list_append (NULL,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "name",
+ "attribute", "name",
+ "label", _("Name"),
+ "description", _("The name and icon of the file."),
+ NULL));
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "size",
+ "attribute", "size",
+ "label", _("Size"),
+ "description", _("The size of the file."),
+ "xalign", 1.0,
+ NULL));
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "type",
+ "attribute", "type",
+ "label", _("Type"),
+ "description", _("The type of the file."),
+ NULL));
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "date_modified",
+ "attribute", "date_modified",
+ "label", _("Date Modified"),
+ "description", _("The date the file was modified."),
+ NULL));
+
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "date_accessed",
+ "attribute", "date_accessed",
+ "label", _("Date Accessed"),
+ "description", _("The date the file was accessed."),
+ NULL));
+
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "owner",
+ "attribute", "owner",
+ "label", _("Owner"),
+ "description", _("The owner of the file."),
+ NULL));
+
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "group",
+ "attribute", "group",
+ "label", _("Group"),
+ "description", _("The group of the file."),
+ NULL));
+
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "permissions",
+ "attribute", "permissions",
+ "label", _("Permissions"),
+ "description", _("The permissions of the file."),
+ NULL));
+
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "octal_permissions",
+ "attribute", "octal_permissions",
+ "label", _("Octal Permissions"),
+ "description", _("The permissions of the file, in octal notation."),
+ NULL));
+
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "mime_type",
+ "attribute", "mime_type",
+ "label", _("MIME Type"),
+ "description", _("The mime type of the file."),
+ NULL));
+ return columns;
+}
+
+static GList *
+get_extension_columns (void)
+{
+ GList *columns;
+ GList *providers;
+ GList *l;
+
+ providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_COLUMN_PROVIDER);
+
+ columns = NULL;
+
+ for (l = providers; l != NULL; l = l->next) {
+ NautilusColumnProvider *provider;
+ GList *provider_columns;
+
+ provider = NAUTILUS_COLUMN_PROVIDER (l->data);
+ provider_columns = nautilus_column_provider_get_columns (provider);
+ columns = g_list_concat (columns, provider_columns);
+ }
+
+ nautilus_module_extension_list_free (providers);
+
+ return columns;
+}
+
+GList *
+nautilus_get_all_columns (void)
+{
+ static GList *columns = NULL;
+
+ if (!columns) {
+ columns = g_list_concat (get_builtin_columns (),
+ get_extension_columns ());
+ }
+
+ return nautilus_column_list_copy (columns);
+}
+
+GList *
+nautilus_column_list_copy (GList *columns)
+{
+ GList *ret;
+ GList *l;
+
+ ret = g_list_copy (columns);
+
+ for (l = ret; l != NULL; l = l->next) {
+ g_object_ref (l->data);
+ }
+
+ return ret;
+}
+
+void
+nautilus_column_list_free (GList *columns)
+{
+ GList *l;
+
+ for (l = columns; l != NULL; l = l->next) {
+ g_object_unref (l->data);
+ }
+
+ g_list_free (columns);
+}
+
+static int
+column_compare (NautilusColumn *a, NautilusColumn *b, GList *column_order)
+{
+ int index_a;
+ int index_b;
+ char *name;
+
+ g_object_get (G_OBJECT (a), "name", &name, NULL);
+ index_a = eel_g_str_list_index (column_order, name);
+ g_free (name);
+
+ g_object_get (G_OBJECT (b), "name", &name, NULL);
+ index_b = eel_g_str_list_index (column_order, name);
+ g_free (name);
+
+ if (index_a == index_b) {
+ int ret;
+ char *label_a;
+ char *label_b;
+
+ g_object_get (G_OBJECT (a), "label", &label_a, NULL);
+ g_object_get (G_OBJECT (b), "label", &label_b, NULL);
+ ret = strcmp (label_a, label_b);
+ g_free (a);
+ g_free (b);
+
+ return ret;
+ } else if (index_a == -1) {
+ return 1;
+ } else if (index_b == -1) {
+ return -1;
+ } else {
+ return index_a - index_b;
+ }
+}
+
+GList *
+nautilus_sort_columns (GList *columns,
+ GList *column_order)
+{
+ return g_list_sort_with_data (columns,
+ (GCompareDataFunc)column_compare,
+ column_order);
+}
+
diff --git a/libnautilus-private/nautilus-column-utilities.h b/libnautilus-private/nautilus-column-utilities.h
new file mode 100644
index 000000000..48611db6c
--- /dev/null
+++ b/libnautilus-private/nautilus-column-utilities.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* nautilus-column-utilities.h - Utilities related to column specifications
+
+ Copyright (C) 2004 Novell, Inc.
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the column COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: Dave Camp <dave@ximian.com>
+*/
+
+#ifndef NAUTILUS_COLUMN_UTILITIES_H
+#define NAUTILUS_COLUMN_UTILITIES_H
+
+#include <libnautilus-extension/nautilus-column.h>
+
+GList *nautilus_get_all_columns (void);
+GList *nautilus_column_list_copy (GList *columns);
+void nautilus_column_list_free (GList *columns);
+
+GList *nautilus_sort_columns (GList *columns,
+ GList *column_order);
+
+
+#endif /* NAUTILUS_COLUMN_UTILITIES_H */
diff --git a/libnautilus-private/nautilus-directory-async.c b/libnautilus-private/nautilus-directory-async.c
index 343dd4db3..ab6394dd7 100644
--- a/libnautilus-private/nautilus-directory-async.c
+++ b/libnautilus-private/nautilus-directory-async.c
@@ -32,6 +32,7 @@
#include "nautilus-file-utilities.h"
#include "nautilus-global-preferences.h"
#include "nautilus-link.h"
+#include "nautilus-marshal.h"
#include "nautilus-metafile.h"
#include "nautilus-search-uri.h"
#include <eel/eel-glib-extensions.h>
@@ -94,6 +95,13 @@ typedef struct {
Request request;
} Monitor;
+typedef struct {
+ NautilusDirectory *directory;
+ NautilusInfoProvider *provider;
+ NautilusOperationHandle *handle;
+ NautilusOperationResult result;
+} InfoProviderResponse;
+
typedef gboolean (* RequestCheck) (const Request *);
typedef gboolean (* FileCheck) (NautilusFile *);
@@ -127,8 +135,12 @@ static gboolean file_needs_high_priority_work_done (NautilusDirectory *directory
NautilusFile *file);
static gboolean file_needs_low_priority_work_done (NautilusDirectory *directory,
NautilusFile *file);
+static gboolean file_needs_extension_work_done (NautilusDirectory *directory,
+ NautilusFile *file);
static void move_file_to_low_priority_queue (NautilusDirectory *directory,
NautilusFile *file);
+static void move_file_to_extension_queue (NautilusDirectory *directory,
+ NautilusFile *file);
void
@@ -571,6 +583,8 @@ nautilus_directory_set_up_request (Request *request,
request->metafile |= (file_attributes &
NAUTILUS_FILE_ATTRIBUTE_METADATA) != FALSE;
+
+ request->extension_info = (file_attributes & NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO) != FALSE;
}
static void
@@ -1748,6 +1762,17 @@ wants_link_info (const Request *request)
return request->link_info;
}
+static gboolean
+lacks_extension_info (NautilusFile *file)
+{
+ return file->details->pending_info_providers != NULL;
+}
+
+static gboolean
+wants_extension_info (const Request *request)
+{
+ return request->extension_info;
+}
static gboolean
has_problem (NautilusDirectory *directory, NautilusFile *file, FileCheck problem)
@@ -3136,6 +3161,153 @@ link_info_start (NautilusDirectory *directory,
}
static void
+extension_info_cancel (NautilusDirectory *directory)
+{
+ if (directory->details->extension_info_in_progress != NULL) {
+ nautilus_info_provider_cancel_update
+ (directory->details->extension_info_provider,
+ directory->details->extension_info_in_progress);
+
+ directory->details->extension_info_in_progress = NULL;
+ directory->details->extension_info_file = NULL;
+ directory->details->extension_info_provider = NULL;
+
+ async_job_end (directory, "extension info");
+ }
+}
+
+static void
+extension_info_stop (NautilusDirectory *directory)
+{
+ if (directory->details->extension_info_in_progress != NULL) {
+ NautilusFile *file;
+
+ file = directory->details->extension_info_file;
+ if (file != NULL) {
+ g_assert (NAUTILUS_IS_FILE (file));
+ g_assert (file->details->directory == directory);
+ if (is_needy (file, lacks_extension_info, wants_extension_info)) {
+ return;
+ }
+ }
+
+ /* The info is not wanted, so stop it. */
+ extension_info_cancel (directory);
+ }
+}
+
+static void
+finish_info_provider (NautilusDirectory *directory,
+ NautilusFile *file,
+ NautilusInfoProvider *provider)
+{
+ file->details->pending_info_providers =
+ g_list_remove (file->details->pending_info_providers,
+ provider);
+ g_object_unref (provider);
+
+ nautilus_directory_async_state_changed (directory);
+
+ if (file->details->pending_info_providers == NULL) {
+ nautilus_file_info_providers_done (file);
+ }
+}
+
+
+static gboolean
+info_provider_idle_callback (gpointer user_data)
+{
+ InfoProviderResponse *response;
+ NautilusDirectory *directory;
+
+ response = user_data;
+ directory = response->directory;
+
+ if (response->handle != directory->details->extension_info_in_progress
+ || response->provider != directory->details->extension_info_provider) {
+ g_warning ("Unexpected plugin response. This probably indicates a bug in a Nautilus extension: handle=%p", response->handle);
+ } else {
+ NautilusFile *file;
+ async_job_end (directory, "extension info");
+
+ file = directory->details->extension_info_file;
+
+ directory->details->extension_info_file = NULL;
+ directory->details->extension_info_provider = NULL;
+ directory->details->extension_info_in_progress = NULL;
+
+ finish_info_provider (directory, file, response->provider);
+ }
+
+ return FALSE;
+}
+
+static void
+info_provider_callback (NautilusInfoProvider *provider,
+ NautilusOperationHandle *handle,
+ NautilusOperationResult result,
+ gpointer user_data)
+{
+ InfoProviderResponse *response;
+
+ response = g_new0 (InfoProviderResponse, 1);
+ response->provider = provider;
+ response->handle = handle;
+ response->result = result;
+ response->directory = NAUTILUS_DIRECTORY (user_data);
+
+ g_idle_add (info_provider_idle_callback, response);
+}
+
+static void
+extension_info_start (NautilusDirectory *directory,
+ NautilusFile *file)
+{
+ NautilusInfoProvider *provider;
+ NautilusOperationResult result;
+ NautilusOperationHandle *handle;
+ GClosure *update_complete;
+
+ if (directory->details->extension_info_in_progress != NULL) {
+ return;
+ }
+
+ if (!is_needy (file, lacks_extension_info, wants_extension_info)) {
+ return;
+ }
+
+ if (!async_job_start (directory, "extension info")) {
+ return;
+ }
+
+ provider = file->details->pending_info_providers->data;
+
+ update_complete = g_cclosure_new (G_CALLBACK (info_provider_callback),
+ directory,
+ NULL);
+ g_closure_set_marshal (update_complete,
+ nautilus_marshal_VOID__POINTER_ENUM);
+
+ result = nautilus_info_provider_update_file_info
+ (provider,
+ NAUTILUS_FILE_INFO (file),
+ update_complete,
+ &handle);
+
+ g_closure_unref (update_complete);
+
+ if (result == NAUTILUS_OPERATION_COMPLETE ||
+ result == NAUTILUS_OPERATION_FAILED) {
+ finish_info_provider (directory, file, provider);
+ async_job_end (directory, "extension info");
+ } else {
+ directory->details->extension_info_in_progress = handle;
+ directory->details->extension_info_provider = provider;
+ directory->details->extension_info_file = file;
+ }
+}
+
+static void
start_or_stop_io (NautilusDirectory *directory)
{
NautilusFile *file;
@@ -3150,6 +3322,7 @@ start_or_stop_io (NautilusDirectory *directory)
mime_list_stop (directory);
top_left_stop (directory);
link_info_stop (directory);
+ extension_info_stop (directory);
/* Take files that are all done off the queue. */
while (!nautilus_file_queue_is_empty (directory->details->high_priority_queue)) {
@@ -3177,6 +3350,20 @@ start_or_stop_io (NautilusDirectory *directory)
top_left_start (directory, file);
return;
} else {
+ move_file_to_extension_queue (directory, file);
+
+ }
+ }
+
+ /* Low priority queue must be empty */
+ while (!nautilus_file_queue_is_empty (directory->details->extension_queue)) {
+ file = nautilus_file_queue_head (directory->details->extension_queue);
+
+ if (file_needs_extension_work_done (directory, file)) {
+ /* Start getting attributes if possible */
+ extension_info_start (directory, file);
+ return;
+ } else {
nautilus_directory_remove_file_from_work_queue (directory, file);
}
@@ -3228,6 +3415,7 @@ nautilus_directory_cancel (NautilusDirectory *directory)
link_info_cancel (directory);
mime_list_cancel (directory);
top_left_cancel (directory);
+ extension_info_cancel (directory);
/* We aren't waiting for anything any more. */
if (waiting_directories != NULL) {
@@ -3322,6 +3510,10 @@ cancel_loading_attributes (NautilusDirectory *directory,
if (request.link_info) {
link_info_cancel (directory);
}
+
+ if (request.extension_info) {
+ extension_info_cancel (directory);
+ }
/* FIXME bugzilla.gnome.org 45064: implement cancelling metadata when we
implement invalidating metadata */
@@ -3407,11 +3599,23 @@ file_needs_low_priority_work_done (NautilusDirectory *directory,
}
static gboolean
+file_needs_extension_work_done (NautilusDirectory *directory,
+ NautilusFile *file)
+{
+ if (is_needy (file, lacks_extension_info, wants_extension_info)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
file_needs_work_done (NautilusDirectory *directory,
NautilusFile *file)
{
return (file_needs_high_priority_work_done (directory, file) ||
- file_needs_low_priority_work_done (directory, file));
+ file_needs_low_priority_work_done (directory, file) ||
+ file_needs_extension_work_done (directory, file));
}
@@ -3451,6 +3655,8 @@ nautilus_directory_remove_file_from_work_queue (NautilusDirectory *directory,
file);
nautilus_file_queue_remove (directory->details->low_priority_queue,
file);
+ nautilus_file_queue_remove (directory->details->extension_queue,
+ file);
}
@@ -3458,15 +3664,32 @@ static void
move_file_to_low_priority_queue (NautilusDirectory *directory,
NautilusFile *file)
{
+ /* Must add before removing to avoid ref underflow */
+ nautilus_file_queue_enqueue (directory->details->low_priority_queue,
+ file);
+ nautilus_file_queue_remove (directory->details->high_priority_queue,
+ file);
+
if (!file_needs_low_priority_work_done (directory, file)) {
- nautilus_file_queue_remove (directory->details->high_priority_queue,
+ move_file_to_extension_queue (directory, file);
+
+ return;
+ }
+}
+
+static void
+move_file_to_extension_queue (NautilusDirectory *directory,
+ NautilusFile *file)
+{
+ if (!file_needs_extension_work_done (directory, file)) {
+ nautilus_file_queue_remove (directory->details->low_priority_queue,
file);
return;
}
/* Must add before removing to avoid ref underflow */
- nautilus_file_queue_enqueue (directory->details->low_priority_queue,
+ nautilus_file_queue_enqueue (directory->details->extension_queue,
file);
- nautilus_file_queue_remove (directory->details->high_priority_queue,
+ nautilus_file_queue_remove (directory->details->low_priority_queue,
file);
}
diff --git a/libnautilus-private/nautilus-directory-private.h b/libnautilus-private/nautilus-directory-private.h
index fc4cd5d72..9dc3bae98 100644
--- a/libnautilus-private/nautilus-directory-private.h
+++ b/libnautilus-private/nautilus-directory-private.h
@@ -33,6 +33,7 @@
#include <libnautilus-private/nautilus-metafile-server.h>
#include <libnautilus-private/nautilus-monitor.h>
#include <libnautilus/nautilus-idle-queue.h>
+#include <libnautilus-extension/nautilus-info-provider.h>
#include <libxml/tree.h>
typedef struct LinkInfoReadState LinkInfoReadState;
@@ -53,6 +54,7 @@ struct NautilusDirectoryDetails
/* Queues of files needing some I/O done. */
NautilusFileQueue *high_priority_queue;
NautilusFileQueue *low_priority_queue;
+ NautilusFileQueue *extension_queue;
/* These lists are going to be pretty short. If we think they
* are going to get big, we can use hash tables instead.
@@ -100,6 +102,10 @@ struct NautilusDirectoryDetails
NautilusFile *get_info_file;
GnomeVFSAsyncHandle *get_info_in_progress;
+ NautilusFile *extension_info_file;
+ NautilusInfoProvider *extension_info_provider;
+ NautilusOperationHandle *extension_info_in_progress;
+
TopLeftTextReadState *top_left_read_state;
LinkInfoReadState *link_info_read_state;
@@ -119,6 +125,7 @@ typedef struct {
gboolean metafile;
gboolean mime_list;
gboolean top_left_text;
+ gboolean extension_info;
} Request;
NautilusDirectory *nautilus_directory_get_existing (const char *uri);
diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c
index 0ee12c3ac..9a8e5913f 100644
--- a/libnautilus-private/nautilus-directory.c
+++ b/libnautilus-private/nautilus-directory.c
@@ -135,6 +135,7 @@ nautilus_directory_init (gpointer object, gpointer klass)
directory->details->file_hash = g_hash_table_new (g_str_hash, g_str_equal);
directory->details->high_priority_queue = nautilus_file_queue_new ();
directory->details->low_priority_queue = nautilus_file_queue_new ();
+ directory->details->extension_queue = nautilus_file_queue_new ();
directory->details->idle_queue = nautilus_idle_queue_new ();
directory->details->hidden_file_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
@@ -209,6 +210,7 @@ nautilus_directory_finalize (GObject *object)
nautilus_file_queue_destroy (directory->details->high_priority_queue);
nautilus_file_queue_destroy (directory->details->low_priority_queue);
+ nautilus_file_queue_destroy (directory->details->extension_queue);
nautilus_idle_queue_destroy (directory->details->idle_queue);
g_assert (directory->details->directory_load_in_progress == NULL);
g_assert (directory->details->count_in_progress == NULL);
@@ -1023,6 +1025,7 @@ nautilus_directory_notify_files_changed (GList *uris)
file->details->file_info_is_up_to_date = FALSE;
file->details->top_left_text_is_up_to_date = FALSE;
file->details->link_info_is_up_to_date = FALSE;
+ nautilus_file_invalidate_extension_info_internal (file);
hash_table_list_prepend (changed_lists,
file->details->directory,
diff --git a/libnautilus-private/nautilus-file-attributes.h b/libnautilus-private/nautilus-file-attributes.h
index 38e1da94f..ba02bd426 100644
--- a/libnautilus-private/nautilus-file-attributes.h
+++ b/libnautilus-private/nautilus-file-attributes.h
@@ -43,6 +43,7 @@ typedef enum {
NAUTILUS_FILE_ATTRIBUTE_TOP_LEFT_TEXT = 1 << 10,
NAUTILUS_FILE_ATTRIBUTE_DISPLAY_NAME = 1 << 11,
NAUTILUS_FILE_ATTRIBUTE_VOLUMES = 1 << 12,
+ NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO = 1 << 13,
} NautilusFileAttributes;
#endif /* NAUTILUS_FILE_ATTRIBUTES_H */
diff --git a/libnautilus-private/nautilus-file-private.h b/libnautilus-private/nautilus-file-private.h
index 36f94e5e6..9f3b1da37 100644
--- a/libnautilus-private/nautilus-file-private.h
+++ b/libnautilus-private/nautilus-file-private.h
@@ -93,7 +93,18 @@ struct NautilusFileDetails
/* We use this to cache automatic emblems and emblem keywords
to speed up compare_by_emblems. */
NautilusFileSortByEmblemCache *compare_by_emblem_cache;
-
+
+ /* NautilusInfoProviders that need to be run for this file */
+ GList *pending_info_providers;
+
+ /* Emblems provided by extensions */
+ GList *extension_emblems;
+ GList *pending_extension_emblems;
+
+ /* Attributes provided by extensions */
+ GHashTable *extension_attributes;
+ GHashTable *pending_extension_attributes;
+
/* boolean fields: bitfield to save space, since there can be
many NautilusFile objects. */
@@ -173,13 +184,15 @@ gboolean nautilus_file_should_get_top_left_text (NautilusFile
/* Mark specified attributes for this file out of date without canceling current
* I/O or kicking off new I/O.
*/
-void nautilus_file_invalidate_attributes_internal (NautilusFile *file,
- NautilusFileAttributes file_attributes);
-NautilusFileAttributes nautilus_file_get_all_attributes (void);
-gboolean nautilus_file_is_self_owned (NautilusFile *file);
-void nautilus_file_invalidate_count_and_mime_list (NautilusFile *file);
-gboolean nautilus_file_rename_in_progress (NautilusFile *file);
-GnomeVFSFileInfo * nautilus_file_peek_vfs_file_info (NautilusFile *file);
+void nautilus_file_invalidate_attributes_internal (NautilusFile *file,
+ NautilusFileAttributes file_attributes);
+NautilusFileAttributes nautilus_file_get_all_attributes (void);
+gboolean nautilus_file_is_self_owned (NautilusFile *file);
+void nautilus_file_invalidate_count_and_mime_list (NautilusFile *file);
+gboolean nautilus_file_rename_in_progress (NautilusFile *file);
+GnomeVFSFileInfo * nautilus_file_peek_vfs_file_info (NautilusFile *file);
+void nautilus_file_invalidate_extension_info_internal (NautilusFile *file);
+void nautilus_file_info_providers_done (NautilusFile *file);
/* Thumbnailing: */
diff --git a/libnautilus-private/nautilus-file.c b/libnautilus-private/nautilus-file.c
index dc6141723..1ea79d4c0 100644
--- a/libnautilus-private/nautilus-file.c
+++ b/libnautilus-private/nautilus-file.c
@@ -39,6 +39,7 @@
#include "nautilus-link.h"
#include "nautilus-link-desktop-file.h"
#include "nautilus-metadata.h"
+#include "nautilus-module.h"
#include "nautilus-thumbnails.h"
#include "nautilus-trash-directory.h"
#include "nautilus-trash-file.h"
@@ -59,6 +60,7 @@
#include <libgnomevfs/gnome-vfs-volume.h>
#include <libgnomevfs/gnome-vfs-volume-monitor.h>
#include <libgnomevfs/gnome-vfs-drive.h>
+#include <libnautilus-extension/nautilus-file-info.h>
#include <libxml/parser.h>
#include <pwd.h>
#include <stdlib.h>
@@ -110,24 +112,62 @@ enum {
static guint signals[LAST_SIGNAL];
-static GHashTable *symbolic_links;
-
-static char * nautilus_file_get_owner_as_string (NautilusFile *file,
- gboolean include_real_name);
-static char * nautilus_file_get_type_as_string (NautilusFile *file);
-static gboolean update_info_and_name (NautilusFile *file,
- GnomeVFSFileInfo *info);
-static char * nautilus_file_get_display_name_nocopy (NautilusFile *file);
-static char * nautilus_file_get_display_name_collation_key (NautilusFile *file);
+static GObjectClass *parent_class = NULL;
+static GHashTable *symbolic_links;
-GNOME_CLASS_BOILERPLATE (NautilusFile, nautilus_file,
- GObject, G_TYPE_OBJECT)
+static void nautilus_file_instance_init (NautilusFile *file);
+static void nautilus_file_class_init (NautilusFileClass *class);
+static void nautilus_file_info_iface_init (NautilusFileInfoIface *iface);
+static char * nautilus_file_get_owner_as_string (NautilusFile *file,
+ gboolean include_real_name);
+static char * nautilus_file_get_type_as_string (NautilusFile *file);
+static gboolean update_info_and_name (NautilusFile *file,
+ GnomeVFSFileInfo *info);
+static char * nautilus_file_get_display_name_nocopy (NautilusFile *file);
+static char * nautilus_file_get_display_name_collation_key (NautilusFile *file);
+
+GType
+nautilus_file_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo info = {
+ sizeof (NautilusFileClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) nautilus_file_class_init,
+ NULL,
+ NULL,
+ sizeof (NautilusFile),
+ 0,
+ (GInstanceInitFunc) nautilus_file_instance_init,
+ };
+
+ static const GInterfaceInfo file_info_iface_info = {
+ (GInterfaceInitFunc) nautilus_file_info_iface_init,
+ NULL,
+ NULL
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "NautilusFile",
+ &info, 0);
+ g_type_add_interface_static (type,
+ NAUTILUS_TYPE_FILE_INFO,
+ &file_info_iface_info);
+ }
+
+ return type;
+}
static void
nautilus_file_instance_init (NautilusFile *file)
{
file->details = G_TYPE_INSTANCE_GET_PRIVATE ((file), NAUTILUS_TYPE_FILE, NautilusFileDetails);
+
+ nautilus_file_invalidate_extension_info_internal (file);
}
static NautilusFile *
@@ -459,10 +499,20 @@ finalize (GObject *object)
eel_g_list_free_deep (file->details->mime_list);
+ eel_g_list_free_deep (file->details->pending_extension_emblems);
+ eel_g_list_free_deep (file->details->extension_emblems);
+
+ if (file->details->pending_extension_attributes) {
+ g_hash_table_destroy (file->details->pending_extension_attributes);
+ }
+
+ if (file->details->extension_attributes) {
+ g_hash_table_destroy (file->details->extension_attributes);
+ }
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-
NautilusFile *
nautilus_file_ref (NautilusFile *file)
{
@@ -2040,16 +2090,27 @@ compare_by_full_path (NautilusFile *file_1, NautilusFile *file_2)
static int
nautilus_file_compare_for_sort_internal (NautilusFile *file_1,
NautilusFile *file_2,
- NautilusFileSortType sort_type)
+ gboolean directories_first)
{
int compare;
GnomeVFSDrive *drive1, *drive2;
GnomeVFSVolume *volume1, *volume2;
- if (file_1 == file_2) {
- return 0;
+ gboolean is_directory_1, is_directory_2;
+
+ if (directories_first) {
+ is_directory_1 = nautilus_file_is_directory (file_1);
+ is_directory_2 = nautilus_file_is_directory (file_2);
+
+ if (is_directory_1 && !is_directory_2) {
+ return -1;
+ }
+
+ if (is_directory_2 && !is_directory_1) {
+ return +1;
+ }
}
-
+
/* Always sort drives/volumes separately: */
if (file_1->details->has_drive != file_2->details->has_drive) {
if (file_1->details->has_drive) {
@@ -2082,53 +2143,8 @@ nautilus_file_compare_for_sort_internal (NautilusFile *file_1,
return compare;
}
}
-
- switch (sort_type) {
- case NAUTILUS_FILE_SORT_BY_DISPLAY_NAME:
- compare = compare_by_display_name (file_1, file_2);
- if (compare != 0) {
- return compare;
- }
- return compare_by_directory_name (file_1, file_2);
- case NAUTILUS_FILE_SORT_BY_DIRECTORY:
- return compare_by_full_path (file_1, file_2);
- case NAUTILUS_FILE_SORT_BY_SIZE:
- /* Compare directory sizes ourselves, then if necessary
- * use GnomeVFS to compare file sizes.
- */
- compare = compare_by_size (file_1, file_2);
- if (compare != 0) {
- return compare;
- }
- return compare_by_full_path (file_1, file_2);
- case NAUTILUS_FILE_SORT_BY_TYPE:
- /* GnomeVFS doesn't know about our special text for certain
- * mime types, so we handle the mime-type sorting ourselves.
- */
- compare = compare_by_type (file_1, file_2);
- if (compare != 0) {
- return compare;
- }
- return compare_by_full_path (file_1, file_2);
- case NAUTILUS_FILE_SORT_BY_MTIME:
- compare = compare_by_modification_time (file_1, file_2);
- if (compare != 0) {
- return compare;
- }
- return compare_by_full_path (file_1, file_2);
- case NAUTILUS_FILE_SORT_BY_EMBLEMS:
- /* GnomeVFS doesn't know squat about our emblems, so
- * we handle comparing them here, before falling back
- * to tie-breakers.
- */
- compare = compare_by_emblems (file_1, file_2);
- if (compare != 0) {
- return compare;
- }
- return compare_by_full_path (file_1, file_2);
- default:
- g_return_val_if_reached (0);
- }
+
+ return 0;
}
/**
@@ -2154,27 +2170,135 @@ nautilus_file_compare_for_sort (NautilusFile *file_1,
gboolean reversed)
{
int result;
- gboolean is_directory_1, is_directory_2;
- if (directories_first) {
- is_directory_1 = nautilus_file_is_directory (file_1);
- is_directory_2 = nautilus_file_is_directory (file_2);
-
- if (is_directory_1 && !is_directory_2) {
- return -1;
+ if (file_1 == file_2) {
+ return 0;
+ }
+
+ result = nautilus_file_compare_for_sort_internal (file_1, file_2, directories_first);
+
+ if (result == 0) {
+ switch (sort_type) {
+ case NAUTILUS_FILE_SORT_BY_DISPLAY_NAME:
+ result = compare_by_display_name (file_1, file_2);
+ if (result == 0) {
+ result = compare_by_directory_name (file_1, file_2);
+ }
+ break;
+ case NAUTILUS_FILE_SORT_BY_DIRECTORY:
+ result = compare_by_full_path (file_1, file_2);
+ break;
+ case NAUTILUS_FILE_SORT_BY_SIZE:
+ /* Compare directory sizes ourselves, then if necessary
+ * use GnomeVFS to compare file sizes.
+ */
+ result = compare_by_size (file_1, file_2);
+ if (result == 0) {
+ result = compare_by_full_path (file_1, file_2);
+ }
+ break;
+ case NAUTILUS_FILE_SORT_BY_TYPE:
+ /* GnomeVFS doesn't know about our special text for certain
+ * mime types, so we handle the mime-type sorting ourselves.
+ */
+ result = compare_by_type (file_1, file_2);
+ if (result == 0) {
+ result = compare_by_full_path (file_1, file_2);
+ }
+ break;
+ case NAUTILUS_FILE_SORT_BY_MTIME:
+ result = compare_by_modification_time (file_1, file_2);
+ if (result == 0) {
+ result = compare_by_full_path (file_1, file_2);
+ }
+ break;
+ case NAUTILUS_FILE_SORT_BY_EMBLEMS:
+ /* GnomeVFS doesn't know squat about our emblems, so
+ * we handle comparing them here, before falling back
+ * to tie-breakers.
+ */
+ result = compare_by_emblems (file_1, file_2);
+ if (result == 0) {
+ result = compare_by_full_path (file_1, file_2);
+ }
+ default:
+ g_return_val_if_reached (0);
}
+ }
- if (is_directory_2 && !is_directory_1) {
- return +1;
- }
+ if (reversed) {
+ result = -result;
}
- result = nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type);
+ return result;
+}
+
+int
+nautilus_file_compare_for_sort_by_attribute (NautilusFile *file_1,
+ NautilusFile *file_2,
+ const char *attribute,
+ gboolean directories_first,
+ gboolean reversed)
+{
+ int result;
+
+ if (file_1 == file_2) {
+ return 0;
+ }
+
+ /* Convert certain attributes into NautilusFileSortTypes and use
+ * nautilus_file_compare_for_sort()
+ */
+ if (attribute == NULL || !strcmp (attribute, "name")) {
+ return nautilus_file_compare_for_sort (file_1, file_2,
+ NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
+ directories_first,
+ reversed);
+ } else if (!strcmp (attribute, "size")) {
+ return nautilus_file_compare_for_sort (file_1, file_2,
+ NAUTILUS_FILE_SORT_BY_SIZE,
+ directories_first,
+ reversed);
+ } else if (!strcmp (attribute, "type")) {
+ return nautilus_file_compare_for_sort (file_1, file_2,
+ NAUTILUS_FILE_SORT_BY_TYPE,
+ directories_first,
+ reversed);
+ } else if (!strcmp (attribute, "modification_date") || !strcmp (attribute, "date_modified")) {
+ return nautilus_file_compare_for_sort (file_1, file_2,
+ NAUTILUS_FILE_SORT_BY_MTIME,
+ directories_first,
+ reversed);
+ } else if (!strcmp (attribute, "emblems")) {
+ return nautilus_file_compare_for_sort (file_1, file_2,
+ NAUTILUS_FILE_SORT_BY_EMBLEMS,
+ directories_first,
+ reversed);
+ }
+
+ /* it is a normal attribute, compare by strings */
+
+ result = nautilus_file_compare_for_sort_internal (file_1, file_2, directories_first);
+
+ if (result == 0) {
+ char *value_1;
+ char *value_2;
+
+ value_1 = nautilus_file_get_string_attribute (file_1,
+ attribute);
+ value_2 = nautilus_file_get_string_attribute (file_2,
+ attribute);
+
+ result = strcmp (value_1, value_2);
+
+ g_free (value_1);
+ g_free (value_2);
+ }
if (reversed) {
result = -result;
}
-
+
return result;
}
@@ -4318,6 +4442,8 @@ nautilus_file_get_deep_directory_count_as_string (NautilusFile *file)
char *
nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_name)
{
+ char *extension_attribute;
+
/* FIXME bugzilla.gnome.org 40646:
* Use hash table and switch statement or function pointers for speed?
*/
@@ -4389,7 +4515,18 @@ nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_na
if (strcmp (attribute_name, "free_space") == 0) {
return nautilus_file_get_volume_free_space (file);
}
- return NULL;
+
+ extension_attribute = NULL;
+
+ if (file->details->pending_extension_attributes) {
+ extension_attribute = g_hash_table_lookup (file->details->pending_extension_attributes, attribute_name);
+ }
+
+ if (extension_attribute == NULL && file->details->extension_attributes) {
+ extension_attribute = g_hash_table_lookup (file->details->extension_attributes, attribute_name);
+ }
+
+ return g_strdup (extension_attribute);
}
/**
@@ -4689,7 +4826,10 @@ nautilus_file_get_keywords (NautilusFile *file)
/* Put all the keywords into a list. */
keywords = nautilus_file_get_metadata_list
(file, "keyword", "name");
-
+
+ keywords = g_list_concat (keywords, eel_g_str_list_copy (file->details->extension_emblems));
+ keywords = g_list_concat (keywords, eel_g_str_list_copy (file->details->pending_extension_emblems));
+
return sort_keyword_list_and_remove_duplicates (keywords);
}
@@ -5274,7 +5414,6 @@ invalidate_directory_count (NautilusFile *file)
file->details->directory_count_is_up_to_date = FALSE;
}
-
static void
invalidate_deep_counts (NautilusFile *file)
{
@@ -5306,6 +5445,19 @@ invalidate_link_info (NautilusFile *file)
}
void
+nautilus_file_invalidate_extension_info_internal (NautilusFile *file)
+{
+ file->details->pending_info_providers =
+ nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_INFO_PROVIDER);
+ if (!file->details->pending_extension_attributes) {
+ file->details->pending_extension_attributes =
+ g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)g_free);
+ }
+}
+
+void
nautilus_file_invalidate_attributes_internal (NautilusFile *file,
NautilusFileAttributes file_attributes)
{
@@ -5343,6 +5495,9 @@ nautilus_file_invalidate_attributes_internal (NautilusFile *file,
if (request.link_info) {
invalidate_link_info (file);
}
+ if (request.extension_info) {
+ nautilus_file_invalidate_extension_info_internal (file);
+ }
/* FIXME bugzilla.gnome.org 45075: implement invalidating metadata */
}
@@ -5633,6 +5788,8 @@ nautilus_extract_top_left_text (const char *text,
static void
nautilus_file_class_init (NautilusFileClass *class)
{
+ parent_class = g_type_class_peek_parent (class);
+
G_OBJECT_CLASS (class)->finalize = finalize;
signals[CHANGED] =
@@ -5656,6 +5813,79 @@ nautilus_file_class_init (NautilusFileClass *class)
g_type_class_add_private (class, sizeof (NautilusFileDetails));
}
+static GnomeVFSFileInfo *
+nautilus_file_get_vfs_file_info (NautilusFile *file)
+{
+ return gnome_vfs_file_info_dup (file->details->info);
+}
+
+static void
+nautilus_file_add_emblem (NautilusFile *file,
+ const char *emblem_name)
+{
+ if (file->details->pending_info_providers) {
+ file->details->pending_extension_emblems = g_list_prepend (file->details->pending_extension_emblems,
+ g_strdup (emblem_name));
+ } else {
+ file->details->extension_emblems = g_list_prepend (file->details->extension_emblems,
+ g_strdup (emblem_name));
+ }
+
+ nautilus_file_changed (file);
+}
+
+static void
+nautilus_file_add_string_attribute (NautilusFile *file,
+ const char *attribute_name,
+ const char *value)
+{
+ if (file->details->pending_info_providers) {
+ g_hash_table_insert (file->details->pending_extension_attributes,
+ g_strdup (attribute_name),
+ g_strdup (value));
+ } else {
+ g_hash_table_insert (file->details->extension_attributes,
+ g_strdup (attribute_name),
+ g_strdup (value));
+ }
+
+ nautilus_file_changed (file);
+}
+
+void
+nautilus_file_info_providers_done (NautilusFile *file)
+{
+ eel_g_list_free_deep (file->details->extension_emblems);
+ file->details->extension_emblems = file->details->pending_extension_emblems;
+ file->details->pending_extension_emblems = NULL;
+
+ if (file->details->extension_attributes) {
+ g_hash_table_destroy (file->details->extension_attributes);
+ }
+
+ file->details->extension_attributes = file->details->pending_extension_attributes;
+ file->details->pending_extension_attributes = NULL;
+
+ nautilus_file_changed (file);
+}
+
+static void
+nautilus_file_info_iface_init (NautilusFileInfoIface *iface)
+{
+ iface->is_gone = nautilus_file_is_gone;
+ iface->get_name = nautilus_file_get_name;
+ iface->get_uri = nautilus_file_get_uri;
+ iface->get_parent_uri = nautilus_file_get_parent_uri;
+ iface->get_uri_scheme = nautilus_file_get_uri_scheme;
+ iface->get_mime_type = nautilus_file_get_mime_type;
+ iface->is_mime_type = nautilus_file_is_mime_type;
+ iface->is_directory = nautilus_file_is_directory;
+ iface->get_vfs_file_info = nautilus_file_get_vfs_file_info;
+ iface->add_emblem = nautilus_file_add_emblem;
+ iface->get_string_attribute = nautilus_file_get_string_attribute;
+ iface->add_string_attribute = nautilus_file_add_string_attribute;
+}
+
#if !defined (NAUTILUS_OMIT_SELF_CHECK)
void
diff --git a/libnautilus-private/nautilus-file.h b/libnautilus-private/nautilus-file.h
index 22971972e..c945fd391 100644
--- a/libnautilus-private/nautilus-file.h
+++ b/libnautilus-private/nautilus-file.h
@@ -286,6 +286,11 @@ int nautilus_file_compare_for_sort (Nautilu
NautilusFileSortType sort_type,
gboolean directories_first,
gboolean reversed);
+int nautilus_file_compare_for_sort_by_attribute (NautilusFile *file_1,
+ NautilusFile *file_2,
+ const char *attribute,
+ gboolean directories_first,
+ gboolean reversed);
int nautilus_file_compare_display_name (NautilusFile *file_1,
const char *pattern);
diff --git a/libnautilus-private/nautilus-global-preferences.c b/libnautilus-private/nautilus-global-preferences.c
index 29fb25dc4..1342ce774 100644
--- a/libnautilus-private/nautilus-global-preferences.c
+++ b/libnautilus-private/nautilus-global-preferences.c
@@ -213,21 +213,6 @@ static EelEnumerationEntry standard_font_size_entries[] = {
{ NULL }
};
-static EelEnumerationEntry icon_captions_enum_entries[] = {
- { "size", N_("size"), 0 },
- { "type", N_("type"), 1 },
- { "date_modified", N_("date modified"), 2 },
- { "date_changed", N_("date changed"), 3 },
- { "date_accessed", N_("date accessed"), 4 },
- { "owner", N_("owner"), 5 },
- { "group", N_("group"), 6 },
- { "permissions", N_("permissions"), 7 },
- { "octal_permissions", N_("octal permissions"), 8 },
- { "mime_type", N_("MIME type"), 9 },
- { "none", N_("none"), 10 },
- { NULL }
-};
-
/* These enumerations are used in the preferences dialog to
* populate widgets and route preferences changes between the
* storage (GConf) and the displayed values.
@@ -240,7 +225,6 @@ static EelEnumerationInfo enumerations[] = {
{ "default_zoom_level", default_zoom_level_enum_entries },
{ "executable_text_activation", executable_text_activation_enum_entries },
{ "file_size", file_size_enum_entries },
- { "icon_captions", icon_captions_enum_entries },
{ "search_bar_type", search_bar_type_enum_entries },
{ "speed_tradeoff", speed_tradeoff_enum_entries },
{ "standard_font_size", standard_font_size_entries },
diff --git a/libnautilus-private/nautilus-global-preferences.h b/libnautilus-private/nautilus-global-preferences.h
index 176f01ce3..754b1d4f5 100644
--- a/libnautilus-private/nautilus-global-preferences.h
+++ b/libnautilus-private/nautilus-global-preferences.h
@@ -123,6 +123,8 @@ enum
#define NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_SORT_IN_REVERSE_ORDER "list_view/default_sort_in_reverse_order"
#define NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_SORT_ORDER "list_view/default_sort_order"
#define NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL "list_view/default_zoom_level"
+#define NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS "list_view/default_visible_columns"
+#define NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER "list_view/default_column_order"
/* News panel */
#define NAUTILUS_PREFERENCES_NEWS_MAX_ITEMS "news/max_items"
diff --git a/libnautilus-private/nautilus-marshal.list b/libnautilus-private/nautilus-marshal.list
index c0d617827..3261b785f 100644
--- a/libnautilus-private/nautilus-marshal.list
+++ b/libnautilus-private/nautilus-marshal.list
@@ -13,3 +13,4 @@ VOID:POINTER,STRING
VOID:STRING,STRING
VOID:POINTER,POINTER,POINTER,INT,INT,INT
VOID:POINTER,STRING,UINT,INT,INT
+VOID:POINTER,ENUM
diff --git a/libnautilus-private/nautilus-metadata.h b/libnautilus-private/nautilus-metadata.h
index 06a4014a7..710d82c0f 100644
--- a/libnautilus-private/nautilus-metadata.h
+++ b/libnautilus-private/nautilus-metadata.h
@@ -58,6 +58,9 @@
#define NAUTILUS_METADATA_KEY_LIST_VIEW_ZOOM_LEVEL "list_view_zoom_level"
#define NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN "list_view_sort_column"
#define NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED "list_view_sort_reversed"
+#define NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS "list_view_visible_columns"
+#define NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER "list_view_column_order"
+#define NAUTILUS_METADATA_SUBKEY_COLUMNS "columns"
#define NAUTILUS_METADATA_KEY_WINDOW_GEOMETRY "window_geometry"
#define NAUTILUS_METADATA_KEY_WINDOW_SCROLL_POSITION "window_scroll_position"
diff --git a/libnautilus-private/nautilus-module.c b/libnautilus-private/nautilus-module.c
new file mode 100644
index 000000000..0edd200c2
--- /dev/null
+++ b/libnautilus-private/nautilus-module.c
@@ -0,0 +1,258 @@
+/*
+ * nautilus-module.h - Interface to nautilus extensions
+ *
+ * Copyright (C) 2003 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Dave Camp <dave@ximian.com>
+ *
+ */
+
+#include <config.h>
+#include "nautilus-module.h"
+
+#include <eel/eel-gtk-macros.h>
+#include <gmodule.h>
+#include <libgnome/gnome-macros.h>
+
+#define NAUTILUS_TYPE_MODULE (nautilus_module_get_type ())
+#define NAUTILUS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_MODULE, NautilusModule))
+#define NAUTILUS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_MODULE, NautilusModule))
+#define NAUTILUS_IS_MODULE(obj) (G_TYPE_INSTANCE_CHECK_TYPE ((obj), NAUTILUS_TYPE_MODULE))
+#define NAUTILUS_IS_MODULE_CLASS(klass) (G_TYPE_CLASS_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_MODULE))
+
+typedef struct _NautilusModule NautilusModule;
+typedef struct _NautilusModuleClass NautilusModuleClass;
+
+struct _NautilusModule {
+ GTypeModule parent;
+
+ GModule *library;
+
+ char *path;
+
+ void (*initialize) (GTypeModule *module);
+ void (*shutdown) (void);
+
+ void (*list_types) (const GType **types,
+ int *num_types);
+
+};
+
+struct _NautilusModuleClass {
+ GTypeModuleClass parent;
+};
+
+static GType nautilus_module_get_type (void);
+
+static GList *module_objects = NULL;
+
+GNOME_CLASS_BOILERPLATE (NautilusModule,
+ nautilus_module,
+ GTypeModule,
+ G_TYPE_TYPE_MODULE);
+
+static gboolean
+nautilus_module_load (GTypeModule *gmodule)
+{
+ NautilusModule *module;
+
+ module = NAUTILUS_MODULE (gmodule);
+
+ module->library = g_module_open (module->path, 0);
+
+ if (!module->library) {
+ g_warning (g_module_error ());
+ return FALSE;
+ }
+
+ if (!g_module_symbol (module->library,
+ "nautilus_module_initialize",
+ (gpointer *)&module->initialize) ||
+ !g_module_symbol (module->library,
+ "nautilus_module_shutdown",
+ (gpointer *)&module->shutdown) ||
+ !g_module_symbol (module->library,
+ "nautilus_module_list_types",
+ (gpointer *)&module->list_types)) {
+
+ g_warning (g_module_error ());
+ g_module_close (module->library);
+
+ return FALSE;
+ }
+
+ module->initialize (gmodule);
+
+ return TRUE;
+}
+
+static void
+nautilus_module_unload (GTypeModule *gmodule)
+{
+ NautilusModule *module;
+
+ module = NAUTILUS_MODULE (gmodule);
+
+ module->shutdown ();
+
+ g_module_close (module->library);
+
+ module->initialize = NULL;
+ module->shutdown = NULL;
+ module->list_types = NULL;
+}
+
+static void
+nautilus_module_finalize (GObject *object)
+{
+ NautilusModule *module;
+
+ module = NAUTILUS_MODULE (object);
+
+ g_free (module->path);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+nautilus_module_instance_init (NautilusModule *module)
+{
+}
+
+static void
+nautilus_module_class_init (NautilusModuleClass *class)
+{
+ G_OBJECT_CLASS (class)->finalize = nautilus_module_finalize;
+ G_TYPE_MODULE_CLASS (class)->load = nautilus_module_load;
+ G_TYPE_MODULE_CLASS (class)->unload = nautilus_module_unload;
+}
+
+static void
+module_object_weak_notify (gpointer user_data, GObject *object)
+{
+ module_objects = g_list_remove (module_objects, object);
+}
+
+static void
+add_module_objects (NautilusModule *module)
+{
+ const GType *types;
+ int num_types;
+ int i;
+
+ module->list_types (&types, &num_types);
+
+ for (i = 0; i < num_types; i++) {
+ nautilus_module_add_type (types[i]);
+ }
+}
+
+static NautilusModule *
+nautilus_module_load_file (const char *filename)
+{
+ NautilusModule *module;
+
+ module = g_object_new (NAUTILUS_TYPE_MODULE, NULL);
+ module->path = g_strdup (filename);
+
+ if (g_type_module_use (G_TYPE_MODULE (module))) {
+ add_module_objects (module);
+ g_type_module_unuse (G_TYPE_MODULE (module));
+ return module;
+ } else {
+ g_object_unref (module);
+ return NULL;
+ }
+}
+
+static void
+load_module_dir (const char *dirname)
+{
+ GDir *dir;
+
+ dir = g_dir_open (dirname, 0, NULL);
+
+ if (dir) {
+ const char *name;
+
+ while ((name = g_dir_read_name (dir))) {
+ if (g_str_has_suffix (name, "." G_MODULE_SUFFIX)) {
+ char *filename;
+
+ filename = g_build_filename (dirname,
+ name,
+ NULL);
+ nautilus_module_load_file (filename);
+ }
+ }
+
+ g_dir_close (dir);
+ }
+}
+
+void
+nautilus_module_init (void)
+{
+ static gboolean initialized = FALSE;
+
+ if (!initialized) {
+ initialized = TRUE;
+
+ load_module_dir (NAUTILUS_EXTENSIONDIR);
+ }
+}
+
+GList *
+nautilus_module_get_extensions_for_type (GType type)
+{
+ GList *l;
+ GList *ret = NULL;
+
+ for (l = module_objects; l != NULL; l = l->next) {
+ if (G_TYPE_CHECK_INSTANCE_TYPE (G_OBJECT (l->data),
+ type)) {
+ g_object_ref (l->data);
+ ret = g_list_prepend (ret, l->data);
+ }
+ }
+
+ return ret;
+}
+
+void
+nautilus_module_extension_list_free (GList *extensions)
+{
+ GList *l;
+
+ for (l = extensions; l != NULL; l = l->next) {
+ g_object_unref (l->data);
+ }
+ g_list_free (extensions);
+}
+
+void
+nautilus_module_add_type (GType type)
+{
+ GObject *object;
+
+ object = g_object_new (type, NULL);
+ g_object_weak_ref (object,
+ (GWeakNotify)module_object_weak_notify,
+ NULL);
+
+ module_objects = g_list_prepend (module_objects, object);
+}
diff --git a/libnautilus-private/nautilus-module.h b/libnautilus-private/nautilus-module.h
new file mode 100644
index 000000000..8c26b73e1
--- /dev/null
+++ b/libnautilus-private/nautilus-module.h
@@ -0,0 +1,42 @@
+/*
+ * nautilus-module.h - Interface to nautilus extensions
+ *
+ * Copyright (C) 2003 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Dave Camp <dave@ximian.com>
+ *
+ */
+
+#ifndef NAUTILUS_MODULE_H
+#define NAUTILUS_MODULE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void nautilus_module_init (void);
+GList *nautilus_module_get_extensions_for_type (GType type);
+void nautilus_module_extension_list_free (GList *list);
+
+
+/* Add a type to the module interface - allows nautilus to add its own modules
+ * without putting them in separate shared libraries */
+void nautilus_module_add_type (GType type);
+
+G_END_DECLS
+
+#endif