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.

Reply via email to