diff options
Diffstat (limited to 'awesome/lib/awful/widget/tasklist.lua')
-rw-r--r-- | awesome/lib/awful/widget/tasklist.lua | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/awesome/lib/awful/widget/tasklist.lua b/awesome/lib/awful/widget/tasklist.lua new file mode 100644 index 0000000..d5580c1 --- /dev/null +++ b/awesome/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 <julien@danjou.info> +-- @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 |