Reworked a whole lot. New config file and theme config file for easier changes. Did #19. And much more
This commit is contained in:
236
awesome/src/tools/xdg_icon_lookup.lua
Normal file
236
awesome/src/tools/xdg_icon_lookup.lua
Normal file
@@ -0,0 +1,236 @@
|
||||
-----------------------------------------------------
|
||||
-- Helper to get icons from a program/program name --
|
||||
-----------------------------------------------------
|
||||
|
||||
local gears = require("gears")
|
||||
local GLib = require("lgi").GLib
|
||||
|
||||
local theme_index = require("src.tools.theme_index")
|
||||
|
||||
local function get_basedir()
|
||||
local dirs = {}
|
||||
|
||||
local dir = GLib.build_filenamev({ GLib.get_home_dir(), ".icons" })
|
||||
if gears.filesystem.dir_readable(dir) then
|
||||
table.insert(dirs, dir)
|
||||
end
|
||||
|
||||
dir = GLib.build_filenamev({ GLib.get_user_data_dir(), "icons" })
|
||||
if gears.filesystem.dir_readable(dir) then table.insert(dirs, dir) end
|
||||
|
||||
for _, value in ipairs(GLib.get_system_data_dirs()) do
|
||||
dir = GLib.build_filenamev({ value, ".icons" })
|
||||
if gears.filesystem.dir_readable(dir) then table.insert(dirs, dir) end
|
||||
end
|
||||
|
||||
local need_usr_share_pixmaps = true
|
||||
for _, value in ipairs(GLib.get_system_data_dirs()) do
|
||||
dir = GLib.build_filenamev({ value, ".icons" })
|
||||
if gears.filesystem.dir_readable(dir) then table.insert(dirs, dir) end
|
||||
if dir == "/usr/share/pixmaps" then
|
||||
need_usr_share_pixmaps = false
|
||||
end
|
||||
end
|
||||
|
||||
dir = "/usr/share/pixmaps"
|
||||
if gears.filesystem.dir_readable(dir) then table.insert(dirs, dir) end
|
||||
if need_usr_share_pixmaps and gears.filesystem.dir_readable(dir) then
|
||||
table.insert(dirs, dir)
|
||||
end
|
||||
|
||||
table.insert(dirs, "/usr/share/icons")
|
||||
|
||||
return dirs
|
||||
end
|
||||
|
||||
local xdg_icon_lookup = { mt = {} }
|
||||
|
||||
local icon_cache = {}
|
||||
|
||||
xdg_icon_lookup.new = function(theme, base_dirs)
|
||||
local self = {}
|
||||
|
||||
self.icon_theme = theme or User_config.icon_theme
|
||||
self.base_directories = base_dirs or get_basedir()
|
||||
self.file_extension = { "svg", "png", "xpm" }
|
||||
|
||||
if not icon_cache[self.icon_theme] then
|
||||
icon_cache[self.icon_theme] = {}
|
||||
end
|
||||
|
||||
local cache_key = table.concat(self.base_directories, ":")
|
||||
if not icon_cache[self.icon_theme][cache_key] then
|
||||
icon_cache[self.icon_theme][cache_key] = theme_index(self.icon_theme, self.base_directories)
|
||||
end
|
||||
self.theme_index = icon_cache[self.icon_theme][cache_key]
|
||||
|
||||
return setmetatable(self, { __index = xdg_icon_lookup })
|
||||
end
|
||||
|
||||
---Look for an fallback icon
|
||||
---@param iconname any
|
||||
---@return string
|
||||
local function lookup_fallback_icon(self, iconname)
|
||||
for _, dir in ipairs(self.base_directories) do
|
||||
for _, ext in ipairs(self.file_extension) do
|
||||
local filename = string.format("%s/%s.%s", dir, iconname, ext)
|
||||
if gears.filesystem.file_readable(filename) then
|
||||
return filename
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Checkes if the size equals the actual icon size
|
||||
---@param subdir any
|
||||
---@param iconsize any
|
||||
---@return boolean
|
||||
local function directory_matches_size(self, subdir, iconsize)
|
||||
local type, size, min_size, max_size, threshold = self.theme_index.per_directory_keys[subdir]["Type"],
|
||||
self.theme_index.per_directory_keys[subdir]["Size"], self.theme_index.per_directory_keys[subdir]["MinSize"],
|
||||
self.theme_index.per_directory_keys[subdir]["MaxSize"], self.theme_index.per_directory_keys[subdir]["Threshold"]
|
||||
|
||||
if type == "Fixed" then
|
||||
return iconsize == size
|
||||
elseif type == "Scalable" then
|
||||
return iconsize >= min_size and iconsize <= max_size
|
||||
elseif type == "Threshold" then
|
||||
return iconsize >= size - threshold and iconsize <= size + threshold
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
---Returns how far off the size is from the actual icon size
|
||||
---@param subdir table
|
||||
---@param iconsize number
|
||||
---@return number
|
||||
local function directory_size_distance(self, subdir, iconsize)
|
||||
local type, size, min_size, max_size, threshold = self.theme_index.per_directory_keys[subdir]["Type"],
|
||||
self.theme_index.per_directory_keys[subdir]["Size"], self.theme_index.per_directory_keys[subdir]["MinSize"],
|
||||
self.theme_index.per_directory_keys[subdir]["MaxSize"], self.theme_index.per_directory_keys[subdir]["Threshold"]
|
||||
|
||||
if type and min_size and max_size and threshold then
|
||||
if type == "Fixed" then
|
||||
return math.abs(size - iconsize)
|
||||
elseif type == "Scalable" then
|
||||
if iconsize < min_size then
|
||||
return min_size - iconsize
|
||||
elseif iconsize > max_size then
|
||||
return iconsize - max_size
|
||||
end
|
||||
return 0
|
||||
elseif type == "Threshold" then
|
||||
if iconsize < size - threshold then
|
||||
return min_size - iconsize
|
||||
elseif iconsize > size + threshold then
|
||||
return iconsize - max_size
|
||||
end
|
||||
return 0
|
||||
end
|
||||
end
|
||||
return 0xffffffff
|
||||
end
|
||||
|
||||
---Checks each and every sub directory for an icon
|
||||
---@param iconname any
|
||||
---@param size any
|
||||
---@return string path_to_icon
|
||||
local function lookup_icon(self, iconname, size)
|
||||
local already_checked = {}
|
||||
for _, subdir in ipairs(self.theme_index:get_subdirectories()) do
|
||||
for _, dir in ipairs(self.base_directories) do
|
||||
for _, ext in ipairs(self.file_extension) do
|
||||
if directory_matches_size(self, subdir, size) then
|
||||
local filename = string.format("%s/%s/%s/%s.%s", dir, self.icon_theme, subdir, iconname, ext)
|
||||
if gears.filesystem.file_readable(filename) then
|
||||
return filename
|
||||
else
|
||||
already_checked[filename] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local min_size = 0xffffffff
|
||||
local closest_filename = nil
|
||||
for _, subdir in ipairs(self.theme_index:get_subdirectories()) do
|
||||
local dist = directory_size_distance(self, subdir, size)
|
||||
if dist < min_size then
|
||||
for _, dir in ipairs(self.base_directories) do
|
||||
for _, ext in ipairs(self.file_extension) do
|
||||
local filename = string.format("%s/%s/%s/%s.%s", dir, self.icon_theme, subdir, iconname, ext)
|
||||
if not already_checked[filename] then
|
||||
if gears.filesystem.file_readable(filename) then
|
||||
closest_filename = filename
|
||||
min_size = dist
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return closest_filename or nil
|
||||
end
|
||||
|
||||
---Check if the icon inherits from another icon theme and search that for an icon
|
||||
---@param icon any
|
||||
---@param size any
|
||||
---@param self any
|
||||
---@return string path_to_icon
|
||||
local function find_icon_helper(self, icon, size)
|
||||
local filename = lookup_icon(self, icon, size)
|
||||
if filename then return filename end
|
||||
|
||||
filename = lookup_icon(self, icon:lower(), size)
|
||||
if filename then return filename end
|
||||
|
||||
for _, parent in ipairs(self.theme_index:get_inherits()) do
|
||||
filename = find_icon_helper(xdg_icon_lookup(parent, self.base_directories), icon, size)
|
||||
if filename then return filename end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local iconcache = {}
|
||||
---Takes an icon and its props and theme to search for it inside the theme
|
||||
---@param icon any
|
||||
---@param size any
|
||||
---@return string path_to_icon
|
||||
function xdg_icon_lookup:find_icon(icon, size)
|
||||
if iconcache[icon] then
|
||||
return iconcache[icon]
|
||||
end
|
||||
size = size or 64
|
||||
if not icon or icon == "" then return nil end
|
||||
|
||||
local filename = find_icon_helper(self, icon, size)
|
||||
if filename then
|
||||
iconcache[icon] = filename
|
||||
return filename
|
||||
end
|
||||
|
||||
filename = find_icon_helper(xdg_icon_lookup("hicolor", self.base_directories), icon, size)
|
||||
if filename then
|
||||
iconcache[icon] = filename
|
||||
return filename
|
||||
end
|
||||
|
||||
filename = lookup_fallback_icon(self, icon)
|
||||
if filename then
|
||||
iconcache[icon] = filename
|
||||
return filename
|
||||
end
|
||||
|
||||
local fallback = gears.color.recolor_image(require("awful").util.getdir("config") .. "src/assets/icons/fallback.svg",
|
||||
"#ffffff")
|
||||
iconcache[icon] = fallback
|
||||
return fallback
|
||||
end
|
||||
|
||||
xdg_icon_lookup.mt.__call = function(_, ...)
|
||||
return xdg_icon_lookup.new(...)
|
||||
end
|
||||
|
||||
return setmetatable(xdg_icon_lookup, xdg_icon_lookup.mt)
|
||||
Reference in New Issue
Block a user