Search code examples
luaawesome-wm

I cannot catch mouse signals on widgets within a wibox.container.scroll


I am constructing widgets dynamically from from the output of iw dev interface scan I then add them to a scroll box held in a wibox. The problem I find is that the mouse::enter and mouse::leave signals I connect the widgets to do not catch the mouse signals when inside the wibox.container.scroll. All the rest of the code works as intended and the signals are caught as intended if I omit the wibox.container.scroll wrapper.

The widget template to be added to the scroll container:

function wifitbox.new(ssid, screen, interface)
    tbox = wibox.widget{
        {
            {
                wibox.widget.textbox(ssid[2] .. " " .. ssid[3]),
                {
                    wibox.widget.textbox(ssid[4]),
                    halign = "right",
                    widget = wibox.container.place
                },
                layout = wibox.layout.ratio.horizontal
            },
            margins = beautiful.xresources.apply_dpi(10, screen),
            widget = wibox.container.margin
        },
        id = "tbox",
        bg = beautiful.wifi_tbox_bg or "#928374",   
        shape = function(cr, width, height)
            gears.shape.rounded_rect(cr, width, height, 5)
        end,
        widget = wibox.container.background
    }

    awful.spawn.easy_async('bash -c "sudo iw dev ' .. interface .. ' station dump | awk \'FNR == 1 {print($2)}\'"', function(stdout)
        if(gears.string.split(stdout, "\n")[1] == ssid[1]) then
            tbox.bg = "#b16286"
        end
    end)

    tbox:connect_signal("mouse::enter", function()
        tbox.bg_cache = tbox.bg
        tbox.bg = "#689d6a"
    end)

    tbox:connect_signal("mouse::leave", function()
        tbox.bg = tbox.bg_cache
    end)

    return tbox
end

The two :signal_connect() statements are the ones in questions.

The widgets are added to the scroll container a follows:

    awful.spawn.with_line_callback(cmd, {
            stdout = function(line)
                local ssid = gears.string.split(line, "\t")
                wifitbox_table:get_children_by_id("tbox_list")[1]:add(wifitbox(ssid, screen, interface))
            end,
            output_done = function()
                self:set_widget(wifitbox_table)
            end
        })

The widget the containing the scroll container is as follows:

local wifitbox_table = wibox.widget{ 
        scrollbtn,
    {
        id = "scroll_box",
        speed = 100,
        extra_space = beautiful.xresources.apply_dpi(5, screen),
        layout = wibox.container.scroll.vertical,
        step_function = wibox.container.scroll.step_functions.linear_increase,
        {
            id= "tbox_list",
            spacing = beautiful.xresources.apply_dpi(5, screen),
            layout = wibox.layout.fixed.vertical()
        }
    },
    spacing = beautiful.xresources.apply_dpi(5, screen),
    layout = wibox.layout.fixed.vertical,
}

As I mentioned before if i remove the "scroll_box" widget around the "tbox_list" widget the signals connect without issue. But then obviously I don't get scrolling.

And finally all of it put together:

local awful = require('awful')
local wibox = require('wibox')
local gears = require('gears')
local beautiful = require('beautiful')

local wifimodal = { mt = {} }
local wifitbox = { mt = {} }
local setmetatable = setmetatable

function wifitbox.new(ssid, screen, interface)
    tbox = wibox.widget{
        {
            {
                wibox.widget.textbox(ssid[2] .. " " .. ssid[3]),
                {
                    wibox.widget.textbox(ssid[4]),
                    halign = "right",
                    widget = wibox.container.place
                },
                layout = wibox.layout.ratio.horizontal
            },
            margins = beautiful.xresources.apply_dpi(10, screen),
            widget = wibox.container.margin
        },
        id = "tbox",
        bg = beautiful.wifi_tbox_bg or "#928374",   
        shape = function(cr, width, height)
            gears.shape.rounded_rect(cr, width, height, 5)
        end,
        widget = wibox.container.background,
    }

    awful.spawn.easy_async('bash -c "sudo iw dev ' .. interface .. ' station dump | awk \'FNR == 1 {print($2)}\'"', function(stdout)
        if(gears.string.split(stdout, "\n")[1] == ssid[1]) then
            tbox.bg = "#b16286"
        end
    end)

    tbox:connect_signal("mouse::enter", function()
        tbox.bg_cache = tbox.bg
        tbox.bg = "#689d6a"
    end)

    tbox:connect_signal("mouse::leave", function()
        tbox.bg = tbox.bg_cache
    end)

    return tbox
