--------------------------------------------------------------------------- -- @author Julien Danjou <julien@danjou.info> -- @copyright 2008 Julien Danjou -- @release @AWESOME_VERSION@ --------------------------------------------------------------------------- -- Grab environment we need local ipairs = ipairs local pairs = pairs local table = table local otable = otable local type = type local capi = { screen = screen, client = client, button = button, widget = widget, image = image, mouse = mouse } local util = require("awful.util") local hooks = require("awful.hooks") local beautiful = require("beautiful") local menu = require("awful.menu") local client = require("awful.client") --- Widget module for awful module("awful.widget") -- Various public structures taglist = {} taglist.label = {} tasklist = {} tasklist.label = {} -- Private structures local tagwidgets = otable() local function taglist_update (screen, w, label, buttons, data) local tags = capi.screen[screen]:tags() -- Hack: if it has been registered as a widget in a wibox, -- it's w.len since __len meta does not work on table until Lua 5.2. -- Otherwise it's standard #w. local len = w.len or #w -- Add more widgets if len < #tags then for i = len + 1, #tags do local wi = capi.widget({ type = "textbox" }) w[i] = wi tagwidgets[wi] = tags[i] end -- Remove widgets elseif len > #tags then for i = #tags + 1, len do tagwidgets[w[i]] = nil w[i] = nil end end -- Update widgets text for k, tag in ipairs(tags) do local text, bg, bg_image, bg_resize = label(tag) w[k].text = text if text then w[k].bg, w[k].bg_image, w[k].bg_resize = bg, bg_image, bg_resize if buttons then if not data[tag] then -- Replace press function by a new one calling with tags as -- argument. -- This is done here because order of tags can change data[tag] = {} for kb, b in ipairs(buttons) do -- Copy object data[tag][kb] = capi.button(b) data[tag][kb].press = function () b.press(tag) end end end w[k]:buttons(data[tag]) end end end end function taglist.gettag(widget) return tagwidgets[widget] end --- Create a new taglist widget. -- @param screen The screen to draw tag list for. -- @param label Label function to use. -- @param buttons A table with buttons binding to set. function taglist.new(screen, label, buttons) local w = {} local data = otable() local u = function (s) if s == screen then taglist_update(s, w, label, buttons, data) end end local uc = function (c) return u(c.screen) end hooks.focus.register(uc) hooks.unfocus.register(uc) hooks.arrange.register(u) hooks.tags.register(u) hooks.tagged.register(uc) hooks.property.register(function (c, prop) if prop == "urgent" then u(c.screen) end end) -- Free data on tag removal hooks.tags.register(function (s, tag, action) if action == "remove" then data[tag] = nil end end) u(screen) return w end --- Return labels for a taglist widget with all tag from screen. -- It returns the tag name and set a special -- foreground and background color for selected tags. -- @param t The tag. -- @param args The arguments table. -- bg_focus The background color for selected tag. -- fg_focus The foreground color for selected tag. -- bg_urgent The background color for urgent tags. -- fg_urgent The foreground color for urgent tags. -- squares_sel Optional: a user provided image for selected squares. -- squares_unsel Optional: a user provided image for unselected squares. -- squares_resize Optional: true or false to resize squares. -- @return A string to print, a background color, a background image and a -- background resize value. function taglist.label.all(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 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_resize = theme.taglist_squares_resize or args.squares_resize or "true" local font = args.font or theme.taglist_font or theme.font or "" local text = " " local sel = capi.client.focus local bg_color = nil local fg_color = nil local bg_image local bg_resize = false if t.selected then bg_color = bg_focus fg_color = fg_focus end if sel and sel:tags()[t] then if taglist_squares_sel then bg_image = capi.image(taglist_squares_sel) bg_resize = taglist_squares_resize == "true" end else local cls = t:clients() if #cls > 0 and taglist_squares_unsel then bg_image = capi.image(taglist_squares_unsel) bg_resize = taglist_squares_resize == "true" end for k, c in pairs(cls) do if c.urgent then if bg_urgent then bg_color = bg_urgent end if fg_urgent then fg_color = fg_urgent end break end end end if fg_color then text = text .. ""..util.escape(t.name).."" else text = text .. util.escape(t.name) end text = text .. " " return text, bg_color, bg_image, bg_resize end --- Return labels for a taglist widget with all *non empty* tags from screen. -- It returns the tag name and set a special -- foreground and background color for selected tags. -- @param t The tag. -- @param args The arguments table. -- bg_focus The background color for selected tag. -- fg_focus The foreground color for selected tag. -- bg_urgent The background color for urgent tags. -- fg_urgent The foreground color for urgent tags. -- @return A string to print, a background color, a background image and a -- background resize value. function taglist.label.noempty(t, args) if #t:clients() > 0 or t.selected then return taglist.label.all(t, args) end end local function tasklist_update(w, buttons, label, data) local clients = capi.client.get() local shownclients = {} for k, c in ipairs(clients) do if not (c.skip_taskbar or c.hide or c.type == "splash" or c.type == "dock" or c.type == "desktop") then table.insert(shownclients, c) end end clients = shownclients -- Hack: if it has been registered as a widget in a wibox, -- it's w.len since __len meta does not work on table until Lua 5.2. -- Otherwise it's standard #w. local len = (w.len or #w) / 2 -- Add more widgets if len < #clients then for i = len * 2 + 1, #clients * 2, 2 do w[i] = capi.widget({ type = "imagebox", align = "flex" }) w[i + 1] = capi.widget({ type = "textbox", align = "flex" }) w[i + 1]:margin({ left = 2, right = 2 }) w[i + 1].bg_resize = true w[i + 1].bg_align = "right" end -- Remove widgets elseif len > #clients then for i = #clients * 2 + 1, len * 2, 2 do w[i] = nil w[i + 1] = nil end end -- Update widgets text for k = 1, #clients * 2, 2 do if buttons then local c = clients[(k + 1) / 2] if not data[c] then data[c] = {} -- Replace press function by a new one calling with tags as -- argument for kb, b in ipairs(buttons) do -- Copy object data[c][kb] = capi.button(b) data[c][kb].press = function () b.press(c) end end end w[k]:buttons(data[c]) w[k + 1]:buttons(data[c]) end w[k + 1].text, w[k + 1].bg, w[k + 1].bg_image= label(clients[(k + 1) / 2]) w[k].bg = w[k + 1].bg if w[k + 1].text then -- Set icon w[k].image = clients[(k + 1) / 2].icon if w[k].image then w[k].visible = true else w[k].visible = false end w[k + 1].visible = true else w[k].visible = false w[k + 1].visible = false end end end --- Create a new tasklist widget. -- @param label Label function to use. -- @param buttons A table with buttons binding to set. function tasklist.new(label, buttons) local w = {} local data = otable() local u = function () tasklist_update(w, buttons, label, data) end hooks.arrange.register(u) hooks.clients.register(u) hooks.tagged.register(u) hooks.focus.register(u) hooks.unfocus.register(u) hooks.property.register(function (c, prop) if prop == "urgent" or prop == "floating" or prop == "maximized_horizontal" or prop == "maximized_vertical" or prop == "icon" or prop == "name" or prop == "icon_name" then u() end end) u() -- Free data on unmanage hooks.unmanage.register(function (c) data[c] = nil end) return w end local function widget_tasklist_label_common(c, args) if not args then args = {} end local theme = beautiful.get() local fg_focus = args.fg_focus or theme.tasklist_fg_focus or theme.fg_focus local bg_focus = args.bg_focus or theme.tasklist_bg_focus or theme.bg_focus local fg_urgent = args.fg_urgent or theme.tasklist_fg_urgent or theme.fg_urgent local bg_urgent = args.bg_urgent or theme.tasklist_bg_urgent or theme.bg_urgent local floating_icon = args.floating_icon or theme.tasklist_floating_icon local font = args.font or theme.tasklist_font or theme.font or "" local bg = nil local text = "" local name local status_image if client.floating.get(c) and floating_icon then status_image = capi.image(floating_icon) end if c.minimized then name = util.escape(c.icon_name) or "" else name = util.escape(c.name) or "" end if capi.client.focus == c then bg = bg_focus if fg_focus then text = text .. ""..name.."" else text = text .. name end elseif c.urgent and fg_urgent then bg = bg_urgent text = text .. ""..name.."" else text = text .. name end text = text .. "" return text, bg, status_image end --- Return labels for a tasklist widget with clients from all tags and screen. -- It returns the client name and set a special -- foreground and background color for focused client. -- It also puts a special icon for floating windows. -- @param c The client. -- @param screen The screen we are drawing on. -- @param args The arguments table. -- bg_focus The background color for focused client. -- fg_focus The foreground color for focused client. -- bg_urgent The background color for urgent clients. -- fg_urgent The foreground color for urgent clients. -- @return A string to print, a background color and a status image. function tasklist.label.allscreen(c, screen, args) return widget_tasklist_label_common(c, args) end --- Return labels for a tasklist widget with clients from all tags. -- It returns the client name and set a special -- foreground and background color for focused client. -- It also puts a special icon for floating windows. -- @param c The client. -- @param screen The screen we are drawing on. -- @param args The arguments table. -- bg_focus The background color for focused client. -- fg_focus The foreground color for focused client. -- bg_urgent The background color for urgent clients. -- fg_urgent The foreground color for urgent clients. -- @return A string to print, a background color and a status image. function tasklist.label.alltags(c, screen, args) -- Only print client on the same screen as this widget if c.screen ~= screen then return end return widget_tasklist_label_common(c, args) end --- Return labels for a tasklist widget with clients from currently selected tags. -- It returns the client name and set a special -- foreground and background color for focused client. -- It also puts a special icon for floating windows. -- @param c The client. -- @param screen The screen we are drawing on. -- @param args The arguments table. -- bg_focus The background color for focused client. -- fg_focus The foreground color for focused client. -- bg_urgent The background color for urgent clients. -- fg_urgent The foreground color for urgent clients. -- @return A string to print, a background color and a status image. function tasklist.label.currenttags(c, screen, args) -- Only print client on the same screen as this widget if c.screen ~= screen then return end for k, t in ipairs(capi.screen[screen]:tags()) do if t.selected and c:tags()[t] then return widget_tasklist_label_common(c, args) end end end --- Create a button widget. When clicked, the image is deplaced to make it like -- a real button. -- @param args Standard widget table arguments, plus image for the image path or -- the image object. -- @return A textbox widget configured as a button. function button(args) if not args or not args.image then return end local img_release if type(args.image) == "string" then img_release = image(args.image) elseif type(args.image) == "image" then img_release = args.image else return end local img_press = img_release:crop(-2, -2, img_release.width, img_release.height) args.type = "imagebox" local w = capi.widget(args) w.image = img_release w:buttons({ capi.button({}, 1, function () w.image = img_press end, function () w.image = img_release end) }) function w.mouse_leave(s) w.image = img_release end function w.mouse_enter(s) if capi.mouse.coords().buttons[1] then w.image = img_press end end return w end --- 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(args) if not args.command and not args.menu then return end local w = button(args) if not w then return end local b = w:buttons() if args.command then b[#b + 1] = capi.button({}, 1, nil, function () util.spawn(args.command) end) elseif args.menu then b[#b + 1] = capi.button({}, 1, nil, function () args.menu:toggle() end) end w:buttons(b) return w end -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80