diff options
Diffstat (limited to 'awesome/lib/awful/wibar.lua')
-rw-r--r-- | awesome/lib/awful/wibar.lua | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/awesome/lib/awful/wibar.lua b/awesome/lib/awful/wibar.lua new file mode 100644 index 0000000..bbe7289 --- /dev/null +++ b/awesome/lib/awful/wibar.lua @@ -0,0 +1,603 @@ +--------------------------------------------------------------------------- +--- Wibox module for awful. +-- This module allows you to easily create wibox and attach them to the edge of +-- a screen. +-- +-- @author Emmanuel Lepage Vallee <elv1313@gmail.com> +-- @copyright 2016 Emmanuel Lepage Vallee +-- @classmod awful.wibar +--------------------------------------------------------------------------- + +-- Grab environment we need +local capi = +{ + screen = screen, + client = client +} +local setmetatable = setmetatable +local tostring = tostring +local ipairs = ipairs +local error = error +local wibox = require("wibox") +local beautiful = require("beautiful") +local util = require("awful.util") +local placement = require("awful.placement") + +local function get_screen(s) + return s and capi.screen[s] +end + +local awfulwibar = { mt = {} } + +--- Array of table with wiboxes inside. +-- It's an array so it is ordered. +local wiboxes = setmetatable({}, {__mode = "v"}) + +-- Compute the margin on one side +local function get_margin(w, position, auto_stop) + local h_or_w = (position == "top" or position == "bottom") and "height" or "width" + local ret = 0 + + for _, v in ipairs(wiboxes) do + -- Ignore the wibars placed after this one + if auto_stop and v == w then break end + + if v.position == position and v.screen == w.screen and v.visible then + ret = ret + v[h_or_w] + end + end + + return ret +end + +-- `honor_workarea` cannot be used as it does modify the workarea itself. +-- a manual padding has to be generated. +local function get_margins(w) + local position = w.position + assert(position) + + local margins = {left=0, right=0, top=0, bottom=0} + + margins[position] = get_margin(w, position, true) + + -- Avoid overlapping wibars + if position == "left" or position == "right" then + margins.top = get_margin(w, "top" ) + margins.bottom = get_margin(w, "bottom") + end + + return margins +end + +-- Create the placement function +local function gen_placement(position, stretch) + local maximize = (position == "right" or position == "left") and + "maximize_vertically" or "maximize_horizontally" + + return placement[position] + (stretch and placement[maximize] or nil) +end + +-- Attach the placement function. +local function attach(wb, align) + gen_placement(align, wb._stretch)(wb, { + attach = true, + update_workarea = true, + margins = get_margins(wb) + }) +end + +-- Re-attach all wibars on a given wibar screen +local function reattach(wb) + local s = wb.screen + for _, w in ipairs(wiboxes) do + if w ~= wb and w.screen == s then + if w.detach_callback then + w.detach_callback() + w.detach_callback = nil + end + attach(w, w.position) + end + end +end + +--- The wibox position. +-- @property position +-- @param string Either "left", right", "top" or "bottom" + +local function get_position(wb) + return wb._position or "top" +end + +local function set_position(wb, position) + -- Detach first to avoid any uneeded callbacks + if wb.detach_callback then + wb.detach_callback() + + -- Avoid disconnecting twice, this produces a lot of warnings + wb.detach_callback = nil + end + + -- Move the wibar to the end of the list to avoid messing up the others in + -- case there is stacked wibars on one side. + if wb._position then + for k, w in ipairs(wiboxes) do + if w == wb then + table.remove(wiboxes, k) + end + end + table.insert(wiboxes, wb) + end + + -- In case the position changed, it may be necessary to reset the size + if (wb._position == "left" or wb._position == "right") + and (position == "top" or position == "bottom") then + wb.height = math.ceil(beautiful.get_font_height(wb.font) * 1.5) + elseif (wb._position == "top" or wb._position == "bottom") + and (position == "left" or position == "right") then + wb.width = math.ceil(beautiful.get_font_height(wb.font) * 1.5) + end + + -- Changing the position will also cause the other margins to be invalidated. + -- For example, adding a wibar to the top will change the margins of any left + -- or right wibars. To solve, this, they need to be re-attached. + reattach(wb) + + -- Set the new position + wb._position = position + + -- Attach to the new position + attach(wb, position) +end + +--- Stretch the wibar. +-- +-- @property stretch +-- @param[opt=true] boolean + +local function get_stretch(w) + return w._stretch +end + +local function set_stretch(w, value) + w._stretch = value + + attach(w, w.position) +end + +--- Remove a wibar. +-- @function remove +local function remove(self) + self.visible = false + + if self.detach_callback then + self.detach_callback() + self.detach_callback = nil + end + + for k, w in ipairs(wiboxes) do + if w == self then + table.remove(wiboxes, k) + end + end + + self._screen = nil +end + +--- Get a wibox position if it has been set, or return top. +-- @param wb The wibox +-- @deprecated awful.wibar.get_position +-- @return The wibox position. +function awfulwibar.get_position(wb) + util.deprecate("Use wb:get_position() instead of awful.wibar.get_position") + return get_position(wb) +end + +--- Put a wibox on a screen at this position. +-- @param wb The wibox to attach. +-- @param position The position: top, bottom left or right. +-- @param screen This argument is deprecated, use wb.screen directly. +-- @deprecated awful.wibar.set_position +function awfulwibar.set_position(wb, position, screen) --luacheck: no unused args + util.deprecate("Use wb:set_position(position) instead of awful.wibar.set_position") + + set_position(wb, position) +end + +--- Attach a wibox to a screen. +-- +-- This function has been moved to the `awful.placement` module. Calling this +-- no longer does anything. +-- +-- @param wb The wibox to attach. +-- @param position The position of the wibox: top, bottom, left or right. +-- @param screen The screen to attach to +-- @see awful.placement +-- @deprecated awful.wibar.attach +function awfulwibar.attach(wb, position, screen) --luacheck: no unused args + util.deprecate("awful.wibar.attach is deprecated, use the 'attach' property".. + " of awful.placement. This method doesn't do anything anymore" + ) +end + +--- Align a wibox. +-- +-- Supported alignment are: +-- +-- * top_left +-- * top_right +-- * bottom_left +-- * bottom_right +-- * left +-- * right +-- * top +-- * bottom +-- * centered +-- * center_vertical +-- * center_horizontal +-- +-- @param wb The wibox. +-- @param align The alignment +-- @param screen This argument is deprecated. It is not used. Use wb.screen +-- directly. +-- @deprecated awful.wibar.align +-- @see awful.placement.align +function awfulwibar.align(wb, align, screen) --luacheck: no unused args + if align == "center" then + util.deprecate("awful.wibar.align(wb, 'center' is deprecated, use 'centered'") + align = "centered" + end + + if screen then + util.deprecate("awful.wibar.align 'screen' argument is deprecated") + end + + if placement[align] then + return placement[align](wb) + end +end + +--- Stretch a wibox so it takes all screen width or height. +-- +-- **This function has been removed.** +-- +-- @deprecated awful.wibox.stretch +-- @see awful.placement +-- @see awful.wibar.stretch + +--- Create a new wibox and attach it to a screen edge. +-- You can add also position key with value top, bottom, left or right. +-- You can also use width or height in % and set align to center, right or left. +-- You can also set the screen key with a screen number to attach the wibox. +-- If not specified, the primary screen is assumed. +-- @see wibox +-- @tparam[opt=nil] table arg +-- @tparam string arg.position The position. +-- @tparam string arg.stretch If the wibar need to be stretched to fill the screen. +-- @tparam integer arg.border_width Border width. +-- @tparam string arg.border_color Border color. +-- @tparam boolean arg.ontop On top of other windows. +-- @tparam string arg.cursor The mouse cursor. +-- @tparam boolean arg.visible Visibility. +-- @tparam number arg.opacity The opacity of the wibox, between 0 and 1. +-- @tparam string arg.type The window type (desktop, normal, dock, …). +-- @tparam integer arg.x The x coordinates. +-- @tparam integer arg.y The y coordinates. +-- @tparam integer arg.width The width of the wibox. +-- @tparam integer arg.height The height of the wibox. +-- @tparam screen arg.screen The wibox screen. +-- @tparam wibox.widget arg.widget The widget that the wibox displays. +-- @param arg.shape_bounding The wibox’s bounding shape as a (native) cairo surface. +-- @param arg.shape_clip The wibox’s clip shape as a (native) cairo surface. +-- @tparam color arg.bg The background of the wibox. +-- @tparam surface arg.bgimage The background image of the drawable. +-- @tparam color arg.fg The foreground (text) of the wibox. +-- @return The new wibar +-- @function awful.wibar +function awfulwibar.new(arg) + arg = arg or {} + local position = arg.position or "top" + local has_to_stretch = true + local screen = get_screen(arg.screen or 1) + + arg.type = arg.type or "dock" + + if position ~= "top" and position ~="bottom" + and position ~= "left" and position ~= "right" then + error("Invalid position in awful.wibar(), you may only use" + .. " 'top', 'bottom', 'left' and 'right'") + end + + -- Set default size + if position == "left" or position == "right" then + arg.width = arg.width or math.ceil(beautiful.get_font_height(arg.font) * 1.5) + if arg.height then + has_to_stretch = false + if arg.screen then + local hp = tostring(arg.height):match("(%d+)%%") + if hp then + arg.height = math.ceil(screen.geometry.height * hp / 100) + end + end + end + else + arg.height = arg.height or math.ceil(beautiful.get_font_height(arg.font) * 1.5) + if arg.width then + has_to_stretch = false + if arg.screen then + local wp = tostring(arg.width):match("(%d+)%%") + if wp then + arg.width = math.ceil(screen.geometry.width * wp / 100) + end + end + end + end + + arg.screen = nil + + local w = wibox(arg) + + w.screen = screen + w._screen = screen --HACK When a screen is removed, then getbycoords wont work + w._stretch = arg.stretch == nil and has_to_stretch or arg.stretch + + w.get_position = get_position + w.set_position = set_position + + w.get_stretch = get_stretch + w.set_stretch = set_stretch + w.remove = remove + + if arg.visible == nil then w.visible = true end + + w:set_position(position) + + table.insert(wiboxes, w) + + w:connect_signal("property::visible", function() reattach(w) end) + + return w +end + +capi.screen.connect_signal("removed", function(s) + for _, wibar in ipairs(wiboxes) do + if wibar._screen == s then + wibar:remove() + end + end +end) + +function awfulwibar.mt:__call(...) + return awfulwibar.new(...) +end + +--Imported documentation + +--- Border width. +-- +-- **Signal:** +-- +-- * *property::border_width* +-- +-- @property border_width +-- @param integer + +--- Border color. +-- +-- Please note that this property only support string based 24 bit or 32 bit +-- colors: +-- +-- Red Blue +-- _| _| +-- #FF00FF +-- T‾ +-- Green +-- +-- +-- Red Blue +-- _| _| +-- #FF00FF00 +-- T‾ ‾T +-- Green Alpha +-- +-- **Signal:** +-- +-- * *property::border_color* +-- +-- @property border_color +-- @param string + +--- On top of other windows. +-- +-- **Signal:** +-- +-- * *property::ontop* +-- +-- @property ontop +-- @param boolean + +--- The mouse cursor. +-- +-- **Signal:** +-- +-- * *property::cursor* +-- +-- @property cursor +-- @param string +-- @see mouse + +--- Visibility. +-- +-- **Signal:** +-- +-- * *property::visible* +-- +-- @property visible +-- @param boolean + +--- The opacity of the wibox, between 0 and 1. +-- +-- **Signal:** +-- +-- * *property::opacity* +-- +-- @property opacity +-- @tparam number opacity (between 0 and 1) + +--- The window type (desktop, normal, dock, ...). +-- +-- **Signal:** +-- +-- * *property::type* +-- +-- @property type +-- @param string +-- @see client.type + +--- The x coordinates. +-- +-- **Signal:** +-- +-- * *property::x* +-- +-- @property x +-- @param integer + +--- The y coordinates. +-- +-- **Signal:** +-- +-- * *property::y* +-- +-- @property y +-- @param integer + +--- The width of the wibox. +-- +-- **Signal:** +-- +-- * *property::width* +-- +-- @property width +-- @param width + +--- The height of the wibox. +-- +-- **Signal:** +-- +-- * *property::height* +-- +-- @property height +-- @param height + +--- The wibox screen. +-- +-- @property screen +-- @param screen + +--- The wibox's `drawable`. +-- +-- **Signal:** +-- +-- * *property::drawable* +-- +-- @property drawable +-- @tparam drawable drawable + +--- The widget that the `wibox` displays. +-- @property widget +-- @param widget + +--- The X window id. +-- +-- **Signal:** +-- +-- * *property::window* +-- +-- @property window +-- @param string +-- @see client.window + +--- The wibox's bounding shape as a (native) cairo surface. +-- +-- **Signal:** +-- +-- * *property::shape_bounding* +-- +-- @property shape_bounding +-- @param surface._native + +--- The wibox's clip shape as a (native) cairo surface. +-- +-- **Signal:** +-- +-- * *property::shape_clip* +-- +-- @property shape_clip +-- @param surface._native + +--- Get or set mouse buttons bindings to a wibox. +-- +-- @param buttons_table A table of buttons objects, or nothing. +-- @function buttons + +--- Get or set wibox geometry. That's the same as accessing or setting the x, +-- y, width or height properties of a wibox. +-- +-- @param A table with coordinates to modify. +-- @return A table with wibox coordinates and geometry. +-- @function geometry + +--- Get or set wibox struts. +-- +-- @param strut A table with new strut, or nothing +-- @return The wibox strut in a table. +-- @function struts +-- @see client.struts + +--- The default background color. +-- @beautiful beautiful.bg_normal +-- @see bg + +--- The default foreground (text) color. +-- @beautiful beautiful.fg_normal +-- @see fg + +--- Set a declarative widget hierarchy description. +-- See [The declarative layout system](../documentation/03-declarative-layout.md.html) +-- @param args An array containing the widgets disposition +-- @name setup +-- @class function + +--- The background of the wibox. +-- @param c The background to use. This must either be a cairo pattern object, +-- nil or a string that gears.color() understands. +-- @property bg +-- @see gears.color + +--- The background image of the drawable. +-- If `image` is a function, it will be called with `(context, cr, width, height)` +-- as arguments. Any other arguments passed to this method will be appended. +-- @param image A background image or a function +-- @property bgimage +-- @see gears.surface + +--- The foreground (text) of the wibox. +-- @param c The foreground to use. This must either be a cairo pattern object, +-- nil or a string that gears.color() understands. +-- @property fg +-- @see gears.color + +--- Find a widget by a point. +-- The wibox must have drawn itself at least once for this to work. +-- @tparam number x X coordinate of the point +-- @tparam number y Y coordinate of the point +-- @treturn table A sorted table of widgets positions. The first element is the biggest +-- container while the last is the topmost widget. The table contains *x*, *y*, +-- *width*, *height* and *widget*. +-- @name find_widgets +-- @class function + + +return setmetatable(awfulwibar, awfulwibar.mt) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 |