only operate on surface copies

Working with icons is tricky because their surfaces do not use reference counting correctly. If gears.surface(c.icon) is called multiple time on the same icon, it will cause a double-free error and Awesome will crash.
This commit is contained in:
BZ 2021-02-02 17:26:36 +01:00
parent 7b37f7eece
commit 0afab7248e
1 changed files with 98 additions and 72 deletions

View File

@ -1,16 +1,20 @@
local gears = require("gears")
local awful = require("awful")
local theme = require("beautiful")
local cairo = require("lgi").cairo
local module = {}
-- luacheck: globals client
local client = client
local icons, dynamic_icons, dynamic_classes, delay
local function len(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
for _ in pairs(T) do
count = count + 1
end
return count
end
@ -23,14 +27,26 @@ local function contains(T, V)
return false
end
local function icon_copy(icon)
if not icon then
return nil
end
local s = gears.surface(icon)
local img = cairo.ImageSurface.create(cairo.Format.ARGB32, s:get_width(), s:get_height())
local cr = cairo.Context(img)
cr:set_source_surface(s, 0, 0)
cr:paint()
return img
end
local function set_icon(c, icon)
if c and c.valid then
if not c.icon_backup then
c.icon_backup = icons[c.class] and gears.surface(icons[c.class]) or gears.surface(c.icon)
c.icon_backup = icon_copy(icons[c.class]) or icon_copy(c.icon)
end
icon = icon_copy(icon)
if icon then
icon = gears.surface(icon)
c.icon = icon and icon._native or nil
c.icon = icon._native
end
end
end
@ -46,7 +62,7 @@ local function set_dynamic_icon(c)
end
if c.icon_backup then
c.icon = c.icon_backup and c.icon_backup._native or nil
c.icon = c.icon_backup._native or nil
end
end
@ -58,10 +74,18 @@ local function setup(config)
dynamic_classes = cfg.dynamic_classes or theme.ic_dynamic_classes or {}
delay = cfg.delay or 0.5
if type(icons) ~= 'table' then icons = {} end
if type(dynamic_icons) ~= 'table' then dynamic_icons = {} end
if type(dynamic_classes) ~= 'table' then dynamic_classes = {} end
if type(delay) ~= 'number' then delay = 0.5 end
if type(icons) ~= 'table' then
icons = {}
end
if type(dynamic_icons) ~= 'table' then
dynamic_icons = {}
end
if type(dynamic_classes) ~= 'table' then
dynamic_classes = {}
end
if type(delay) ~= 'number' then
delay = 0.5
end
client.connect_signal("manage", function(c)
-- set icon based on c.class
@ -89,7 +113,8 @@ local function setup(config)
end)
end
return setmetatable(module, { __call = function(_, ...)
return setmetatable(module, {
__call = function(_, ...)
setup(...)
-- we have to update all clients icons manually when the user restarts awesomewm
-- since there is no "property::name" signal emitted by already running clients.
@ -101,4 +126,5 @@ return setmetatable(module, { __call = function(_, ...)
end
end
end)
end })
end
})