diff --git a/lib/awful/tag.lua b/lib/awful/tag.lua index 17b162e8c..2e3c3f1b7 100644 --- a/lib/awful/tag.lua +++ b/lib/awful/tag.lua @@ -349,6 +349,45 @@ function tag.find_fallback(screen, invalids) end end +--- When all clients are removed from the tag. +-- @signal cleared +-- @see clear + +--- Remove all tagged clients. +-- +-- @DOC_sequences_tag_clear_EXAMPLE@ +-- +-- @method clear +-- @tparam table args The arguments. +-- @tparam tag args.fallback_tag A fallback tag. +-- @tparam[opt=false] boolean args.allow_untagged Allow the untagged clients to remain untagged. +-- @emits cleared After all clients have been untagged. +-- @emits untagged For each currently tagged clients. +-- @emitstparam untagged client c The untagged client. +function tag.object.clear(self, args) + args = args or {} + + local clients = self:clients() + + -- Clear + self:clients({}) + + if #clients > 0 and not args.allow_untagged then + local target_scr = get_screen(tag.getproperty(self, "screen")) + local fallback_tag = args.fallback_tag or tag.find_fallback(target_scr, {self}) + + if not fallback_tag then return end + + for _, c in ipairs(clients) do + if #c:tags() == 0 then + c:tags({fallback_tag}) + end + end + end + + self:emit_signal("cleared") +end + --- Delete a tag. -- -- To delete the current tag: diff --git a/objects/tag.c b/objects/tag.c index 1b1a13576..f41ce6545 100644 --- a/objects/tag.c +++ b/objects/tag.c @@ -473,8 +473,10 @@ luaA_tag_clients(lua_State *L) if(lua_gettop(L) == 2) { luaA_checktable(L, 2); - foreach(c, tag->clients) + for(int j = 0; j < clients->len; j++) { + client_t *c = clients->tab[j]; + /* Only untag if we aren't going to add this tag again */ bool found = false; lua_pushnil(L); @@ -483,7 +485,7 @@ luaA_tag_clients(lua_State *L) client_t *tc = luaA_checkudata(L, -1, &client_class); /* Pop the value from lua_next */ lua_pop(L, 1); - if (tc != *c) + if (tc != c) continue; /* Pop the key from lua_next */ @@ -491,8 +493,10 @@ luaA_tag_clients(lua_State *L) found = true; break; } - if(!found) - untag_client(*c, tag); + if(!found) { + untag_client(c, tag); + j--; + } } lua_pushnil(L); while(lua_next(L, 2)) diff --git a/tests/examples/sequences/tag/clear.lua b/tests/examples/sequences/tag/clear.lua new file mode 100644 index 000000000..586f5da6b --- /dev/null +++ b/tests/examples/sequences/tag/clear.lua @@ -0,0 +1,50 @@ + --DOC_GEN_IMAGE --DOC --DOC_NO_USAGE +local module = ... --DOC_HIDE +local awful = {tag = require("awful.tag"), --DOC_HIDE + layout = require("awful.layout"), --DOC_HIDE +} --DOC_HIDE +screen[1]._resize {x = 0, width = 128, height = 96} --DOC_HIDE + +function awful.spawn(_, args) --DOC_HIDE + local c = client.gen_fake{} --DOC_HIDE + c:tags({args.tag}) --DOC_HIDE + assert(#c:tags() == 1) --DOC_HIDE + assert(c:tags()[1] == args.tag) --DOC_HIDE +end --DOC_HIDE + +assert(awful.layout.layouts[1]) --DOC_HIDE +local some_layouts = {--DOC_HIDE + awful.layout.suit.fair,--DOC_HIDE + awful.layout.suit.fair,--DOC_HIDE +} --DOC_HIDE + + -- Calling awful.tag.new + awful.tag({ "one", "two" }, screen[1], some_layouts) + +assert(#screen[1].tags == 2) --DOC_HIDE +for k, t in ipairs(screen[1].tags) do --DOC_HIDE + assert(t.layout and t.layout == some_layouts[k]) --DOC_HIDE + assert(#t:clients() == 0) --DOC_HIDE +end --DOC_HIDE + +--DOC_NEWLINE + +module.add_event("Calling awful.tag.new and add some clients", function() --DOC_HIDE + for _, t in ipairs(screen[1].tags) do--DOC_HIDE + for _ = 1, 3 do --DOC_HIDE + awful.spawn("xterm", {tag = t})--DOC_HIDE + end --DOC_HIDE + assert(#t:clients() == 3) --DOC_HIDE + end --DOC_HIDE +end) --DOC_HIDE + +module.display_tags() --DOC_HIDE + +module.add_event("Call `:clear()` on the first tag.", function() --DOC_HIDE + -- Call :clear() on the first tag. + screen[1].tags[1]:clear{} +end) + +module.display_tags() --DOC_HIDE + +module.execute {show_empty = true} --DOC_HIDE diff --git a/tests/examples/shims/client.lua b/tests/examples/shims/client.lua index f554b76bd..6ed7a1c41 100644 --- a/tests/examples/shims/client.lua +++ b/tests/examples/shims/client.lua @@ -170,6 +170,7 @@ function client.gen_fake(args) for _, t in ipairs(old_tags) do ret:emit_signal("untagged", t) + t:emit_signal("untagged", ret) t:emit_signal("property::tags") end diff --git a/tests/examples/shims/tag.lua b/tests/examples/shims/tag.lua index d9c092730..29cbcf902 100644 --- a/tests/examples/shims/tag.lua +++ b/tests/examples/shims/tag.lua @@ -1,4 +1,5 @@ local gears_obj = require("gears.object") +local gtable = require("gears.table") local tag, meta = awesome._shim_fake_class() @@ -11,6 +12,22 @@ local function has_selected_tag(s) return false end +local function get_clients(self) + local list = {} + + for _, c in ipairs(client.get()) do + if #c:tags() > 0 then + for _, t in ipairs(c:tags()) do + if t == self then + table.insert(list, c) + end + end + end + end + + return list +end + local function new_tag(_, args) local ret = gears_obj() awesome._forward_class(ret, tag) @@ -23,18 +40,40 @@ local function new_tag(_, args) -- Deprecated. ret.data = ret._private - function ret:clients(_) --TODO handle new - local list = {} - for _, c in ipairs(client.get()) do - if #c:tags() > 0 then - for _, t in ipairs(c:tags()) do - if t == ret then - table.insert(list, c) + function ret:clients(new_clients) + local old_clients = get_clients(ret) + + -- Remove the old clients. + if new_clients then + for _, c in ipairs(client.get()) do + local had_client = gtable.hasitem(old_clients, c) + local has_client = gtable.hasitem(new_clients, c) + if had_client and not has_client then + local ctags = gtable.clone(c:tags(), false) + + for k, t in ipairs(ctags) do + if t == self then + table.remove(ctags, k) + c:tags(ctags) + end end end end + + -- Add the new clients. + for _, c in ipairs(new_clients) do + + if new_clients and not gtable.hasitem(old_clients, c) then + local ctags = gtable.clone(c:tags(), false) + table.insert(ctags, self) + c:tags(ctags) + end + end end + -- Generate the client list. + local list = get_clients(ret) + return list end diff --git a/tests/test-awful-tag.lua b/tests/test-awful-tag.lua index 91ad2b443..6536c9042 100644 --- a/tests/test-awful-tag.lua +++ b/tests/test-awful-tag.lua @@ -355,6 +355,44 @@ table.insert(steps, function() return true end) +-- Check tag:clear() +table.insert(steps, function() + screen[1].tags[1]:view_only() + mouse.coords { + x = screen[1].geometry.x + 1, + y = screen[1].geometry.y + 1, + } + + awful.spawn("xterm") + awful.spawn("xterm") + + return true +end) + +table.insert(steps, function() + if #screen[1].tags[1]:clients() ~= 2 then return end + + local old_clients = screen[1].tags[1]:clients() + + local clear_called, untagged = false, 0 + + screen[1].tags[1]:connect_signal("cleared", function() clear_called = true end) + screen[1].tags[1]:connect_signal("untagged", function() + untagged = untagged + 1 + end) + + screen[1].tags[1]:clear{} + assert(#screen[1].tags[1]:clients() == 0) + assert(clear_called) + assert(untagged == 2) + + for _, c in ipairs(old_clients) do + assert(#c:tags() > 0) + end + + return true +end) + require("_runner").run_steps(steps) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80