end

function wifitbox.mt.__call(_, ...)
    return wifitbox.new(...)
end

setmetatable(wifitbox, wifitbox.mt)

function wifimodal.new(screen, interface, curSSID)

    self = wibox {
        screen = screen,
        width = screen.geometry.width / 5,
        type = 'modal',
        height = screen.workarea.height/2,
        x = screen.geometry.width - screen.geometry.width/5,
        y = beautiful.xresources.apply_dpi(beautiful.wibar_height or 25, screen),
        ontop = true,
        visible = true,
        bg = beautiful.bg_normal,
        fg = "black",
        opacity = 0.8,
        shape = function(cr, width, height)
            gears.shape.rounded_rect(cr, width, height, 5)
        end
    }

    self:connect_signal('mouse::leave', function()
        self.visible = false
        self = nil
    end)

    local scrollbtn = wibox.widget{
        {
            {
                widget = wibox.widget.imagebox,
                resize = true,
                image = gears.filesystem.get_configuration_dir() .. "widgets/wifi/arrow_up.png",
                forced_height = beautiful.xresources.apply_dpi(25, screen),
            },
            widget = wibox.container.place,
            valign = "center",
        },
        shape = function(cr, width, height)
            gears.shape.rounded_rect(cr, width, height, 5)
        end,
        widget = wibox.container.background,
        bg = beautiful.wifi_scroll_btn_bg or "#d79921",
    }

    scrollbtn:connect_signal("mouse::enter", function()
        scrollbtn:emit_signal_recursive("scroll::continue")
        scrollbtn.bg = beautiful.wifi_scroll_btn_bg_hover or "#458588"
    end)

    scrollbtn:connect_signal("mouse::leave", function()
        scrollbtn:emit_signal_recursive("scroll::pause")
        scrollbtn.bg = beautiful.wifi_scroll_btn_bg or "#d79921"
    end)

    local scan_awk = gears.filesystem.get_configuration_dir() .. "widgets/wifi/scan.awk"
    local cmd = 'bash -c "sudo iw ' .. interface .. ' scan | awk -f ' .. scan_awk .. '"'
    local wifitbox_table = wibox.widget{ 
            scrollbtn,
        {
            id = "scroll_box",
            speed = 100,
            extra_space = beautiful.xresources.apply_dpi(5, screen),
            layout = wibox.container.scroll.vertical,
            step_function = wibox.container.scroll.step_functions.linear_increase,
            {
                id= "tbox_list",
                spacing = beautiful.xresources.apply_dpi(5, screen),
                layout = wibox.layout.fixed.vertical()
            }
        },
        spacing = beautiful.xresources.apply_dpi(5, screen),
        layout = wibox.layout.fixed.vertical,
    }

    local scrollbox = wifitbox_table:get_children_by_id("scroll_box")[1]
    scrollbox:pause()

    wifitbox_table:connect_signal("scroll::continue", function()
        scrollbox:continue()
    end)

    wifitbox_table:connect_signal("scroll::pause", function()
        scrollbox:pause()
    end)

    awful.spawn.with_line_callback(cmd, {
            stdout = function(line)
                local ssid = gears.string.split(line, "\t")
                wifitbox_table:get_children_by_id("tbox_list")[1]:add(wifitbox(ssid, screen, interface))
            end,
            output_done = function()
                self:set_widget(wifitbox_table)
            end
        })


    return self
end

function wifimodal.mt.__call(_, ...)
    return wifimodal.new(...)
end

return setmetatable(wifimodal, wifimodal.mt)

Here is a screen shot for some context:

enter image description here

Also, if you don't have the answer but notice something else you can critic feel free. Thank you


Solution

  • The problem I find is that the mouse::enter and mouse::leave signals I connect the widgets to do not catch the mouse signals when inside the wibox.container.scroll

    The third sentence on https://awesomewm.org/doc/api/classes/wibox.container.scroll.html is:

    Please note that mouse events do not propagate to widgets inside of the scroll container.

    So, this is "working as intended".

    Also: https://github.com/awesomeWM/awesome/issues/3076