Multi-row support of systray by taking a beautiful variable specifying the maximum number of rows to fill per column. (#3520)
Also, fix the fitting logic so that the result width and height are fitted in the available space. Previously the result dimensions can be larger than the input, but cropped in e7a21947e6/lib/wibox/widget/base.lua (L547)
. But still it can cause problems e.g. when used inside wibox.container.place.
This commit is contained in:
parent
7451c6952e
commit
b49a53f6dd
|
@ -30,6 +30,13 @@ local display_on_screen = "primary"
|
|||
-- @beautiful beautiful.bg_systray
|
||||
-- @param string The color (string like "#ff0000" only)
|
||||
|
||||
--- The maximum number of rows for systray icons. Icons will fill the
|
||||
-- current column (orthogonally to the systray direction) before
|
||||
-- filling the next column.
|
||||
--
|
||||
-- @beautiful beautiful.systray_max_rows
|
||||
-- @tparam[opt=1] integer The positive number of rows
|
||||
|
||||
--- The systray icon spacing.
|
||||
--
|
||||
-- @beautiful beautiful.systray_icon_spacing
|
||||
|
@ -49,6 +56,9 @@ function systray:draw(context, cr, width, height)
|
|||
|
||||
local x, y, _, _ = wbase.rect_to_device_geometry(cr, 0, 0, width, height)
|
||||
local num_entries = capi.awesome.systray()
|
||||
local max_rows = math.floor(tonumber(beautiful.systray_max_rows) or 1)
|
||||
local rows = math.max(math.min(num_entries, max_rows), 1)
|
||||
local cols = math.ceil(num_entries / rows)
|
||||
local bg = beautiful.bg_systray or beautiful.bg_normal or "#000000"
|
||||
local spacing = beautiful.systray_icon_spacing or 0
|
||||
|
||||
|
@ -69,18 +79,17 @@ function systray:draw(context, cr, width, height)
|
|||
end
|
||||
-- The formula for a given base, spacing, and num_entries for the necessary
|
||||
-- space is (draw a picture to convince yourself; this assumes horizontal):
|
||||
-- height = base
|
||||
-- width = (base + spacing) * num_entries - spacing
|
||||
-- height = (base + spacing) * rows - spacing
|
||||
-- width = (base + spacing) * cols - spacing
|
||||
-- Now, we check if we are limited by horizontal or vertical space: Which of
|
||||
-- the two limits the base size more?
|
||||
if (ortho + spacing) * num_entries - spacing <= in_dir then
|
||||
base = ortho
|
||||
else
|
||||
base = (ortho + spacing) / rows - spacing
|
||||
if (base + spacing) * cols - spacing > in_dir then
|
||||
-- Solving the "width" formula above for "base" (with width=in_dir):
|
||||
base = (in_dir + spacing) / num_entries - spacing
|
||||
base = (in_dir + spacing) / cols - spacing
|
||||
end
|
||||
capi.awesome.systray(context.wibox.drawin, math.ceil(x), math.ceil(y),
|
||||
base, is_rotated, bg, reverse, spacing)
|
||||
base, is_rotated, bg, reverse, spacing, rows)
|
||||
end
|
||||
|
||||
-- Private API. Does not appear in LDoc on purpose. This function is called
|
||||
|
@ -96,23 +105,28 @@ function systray:fit(context, width, height)
|
|||
end
|
||||
|
||||
local num_entries = capi.awesome.systray()
|
||||
local max_rows = math.floor(tonumber(beautiful.systray_max_rows) or 1)
|
||||
local rows = math.max(math.min(num_entries, max_rows), 1)
|
||||
local cols = math.ceil(num_entries / rows)
|
||||
local base = base_size
|
||||
local spacing = beautiful.systray_icon_spacing or 0
|
||||
if num_entries == 0 then
|
||||
return 0, 0
|
||||
end
|
||||
if base == nil then
|
||||
if width < height then
|
||||
base = width
|
||||
if horizontal then
|
||||
base = math.min(math.floor((height + spacing) / rows) - spacing,
|
||||
math.floor((width + spacing) / cols) - spacing)
|
||||
else
|
||||
base = height
|
||||
base = math.min(math.floor((width + spacing) / rows) - spacing,
|
||||
math.floor((height + spacing) / cols) - spacing)
|
||||
end
|
||||
end
|
||||
base = base + spacing
|
||||
if horizontal then
|
||||
return base * num_entries - spacing, base
|
||||
return base * cols - spacing, base * rows - spacing
|
||||
end
|
||||
return base, base * num_entries - spacing
|
||||
return base * rows - spacing, base * cols - spacing
|
||||
end
|
||||
|
||||
-- Check if the function was called like :foo() or .foo() and do the right thing
|
||||
|
|
|
@ -48,14 +48,18 @@ describe("wibox.widget.systray", function()
|
|||
local context = { wibox = { drawin = true } }
|
||||
local cr = { user_to_device_distance = function() return 1, 0 end }
|
||||
|
||||
local function test_systray(available_size, expected_size, expected_base)
|
||||
local function test_systray(available_size, expected_size, expected_base, expected_rows)
|
||||
systray_arguments = nil
|
||||
local spacing = beautiful_mock.systray_icon_spacing or 0
|
||||
|
||||
assert.widget_fit(widget, available_size, expected_size)
|
||||
widget:draw(context, cr, unpack(available_size))
|
||||
assert.is.near(systray_arguments[4], expected_base, 0.000001)
|
||||
assert.is.same(systray_arguments, {true, 0, 0, systray_arguments[4], true, '#000000', false, spacing})
|
||||
assert.is.same(systray_arguments, {
|
||||
true, 0, 0, systray_arguments[4],
|
||||
true, '#000000', false, spacing,
|
||||
expected_rows or 1
|
||||
})
|
||||
end
|
||||
|
||||
describe("no spacing", function()
|
||||
|
@ -74,18 +78,23 @@ describe("wibox.widget.systray", function()
|
|||
it("two icons", function()
|
||||
num_systray_icons = 2
|
||||
test_systray({ 100, 10 }, { 20, 10 }, 10)
|
||||
test_systray({ 100, 100 }, { 100, 100 }, 100 / 2)
|
||||
test_systray({ 100, 100 }, { 100, 50 }, 100 / 2)
|
||||
end)
|
||||
|
||||
it("three icons", function()
|
||||
num_systray_icons = 3
|
||||
test_systray({ 100, 10 }, { 30, 10 }, 10)
|
||||
test_systray({ 100, 100 }, { 100, 100 }, 100 / 3)
|
||||
test_systray({ 100, 100 }, { 99, 33 }, 100 / 3)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("10 spacing", function()
|
||||
beautiful_mock.systray_icon_spacing = 10
|
||||
setup(function()
|
||||
beautiful_mock.systray_icon_spacing = 10
|
||||
end)
|
||||
teardown(function()
|
||||
beautiful_mock.systray_icon_spacing = nil
|
||||
end)
|
||||
|
||||
it("no icons", function()
|
||||
num_systray_icons = 0
|
||||
|
@ -105,13 +114,92 @@ describe("wibox.widget.systray", function()
|
|||
-- Okay, so we want to place to icons next to each other in a square
|
||||
-- of size 100x100. Between them, there should be 10 pixels of
|
||||
-- space. So, we got 90 pixels for the icons, so 45 px per icon.
|
||||
test_systray({ 100, 100 }, { 100, 100 }, (100 - 10) / 2)
|
||||
test_systray({ 100, 100 }, { 100, 45 }, (100 - 10) / 2)
|
||||
end)
|
||||
|
||||
it("three icons", function()
|
||||
num_systray_icons = 3
|
||||
test_systray({ 100, 10 }, { 50, 10 }, 10)
|
||||
test_systray({ 100, 100 }, { 100, 100 }, (100 - 2 * 10) / 3)
|
||||
test_systray({ 100, 100 }, { 98, 26 }, (100 - 2 * 10) / 3)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("max two rows", function()
|
||||
setup(function()
|
||||
beautiful_mock.systray_max_rows = 2
|
||||
end)
|
||||
teardown(function()
|
||||
beautiful_mock.systray_max_rows = nil
|
||||
end)
|
||||
|
||||
describe("no spacing", function()
|
||||
it("no icons", function()
|
||||
num_systray_icons = 0
|
||||
test_systray({ 100, 10 }, { 0, 0 }, 10, 1)
|
||||
test_systray({ 100, 100 }, { 0, 0 }, 100, 1)
|
||||
end)
|
||||
|
||||
it("one icon", function()
|
||||
num_systray_icons = 1
|
||||
-- +---+
|
||||
-- | 1 |
|
||||
-- +---+
|
||||
test_systray({ 100, 10 }, { 10, 10 }, 10, 1)
|
||||
test_systray({ 100, 100 }, { 100, 100 }, 100, 1)
|
||||
end)
|
||||
|
||||
it("two icons", function()
|
||||
num_systray_icons = 2
|
||||
-- +---+
|
||||
-- | 1 |
|
||||
-- | 2 |
|
||||
-- +---+
|
||||
test_systray({ 100, 10 }, { 5, 10 }, 5, 2)
|
||||
test_systray({ 100, 100 }, { 50, 100 }, 50, 2)
|
||||
end)
|
||||
|
||||
it("three icons", function()
|
||||
num_systray_icons = 3
|
||||
-- +------+
|
||||
-- | 1 3 |
|
||||
-- | 2 |
|
||||
-- +------+
|
||||
test_systray({ 100, 10 }, { 10, 10 }, 5, 2)
|
||||
test_systray({ 100, 100 }, { 100, 100 }, 50, 2)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("10 spacing", function()
|
||||
setup(function()
|
||||
beautiful_mock.systray_icon_spacing = 10
|
||||
end)
|
||||
teardown(function()
|
||||
beautiful_mock.systray_icon_spacing = nil
|
||||
end)
|
||||
|
||||
it("no icons", function()
|
||||
num_systray_icons = 0
|
||||
test_systray({ 100, 20 }, { 0, 0 }, 20, 1)
|
||||
test_systray({ 100, 100 }, { 0, 0 }, 100, 1)
|
||||
end)
|
||||
|
||||
it("one icon", function()
|
||||
num_systray_icons = 1
|
||||
test_systray({ 100, 20 }, { 20, 20 }, 20, 1)
|
||||
test_systray({ 100, 100 }, { 100, 100 }, 100, 1)
|
||||
end)
|
||||
|
||||
it("two icons", function()
|
||||
num_systray_icons = 2
|
||||
test_systray({ 100, 20 }, { 5, 20 }, 5, 2)
|
||||
test_systray({ 100, 100 }, { 45, 100 }, 45, 2)
|
||||
end)
|
||||
|
||||
it("three icons", function()
|
||||
num_systray_icons = 3
|
||||
test_systray({ 100, 20 }, { 20, 20 }, 5, 2)
|
||||
test_systray({ 100, 100 }, { 100, 100 }, 45, 2)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
|
39
systray.c
39
systray.c
|
@ -272,18 +272,22 @@ luaA_systray_invalidate(void)
|
|||
}
|
||||
|
||||
static void
|
||||
systray_update(int base_size, bool horizontal, bool reverse, int spacing, bool force_redraw)
|
||||
systray_update(int base_size, bool horizontal, bool reverse, int spacing, bool force_redraw, int rows)
|
||||
{
|
||||
if(base_size <= 0)
|
||||
return;
|
||||
|
||||
/* Give the systray window the correct size */
|
||||
int num_entries = systray_num_visible_entries();
|
||||
uint32_t config_vals[4] = { base_size, base_size, 0, 0 };
|
||||
if(horizontal)
|
||||
config_vals[0] = base_size * num_entries + spacing * (num_entries - 1);
|
||||
else
|
||||
config_vals[1] = base_size * num_entries + spacing * (num_entries - 1);
|
||||
int cols = (num_entries + rows - 1) / rows;
|
||||
uint32_t config_vals[4] = { 0, 0, 0, 0 };
|
||||
if(horizontal) {
|
||||
config_vals[0] = base_size * cols + spacing * (cols - 1);
|
||||
config_vals[1] = base_size * rows + spacing * (rows - 1);
|
||||
} else {
|
||||
config_vals[0] = base_size * rows + spacing * (rows - 1);
|
||||
config_vals[1] = base_size * cols + spacing * (cols - 1);
|
||||
}
|
||||
xcb_configure_window(globalconf.connection,
|
||||
globalconf.systray.window,
|
||||
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
||||
|
@ -313,10 +317,21 @@ systray_update(int base_size, bool horizontal, bool reverse, int spacing, bool f
|
|||
xcb_map_window(globalconf.connection, em->win);
|
||||
if (force_redraw)
|
||||
xcb_clear_area(globalconf.connection, 1, em->win, 0, 0, 0, 0);
|
||||
if(horizontal)
|
||||
config_vals[0] += base_size + spacing;
|
||||
else
|
||||
config_vals[1] += base_size + spacing;
|
||||
if (i % rows == rows - 1) {
|
||||
if (horizontal) {
|
||||
config_vals[0] += base_size + spacing;
|
||||
config_vals[1] = 0;
|
||||
} else {
|
||||
config_vals[0] = 0;
|
||||
config_vals[1] += base_size + spacing;
|
||||
}
|
||||
} else {
|
||||
if (horizontal) {
|
||||
config_vals[1] += base_size + spacing;
|
||||
} else {
|
||||
config_vals[0] += base_size + spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,6 +347,7 @@ systray_update(int base_size, bool horizontal, bool reverse, int spacing, bool f
|
|||
* \lparam bg Color of the systray background.
|
||||
* \lparam revers If true, the systray icon order will be reversed, else default.
|
||||
* \lparam spacing The size of the spacing between icons.
|
||||
* \lparam rows Number of rows to display.
|
||||
*/
|
||||
int
|
||||
luaA_systray(lua_State *L)
|
||||
|
@ -352,6 +368,7 @@ luaA_systray(lua_State *L)
|
|||
const char *bg = luaL_checklstring(L, 6, &bg_len);
|
||||
bool revers = lua_toboolean(L, 7);
|
||||
int spacing = ceil(luaA_checknumber_range(L, 8, 0, MAX_X11_COORDINATE));
|
||||
int rows = ceil(luaA_checknumber_range(L, 9, 1, INT16_MAX));
|
||||
color_t bg_color;
|
||||
bool force_redraw = false;
|
||||
|
||||
|
@ -385,7 +402,7 @@ luaA_systray(lua_State *L)
|
|||
|
||||
if(systray_num_visible_entries() != 0)
|
||||
{
|
||||
systray_update(base_size, horiz, revers, spacing, force_redraw);
|
||||
systray_update(base_size, horiz, revers, spacing, force_redraw, rows);
|
||||
xcb_map_window(globalconf.connection,
|
||||
globalconf.systray.window);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue