Rewrite {tag,task}list in Lua.
This removes the C implementation of taglist and tasklist widgets and use a Lua one. This works by letting .widgets property of wiboxes to be a table with table, and setting a special metatable on them which notify awesome on newindex events, updating wiboxes. Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
parent
0e3ff0bc8f
commit
862fe193ee
|
@ -77,8 +77,6 @@ set(AWE_SRCS
|
|||
${SOURCE_DIR}/layouts/tile.c
|
||||
${SOURCE_DIR}/widgets/graph.c
|
||||
${SOURCE_DIR}/widgets/progressbar.c
|
||||
${SOURCE_DIR}/widgets/taglist.c
|
||||
${SOURCE_DIR}/widgets/tasklist.c
|
||||
${SOURCE_DIR}/widgets/textbox.c
|
||||
${SOURCE_DIR}/widgets/systray.c
|
||||
${SOURCE_DIR}/widgets/imagebox.c)
|
||||
|
|
|
@ -93,27 +93,6 @@ end
|
|||
-- }}}
|
||||
|
||||
-- {{{ Wibox
|
||||
-- Create a taglist widget
|
||||
mytaglist = widget({ type = "taglist", name = "mytaglist" })
|
||||
mytaglist:buttons({
|
||||
button({ }, 1, function (object, tag) awful.tag.viewonly(tag) end),
|
||||
button({ modkey }, 1, function (object, tag) awful.client.movetotag(tag) end),
|
||||
button({ }, 3, function (object, tag) tag.selected = not tag.selected end),
|
||||
button({ modkey }, 3, function (object, tag) awful.client.toggletag(tag) end),
|
||||
button({ }, 4, awful.tag.viewnext),
|
||||
button({ }, 5, awful.tag.viewprev)
|
||||
})
|
||||
mytaglist.label = awful.widget.taglist.label.all
|
||||
|
||||
-- Create a tasklist widget
|
||||
mytasklist = widget({ type = "tasklist", name = "mytasklist" })
|
||||
mytasklist:buttons({
|
||||
button({ }, 1, function (object, c) client.focus = c; c:raise() end),
|
||||
button({ }, 4, function () awful.client.focus.byidx(1) end),
|
||||
button({ }, 5, function () awful.client.focus.byidx(-1) end)
|
||||
})
|
||||
mytasklist.label = awful.widget.tasklist.label.currenttags
|
||||
|
||||
-- Create a textbox widget
|
||||
mytextbox = widget({ type = "textbox", name = "mytextbox", align = "right" })
|
||||
-- Set the default text in textbox
|
||||
|
@ -127,37 +106,52 @@ mylauncher = awful.widget.launcher({ name = "mylauncher",
|
|||
-- Create a systray
|
||||
mysystray = widget({ type = "systray", name = "mysystray", align = "right" })
|
||||
|
||||
-- Create an iconbox widget which will contains an icon indicating which layout we're using.
|
||||
-- We need one layoutbox per screen.
|
||||
mylayoutbox = {}
|
||||
for s = 1, screen.count() do
|
||||
mylayoutbox[s] = widget({ type = "imagebox", name = "mylayoutbox", align = "right" })
|
||||
mylayoutbox[s]:buttons({
|
||||
button({ }, 1, function () awful.layout.inc(layouts, 1) end),
|
||||
button({ }, 3, function () awful.layout.inc(layouts, -1) end),
|
||||
button({ }, 4, function () awful.layout.inc(layouts, 1) end),
|
||||
button({ }, 5, function () awful.layout.inc(layouts, -1) end)
|
||||
})
|
||||
mylayoutbox[s].image = image("@AWESOME_ICON_PATH@/layouts/tilew.png")
|
||||
end
|
||||
|
||||
-- Create a wibox for each screen and add it
|
||||
mywibox = {}
|
||||
mypromptbox = {}
|
||||
mylayoutbox = {}
|
||||
mytaglist = {}
|
||||
mytaglist.buttons = { button({ }, 1, awful.tag.viewonly),
|
||||
button({ modkey }, 1, awful.client.movetotag),
|
||||
button({ }, 3, function (tag) tag.selected = not tag.selected end),
|
||||
button({ modkey }, 3, awful.client.toggletag),
|
||||
button({ }, 4, awful.tag.viewnext),
|
||||
button({ }, 5, awful.tag.viewprev) }
|
||||
mytasklist = {}
|
||||
mytasklist.buttons = { button({ }, 1, function (c) client.focus = c; c:raise() end),
|
||||
button({ }, 4, function () awful.client.focus.byidx(1) end),
|
||||
button({ }, 5, function () awful.client.focus.byidx(-1) end) }
|
||||
|
||||
for s = 1, screen.count() do
|
||||
mywibox[s] = wibox({ position = "top", name = "mywibox" .. s,
|
||||
fg = beautiful.fg_normal, bg = beautiful.bg_normal })
|
||||
-- Create a promptbox for each screen
|
||||
mypromptbox[s] = widget({ type = "textbox", name = "mypromptbox" .. s, align = "left" })
|
||||
-- Create an imagebox widget which will contains an icon indicating which layout we're using.
|
||||
-- We need one layoutbox per screen.
|
||||
mylayoutbox[s] = widget({ type = "imagebox", name = "mylayoutbox", align = "right" })
|
||||
mylayoutbox[s]:buttons({ button({ }, 1, function () awful.layout.inc(layouts, 1) end),
|
||||
button({ }, 3, function () awful.layout.inc(layouts, -1) end),
|
||||
button({ }, 4, function () awful.layout.inc(layouts, 1) end),
|
||||
button({ }, 5, function () awful.layout.inc(layouts, -1) end) })
|
||||
-- Create a taglist widget
|
||||
mytaglist[s] = awful.widget.taglist.new(s, awful.widget.taglist.label.all, mytaglist.buttons)
|
||||
|
||||
-- Create a tasklist widget
|
||||
mytasklist[s] = awful.widget.tasklist.new(function(c)
|
||||
return awful.widget.tasklist.label.currenttags(c, s)
|
||||
end, mytasklist.buttons)
|
||||
|
||||
-- Create the wibox
|
||||
mywibox[s] = wibox({ position = "top", name = "mywibox" .. s,
|
||||
fg = beautiful.fg_normal, bg = beautiful.bg_normal })
|
||||
-- Add widgets to the wibox - order matters
|
||||
mywibox[s]:widgets({
|
||||
mytaglist,
|
||||
mytasklist,
|
||||
mylauncher,
|
||||
mypromptbox[s],
|
||||
mytextbox,
|
||||
mylayoutbox[s],
|
||||
s == 1 and mysystray or nil
|
||||
})
|
||||
mywibox[s].widgets = { mytaglist[s],
|
||||
mylauncher,
|
||||
mytasklist[s],
|
||||
mypromptbox[s],
|
||||
mytextbox,
|
||||
mylayoutbox[s],
|
||||
s == 1 and mysystray or nil }
|
||||
mywibox[s].screen = s
|
||||
end
|
||||
-- }}}
|
||||
|
|
9
client.c
9
client.c
|
@ -185,7 +185,6 @@ client_unfocus(client_t *c)
|
|||
luaA_client_userdata_new(globalconf.L, c);
|
||||
luaA_dofunction(globalconf.L, globalconf.hooks.unfocus, 1, 0);
|
||||
|
||||
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
|
||||
ewmh_update_net_active_window(c->phys_screen);
|
||||
}
|
||||
|
||||
|
@ -243,7 +242,6 @@ client_focus(client_t *c)
|
|||
luaA_dofunction(globalconf.L, globalconf.hooks.focus, 1, 0);
|
||||
|
||||
ewmh_update_net_active_window(c->phys_screen);
|
||||
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
|
||||
}
|
||||
|
||||
/** Stack a window below.
|
||||
|
@ -468,7 +466,6 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int phys_screen,
|
|||
ewmh_client_strut_update(c, NULL);
|
||||
|
||||
ewmh_update_net_client_list(c->phys_screen);
|
||||
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
|
||||
|
||||
/* Call hook to notify list change */
|
||||
luaA_dofunction(globalconf.L, globalconf.hooks.clients, 0, 0);
|
||||
|
@ -624,7 +621,6 @@ client_setfloating(client_t *c, bool floating)
|
|||
if(!c->isfullscreen)
|
||||
client_resize(c, c->f_geometry, false);
|
||||
client_need_arrange(c);
|
||||
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
|
||||
client_stack();
|
||||
xcb_change_property(globalconf.connection,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
|
@ -1039,8 +1035,6 @@ luaA_client_swap(lua_State *L)
|
|||
client_list_swap(&globalconf.clients, *swap, *c);
|
||||
client_need_arrange(*c);
|
||||
client_need_arrange(*swap);
|
||||
widget_invalidate_cache((*c)->screen, WIDGET_CACHE_CLIENTS);
|
||||
widget_invalidate_cache((*swap)->screen, WIDGET_CACHE_CLIENTS);
|
||||
|
||||
/* Call hook to notify list change */
|
||||
luaA_dofunction(L, globalconf.hooks.clients, 0, 0);
|
||||
|
@ -1270,7 +1264,8 @@ luaA_client_newindex(lua_State *L)
|
|||
image_unref(&(*c)->icon);
|
||||
image_ref(image);
|
||||
(*c)->icon = *image;
|
||||
widget_invalidate_cache((*c)->screen, WIDGET_CACHE_CLIENTS);
|
||||
/* execute hook */
|
||||
hooks_property(*c, "icon");
|
||||
break;
|
||||
case A_TK_OPACITY:
|
||||
if(lua_isnil(L, 3))
|
||||
|
|
|
@ -37,6 +37,7 @@ invert
|
|||
label
|
||||
layout
|
||||
left
|
||||
len
|
||||
line
|
||||
Lock
|
||||
machine
|
||||
|
@ -87,6 +88,7 @@ type
|
|||
urgent
|
||||
visible
|
||||
vertical
|
||||
widgets
|
||||
width
|
||||
workarea
|
||||
yes
|
||||
|
|
1
ewmh.c
1
ewmh.c
|
@ -333,7 +333,6 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
|
|||
luaA_client_userdata_new(globalconf.L, c);
|
||||
lua_pushliteral(globalconf.L, "urgent");
|
||||
luaA_dofunction(globalconf.L, globalconf.hooks.property, 2, 0);
|
||||
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,16 +80,9 @@ function add(c, args)
|
|||
bts[#bts + 1] = b
|
||||
close:buttons(bts)
|
||||
|
||||
tb:widgets({
|
||||
appicon,
|
||||
title,
|
||||
closef, close
|
||||
})
|
||||
tb.widgets = { appicon, title, closef, close }
|
||||
else
|
||||
tb:widgets({
|
||||
appicon,
|
||||
title
|
||||
})
|
||||
tbx.widgets = { appicon, title }
|
||||
end
|
||||
|
||||
c.titlebar = tb
|
||||
|
@ -103,7 +96,7 @@ end
|
|||
-- @param prop The property name which has changed.
|
||||
function update(c, prop)
|
||||
if c.titlebar and data[c] then
|
||||
local widgets = c.titlebar:widgets()
|
||||
local widgets = c.titlebar.widgets
|
||||
local title, close, closef
|
||||
for k, v in ipairs(widgets) do
|
||||
if v.name == "title" then title = v
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local pairs = pairs
|
||||
local table = table
|
||||
local capi =
|
||||
{
|
||||
screen = screen,
|
||||
|
@ -16,6 +17,7 @@ local capi =
|
|||
mouse = mouse
|
||||
}
|
||||
local util = require("awful.util")
|
||||
local hooks = require("awful.hooks")
|
||||
local beautiful = require("awful.beautiful")
|
||||
|
||||
--- Widget module for awful
|
||||
|
@ -27,6 +29,60 @@ taglist.label = {}
|
|||
tasklist = {}
|
||||
tasklist.label = {}
|
||||
|
||||
--- Create a new taglist widget.
|
||||
-- @param screen The screen to draw tag list.
|
||||
-- @param label Label function to use.
|
||||
-- @param buttons A table with buttons binding to set.
|
||||
function taglist.new(scr, label, buttons)
|
||||
local w = {}
|
||||
local function taglist_update (screen)
|
||||
-- Return right now if we do not care about this screen
|
||||
if scr ~= screen then return end
|
||||
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
|
||||
w[i] = capi.widget({ type = "textbox", name = "taglist" .. i })
|
||||
end
|
||||
-- Remove widgets
|
||||
elseif len > #tags then
|
||||
for i = #tags, len do
|
||||
w[i] = nil
|
||||
end
|
||||
end
|
||||
-- Update widgets text
|
||||
for k, tag in ipairs(tags) do
|
||||
w[k].text = label(tag)
|
||||
if buttons then
|
||||
-- Replace press function by a new one calling with tags as
|
||||
-- argument.
|
||||
-- This is done here because order of tags can change
|
||||
local mbuttons = {}
|
||||
for kb, b in ipairs(buttons) do
|
||||
-- Copy object
|
||||
mbuttons[kb] = capi.button(b)
|
||||
mbuttons[kb].press = function () b.press(tag) end
|
||||
end
|
||||
w[k]:buttons(mbuttons)
|
||||
end
|
||||
end
|
||||
end
|
||||
hooks.arrange.register(taglist_update)
|
||||
hooks.tags.register(taglist_update)
|
||||
hooks.tagged.register(function (c, tag) taglist_update(c.screen) end)
|
||||
hooks.property.register(function (c, prop)
|
||||
if c.screen == scr and prop == "urgent" then
|
||||
taglist_update(c.screen)
|
||||
end
|
||||
end)
|
||||
taglist_update(scr)
|
||||
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.
|
||||
|
@ -135,6 +191,76 @@ function taglist.label.noempty(t, args)
|
|||
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 function tasklist_update ()
|
||||
local clients = capi.client.get()
|
||||
for k, c in ipairs(clients) do
|
||||
if c.skip_taskbar or c.hide
|
||||
or c.type == "splash" or c.type == "dock" or c.type == "desktop" then
|
||||
table.remove(clients, k)
|
||||
end
|
||||
end
|
||||
-- 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", name = "tasklist_icon" .. i, align = "flex" })
|
||||
w[i + 1] = capi.widget({ type = "textbox", name = "tasklist_text" .. i, align = "flex" })
|
||||
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
|
||||
-- Replace press function by a new one calling with tags as
|
||||
-- argument
|
||||
local mbuttons = {}
|
||||
for kb, b in ipairs(buttons) do
|
||||
-- Copy object
|
||||
mbuttons[kb] = capi.button(b)
|
||||
mbuttons[kb].press = function () b.press(clients[(k + 1) / 2]) end
|
||||
end
|
||||
w[k]:buttons(mbuttons)
|
||||
w[k + 1]:buttons(mbuttons)
|
||||
end
|
||||
w[k + 1].text, w[k].bg = label(clients[(k + 1) / 2])
|
||||
if w[k + 1].text then
|
||||
w[k].visible = true
|
||||
w[k + 1].visible = true
|
||||
w[k].image = clients[(k + 1) / 2].icon
|
||||
else
|
||||
w[k].visible = false
|
||||
w[k + 1].visible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
hooks.clients.register(tasklist_update)
|
||||
hooks.tagged.register(tasklist_update)
|
||||
hooks.focus.register(tasklist_update)
|
||||
hooks.unfocus.register(tasklist_update)
|
||||
hooks.property.register(function (c, prop)
|
||||
if prop == "urgent"
|
||||
or prop == "floating"
|
||||
or prop == "icon" then
|
||||
tasklist_update()
|
||||
end
|
||||
end)
|
||||
tasklist_update()
|
||||
return w
|
||||
end
|
||||
|
||||
local function widget_tasklist_label_common(c, args)
|
||||
if not args then args = {} end
|
||||
local theme = beautiful.get()
|
||||
|
@ -142,6 +268,7 @@ local function widget_tasklist_label_common(c, args)
|
|||
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 bg = nil
|
||||
local text = "<margin left=\"2\" right=\"2\"/>"
|
||||
local name
|
||||
if c.floating then
|
||||
|
@ -154,16 +281,18 @@ local function widget_tasklist_label_common(c, args)
|
|||
end
|
||||
if capi.client.focus == c then
|
||||
if bg_focus and fg_focus then
|
||||
bg = bg_focus
|
||||
text = text .. "<bg color='"..bg_focus.."'/><span color='"..util.color_strip_alpha(fg_focus).."'>"..name.."</span>"
|
||||
else
|
||||
text = text .. name
|
||||
end
|
||||
elseif c.urgent and bg_urgent and fg_urgent then
|
||||
local bg = bg_urgent
|
||||
text = text .. "<bg color='"..bg_urgent.."'/><span color='"..util.color_strip_alpha(fg_urgent).."'>"..name.."</span>"
|
||||
else
|
||||
text = text .. name
|
||||
end
|
||||
return text
|
||||
return text, bg
|
||||
end
|
||||
|
||||
--- Return labels for a tasklist widget with clients from all tags and screen.
|
||||
|
|
|
@ -69,7 +69,7 @@ function player.new ()
|
|||
|
||||
w = widget({ type = "imagebox", name = "player" })
|
||||
w.image = image("@AWESOME_ICON_PATH@/invaders/player.png")
|
||||
p:widgets({ w })
|
||||
p.widgets = w
|
||||
|
||||
return p
|
||||
end
|
||||
|
@ -177,7 +177,7 @@ function enemies.new (t)
|
|||
e.screen = 1
|
||||
w = widget({ type = "imagebox", name = "enemy"..t })
|
||||
w.image = image("@AWESOME_ICON_PATH@/invaders/enemy_"..t..".png")
|
||||
e:widgets({ w })
|
||||
e.widgets = w
|
||||
return e
|
||||
end
|
||||
|
||||
|
@ -328,7 +328,7 @@ function game.quit()
|
|||
|
||||
if gamedata.highscore.window then
|
||||
gamedata.highscore.window.screen = nil
|
||||
gamedata.highscore.window:widgets({ })
|
||||
gamedata.highscore.window.widgets = nil
|
||||
end
|
||||
|
||||
if gamedata.field.background then
|
||||
|
@ -336,7 +336,7 @@ function game.quit()
|
|||
end
|
||||
|
||||
gamedata.player.screen = nil
|
||||
gamedata.player:widgets({ })
|
||||
gamedata.player.widgets = nil
|
||||
gamedata.player = nil
|
||||
|
||||
gamedata.field.north.screen = nil
|
||||
|
@ -354,7 +354,7 @@ function game.quit()
|
|||
for y = 1, #gamedata.enemies.data do
|
||||
for x = 1, #gamedata.enemies.data[y] do
|
||||
gamedata.enemies.data[y][x].screen = nil
|
||||
gamedata.enemies.data[y][x]:widgets({ })
|
||||
gamedata.enemies.data[y][x].widgets = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -374,7 +374,7 @@ function game.highscore_show ()
|
|||
gamedata.highscore.window.screen = 1
|
||||
|
||||
gamedata.highscore.table = widget({ type = "textbox", name = "highscore" })
|
||||
gamedata.highscore.window:widgets({ gamedata.highscore.table })
|
||||
gamedata.highscore.window.widgets = gamedata.highscore.table
|
||||
|
||||
gamedata.highscore.table.text = " Highscores:\n"
|
||||
|
||||
|
@ -440,7 +440,7 @@ function game.highscore (score)
|
|||
|
||||
gamedata.namebox = widget({ type = "textbox", name = "foobar" })
|
||||
gamedata.namebox.text = " Name: |"
|
||||
gamedata.highscore.window:widgets({ gamedata.namebox })
|
||||
gamedata.highscore.window.widgets = gamedata.namebox
|
||||
|
||||
if newentry then
|
||||
gamedata.name = ""
|
||||
|
@ -493,7 +493,7 @@ function run(args)
|
|||
gamedata.field.caption = widget({ type = "textbox", name = "caption", align = "left" })
|
||||
gamedata.field.caption.text = " Awesome Invaders"
|
||||
|
||||
gamedata.field.north:widgets({ gamedata.field.caption, gamedata.field.status })
|
||||
gamedata.field.north.widgets = { gamedata.field.caption, gamedata.field.status }
|
||||
|
||||
gamedata.field.south = wibox({ position = "floating",
|
||||
bg = gamedata.btheme.bg_focus or "#333333",
|
||||
|
|
|
@ -217,7 +217,7 @@ function notify(args)
|
|||
iconbox.width = 20
|
||||
end
|
||||
|
||||
box:widgets({ iconbox, textbox })
|
||||
box.widgets = { iconbox, textbox }
|
||||
|
||||
local timer = function () destroy(notification) end
|
||||
hooks.timer.register(timeout, timer)
|
||||
|
|
260
luaa.c
260
luaa.c
|
@ -231,6 +231,32 @@ luaA_hooks_clients(lua_State *L)
|
|||
return luaA_registerfct(L, 1, &globalconf.hooks.clients);
|
||||
}
|
||||
|
||||
/** Set the function called on each screen tag list change.
|
||||
* This function is called with a screen number as argument.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
* \luastack
|
||||
* \lparam A function to call on each tag list change.
|
||||
*/
|
||||
static int
|
||||
luaA_hooks_tags(lua_State *L)
|
||||
{
|
||||
return luaA_registerfct(L, 1, &globalconf.hooks.tags);
|
||||
}
|
||||
|
||||
/** Set the function called on each client's tags change.
|
||||
* This function is called with the client and the tag as argument.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
* \luastack
|
||||
* \lparam A function to call on each client's tags change.
|
||||
*/
|
||||
static int
|
||||
luaA_hooks_tagged(lua_State *L)
|
||||
{
|
||||
return luaA_registerfct(L, 1, &globalconf.hooks.tagged);
|
||||
}
|
||||
|
||||
/** Set the function called on each screen arrange. This function is called
|
||||
* with the screen number as argument.
|
||||
* \param L The Lua VM state.
|
||||
|
@ -397,6 +423,10 @@ luaA_openlib(lua_State *L, const char *name,
|
|||
lua_pop(L, 2);
|
||||
}
|
||||
|
||||
/** UTF-8 aware string length computing.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_mbstrlen(lua_State *L)
|
||||
{
|
||||
|
@ -405,8 +435,12 @@ luaA_mbstrlen(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/** Overload standard Lua next function to use __next key on metatable.
|
||||
* \param L The Lua VM state.
|
||||
* \param The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_next(lua_State *L)
|
||||
luaAe_next(lua_State *L)
|
||||
{
|
||||
if(luaL_getmetafield(L, 1, "__next"))
|
||||
{
|
||||
|
@ -423,8 +457,56 @@ luaA_next(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/** Overload lua_next() function by using __next metatable field
|
||||
* to get next elements.
|
||||
* \param L The Lua VM stack.
|
||||
* \param idx The index number of elements in stack.
|
||||
* \return 1 if more elements to come, 0 otherwise.
|
||||
*/
|
||||
int
|
||||
luaA_next(lua_State *L, int idx)
|
||||
{
|
||||
if(luaL_getmetafield(L, idx, "__next"))
|
||||
{
|
||||
/* if idx is relative, reduce it since we got __next */
|
||||
if(idx < 0) idx--;
|
||||
/* copy table and then move key */
|
||||
lua_pushvalue(L, idx);
|
||||
lua_pushvalue(L, -3);
|
||||
lua_remove(L, -4);
|
||||
lua_pcall(L, 2, 2, 0);
|
||||
/* next returned nil, it's the end */
|
||||
if(lua_isnil(L, -1))
|
||||
{
|
||||
/* remove nil */
|
||||
lua_pop(L, 2);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return lua_next(L, idx);
|
||||
}
|
||||
|
||||
/** Generic pairs function.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_pairs(lua_State *L)
|
||||
luaA_generic_pairs(lua_State *L)
|
||||
{
|
||||
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
|
||||
lua_pushvalue(L, 1); /* state, */
|
||||
lua_pushnil(L); /* and initial value */
|
||||
return 3;
|
||||
}
|
||||
|
||||
/** Overload standard pairs function to use __pairs field of metatables.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaAe_pairs(lua_State *L)
|
||||
{
|
||||
if(luaL_getmetafield(L, 1, "__pairs"))
|
||||
{
|
||||
|
@ -448,14 +530,170 @@ luaA_fixups(lua_State *L)
|
|||
lua_setfield(L, -2, "len");
|
||||
lua_pop(L, 1);
|
||||
lua_pushliteral(L, "next");
|
||||
lua_pushcfunction(L, luaA_next);
|
||||
lua_pushcfunction(L, luaAe_next);
|
||||
lua_settable(L, LUA_GLOBALSINDEX);
|
||||
lua_pushliteral(L, "pairs");
|
||||
lua_pushcfunction(L, luaA_next);
|
||||
lua_pushcclosure(L, luaA_pairs, 1); /* pairs get next as upvalue */
|
||||
lua_pushcfunction(L, luaAe_next);
|
||||
lua_pushcclosure(L, luaAe_pairs, 1); /* pairs get next as upvalue */
|
||||
lua_settable(L, LUA_GLOBALSINDEX);
|
||||
}
|
||||
|
||||
/** __next function for wtable objects.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_wtable_next(lua_State *L)
|
||||
{
|
||||
/* upvalue 1 is content table */
|
||||
if(lua_next(L, lua_upvalueindex(1)))
|
||||
return 2;
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Index function of wtable objects.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_wtable_index(lua_State *L)
|
||||
{
|
||||
size_t len;
|
||||
const char *buf;
|
||||
|
||||
lua_pushvalue(L, 2);
|
||||
/* check for size, waiting lua 5.2 and __len on tables */
|
||||
if((buf = lua_tolstring(L, -1, &len)))
|
||||
if(a_tokenize(buf, len) == A_TK_LEN)
|
||||
{
|
||||
lua_pushnumber(L, lua_objlen(L, lua_upvalueindex(1)));
|
||||
return 1;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
/* upvalue 1 is content table */
|
||||
lua_rawget(L, lua_upvalueindex(1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Newndex function of wtable objects.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_wtable_newindex(lua_State *L)
|
||||
{
|
||||
bool invalid = false;
|
||||
|
||||
/* push key on top */
|
||||
lua_pushvalue(L, 2);
|
||||
/* get current key value in content table */
|
||||
lua_rawget(L, lua_upvalueindex(1));
|
||||
/* if value is a widget, notify change */
|
||||
if(lua_istable(L, -1) || luaA_toudata(L, -1, "widget"))
|
||||
invalid = true;
|
||||
|
||||
lua_pop(L, 1); /* remove value */
|
||||
|
||||
/* if new value is a widget or a table */
|
||||
if(lua_istable(L, 3))
|
||||
{
|
||||
luaA_table2wtable(L);
|
||||
invalid = true;
|
||||
}
|
||||
else if(!invalid && luaA_toudata(L, 3, "widget"))
|
||||
invalid = true;
|
||||
|
||||
/* upvalue 1 is content table */
|
||||
lua_rawset(L, lua_upvalueindex(1));
|
||||
|
||||
if(invalid)
|
||||
luaA_wibox_invalidate_byitem(L, lua_topointer(L, 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Convert the top element of the stack to a proxied wtable.
|
||||
* \param L The Lua VM state.
|
||||
*/
|
||||
void
|
||||
luaA_table2wtable(lua_State *L)
|
||||
{
|
||||
if(!lua_istable(L, -1))
|
||||
return;
|
||||
|
||||
lua_newtable(L); /* create *real* content table */
|
||||
lua_newtable(L); /* metatable */
|
||||
lua_pushvalue(L, -2); /* copy content table */
|
||||
lua_pushcclosure(L, luaA_wtable_next, 1); /* __next has the content table as upvalue */
|
||||
lua_pushvalue(L, -3); /* copy content table */
|
||||
lua_pushcclosure(L, luaA_wtable_index, 1); /* __index has the content table as upvalue */
|
||||
lua_pushvalue(L, -4); /* copy content table */
|
||||
lua_pushcclosure(L, luaA_wtable_newindex, 1); /* __newindex has the content table as upvalue */
|
||||
/* set metatable field with just pushed closure */
|
||||
lua_setfield(L, -4, "__newindex");
|
||||
lua_setfield(L, -3, "__index");
|
||||
lua_setfield(L, -2, "__next");
|
||||
/* set metatable impossible to touch */
|
||||
lua_pushliteral(L, "wtable");
|
||||
lua_setfield(L, -2, "__metatable");
|
||||
/* set new metatable on original table */
|
||||
lua_setmetatable(L, -3);
|
||||
|
||||
/* initial key */
|
||||
lua_pushnil(L);
|
||||
/* go through original table */
|
||||
while(lua_next(L, -3))
|
||||
{
|
||||
/* if convert value to wtable */
|
||||
luaA_table2wtable(L);
|
||||
/* copy key */
|
||||
lua_pushvalue(L, -2);
|
||||
/* move key before value */
|
||||
lua_insert(L, -2);
|
||||
/* set same value in content table */
|
||||
lua_rawset(L, -4);
|
||||
/* copy key */
|
||||
lua_pushvalue(L, -1);
|
||||
/* push the new value :-> */
|
||||
lua_pushnil(L);
|
||||
/* set orig[k] = nil */
|
||||
lua_rawset(L, -5);
|
||||
}
|
||||
/* remove content table */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
/** Look for an item: table, function, etc.
|
||||
* \param L The Lua VM state.
|
||||
* \param item The pointer item.
|
||||
*/
|
||||
bool
|
||||
luaA_hasitem(lua_State *L, const void *item)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
while(luaA_next(L, -2))
|
||||
{
|
||||
if(lua_topointer(L, -1) == item)
|
||||
{
|
||||
/* remove value and key */
|
||||
lua_pop(L, 2);
|
||||
return true;
|
||||
}
|
||||
if(lua_istable(L, -1))
|
||||
if(luaA_hasitem(L, item))
|
||||
{
|
||||
/* remove key and value */
|
||||
lua_pop(L, 2);
|
||||
return true;
|
||||
}
|
||||
/* remove value */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Object table.
|
||||
* This table can use safely object as key.
|
||||
* \param L The Lua VM state.
|
||||
|
@ -625,6 +863,8 @@ luaA_init(void)
|
|||
{ "property", luaA_hooks_property },
|
||||
{ "arrange", luaA_hooks_arrange },
|
||||
{ "clients", luaA_hooks_clients },
|
||||
{ "tags", luaA_hooks_tags },
|
||||
{ "tagged", luaA_hooks_tagged },
|
||||
{ "timer", luaA_hooks_timer },
|
||||
/* deprecated */
|
||||
{ "mouse_over", luaA_hooks_mouse_over },
|
||||
|
@ -701,6 +941,8 @@ luaA_init(void)
|
|||
globalconf.hooks.mouse_enter = LUA_REFNIL;
|
||||
globalconf.hooks.arrange = LUA_REFNIL;
|
||||
globalconf.hooks.clients = LUA_REFNIL;
|
||||
globalconf.hooks.tags = LUA_REFNIL;
|
||||
globalconf.hooks.tagged = LUA_REFNIL;
|
||||
globalconf.hooks.property = LUA_REFNIL;
|
||||
globalconf.hooks.timer = LUA_REFNIL;
|
||||
}
|
||||
|
@ -1001,7 +1243,12 @@ luaA_on_timer(EV_P_ ev_timer *w, int revents)
|
|||
awesome_refresh(globalconf.connection);
|
||||
}
|
||||
|
||||
void
|
||||
/** Push a color as a string onto the stack
|
||||
* \param L The Lua VM state.
|
||||
* \param c The color to push.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
int
|
||||
luaA_pushcolor(lua_State *L, const xcolor_t *c)
|
||||
{
|
||||
uint8_t r = (unsigned)c->red * 0xff / 0xffff;
|
||||
|
@ -1015,4 +1262,5 @@ luaA_pushcolor(lua_State *L, const xcolor_t *c)
|
|||
else
|
||||
snprintf(s, sizeof(s), "#%02x%02x%02x%02x", r, g, b, a);
|
||||
lua_pushlstring(L, s, sizeof(s));
|
||||
return 1;
|
||||
}
|
||||
|
|
16
luaa.h
16
luaa.h
|
@ -333,17 +333,11 @@ void luaA_init(void);
|
|||
bool luaA_parserc(const char *, bool);
|
||||
void luaA_cs_init(void);
|
||||
void luaA_cs_cleanup(void);
|
||||
void luaA_on_timer(EV_P_ ev_timer *w, int revents);
|
||||
void luaA_pushcolor(lua_State *, const xcolor_t *);
|
||||
|
||||
static inline int
|
||||
luaA_generic_pairs(lua_State *L)
|
||||
{
|
||||
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
|
||||
lua_pushvalue(L, 1); /* state, */
|
||||
lua_pushnil(L); /* and initial value */
|
||||
return 3;
|
||||
}
|
||||
void luaA_on_timer(EV_P_ ev_timer *, int);
|
||||
int luaA_pushcolor(lua_State *, const xcolor_t *);
|
||||
bool luaA_hasitem(lua_State *, const void *);
|
||||
void luaA_table2wtable(lua_State *);
|
||||
int luaA_next(lua_State *, int);
|
||||
|
||||
#define hooks_property(c, prop) \
|
||||
do { \
|
||||
|
|
|
@ -187,11 +187,8 @@ property_update_wm_hints(client_t *c, xcb_get_property_reply_t *reply)
|
|||
if(isurgent != c->isurgent)
|
||||
{
|
||||
c->isurgent = isurgent;
|
||||
|
||||
/* execute hook */
|
||||
hooks_property(c, "urgent");
|
||||
|
||||
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
|
||||
}
|
||||
if(wmh.flags & XCB_WM_HINT_STATE &&
|
||||
wmh.initial_state == XCB_WM_STATE_WITHDRAWN)
|
||||
|
@ -240,8 +237,6 @@ property_update_wm_name(client_t *c)
|
|||
|
||||
/* call hook */
|
||||
hooks_property(c, "name");
|
||||
|
||||
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -290,7 +285,6 @@ property_handle_net_wm_icon(void *data,
|
|||
{
|
||||
image_t *icon;
|
||||
image_unref(&c->icon);
|
||||
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
|
||||
icon = ewmh_window_icon_from_reply(reply);
|
||||
c->icon = icon ? image_ref(&icon) : NULL;
|
||||
|
||||
|
|
3
screen.c
3
screen.c
|
@ -315,9 +315,6 @@ screen_client_moveto(client_t *c, int new_screen, bool dotag, bool doresize)
|
|||
if(c->titlebar)
|
||||
c->titlebar->screen = new_screen;
|
||||
|
||||
widget_invalidate_cache(old_screen, WIDGET_CACHE_CLIENTS);
|
||||
widget_invalidate_cache(new_screen, WIDGET_CACHE_CLIENTS);
|
||||
|
||||
if(dotag && !c->issticky)
|
||||
{
|
||||
/* remove old tags */
|
||||
|
|
|
@ -105,6 +105,7 @@ typedef struct
|
|||
int screen;
|
||||
/** Widget list */
|
||||
widget_node_t *widgets;
|
||||
luaA_ref widgets_table;
|
||||
/** Widget the mouse is over */
|
||||
widget_node_t *mouse_over;
|
||||
/** Need update */
|
||||
|
@ -141,8 +142,6 @@ struct widget_t
|
|||
widget_constructor_t *type;
|
||||
/** Widget destructor */
|
||||
widget_destructor_t *destructor;
|
||||
/** Widget detach function */
|
||||
void (*detach)(widget_t *, wibox_t *);
|
||||
/** Draw function */
|
||||
int (*draw)(draw_context_t *, int, widget_node_t *, int, int, wibox_t *);
|
||||
/** Index function */
|
||||
|
@ -437,6 +436,10 @@ struct awesome_t
|
|||
luaA_ref arrange;
|
||||
/** Command to run when client list changes */
|
||||
luaA_ref clients;
|
||||
/** Command to run on numbers of tag changes */
|
||||
luaA_ref tags;
|
||||
/** Command to run when client gets (un)tagged */
|
||||
luaA_ref tagged;
|
||||
/** Command to run on property change */
|
||||
luaA_ref property;
|
||||
/** Command to run on time */
|
||||
|
|
22
tag.c
22
tag.c
|
@ -42,7 +42,6 @@ tag_view(tag_t *tag, bool view)
|
|||
{
|
||||
tag->selected = view;
|
||||
ewmh_update_net_current_desktop(screen_virttophys(tag->screen));
|
||||
widget_invalidate_cache(tag->screen, WIDGET_CACHE_TAGS);
|
||||
globalconf.screens[tag->screen].need_arrange = true;
|
||||
}
|
||||
|
||||
|
@ -94,7 +93,9 @@ tag_append_to_screen(tag_t *tag, screen_t *s)
|
|||
ewmh_update_net_numbers_of_desktop(phys_screen);
|
||||
ewmh_update_net_desktop_names(phys_screen);
|
||||
ewmh_update_workarea(phys_screen);
|
||||
widget_invalidate_cache(s->index, WIDGET_CACHE_TAGS);
|
||||
/* call hook */
|
||||
lua_pushnumber(globalconf.L, s->index+ 1);
|
||||
luaA_dofunction(globalconf.L, globalconf.hooks.tags, 1, 0);
|
||||
}
|
||||
|
||||
/** Remove a tag from screen. Tag must be on a screen and have no clients.
|
||||
|
@ -103,6 +104,7 @@ tag_append_to_screen(tag_t *tag, screen_t *s)
|
|||
static void
|
||||
tag_remove_from_screen(tag_t *tag)
|
||||
{
|
||||
int screen = tag->screen;
|
||||
int phys_screen = screen_virttophys(tag->screen);
|
||||
tag_array_t *tags = &globalconf.screens[tag->screen].tags;
|
||||
|
||||
|
@ -115,9 +117,11 @@ tag_remove_from_screen(tag_t *tag)
|
|||
ewmh_update_net_numbers_of_desktop(phys_screen);
|
||||
ewmh_update_net_desktop_names(phys_screen);
|
||||
ewmh_update_workarea(phys_screen);
|
||||
widget_invalidate_cache(tag->screen, WIDGET_CACHE_TAGS);
|
||||
tag->screen = SCREEN_UNDEF;
|
||||
tag_unref(&tag);
|
||||
/* call hook */
|
||||
lua_pushnumber(globalconf.L, screen + 1);
|
||||
luaA_dofunction(globalconf.L, globalconf.hooks.tags, 1, 0);
|
||||
}
|
||||
|
||||
/** Tag a client with specified tag.
|
||||
|
@ -134,8 +138,10 @@ tag_client(client_t *c, tag_t *t)
|
|||
tag_ref(&t);
|
||||
client_array_append(&t->clients, c);
|
||||
client_saveprops_tags(c);
|
||||
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
|
||||
client_need_arrange(c);
|
||||
/* call hook */
|
||||
luaA_client_userdata_new(globalconf.L, c);
|
||||
luaA_dofunction(globalconf.L, globalconf.hooks.tagged, 1, 0);
|
||||
}
|
||||
|
||||
/** Untag a client with specified tag.
|
||||
|
@ -152,7 +158,10 @@ untag_client(client_t *c, tag_t *t)
|
|||
client_array_take(&t->clients, i);
|
||||
tag_unref(&t);
|
||||
client_saveprops_tags(c);
|
||||
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
|
||||
/* call hook */
|
||||
luaA_client_userdata_new(globalconf.L, c);
|
||||
luaA_tag_userdata_new(globalconf.L, t);
|
||||
luaA_dofunction(globalconf.L, globalconf.hooks.tagged, 2, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -404,12 +413,9 @@ luaA_tag_newindex(lua_State *L)
|
|||
case A_TK_NAME:
|
||||
buf = luaL_checklstring(L, 3, &len);
|
||||
if((*tag)->screen != SCREEN_UNDEF)
|
||||
{
|
||||
if(tag_getbyname((*tag)->screen, (*tag)->name) != *tag)
|
||||
luaL_error(L, "a tag with the name `%s' is already on screen %d",
|
||||
buf, (*tag)->screen);
|
||||
widget_invalidate_cache((*tag)->screen, WIDGET_CACHE_TAGS);
|
||||
}
|
||||
p_delete(&(*tag)->name);
|
||||
a_iso2utf8(&(*tag)->name, buf, len);
|
||||
break;
|
||||
|
|
163
wibox.c
163
wibox.c
|
@ -439,6 +439,18 @@ wibox_position_update(wibox_t *wibox)
|
|||
wibox_move(wibox, wingeom.x, wingeom.y);
|
||||
}
|
||||
|
||||
/** Delete a wibox.
|
||||
* \param wibox wibox to delete.
|
||||
*/
|
||||
void
|
||||
wibox_delete(wibox_t **wibox)
|
||||
{
|
||||
simplewindow_wipe(&(*wibox)->sw);
|
||||
luaL_unref(globalconf.L, LUA_REGISTRYINDEX, (*wibox)->widgets_table);
|
||||
widget_node_list_wipe(&(*wibox)->widgets);
|
||||
p_delete(wibox);
|
||||
}
|
||||
|
||||
/** Get a wibox by its window.
|
||||
* \param w The window id.
|
||||
* \return A wibox if found, NULL otherwise.
|
||||
|
@ -627,6 +639,7 @@ luaA_wibox_new(lua_State *L)
|
|||
luaA_checktable(L, 2);
|
||||
|
||||
w = p_new(wibox_t, 1);
|
||||
w->widgets_table = LUA_REFNIL;
|
||||
|
||||
w->sw.ctx.fg = globalconf.colors.fg;
|
||||
if((buf = luaA_getopt_lstring(L, 2, "fg", NULL, &len)))
|
||||
|
@ -677,6 +690,64 @@ luaA_wibox_new(lua_State *L)
|
|||
return luaA_wibox_userdata_new(L, w);
|
||||
}
|
||||
|
||||
/** Rebuild wibox widgets list.
|
||||
* \param L The Lua VM state.
|
||||
* \param wibox The wibox.
|
||||
*/
|
||||
static void
|
||||
wibox_widgets_table_build(lua_State *L, wibox_t *wibox)
|
||||
{
|
||||
widget_node_list_wipe(&wibox->widgets);
|
||||
luaA_table2widgets(L, &wibox->widgets);
|
||||
wibox->mouse_over = NULL;
|
||||
wibox->need_update = true;
|
||||
}
|
||||
|
||||
/** Check if a wibox widget table has an item.
|
||||
* \param L The Lua VM state.
|
||||
* \param wibox The wibox.
|
||||
* \param item The item to look for.
|
||||
*/
|
||||
static bool
|
||||
luaA_wibox_hasitem(lua_State *L, wibox_t *wibox, const void *item)
|
||||
{
|
||||
bool ret = false;
|
||||
lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, wibox->widgets_table);
|
||||
if(lua_topointer(L, -1) == item || luaA_hasitem(L, item))
|
||||
ret = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Invalidate a wibox by a Lua object (table, etc).
|
||||
* \param L The Lua VM state.
|
||||
* \param item The object identifier.
|
||||
*/
|
||||
void
|
||||
luaA_wibox_invalidate_byitem(lua_State *L, const void *item)
|
||||
{
|
||||
for(int screen = 0; screen < globalconf.nscreen; screen++)
|
||||
for(int i = 0; i < globalconf.screens[screen].wiboxes.len; i++)
|
||||
{
|
||||
wibox_t *wibox = globalconf.screens[screen].wiboxes.tab[i];
|
||||
if(luaA_wibox_hasitem(L, wibox, item))
|
||||
{
|
||||
/* recompute widget node list */
|
||||
wibox_widgets_table_build(L, wibox);
|
||||
lua_pop(L, 1); /* remove widgets table */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(client_t *c = globalconf.clients; c; c = c->next)
|
||||
if(c->titlebar && luaA_wibox_hasitem(L, c->titlebar, item))
|
||||
{
|
||||
/* recompute widget node list */
|
||||
wibox_widgets_table_build(L, c->titlebar);
|
||||
lua_pop(L, 1); /* remove widgets table */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Wibox object.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
|
@ -742,6 +813,9 @@ luaA_wibox_index(lua_State *L)
|
|||
case A_TK_ORIENTATION:
|
||||
lua_pushstring(L, orientation_tostr((*wibox)->sw.orientation));
|
||||
break;
|
||||
case A_TK_WIDGETS:
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, (*wibox)->widgets_table);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -749,88 +823,6 @@ luaA_wibox_index(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/** Generic widget set.
|
||||
* \param L The Lua VM state.
|
||||
* \param idx The table of widgets index.
|
||||
* \param object The object the widget will be attached to.
|
||||
* \param widgets The widgets to fill.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static void
|
||||
luaA_widget_set(lua_State *L, int idx, wibox_t *object, widget_node_t **widgets)
|
||||
{
|
||||
widget_node_t *witer;
|
||||
|
||||
luaA_checktable(L, idx);
|
||||
|
||||
/* remove all widgets */
|
||||
for(witer = *widgets; witer; witer = *widgets)
|
||||
{
|
||||
if(witer->widget->detach)
|
||||
witer->widget->detach(witer->widget, object);
|
||||
widget_unref(&witer->widget);
|
||||
widget_node_list_detach(widgets, witer);
|
||||
p_delete(&witer);
|
||||
}
|
||||
|
||||
/* now read all widgets and add them */
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, idx))
|
||||
{
|
||||
widget_t **widget = luaA_checkudata(L, -1, "widget");
|
||||
widget_node_t *w = p_new(widget_node_t, 1);
|
||||
w->widget = *widget;
|
||||
widget_node_list_append(widgets, w);
|
||||
widget_ref(widget);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Generic widget get.
|
||||
* \param L The Lua VM state.
|
||||
* \param widget The widget list.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_widget_get(lua_State *L, widget_node_t *widgets)
|
||||
{
|
||||
widget_node_t *witer;
|
||||
int i = 0;
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
for(witer = widgets; witer; witer = witer->next)
|
||||
{
|
||||
luaA_widget_userdata_new(L, witer->widget);
|
||||
lua_rawseti(L, -2, ++i);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** Get or set the wibox widgets.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
* \luastack
|
||||
* \lparam None, or a table of widgets to set.
|
||||
* \lreturn The current wibox widgets.
|
||||
*/
|
||||
static int
|
||||
luaA_wibox_widgets(lua_State *L)
|
||||
{
|
||||
wibox_t **wibox = luaA_checkudata(L, 1, "wibox");
|
||||
|
||||
if(lua_gettop(L) == 2)
|
||||
{
|
||||
luaA_widget_set(L, 2, *wibox, &(*wibox)->widgets);
|
||||
(*wibox)->need_update = true;
|
||||
(*wibox)->mouse_over = NULL;
|
||||
return 1;
|
||||
}
|
||||
return luaA_widget_get(L, (*wibox)->widgets);
|
||||
}
|
||||
|
||||
/* Set or get the wibox geometry.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
|
@ -986,6 +978,12 @@ luaA_wibox_newindex(lua_State *L)
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case A_TK_WIDGETS:
|
||||
luaA_register(L, 3, &(*wibox)->widgets_table);
|
||||
/* recompute widget node list */
|
||||
wibox_widgets_table_build(L, *wibox);
|
||||
luaA_table2wtable(L);
|
||||
break;
|
||||
default:
|
||||
switch((*wibox)->type)
|
||||
{
|
||||
|
@ -1006,7 +1004,6 @@ const struct luaL_reg awesome_wibox_methods[] =
|
|||
};
|
||||
const struct luaL_reg awesome_wibox_meta[] =
|
||||
{
|
||||
{ "widgets", luaA_wibox_widgets },
|
||||
{ "geometry", luaA_wibox_geometry },
|
||||
{ "__index", luaA_wibox_index },
|
||||
{ "__newindex", luaA_wibox_newindex },
|
||||
|
|
11
wibox.h
11
wibox.h
|
@ -32,18 +32,13 @@ void wibox_refresh(void);
|
|||
|
||||
int luaA_wibox_new(lua_State *);
|
||||
int luaA_wibox_userdata_new(lua_State *, wibox_t *);
|
||||
void luaA_wibox_invalidate_byitem(lua_State *, const void *);
|
||||
|
||||
void wibox_position_update(wibox_t *);
|
||||
wibox_t * wibox_getbywin(xcb_window_t);
|
||||
void wibox_detach(wibox_t *);
|
||||
void wibox_attach(wibox_t *, screen_t *);
|
||||
|
||||
static inline void
|
||||
wibox_delete(wibox_t **wibox)
|
||||
{
|
||||
simplewindow_wipe(&(*wibox)->sw);
|
||||
widget_node_list_wipe(&(*wibox)->widgets);
|
||||
p_delete(wibox);
|
||||
}
|
||||
void wibox_delete(wibox_t **);
|
||||
|
||||
static inline void
|
||||
wibox_moveresize(wibox_t *wibox, area_t geometry)
|
||||
|
|
67
widget.c
67
widget.c
|
@ -82,6 +82,34 @@ widget_common_button(widget_node_t *w,
|
|||
}
|
||||
}
|
||||
|
||||
/** Convert a Lua table to a list of widget nodet.
|
||||
* \param L The Lua VM state.
|
||||
* \param widgets The linked list of widget node.
|
||||
*/
|
||||
void
|
||||
luaA_table2widgets(lua_State *L, widget_node_t **widgets)
|
||||
{
|
||||
if(lua_istable(L, -1))
|
||||
{
|
||||
lua_pushnil(L);
|
||||
while(luaA_next(L, -2))
|
||||
{
|
||||
luaA_table2widgets(L, widgets);
|
||||
lua_pop(L, 1); /* remove value */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
widget_t **widget = luaA_toudata(L, -1, "widget");
|
||||
if(widget)
|
||||
{
|
||||
widget_node_t *w = p_new(widget_node_t, 1);
|
||||
w->widget = widget_ref(widget);
|
||||
widget_node_list_append(widgets, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Render a list of widgets.
|
||||
* \param wnode The list of widgets.
|
||||
* \param ctx The draw context where to render.
|
||||
|
@ -91,13 +119,13 @@ widget_common_button(widget_node_t *w,
|
|||
* \param orientation The object orientation.
|
||||
* \param x The x coordinates of the object.
|
||||
* \param y The y coordinates of the object.
|
||||
* \param object The wibox.
|
||||
* \param wibox The wibox.
|
||||
* \todo Remove GC.
|
||||
*/
|
||||
void
|
||||
widget_render(widget_node_t *wnode, draw_context_t *ctx, xcb_gcontext_t gc, xcb_pixmap_t rotate_px,
|
||||
int screen, orientation_t orientation,
|
||||
int x, int y, wibox_t *object)
|
||||
int x, int y, wibox_t *wibox)
|
||||
{
|
||||
xcb_pixmap_t rootpix;
|
||||
xcb_screen_t *s;
|
||||
|
@ -157,16 +185,27 @@ widget_render(widget_node_t *wnode, draw_context_t *ctx, xcb_gcontext_t gc, xcb_
|
|||
|
||||
for(w = wnode; w; w = w->next)
|
||||
if(w->widget->align == AlignLeft && w->widget->isvisible)
|
||||
left += w->widget->draw(ctx, screen, w, left, (left + right), object);
|
||||
left += w->widget->draw(ctx, screen, w, left, (left + right), wibox);
|
||||
|
||||
/* renders right widget from last to first */
|
||||
for(w = *widget_node_list_last(&wnode); w; w = w->prev)
|
||||
if(w->widget->align == AlignRight && w->widget->isvisible)
|
||||
right += w->widget->draw(ctx, screen, w, right, (left + right), object);
|
||||
right += w->widget->draw(ctx, screen, w, right, (left + right), wibox);
|
||||
|
||||
/* \todo rewrite this */
|
||||
int flex = 0;
|
||||
for(w = wnode; w; w = w->next)
|
||||
if(w->widget->align == AlignFlex && w->widget->isvisible)
|
||||
left += w->widget->draw(ctx, screen, w, left, (left + right), object);
|
||||
flex++;
|
||||
|
||||
if(flex)
|
||||
{
|
||||
int length = (ctx->width - (left + right)) / flex;
|
||||
|
||||
for(w = wnode; w; w = w->next)
|
||||
if(w->widget->align == AlignFlex && w->widget->isvisible)
|
||||
left += w->widget->draw(ctx, screen, w, left, (left + right) + length * --flex , wibox);
|
||||
}
|
||||
|
||||
switch(orientation)
|
||||
{
|
||||
|
@ -228,29 +267,27 @@ widget_invalidate_cache(int screen, int flags)
|
|||
void
|
||||
widget_invalidate_bywidget(widget_t *widget)
|
||||
{
|
||||
int screen;
|
||||
widget_node_t *witer;
|
||||
client_t *c;
|
||||
|
||||
for(screen = 0; screen < globalconf.nscreen; screen++)
|
||||
for(int screen = 0; screen < globalconf.nscreen; screen++)
|
||||
for(int i = 0; i < globalconf.screens[screen].wiboxes.len; i++)
|
||||
{
|
||||
wibox_t *wibox = globalconf.screens[screen].wiboxes.tab[i];
|
||||
|
||||
if(!wibox->need_update)
|
||||
for(witer = wibox->widgets; witer; witer = witer->next)
|
||||
for(widget_node_t *witer = wibox->widgets; witer; witer = witer->next)
|
||||
if(witer->widget == widget)
|
||||
{
|
||||
wibox->need_update = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(c = globalconf.clients; c; c = c->next)
|
||||
for(client_t *c = globalconf.clients; c; c = c->next)
|
||||
if(c->titlebar && !c->titlebar->need_update)
|
||||
for(witer = c->titlebar->widgets; witer; witer = witer->next)
|
||||
for(widget_node_t *witer = c->titlebar->widgets; witer; witer = witer->next)
|
||||
if(witer->widget == widget)
|
||||
{
|
||||
c->titlebar->need_update = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a new widget.
|
||||
|
|
5
widget.h
5
widget.h
|
@ -24,8 +24,6 @@
|
|||
|
||||
#include "structs.h"
|
||||
|
||||
#define WIDGET_CACHE_CLIENTS (1<<0)
|
||||
#define WIDGET_CACHE_TAGS (1<<2)
|
||||
#define WIDGET_CACHE_EMBEDDED (1<<3)
|
||||
|
||||
void widget_invalidate_cache(int, int);
|
||||
|
@ -34,14 +32,13 @@ void widget_common_new(widget_t *);
|
|||
void widget_render(widget_node_t *, draw_context_t *, xcb_gcontext_t, xcb_drawable_t, int, orientation_t, int, int, wibox_t *);
|
||||
|
||||
int luaA_widget_userdata_new(lua_State *, widget_t *);
|
||||
void luaA_table2widgets(lua_State *, widget_node_t **);
|
||||
|
||||
void widget_invalidate_bywidget(widget_t *);
|
||||
|
||||
widget_constructor_t taglist_new;
|
||||
widget_constructor_t textbox_new;
|
||||
widget_constructor_t progressbar_new;
|
||||
widget_constructor_t graph_new;
|
||||
widget_constructor_t tasklist_new;
|
||||
widget_constructor_t systray_new;
|
||||
widget_constructor_t imagebox_new;
|
||||
|
||||
|
|
|
@ -1,306 +0,0 @@
|
|||
/*
|
||||
* taglist.c - tag list widget
|
||||
*
|
||||
* Copyright © 2008 Julien Danjou <julien@danjou.info>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "widget.h"
|
||||
#include "tag.h"
|
||||
#include "wibox.h"
|
||||
#include "common/tokenize.h"
|
||||
|
||||
extern awesome_t globalconf;
|
||||
|
||||
/** Data type used to store where we draw the taglist for a particular object.
|
||||
* This is filled in the draw function, and use later when we get a click.
|
||||
*/
|
||||
typedef struct taglist_drawn_area_t taglist_drawn_area_t;
|
||||
struct taglist_drawn_area_t
|
||||
{
|
||||
wibox_t *object;
|
||||
area_array_t areas;
|
||||
taglist_drawn_area_t *next, *prev;
|
||||
};
|
||||
|
||||
/** Delete a taglist_drawn_area_t object.
|
||||
* \param a The drawn area to delete.
|
||||
*/
|
||||
static void
|
||||
taglist_drawn_area_delete(taglist_drawn_area_t **a)
|
||||
{
|
||||
area_array_wipe(&(*a)->areas);
|
||||
p_delete(a);
|
||||
}
|
||||
|
||||
DO_SLIST(taglist_drawn_area_t, taglist_drawn_area, taglist_drawn_area_delete);
|
||||
|
||||
/** Taglist widget private data */
|
||||
typedef struct
|
||||
{
|
||||
taglist_drawn_area_t *drawn_area;
|
||||
luaA_ref label;
|
||||
} taglist_data_t;
|
||||
|
||||
static taglist_drawn_area_t *
|
||||
taglist_drawn_area_getbyobj(taglist_drawn_area_t *list, wibox_t *p)
|
||||
{
|
||||
taglist_drawn_area_t *t;
|
||||
|
||||
for(t = list; t; t = t->next)
|
||||
if(t->object == p)
|
||||
return t;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Draw a taglist.
|
||||
* \param ctx The draw context.
|
||||
* \param screen The screen we're drawing for.
|
||||
* \param w The widget node we're drawing for.
|
||||
* \param offset Offset to draw at.
|
||||
* \param used Space already used.
|
||||
* \param object The object pointer we're drawing onto.
|
||||
* \return The width used.
|
||||
*/
|
||||
static int
|
||||
taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w,
|
||||
int offset,
|
||||
int used __attribute__ ((unused)),
|
||||
wibox_t *object)
|
||||
{
|
||||
taglist_data_t *data = w->widget->data;
|
||||
area_t area;
|
||||
taglist_drawn_area_t *tda;
|
||||
int prev_width = 0;
|
||||
|
||||
tag_array_t *tags = &globalconf.screens[screen].tags;
|
||||
const char **text = p_alloca(const char *, tags->len);
|
||||
size_t *len = p_alloca(size_t, tags->len);
|
||||
draw_parser_data_t *pdata = p_alloca(draw_parser_data_t, tags->len);
|
||||
|
||||
w->area.width = w->area.y = 0;
|
||||
|
||||
/* Lookup for our taglist_drawn_area.
|
||||
* This will be used to store area where we draw tag list for each object. */
|
||||
if(!(tda = taglist_drawn_area_getbyobj(data->drawn_area, object)))
|
||||
{
|
||||
/* Oh, we did not find a drawn area for our object. First time? */
|
||||
tda = p_new(taglist_drawn_area_t, 1);
|
||||
tda->object = object;
|
||||
taglist_drawn_area_list_push(&data->drawn_area, tda);
|
||||
}
|
||||
|
||||
area_array_wipe(&tda->areas);
|
||||
area_array_init(&tda->areas);
|
||||
|
||||
/* First compute text and widget width */
|
||||
for(int i = 0; i < tags->len; i++)
|
||||
{
|
||||
tag_t *tag = tags->tab[i];
|
||||
p_clear(&area, 1);
|
||||
|
||||
luaA_tag_userdata_new(globalconf.L, tag);
|
||||
if(luaA_dofunction(globalconf.L, data->label, 1, 1))
|
||||
{
|
||||
if(lua_isstring(globalconf.L, -1))
|
||||
text[i] = lua_tolstring(globalconf.L, -1, &len[i]);
|
||||
|
||||
lua_pop(globalconf.L, 1);
|
||||
|
||||
draw_parser_data_init(&pdata[i]);
|
||||
area = draw_text_extents(ctx->phys_screen,
|
||||
globalconf.font, text[i], len[i], &pdata[i]);
|
||||
area.height = ctx->height;
|
||||
|
||||
if(pdata[i].bg_image)
|
||||
area.width = MAX(area.width,
|
||||
pdata[i].bg_resize ? ((double) pdata[i].bg_image->width / (double) pdata[i].bg_image->height) * w->area.height : pdata[i].bg_image->width);
|
||||
|
||||
w->area.width += area.width;
|
||||
}
|
||||
area_array_append(&tda->areas, area);
|
||||
}
|
||||
|
||||
/* Now that we have widget width we can compute widget x coordinate */
|
||||
w->area.x = widget_calculate_offset(ctx->width, w->area.width,
|
||||
offset, w->widget->align);
|
||||
|
||||
for(int i = 0; i < tags->len; i++)
|
||||
{
|
||||
area_t *r = &tda->areas.tab[i];
|
||||
|
||||
r->x = w->area.x + prev_width;
|
||||
prev_width += r->width;
|
||||
draw_text(ctx, globalconf.font, *r, text[i], len[i], &pdata[i]);
|
||||
draw_parser_data_wipe(&pdata[i]);
|
||||
}
|
||||
|
||||
w->area.height = ctx->height;
|
||||
return w->area.width;
|
||||
}
|
||||
|
||||
/** Handle button click on tasklist.
|
||||
* \param w The widget node.
|
||||
* \param ev The button press event.
|
||||
* \param btype The button press event type.
|
||||
* \param screen The screen where the click was.
|
||||
* \param object The object we're onto.
|
||||
*/
|
||||
static void
|
||||
taglist_button(widget_node_t *w,
|
||||
xcb_button_press_event_t *ev,
|
||||
int screen,
|
||||
wibox_t *object)
|
||||
{
|
||||
tag_array_t *tags = &globalconf.screens[screen].tags;
|
||||
taglist_data_t *data = w->widget->data;
|
||||
taglist_drawn_area_t *tda;
|
||||
button_array_t *barr = &w->widget->buttons;
|
||||
|
||||
/* Find the good drawn area list */
|
||||
if((tda = taglist_drawn_area_getbyobj(data->drawn_area, object)))
|
||||
for(int i = 0; i < barr->len; i++)
|
||||
if(ev->detail == barr->tab[i]->button
|
||||
&& XUTIL_MASK_CLEAN(ev->state) == barr->tab[i]->mod)
|
||||
for(int j = 0; i < MIN(tags->len, tda->areas.len); j++)
|
||||
{
|
||||
tag_t *tag = tags->tab[j];
|
||||
area_t *area = &tda->areas.tab[j];
|
||||
if(ev->event_x >= AREA_LEFT(*area)
|
||||
&& ev->event_x < AREA_RIGHT(*area))
|
||||
{
|
||||
luaA_wibox_userdata_new(globalconf.L, object);
|
||||
luaA_tag_userdata_new(globalconf.L, tag);
|
||||
luaA_dofunction(globalconf.L,
|
||||
ev->response_type == XCB_BUTTON_PRESS ?
|
||||
barr->tab[i]->press : barr->tab[i]->release,
|
||||
2, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Taglist widget.
|
||||
* \param L The Lua VM state.
|
||||
* \param token The key token.
|
||||
* \return The number of elements pushed on stack.
|
||||
* \luastack
|
||||
* \lfield label Function used to get the string to display as the tag title.
|
||||
* It gets the tag as argument, and must return a string.
|
||||
*/
|
||||
static int
|
||||
luaA_taglist_index(lua_State *L, awesome_token_t token)
|
||||
{
|
||||
widget_t **widget = luaA_checkudata(L, 1, "widget");
|
||||
taglist_data_t *d = (*widget)->data;
|
||||
|
||||
switch(token)
|
||||
{
|
||||
case A_TK_LABEL:
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, d->label);
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Newindex function for taglist.
|
||||
* \param L The Lua VM state.
|
||||
* \param token The key token.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_taglist_newindex(lua_State *L, awesome_token_t token)
|
||||
{
|
||||
widget_t **widget = luaA_checkudata(L, 1, "widget");
|
||||
taglist_data_t *d = (*widget)->data;
|
||||
|
||||
switch(token)
|
||||
{
|
||||
case A_TK_LABEL:
|
||||
luaA_registerfct(L, 3, &d->label);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
widget_invalidate_bywidget(*widget);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Taglist destructor.
|
||||
* \param widget The widget to destroy.
|
||||
*/
|
||||
static void
|
||||
taglist_destructor(widget_t *widget)
|
||||
{
|
||||
taglist_data_t *d = widget->data;
|
||||
|
||||
taglist_drawn_area_list_wipe(&d->drawn_area);
|
||||
p_delete(&d);
|
||||
}
|
||||
|
||||
/** Taglist detach function.
|
||||
* \param widget The widget which is detaching.
|
||||
* \param object The object we are leaving.
|
||||
*/
|
||||
static void
|
||||
taglist_detach(widget_t *widget, wibox_t *object)
|
||||
{
|
||||
taglist_data_t *d = widget->data;
|
||||
taglist_drawn_area_t *tda;
|
||||
|
||||
if((tda = taglist_drawn_area_getbyobj(d->drawn_area, object)))
|
||||
{
|
||||
taglist_drawn_area_list_detach(&d->drawn_area, tda);
|
||||
taglist_drawn_area_delete(&tda);
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a brand new taglist widget.
|
||||
* \param align Widget alignment.
|
||||
* \return A taglist widget.
|
||||
*/
|
||||
widget_t *
|
||||
taglist_new(alignment_t align)
|
||||
{
|
||||
widget_t *w;
|
||||
taglist_data_t *d;
|
||||
|
||||
w = p_new(widget_t, 1);
|
||||
widget_common_new(w);
|
||||
w->index = luaA_taglist_index;
|
||||
w->newindex = luaA_taglist_newindex;
|
||||
w->align = align;
|
||||
w->draw = taglist_draw;
|
||||
w->button = taglist_button;
|
||||
w->destructor = taglist_destructor;
|
||||
w->detach = taglist_detach;
|
||||
|
||||
w->data = d = p_new(taglist_data_t, 1);
|
||||
d->label = LUA_REFNIL;
|
||||
|
||||
/* Set cache property */
|
||||
w->cache_flags = WIDGET_CACHE_TAGS | WIDGET_CACHE_CLIENTS;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
|
@ -1,430 +0,0 @@
|
|||
/*
|
||||
* tasklist.c - task list widget
|
||||
*
|
||||
* Copyright © 2008 Julien Danjou <julien@danjou.info>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "widget.h"
|
||||
#include "tag.h"
|
||||
#include "wibox.h"
|
||||
#include "common/markup.h"
|
||||
#include "common/tokenize.h"
|
||||
|
||||
extern awesome_t globalconf;
|
||||
|
||||
/** Link a client and a label */
|
||||
typedef struct
|
||||
{
|
||||
/** A client */
|
||||
client_t *client;
|
||||
/** The client label */
|
||||
char *label;
|
||||
/** The client label len */
|
||||
size_t label_len;
|
||||
} client_label_t;
|
||||
|
||||
/** Delete a client label.
|
||||
* \param l The client label.
|
||||
*/
|
||||
static void
|
||||
client_label_wipe(client_label_t *l)
|
||||
{
|
||||
p_delete(&l->label);
|
||||
}
|
||||
|
||||
DO_ARRAY(client_label_t, client_label, client_label_wipe)
|
||||
|
||||
typedef struct tasklist_object_data_t tasklist_object_data_t;
|
||||
/** Link an object with a client label array and other infos */
|
||||
struct tasklist_object_data_t
|
||||
{
|
||||
/** The object */
|
||||
wibox_t *object;
|
||||
/** The box width for each client */
|
||||
int box_width;
|
||||
/** The client label array for the object */
|
||||
client_label_array_t client_labels;
|
||||
/** This is a list */
|
||||
tasklist_object_data_t *prev, *next;
|
||||
};
|
||||
|
||||
static void
|
||||
tasklist_object_data_delete(tasklist_object_data_t **l)
|
||||
{
|
||||
client_label_array_wipe(&(*l)->client_labels);
|
||||
p_delete(l);
|
||||
}
|
||||
|
||||
DO_SLIST(tasklist_object_data_t, tasklist_object_data, tasklist_object_data_delete)
|
||||
|
||||
/** The tasklist private data structure. */
|
||||
typedef struct
|
||||
{
|
||||
bool show_icons;
|
||||
luaA_ref label;
|
||||
tasklist_object_data_t *objects_data;
|
||||
bool invert;
|
||||
} tasklist_data_t;
|
||||
|
||||
/** Get an object data by its object.
|
||||
* \param od The object data list.
|
||||
* \param p The object.
|
||||
* \return A object data or NULL if not found.
|
||||
*/
|
||||
static tasklist_object_data_t *
|
||||
tasklist_object_data_getbyobj(tasklist_object_data_t *od, wibox_t *p)
|
||||
{
|
||||
tasklist_object_data_t *o;
|
||||
|
||||
for(o = od; o; o = o->next)
|
||||
if(o->object == p)
|
||||
return o;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Draw an item in a tasklist widget.
|
||||
* \param ctx The draw context, must be the same used to draw the tasklist
|
||||
* \param w Tasklist widget node
|
||||
* \param odata Tasklist object data
|
||||
* \param width_mod Width modification of the item
|
||||
* \param pos Position to draw the item at
|
||||
* \param i Item to draw
|
||||
*/
|
||||
static void
|
||||
tasklist_draw_item(draw_context_t *ctx,
|
||||
widget_node_t *w,
|
||||
tasklist_object_data_t *odata,
|
||||
int width_mod, int pos, int i) {
|
||||
draw_parser_data_t pdata, *parser_data;
|
||||
image_t *image;
|
||||
area_t area;
|
||||
tasklist_data_t *d = w->widget->data;
|
||||
int icon_width = 0;
|
||||
|
||||
if(d->show_icons)
|
||||
{
|
||||
draw_parser_data_init(&pdata);
|
||||
|
||||
/* Actually look for the proper background color, since
|
||||
* otherwise the background wibox color is used instead */
|
||||
if(draw_text_markup_expand(&pdata,
|
||||
odata->client_labels.tab[i].label,
|
||||
odata->client_labels.tab[i].label_len))
|
||||
{
|
||||
parser_data = &pdata;
|
||||
if(pdata.has_bg_color)
|
||||
{
|
||||
/* draw a background for icons */
|
||||
area.x = w->area.x + pos;
|
||||
area.y = w->area.y;
|
||||
area.height = ctx->height;
|
||||
area.width = odata->box_width;
|
||||
draw_rectangle(ctx, area, 1.0, true, &pdata.bg_color);
|
||||
}
|
||||
}
|
||||
else
|
||||
parser_data = NULL;
|
||||
|
||||
if(odata->client_labels.tab[i].client->icon)
|
||||
{
|
||||
image = odata->client_labels.tab[i].client->icon;
|
||||
icon_width = ((double) ctx->height / (double) image->height) * image->width;
|
||||
draw_image(ctx, w->area.x + odata->box_width * i,
|
||||
w->area.y, ctx->height, image);
|
||||
}
|
||||
}
|
||||
else
|
||||
parser_data = NULL;
|
||||
|
||||
area.x = w->area.x + icon_width + pos;
|
||||
area.y = w->area.y;
|
||||
area.width = odata->box_width - icon_width + width_mod;
|
||||
area.height = ctx->height;
|
||||
|
||||
draw_text(ctx, globalconf.font, area,
|
||||
odata->client_labels.tab[i].label,
|
||||
odata->client_labels.tab[i].label_len,
|
||||
parser_data);
|
||||
draw_parser_data_wipe(parser_data);
|
||||
}
|
||||
|
||||
/** Draw a tasklist widget.
|
||||
* \param ctx The draw context.
|
||||
* \param screen The screen number.
|
||||
* \param w The widget node we are called from.
|
||||
* \param offset The offset to draw at.
|
||||
* \param used The already used width.
|
||||
* \param p A pointer to the object we're drawing onto.
|
||||
* \return The widget width.
|
||||
*/
|
||||
static int
|
||||
tasklist_draw(draw_context_t *ctx, int screen,
|
||||
widget_node_t *w,
|
||||
int offset, int used, wibox_t *p)
|
||||
{
|
||||
client_t *c;
|
||||
tasklist_data_t *d = w->widget->data;
|
||||
int i = 0, box_width_rest = 0, pos = 0;
|
||||
tasklist_object_data_t *odata;
|
||||
|
||||
if(used >= ctx->width)
|
||||
return (w->area.width = 0);
|
||||
|
||||
if(!(odata = tasklist_object_data_getbyobj(d->objects_data, p)))
|
||||
{
|
||||
odata = p_new(tasklist_object_data_t, 1);
|
||||
odata->object = p;
|
||||
tasklist_object_data_list_push(&d->objects_data, odata);
|
||||
}
|
||||
|
||||
client_label_array_wipe(&odata->client_labels);
|
||||
client_label_array_init(&odata->client_labels);
|
||||
|
||||
for(c = globalconf.clients; c; c = c->next)
|
||||
if(!c->skiptb
|
||||
&& !c->ishidden
|
||||
&& c->type != WINDOW_TYPE_SPLASH
|
||||
&& c->type != WINDOW_TYPE_DOCK
|
||||
&& c->type != WINDOW_TYPE_DESKTOP)
|
||||
{
|
||||
/* push client */
|
||||
luaA_client_userdata_new(globalconf.L, c);
|
||||
/* push screen we're at */
|
||||
lua_pushnumber(globalconf.L, screen + 1);
|
||||
/* call label function with client as argument and wait for one
|
||||
* result */
|
||||
if(luaA_dofunction(globalconf.L, d->label, 2, 1))
|
||||
{
|
||||
/* If we got a string as returned value, we got something to write:
|
||||
* a label. So we store it in a client_label_t structure, pushed
|
||||
* into the client_label_array_t which is owned by the object. */
|
||||
if(lua_isstring(globalconf.L, -1))
|
||||
{
|
||||
client_label_t cl;
|
||||
cl.client = c;
|
||||
cl.label = a_strdup(lua_tolstring(globalconf.L, -1, &cl.label_len));
|
||||
client_label_array_append(&odata->client_labels, cl);
|
||||
}
|
||||
|
||||
lua_pop(globalconf.L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(!odata->client_labels.len)
|
||||
return (w->area.width = 0);
|
||||
|
||||
odata->box_width = (ctx->width - used) / odata->client_labels.len;
|
||||
/* compute how many pixel we left empty */
|
||||
box_width_rest = (ctx->width - used) % odata->client_labels.len;
|
||||
|
||||
w->area.x = widget_calculate_offset(ctx->width,
|
||||
0, offset, w->widget->align);
|
||||
|
||||
w->area.y = 0;
|
||||
|
||||
if(d->invert)
|
||||
for(i = odata->client_labels.len - 1; i >= 0; i--)
|
||||
{
|
||||
/* if we're on last elem, it has the last pixels left. */
|
||||
if (i == 0)
|
||||
tasklist_draw_item(ctx, w, odata, 0, pos, i);
|
||||
else
|
||||
tasklist_draw_item(ctx, w, odata, box_width_rest, pos, i);
|
||||
pos += odata->box_width;
|
||||
}
|
||||
else
|
||||
for(i = 0; i < odata->client_labels.len; i++)
|
||||
{
|
||||
/* if we're on last elem, it has the last pixels left. */
|
||||
if(i != odata->client_labels.len - 1)
|
||||
tasklist_draw_item(ctx, w, odata, 0, pos , i);
|
||||
else
|
||||
tasklist_draw_item(ctx, w, odata, box_width_rest, pos, i);
|
||||
pos += odata->box_width;
|
||||
}
|
||||
|
||||
w->area.width = ctx->width - used;
|
||||
w->area.height = ctx->height;
|
||||
|
||||
return w->area.width;
|
||||
}
|
||||
|
||||
/** Handle button click on tasklist.
|
||||
* \param w The widget node.
|
||||
* \param ev The button press event.
|
||||
* \param screen The screen where the click was.
|
||||
* \param object The object we're onto.
|
||||
*/
|
||||
static void
|
||||
tasklist_button(widget_node_t *w,
|
||||
xcb_button_press_event_t *ev,
|
||||
int screen,
|
||||
wibox_t *object)
|
||||
{
|
||||
tasklist_data_t *d = w->widget->data;
|
||||
int ci = 0;
|
||||
tasklist_object_data_t *odata;
|
||||
button_array_t *barr = &w->widget->buttons;
|
||||
|
||||
odata = tasklist_object_data_getbyobj(d->objects_data, object);
|
||||
|
||||
if(!odata || !odata->client_labels.len)
|
||||
return;
|
||||
|
||||
if (!d->invert)
|
||||
ci = (ev->event_x - w->area.x) / odata->box_width;
|
||||
else
|
||||
ci = odata->client_labels.len - 1 - (ev->event_x - w->area.x) / odata->box_width;
|
||||
|
||||
for(int i = 0; i < barr->len; i++)
|
||||
if(ev->detail == barr->tab[i]->button
|
||||
&& XUTIL_MASK_CLEAN(ev->state) == barr->tab[i]->mod)
|
||||
{
|
||||
luaA_wibox_userdata_new(globalconf.L, object);
|
||||
luaA_client_userdata_new(globalconf.L, odata->client_labels.tab[ci].client);
|
||||
luaA_dofunction(globalconf.L,
|
||||
ev->response_type == XCB_BUTTON_PRESS ?
|
||||
barr->tab[i]->press : barr->tab[i]->release,
|
||||
2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Tasklist widget.
|
||||
* \param L The Lua VM state.
|
||||
* \param token The key token.
|
||||
* \return The number of elements pushed on stack.
|
||||
* \luastack
|
||||
* \lfield show_icons Show icons near client title.
|
||||
* \lfield label Function used to get the string to display as the window title.
|
||||
* It gets the client and a screen number as argument, and must return a string.
|
||||
*/
|
||||
static int
|
||||
luaA_tasklist_index(lua_State *L, awesome_token_t token)
|
||||
{
|
||||
widget_t **widget = luaA_checkudata(L, 1, "widget");
|
||||
tasklist_data_t *d = (*widget)->data;
|
||||
|
||||
switch(token)
|
||||
{
|
||||
case A_TK_SHOW_ICONS:
|
||||
lua_pushboolean(L, d->show_icons);
|
||||
return 1;
|
||||
case A_TK_LABEL:
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, d->label);
|
||||
return 1;
|
||||
case A_TK_INVERT:
|
||||
lua_pushboolean(L, d->invert);
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Newindex function for tasklist widget.
|
||||
* \param L The Lua VM state.
|
||||
* \param token The key token.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_tasklist_newindex(lua_State *L, awesome_token_t token)
|
||||
{
|
||||
widget_t **widget = luaA_checkudata(L, 1, "widget");
|
||||
tasklist_data_t *d = (*widget)->data;
|
||||
|
||||
switch(token)
|
||||
{
|
||||
case A_TK_SHOW_ICONS:
|
||||
d->show_icons = luaA_checkboolean(L, 3);
|
||||
break;
|
||||
case A_TK_LABEL:
|
||||
luaA_registerfct(L, 3, &d->label);
|
||||
break;
|
||||
case A_TK_INVERT:
|
||||
d->invert = luaA_checkboolean(L, 3);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
widget_invalidate_bywidget(*widget);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Destructor for the tasklist widget.
|
||||
* \param widget The widget to destroy.
|
||||
*/
|
||||
static void
|
||||
tasklist_destructor(widget_t *widget)
|
||||
{
|
||||
tasklist_data_t *d = widget->data;
|
||||
tasklist_object_data_list_wipe(&d->objects_data);
|
||||
p_delete(&d);
|
||||
}
|
||||
|
||||
/** Tasklist detach function.
|
||||
* \param widget The widget which is detaching.
|
||||
* \param object The object we are leaving.
|
||||
*/
|
||||
static void
|
||||
tasklist_detach(widget_t *widget, wibox_t *object)
|
||||
{
|
||||
tasklist_data_t *d = widget->data;
|
||||
tasklist_object_data_t *od;
|
||||
|
||||
if((od = tasklist_object_data_getbyobj(d->objects_data, object)))
|
||||
{
|
||||
tasklist_object_data_list_detach(&d->objects_data, od);
|
||||
tasklist_object_data_delete(&od);
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a new widget tasklist.
|
||||
* \param align The widget alignment, which is flex anyway.
|
||||
* \return A brand new tasklist widget.
|
||||
*/
|
||||
widget_t *
|
||||
tasklist_new(alignment_t align __attribute__ ((unused)))
|
||||
{
|
||||
widget_t *w;
|
||||
tasklist_data_t *d;
|
||||
|
||||
w = p_new(widget_t, 1);
|
||||
widget_common_new(w);
|
||||
w->draw = tasklist_draw;
|
||||
w->button = tasklist_button;
|
||||
w->align = AlignFlex;
|
||||
w->index = luaA_tasklist_index;
|
||||
w->newindex = luaA_tasklist_newindex;
|
||||
w->data = d = p_new(tasklist_data_t, 1);
|
||||
w->destructor = tasklist_destructor;
|
||||
w->detach = tasklist_detach;
|
||||
|
||||
d->show_icons = true;
|
||||
d->label = LUA_REFNIL;
|
||||
d->invert = false;
|
||||
|
||||
/* Set cache property */
|
||||
w->cache_flags = WIDGET_CACHE_CLIENTS | WIDGET_CACHE_TAGS;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
Loading…
Reference in New Issue