[Xfce4-commits] <thunar:nick/on-demand-content-type> Load content types on-demand.
Nick Schermer
noreply at xfce.org
Wed Nov 14 21:30:03 CET 2012
Updating branch refs/heads/nick/on-demand-content-type
to b4c7d55e6de8f91cebb2bd0a634ec2d5be57687b (commit)
from 3cf90bd6fcdb399975b587c2c94569e989970827 (commit)
commit b4c7d55e6de8f91cebb2bd0a634ec2d5be57687b
Author: Nick Schermer <nick at xfce.org>
Date: Wed Nov 14 21:26:59 2012 +0100
Load content types on-demand.
This saves a lot of search and reading file content when
loading large folder. Still in experimental stage.
thunar/thunar-file.c | 202 +++++++++++++++++++++++++++++++--------
thunar/thunar-file.h | 4 +-
thunar/thunar-icon-factory.c | 3 +-
thunar/thunar-list-model.c | 8 +-
thunar/thunar-location-button.c | 3 +-
thunar/thunar-standard-view.c | 2 +-
thunar/thunar-window.c | 3 +-
thunarx/thunarx-file-info.h | 15 ++-
8 files changed, 181 insertions(+), 59 deletions(-)
diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c
index 4c340f6..5bc2e04 100644
--- a/thunar/thunar-file.c
+++ b/thunar/thunar-file.c
@@ -161,6 +161,8 @@ struct _ThunarFile
GFileInfo *info;
GFileType kind;
GFile *gfile;
+ gchar *content_type;
+ gchar *icon_name;
gchar *custom_icon_name;
gchar *display_name;
@@ -190,6 +192,23 @@ typedef struct
}
ThunarFileGetData;
+static struct
+{
+ GUserDirectory type;
+ const gchar *icon_name;
+}
+thunar_file_dirs[] =
+{
+ { G_USER_DIRECTORY_DESKTOP, "user-desktop" },
+ { G_USER_DIRECTORY_DOCUMENTS, "folder-documents" },
+ { G_USER_DIRECTORY_DOWNLOAD, "folder-download" },
+ { G_USER_DIRECTORY_MUSIC, "folder-music" },
+ { G_USER_DIRECTORY_PICTURES, "folder-pictures" },
+ { G_USER_DIRECTORY_PUBLIC_SHARE, "folder-publicshare" },
+ { G_USER_DIRECTORY_TEMPLATES, "folder-templates" },
+ { G_USER_DIRECTORY_VIDEOS, "folder-videos" }
+};
+
G_DEFINE_TYPE_WITH_CODE (ThunarFile, thunar_file, G_TYPE_OBJECT,
@@ -404,6 +423,10 @@ thunar_file_finalize (GObject *object)
/* free the custom icon name */
g_free (file->custom_icon_name);
+ /* content type info */
+ g_free (file->content_type);
+ g_free (file->icon_name);
+
/* free display name and basename */
g_free (file->display_name);
g_free (file->basename);
@@ -469,10 +492,7 @@ thunar_file_info_get_uri_scheme (ThunarxFileInfo *file_info)
static gchar*
thunar_file_info_get_mime_type (ThunarxFileInfo *file_info)
{
- if (THUNAR_FILE (file_info)->info == NULL)
- return NULL;
-
- return g_strdup (g_file_info_get_content_type (THUNAR_FILE (file_info)->info));
+ return g_strdup (thunar_file_get_content_type (THUNAR_FILE (file_info)));
}
@@ -484,7 +504,7 @@ thunar_file_info_has_mime_type (ThunarxFileInfo *file_info,
if (THUNAR_FILE (file_info)->info == NULL)
return FALSE;
- return g_content_type_is_a (g_file_info_get_content_type (THUNAR_FILE (file_info)->info), mime_type);
+ return g_content_type_is_a (thunar_file_get_content_type (THUNAR_FILE (file_info)), mime_type);
}
@@ -769,6 +789,12 @@ thunar_file_info_clear (ThunarFile *file)
g_free (file->basename);
file->basename = NULL;
+ /* content type */
+ g_free (file->content_type);
+ file->content_type = NULL;
+ g_free (file->icon_name);
+ file->icon_name = NULL;
+
/* free collate keys */
if (file->collate_key_nocase != file->collate_key)
g_free (file->collate_key_nocase);
@@ -1590,7 +1616,7 @@ thunar_file_launch (ThunarFile *file,
/* determine the default application to open the file */
/* TODO We should probably add a cancellable argument to thunar_file_launch() */
- app_info = thunar_file_get_default_handler (file);
+ app_info = thunar_file_get_default_handler (THUNAR_FILE (file));
/* display the application chooser if no application is defined for this file
* type yet */
@@ -2201,14 +2227,55 @@ thunar_file_get_user (const ThunarFile *file)
* Return value: content type of @file.
**/
const gchar *
-thunar_file_get_content_type (const ThunarFile *file)
+thunar_file_get_content_type (ThunarFile *file)
{
+ GFileInfo *info;
+ GError *err = NULL;
+ const gchar *content_type = NULL;
+
_thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL);
- if (file->info == NULL)
- return NULL;
+ if (G_UNLIKELY (file->content_type == NULL))
+ {
+ /* make sure this is not loaded in the general info */
+ _thunar_assert (file->info == NULL
+ || !g_file_info_has_attribute (file->info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE));
+
+ if (file->kind == G_FILE_TYPE_DIRECTORY)
+ {
+ /* this we known for sure */
+ file->content_type = g_strdup ("inode/directory");
+ return file->content_type;
+ }
+
+ /* async load the content-type */
+ info = g_file_query_info (file->gfile,
+ THUNARX_FILE_INFO_MIME_NAMESPACE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, &err);
+
+ if (G_LIKELY (info != NULL))
+ {
+ /* store the new content type */
+ content_type = g_file_info_get_content_type (info);
+ if (G_UNLIKELY (content_type != NULL))
+ file->content_type = g_strdup (content_type);
+ g_object_unref (G_OBJECT (info));
+ }
+ else
+ {
+ g_warning ("Content type loading failed for %s: %s",
+ thunar_file_get_display_name (file),
+ err->message);
+ g_error_free (err);
+ }
+
+ /* always provide a fallback */
+ if (file->content_type == NULL)
+ file->content_type = g_strdup ("unknown");
+ }
- return g_file_info_get_content_type (file->info);
+ return file->content_type;
}
@@ -2316,7 +2383,7 @@ thunar_file_get_default_handler (const ThunarFile *file)
_thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL);
- content_type = thunar_file_get_content_type (file);
+ content_type = thunar_file_get_content_type (THUNAR_FILE (file));
if (content_type != NULL)
{
path = g_file_get_path (file->gfile);
@@ -2596,7 +2663,7 @@ thunar_file_is_executable (const ThunarFile *file)
if (g_file_info_get_attribute_boolean (file->info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE))
{
/* get the content type of the file */
- content_type = g_file_info_get_content_type (file->info);
+ content_type = thunar_file_get_content_type (THUNAR_FILE (file));
if (G_LIKELY (content_type != NULL))
{
#ifdef G_OS_WIN32
@@ -3332,6 +3399,29 @@ thunar_file_get_preview_icon (const ThunarFile *file)
+static const gchar *
+thunar_file_get_icon_name_for_state (const gchar *icon_name,
+ ThunarFileIconState icon_state)
+{
+ if (exo_str_is_empty (icon_name))
+ return NULL;
+
+ /* check if we have an accept icon for the icon we found */
+ if (icon_state != THUNAR_FILE_ICON_STATE_DEFAULT
+ && (strcmp (icon_name, "inode-directory") == 0
+ || strcmp (icon_name, "folder") == 0))
+ {
+ if (icon_state == THUNAR_FILE_ICON_STATE_DROP)
+ return "folder-drag-accept";
+ else if (icon_state == THUNAR_FILE_ICON_STATE_OPEN)
+ return "folder-open";
+ }
+
+ return icon_name;
+}
+
+
+
/**
* thunar_file_get_icon_name:
* @file : a #ThunarFile instance.
@@ -3339,41 +3429,78 @@ thunar_file_get_preview_icon (const ThunarFile *file)
* @icon_theme : the #GtkIconTheme on which to lookup up the icon name.
*
* Returns the name of the icon that can be used to present @file, based
- * on the given @icon_state and @icon_theme. The returned string has to
- * be freed using g_free().
+ * on the given @icon_state and @icon_theme.
*
* Return value: the icon name for @file in @icon_theme.
**/
-gchar *
-thunar_file_get_icon_name (const ThunarFile *file,
+const gchar *
+thunar_file_get_icon_name (ThunarFile *file,
ThunarFileIconState icon_state,
GtkIconTheme *icon_theme)
{
GFile *icon_file;
- GIcon *icon;
+ GIcon *icon = NULL;
const gchar * const *names;
gchar *icon_name = NULL;
- gint i;
+ gchar *path;
+ const gchar *special_names[3] = { NULL, "folder", NULL };
+ guint i;
+ const gchar *special_dir;
_thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL);
_thunar_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
+ /* return cached name */
+ if (G_LIKELY (file->icon_name != NULL))
+ return thunar_file_get_icon_name_for_state (file->icon_name, icon_state);
+
/* the system root folder has a special icon */
if (thunar_file_is_directory (file)
- && thunar_file_is_local (file)
- && thunar_file_is_root (file))
- return g_strdup ("drive-harddisk");
+ && thunar_file_is_local (file))
+ {
+ path = g_file_get_path (file->gfile);
+ if (G_LIKELY (path != NULL))
+ {
+ if (strcmp (path, G_DIR_SEPARATOR_S) == 0)
+ *special_names = "drive-harddisk";
+ else if (strcmp (path, xfce_get_homedir ()) == 0)
+ *special_names = "user-home";
+ else
+ for (i = 0; i < G_N_ELEMENTS (thunar_file_dirs); i++)
+ {
+ special_dir = g_get_user_special_dir (thunar_file_dirs[i].type);
+ if (special_dir != NULL
+ && strcmp (path, special_dir) == 0)
+ {
+ *special_names = thunar_file_dirs[i].icon_name;
+ break;
+ }
+ }
+
+ g_free (path);
+ if (*special_names != NULL)
+ {
+ names = special_names;
+ goto check_names;
+ }
+ }
+ }
+
+ /* try again later */
if (file->info == NULL)
return NULL;
- icon = g_file_info_get_icon (file->info);
-
+ /* lookup for content type, just like gio does*/
+ icon = g_content_type_get_icon (thunar_file_get_content_type (file));
if (icon != NULL)
{
if (G_IS_THEMED_ICON (icon))
{
names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+
+ check_names:
+
if (G_LIKELY (names != NULL))
{
for (i = 0; names[i] != NULL; ++i)
@@ -3391,27 +3518,18 @@ thunar_file_get_icon_name (const ThunarFile *file,
if (icon_file != NULL)
icon_name = g_file_get_path (icon_file);
}
- }
- /* check if we have an accept icon for the icon we found */
- if (icon_name != NULL
- && icon_state != THUNAR_FILE_ICON_STATE_DEFAULT
- && (strcmp (icon_name, "inode-directory") == 0
- || strcmp (icon_name, "folder") == 0))
- {
- if (icon_state == THUNAR_FILE_ICON_STATE_DROP)
- {
- g_free (icon_name);
- icon_name = g_strdup ("folder-drag-accept");
- }
- else if (icon_state == THUNAR_FILE_ICON_STATE_OPEN)
- {
- g_free (icon_name);
- icon_name = g_strdup ("folder-open");
- }
+ if (G_LIKELY (icon != NULL))
+ g_object_unref (icon);
}
- return icon_name;
+ /* store new name, or empty string to avoid recursion */
+ if (G_LIKELY (icon_name != NULL))
+ file->icon_name = icon_name;
+ else
+ file->icon_name = g_strdup ("");
+
+ return thunar_file_get_icon_name_for_state (file->icon_name, icon_state);
}
@@ -3735,7 +3853,7 @@ thunar_file_list_get_applications (GList *file_list)
GList *next;
GList *ap;
GList *lp;
- const gchar *previous_type;
+ const gchar *previous_type = NULL;
const gchar *current_type;
/* determine the set of applications that can open all files */
diff --git a/thunar/thunar-file.h b/thunar/thunar-file.h
index 48b3770..05f7f1b 100644
--- a/thunar/thunar-file.h
+++ b/thunar/thunar-file.h
@@ -173,7 +173,7 @@ GVolume *thunar_file_get_volume (const ThunarFile *file
ThunarGroup *thunar_file_get_group (const ThunarFile *file);
ThunarUser *thunar_file_get_user (const ThunarFile *file);
-const gchar *thunar_file_get_content_type (const ThunarFile *file);
+const gchar *thunar_file_get_content_type (ThunarFile *file);
const gchar *thunar_file_get_symlink_target (const ThunarFile *file);
const gchar *thunar_file_get_basename (const ThunarFile *file) G_GNUC_CONST;
gboolean thunar_file_is_symlink (const ThunarFile *file);
@@ -227,7 +227,7 @@ ThunarFileThumbState thunar_file_get_thumb_state (const ThunarFile *fil
void thunar_file_set_thumb_state (ThunarFile *file,
ThunarFileThumbState state);
GIcon *thunar_file_get_preview_icon (const ThunarFile *file);
-gchar *thunar_file_get_icon_name (const ThunarFile *file,
+const gchar *thunar_file_get_icon_name (ThunarFile *file,
ThunarFileIconState icon_state,
GtkIconTheme *icon_theme);
diff --git a/thunar/thunar-icon-factory.c b/thunar/thunar-icon-factory.c
index 2826e22..d0544d1 100644
--- a/thunar/thunar-icon-factory.c
+++ b/thunar/thunar-icon-factory.c
@@ -748,7 +748,7 @@ thunar_icon_factory_load_file_icon (ThunarIconFactory *factory,
const gchar *thumbnail_path;
GdkPixbuf *icon = NULL;
GIcon *gicon;
- gchar *icon_name;
+ const gchar *icon_name;
const gchar *custom_icon;
ThunarIconStore *store;
@@ -846,7 +846,6 @@ thunar_icon_factory_load_file_icon (ThunarIconFactory *factory,
{
icon_name = thunar_file_get_icon_name (file, icon_state, factory->icon_theme);
icon = thunar_icon_factory_load_icon (factory, icon_name, icon_size, TRUE);
- g_free (icon_name);
}
if (G_LIKELY (icon != NULL))
diff --git a/thunar/thunar-list-model.c b/thunar/thunar-list-model.c
index 6c0d27b..58b41c5 100644
--- a/thunar/thunar-list-model.c
+++ b/thunar/thunar-list-model.c
@@ -1422,8 +1422,8 @@ sort_by_mime_type (const ThunarFile *a,
const gchar *content_type_b;
gint result;
- content_type_a = thunar_file_get_content_type (a);
- content_type_b = thunar_file_get_content_type (b);
+ content_type_a = thunar_file_get_content_type (THUNAR_FILE (a));
+ content_type_b = thunar_file_get_content_type (THUNAR_FILE (b));
if (content_type_a == NULL)
content_type_a = "";
@@ -1551,7 +1551,7 @@ sort_by_type (const ThunarFile *a,
}
else
{
- content_type_a = thunar_file_get_content_type (a);
+ content_type_a = thunar_file_get_content_type (THUNAR_FILE (a));
description_a = g_content_type_get_description (content_type_a);
}
@@ -1562,7 +1562,7 @@ sort_by_type (const ThunarFile *a,
}
else
{
- content_type_b = thunar_file_get_content_type (b);
+ content_type_b = thunar_file_get_content_type (THUNAR_FILE (a));
description_b = g_content_type_get_description (content_type_b);
}
diff --git a/thunar/thunar-location-button.c b/thunar/thunar-location-button.c
index 7f9cd0f..6769d9d 100644
--- a/thunar/thunar-location-button.c
+++ b/thunar/thunar-location-button.c
@@ -424,7 +424,7 @@ thunar_location_button_file_changed (ThunarLocationButton *location_button,
GtkIconTheme *icon_theme;
GtkSettings *settings;
GdkPixbuf *icon;
- gchar *icon_name;
+ const gchar *icon_name;
gint height;
gint width;
gint size;
@@ -489,7 +489,6 @@ thunar_location_button_file_changed (ThunarLocationButton *location_button,
{
icon_name = thunar_file_get_icon_name (file, location_button->file_icon_state, icon_theme);
gtk_drag_source_set_icon_name (GTK_BIN (location_button)->child, icon_name);
- g_free (icon_name);
}
}
diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c
index ac82415..665ee6f 100644
--- a/thunar/thunar-standard-view.c
+++ b/thunar/thunar-standard-view.c
@@ -2324,7 +2324,7 @@ thunar_standard_view_action_create_template (GtkAction *action,
/* ask the user to enter a name for the new document */
name = thunar_show_create_dialog (GTK_WIDGET (standard_view),
- thunar_file_get_content_type (file),
+ thunar_file_get_content_type (THUNAR_FILE (file)),
thunar_file_get_display_name (file),
title);
if (G_LIKELY (name != NULL))
diff --git a/thunar/thunar-window.c b/thunar/thunar-window.c
index 9ff29aa..ce7a315 100644
--- a/thunar/thunar-window.c
+++ b/thunar/thunar-window.c
@@ -3122,7 +3122,7 @@ thunar_window_current_directory_changed (ThunarFile *current_directory,
{
GtkIconTheme *icon_theme;
GtkAction *action;
- gchar *icon_name;
+ const gchar *icon_name;
gchar *title;
gboolean show_full_path;
gchar *parse_name = NULL;
@@ -3156,7 +3156,6 @@ thunar_window_current_directory_changed (ThunarFile *current_directory,
THUNAR_FILE_ICON_STATE_DEFAULT,
icon_theme);
gtk_window_set_icon_name (GTK_WINDOW (window), icon_name);
- g_free (icon_name);
}
diff --git a/thunarx/thunarx-file-info.h b/thunarx/thunarx-file-info.h
index c8e305f..304089a 100644
--- a/thunarx/thunarx-file-info.h
+++ b/thunarx/thunarx-file-info.h
@@ -38,15 +38,22 @@ G_BEGIN_DECLS;
**/
#define THUNARX_FILE_INFO_NAMESPACE \
"access::*," \
- "id::*," \
- "mountable::*," \
+ "id::filesystem," \
+ "mountable::can-mount,standard::target-uri," \
"preview::*," \
- "standard::*," \
+ "standard::type,standard::is-hidden,standard::is-backup," \
+ "standard::is-symlink,standard::name,standard::display-name," \
+ "standard::size,standard::symlink-target," \
"time::*," \
"trash::*," \
- "unix::*," \
+ "unix::gid,unix::uid,unix::mode," \
"metadata::emblems"
+#define THUNARX_FILE_INFO_MIME_NAMESPACE \
+ "standard::content-type"
+
+
+
/**
* Filesystem information namespaces available in the #GFileInfo
* returned by thunarx_file_info_get_filesystem_info().
More information about the Xfce4-commits
mailing list