From 393d1ce317bd0a304e1aba839e9f60691b0f54f3 Mon Sep 17 00:00:00 2001 From: vanadiae Date: Thu, 24 Dec 2020 17:36:04 +0100 Subject: [PATCH 1/2] content-type: Check for conflicting plain files and markdown files Currently when a file is named i.e. COPYING or README, it is tagged a content type text/x-copying, so it receives the correct symbolic icon. But when the file is i.e. COPYING.md or README.md, then it's detected as a markdown file and so it uses the markdown icon instead of the correct bundled icon (copyright logo). So this commit checks for common file names that might be put as markdown (or another format, for what it's worth), and use the correct bundled icon for those files. This work can't be done in the shared-mime-info database because it's mostly based on the use-case of the file, not its format, so there would be conflicts between multiple content type. --- src/libide/editor/ide-editor-page.c | 2 +- src/libide/io/ide-content-type.c | 25 ++++++++++++++++++- src/libide/io/ide-content-type.h | 5 ++-- src/libide/projects/ide-project-file.c | 2 +- .../file-search/gbp-file-search-index.c | 2 +- 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/libide/editor/ide-editor-page.c b/src/libide/editor/ide-editor-page.c index 08cd60bf3..67f5c162d 100644 --- a/src/libide/editor/ide-editor-page.c +++ b/src/libide/editor/ide-editor-page.c @@ -117,7 +117,7 @@ ide_editor_page_update_icon (IdeEditorPage *self) content_type = g_content_type_guess (name, (const guchar *)sniff, strlen (sniff), NULL); /* Update icon to match guess */ - icon = ide_g_content_type_get_symbolic_icon (content_type); + icon = ide_g_content_type_get_symbolic_icon (content_type, name); ide_page_set_icon (IDE_PAGE (self), icon); } diff --git a/src/libide/io/ide-content-type.c b/src/libide/io/ide-content-type.c index df2a88dc7..829c0ae76 100644 --- a/src/libide/io/ide-content-type.c +++ b/src/libide/io/ide-content-type.c @@ -37,9 +37,26 @@ * Since: 3.32 */ GIcon * -ide_g_content_type_get_symbolic_icon (const gchar *content_type) +ide_g_content_type_get_symbolic_icon (const gchar *content_type, + const gchar *filename) { static GHashTable *bundled; + /* This ensures those files get a proper icon when they end with .md (markdown files). + * It can't be fixed in the shared-mime-info db because otherwise they wouldn't get detected as + * markdown anymore. + */ + static const struct { + const gchar *searched_prefix; + const gchar *icon_name; + } bundled_check_by_name_prefix[] = { + {"README", "text-x-readme-symbolic"}, + {"NEWS", "text-x-changelog-symbolic"}, + {"CHANGELOG", "text-x-changelog-symbolic"}, + {"COPYING", "text-x-copying-symbolic"}, + {"LICENSE", "text-x-copying-symbolic"}, + {"AUTHORS", "text-x-authors-symbolic"}, + {"MAINTAINERS", "text-x-authors-symbolic"}, + }; g_autoptr(GIcon) icon = NULL; g_return_val_if_fail (content_type != NULL, NULL); @@ -93,6 +110,12 @@ ide_g_content_type_get_symbolic_icon (const gchar *content_type) { const gchar * const *names = g_themed_icon_get_names (G_THEMED_ICON (icon)); + for (guint j = 0; j < G_N_ELEMENTS (bundled_check_by_name_prefix); j++) + { + if (g_str_has_prefix (filename, bundled_check_by_name_prefix[j].searched_prefix)) + return g_icon_new_for_string (bundled_check_by_name_prefix[j].icon_name, NULL); + } + if (names != NULL) { gboolean fallback = FALSE; diff --git a/src/libide/io/ide-content-type.h b/src/libide/io/ide-content-type.h index 6304b69c1..7311ebed7 100644 --- a/src/libide/io/ide-content-type.h +++ b/src/libide/io/ide-content-type.h @@ -24,8 +24,9 @@ G_BEGIN_DECLS -IDE_AVAILABLE_IN_3_32 -GIcon *ide_g_content_type_get_symbolic_icon (const gchar *content_type); +IDE_AVAILABLE_IN_3_40 +GIcon *ide_g_content_type_get_symbolic_icon (const gchar *content_type, + const gchar *filename); G_END_DECLS diff --git a/src/libide/projects/ide-project-file.c b/src/libide/projects/ide-project-file.c index 05dfb8748..627ec0b1b 100644 --- a/src/libide/projects/ide-project-file.c +++ b/src/libide/projects/ide-project-file.c @@ -389,7 +389,7 @@ ide_project_file_get_symbolic_icon (IdeProjectFile *self) { g_autoptr(GIcon) override = NULL; - if ((override = ide_g_content_type_get_symbolic_icon (content_type))) + if ((override = ide_g_content_type_get_symbolic_icon (content_type, g_file_info_get_display_name (priv->info)))) g_file_info_set_symbolic_icon (priv->info, override); } } diff --git a/src/plugins/file-search/gbp-file-search-index.c b/src/plugins/file-search/gbp-file-search-index.c index 5f12790f2..f7e4b9c20 100644 --- a/src/plugins/file-search/gbp-file-search-index.c +++ b/src/plugins/file-search/gbp-file-search-index.c @@ -395,7 +395,7 @@ gbp_file_search_index_populate (GbpFileSearchIndex *self, * Sniffing would be way too slow here. */ if ((content_type = g_content_type_guess (filename, NULL, 0, NULL))) - themed_icon = ide_g_content_type_get_symbolic_icon (content_type); + themed_icon = ide_g_content_type_get_symbolic_icon (content_type, filename); result = g_object_new (GBP_TYPE_FILE_SEARCH_RESULT, "context", context, -- GitLab From 52aae2cd25d8663c5439628631ccf6df608d500e Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Fri, 25 Dec 2020 15:15:28 -0800 Subject: [PATCH 2/2] io: speed up icon remap check with filter table This lets us check by first character only in a 256-byte lookup table so that we can quickly ignore most files without any costly string comparisons or function calls. --- src/libide/io/ide-content-type.c | 139 ++++++++++++++++++------------- 1 file changed, 81 insertions(+), 58 deletions(-) diff --git a/src/libide/io/ide-content-type.c b/src/libide/io/ide-content-type.c index 829c0ae76..ab65bc2bc 100644 --- a/src/libide/io/ide-content-type.c +++ b/src/libide/io/ide-content-type.c @@ -22,81 +22,99 @@ #include "config.h" +#include "../../gconstructor.h" + #include "ide-content-type.h" +static gchar bundled_lookup_table[256]; +static GHashTable *bundled; +/* This ensures those files get a proper icon when they end with .md + * (markdown files). It can't be fixed in the shared-mime-info db because + * otherwise they wouldn't get detected as markdown anymore. + */ +static const struct { + const gchar *searched_prefix; + const gchar *icon_name; +} bundled_check_by_name_prefix[] = { + { "README", "text-x-readme-symbolic" }, + { "NEWS", "text-x-changelog-symbolic" }, + { "CHANGELOG", "text-x-changelog-symbolic" }, + { "COPYING", "text-x-copying-symbolic" }, + { "LICENSE", "text-x-copying-symbolic" }, + { "AUTHORS", "text-x-authors-symbolic" }, + { "MAINTAINERS", "text-x-authors-symbolic" }, +}; + +#if defined (G_HAS_CONSTRUCTORS) +# ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA +# pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(ide_io_init_ctor) +# endif +G_DEFINE_CONSTRUCTOR(ide_io_init_ctor) +#else +# error Your platform/compiler is missing constructor support +#endif + +static void +ide_io_init_ctor (void) +{ + bundled = g_hash_table_new (g_str_hash, g_str_equal); + + /* + * This needs to be updated when we add icons for specific mime-types + * because of how icon theme loading works (and it wanting to use + * Adwaita generic icons before our hicolor specific icons. + */ +#define ADD_ICON(t, n, v) g_hash_table_insert (t, (gpointer)n, v ? (gpointer)v : (gpointer)n) + ADD_ICON (bundled, "application-x-php-symbolic", NULL); + ADD_ICON (bundled, "text-css-symbolic", NULL); + ADD_ICON (bundled, "text-html-symbolic", NULL); + ADD_ICON (bundled, "text-markdown-symbolic", NULL); + ADD_ICON (bundled, "text-rust-symbolic", NULL); + ADD_ICON (bundled, "text-sql-symbolic", NULL); + ADD_ICON (bundled, "text-x-authors-symbolic", NULL); + ADD_ICON (bundled, "text-x-changelog-symbolic", NULL); + ADD_ICON (bundled, "text-x-chdr-symbolic", NULL); + ADD_ICON (bundled, "text-x-copying-symbolic", NULL); + ADD_ICON (bundled, "text-x-cpp-symbolic", NULL); + ADD_ICON (bundled, "text-x-csrc-symbolic", NULL); + ADD_ICON (bundled, "text-x-javascript-symbolic", NULL); + ADD_ICON (bundled, "text-x-python-symbolic", NULL); + ADD_ICON (bundled, "text-x-python3-symbolic", "text-x-python-symbolic"); + ADD_ICON (bundled, "text-x-readme-symbolic", NULL); + ADD_ICON (bundled, "text-x-ruby-symbolic", NULL); + ADD_ICON (bundled, "text-x-script-symbolic", NULL); + ADD_ICON (bundled, "text-x-vala-symbolic", NULL); + ADD_ICON (bundled, "text-xml-symbolic", NULL); +#undef ADD_ICON + + /* Create faster check than doing full string checks */ + for (guint i = 0; i < G_N_ELEMENTS (bundled_check_by_name_prefix); i++) + bundled_lookup_table[(guint)bundled_check_by_name_prefix[i].searched_prefix[0]] = 1; +} + /** * ide_g_content_type_get_symbolic_icon: + * @content_type: the content-type to lookup * * This function is simmilar to g_content_type_get_symbolic_icon() except that * it takes our bundled icons into account to ensure that they are taken at a * higher priority than the fallbacks from the current icon theme such as * Adwaita. * + * In 3.40, this function was modified to add the @filename parameter. + * * Returns: (transfer full) (nullable): A #GIcon or %NULL * - * Since: 3.32 + * Since: 3.40 */ GIcon * ide_g_content_type_get_symbolic_icon (const gchar *content_type, const gchar *filename) { - static GHashTable *bundled; - /* This ensures those files get a proper icon when they end with .md (markdown files). - * It can't be fixed in the shared-mime-info db because otherwise they wouldn't get detected as - * markdown anymore. - */ - static const struct { - const gchar *searched_prefix; - const gchar *icon_name; - } bundled_check_by_name_prefix[] = { - {"README", "text-x-readme-symbolic"}, - {"NEWS", "text-x-changelog-symbolic"}, - {"CHANGELOG", "text-x-changelog-symbolic"}, - {"COPYING", "text-x-copying-symbolic"}, - {"LICENSE", "text-x-copying-symbolic"}, - {"AUTHORS", "text-x-authors-symbolic"}, - {"MAINTAINERS", "text-x-authors-symbolic"}, - }; g_autoptr(GIcon) icon = NULL; g_return_val_if_fail (content_type != NULL, NULL); - if (g_once_init_enter (&bundled)) - { - GHashTable *table = g_hash_table_new (g_str_hash, g_str_equal); - - /* - * This needs to be updated when we add icons for specific mime-types - * because of how icon theme loading works (and it wanting to use - * Adwaita generic icons before our hicolor specific icons. - */ - -#define ADD_ICON(t, n, v) g_hash_table_insert (t, (gpointer)n, v ? (gpointer)v : (gpointer)n) - ADD_ICON (table, "application-x-php-symbolic", NULL); - ADD_ICON (table, "text-css-symbolic", NULL); - ADD_ICON (table, "text-html-symbolic", NULL); - ADD_ICON (table, "text-markdown-symbolic", NULL); - ADD_ICON (table, "text-rust-symbolic", NULL); - ADD_ICON (table, "text-sql-symbolic", NULL); - ADD_ICON (table, "text-x-authors-symbolic", NULL); - ADD_ICON (table, "text-x-changelog-symbolic", NULL); - ADD_ICON (table, "text-x-chdr-symbolic", NULL); - ADD_ICON (table, "text-x-copying-symbolic", NULL); - ADD_ICON (table, "text-x-cpp-symbolic", NULL); - ADD_ICON (table, "text-x-csrc-symbolic", NULL); - ADD_ICON (table, "text-x-javascript-symbolic", NULL); - ADD_ICON (table, "text-x-python-symbolic", NULL); - ADD_ICON (table, "text-x-python3-symbolic", "text-x-python-symbolic"); - ADD_ICON (table, "text-x-readme-symbolic", NULL); - ADD_ICON (table, "text-x-ruby-symbolic", NULL); - ADD_ICON (table, "text-x-script-symbolic", NULL); - ADD_ICON (table, "text-x-vala-symbolic", NULL); - ADD_ICON (table, "text-xml-symbolic", NULL); -#undef ADD_ICON - - g_once_init_leave (&bundled, table); - } - /* * Basically just steal the name if we get something that is not generic, * because that is the only way we can somewhat ensure that we don't use @@ -108,14 +126,19 @@ ide_g_content_type_get_symbolic_icon (const gchar *content_type, if (G_IS_THEMED_ICON (icon)) { - const gchar * const *names = g_themed_icon_get_names (G_THEMED_ICON (icon)); + const gchar * const *names; - for (guint j = 0; j < G_N_ELEMENTS (bundled_check_by_name_prefix); j++) + if (filename != NULL && bundled_lookup_table [(guint8)filename[0]]) { - if (g_str_has_prefix (filename, bundled_check_by_name_prefix[j].searched_prefix)) - return g_icon_new_for_string (bundled_check_by_name_prefix[j].icon_name, NULL); + for (guint j = 0; j < G_N_ELEMENTS (bundled_check_by_name_prefix); j++) + { + if (g_str_has_prefix (filename, bundled_check_by_name_prefix[j].searched_prefix)) + return g_icon_new_for_string (bundled_check_by_name_prefix[j].icon_name, NULL); + } } + names = g_themed_icon_get_names (G_THEMED_ICON (icon)); + if (names != NULL) { gboolean fallback = FALSE; -- GitLab