2010-10-06 12:42:56 +02:00
|
|
|
---------------------------------------------------------------------------
|
|
|
|
-- @author Uli Schlachter
|
|
|
|
-- @copyright 2010 Uli Schlachter
|
2015-02-25 11:18:53 +01:00
|
|
|
-- @classmod wibox.widget.systray
|
2010-10-06 12:42:56 +02:00
|
|
|
---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
local wbase = require("wibox.widget.base")
|
Partly fix removal of systray from a wibox
This commit changes the systray widget, wibox.drawable and the C code to
fix the following bug: When the systray widget is removed from a
drawable without being moved somewhere else, the systray stayed visible.
This was because the systray is not drawn by awesome, but only placed.
When the widget is no longer "drawn", it stays wherever it was placed
last.
This change works by detecting the situation when the systray is
removed. Then, the C code is specifically told to remove the systray
window from the drawable.
Note that this is only a partial fix. This change works correctly when
the widget is removed completely, because it is no longer placed by its
parent widget. However, for example, when you do
wibox.widget.systray().visible = false, the effect is just that the
systray widget gets size 0x0. This is not really visible, but as far as
this change is concerned, the widget is still part of the drawable.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2017-03-11 18:14:38 +01:00
|
|
|
local drawable = require("wibox.drawable")
|
2010-10-17 09:24:59 +02:00
|
|
|
local beautiful = require("beautiful")
|
2017-03-08 21:18:33 +01:00
|
|
|
local gtable = require("gears.table")
|
2016-03-05 16:49:49 +01:00
|
|
|
local capi = {
|
|
|
|
awesome = awesome,
|
|
|
|
screen = screen
|
|
|
|
}
|
2010-10-06 12:42:56 +02:00
|
|
|
local setmetatable = setmetatable
|
|
|
|
local error = error
|
2013-02-16 22:14:08 +01:00
|
|
|
local abs = math.abs
|
2010-10-06 12:42:56 +02:00
|
|
|
|
2012-06-12 15:55:10 +02:00
|
|
|
local systray = { mt = {} }
|
2010-10-06 12:42:56 +02:00
|
|
|
|
2016-03-05 16:39:25 +01:00
|
|
|
local instance = nil
|
2010-10-06 12:42:56 +02:00
|
|
|
local horizontal = true
|
2010-10-07 11:54:45 +02:00
|
|
|
local base_size = nil
|
2014-04-02 15:25:03 +02:00
|
|
|
local reverse = false
|
2016-03-05 16:49:49 +01:00
|
|
|
local display_on_screen = "primary"
|
|
|
|
|
2016-05-23 09:13:15 +02:00
|
|
|
--- The systray background color.
|
|
|
|
-- @beautiful beautiful.bg_systray
|
|
|
|
-- @param string The color (string like "#ff0000" only)
|
|
|
|
|
|
|
|
--- The systray icon spacing.
|
|
|
|
-- @beautiful beautiful.systray_icon_spacing
|
|
|
|
-- @tparam[opt=0] integer The icon spacing
|
|
|
|
|
2016-03-05 16:49:49 +01:00
|
|
|
local function should_display_on(s)
|
|
|
|
if display_on_screen == "primary" then
|
|
|
|
return s == capi.screen.primary
|
|
|
|
end
|
|
|
|
return s == display_on_screen
|
|
|
|
end
|
2010-10-06 12:42:56 +02:00
|
|
|
|
2015-08-08 13:18:54 +02:00
|
|
|
function systray:draw(context, cr, width, height)
|
2016-03-05 16:49:49 +01:00
|
|
|
if not should_display_on(context.screen) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2015-07-25 15:52:53 +02:00
|
|
|
local x, y, _, _ = wbase.rect_to_device_geometry(cr, 0, 0, width, height)
|
2010-10-06 12:42:56 +02:00
|
|
|
local num_entries = capi.awesome.systray()
|
2012-11-27 22:55:42 +01:00
|
|
|
local bg = beautiful.bg_systray or beautiful.bg_normal or "#000000"
|
2014-05-10 06:08:42 +02:00
|
|
|
local spacing = beautiful.systray_icon_spacing or 0
|
2010-10-06 12:42:56 +02:00
|
|
|
|
2015-10-10 20:30:08 +02:00
|
|
|
if context and not context.wibox then
|
|
|
|
error("The systray widget can only be placed inside a wibox.")
|
|
|
|
end
|
|
|
|
|
2013-02-16 22:14:08 +01:00
|
|
|
-- Figure out if the cairo context is rotated
|
|
|
|
local dir_x, dir_y = cr:user_to_device_distance(1, 0)
|
|
|
|
local is_rotated = abs(dir_x) < abs(dir_y)
|
|
|
|
|
2010-10-07 11:54:45 +02:00
|
|
|
local in_dir, ortho, base
|
2010-10-06 12:42:56 +02:00
|
|
|
if horizontal then
|
|
|
|
in_dir, ortho = width, height
|
2013-02-16 22:14:08 +01:00
|
|
|
is_rotated = not is_rotated
|
2010-10-06 12:42:56 +02:00
|
|
|
else
|
|
|
|
ortho, in_dir = width, height
|
|
|
|
end
|
|
|
|
if ortho * num_entries <= in_dir then
|
|
|
|
base = ortho
|
|
|
|
else
|
|
|
|
base = in_dir / num_entries
|
|
|
|
end
|
2015-08-08 13:18:54 +02:00
|
|
|
capi.awesome.systray(context.wibox.drawin, math.ceil(x), math.ceil(y),
|
2015-05-28 15:50:36 +02:00
|
|
|
base, is_rotated, bg, reverse, spacing)
|
2010-10-06 12:42:56 +02:00
|
|
|
end
|
|
|
|
|
Partly fix removal of systray from a wibox
This commit changes the systray widget, wibox.drawable and the C code to
fix the following bug: When the systray widget is removed from a
drawable without being moved somewhere else, the systray stayed visible.
This was because the systray is not drawn by awesome, but only placed.
When the widget is no longer "drawn", it stays wherever it was placed
last.
This change works by detecting the situation when the systray is
removed. Then, the C code is specifically told to remove the systray
window from the drawable.
Note that this is only a partial fix. This change works correctly when
the widget is removed completely, because it is no longer placed by its
parent widget. However, for example, when you do
wibox.widget.systray().visible = false, the effect is just that the
systray widget gets size 0x0. This is not really visible, but as far as
this change is concerned, the widget is still part of the drawable.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2017-03-11 18:14:38 +01:00
|
|
|
-- Private API. Does not appear in LDoc on purpose. This function is called
|
|
|
|
-- some time after the systray is removed from some drawable. It's purpose is to
|
|
|
|
-- really remove the systray.
|
|
|
|
function systray:_kickout(context)
|
|
|
|
capi.awesome.systray(context.wibox.drawin)
|
|
|
|
end
|
|
|
|
|
2016-03-05 16:49:49 +01:00
|
|
|
function systray:fit(context, width, height)
|
|
|
|
if not should_display_on(context.screen) then
|
|
|
|
return 0, 0
|
|
|
|
end
|
|
|
|
|
2010-10-06 12:42:56 +02:00
|
|
|
local num_entries = capi.awesome.systray()
|
2010-10-07 11:54:45 +02:00
|
|
|
local base = base_size
|
2014-05-10 06:08:42 +02:00
|
|
|
local spacing = beautiful.systray_icon_spacing or 0
|
2014-05-11 17:24:01 +02:00
|
|
|
if num_entries == 0 then
|
|
|
|
return 0, 0
|
|
|
|
end
|
2010-10-07 11:54:45 +02:00
|
|
|
if base == nil then
|
|
|
|
if width < height then
|
|
|
|
base = width
|
|
|
|
else
|
|
|
|
base = height
|
|
|
|
end
|
|
|
|
end
|
2014-05-10 06:08:42 +02:00
|
|
|
base = base + spacing
|
2010-10-06 12:42:56 +02:00
|
|
|
if horizontal then
|
2014-05-10 06:08:42 +02:00
|
|
|
return base * num_entries - spacing, base
|
2010-10-06 12:42:56 +02:00
|
|
|
end
|
2014-05-10 06:08:42 +02:00
|
|
|
return base, base * num_entries - spacing
|
2010-10-06 12:42:56 +02:00
|
|
|
end
|
|
|
|
|
2016-03-05 16:39:25 +01:00
|
|
|
-- Check if the function was called like :foo() or .foo() and do the right thing
|
|
|
|
local function get_args(self, ...)
|
|
|
|
if self == instance then
|
|
|
|
return ...
|
|
|
|
end
|
|
|
|
return self, ...
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Set the size of a single icon.
|
|
|
|
-- If this is set to nil, then the size is picked dynamically based on the
|
|
|
|
-- available space. Otherwise, any single icon has a size of `size`x`size`.
|
|
|
|
-- @tparam integer|nil size The base size
|
|
|
|
function systray:set_base_size(size)
|
|
|
|
base_size = get_args(self, size)
|
2016-03-05 16:53:38 +01:00
|
|
|
if instance then
|
|
|
|
instance:emit_signal("widget::layout_changed")
|
|
|
|
end
|
2016-03-05 16:39:25 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
--- Decide between horizontal or vertical display.
|
|
|
|
-- @tparam boolean horiz Use horizontal mode?
|
|
|
|
function systray:set_horizontal(horiz)
|
|
|
|
horizontal = get_args(self, horiz)
|
2016-03-05 16:53:38 +01:00
|
|
|
if instance then
|
|
|
|
instance:emit_signal("widget::layout_changed")
|
|
|
|
end
|
2016-03-05 16:39:25 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
--- Should the systray icons be displayed in reverse order?
|
|
|
|
-- @tparam boolean rev Display in reverse order
|
|
|
|
function systray:set_reverse(rev)
|
|
|
|
reverse = get_args(self, rev)
|
2016-03-05 16:53:38 +01:00
|
|
|
if instance then
|
|
|
|
instance:emit_signal("widget::redraw_needed")
|
|
|
|
end
|
2016-03-05 16:39:25 +01:00
|
|
|
end
|
|
|
|
|
2016-03-05 16:49:49 +01:00
|
|
|
--- Set the screen that the systray should be displayed on.
|
|
|
|
-- This can either be a screen, in which case the systray will be displayed on
|
|
|
|
-- exactly that screen, or the string `"primary"`, in which case it will be
|
|
|
|
-- visible on the primary screen. The default value is "primary".
|
|
|
|
-- @tparam screen|"primary" s The screen to display on.
|
|
|
|
function systray:set_screen(s)
|
|
|
|
display_on_screen = get_args(self, s)
|
2016-03-05 16:53:38 +01:00
|
|
|
if instance then
|
|
|
|
instance:emit_signal("widget::layout_changed")
|
|
|
|
end
|
2016-03-05 16:49:49 +01:00
|
|
|
end
|
|
|
|
|
2016-05-23 08:54:01 +02:00
|
|
|
--- Create the systray widget.
|
|
|
|
-- Note that this widget can only exist once.
|
|
|
|
-- @tparam boolean revers Show in the opposite direction
|
|
|
|
-- @treturn table The new `systray` widget
|
|
|
|
-- @function wibox.widget.systray
|
|
|
|
|
2014-04-02 15:25:03 +02:00
|
|
|
local function new(revers)
|
2010-10-06 12:42:56 +02:00
|
|
|
local ret = wbase.make_widget()
|
|
|
|
|
2017-03-08 21:18:33 +01:00
|
|
|
gtable.crush(ret, systray, true)
|
2014-04-02 15:25:03 +02:00
|
|
|
|
|
|
|
if revers then
|
|
|
|
ret:set_reverse(true)
|
|
|
|
end
|
2010-10-06 12:42:56 +02:00
|
|
|
|
|
|
|
capi.awesome.connect_signal("systray::update", function()
|
2015-06-14 16:37:07 +02:00
|
|
|
ret:emit_signal("widget::layout_changed")
|
2015-11-29 12:33:13 +01:00
|
|
|
ret:emit_signal("widget::redraw_needed")
|
2010-10-06 12:42:56 +02:00
|
|
|
end)
|
2016-03-05 16:49:49 +01:00
|
|
|
capi.screen.connect_signal("primary_changed", function()
|
|
|
|
if display_on_screen == "primary" then
|
|
|
|
ret:emit_signal("widget::layout_changed")
|
|
|
|
end
|
|
|
|
end)
|
2010-10-06 12:42:56 +02:00
|
|
|
|
Partly fix removal of systray from a wibox
This commit changes the systray widget, wibox.drawable and the C code to
fix the following bug: When the systray widget is removed from a
drawable without being moved somewhere else, the systray stayed visible.
This was because the systray is not drawn by awesome, but only placed.
When the widget is no longer "drawn", it stays wherever it was placed
last.
This change works by detecting the situation when the systray is
removed. Then, the C code is specifically told to remove the systray
window from the drawable.
Note that this is only a partial fix. This change works correctly when
the widget is removed completely, because it is no longer placed by its
parent widget. However, for example, when you do
wibox.widget.systray().visible = false, the effect is just that the
systray widget gets size 0x0. This is not really visible, but as far as
this change is concerned, the widget is still part of the drawable.
Signed-off-by: Uli Schlachter <psychon@znc.in>
2017-03-11 18:14:38 +01:00
|
|
|
drawable._set_systray_widget(ret)
|
|
|
|
|
2010-10-06 12:42:56 +02:00
|
|
|
return ret
|
|
|
|
end
|
|
|
|
|
2012-06-12 15:55:10 +02:00
|
|
|
function systray.mt:__call(...)
|
2016-03-05 16:17:35 +01:00
|
|
|
if not instance then
|
|
|
|
instance = new(...)
|
|
|
|
end
|
|
|
|
return instance
|
2012-06-12 15:55:10 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
return setmetatable(systray, systray.mt)
|
2010-10-06 12:42:56 +02:00
|
|
|
|
2011-09-11 16:50:01 +02:00
|
|
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|