-- -- Provides: -- bling::task_preview::visibility -- s (screen) -- v (boolean) -- c (client) -- local awful = require("awful") local wibox = require("wibox") local helpers = require(tostring(...):match(".*bling") .. ".helpers") local gears = require("gears") local beautiful = require("beautiful") local dpi = beautiful.xresources.apply_dpi local cairo = require("lgi").cairo -- TODO: rename structure to something better? local function draw_widget( c, widget_template, screen_radius, widget_bg, widget_border_color, widget_border_width, margin, widget_width, widget_height ) if not pcall(function() return type(c.content) end) then return end local content = nil if c.active then content = gears.surface(c.content) elseif c.prev_content then content = gears.surface(c.prev_content) end local img = nil if content ~= nil then local cr = cairo.Context(content) local x, y, w, h = cr:clip_extents() img = cairo.ImageSurface.create(cairo.Format.ARGB32, w - x, h - y) cr = cairo.Context(img) cr:set_source_surface(content, 0, 0) cr.operator = cairo.Operator.SOURCE cr:paint() end local widget = wibox.widget({ (widget_template or { { { { { id = "icon_role", resize = true, forced_height = dpi(20), forced_width = dpi(20), widget = wibox.widget.imagebox, }, { { id = "name_role", align = "center", widget = wibox.widget.textbox, }, left = dpi(4), right = dpi(4), widget = wibox.container.margin, }, layout = wibox.layout.align.horizontal, }, { { { id = "image_role", resize = true, clip_shape = helpers.shape.rrect(screen_radius), widget = wibox.widget.imagebox, }, valign = "center", halign = "center", widget = wibox.container.place, }, top = margin * 0.25, widget = wibox.container.margin, }, fill_space = true, layout = wibox.layout.fixed.vertical, }, margins = margin, widget = wibox.container.margin, }, bg = widget_bg, shape_border_width = widget_border_width, shape_border_color = widget_border_color, shape = helpers.shape.rrect(screen_radius), widget = wibox.container.background, }), width = widget_width, height = widget_height, widget = wibox.container.constraint, }) -- TODO: have something like a create callback here? for _, w in ipairs(widget:get_children_by_id("image_role")) do w.image = img -- TODO: copy it with gears.surface.xxx or something end for _, w in ipairs(widget:get_children_by_id("name_role")) do w.text = c.name end for _, w in ipairs(widget:get_children_by_id("icon_role")) do w.image = c.icon -- TODO: detect clienticon end return widget end local enable = function(opts) local opts = opts or {} local widget_x = opts.x or dpi(20) local widget_y = opts.y or dpi(20) local widget_height = opts.height or dpi(200) local widget_width = opts.width or dpi(200) local placement_fn = opts.placement_fn or nil local margin = beautiful.task_preview_widget_margin or dpi(0) local screen_radius = beautiful.task_preview_widget_border_radius or dpi(0) local widget_bg = beautiful.task_preview_widget_bg or "#000000" local widget_border_color = beautiful.task_preview_widget_border_color or "#ffffff" local widget_border_width = beautiful.task_preview_widget_border_width or dpi(3) local task_preview_box = awful.popup({ type = "dropdown_menu", visible = false, ontop = true, placement = placement_fn, widget = wibox.container.background, -- A dummy widget to make awful.popup not scream input_passthrough = true, bg = "#00000000", }) tag.connect_signal("property::selected", function(t) -- Awesome switches up tags on startup really fast it seems, probably depends on what rules you have set -- which can cause the c.content to not show the correct image gears.timer { timeout = 0.1, call_now = false, autostart = true, single_shot = true, callback = function() if t.selected == true then for _, c in ipairs(t:clients()) do c.prev_content = gears.surface.duplicate_surface(c.content) end end end } end) awesome.connect_signal("bling::task_preview::visibility", function(s, v, c) if v then -- Update task preview contents task_preview_box.widget = draw_widget( c, opts.structure, screen_radius, widget_bg, widget_border_color, widget_border_width, margin, widget_width, widget_height ) else task_preview_box.widget = nil collectgarbage("collect") end if not placement_fn then task_preview_box.x = s.geometry.x + widget_x task_preview_box.y = s.geometry.y + widget_y end task_preview_box.visible = v end) end return { enable = enable, draw_widget = draw_widget }