This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository efm2.
View the commit online.
commit 277a239719e9f149cbd92dd63bdc82479a5c8c9b
Author: Carsten Haitzler (Rasterman) <[email protected]>
AuthorDate: Thu Feb 26 09:17:18 2026 +0000
add icon override infra
this allows personal user or installed with efm2 system config to
override icons for specific filenames, paths or mime types
---
src/backends/default/icon_override.c | 250 +++++++++++++++++++++++++++++++++++
src/backends/default/icon_override.h | 18 +++
src/backends/default/meson.build | 1 +
src/backends/default/open.c | 71 +++++++++-
src/efm/efm_back_end.c | 21 +++
src/efm/efm_graph.c | 2 +-
src/efm/efm_icon.c | 2 +-
7 files changed, 360 insertions(+), 5 deletions(-)
diff --git a/src/backends/default/icon_override.c b/src/backends/default/icon_override.c
new file mode 100644
index 0000000..21ad1fd
--- /dev/null
+++ b/src/backends/default/icon_override.c
@@ -0,0 +1,250 @@
+#include <Eina.h>
+#include <Efreet.h>
+#include <Ecore.h>
+#include <Ecore_File.h>
+#include "icon_override.h"
+
+// this file handles overrides from mime or desktop files so you can have a
+// standard config and personal config giving specific icons for specific
+// file names and paths or mime types
+
+static const char *_config_dir = NULL;
+static const char *_data_dir = NULL;
+
+static Eina_Hash *_hash_files = NULL;
+static Eina_Hash *_hash_mimes = NULL;
+
+///////////////////////////////////////////////////////////////////////////////
+static const char *
+_xdg_dir_get(const char *xdg)
+{
+ const char *ret = NULL;
+
+#define G(_v, _f) if (!strcmp(xdg, _v)) ret = _f(); if (ret) return ret
+ G("XDG_DESKTOP_DIR", efreet_desktop_dir_get);
+ G("XDG_DOCUMENTS_DIR", efreet_documents_dir_get);
+ G("XDG_DOWNLOAD_DIR", efreet_download_dir_get);
+ G("XDG_MUSIC_DIR", efreet_music_dir_get);
+ G("XDG_PICTURES_DIR", efreet_pictures_dir_get);
+ G("XDG_PUBLICSHARE_DIR", efreet_public_share_dir_get);
+ G("XDG_TEMPLATES_DIR", efreet_templates_dir_get);
+ G("XDG_VIDEOS_DIR", efreet_videos_dir_get);
+#undef G
+ return ret;
+}
+static char *
+_env_resolve(const char *file)
+{
+ Eina_Strbuf *buf;
+ const char *p, *e = NULL, *e_end = NULL, *val;
+ char *env, *ret;
+ size_t len;
+
+ if (!file) return NULL;
+ if (!(buf = eina_strbuf_new())) return NULL;
+
+ env = alloca(strlen(file) + 1);
+ for (p = file; ; p++)
+ {
+ if (!e)
+ {
+ if (*p == '$') e = p + 1; // env starts
+ else if (*p) eina_strbuf_append_char(buf, *p);
+ }
+ else if (!(((*p >= 'a') && (*p <= 'z'))
+ || ((*p >= 'A') && (*p <= 'Z'))
+ || ((*p >= '0') && (*p <= '9'))
+ || (*p == '_')) || (*p == 0))
+ { // env var string char is not valid - end of var name
+ e_end = p;
+ len = (size_t)(e_end - e);
+ if (len > 0)
+ { // store the env var name string
+ memcpy(env, e, len);
+ env[len] = 0;
+ // get env var
+ val = NULL;
+ // if it might be a special $XDG_ "virtual" env
+ if (!strncmp(env, "XDG_", 4)) val = _xdg_dir_get(env);
+ // we didnt get a special xdg env - look at real one
+ if (!val) val = getenv(env);
+ // found it - append it
+ if (val) eina_strbuf_append(buf, val);
+ }
+ e = NULL; // we don't have an env anymore
+ eina_strbuf_append_char(buf, *p);
+ }
+ if (*p == 0) break; // end of string - special
+ }
+ ret = strdup(eina_strbuf_string_get(buf));
+ eina_strbuf_free(buf);
+ return ret;
+}
+
+static void
+_cb_hash_item_free(void *data)
+{
+ efreet_ini_free(data);
+}
+
+static void
+_file_file_load_hash_add(const char *file, Efreet_Ini *ini)
+{
+ if (eina_hash_find(_hash_files, file))
+ { // if we already have an entry - don't replace it
+ efreet_ini_free(ini);
+ return;
+ }
+ eina_hash_add(_hash_files, file, ini);
+}
+
+static void
+_file_file_load(const char *file, Efreet_Ini *ini)
+{
+ char *resolved = NULL;
+
+ if (!_hash_files)
+ _hash_files = eina_hash_string_superfast_new(_cb_hash_item_free);
+ if (!_hash_files)
+ {
+ efreet_ini_free(ini);
+ return;
+ }
+ if (file[0] == '/') // full path
+ _file_file_load_hash_add(file, ini);
+ else if (eina_fnmatch("~/*", file, EINA_FNMATCH_PATHNAME))
+ { // user homedir ~/something - so resolve ~ to $HOME
+ const char *env = getenv("HOME");
+ if (env)
+ { // we've got home - build string to put it in
+ resolved = malloc(strlen(env) + strlen(file + 1));
+ if (resolved)
+ { // we have space
+ strcpy(resolved, env); // replace ~ with $HOME
+ strcat(resolved, file + 1); // append all after ~
+ _file_file_load_hash_add(resolved, ini);
+ }
+ else efreet_ini_free(ini);
+ }
+ else efreet_ini_free(ini);
+ }
+ else
+ { // resolve any normal env vars in the filename or path
+ resolved = _env_resolve(file);
+ if (resolved) _file_file_load_hash_add(resolved, ini);
+ else efreet_ini_free(ini);
+ }
+ if (resolved) free(resolved);
+}
+
+static void
+_file_mime_load(const char *mime, Efreet_Ini *ini)
+{
+ if (!_hash_mimes)
+ _hash_mimes = eina_hash_string_superfast_new(_cb_hash_item_free);
+ if (!_hash_mimes)
+ {
+ efreet_ini_free(ini);
+ return;
+ }
+ if (eina_hash_find(_hash_mimes, mime))
+ { // if we already have an entry - don't replace it
+ efreet_ini_free(ini);
+ return;
+ }
+ eina_hash_add(_hash_files, mime, ini);
+}
+
+static void
+_file_load(const char *file)
+{
+ Efreet_Ini *ini = efreet_ini_new(file);
+ const char *field;
+
+ if (!ini) return;
+ if (!ini->data) goto done;
+ if (!efreet_ini_section_set(ini, "Efm Override")) goto done;
+ field = eina_hash_find(ini->section, "File");
+ if (field) _file_file_load(field, ini);
+ else
+ {
+ field = eina_hash_find(ini->section, "Mime");
+ if (field) _file_mime_load(field, ini);
+ }
+ return;
+done:
+ efreet_ini_free(ini);
+}
+
+static void
+_dir_load(const char *dir)
+{
+ Eina_Iterator *it;
+ Eina_File_Direct_Info *info;
+
+ it = eina_file_direct_ls(dir);
+ EINA_ITERATOR_FOREACH(it, info)
+ {
+ if (info->path[info->name_start] != '.')
+ {
+ if (ecore_file_is_dir(info->path)) _dir_load(info->path);
+ else
+ {
+ if (eina_fnmatch("*.over.efm", &(info->path[info->name_start]),
+ EINA_FNMATCH_FILE_NAME))
+ _file_load(info->path);
+ }
+ }
+ }
+ eina_iterator_free(it);
+}
+
+static void
+_data_init(void)
+{ // do
+ char buf[PATH_MAX];
+
+ snprintf(buf, sizeof(buf), "%s/efm/icon_override", _config_dir);
+ _dir_load(buf);
+ snprintf(buf, sizeof(buf), "%s/efm/icon_override", _data_dir);
+ _dir_load(buf);
+}
+
+static const char *
+_hash_find(Eina_Hash *hash, const char *entry, const char *field)
+{
+ Efreet_Ini *ini;
+
+ if (!hash) return NULL;
+ ini = eina_hash_find(hash, entry);
+ if (!ini) return NULL;
+ return eina_hash_find(ini->section, field);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+const char *
+icon_override_path_find(const char *path, const char *field)
+{
+ return _hash_find(_hash_files, path, field);
+}
+
+const char *
+icon_override_mime_find(const char *mime, const char *field)
+{
+ return _hash_find(_hash_mimes, mime, field);
+}
+
+void
+icon_override_init(const char *config_dir, const char *data_dir)
+{
+ _config_dir = eina_stringshare_add(config_dir);
+ _data_dir = eina_stringshare_add(data_dir);
+ _data_init();
+}
+
+void
+icon_override_shutdown(void)
+{
+ eina_stringshare_del(_data_dir);
+ eina_stringshare_del(_config_dir);
+}
diff --git a/src/backends/default/icon_override.h b/src/backends/default/icon_override.h
new file mode 100644
index 0000000..79097a1
--- /dev/null
+++ b/src/backends/default/icon_override.h
@@ -0,0 +1,18 @@
+#ifndef ICON_OVERRIDE_H
+#define ICON_OVERRIDE_H
+#include <Eina.h>
+
+// field is a .desktop file style field like:
+// Icon
+// X-IconClicked
+// X-IconSelected
+// X-IconOver
+// X-IconBadge
+
+const char *icon_override_path_find(const char *path, const char *field);
+const char *icon_override_mime_find(const char *mime, const char *field);
+
+void icon_override_init(const char *config_dir, const char *data_dir);
+void icon_override_shutdown(void);
+
+#endif
\ No newline at end of file
diff --git a/src/backends/default/meson.build b/src/backends/default/meson.build
index af4797a..11c9d0d 100644
--- a/src/backends/default/meson.build
+++ b/src/backends/default/meson.build
@@ -14,6 +14,7 @@ executable('open', [
'../../backends/common/fs_backend_core.c',
'open.c',
'meta.c',
+ 'icon_override.c',
],
include_directories: inc,
dependencies: deps,
diff --git a/src/backends/default/open.c b/src/backends/default/open.c
index 96036f1..e6067a6 100644
--- a/src/backends/default/open.c
+++ b/src/backends/default/open.c
@@ -20,6 +20,7 @@
#include "cmd.h"
#include "sha.h"
#include "meta.h"
+#include "icon_override.h"
#include "thumb_check.h"
#include "esc.h"
#include "util.h"
@@ -71,6 +72,7 @@ typedef struct
static Ecore_File_Monitor *mon = NULL;
static const char *icon_theme = NULL;
static const char *config_dir = NULL;
+static const char *data_dir = NULL;
static const char *home_dir = NULL;
static Eina_Hash *order_hash = NULL;
static Eina_List *sub_queue = NULL;
@@ -758,6 +760,37 @@ _cmd_typebuf_icon_send(const char *icon)
cmd_strbuf_print_consume(strbuf);
}
+static const char *
+_file_add_path_icon_override_find(const char *path, const char *field)
+{
+ const char *icon = icon_override_path_find(path, field);
+ if (!icon)
+ {
+ const char *file = ecore_file_file_get(path);
+
+ if (file) icon = icon_override_path_find(file, field);
+ }
+ return icon;
+}
+
+static void
+_file_add_path_icon_override_field_add(const char *path, Eina_Strbuf *strbuf,
+ const char *or_icon,
+ const char *arg_icon)
+{
+ const char *icon = _file_add_path_icon_override_find(path, or_icon);
+ if (icon) cmd_strbuf_append(strbuf, arg_icon, icon);
+}
+
+static void
+_file_add_mime_icon_override_field_add(const char *mime, Eina_Strbuf *strbuf,
+ const char *or_icon,
+ const char *arg_icon)
+{
+ const char *icon = icon_override_mime_find(mime, or_icon);
+ if (icon) cmd_strbuf_append(strbuf, arg_icon, icon);
+}
+
static void
_file_add_mod_desktop_fields_append(Eina_Strbuf *strbuf, Efreet_Desktop *d,
const char *key_prefix, const char *path,
@@ -869,7 +902,7 @@ _file_add_mod_info(Eina_Strbuf *strbuf, const char *path, Eina_Bool delay)
int mode;
struct passwd *pw;
struct group *gr;
- const char *mime, *ext, *icon, *file;
+ const char *mime = NULL, *ext, *icon, *file;
Efreet_Desktop *desktop;
Eina_Bool have_label = EINA_FALSE;
uintptr_t order;
@@ -1087,14 +1120,39 @@ _file_add_mod_info(Eina_Strbuf *strbuf, const char *path, Eina_Bool delay)
_file_add_mod_meta_append(path, "xy", "meta.xy", strbuf);
_file_add_mod_meta_append(path, "wh", "meta.wh", strbuf);
_file_add_mod_meta_icon_append(path, "icon", "meta.icon", &st, strbuf);
+ _file_add_mod_meta_icon_append(path, "icon-clicked", "meta.icon-clicked", &st,
+ strbuf);
_file_add_mod_meta_icon_append(path, "icon-selected", "meta.icon-selected",
&st, strbuf);
- _file_add_mod_meta_icon_append(path, "icon-clicked", "meta.icon-clicked",
- &st, strbuf);
_file_add_mod_meta_icon_append(path, "icon-over", "meta.icon-over", &st,
strbuf);
_file_add_mod_meta_icon_append(path, "icon-badge", "meta.icon-badge", &st,
strbuf);
+ // handle overrides
+ if (mime)
+ {
+ _file_add_mime_icon_override_field_add(mime, strbuf, "Icon",
+ "override.mime.icon");
+ _file_add_mime_icon_override_field_add(mime, strbuf, "X-IconClicked",
+ "override.mime.icon-clicked");
+ _file_add_mime_icon_override_field_add(mime, strbuf, "X-IconSelected",
+ "override.mime.icon-selected");
+ _file_add_mime_icon_override_field_add(mime, strbuf, "X-IconOver",
+ "override.mime.icon-over");
+ _file_add_mime_icon_override_field_add(mime, strbuf, "X-IconBadge",
+ "override.mime.icon-badge");
+ }
+ _file_add_path_icon_override_field_add(path, strbuf, "Icon",
+ "override.file.icon");
+ _file_add_path_icon_override_field_add(path, strbuf, "X-IconClicked",
+ "override.file.icon-clicked");
+ _file_add_path_icon_override_field_add(path, strbuf, "X-IconSelected",
+ "override.file.icon-selected");
+ _file_add_path_icon_override_field_add(path, strbuf, "X-IconOver",
+ "override.file.icon-over");
+ _file_add_path_icon_override_field_add(path, strbuf, "X-IconBadge",
+ "override.file.icon-badge");
+
// get order index number if any
order = _order_index_get(file);
if (order > 0)
@@ -1982,6 +2040,7 @@ int do_init(int argc EINA_UNUSED, const char **argv EINA_UNUSED)
icon_theme = getenv("E_ICON_THEME");
config_dir = getenv("E_HOME_DIR");
+ data_dir = getenv("E_DATA_DIR");
home_dir = getenv("HOME");
if (!home_dir) return 77; // no $HOME? definitely an error!
if (!config_dir)
@@ -1991,6 +2050,10 @@ int do_init(int argc EINA_UNUSED, const char **argv EINA_UNUSED)
snprintf(buf, sizeof(buf), "%s/.e/e", home_dir);
config_dir = eina_stringshare_add(buf);
}
+ if (!data_dir)
+ {
+ data_dir = eina_stringshare_add("/usr/local/share/enlightenment");
+ }
s = getenv("EFM_OPEN_AUTOEXIT");
if ((s) && (atoi(s) == 1)) auto_exit = EINA_TRUE;
@@ -2005,6 +2068,7 @@ int do_init(int argc EINA_UNUSED, const char **argv EINA_UNUSED)
if (thumb_busy_max < 1) thumb_busy_max = 1;
meta_init(config_dir);
+ icon_override_init(config_dir, data_dir);
// we want to listen for when thumbnails slaves finish
thumb_exe_del_handler
@@ -2027,6 +2091,7 @@ do_shutdown(void)
if (mon) ecore_file_monitor_del(mon);
mon = NULL;
+ icon_override_shutdown();
meta_shutdown();
efreet_mime_shutdown();
diff --git a/src/efm/efm_back_end.c b/src/efm/efm_back_end.c
index f28c02b..59fe716 100644
--- a/src/efm/efm_back_end.c
+++ b/src/efm/efm_back_end.c
@@ -394,6 +394,27 @@ _icon_add_mod_props_get(Icon *icon, Cmd *c, const char *label)
if (s) eina_stringshare_replace(&(icon->info.icon_over), s);
s = cmd_key_find(c, "meta.icon-badge");
if (s) eina_stringshare_replace(&(icon->info.icon_badge), s);
+ s = cmd_key_find(c, "override.mime.icon");
+ if (s) _icon_meta_override(icon, s);
+ s = cmd_key_find(c, "override.mime.icon-clicked");
+ if (s) eina_stringshare_replace(&(icon->info.icon_clicked), s);
+ s = cmd_key_find(c, "override.mine.icon-selected");
+ if (s) eina_stringshare_replace(&(icon->info.icon_selected), s);
+ s = cmd_key_find(c, "override.mine.icon-over");
+ if (s) eina_stringshare_replace(&(icon->info.icon_over), s);
+ s = cmd_key_find(c, "override.mine.icon-badge");
+ if (s) eina_stringshare_replace(&(icon->info.icon_badge), s);
+ s = cmd_key_find(c, "override.file.icon");
+ if (s) _icon_meta_override(icon, s);
+ s = cmd_key_find(c, "override.file.icon-clicked");
+ if (s) eina_stringshare_replace(&(icon->info.icon_clicked), s);
+ s = cmd_key_find(c, "override.file.icon-selected");
+ if (s) eina_stringshare_replace(&(icon->info.icon_selected), s);
+ s = cmd_key_find(c, "override.file.icon-over");
+ if (s) eina_stringshare_replace(&(icon->info.icon_over), s);
+ s = cmd_key_find(c, "override.file.icon-badge");
+ if (s) eina_stringshare_replace(&(icon->info.icon_badge), s);
+
s = cmd_key_find(c, "broken-link");
if ((s) && (!strcmp(s, "true"))) icon->info.broken = EINA_TRUE;
else icon->info.broken = EINA_FALSE;
diff --git a/src/efm/efm_graph.c b/src/efm/efm_graph.c
index 0efdf78..84dbe04 100644
--- a/src/efm/efm_graph.c
+++ b/src/efm/efm_graph.c
@@ -27,7 +27,7 @@ static Evas_Smart_Class _sc_parent = EVAS_SMART_CLASS_INIT_NULL;
#define ENTRY \
Smart_Data *sd = evas_object_smart_data_get(obj); \
- if (!sd) return
+ if ((!sd) || (evas_object_smart_smart_get(obj) != _smart)) return
static void
_clear(Smart_Data *sd)
diff --git a/src/efm/efm_icon.c b/src/efm/efm_icon.c
index e059652..5f84bc7 100644
--- a/src/efm/efm_icon.c
+++ b/src/efm/efm_icon.c
@@ -67,7 +67,7 @@ static const int _svg_sizes[]
#define ENTRY \
Smart_Data *sd = evas_object_smart_data_get(obj); \
- if (!sd) return
+ if ((!sd) || (evas_object_smart_smart_get(obj) != _smart)) return
static void
_image_add(Smart_Data *sd)
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.