summaryrefslogtreecommitdiff
path: root/lib/awful/titlebar.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lib/awful/titlebar.lua')
-rw-r--r--lib/awful/titlebar.lua509
1 files changed, 509 insertions, 0 deletions
diff --git a/lib/awful/titlebar.lua b/lib/awful/titlebar.lua
new file mode 100644
index 0000000..c055349
--- /dev/null
+++ b/lib/awful/titlebar.lua
@@ -0,0 +1,509 @@
+---------------------------------------------------------------------------
+--- Titlebars for awful.
+--
+-- @author Uli Schlachter
+-- @copyright 2012 Uli Schlachter
+-- @module awful.titlebar
+---------------------------------------------------------------------------
+
+local error = error
+local type = type
+local util = require("awful.util")
+local abutton = require("awful.button")
+local aclient = require("awful.client")
+local atooltip = require("awful.tooltip")
+local beautiful = require("beautiful")
+local drawable = require("wibox.drawable")
+local imagebox = require("wibox.widget.imagebox")
+local textbox = require("wibox.widget.textbox")
+local base = require("wibox.widget.base")
+local capi = {
+ client = client
+}
+local titlebar = {
+ widget = {}
+}
+
+--- The titlebar foreground (text) color.
+-- @beautiful beautiful.titlebar_fg_normal
+-- @param color
+-- @see gears.color
+
+--- The titlebar background color.
+-- @beautiful beautiful.titlebar_bg_normal
+-- @param color
+-- @see gears.color
+
+--- The titlebar background image image.
+-- @beautiful beautiful.titlebar_bgimage_normal
+-- @param surface
+-- @see gears.surface
+
+--- The titlebar foreground (text) color.
+-- @beautiful beautiful.titlebar_fg
+-- @param color
+-- @see gears.color
+
+--- The titlebar background color.
+-- @beautiful beautiful.titlebar_bg
+-- @param color
+-- @see gears.color
+
+--- The titlebar background image image.
+-- @beautiful beautiful.titlebar_bgimage
+-- @param surface
+-- @see gears.surface
+
+--- The focused titlebar foreground (text) color.
+-- @beautiful beautiful.titlebar_fg_focus
+-- @param color
+-- @see gears.color
+
+--- The focused titlebar background color.
+-- @beautiful beautiful.titlebar_bg_focus
+-- @param color
+-- @see gears.color
+
+--- The focused titlebar background image image.
+-- @beautiful beautiful.titlebar_bgimage_focus
+-- @param surface
+-- @see gears.surface
+
+--- floating_button_normal.
+-- @beautiful beautiful.titlebar_floating_button_normal
+-- @param surface
+-- @see gears.surface
+
+--- maximized_button_normal.
+-- @beautiful beautiful.titlebar_maximized_button_normal
+-- @param surface
+-- @see gears.surface
+
+--- minimize_button_normal
+-- @beautiful beautiful.titlebar_minimize_button_normal
+-- @param surface
+-- @see gears.surface
+
+--- close_button_normal.
+-- @beautiful beautiful.titlebar_close_button_normal
+-- @param surface
+-- @see gears.surface
+
+--- ontop_button_normal.
+-- @beautiful beautiful.titlebar_ontop_button_normal
+-- @param surface
+-- @see gears.surface
+
+--- sticky_button_normal.
+-- @beautiful beautiful.titlebar_sticky_button_normal
+-- @param surface
+-- @see gears.surface
+
+--- floating_button_focus.
+-- @beautiful beautiful.titlebar_floating_button_focus
+-- @param surface
+-- @see gears.surface
+
+--- maximized_button_focus.
+-- @beautiful beautiful.titlebar_maximized_button_focus
+-- @param surface
+-- @see gears.surface
+
+--- minimize_button_focus.
+-- @beautiful beautiful.titlebar_minimize_button_focus
+-- @param surface
+-- @see gears.surface
+
+--- close_button_focus.
+-- @beautiful beautiful.titlebar_close_button_focus
+-- @param surface
+-- @see gears.surface
+
+--- ontop_button_focus.
+-- @beautiful beautiful.titlebar_ontop_button_focus
+-- @param surface
+-- @see gears.surface
+
+--- sticky_button_focus.
+-- @beautiful beautiful.titlebar_sticky_button_focus
+-- @param surface
+-- @see gears.surface
+
+--- floating_button_normal_active.
+-- @beautiful beautiful.titlebar_floating_button_normal_active
+-- @param surface
+-- @see gears.surface
+
+--- maximized_button_normal_active.
+-- @beautiful beautiful.titlebar_maximized_button_normal_active
+-- @param surface
+-- @see gears.surface
+
+--- ontop_button_normal_active.
+-- @beautiful beautiful.titlebar_ontop_button_normal_active
+-- @param surface
+-- @see gears.surface
+
+--- sticky_button_normal_active.
+-- @beautiful beautiful.titlebar_sticky_button_normal_active
+-- @param surface
+-- @see gears.surface
+
+--- floating_button_focus_active.
+-- @beautiful beautiful.titlebar_floating_button_focus_active
+-- @param surface
+-- @see gears.surface
+
+--- maximized_button_focus_active.
+-- @beautiful beautiful.titlebar_maximized_button_focus_active
+-- @param surface
+-- @see gears.surface
+
+--- ontop_button_focus_active.
+-- @beautiful beautiful.titlebar_ontop_button_focus_active
+-- @param surface
+-- @see gears.surface
+
+--- sticky_button_focus_active.
+-- @beautiful beautiful.titlebar_sticky_button_focus_active
+-- @param surface
+-- @see gears.surface
+
+--- floating_button_normal_inactive.
+-- @beautiful beautiful.titlebar_floating_button_normal_inactive
+-- @param surface
+-- @see gears.surface
+
+--- maximized_button_normal_inactive.
+-- @beautiful beautiful.titlebar_maximized_button_normal_inactive
+-- @param surface
+-- @see gears.surface
+
+--- ontop_button_normal_inactive.
+-- @beautiful beautiful.titlebar_ontop_button_normal_inactive
+-- @param surface
+-- @see gears.surface
+
+--- sticky_button_normal_inactive.
+-- @beautiful beautiful.titlebar_sticky_button_normal_inactive
+-- @param surface
+-- @see gears.surface
+
+--- floating_button_focus_inactive.
+-- @beautiful beautiful.titlebar_floating_button_focus_inactive
+-- @param surface
+-- @see gears.surface
+
+--- maximized_button_focus_inactive.
+-- @beautiful beautiful.titlebar_maximized_button_focus_inactive
+-- @param surface
+-- @see gears.surface
+
+--- ontop_button_focus_inactive.
+-- @beautiful beautiful.titlebar_ontop_button_focus_inactive
+-- @param surface
+-- @see gears.surface
+
+--- sticky_button_focus_inactive.
+-- @beautiful beautiful.titlebar_sticky_button_focus_inactive
+-- @param surface
+-- @see gears.surface
+
+--- 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
+
+--- Show tooltips when hover on titlebar buttons (defaults to 'true')
+titlebar.enable_tooltip = true
+
+local all_titlebars = setmetatable({}, { __mode = 'k' })
+
+-- Get a color for a titlebar, this tests many values from the array and the theme
+local function get_color(name, c, args)
+ local suffix = "_normal"
+ if capi.client.focus == c then
+ suffix = "_focus"
+ end
+ local function get(array)
+ return array["titlebar_"..name..suffix] or array["titlebar_"..name] or array[name..suffix] or array[name]
+ end
+ return get(args) or get(beautiful)
+end
+
+local function get_titlebar_function(c, position)
+ if position == "left" then
+ return c.titlebar_left
+ elseif position == "right" then
+ return c.titlebar_right
+ elseif position == "top" then
+ return c.titlebar_top
+ elseif position == "bottom" then
+ return c.titlebar_bottom
+ else
+ error("Invalid titlebar position '" .. position .. "'")
+ end
+end
+
+--- Get a client's titlebar
+-- @class function
+-- @tparam client c The client for which a titlebar is wanted.
+-- @tparam[opt={}] table args A table with extra arguments for the titlebar.
+-- @tparam[opt=font.height*1.5] number args.size The height of the titlebar.
+-- @tparam[opt=top] string args.position" values are `top`,
+-- `left`, `right` and `bottom`.
+-- @tparam[opt=top] string args.bg_normal
+-- @tparam[opt=top] string args.bg_focus
+-- @tparam[opt=top] string args.bgimage_normal
+-- @tparam[opt=top] string args.bgimage_focus
+-- @tparam[opt=top] string args.fg_normal
+-- @tparam[opt=top] string args.fg_focus
+-- @tparam[opt=top] string args.font
+-- @name titlebar
+local function new(c, args)
+ args = args or {}
+ local position = args.position or "top"
+ local size = args.size or util.round(beautiful.get_font_height(args.font) * 1.5)
+ local d = get_titlebar_function(c, position)(c, size)
+
+ -- Make sure that there is never more than one titlebar for any given client
+ local bars = all_titlebars[c]
+ if not bars then
+ bars = {}
+ all_titlebars[c] = bars
+ end
+
+ local ret
+ if not bars[position] then
+ local context = {
+ client = c,
+ position = position
+ }
+ ret = drawable(d, context, "awful.titlebar")
+ ret:_inform_visible(true)
+ local function update_colors()
+ local args_ = bars[position].args
+ ret:set_bg(get_color("bg", c, args_))
+ ret:set_fg(get_color("fg", c, args_))
+ ret:set_bgimage(get_color("bgimage", c, args_))
+ end
+
+ bars[position] = {
+ args = args,
+ drawable = ret,
+ update_colors = update_colors
+ }
+
+ -- Update the colors when focus changes
+ c:connect_signal("focus", update_colors)
+ c:connect_signal("unfocus", update_colors)
+
+ -- Inform the drawable when it becomes invisible
+ c:connect_signal("unmanage", function() ret:_inform_visible(false) end)
+ else
+ bars[position].args = args
+ ret = bars[position].drawable
+ end
+
+ -- Make sure the titlebar has the right colors applied
+ bars[position].update_colors()
+
+ -- Handle declarative/recursive widget container
+ ret.setup = base.widget.setup
+
+ return ret
+end
+
+--- Show a client's titlebar.
+-- @param c The client whose titlebar is modified
+-- @param[opt] position The position of the titlebar. Must be one of "left",
+-- "right", "top", "bottom". Default is "top".
+function titlebar.show(c, position)
+ position = position or "top"
+ local bars = all_titlebars[c]
+ local data = bars and bars[position]
+ local args = data and data.args
+ new(c, args)
+end
+
+--- Hide a client's titlebar.
+-- @param c The client whose titlebar is modified
+-- @param[opt] position The position of the titlebar. Must be one of "left",
+-- "right", "top", "bottom". Default is "top".
+function titlebar.hide(c, position)
+ position = position or "top"
+ get_titlebar_function(c, position)(c, 0)
+end
+
+--- Toggle a client's titlebar, hiding it if it is visible, otherwise showing it.
+-- @param c The client whose titlebar is modified
+-- @param[opt] position The position of the titlebar. Must be one of "left",
+-- "right", "top", "bottom". Default is "top".
+function titlebar.toggle(c, position)
+ position = position or "top"
+ local _, size = get_titlebar_function(c, position)(c)
+ if size == 0 then
+ titlebar.show(c, position)
+ else
+ titlebar.hide(c, position)
+ end
+end
+
+--- Create a new titlewidget. A title widget displays the name of a client.
+-- Please note that this returns a textbox and all of textbox' API is available.
+-- This way, you can e.g. modify the font that is used.
+-- @param c The client for which a titlewidget should be created.
+-- @return The title widget.
+function titlebar.widget.titlewidget(c)
+ local ret = textbox()
+ local function update()
+ ret:set_text(c.name or "<unknown>")
+ end
+ c:connect_signal("property::name", update)
+ update()
+
+ return ret
+end
+
+--- Create a new icon widget. An icon widget displays the icon of a client.
+-- Please note that this returns an imagebox and all of the imagebox' API is
+-- available. This way, you can e.g. disallow resizes.
+-- @param c The client for which an icon widget should be created.
+-- @return The icon widget.
+function titlebar.widget.iconwidget(c)
+ local ret = imagebox()
+ local function update()
+ ret:set_image(c.icon)
+ end
+ c:connect_signal("property::icon", update)
+ update()
+
+ return ret
+end
+
+--- Create a new button widget. A button widget displays an image and reacts to
+-- mouse clicks. Please note that the caller has to make sure that this widget
+-- gets redrawn when needed by calling the returned widget's update() function.
+-- The selector function should return a value describing a state. If the value
+-- is a boolean, either "active" or "inactive" are used. The actual image is
+-- then found in the theme as "titlebar_[name]_button_[normal/focus]_[state]".
+-- If that value does not exist, the focused state is ignored for the next try.
+-- @param c The client for which a button is created.
+-- @tparam string name Name of the button, used for accessing the theme and
+-- in the tooltip.
+-- @param selector A function that selects the image that should be displayed.
+-- @param action Function that is called when the button is clicked.
+-- @return The widget
+function titlebar.widget.button(c, name, selector, action)
+ local ret = imagebox()
+
+ if titlebar.enable_tooltip then
+ ret._private.tooltip = atooltip({ objects = {ret}, delay_show = 1 })
+ ret._private.tooltip:set_text(name)
+ end
+
+ local function update()
+ local img = selector(c)
+ if type(img) ~= "nil" then
+ -- Convert booleans automatically
+ if type(img) == "boolean" then
+ if img then
+ img = "active"
+ else
+ img = "inactive"
+ end
+ end
+ local prefix = "normal"
+ if capi.client.focus == c then
+ prefix = "focus"
+ end
+ if img ~= "" then
+ prefix = prefix .. "_"
+ end
+ -- First try with a prefix based on the client's focus state,
+ -- then try again without that prefix if nothing was found,
+ -- and finally, try a fallback for compatibility with Awesome 3.5 themes
+ local theme = beautiful["titlebar_" .. name .. "_button_" .. prefix .. img]
+ or beautiful["titlebar_" .. name .. "_button_" .. img]
+ or beautiful["titlebar_" .. name .. "_button_" .. prefix .. "_inactive"]
+ if theme then
+ img = theme
+ end
+ end
+ ret:set_image(img)
+ end
+ if action then
+ ret:buttons(abutton({ }, 1, nil, function() action(c, selector(c)) end))
+ end
+
+ ret.update = update
+ update()
+
+ -- We do magic based on whether a client is focused above, so we need to
+ -- connect to the corresponding signal here.
+ c:connect_signal("focus", update)
+ c:connect_signal("unfocus", update)
+
+ return ret
+end
+
+--- Create a new float button for a client.
+-- @param c The client for which the button is wanted.
+function titlebar.widget.floatingbutton(c)
+ local widget = titlebar.widget.button(c, "floating", aclient.object.get_floating, aclient.floating.toggle)
+ c:connect_signal("property::floating", widget.update)
+ return widget
+end
+
+--- Create a new maximize button for a client.
+-- @param c The client for which the button is wanted.
+function titlebar.widget.maximizedbutton(c)
+ local widget = titlebar.widget.button(c, "maximized", function(cl)
+ return cl.maximized_horizontal or cl.maximized_vertical
+ end, function(cl, state)
+ cl.maximized_horizontal = not state
+ cl.maximized_vertical = not state
+ end)
+ c:connect_signal("property::maximized_vertical", widget.update)
+ c:connect_signal("property::maximized_horizontal", widget.update)
+ return widget
+end
+
+--- Create a new minimize button for a client.
+-- @param c The client for which the button is wanted.
+function titlebar.widget.minimizebutton(c)
+ local widget = titlebar.widget.button(c, "minimize", function() return "" end, function(cl) cl.minimized = not cl.minimized end)
+ c:connect_signal("property::minimized", widget.update)
+ return widget
+end
+
+--- Create a new closing button for a client.
+-- @param c The client for which the button is wanted.
+function titlebar.widget.closebutton(c)
+ return titlebar.widget.button(c, "close", function() return "" end, function(cl) cl:kill() end)
+end
+
+--- Create a new ontop button for a client.
+-- @param c The client for which the button is wanted.
+function titlebar.widget.ontopbutton(c)
+ local widget = titlebar.widget.button(c, "ontop", function(cl) return cl.ontop end, function(cl, state) cl.ontop = not state end)
+ c:connect_signal("property::ontop", widget.update)
+ return widget
+end
+
+--- Create a new sticky button for a client.
+-- @param c The client for which the button is wanted.
+function titlebar.widget.stickybutton(c)
+ local widget = titlebar.widget.button(c, "sticky", function(cl) return cl.sticky end, function(cl, state) cl.sticky = not state end)
+ c:connect_signal("property::sticky", widget.update)
+ return widget
+end
+
+client.connect_signal("unmanage", function(c)
+ all_titlebars[c] = nil
+end)
+
+return setmetatable(titlebar, { __call = function(_, ...) return new(...) end})
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80