summaryrefslogtreecommitdiff
path: root/lib/awful/widget
diff options
context:
space:
mode:
Diffstat (limited to 'lib/awful/widget')
-rw-r--r--lib/awful/widget/button.lua263
-rw-r--r--lib/awful/widget/common.lua119
-rw-r--r--lib/awful/widget/graph.lua16
-rw-r--r--lib/awful/widget/init.lua24
-rw-r--r--lib/awful/widget/keyboardlayout.lua308
-rw-r--r--lib/awful/widget/launcher.lua41
-rw-r--r--lib/awful/widget/layoutbox.lua73
-rw-r--r--lib/awful/widget/progressbar.lua16
-rw-r--r--lib/awful/widget/prompt.lua64
-rw-r--r--lib/awful/widget/taglist.lua452
-rw-r--r--lib/awful/widget/tasklist.lua573
-rw-r--r--lib/awful/widget/textclock.lua16
-rw-r--r--lib/awful/widget/watch.lua91
13 files changed, 2056 insertions, 0 deletions
diff --git a/lib/awful/widget/button.lua b/lib/awful/widget/button.lua
new file mode 100644
index 0000000..388f9dd
--- /dev/null
+++ b/lib/awful/widget/button.lua
@@ -0,0 +1,263 @@
+---------------------------------------------------------------------------
+-- A simple button widget.
+-- @usage local button = awful.widget.button()
+-- button:buttons(awful.util.table.join(
+-- button:buttons(),
+-- awful.button({}, 1, nil, function ()
+-- print("Mouse was clicked")
+-- end)
+-- ))
+-- @author Julien Danjou <julien@danjou.info>
+-- @copyright 2008-2009 Julien Danjou
+-- @classmod awful.widget.button
+---------------------------------------------------------------------------
+
+local setmetatable = setmetatable
+local abutton = require("awful.button")
+local imagebox = require("wibox.widget.imagebox")
+local widget = require("wibox.widget.base")
+local surface = require("gears.surface")
+local cairo = require("lgi").cairo
+
+local button = { mt = {} }
+
+--- Create a button widget. When clicked, the image is deplaced to make it like
+-- a real button.
+--
+-- @param args Widget arguments. "image" is the image to display.
+-- @return A textbox widget configured as a button.
+function button.new(args)
+ if not args or not args.image then
+ return widget.empty_widget()
+ end
+
+ local w = imagebox()
+ local orig_set_image = w.set_image
+ local img_release
+ local img_press
+
+ function w:set_image(image)
+ img_release = surface.load(image)
+ img_press = img_release:create_similar(cairo.Content.COLOR_ALPHA, img_release.width, img_release.height)
+ local cr = cairo.Context(img_press)
+ cr:set_source_surface(img_release, 2, 2)
+ cr:paint()
+ orig_set_image(self, img_release)
+ end
+ w:set_image(args.image)
+ w:buttons(abutton({}, 1, function () orig_set_image(w, img_press) end, function () orig_set_image(w, img_release) end))
+
+ w:connect_signal("mouse::leave", function(self) orig_set_image(self, img_release) end)
+
+ return w
+end
+
+function button.mt:__call(...)
+ return button.new(...)
+end
+
+--Imported documentation
+
+
+--- Get a widex index.
+-- @param widget The widget to look for
+-- @param[opt] recursive Also check sub-widgets
+-- @param[opt] ... Aditional widgets to add at the end of the \"path\"
+-- @return The index
+-- @return The parent layout
+-- @return The path between \"self\" and \"widget\"
+-- @function index
+
+--- Get all direct and indirect children widgets.
+-- This will scan all containers recursively to find widgets
+-- Warning: This method it prone to stack overflow id the widget, or any of its
+-- children, contain (directly or indirectly) itself.
+-- @treturn table The children
+-- @function get_all_children
+
+--- 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
+-- @function setup
+
+--- Force a widget height.
+-- @property forced_height
+-- @tparam number|nil height The height (`nil` for automatic)
+
+--- Force a widget width.
+-- @property forced_width
+-- @tparam number|nil width The width (`nil` for automatic)
+
+--- The widget opacity (transparency).
+-- @property opacity
+-- @tparam[opt=1] number opacity The opacity (between 0 and 1)
+
+--- The widget visibility.
+-- @property visible
+-- @param boolean
+
+--- Set/get a widget's buttons.
+-- @param _buttons The table of buttons that should bind to the widget.
+-- @function buttons
+
+--- Emit a signal and ensure all parent widgets in the hierarchies also
+-- forward the signal. This is useful to track signals when there is a dynamic
+-- set of containers and layouts wrapping the widget.
+-- @tparam string signal_name
+-- @param ... Other arguments
+-- @function emit_signal_recursive
+
+--- When the layout (size) change.
+-- This signal is emitted when the previous results of `:layout()` and `:fit()`
+-- are no longer valid. Unless this signal is emitted, `:layout()` and `:fit()`
+-- must return the same result when called with the same arguments.
+-- @signal widget::layout_changed
+-- @see widget::redraw_needed
+
+--- When the widget content changed.
+-- This signal is emitted when the content of the widget changes. The widget will
+-- be redrawn, it is not re-layouted. Put differently, it is assumed that
+-- `:layout()` and `:fit()` would still return the same results as before.
+-- @signal widget::redraw_needed
+-- @see widget::layout_changed
+
+--- When a mouse button is pressed over the widget.
+-- @signal button::press
+-- @tparam number lx The horizontal position relative to the (0,0) position in
+-- the widget.
+-- @tparam number ly The vertical position relative to the (0,0) position in the
+-- widget.
+-- @tparam number button The button number.
+-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift)
+-- @tparam table find_widgets_result The entry from the result of
+-- @{wibox.drawable:find_widgets} for the position that the mouse hit.
+-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing
+-- the widget.
+-- @tparam widget find_widgets_result.widget The widget being displayed.
+-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy
+-- managing the widget's geometry.
+-- @tparam number find_widgets_result.x An approximation of the X position that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.y An approximation of the Y position that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.width An approximation of the width that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.height An approximation of the height that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.widget_width The exact width of the widget
+-- in its local coordinate system.
+-- @tparam number find_widgets_result.widget_height The exact height of the widget
+-- in its local coordinate system.
+-- @see mouse
+
+--- When a mouse button is released over the widget.
+-- @signal button::release
+-- @tparam number lx The horizontal position relative to the (0,0) position in
+-- the widget.
+-- @tparam number ly The vertical position relative to the (0,0) position in the
+-- widget.
+-- @tparam number button The button number.
+-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift)
+-- @tparam table find_widgets_result The entry from the result of
+-- @{wibox.drawable:find_widgets} for the position that the mouse hit.
+-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing
+-- the widget.
+-- @tparam widget find_widgets_result.widget The widget being displayed.
+-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy
+-- managing the widget's geometry.
+-- @tparam number find_widgets_result.x An approximation of the X position that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.y An approximation of the Y position that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.width An approximation of the width that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.height An approximation of the height that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.widget_width The exact width of the widget
+-- in its local coordinate system.
+-- @tparam number find_widgets_result.widget_height The exact height of the widget
+-- in its local coordinate system.
+-- @see mouse
+
+--- When the mouse enter a widget.
+-- @signal mouse::enter
+-- @tparam table find_widgets_result The entry from the result of
+-- @{wibox.drawable:find_widgets} for the position that the mouse hit.
+-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing
+-- the widget.
+-- @tparam widget find_widgets_result.widget The widget being displayed.
+-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy
+-- managing the widget's geometry.
+-- @tparam number find_widgets_result.x An approximation of the X position that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.y An approximation of the Y position that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.width An approximation of the width that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.height An approximation of the height that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.widget_width The exact width of the widget
+-- in its local coordinate system.
+-- @tparam number find_widgets_result.widget_height The exact height of the widget
+-- in its local coordinate system.
+-- @see mouse
+
+--- When the mouse leave a widget.
+-- @signal mouse::leave
+-- @tparam table find_widgets_result The entry from the result of
+-- @{wibox.drawable:find_widgets} for the position that the mouse hit.
+-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing
+-- the widget.
+-- @tparam widget find_widgets_result.widget The widget being displayed.
+-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy
+-- managing the widget's geometry.
+-- @tparam number find_widgets_result.x An approximation of the X position that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.y An approximation of the Y position that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.width An approximation of the width that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.height An approximation of the height that
+-- the widget is visible at on the surface.
+-- @tparam number find_widgets_result.widget_width The exact width of the widget
+-- in its local coordinate system.
+-- @tparam number find_widgets_result.widget_height The exact height of the widget
+-- in its local coordinate system.
+-- @see mouse
+
+
+--Imported documentation
+
+
+--- Disconnect to a signal.
+-- @tparam string name The name of the signal
+-- @tparam function func The callback that should be disconnected
+-- @function disconnect_signal
+
+--- Emit a signal.
+--
+-- @tparam string name The name of the signal
+-- @param ... Extra arguments for the callback functions. Each connected
+-- function receives the object as first argument and then any extra arguments
+-- that are given to emit_signal()
+-- @function emit_signal
+
+--- Connect to a signal.
+-- @tparam string name The name of the signal
+-- @tparam function func The callback to call when the signal is emitted
+-- @function connect_signal
+
+--- Connect to a signal weakly. This allows the callback function to be garbage
+-- collected and automatically disconnects the signal when that happens.
+--
+-- **Warning:**
+-- Only use this function if you really, really, really know what you
+-- are doing.
+-- @tparam string name The name of the signal
+-- @tparam function func The callback to call when the signal is emitted
+-- @function weak_connect_signal
+
+
+return setmetatable(button, button.mt)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/common.lua b/lib/awful/widget/common.lua
new file mode 100644
index 0000000..e9ae699
--- /dev/null
+++ b/lib/awful/widget/common.lua
@@ -0,0 +1,119 @@
+---------------------------------------------------------------------------
+-- @author Julien Danjou <julien@danjou.info>
+-- @copyright 2008-2009 Julien Danjou
+-- @classmod awful.widget.common
+---------------------------------------------------------------------------
+
+-- Grab environment we need
+local type = type
+local ipairs = ipairs
+local capi = { button = button }
+local wibox = require("wibox")
+local dpi = require("beautiful").xresources.apply_dpi
+
+--- Common utilities for awful widgets
+local common = {}
+
+--- Common method to create buttons.
+-- @tab buttons
+-- @param object
+-- @treturn table
+function common.create_buttons(buttons, object)
+ if buttons then
+ local btns = {}
+ for _, b in ipairs(buttons) do
+ -- Create a proxy button object: it will receive the real
+ -- press and release events, and will propagate them to the
+ -- button object the user provided, but with the object as
+ -- argument.
+ local btn = capi.button { modifiers = b.modifiers, button = b.button }
+ btn:connect_signal("press", function () b:emit_signal("press", object) end)
+ btn:connect_signal("release", function () b:emit_signal("release", object) end)
+ btns[#btns + 1] = btn
+ end
+
+ return btns
+ end
+end
+
+--- Common update method.
+-- @param w The widget.
+-- @tab buttons
+-- @func label Function to generate label parameters from an object.
+-- The function gets passed an object from `objects`, and
+-- has to return `text`, `bg`, `bg_image`, `icon`.
+-- @tab data Current data/cache, indexed by objects.
+-- @tab objects Objects to be displayed / updated.
+function common.list_update(w, buttons, label, data, objects)
+ -- update the widgets, creating them if needed
+ w:reset()
+ for i, o in ipairs(objects) do
+ local cache = data[o]
+ local ib, tb, bgb, tbm, ibm, l
+ if cache then
+ ib = cache.ib
+ tb = cache.tb
+ bgb = cache.bgb
+ tbm = cache.tbm
+ ibm = cache.ibm
+ else
+ ib = wibox.widget.imagebox()
+ tb = wibox.widget.textbox()
+ bgb = wibox.container.background()
+ tbm = wibox.container.margin(tb, dpi(4), dpi(4))
+ ibm = wibox.container.margin(ib, dpi(4))
+ l = wibox.layout.fixed.horizontal()
+
+ -- All of this is added in a fixed widget
+ l:fill_space(true)
+ l:add(ibm)
+ l:add(tbm)
+
+ -- And all of this gets a background
+ bgb:set_widget(l)
+
+ bgb:buttons(common.create_buttons(buttons, o))
+
+ data[o] = {
+ ib = ib,
+ tb = tb,
+ bgb = bgb,
+ tbm = tbm,
+ ibm = ibm,
+ }
+ end
+
+ local text, bg, bg_image, icon, args = label(o, tb)
+ args = args or {}
+
+ -- The text might be invalid, so use pcall.
+ if text == nil or text == "" then
+ tbm:set_margins(0)
+ else
+ if not tb:set_markup_silently(text) then
+ tb:set_markup("<i>&lt;Invalid text&gt;</i>")
+ end
+ end
+ bgb:set_bg(bg)
+ if type(bg_image) == "function" then
+ -- TODO: Why does this pass nil as an argument?
+ bg_image = bg_image(tb,o,nil,objects,i)
+ end
+ bgb:set_bgimage(bg_image)
+ if icon then
+ ib:set_image(icon)
+ else
+ ibm:set_margins(0)
+ end
+
+ bgb.shape = args.shape
+ bgb.shape_border_width = args.shape_border_width
+ bgb.shape_border_color = args.shape_border_color
+
+ w:add(bgb)
+ end
+end
+
+return common
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/graph.lua b/lib/awful/widget/graph.lua
new file mode 100644
index 0000000..e231463
--- /dev/null
+++ b/lib/awful/widget/graph.lua
@@ -0,0 +1,16 @@
+---------------------------------------------------------------------------
+--- This module has been moved to `wibox.widget.graph`
+--
+-- @author Julien Danjou &lt;julien@danjou.info&gt;
+-- @copyright 2009 Julien Danjou
+-- @classmod awful.widget.graph
+---------------------------------------------------------------------------
+local util = require("awful.util")
+
+return util.deprecate_class(
+ require("wibox.widget.graph"),
+ "awful.widget.graph",
+ "wibox.widget.graph"
+)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/init.lua b/lib/awful/widget/init.lua
new file mode 100644
index 0000000..02400a1
--- /dev/null
+++ b/lib/awful/widget/init.lua
@@ -0,0 +1,24 @@
+---------------------------------------------------------------------------
+--- Widget module for awful
+--
+-- @author Julien Danjou &lt;julien@danjou.info&gt;
+-- @copyright 2008-2009 Julien Danjou
+-- @classmod awful.widget
+---------------------------------------------------------------------------
+
+return
+{
+ taglist = require("awful.widget.taglist");
+ tasklist = require("awful.widget.tasklist");
+ button = require("awful.widget.button");
+ launcher = require("awful.widget.launcher");
+ prompt = require("awful.widget.prompt");
+ progressbar = require("awful.widget.progressbar");
+ graph = require("awful.widget.graph");
+ layoutbox = require("awful.widget.layoutbox");
+ textclock = require("awful.widget.textclock");
+ keyboardlayout = require("awful.widget.keyboardlayout");
+ watch = require("awful.widget.watch");
+}
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/keyboardlayout.lua b/lib/awful/widget/keyboardlayout.lua
new file mode 100644
index 0000000..4f79a81
--- /dev/null
+++ b/lib/awful/widget/keyboardlayout.lua
@@ -0,0 +1,308 @@
+---------------------------------------------------------------------------
+-- @author Aleksey Fedotov &lt;lexa@cfotr.com&gt;
+-- @copyright 2015 Aleksey Fedotov
+-- @classmod wibox.widget.keyboardlayout
+---------------------------------------------------------------------------
+
+local capi = {awesome = awesome}
+local setmetatable = setmetatable
+local textbox = require("wibox.widget.textbox")
+local button = require("awful.button")
+local util = require("awful.util")
+local widget_base = require("wibox.widget.base")
+local gdebug = require("gears.debug")
+
+--- Keyboard Layout widget.
+-- awful.widget.keyboardlayout
+local keyboardlayout = { mt = {} }
+
+-- As to the country-code-like symbols below, refer to the names of XKB's
+-- data files in /.../xkb/symbols/*.
+keyboardlayout.xkeyboard_country_code = {
+ ["ad"] = true, -- Andorra
+ ["af"] = true, -- Afganistan
+ ["al"] = true, -- Albania
+ ["am"] = true, -- Armenia
+ ["ara"] = true, -- Arabic
+ ["at"] = true, -- Austria
+ ["az"] = true, -- Azerbaijan
+ ["ba"] = true, -- Bosnia and Herzegovina
+ ["bd"] = true, -- Bangladesh
+ ["be"] = true, -- Belgium
+ ["bg"] = true, -- Bulgaria
+ ["br"] = true, -- Brazil
+ ["bt"] = true, -- Bhutan
+ ["bw"] = true, -- Botswana
+ ["by"] = true, -- Belarus
+ ["ca"] = true, -- Canada
+ ["cd"] = true, -- Congo
+ ["ch"] = true, -- Switzerland
+ ["cm"] = true, -- Cameroon
+ ["cn"] = true, -- China
+ ["cz"] = true, -- Czechia
+ ["de"] = true, -- Germany
+ ["dk"] = true, -- Denmark
+ ["ee"] = true, -- Estonia
+ ["epo"] = true, -- Esperanto
+ ["es"] = true, -- Spain
+ ["et"] = true, -- Ethiopia
+ ["fi"] = true, -- Finland
+ ["fo"] = true, -- Faroe Islands
+ ["fr"] = true, -- France
+ ["gb"] = true, -- United Kingdom
+ ["ge"] = true, -- Georgia
+ ["gh"] = true, -- Ghana
+ ["gn"] = true, -- Guinea
+ ["gr"] = true, -- Greece
+ ["hr"] = true, -- Croatia
+ ["hu"] = true, -- Hungary
+ ["ie"] = true, -- Ireland
+ ["il"] = true, -- Israel
+ ["in"] = true, -- India
+ ["iq"] = true, -- Iraq
+ ["ir"] = true, -- Iran
+ ["is"] = true, -- Iceland
+ ["it"] = true, -- Italy
+ ["jp"] = true, -- Japan
+ ["ke"] = true, -- Kenya
+ ["kg"] = true, -- Kyrgyzstan
+ ["kh"] = true, -- Cambodia
+ ["kr"] = true, -- Korea
+ ["kz"] = true, -- Kazakhstan
+ ["la"] = true, -- Laos
+ ["latam"] = true, -- Latin America
+ ["latin"] = true, -- Latin
+ ["lk"] = true, -- Sri Lanka
+ ["lt"] = true, -- Lithuania
+ ["lv"] = true, -- Latvia
+ ["ma"] = true, -- Morocco
+ ["mao"] = true, -- Maori
+ ["me"] = true, -- Montenegro
+ ["mk"] = true, -- Macedonia
+ ["ml"] = true, -- Mali
+ ["mm"] = true, -- Myanmar
+ ["mn"] = true, -- Mongolia
+ ["mt"] = true, -- Malta
+ ["mv"] = true, -- Maldives
+ ["ng"] = true, -- Nigeria
+ ["nl"] = true, -- Netherlands
+ ["no"] = true, -- Norway
+ ["np"] = true, -- Nepal
+ ["ph"] = true, -- Philippines
+ ["pk"] = true, -- Pakistan
+ ["pl"] = true, -- Poland
+ ["pt"] = true, -- Portugal
+ ["ro"] = true, -- Romania
+ ["rs"] = true, -- Serbia
+ ["ru"] = true, -- Russia
+ ["se"] = true, -- Sweden
+ ["si"] = true, -- Slovenia
+ ["sk"] = true, -- Slovakia
+ ["sn"] = true, -- Senegal
+ ["sy"] = true, -- Syria
+ ["th"] = true, -- Thailand
+ ["tj"] = true, -- Tajikistan
+ ["tm"] = true, -- Turkmenistan
+ ["tr"] = true, -- Turkey
+ ["tw"] = true, -- Taiwan
+ ["tz"] = true, -- Tanzania
+ ["ua"] = true, -- Ukraine
+ ["us"] = true, -- USA
+ ["uz"] = true, -- Uzbekistan
+ ["vn"] = true, -- Vietnam
+ ["za"] = true, -- South Africa
+}
+
+-- Callback for updating current layout.
+local function update_status (self)
+ self._current = awesome.xkb_get_layout_group();
+ local text = ""
+ if (#self._layout > 0) then
+ text = (" " .. self._layout[self._current] .. " ")
+ end
+ self.widget:set_text(text)
+end
+
+--- Auxiliary function for the local function update_layout().
+-- Create an array whose element is a table consisting of the four fields:
+-- vendor, file, section and group_idx, which all correspond to the
+-- xkb_symbols pattern "vendor/file(section):group_idx".
+-- @tparam string group_names The string awesome.xkb_get_group_names() returns.
+-- @treturn table An array of tables whose keys are vendor, file, section, and group_idx.
+function keyboardlayout.get_groups_from_group_names(group_names)
+ if group_names == nil then
+ return nil
+ end
+
+ -- Pattern elements to be captured.
+ local word_pat = "([%w_]+)"
+ local sec_pat = "(%b())"
+ local idx_pat = ":(%d)"
+ -- Pairs of a pattern and its callback. In callbacks, set 'group_idx' to 1
+ -- and return it if there's no specification on 'group_idx' in the given
+ -- pattern.
+ local pattern_and_callback_pairs = {
+ -- vendor/file(section):group_idx
+ ["^" .. word_pat .. "/" .. word_pat .. sec_pat .. idx_pat .. "$"]
+ = function(token, pattern)
+ local vendor, file, section, group_idx = string.match(token, pattern)
+ return vendor, file, section, group_idx
+ end,
+ -- vendor/file(section)
+ ["^" .. word_pat .. "/" .. word_pat .. sec_pat .. "$"]
+ = function(token, pattern)
+ local vendor, file, section = string.match(token, pattern)
+ return vendor, file, section, 1
+ end,
+ -- vendor/file:group_idx
+ ["^" .. word_pat .. "/" .. word_pat .. idx_pat .. "$"]
+ = function(token, pattern)
+ local vendor, file, group_idx = string.match(token, pattern)
+ return vendor, file, nil, group_idx
+ end,
+ -- vendor/file
+ ["^" .. word_pat .. "/" .. word_pat .. "$"]
+ = function(token, pattern)
+ local vendor, file = string.match(token, pattern)
+ return vendor, file, nil, 1
+ end,
+ -- file(section):group_idx
+ ["^" .. word_pat .. sec_pat .. idx_pat .. "$"]
+ = function(token, pattern)
+ local file, section, group_idx = string.match(token, pattern)
+ return nil, file, section, group_idx
+ end,
+ -- file(section)
+ ["^" .. word_pat .. sec_pat .. "$"]
+ = function(token, pattern)
+ local file, section = string.match(token, pattern)
+ return nil, file, section, 1
+ end,
+ -- file:group_idx
+ ["^" .. word_pat .. idx_pat .. "$"]
+ = function(token, pattern)
+ local file, group_idx = string.match(token, pattern)
+ return nil, file, nil, group_idx
+ end,
+ -- file
+ ["^" .. word_pat .. "$"]
+ = function(token, pattern)
+ local file = string.match(token, pattern)
+ return nil, file, nil, 1
+ end
+ }
+
+ -- Split 'group_names' into 'tokens'. The separator is "+".
+ local tokens = {}
+ string.gsub(group_names, "[^+]+", function(match)
+ table.insert(tokens, match)
+ end)
+
+ -- For each token in 'tokens', check if it matches one of the patterns in
+ -- the array 'pattern_and_callback_pairs', where the patterns are used as
+ -- key. If a match is found, extract captured strings using the
+ -- corresponding callback function. Check if those extracted is country
+ -- specific part of a layout. If so, add it to 'layout_groups'; otherwise,
+ -- ignore it.
+ local layout_groups = {}
+ for i = 1, #tokens do
+ for pattern, callback in pairs(pattern_and_callback_pairs) do
+ local vendor, file, section, group_idx = callback(tokens[i], pattern)
+ if file then
+ if not keyboardlayout.xkeyboard_country_code[file] then
+ break
+ end
+
+ if section then
+ section = string.gsub(section, "%(([%w-_]+)%)", "%1")
+ end
+
+ table.insert(layout_groups, { vendor = vendor,
+ file = file,
+ section = section,
+ group_idx = tonumber(group_idx) })
+ break
+ end
+ end
+ end
+
+ return layout_groups
+end
+
+-- Callback for updating list of layouts
+local function update_layout(self)
+ self._layout = {};
+ local layouts = keyboardlayout.get_groups_from_group_names(awesome.xkb_get_group_names())
+ if layouts == nil or layouts[1] == nil then
+ gdebug.print_error("Failed to get list of keyboard groups")
+ return
+ end
+ if #layouts == 1 then
+ layouts[1].group_idx = 0
+ end
+ for _, v in ipairs(layouts) do
+ local layout_name = self.layout_name(v)
+ -- Please note that numbers of groups reported by xkb_get_group_names
+ -- is greater by one than the real group number.
+ self._layout[v.group_idx - 1] = layout_name
+ end
+ update_status(self)
+end
+
+--- Create a keyboard layout widget. It shows current keyboard layout name in a textbox.
+-- @return A keyboard layout widget.
+function keyboardlayout.new()
+ local widget = textbox()
+ local self = widget_base.make_widget(widget)
+
+ self.widget = widget
+
+ self.layout_name = function(v)
+ local name = v.file
+ if v.section ~= nil then
+ name = name .. "(" .. v.section .. ")"
+ end
+ return name
+ end
+
+ self.next_layout = function()
+ self.set_layout((self._current + 1) % (#self._layout + 1))
+ end
+
+ self.set_layout = function(group_number)
+ if (0 > group_number) or (group_number > #self._layout) then
+ error("Invalid group number: " .. group_number ..
+ "expected number from 0 to " .. #self._layout)
+ return;
+ end
+ awesome.xkb_set_layout_group(group_number);
+ end
+
+ update_layout(self);
+
+ -- callback for processing layout changes
+ capi.awesome.connect_signal("xkb::map_changed",
+ function () update_layout(self) end)
+ capi.awesome.connect_signal("xkb::group_changed",
+ function () update_status(self) end);
+
+ -- Mouse bindings
+ self:buttons(
+ util.table.join(button({ }, 1, self.next_layout))
+ )
+
+ return self
+end
+
+local _instance = nil;
+
+function keyboardlayout.mt:__call(...)
+ if _instance == nil then
+ _instance = keyboardlayout.new(...)
+ end
+ return _instance
+end
+
+return setmetatable(keyboardlayout, keyboardlayout.mt)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/launcher.lua b/lib/awful/widget/launcher.lua
new file mode 100644
index 0000000..a944908
--- /dev/null
+++ b/lib/awful/widget/launcher.lua
@@ -0,0 +1,41 @@
+---------------------------------------------------------------------------
+-- @author Julien Danjou &lt;julien@danjou.info&gt;
+-- @copyright 2008-2009 Julien Danjou
+-- @classmod awful.widget.launcher
+---------------------------------------------------------------------------
+
+local setmetatable = setmetatable
+local util = require("awful.util")
+local spawn = require("awful.spawn")
+local wbutton = require("awful.widget.button")
+local button = require("awful.button")
+
+local launcher = { mt = {} }
+
+--- Create a button widget which will launch a command.
+-- @param args Standard widget table arguments, plus image for the image path
+-- and command for the command to run on click, or either menu to create menu.
+-- @return A launcher widget.
+function launcher.new(args)
+ if not args.command and not args.menu then return end
+ local w = wbutton(args)
+ if not w then return end
+
+ local b
+ if args.command then
+ b = util.table.join(w:buttons(), button({}, 1, nil, function () spawn(args.command) end))
+ elseif args.menu then
+ b = util.table.join(w:buttons(), button({}, 1, nil, function () args.menu:toggle() end))
+ end
+
+ w:buttons(b)
+ return w
+end
+
+function launcher.mt:__call(...)
+ return launcher.new(...)
+end
+
+return setmetatable(launcher, launcher.mt)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/layoutbox.lua b/lib/awful/widget/layoutbox.lua
new file mode 100644
index 0000000..c5f8ed3
--- /dev/null
+++ b/lib/awful/widget/layoutbox.lua
@@ -0,0 +1,73 @@
+---------------------------------------------------------------------------
+--- Layoutbox widget.
+--
+-- @author Julien Danjou &lt;julien@danjou.info&gt;
+-- @copyright 2009 Julien Danjou
+-- @classmod awful.widget.layoutbox
+---------------------------------------------------------------------------
+
+local setmetatable = setmetatable
+local capi = { screen = screen, tag = tag }
+local layout = require("awful.layout")
+local tooltip = require("awful.tooltip")
+local beautiful = require("beautiful")
+local imagebox = require("wibox.widget.imagebox")
+
+local function get_screen(s)
+ return s and capi.screen[s]
+end
+
+local layoutbox = { mt = {} }
+
+local boxes = nil
+
+local function update(w, screen)
+ screen = get_screen(screen)
+ local name = layout.getname(layout.get(screen))
+ w._layoutbox_tooltip:set_text(name or "[no name]")
+ w:set_image(name and beautiful["layout_" .. name])
+end
+
+local function update_from_tag(t)
+ local screen = get_screen(t.screen)
+ local w = boxes[screen]
+ if w then
+ update(w, screen)
+ end
+end
+
+--- Create a layoutbox widget. It draws a picture with the current layout
+-- symbol of the current tag.
+-- @param screen The screen number that the layout will be represented for.
+-- @return An imagebox widget configured as a layoutbox.
+function layoutbox.new(screen)
+ screen = get_screen(screen or 1)
+
+ -- Do we already have the update callbacks registered?
+ if boxes == nil then
+ boxes = setmetatable({}, { __mode = "kv" })
+ capi.tag.connect_signal("property::selected", update_from_tag)
+ capi.tag.connect_signal("property::layout", update_from_tag)
+ layoutbox.boxes = boxes
+ end
+
+ -- Do we already have a layoutbox for this screen?
+ local w = boxes[screen]
+ if not w then
+ w = imagebox()
+ w._layoutbox_tooltip = tooltip {objects = {w}, delay_show = 1}
+
+ update(w, screen)
+ boxes[screen] = w
+ end
+
+ return w
+end
+
+function layoutbox.mt:__call(...)
+ return layoutbox.new(...)
+end
+
+return setmetatable(layoutbox, layoutbox.mt)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/progressbar.lua b/lib/awful/widget/progressbar.lua
new file mode 100644
index 0000000..11147f4
--- /dev/null
+++ b/lib/awful/widget/progressbar.lua
@@ -0,0 +1,16 @@
+---------------------------------------------------------------------------
+--- This module has been moved to `wibox.widget.progressbar`
+--
+-- @author Julien Danjou &lt;julien@danjou.info&gt;
+-- @copyright 2009 Julien Danjou
+-- @classmod awful.widget.progressbar
+---------------------------------------------------------------------------
+local util = require("awful.util")
+
+return util.deprecate_class(
+ require("wibox.widget.progressbar"),
+ "awful.widget.progressbar",
+ "wibox.widget.progressbar"
+)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/prompt.lua b/lib/awful/widget/prompt.lua
new file mode 100644
index 0000000..ff9d904
--- /dev/null
+++ b/lib/awful/widget/prompt.lua
@@ -0,0 +1,64 @@
+---------------------------------------------------------------------------
+-- @author Julien Danjou &lt;julien@danjou.info&gt;
+-- @copyright 2009 Julien Danjou
+-- @classmod awful.widget.prompt
+---------------------------------------------------------------------------
+
+local setmetatable = setmetatable
+
+local completion = require("awful.completion")
+local util = require("awful.util")
+local spawn = require("awful.spawn")
+local prompt = require("awful.prompt")
+local widget_base = require("wibox.widget.base")
+local textbox = require("wibox.widget.textbox")
+local type = type
+
+local widgetprompt = { mt = {} }
+
+--- Run method for promptbox.
+--
+-- @param promptbox The promptbox to run.
+local function run(promptbox)
+ return prompt.run {
+ prompt = promptbox.prompt,
+ textbox = promptbox.widget,
+ completion_callback = completion.shell,
+ history_path = util.get_cache_dir() .. "/history",
+ exe_callback = function (...)
+ promptbox:spawn_and_handle_error(...)
+ end,
+ }
+end
+
+local function spawn_and_handle_error(self, ...)
+ local result = spawn(...)
+ if type(result) == "string" then
+ self.widget:set_text(result)
+ end
+end
+
+--- Create a prompt widget which will launch a command.
+--
+-- @param args Arguments table. "prompt" is the prompt to use.
+-- @return A launcher widget.
+function widgetprompt.new(args)
+ args = args or {}
+ local widget = textbox()
+ local promptbox = widget_base.make_widget(widget)
+
+ promptbox.widget = widget
+ promptbox.widget:set_ellipsize("start")
+ promptbox.run = run
+ promptbox.spawn_and_handle_error = spawn_and_handle_error
+ promptbox.prompt = args.prompt or "Run: "
+ return promptbox
+end
+
+function widgetprompt.mt:__call(...)
+ return widgetprompt.new(...)
+end
+
+return setmetatable(widgetprompt, widgetprompt.mt)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/taglist.lua b/lib/awful/widget/taglist.lua
new file mode 100644
index 0000000..d8cf475
--- /dev/null
+++ b/lib/awful/widget/taglist.lua
@@ -0,0 +1,452 @@
+---------------------------------------------------------------------------
+--- Taglist widget module for awful
+--
+-- @author Julien Danjou &lt;julien@danjou.info&gt;
+-- @copyright 2008-2009 Julien Danjou
+-- @classmod awful.widget.taglist
+---------------------------------------------------------------------------
+
+-- Grab environment we need
+local capi = { screen = screen,
+ awesome = awesome,
+ client = client }
+local setmetatable = setmetatable
+local pairs = pairs
+local ipairs = ipairs
+local table = table
+local common = require("awful.widget.common")
+local util = require("awful.util")
+local tag = require("awful.tag")
+local beautiful = require("beautiful")
+local fixed = require("wibox.layout.fixed")
+local surface = require("gears.surface")
+local timer = require("gears.timer")
+
+local function get_screen(s)
+ return s and capi.screen[s]
+end
+
+local taglist = { mt = {} }
+taglist.filter = {}
+
+--- The tag list main foreground (text) color.
+-- @beautiful beautiful.taglist_fg_focus
+-- @param[opt=fg_focus] color
+-- @see gears.color
+
+--- The tag list main background color.
+-- @beautiful beautiful.taglist_bg_focus
+-- @param[opt=bg_focus] color
+-- @see gears.color
+
+--- The tag list urgent elements foreground (text) color.
+-- @beautiful beautiful.taglist_fg_urgent
+-- @param[opt=fg_urgent] color
+-- @see gears.color
+
+--- The tag list urgent elements background color.
+-- @beautiful beautiful.taglist_bg_urgent
+-- @param[opt=bg_urgent] color
+-- @see gears.color
+
+--- The tag list occupied elements background color.
+-- @beautiful beautiful.taglist_bg_occupied
+-- @param color
+-- @see gears.color
+
+--- The tag list occupied elements foreground (text) color.
+-- @beautiful beautiful.taglist_fg_occupied
+-- @param color
+-- @see gears.color
+
+--- The tag list empty elements background color.
+-- @beautiful beautiful.taglist_bg_empty
+-- @param color
+-- @see gears.color
+
+--- The tag list empty elements foreground (text) color.
+-- @beautiful beautiful.taglist_fg_empty
+-- @param color
+-- @see gears.color
+
+--- The selected elements background image.
+-- @beautiful beautiful.taglist_squares_sel
+-- @param surface
+-- @see gears.surface
+
+--- The unselected elements background image.
+-- @beautiful beautiful.taglist_squares_unsel
+-- @param surface
+-- @see gears.surface
+
+--- The selected empty elements background image.
+-- @beautiful beautiful.taglist_squares_sel_empty
+-- @param surface
+-- @see gears.surface
+
+--- The unselected empty elements background image.
+-- @beautiful beautiful.taglist_squares_unsel_empty
+-- @param surface
+-- @see gears.surface
+
+--- If the background images can be resized.
+-- @beautiful beautiful.taglist_squares_resize
+-- @param boolean
+
+--- Do not display the tag icons, even if they are set.
+-- @beautiful beautiful.taglist_disable_icon
+-- @param boolean
+
+--- The taglist font.
+-- @beautiful beautiful.taglist_font
+-- @param string
+
+--- The main shape used for the elements.
+-- This will be the fallback for state specific shapes.
+-- To get a shape for the whole taglist, use `wibox.container.background`.
+-- @beautiful beautiful.taglist_shape
+-- @param[opt=rectangle] gears.shape
+-- @see gears.shape
+-- @see beautiful.taglist_shape_empty
+-- @see beautiful.taglist_shape_focus
+-- @see beautiful.taglist_shape_urgent
+
+--- The shape elements border width.
+-- @beautiful beautiful.taglist_shape_border_width
+-- @param[opt=0] number
+-- @see wibox.container.background
+
+--- The elements shape border color.
+-- @beautiful beautiful.taglist_shape_border_color
+-- @param color
+-- @see gears.color
+
+--- The shape used for the empty elements.
+-- @beautiful beautiful.taglist_shape_empty
+-- @param[opt=rectangle] gears.shape
+-- @see gears.shape
+
+--- The shape used for the empty elements border width.
+-- @beautiful beautiful.taglist_shape_border_width_empty
+-- @param[opt=0] number
+-- @see wibox.container.background
+
+--- The empty elements shape border color.
+-- @beautiful beautiful.taglist_shape_border_color_empty
+-- @param color
+-- @see gears.color
+
+--- The shape used for the selected elements.
+-- @beautiful beautiful.taglist_shape_focus
+-- @param[opt=rectangle] gears.shape
+-- @see gears.shape
+
+--- The shape used for the selected elements border width.
+-- @beautiful beautiful.taglist_shape_border_width_focus
+-- @param[opt=0] number
+-- @see wibox.container.background
+
+--- The selected elements shape border color.
+-- @beautiful beautiful.taglist_shape_border_color_focus
+-- @param color
+-- @see gears.color
+
+--- The shape used for the urgent elements.
+-- @beautiful beautiful.taglist_shape_urgent
+-- @param[opt=rectangle] gears.shape
+-- @see gears.shape
+
+--- The shape used for the urgent elements border width.
+-- @beautiful beautiful.taglist_shape_border_width_urgent
+-- @param[opt=0] number
+-- @see wibox.container.background
+
+--- The urgents elements shape border color.
+-- @beautiful beautiful.taglist_shape_border_color_urgent
+-- @param color
+-- @see gears.color
+
+local instances = nil
+
+function taglist.taglist_label(t, args)
+ if not args then args = {} end
+ local theme = beautiful.get()
+ local fg_focus = args.fg_focus or theme.taglist_fg_focus or theme.fg_focus
+ local bg_focus = args.bg_focus or theme.taglist_bg_focus or theme.bg_focus
+ local fg_urgent = args.fg_urgent or theme.taglist_fg_urgent or theme.fg_urgent
+ local bg_urgent = args.bg_urgent or theme.taglist_bg_urgent or theme.bg_urgent
+ local bg_occupied = args.bg_occupied or theme.taglist_bg_occupied
+ local fg_occupied = args.fg_occupied or theme.taglist_fg_occupied
+ local bg_empty = args.bg_empty or theme.taglist_bg_empty
+ local fg_empty = args.fg_empty or theme.taglist_fg_empty
+ local taglist_squares_sel = args.squares_sel or theme.taglist_squares_sel
+ local taglist_squares_unsel = args.squares_unsel or theme.taglist_squares_unsel
+ local taglist_squares_sel_empty = args.squares_sel_empty or theme.taglist_squares_sel_empty
+ local taglist_squares_unsel_empty = args.squares_unsel_empty or theme.taglist_squares_unsel_empty
+ local taglist_squares_resize = theme.taglist_squares_resize or args.squares_resize or "true"
+ local taglist_disable_icon = args.taglist_disable_icon or theme.taglist_disable_icon or false
+ local font = args.font or theme.taglist_font or theme.font or ""
+ local text = nil
+ local sel = capi.client.focus
+ local bg_color = nil
+ local fg_color = nil
+ local bg_image
+ local icon
+ local shape = args.shape or theme.taglist_shape
+ local shape_border_width = args.shape_border_width or theme.taglist_shape_border_width
+ local shape_border_color = args.shape_border_color or theme.taglist_shape_border_color
+ -- TODO: Re-implement bg_resize
+ local bg_resize = false -- luacheck: ignore
+ local is_selected = false
+ local cls = t:clients()
+
+ if sel and taglist_squares_sel then
+ -- Check that the selected client is tagged with 't'.
+ local seltags = sel:tags()
+ for _, v in ipairs(seltags) do
+ if v == t then
+ bg_image = taglist_squares_sel
+ bg_resize = taglist_squares_resize == "true"
+ is_selected = true
+ break
+ end
+ end
+ end
+ if #cls == 0 and t.selected and taglist_squares_sel_empty then
+ bg_image = taglist_squares_sel_empty
+ bg_resize = taglist_squares_resize == "true"
+ elseif not is_selected then
+ if #cls > 0 then
+ if taglist_squares_unsel then
+ bg_image = taglist_squares_unsel
+ bg_resize = taglist_squares_resize == "true"
+ end
+ if bg_occupied then bg_color = bg_occupied end
+ if fg_occupied then fg_color = fg_occupied end
+ else
+ if taglist_squares_unsel_empty then
+ bg_image = taglist_squares_unsel_empty
+ bg_resize = taglist_squares_resize == "true"
+ end
+ if bg_empty then bg_color = bg_empty end
+ if fg_empty then fg_color = fg_empty end
+
+ if args.shape_empty or theme.taglist_shape_empty then
+ shape = args.shape_empty or theme.taglist_shape_empty
+ end
+
+ if args.shape_border_width_empty or theme.taglist_shape_border_width_empty then
+ shape_border_width = args.shape_border_width_empty or theme.taglist_shape_border_width_empty
+ end
+
+ if args.shape_border_color_empty or theme.taglist_shape_border_color_empty then
+ shape_border_color = args.shape_border_color_empty or theme.taglist_shape_border_color_empty
+ end
+ end
+ end
+ if t.selected then
+ bg_color = bg_focus
+ fg_color = fg_focus
+
+ if args.shape_focus or theme.taglist_shape_focus then
+ shape = args.shape_focus or theme.taglist_shape_focus
+ end
+
+ if args.shape_border_width_focus or theme.taglist_shape_border_width_focus then
+ shape = args.shape_border_width_focus or theme.taglist_shape_border_width_focus
+ end
+
+ if args.shape_border_color_focus or theme.taglist_shape_border_color_focus then
+ shape = args.shape_border_color_focus or theme.taglist_shape_border_color_focus
+ end
+
+ elseif tag.getproperty(t, "urgent") then
+ if bg_urgent then bg_color = bg_urgent end
+ if fg_urgent then fg_color = fg_urgent end
+
+ if args.shape_urgent or theme.taglist_shape_urgent then
+ shape = args.shape_urgent or theme.taglist_shape_urgent
+ end
+
+ if args.shape_border_width_urgent or theme.taglist_shape_border_width_urgent then
+ shape_border_width = args.shape_border_width_urgent or theme.taglist_shape_border_width_urgent
+ end
+
+ if args.shape_border_color_urgent or theme.taglist_shape_border_color_urgent then
+ shape_border_color = args.shape_border_color_urgent or theme.taglist_shape_border_color_urgent
+ end
+ end
+
+ if not tag.getproperty(t, "icon_only") then
+ text = "<span font_desc='"..font.."'>"
+ if fg_color then
+ text = text .. "<span color='" .. util.ensure_pango_color(fg_color) ..
+ "'>" .. (util.escape(t.name) or "") .. "</span>"
+ else
+ text = text .. (util.escape(t.name) or "")
+ end
+ text = text .. "</span>"
+ end
+ if not taglist_disable_icon then
+ if t.icon then
+ icon = surface.load(t.icon)
+ end
+ end
+
+ local other_args = {
+ shape = shape,
+ shape_border_width = shape_border_width,
+ shape_border_color = shape_border_color,
+ }
+
+ return text, bg_color, bg_image, not taglist_disable_icon and icon or nil, other_args
+end
+
+local function taglist_update(s, w, buttons, filter, data, style, update_function)
+ local tags = {}
+ for _, t in ipairs(s.tags) do
+ if not tag.getproperty(t, "hide") and filter(t) then
+ table.insert(tags, t)
+ end
+ end
+
+ local function label(c) return taglist.taglist_label(c, style) end
+
+ update_function(w, buttons, label, data, tags)
+end
+
+--- Create a new taglist widget. The last two arguments (update_function
+-- and base_widget) serve to customize the layout of the taglist (eg. to
+-- make it vertical). For that, you will need to copy the
+-- awful.widget.common.list_update function, make your changes to it
+-- and pass it as update_function here. Also change the base_widget if the
+-- default is not what you want.
+-- @param screen The screen to draw taglist for.
+-- @param filter Filter function to define what clients will be listed.
+-- @param buttons A table with buttons binding to set.
+-- @tparam[opt={}] table style The style overrides default theme.
+-- @tparam[opt=nil] string|pattern style.fg_focus
+-- @tparam[opt=nil] string|pattern style.bg_focus
+-- @tparam[opt=nil] string|pattern style.fg_urgent
+-- @tparam[opt=nil] string|pattern style.bg_urgent
+-- @tparam[opt=nil] string|pattern style.bg_occupied
+-- @tparam[opt=nil] string|pattern style.fg_occupied
+-- @tparam[opt=nil] string|pattern style.bg_empty
+-- @tparam[opt=nil] string|pattern style.fg_empty
+-- @tparam[opt=nil] string style.taglist_squares_sel
+-- @tparam[opt=nil] string style.taglist_squares_unsel
+-- @tparam[opt=nil] string style.taglist_squares_sel_empty
+-- @tparam[opt=nil] string style.taglist_squares_unsel_empty
+-- @tparam[opt=nil] string style.taglist_squares_resize
+-- @tparam[opt=nil] string style.taglist_disable_icon
+-- @tparam[opt=nil] string style.font
+-- @tparam[opt=nil] number style.spacing The spacing between tags.
+-- @param[opt] update_function Function to create a tag widget on each
+-- update. See `awful.widget.common`.
+-- @param[opt] base_widget Optional container widget for tag widgets. Default
+-- is wibox.layout.fixed.horizontal().
+-- @param base_widget.bg_focus The background color for focused client.
+-- @param base_widget.fg_focus The foreground color for focused client.
+-- @param base_widget.bg_urgent The background color for urgent clients.
+-- @param base_widget.fg_urgent The foreground color for urgent clients.
+-- @param[opt] base_widget.squares_sel A user provided image for selected squares.
+-- @param[opt] base_widget.squares_unsel A user provided image for unselected squares.
+-- @param[opt] base_widget.squares_sel_empty A user provided image for selected squares for empty tags.
+-- @param[opt] base_widget.squares_unsel_empty A user provided image for unselected squares for empty tags.
+-- @param[opt] base_widget.squares_resize True or false to resize squares.
+-- @param base_widget.font The font.
+-- @function awful.taglist
+function taglist.new(screen, filter, buttons, style, update_function, base_widget)
+ screen = get_screen(screen)
+ local uf = update_function or common.list_update
+ local w = base_widget or fixed.horizontal()
+
+ if w.set_spacing and (style and style.spacing or beautiful.taglist_spacing) then
+ w:set_spacing(style and style.spacing or beautiful.taglist_spacing)
+ end
+
+ local data = setmetatable({}, { __mode = 'k' })
+
+ local queued_update = {}
+ function w._do_taglist_update()
+ -- Add a delayed callback for the first update.
+ if not queued_update[screen] then
+ timer.delayed_call(function()
+ if screen.valid then
+ taglist_update(screen, w, buttons, filter, data, style, uf)
+ end
+ queued_update[screen] = false
+ end)
+ queued_update[screen] = true
+ end
+ end
+ if instances == nil then
+ instances = setmetatable({}, { __mode = "k" })
+ local function u(s)
+ local i = instances[get_screen(s)]
+ if i then
+ for _, tlist in pairs(i) do
+ tlist._do_taglist_update()
+ end
+ end
+ end
+ local uc = function (c) return u(c.screen) end
+ local ut = function (t) return u(t.screen) end
+ capi.client.connect_signal("focus", uc)
+ capi.client.connect_signal("unfocus", uc)
+ tag.attached_connect_signal(nil, "property::selected", ut)
+ tag.attached_connect_signal(nil, "property::icon", ut)
+ tag.attached_connect_signal(nil, "property::hide", ut)
+ tag.attached_connect_signal(nil, "property::name", ut)
+ tag.attached_connect_signal(nil, "property::activated", ut)
+ tag.attached_connect_signal(nil, "property::screen", ut)
+ tag.attached_connect_signal(nil, "property::index", ut)
+ tag.attached_connect_signal(nil, "property::urgent", ut)
+ capi.client.connect_signal("property::screen", function(c, old_screen)
+ u(c.screen)
+ u(old_screen)
+ end)
+ capi.client.connect_signal("tagged", uc)
+ capi.client.connect_signal("untagged", uc)
+ capi.client.connect_signal("unmanage", uc)
+ capi.screen.connect_signal("removed", function(s)
+ instances[get_screen(s)] = nil
+ end)
+ end
+ w._do_taglist_update()
+ local list = instances[screen]
+ if not list then
+ list = setmetatable({}, { __mode = "v" })
+ instances[screen] = list
+ end
+ table.insert(list, w)
+ return w
+end
+
+--- Filtering function to include all nonempty tags on the screen.
+-- @param t The tag.
+-- @return true if t is not empty, else false
+function taglist.filter.noempty(t)
+ return #t:clients() > 0 or t.selected
+end
+
+--- Filtering function to include selected tags on the screen.
+-- @param t The tag.
+-- @return true if t is not empty, else false
+function taglist.filter.selected(t)
+ return t.selected
+end
+
+--- Filtering function to include all tags on the screen.
+-- @return true
+function taglist.filter.all()
+ return true
+end
+
+function taglist.mt:__call(...)
+ return taglist.new(...)
+end
+
+return setmetatable(taglist, taglist.mt)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/tasklist.lua b/lib/awful/widget/tasklist.lua
new file mode 100644
index 0000000..d5580c1
--- /dev/null
+++ b/lib/awful/widget/tasklist.lua
@@ -0,0 +1,573 @@
+---------------------------------------------------------------------------
+--- Tasklist widget module for awful.
+--
+-- <a name="status_icons"></a>
+-- **Status icons:**
+--
+-- By default, the tasklist prepends some symbols in front of the client name.
+-- This is used to notify that the client has some specific properties that are
+-- currently enabled. This can be disabled using
+-- `beautiful.tasklist_plain_task_name`=true in the theme.
+--
+-- <table class='widget_list' border=1>
+-- <tr style='font-weight: bold;'>
+-- <th align='center'>Icon</th>
+-- <th align='center'>Client property</th>
+-- </tr>
+-- <tr><td>▪</td><td><a href="./client.html#client.sticky">sticky</a></td></tr>
+-- <tr><td>⌃</td><td><a href="./client.html#client.ontop">ontop</a></td></tr>
+-- <tr><td>▴</td><td><a href="./client.html#client.above">above</a></td></tr>
+-- <tr><td>▾</td><td><a href="./client.html#client.below">below</a></td></tr>
+-- <tr><td>✈</td><td><a href="./client.html#client.floating">floating</a></td></tr>
+-- <tr><td>+</td><td><a href="./client.html#client.maximized">maximized</a></td></tr>
+-- <tr><td>⬌</td><td><a href="./client.html#client.maximized_horizontal">maximized_horizontal</a></td></tr>
+-- <tr><td>⬍</td><td><a href="./client.html#client.maximized_vertical">maximized_vertical</a></td></tr>
+-- </table>
+--
+-- @author Julien Danjou &lt;julien@danjou.info&gt;
+-- @copyright 2008-2009 Julien Danjou
+-- @classmod awful.widget.tasklist
+---------------------------------------------------------------------------
+
+-- Grab environment we need
+local capi = { screen = screen,
+ client = client }
+local ipairs = ipairs
+local setmetatable = setmetatable
+local table = table
+local common = require("awful.widget.common")
+local beautiful = require("beautiful")
+local util = require("awful.util")
+local tag = require("awful.tag")
+local flex = require("wibox.layout.flex")
+local timer = require("gears.timer")
+
+local function get_screen(s)
+ return s and screen[s]
+end
+
+local tasklist = { mt = {} }
+
+local instances
+
+--- The default foreground (text) color.
+-- @beautiful beautiful.tasklist_fg_normal
+-- @tparam[opt=nil] string|pattern fg_normal
+-- @see gears.color
+
+--- The default background color.
+-- @beautiful beautiful.tasklist_bg_normal
+-- @tparam[opt=nil] string|pattern bg_normal
+-- @see gears.color
+
+--- The focused client foreground (text) color.
+-- @beautiful beautiful.tasklist_fg_focus
+-- @tparam[opt=nil] string|pattern fg_focus
+-- @see gears.color
+
+--- The focused client background color.
+-- @beautiful beautiful.tasklist_bg_focus
+-- @tparam[opt=nil] string|pattern bg_focus
+-- @see gears.color
+
+--- The urgent clients foreground (text) color.
+-- @beautiful beautiful.tasklist_fg_urgent
+-- @tparam[opt=nil] string|pattern fg_urgent
+-- @see gears.color
+
+--- The urgent clients background color.
+-- @beautiful beautiful.tasklist_bg_urgent
+-- @tparam[opt=nil] string|pattern bg_urgent
+-- @see gears.color
+
+--- The minimized clients foreground (text) color.
+-- @beautiful beautiful.tasklist_fg_minimize
+-- @tparam[opt=nil] string|pattern fg_minimize
+-- @see gears.color
+
+--- The minimized clients background color.
+-- @beautiful beautiful.tasklist_bg_minimize
+-- @tparam[opt=nil] string|pattern bg_minimize
+-- @see gears.color
+
+--- The elements default background image.
+-- @beautiful beautiful.tasklist_bg_image_normal
+-- @tparam[opt=nil] string bg_image_normal
+
+--- The focused client background image.
+-- @beautiful beautiful.tasklist_bg_image_focus
+-- @tparam[opt=nil] string bg_image_focus
+
+--- The urgent clients background image.
+-- @beautiful beautiful.tasklist_bg_image_urgent
+-- @tparam[opt=nil] string bg_image_urgent
+
+--- The minimized clients background image.
+-- @beautiful beautiful.tasklist_bg_image_minimize
+-- @tparam[opt=nil] string bg_image_minimize
+
+--- Disable the tasklist client icons.
+-- @beautiful beautiful.tasklist_tasklist_disable_icon
+-- @tparam[opt=false] boolean tasklist_disable_icon
+
+--- Disable the extra tasklist client property notification icons.
+--
+-- See the <a href="status_icons">Status icons</a> section for more details.
+--
+-- @beautiful beautiful.tasklist_plain_task_name
+-- @tparam[opt=false] boolean tasklist_plain_task_name
+
+--- The tasklist font.
+-- @beautiful beautiful.tasklist_font
+-- @tparam[opt=nil] string font
+
+--- The focused client alignment.
+-- @beautiful beautiful.tasklist_align
+-- @tparam[opt=left] string align *left*, *right* or *center*
+
+--- The focused client title alignment.
+-- @beautiful beautiful.tasklist_font_focus
+-- @tparam[opt=nil] string font_focus
+
+--- The minimized clients font.
+-- @beautiful beautiful.tasklist_font_minimized
+-- @tparam[opt=nil] string font_minimized
+
+--- The urgent clients font.
+-- @beautiful beautiful.tasklist_font_urgent
+-- @tparam[opt=nil] string font_urgent
+
+--- The space between the tasklist elements.
+-- @beautiful beautiful.tasklist_spacing
+-- @tparam[opt=0] number spacing The spacing between tags.
+
+--- The default tasklist elements shape.
+-- @beautiful beautiful.tasklist_shape
+-- @tparam[opt=nil] gears.shape shape
+
+--- The default tasklist elements border width.
+-- @beautiful beautiful.tasklist_shape_border_width
+-- @tparam[opt=0] number shape_border_width
+
+--- The default tasklist elements border color.
+-- @beautiful beautiful.tasklist_shape_border_color
+-- @tparam[opt=nil] string|color shape_border_color
+-- @see gears.color
+
+--- The focused client shape.
+-- @beautiful beautiful.tasklist_shape_focus
+-- @tparam[opt=nil] gears.shape shape_focus
+
+--- The focused client border width.
+-- @beautiful beautiful.tasklist_shape_border_width_focus
+-- @tparam[opt=0] number shape_border_width_focus
+
+--- The focused client border color.
+-- @beautiful beautiful.tasklist_shape_border_color_focus
+-- @tparam[opt=nil] string|color shape_border_color_focus
+-- @see gears.color
+
+--- The minimized clients shape.
+-- @beautiful beautiful.tasklist_shape_minimized
+-- @tparam[opt=nil] gears.shape shape_minimized
+
+--- The minimized clients border width.
+-- @beautiful beautiful.tasklist_shape_border_width_minimized
+-- @tparam[opt=0] number shape_border_width_minimized
+
+--- The minimized clients border color.
+-- @beautiful beautiful.tasklist_shape_border_color_minimized
+-- @tparam[opt=nil] string|color shape_border_color_minimized
+-- @see gears.color
+
+--- The urgent clients shape.
+-- @beautiful beautiful.tasklist_shape_urgent
+-- @tparam[opt=nil] gears.shape shape_urgent
+
+--- The urgent clients border width.
+-- @beautiful beautiful.tasklist_shape_border_width_urgent
+-- @tparam[opt=0] number shape_border_width_urgent
+
+--- The urgent clients border color.
+-- @beautiful beautiful.tasklist_shape_border_color_urgent
+-- @tparam[opt=nil] string|color shape_border_color_urgent
+-- @see gears.color
+
+-- Public structures
+tasklist.filter = {}
+
+local function tasklist_label(c, args, tb)
+ if not args then args = {} end
+ local theme = beautiful.get()
+ local align = args.align or theme.tasklist_align or "left"
+ local fg_normal = util.ensure_pango_color(args.fg_normal or theme.tasklist_fg_normal or theme.fg_normal, "white")
+ local bg_normal = args.bg_normal or theme.tasklist_bg_normal or theme.bg_normal or "#000000"
+ local fg_focus = util.ensure_pango_color(args.fg_focus or theme.tasklist_fg_focus or theme.fg_focus, fg_normal)
+ local bg_focus = args.bg_focus or theme.tasklist_bg_focus or theme.bg_focus or bg_normal
+ local fg_urgent = util.ensure_pango_color(args.fg_urgent or theme.tasklist_fg_urgent or theme.fg_urgent, fg_normal)
+ local bg_urgent = args.bg_urgent or theme.tasklist_bg_urgent or theme.bg_urgent or bg_normal
+ local fg_minimize = util.ensure_pango_color(args.fg_minimize or theme.tasklist_fg_minimize or theme.fg_minimize, fg_normal)
+ local bg_minimize = args.bg_minimize or theme.tasklist_bg_minimize or theme.bg_minimize or bg_normal
+ local bg_image_normal = args.bg_image_normal or theme.bg_image_normal
+ local bg_image_focus = args.bg_image_focus or theme.bg_image_focus
+ local bg_image_urgent = args.bg_image_urgent or theme.bg_image_urgent
+ local bg_image_minimize = args.bg_image_minimize or theme.bg_image_minimize
+ local tasklist_disable_icon = args.tasklist_disable_icon or theme.tasklist_disable_icon or false
+ local font = args.font or theme.tasklist_font or theme.font or ""
+ local font_focus = args.font_focus or theme.tasklist_font_focus or theme.font_focus or font or ""
+ local font_minimized = args.font_minimized or theme.tasklist_font_minimized or theme.font_minimized or font or ""
+ local font_urgent = args.font_urgent or theme.tasklist_font_urgent or theme.font_urgent or font or ""
+ local text = ""
+ local name = ""
+ local bg
+ local bg_image
+ local shape = args.shape or theme.tasklist_shape
+ local shape_border_width = args.shape_border_width or theme.tasklist_shape_border_width
+ local shape_border_color = args.shape_border_color or theme.tasklist_shape_border_color
+
+ -- symbol to use to indicate certain client properties
+ local sticky = args.sticky or theme.tasklist_sticky or "▪"
+ local ontop = args.ontop or theme.tasklist_ontop or '⌃'
+ local above = args.above or theme.tasklist_above or '▴'
+ local below = args.below or theme.tasklist_below or '▾'
+ local floating = args.floating or theme.tasklist_floating or '✈'
+ local maximized = args.maximized or theme.tasklist_maximized or '<b>+</b>'
+ local maximized_horizontal = args.maximized_horizontal or theme.tasklist_maximized_horizontal or '⬌'
+ local maximized_vertical = args.maximized_vertical or theme.tasklist_maximized_vertical or '⬍'
+
+ tb:set_align(align)
+
+ if not theme.tasklist_plain_task_name then
+ if c.sticky then name = name .. sticky end
+
+ if c.ontop then name = name .. ontop
+ elseif c.above then name = name .. above
+ elseif c.below then name = name .. below end
+
+ if c.maximized then
+ name = name .. maximized
+ else
+ if c.maximized_horizontal then name = name .. maximized_horizontal end
+ if c.maximized_vertical then name = name .. maximized_vertical end
+ if c.floating then name = name .. floating end
+ end
+ end
+
+ if c.minimized then
+ name = name .. (util.escape(c.icon_name) or util.escape(c.name) or util.escape("<untitled>"))
+ else
+ name = name .. (util.escape(c.name) or util.escape("<untitled>"))
+ end
+
+ local focused = capi.client.focus == c
+ -- Handle transient_for: the first parent that does not skip the taskbar
+ -- is considered to be focused, if the real client has skip_taskbar.
+ if not focused and capi.client.focus and capi.client.focus.skip_taskbar
+ and capi.client.focus:get_transient_for_matching(function(cl)
+ return not cl.skip_taskbar
+ end) == c then
+ focused = true
+ end
+
+ if focused then
+ bg = bg_focus
+ text = text .. "<span color='"..fg_focus.."'>"..name.."</span>"
+ bg_image = bg_image_focus
+ font = font_focus
+
+ if args.shape_focus or theme.tasklist_shape_focus then
+ shape = args.shape_focus or theme.tasklist_shape_focus
+ end
+
+ if args.shape_border_width_focus or theme.tasklist_shape_border_width_focus then
+ shape_border_width = args.shape_border_width_focus or theme.tasklist_shape_border_width_focus
+ end
+
+ if args.shape_border_color_focus or theme.tasklist_shape_border_color_focus then
+ shape_border_color = args.shape_border_color_focus or theme.tasklist_shape_border_color_focus
+ end
+ elseif c.urgent then
+ bg = bg_urgent
+ text = text .. "<span color='"..fg_urgent.."'>"..name.."</span>"
+ bg_image = bg_image_urgent
+ font = font_urgent
+
+ if args.shape_urgent or theme.tasklist_shape_urgent then
+ shape = args.shape_urgent or theme.tasklist_shape_urgent
+ end
+
+ if args.shape_border_width_urgent or theme.tasklist_shape_border_width_urgent then
+ shape_border_width = args.shape_border_width_urgent or theme.tasklist_shape_border_width_urgent
+ end
+
+ if args.shape_border_color_urgent or theme.tasklist_shape_border_color_urgent then
+ shape_border_color = args.shape_border_color_urgent or theme.tasklist_shape_border_color_urgent
+ end
+ elseif c.minimized then
+ bg = bg_minimize
+ text = text .. "<span color='"..fg_minimize.."'>"..name.."</span>"
+ bg_image = bg_image_minimize
+ font = font_minimized
+
+ if args.shape_minimized or theme.tasklist_shape_minimized then
+ shape = args.shape_minimized or theme.tasklist_shape_minimized
+ end
+
+ if args.shape_border_width_minimized or theme.tasklist_shape_border_width_minimized then
+ shape_border_width = args.shape_border_width_minimized or theme.tasklist_shape_border_width_minimized
+ end
+
+ if args.shape_border_color_minimized or theme.tasklist_shape_border_color_minimized then
+ shape_border_color = args.shape_border_color_minimized or theme.tasklist_shape_border_color_minimized
+ end
+ else
+ bg = bg_normal
+ text = text .. "<span color='"..fg_normal.."'>"..name.."</span>"
+ bg_image = bg_image_normal
+ end
+ tb:set_font(font)
+
+ local other_args = {
+ shape = shape,
+ shape_border_width = shape_border_width,
+ shape_border_color = shape_border_color,
+ }
+
+ return text, bg, bg_image, not tasklist_disable_icon and c.icon or nil, other_args
+end
+
+local function tasklist_update(s, w, buttons, filter, data, style, update_function)
+ local clients = {}
+ for _, c in ipairs(capi.client.get()) do
+ if not (c.skip_taskbar or c.hidden
+ or c.type == "splash" or c.type == "dock" or c.type == "desktop")
+ and filter(c, s) then
+ table.insert(clients, c)
+ end
+ end
+
+ local function label(c, tb) return tasklist_label(c, style, tb) end
+
+ update_function(w, buttons, label, data, clients)
+end
+
+--- Create a new tasklist widget. The last two arguments (update_function
+-- and base_widget) serve to customize the layout of the tasklist (eg. to
+-- make it vertical). For that, you will need to copy the
+-- awful.widget.common.list_update function, make your changes to it
+-- and pass it as update_function here. Also change the base_widget if the
+-- default is not what you want.
+-- @param screen The screen to draw tasklist for.
+-- @param filter Filter function to define what clients will be listed.
+-- @param buttons A table with buttons binding to set.
+-- @tparam[opt={}] table style The style overrides default theme.
+-- @tparam[opt=nil] string|pattern style.fg_normal
+-- @tparam[opt=nil] string|pattern style.bg_normal
+-- @tparam[opt=nil] string|pattern style.fg_focus
+-- @tparam[opt=nil] string|pattern style.bg_focus
+-- @tparam[opt=nil] string|pattern style.fg_urgent
+-- @tparam[opt=nil] string|pattern style.bg_urgent
+-- @tparam[opt=nil] string|pattern style.fg_minimize
+-- @tparam[opt=nil] string|pattern style.bg_minimize
+-- @tparam[opt=nil] string style.bg_image_normal
+-- @tparam[opt=nil] string style.bg_image_focus
+-- @tparam[opt=nil] string style.bg_image_urgent
+-- @tparam[opt=nil] string style.bg_image_minimize
+-- @tparam[opt=nil] boolean style.tasklist_disable_icon
+-- @tparam[opt=nil] string style.font
+-- @tparam[opt=left] string style.align *left*, *right* or *center*
+-- @tparam[opt=nil] string style.font_focus
+-- @tparam[opt=nil] string style.font_minimized
+-- @tparam[opt=nil] string style.font_urgent
+-- @tparam[opt=nil] number style.spacing The spacing between tags.
+-- @tparam[opt=nil] gears.shape style.shape
+-- @tparam[opt=nil] number style.shape_border_width
+-- @tparam[opt=nil] string|color style.shape_border_color
+-- @tparam[opt=nil] gears.shape style.shape_focus
+-- @tparam[opt=nil] number style.shape_border_width_focus
+-- @tparam[opt=nil] string|color style.shape_border_color_focus
+-- @tparam[opt=nil] gears.shape style.shape_minimized
+-- @tparam[opt=nil] number style.shape_border_width_minimized
+-- @tparam[opt=nil] string|color style.shape_border_color_minimized
+-- @tparam[opt=nil] gears.shape style.shape_urgent
+-- @tparam[opt=nil] number style.shape_border_width_urgent
+-- @tparam[opt=nil] string|color style.shape_border_color_urgent
+-- @param[opt] update_function Function to create a tag widget on each
+-- update. See `awful.widget.common.list_update`.
+-- @tparam[opt] table base_widget Container widget for tag widgets. Default
+-- is `wibox.layout.flex.horizontal`.
+-- @function awful.tasklist
+function tasklist.new(screen, filter, buttons, style, update_function, base_widget)
+ screen = get_screen(screen)
+ local uf = update_function or common.list_update
+ local w = base_widget or flex.horizontal()
+
+ local data = setmetatable({}, { __mode = 'k' })
+
+ if w.set_spacing and (style and style.spacing or beautiful.taglist_spacing) then
+ w:set_spacing(style and style.spacing or beautiful.taglist_spacing)
+ end
+
+ local queued_update = false
+ function w._do_tasklist_update()
+ -- Add a delayed callback for the first update.
+ if not queued_update then
+ timer.delayed_call(function()
+ queued_update = false
+ if screen.valid then
+ tasklist_update(screen, w, buttons, filter, data, style, uf)
+ end
+ end)
+ queued_update = true
+ end
+ end
+ function w._unmanage(c)
+ data[c] = nil
+ end
+ if instances == nil then
+ instances = setmetatable({}, { __mode = "k" })
+ local function us(s)
+ local i = instances[get_screen(s)]
+ if i then
+ for _, tlist in pairs(i) do
+ tlist._do_tasklist_update()
+ end
+ end
+ end
+ local function u()
+ for s in pairs(instances) do
+ if s.valid then
+ us(s)
+ end
+ end
+ end
+
+ tag.attached_connect_signal(nil, "property::selected", u)
+ tag.attached_connect_signal(nil, "property::activated", u)
+ capi.client.connect_signal("property::urgent", u)
+ capi.client.connect_signal("property::sticky", u)
+ capi.client.connect_signal("property::ontop", u)
+ capi.client.connect_signal("property::above", u)
+ capi.client.connect_signal("property::below", u)
+ capi.client.connect_signal("property::floating", u)
+ capi.client.connect_signal("property::maximized_horizontal", u)
+ capi.client.connect_signal("property::maximized_vertical", u)
+ capi.client.connect_signal("property::minimized", u)
+ capi.client.connect_signal("property::name", u)
+ capi.client.connect_signal("property::icon_name", u)
+ capi.client.connect_signal("property::icon", u)
+ capi.client.connect_signal("property::skip_taskbar", u)
+ capi.client.connect_signal("property::screen", function(c, old_screen)
+ us(c.screen)
+ us(old_screen)
+ end)
+ capi.client.connect_signal("property::hidden", u)
+ capi.client.connect_signal("tagged", u)
+ capi.client.connect_signal("untagged", u)
+ capi.client.connect_signal("unmanage", function(c)
+ u(c)
+ for _, i in pairs(instances) do
+ for _, tlist in pairs(i) do
+ tlist._unmanage(c)
+ end
+ end
+ end)
+ capi.client.connect_signal("list", u)
+ capi.client.connect_signal("focus", u)
+ capi.client.connect_signal("unfocus", u)
+ capi.screen.connect_signal("removed", function(s)
+ instances[get_screen(s)] = nil
+ end)
+ end
+ w._do_tasklist_update()
+ local list = instances[screen]
+ if not list then
+ list = setmetatable({}, { __mode = "v" })
+ instances[screen] = list
+ end
+ table.insert(list, w)
+ return w
+end
+
+--- Filtering function to include all clients.
+-- @return true
+function tasklist.filter.allscreen()
+ return true
+end
+
+--- Filtering function to include the clients from all tags on the screen.
+-- @param c The client.
+-- @param screen The screen we are drawing on.
+-- @return true if c is on screen, false otherwise
+function tasklist.filter.alltags(c, screen)
+ -- Only print client on the same screen as this widget
+ return get_screen(c.screen) == get_screen(screen)
+end
+
+--- Filtering function to include only the clients from currently selected tags.
+-- @param c The client.
+-- @param screen The screen we are drawing on.
+-- @return true if c is in a selected tag on screen, false otherwise
+function tasklist.filter.currenttags(c, screen)
+ screen = get_screen(screen)
+ -- Only print client on the same screen as this widget
+ if get_screen(c.screen) ~= screen then return false end
+ -- Include sticky client too
+ if c.sticky then return true end
+ local tags = screen.tags
+ for _, t in ipairs(tags) do
+ if t.selected then
+ local ctags = c:tags()
+ for _, v in ipairs(ctags) do
+ if v == t then
+ return true
+ end
+ end
+ end
+ end
+ return false
+end
+
+--- Filtering function to include only the minimized clients from currently selected tags.
+-- @param c The client.
+-- @param screen The screen we are drawing on.
+-- @return true if c is in a selected tag on screen and is minimized, false otherwise
+function tasklist.filter.minimizedcurrenttags(c, screen)
+ screen = get_screen(screen)
+ -- Only print client on the same screen as this widget
+ if get_screen(c.screen) ~= screen then return false end
+ -- Check client is minimized
+ if not c.minimized then return false end
+ -- Include sticky client
+ if c.sticky then return true end
+ local tags = screen.tags
+ for _, t in ipairs(tags) do
+ -- Select only minimized clients
+ if t.selected then
+ local ctags = c:tags()
+ for _, v in ipairs(ctags) do
+ if v == t then
+ return true
+ end
+ end
+ end
+ end
+ return false
+end
+
+--- Filtering function to include only the currently focused client.
+-- @param c The client.
+-- @param screen The screen we are drawing on.
+-- @return true if c is focused on screen, false otherwise
+function tasklist.filter.focused(c, screen)
+ -- Only print client on the same screen as this widget
+ return get_screen(c.screen) == get_screen(screen) and capi.client.focus == c
+end
+
+function tasklist.mt:__call(...)
+ return tasklist.new(...)
+end
+
+return setmetatable(tasklist, tasklist.mt)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/textclock.lua b/lib/awful/widget/textclock.lua
new file mode 100644
index 0000000..002aa0e
--- /dev/null
+++ b/lib/awful/widget/textclock.lua
@@ -0,0 +1,16 @@
+---------------------------------------------------------------------------
+-- This widget has moved to `wibox.widget.textclock`
+--
+-- @author Julien Danjou &lt;julien@danjou.info&gt;
+-- @copyright 2008-2009 Julien Danjou
+-- @classmod awful.widget.textclock
+---------------------------------------------------------------------------
+local util = require("awful.util")
+
+return util.deprecate_class(
+ require("wibox.widget.textclock"),
+ "awful.widget.textclock",
+ "wibox.widget.textclock"
+)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/awful/widget/watch.lua b/lib/awful/widget/watch.lua
new file mode 100644
index 0000000..bc4c9af
--- /dev/null
+++ b/lib/awful/widget/watch.lua
@@ -0,0 +1,91 @@
+---------------------------------------------------------------------------
+--- Watch widget.
+-- Here is an example of simple temperature widget which will update each 15
+-- seconds implemented in two different ways.
+-- The first, simpler one, will just display the return command output
+-- (so output is stripped by shell commands).
+-- In the other example `sensors` returns to the widget its full output
+-- and it's trimmed in the widget callback function:
+--
+-- 211 mytextclock,
+-- 212 wibox.widget.textbox(' | '),
+-- 213 -- one way to do that:
+-- 214 awful.widget.watch('bash -c "sensors | grep temp1"', 15),
+-- 215 -- another way:
+-- 216 awful.widget.watch('sensors', 15, function(widget, stdout)
+-- 217 for line in stdout:gmatch("[^\r\n]+") do
+-- 218 if line:match("temp1") then
+-- 219 widget:set_text(line)
+-- 220 return
+-- 221 end
+-- 222 end
+-- 223 end),
+-- 224 s.mylayoutbox,
+--
+-- ![Example screenshot](../images/awful_widget_watch.png)
+--
+-- @author Benjamin Petrenko
+-- @author Yauheni Kirylau
+-- @copyright 2015, 2016 Benjamin Petrenko, Yauheni Kirylau
+-- @classmod awful.widget.watch
+---------------------------------------------------------------------------
+
+local setmetatable = setmetatable
+local textbox = require("wibox.widget.textbox")
+local timer = require("gears.timer")
+local spawn = require("awful.spawn")
+
+local watch = { mt = {} }
+
+--- Create a textbox that shows the output of a command
+-- and updates it at a given time interval.
+--
+-- @tparam string|table command The command.
+--
+-- @tparam[opt=5] integer timeout The time interval at which the textbox
+-- will be updated.
+--
+-- @tparam[opt] function callback The function that will be called after
+-- the command output will be received. it is shown in the textbox.
+-- Defaults to:
+-- function(widget, stdout, stderr, exitreason, exitcode)
+-- widget:set_text(stdout)
+-- end
+-- @param callback.widget Base widget instance.
+-- @tparam string callback.stdout Output on stdout.
+-- @tparam string callback.stderr Output on stderr.
+-- @tparam string callback.exitreason Exit Reason.
+-- The reason can be "exit" or "signal".
+-- @tparam integer callback.exitcode Exit code.
+-- For "exit" reason it's the exit code.
+-- For "signal" reason — the signal causing process termination.
+--
+-- @param[opt=wibox.widget.textbox()] base_widget Base widget.
+--
+-- @return The widget used by this watch
+function watch.new(command, timeout, callback, base_widget)
+ timeout = timeout or 5
+ base_widget = base_widget or textbox()
+ callback = callback or function(widget, stdout, stderr, exitreason, exitcode) -- luacheck: no unused args
+ widget:set_text(stdout)
+ end
+ local t = timer { timeout = timeout }
+ t:connect_signal("timeout", function()
+ t:stop()
+ spawn.easy_async(command, function(stdout, stderr, exitreason, exitcode)
+ callback(base_widget, stdout, stderr, exitreason, exitcode)
+ t:again()
+ end)
+ end)
+ t:start()
+ t:emit_signal("timeout")
+ return base_widget
+end
+
+function watch.mt.__call(_, ...)
+ return watch.new(...)
+end
+
+return setmetatable(watch, watch.mt)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80