diff --git a/thunar/thunar-create-dialog.c b/thunar/thunar-create-dialog.c index 781b060e19f16321203cf582270cc754bb3f1ac0..f31f337bac720898fdc99c7422251b17b60947f5 100644 --- a/thunar/thunar-create-dialog.c +++ b/thunar/thunar-create-dialog.c @@ -329,7 +329,7 @@ thunar_create_dialog_set_filename (ThunarCreateDialog *dialog, gtk_entry_set_text (GTK_ENTRY (dialog->entry), filename); /* check if filename contains a dot */ - dot = g_utf8_strrchr (filename, -1, '.'); + dot = thunar_util_str_get_extension (filename); if (G_LIKELY (dot != NULL)) { /* grab focus to the entry first, else diff --git a/thunar/thunar-dialogs.c b/thunar/thunar-dialogs.c index 953d4f5002157baee666a1947a96a112a1290336..99b9e54174c1de41a4b108c855fc9c002d623848 100644 --- a/thunar/thunar-dialogs.c +++ b/thunar/thunar-dialogs.c @@ -137,8 +137,8 @@ thunar_dialogs_show_rename_file (gpointer parent, /* check if we don't have a directory here */ if (!thunar_file_is_directory (file)) { - /* check if the filename contains a dot */ - text = g_utf8_strrchr (filename, -1, '.'); + /* check if the filename contains an extension */ + text = thunar_util_str_get_extension (filename); if (G_LIKELY (text != NULL)) { /* grab focus to the entry first, else the selection will be altered later */ diff --git a/thunar/thunar-properties-dialog.c b/thunar/thunar-properties-dialog.c index f5e5483db65d9d8a51efa4c671b6d9fd5555335b..6e6fa8de7ae55da5858f7b680da5afa7ea3dcdda 100644 --- a/thunar/thunar-properties-dialog.c +++ b/thunar/thunar-properties-dialog.c @@ -56,6 +56,7 @@ #include <thunar/thunar-properties-dialog.h> #include <thunar/thunar-size-label.h> #include <thunar/thunar-thumbnailer.h> +#include <thunar/thunar-util.h> @@ -913,7 +914,7 @@ thunar_properties_dialog_update_single (ThunarPropertiesDialog *dialog) gtk_widget_grab_focus (dialog->name_entry); /* select the pre-dot part of the name */ - str = strrchr (name, '.'); + str = thunar_util_str_get_extension (name); if (G_LIKELY (str != NULL)) { /* calculate the offset */ @@ -1260,9 +1261,6 @@ thunar_properties_dialog_update (ThunarPropertiesDialog *dialog) /* update the properties for a dialog showing 1 file */ thunar_properties_dialog_update_single (dialog); - - /* place the initial focus on the name entry widget */ - gtk_widget_grab_focus (dialog->name_entry); } else { diff --git a/thunar/thunar-renamer-model.c b/thunar/thunar-renamer-model.c index 853b797802ad50244582ee50b76cb372d38fc0ce..3d8c20951be3ebb42fdef232b107e21a455d7936 100644 --- a/thunar/thunar-renamer-model.c +++ b/thunar/thunar-renamer-model.c @@ -33,6 +33,7 @@ #include <thunar/thunar-gobject-extensions.h> #include <thunar/thunar-private.h> #include <thunar/thunar-renamer-model.h> +#include <thunar/thunar-util.h> @@ -819,10 +820,8 @@ thunar_renamer_model_process_item (ThunarRenamerModel *renamer_model, /* determine the current display name of the file */ display_name = thunar_file_get_display_name (item->file); - /* determine the last dot in the filename */ - dot = strrchr (display_name, '.'); - if (G_UNLIKELY (dot == display_name || (dot != NULL && dot[1] == '\0'))) - dot = NULL; + /* determine the extension in the filename */ + dot = thunar_util_str_get_extension (display_name); /* if we don't have a dot, then no "Suffix only" rename can take place */ if (G_LIKELY (dot != NULL || renamer_model->mode != THUNAR_RENAMER_MODE_SUFFIX)) diff --git a/thunar/thunar-text-renderer.c b/thunar/thunar-text-renderer.c index 8b111ccd725f4d95ff72e15f11b45a68f6e7eb01..d85f65a22cfc553f5c9eb1aafa04621099707118 100644 --- a/thunar/thunar-text-renderer.c +++ b/thunar/thunar-text-renderer.c @@ -34,6 +34,7 @@ #include <thunar/thunar-marshal.h> #include <thunar/thunar-pango-extensions.h> #include <thunar/thunar-text-renderer.h> +#include <thunar/thunar-util.h> @@ -756,7 +757,7 @@ thunar_text_renderer_grab_focus (GtkWidget *entry, text = gtk_entry_get_text (GTK_ENTRY (entry)); /* lookup the last dot in the text */ - dot = strrchr (text, '.'); + dot = thunar_util_str_get_extension (text); if (G_LIKELY (dot != NULL)) { /* determine the UTF-8 char offset */ diff --git a/thunar/thunar-util.c b/thunar/thunar-util.c index 7b8665f034081d7fb421b1795b5d214e2c7aeed1..77a36f989b3afa3d460ac50282417e86a9a72990 100644 --- a/thunar/thunar-util.c +++ b/thunar/thunar-util.c @@ -62,6 +62,113 @@ +/** + * thunar_util_strrchr_offset: + * @str: haystack + * @offset: pointer offset in @str + * @c: search needle + * + * Return the last occurrence of the character @c in + * the string @str starting at @offset. + * + * There are also Glib functions for this like g_strrstr_len + * and g_utf8_strrchr, but these work internally the same + * as this function (tho, less efficient). + * + * Return value: pointer in @str or NULL. + **/ +static inline gchar * +thunar_util_strrchr_offset (const gchar *str, + const gchar *offset, + gchar c) +{ + const gchar *p; + + for (p = offset; p > str; p--) + if (*p == c) + return (gchar *) p; + + return NULL; +} + + + +/** + * thunar_util_str_get_extension + * @filename : an UTF-8 filename + * + * Returns a pointer to the extension in @filename. + * + * This is an improved version of g_utf8_strrchr with + * improvements to recognize compound extensions like + * ".tar.gz" and ".desktop.in.in". + * + * Return value: pointer to the extension in @filename + * or NULL. +**/ +gchar * +thunar_util_str_get_extension (const gchar *filename) +{ + static const gchar *compressed[] = { "gz", "bz2", "lzma", "lrz", "rpm", "lzo", "xz", "z" }; + gchar *dot; + gchar *ext; + guint i; + gchar *dot2; + gsize len; + gboolean is_in; + + /* check if there is an possible extension part in the name */ + dot = strrchr (filename, '.'); + if (dot == NULL || dot[1] == '\0') + return NULL; + + /* skip the . */ + ext = dot + 1; + + /* check if this looks like a compression mime-type */ + for (i = 0; i < G_N_ELEMENTS (compressed); i++) + { + if (strcasecmp (ext, compressed[i]) == 0) + { + /* look for a possible container part (tar, psd, epsf) */ + dot2 = thunar_util_strrchr_offset (filename, dot - 1, '.'); + if (dot2 != NULL) + { + /* check the 2nd part range, keep it between 2 and 5 chars */ + len = dot - dot2 - 1; + if (len >= 2 && len <= 5) + dot = dot2; + } + + /* that's it for compression types */ + return dot; + } + } + + /* for coders, .in are quite common, so check for those too + * with a max of 3 rounds (2x .in and the possibly final extension) */ + if (strcasecmp (ext, "in") == 0) + { + for (i = 0, is_in = TRUE; is_in && i < 3; i++) + { + dot2 = thunar_util_strrchr_offset (filename, dot - 1, '.'); + /* the extension before .in could be long. check that it's at least 2 chars */ + len = dot - dot2 - 1; + if (dot2 == NULL || len < 2) + break; + + /* continue if another .in was found */ + is_in = dot - dot2 == 3 && strncasecmp (dot2, ".in", 3) == 0; + + dot = dot2; + } + } + + return dot; +} + + + void thunar_util_load_bookmarks (GFile *bookmarks_file, ThunarBookmarksFunc foreach_func, diff --git a/thunar/thunar-util.h b/thunar/thunar-util.h index 8170bdc3b8e47407606a9cc71d5eaa41e4e81c8e..b80f0704b8b211c0b6cc7aca95b607d523946b0b 100644 --- a/thunar/thunar-util.h +++ b/thunar/thunar-util.h @@ -31,6 +31,8 @@ typedef void (*ThunarBookmarksFunc) (GFile *file, gint row_num, gpointer user_data); +gchar *thunar_util_str_get_extension (const gchar *name) G_GNUC_WARN_UNUSED_RESULT; + void thunar_util_load_bookmarks (GFile *bookmarks_file, ThunarBookmarksFunc foreach_func, gpointer user_data);