Add a only_on_screen container widget
Fixes: https://github.com/awesomeWM/awesome/issues/1565 Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
7d2a83f7d0
commit
2b2612314c
|
@ -19,6 +19,7 @@ return
|
|||
textclock = require("awful.widget.textclock");
|
||||
keyboardlayout = require("awful.widget.keyboardlayout");
|
||||
watch = require("awful.widget.watch");
|
||||
only_on_screen = require("awful.widget.only_on_screen");
|
||||
}
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
---------------------------------------------------------------------------
|
||||
--
|
||||
-- A container that makes a widget display only on a specified screen.
|
||||
--
|
||||
-- @author Uli Schlachter
|
||||
-- @copyright 2017 Uli Schlachter
|
||||
-- @classmod awful.widget.only_on_screen
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
local setmetatable = setmetatable
|
||||
local base = require("wibox.widget.base")
|
||||
local util = require("awful.util")
|
||||
local capi = {
|
||||
screen = screen,
|
||||
awesome = awesome
|
||||
}
|
||||
|
||||
local only_on_screen = { mt = {} }
|
||||
|
||||
local instances = setmetatable({}, { __mode = "k" })
|
||||
|
||||
local function should_display_on(self, s)
|
||||
if not self._private.widget then
|
||||
return false
|
||||
end
|
||||
local success, own_s = pcall(function()
|
||||
return capi.screen[self._private.screen]
|
||||
end)
|
||||
return success and own_s == s
|
||||
end
|
||||
|
||||
-- Layout this layout
|
||||
function only_on_screen:layout(context, ...)
|
||||
if not should_display_on(self, context.screen) then return end
|
||||
return { base.place_widget_at(self._private.widget, 0, 0, ...) }
|
||||
end
|
||||
|
||||
-- Fit this layout into the given area
|
||||
function only_on_screen:fit(context, ...)
|
||||
if not should_display_on(self, context.screen) then
|
||||
return 0, 0
|
||||
end
|
||||
return base.fit_widget(self, context, self._private.widget, ...)
|
||||
end
|
||||
|
||||
--- The widget to be displayed
|
||||
-- @property widget
|
||||
-- @tparam widget widget The widget
|
||||
|
||||
function only_on_screen:set_widget(widget)
|
||||
if widget then
|
||||
base.check_widget(widget)
|
||||
end
|
||||
self._private.widget = widget
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
function only_on_screen:get_widget()
|
||||
return self._private.widget
|
||||
end
|
||||
|
||||
--- Get the number of children element
|
||||
-- @treturn table The children
|
||||
function only_on_screen:get_children()
|
||||
return {self._private.widget}
|
||||
end
|
||||
|
||||
--- Replace the layout children
|
||||
-- This layout only accept one children, all others will be ignored
|
||||
-- @tparam table children A table composed of valid widgets
|
||||
function only_on_screen:set_children(children)
|
||||
self:set_widget(children[1])
|
||||
end
|
||||
|
||||
--- The screen to display on. Can be a screen object, a screen index, a screen
|
||||
-- name ("VGA1") or the string "primary" for the primary screen.
|
||||
-- @property screen
|
||||
-- @tparam screen|string|integer screen The screen.
|
||||
|
||||
function only_on_screen:set_screen(s)
|
||||
self._private.screen = s
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
function only_on_screen:get_screen()
|
||||
return self._private.screen
|
||||
end
|
||||
|
||||
--- Returns a new only_on_screen container.
|
||||
-- This widget makes some other widget visible on just some screens. Use
|
||||
-- `:set_widget()` to set the widget and `:set_screen()` to set the screen.
|
||||
-- @param[opt] widget The widget to display.
|
||||
-- @param[opt] s The screen to display on.
|
||||
-- @treturn table A new only_on_screen container
|
||||
-- @function wibox.container.only_on_screen
|
||||
local function new(widget, s)
|
||||
local ret = base.make_widget(nil, nil, {enable_properties = true})
|
||||
|
||||
util.table.crush(ret, only_on_screen, true)
|
||||
|
||||
ret:set_widget(widget)
|
||||
ret:set_screen(s or "primary")
|
||||
|
||||
instances[ret] = true
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function only_on_screen.mt:__call(...)
|
||||
return new(...)
|
||||
end
|
||||
|
||||
-- Handle lots of cases where a screen changes and thus this widget jumps around
|
||||
|
||||
capi.screen.connect_signal("primary_changed", function()
|
||||
for widget in pairs(instances) do
|
||||
if widget._private.widget and widget._private.screen == "primary" then
|
||||
widget:emit_signal("widget::layout_changed")
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
capi.screen.connect_signal("list", function()
|
||||
for widget in pairs(instances) do
|
||||
if widget._private.widget and type(widget._private.screen) == "number" then
|
||||
widget:emit_signal("widget::layout_changed")
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
capi.screen.connect_signal("property::outputs", function()
|
||||
for widget in pairs(instances) do
|
||||
if widget._private.widget and type(widget._private.screen) == "string" then
|
||||
widget:emit_signal("widget::layout_changed")
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(only_on_screen, only_on_screen.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,155 @@
|
|||
-- Test that awful.widget.only_on_screen works correctly
|
||||
|
||||
local runner = require("_runner")
|
||||
local wibox = require("wibox")
|
||||
local awful = require("awful")
|
||||
|
||||
-- Make sure we have at least two screens to test this on
|
||||
screen.fake_add(-100, -100, 50, 50)
|
||||
assert(screen.count() == 2)
|
||||
|
||||
-- Each screen gets a wibox displaying our only_on_screen widget
|
||||
local inner_widget = wibox.widget.textbox("This is only visible on some screen")
|
||||
local only_widget = awful.widget.only_on_screen()
|
||||
awful.screen.connect_for_each_screen(function(s)
|
||||
local geo = s.geometry
|
||||
-- Just so that :fit() also gets code coverage, we use an align layout
|
||||
local widget = wibox.layout.align.horizontal(only_widget)
|
||||
s.testwibox = wibox{
|
||||
x = geo.x + geo.width / 4,
|
||||
y = geo.y + geo.height / 4,
|
||||
width = geo.width / 2,
|
||||
height = geo.height / 2,
|
||||
widget = widget,
|
||||
visible = true,
|
||||
}
|
||||
end)
|
||||
|
||||
-- Check if the inner_widget is visible on the given screen
|
||||
local function widget_visible_on(s)
|
||||
for _, entry in ipairs(s.testwibox:find_widgets(1, 1)) do
|
||||
if entry.widget == inner_widget then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Test the widget's constructor
|
||||
do
|
||||
local widget = awful.widget.only_on_screen()
|
||||
assert(widget.screen == "primary")
|
||||
assert(widget.widget == nil)
|
||||
|
||||
widget = awful.widget.only_on_screen(inner_widget, 42)
|
||||
assert(widget.screen == 42)
|
||||
assert(widget.widget == inner_widget)
|
||||
end
|
||||
|
||||
local steps = {}
|
||||
|
||||
-- Test that the widget "does nothing" when no widget is set
|
||||
table.insert(steps, function()
|
||||
-- Idle step so that the testwibox added above is drawn
|
||||
return true
|
||||
end)
|
||||
table.insert(steps, function()
|
||||
for s in screen do
|
||||
local res = s.testwibox:find_widgets(1, 1)
|
||||
assert(#res == 1, #res)
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
-- Test that the widget by default is displayed on the primary screen
|
||||
table.insert(steps, function()
|
||||
only_widget.widget = inner_widget
|
||||
return true
|
||||
end)
|
||||
table.insert(steps, function()
|
||||
assert(only_widget.screen == "primary", only_widget.screen)
|
||||
for s in screen do
|
||||
if s == screen.primary then
|
||||
assert(widget_visible_on(s))
|
||||
else
|
||||
assert(not widget_visible_on(s))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
-- Test setting the screen
|
||||
for s in screen do
|
||||
local index = s.index
|
||||
local function check_result()
|
||||
for t in screen do
|
||||
assert(widget_visible_on(t) == (t.index == index))
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- Test by screen object
|
||||
table.insert(steps, function()
|
||||
only_widget.screen = s
|
||||
return true
|
||||
end)
|
||||
table.insert(steps, check_result)
|
||||
|
||||
-- Test by index
|
||||
table.insert(steps, function()
|
||||
only_widget.screen = index
|
||||
return true
|
||||
end)
|
||||
table.insert(steps, check_result)
|
||||
end
|
||||
|
||||
-- Test that the widget is correctly updated when screen "2" is removed
|
||||
table.insert(steps, function()
|
||||
only_widget.screen = 2
|
||||
return true
|
||||
end)
|
||||
table.insert(steps, function()
|
||||
screen[2]:fake_remove()
|
||||
return true
|
||||
end)
|
||||
table.insert(steps, function()
|
||||
for s in screen do
|
||||
assert(not widget_visible_on(s))
|
||||
end
|
||||
screen.fake_add(-100, -100, 50, 50)
|
||||
return true
|
||||
end)
|
||||
table.insert(steps, function()
|
||||
for s in screen do
|
||||
assert(widget_visible_on(s) == (s.index == 2))
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
-- Test what happens when the primary screen is removed
|
||||
table.insert(steps, function()
|
||||
only_widget.screen = "primary"
|
||||
return true
|
||||
end)
|
||||
table.insert(steps, function()
|
||||
local s, s2 = screen.primary, screen[2]
|
||||
assert(s.index == 1)
|
||||
s:fake_remove()
|
||||
assert(screen.primary == s2)
|
||||
return true
|
||||
end)
|
||||
table.insert(steps, function()
|
||||
assert(only_widget.screen == "primary", only_widget.screen)
|
||||
for s in screen do
|
||||
if s == screen.primary then
|
||||
assert(widget_visible_on(s))
|
||||
else
|
||||
assert(not widget_visible_on(s))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
runner.run_steps(steps)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
Loading…
Reference in New Issue