I am attempting to make a pop-up that displays window previews as a tasklist and have almost gotten it, but for a couple of things.
I first added a tasklist that used a clienticon widget to group classes and added a button trigger to launch the pop-up widget. Here is my tasklist code:
function theme.at_screen_connect(s)
...
-- Create an icon only tasklist widget
s.mytasklist = awful.widget.tasklist {
screen = s,
filter = awful.widget.tasklist.filter.currenttags,
source = function()
-- Get all clients
local cls = client.get()
-- Filter by an existing filter function and allowing only one client per class
local result = {}
local class_seen = {}
local class_num = 0
local class_index = {}
for _, c in pairs(cls) do
if awful.widget.tasklist.filter.currenttags(c, s) then
if not class_seen[c.class] then
class_seen[c.class] = true
class_index[c.class] = class_num
class_num = class_num + 1
table.insert(result, c)
end
end
end
return result
end,
-- buttons = awful.util.tasklist_buttons,
--buttons = awful.button({ }, 1, tasklistButton(c)),
buttons = awful.button({ }, 1, function (c)
local client_num=0
for i, cl in pairs(client.get()) do
if cl.class == c.class then
if cl.screen == c.screen then
client_num = client_num + 1
end
end
end
if client_num > 1 then
if cl_menu then
if cl_menu_class == c.class then
cl_menu.visible = false
cl_menu=nil
else
cl_menu.visible = false
cl_menu=nil
cl_menu_class = c.class
cl_menu=clientClassPopup(c)
cl_menu.visible=true
end
else
cl_menu_class = c.class
cl_menu=clientClassPopup(c)
cl_menu.visible=true
end
else
if cl_menu then
cl_menu.visible = false
cl_menu = nil
end
if client.focus == c then
c.minimized = true
else
client.focus = c
awful.tag.viewonly(c:tags()[1])
c:raise()
end
end
end),
layout = {
spacing_widget = {
{
forced_width = 24,
forced_height = 1,
thickness = 1,
color = '#BBBBBB',
widget = wibox.widget.separator
},
valign = 'center',
halign = 'center',
widget = wibox.container.place,
},
spacing = 2,
layout = wibox.layout.fixed.vertical
},
-- Notice that there is *NO* wibox.wibox prefix, it is a template,
-- not a widget instance.
widget_template = {
{
wibox.widget.base.make_widget(),
forced_width = 1,
id = 'background_role',
widget = wibox.container.background,
},
{
{
id = 'clienticon',
widget = awful.widget.clienticon,
},
margins = 4,
widget = wibox.container.margin
},
nil,
create_callback = function(self, c, index, objects) --luacheck: no unused args
self:get_children_by_id('clienticon')[1].client = c
end,
layout = wibox.layout.align.horizontal,
},
}
...
-- Create the wibox
-- s.mywibox_left = awful.wibar({ position = "left", screen = s, width = dpi(36), bg = gears.color.create_linear_pattern("linear:0,0:0,5:0,#ff0000:1,#0000ff"), fg = theme.fg_normal })
s.mywibox_left = awful.wibar({ position = "left", screen = s, width = dpi(48), bg = theme.bg_normal, fg = theme.fg_normal })
-- Add widgets to the wibox
s.mywibox_left:setup {
layout = wibox.layout.align.vertical,
small_spr,
s.mytasklist,
}
...
end
From the code you can see that clicking on the tasklist class item triggers a function that handles the pop-up menu. Here is the function code:
function clientClassPopup(c)
client_class_grid = wibox.widget {
expand = false,
forced_num_cols = 1,
spacing = 1,
vertical_spacing = 1,
layout = wibox.layout.grid,
}
client_class_popup = awful.popup({
screen = c.screen,
widget = client_class_grid,
shape = gears.shape.rounded_rect,
border_width = 1,
border_color = theme.fg_focus,
ontop = true,
visible = false,
})
client_class_popup:connect_signal('mouse::leave', function(self)
self.visible = false
end)
class_count = 0
client_index = 0
class_seen = {}
class_index = {}
for i, cl in pairs(client.get()) do
if not class_seen[cl.class] then
class_seen[cl.class] = true
class_index[cl.class] = class_count
class_count = class_count + 1
end
if cl.class == c.class then
if cl.screen == c.screen then
size = 256
local surface = cairo.ImageSurface(cairo.Format.RGB24,20,20)
local cr = cairo.Context(surface)
local s, geo = gears.surface(cl.content), cl:geometry()
local scale = math.min(size/geo.width, size/geo.height)
local w, h = geo.width*scale, geo.height*scale
local dx, dy = (size-w)/2, (size-h)/2
client_tasklist_item = wibox.widget.imagebox()
client_tasklist_item.fit = function(context, width, height)
return 100, 100
end
client_tasklist_item.fit = function(self, context, width, height)
local size = math.min(width, height)
return size, size
end
client_tasklist_item.set_client = function(self, cl)
ret._private.client[1] = cl
self:emit_signal("widget::redraw_needed")
end
client_tasklist_item.draw = function(self, content, cr, width, height)
--cr:translate(dx, dy)
gears.shape.rounded_rect(cr, w, h, 10)
cr:clip()
cr:scale(scale, scale)
cr:set_source_surface(s)
cr:paint()
end
client_tasklist_item.new = function(cl)
local ret = wibox.widget.base.make_widget(nil, nil, {
enable_properties = true,
})
rawset(ret, "fit" , fit )
rawset(ret, "draw" , draw )
rawset(ret, "set_client", set_client)
ret._private.client = setmetatable({cl}, {__mode="v"})
return ret
end
client_tasklist_item.forced_width = w
client_tasklist_item.forced_height = h
client_tasklist_item:buttons(my_table.join(
awful.button({}, 1, function ()
if client.focus == cl then
cl.minimized=true
client_class_popup.visible=false
else
client.focus = cl
cl:raise()
client_class_popup.visible=false
end
end)
)
)
bg_client_tasklist_item = wibox.widget{
client_tasklist_item,
bg = theme.bg_normal,
resize = true,
shape = gears.shape.rounded_rect,
widget = wibox.container.background
}
client_class_grid:add(bg_client_tasklist_item)
client_index = client_index + 1
end
end
end
return client_class_popup
end
The function launches a pop-up with a grid layout and then iterates through clients on the screen and adds an imagebox widget painted with a cairo surface of the client window contents and adds button and hover behaviour My issue comes from minimized clients. When a client is minimized the contents aren’t drawable and the box is blank.
I have tried numerous things to fix this including trying multiple different compositors for Awesome WM. I am running Arch Linux if that helps. In particular I am curious if there is something I am missing in creating the tasklist that would allow me to get the client contents even when minimized when utilizing a compositor.
Any and all help much appreciated and apologies for the hacky code. LUA and cairo are not my expertise.
Thank you.
-Robert
Robert Nielsen is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.