From a0fa9a4e351dfb2fa6e5b10f36f77076a83113d2 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 27 Nov 2016 05:06:42 -0500 Subject: [PATCH] Comply with the new official client creation sequence Tyrannical now use awful.rules for more callbacks. It can be better integrated, but that's enough for this commit. This commit also drop the legacy and request sub-module, as the legacy was dead code anyway amd requests are now mandatory. --- extra/legacy.lua | 61 ------------------ extra/request.lua | 40 ------------ init.lua | 155 +++++++++++++++++++++++++++++----------------- shortcut.lua | 12 ++-- 4 files changed, 105 insertions(+), 163 deletions(-) delete mode 100644 extra/legacy.lua delete mode 100644 extra/request.lua diff --git a/extra/legacy.lua b/extra/legacy.lua deleted file mode 100644 index 2c71899..0000000 --- a/extra/legacy.lua +++ /dev/null @@ -1,61 +0,0 @@ --- This file is used to store former Tyrannical features now part --- of upstream. They are kept to support the older versions -local capi = {client = client , tag = tag , awesome = awesome, - screen = screen , mouse = mouse } -local awful = require("awful") - --- Check is Awesome is 3.5.3+ -if capi.awesome.startup == nil then - -- Monkey patch a bug fixed in 3.5.3 - awful.tag.setscreen = function(tag,screen) - if not tag or type(tag) ~= "tag" then return end - awful.tag._setscreen(tag,screen) - for k,c in ipairs(tag:clients()) do - c.screen = screen or 1 --Move all clients - c:tags({tag}) --Prevent some very strange side effects, does create some issue with multitag clients - end - awful.tag.history.restore(tag.screen,1) - end -else - -- Restore the old behavior in newer Awesome - require("tyrannical.extra.request") -end - -awful.tag.swap = function(tag1,tag2) - local idx1,idx2,scr2 = awful.tag.getidx(tag1),awful.tag.getidx(tag2),awful.tag.getscreen(tag2) - awful.tag.setscreen(tag2,awful.tag.getscreen(tag1)) - awful.tag.move(idx1,tag2) - awful.tag.setscreen(tag1,scr2) - awful.tag.move(idx2,tag1) -end - --- Check if adding support for sn-based spawn is necessary -if not awful.spawn then - awful.spawn = {snid_buffer={}} - function awful.util.spawn(cmd,sn_rules,callback) - if cmd and cmd ~= "" then - local enable_sn = (sn_rules ~= false or callback) and true or true - if not sn_rules and callback then - sn_rules = {callback=callback} - elseif callback then - sn_rules.callback = callback - end - local pid,snid = capi.awesome.spawn(cmd, enable_sn) - -- The snid will be nil in case of failure - if snid and type(sn_rules) == "table" then - awful.spawn.snid_buffer[snid] = sn_rules - end - return pid,snid - end - -- For consistency - return "Error: No command to execute" - end - local function on_canceled(sn) - awful.spawn.snid_buffer[sn] = nil - end - capi.awesome.connect_signal("spawn::canceled" , on_canceled ) - capi.awesome.connect_signal("spawn::timeout" , on_canceled ) -else - -- Then if it's there, disable the part we don't want - capi.client.disconnect_signal("manage",awful.spawn.on_snid_callback) -end \ No newline at end of file diff --git a/extra/request.lua b/extra/request.lua deleted file mode 100644 index dba7165..0000000 --- a/extra/request.lua +++ /dev/null @@ -1,40 +0,0 @@ -local capi = {client=client,awesome=awesome} -local ewmh = require("awful.ewmh") -local tyrannical = nil - --- Use Tyrannical policies instead of the default ones -capi.client.disconnect_signal("request::activate",ewmh.activate) -capi.client.connect_signal("request::activate",function(c,reason) - if not tyrannical then - tyrannical = require("tyrannical") - end - -- Always grant those request as it probably mean that it is a modal dialog - if c.transient_for and capi.client.focus == c.transient_for then - capi.client.focus = c - c:raise() - -- If it is not modal, then use the normal code path - elseif reason == "rule" or reason == "ewmh" then - tyrannical.focus_client(c) - -- Tyrannical doesn't have enough information, grant the request - else - capi.client.focus = c - c:raise() - end -end) - - -capi.client.disconnect_signal("request::tag", ewmh.tag) -capi.client.connect_signal("request::tag", function(c) --- if capi.awesome.startup then --- --TODO create a tag on that screen --- else --- --TODO block invalid requests, let Tyrannical do its job --- local tags = c:tags() --- if #tags == 0 then --- --TODO cannot happen --- end --- end -end) - - ---lib/awful/tag.lua.in:capi.tag.connect_signal("request::select", tag.viewonly) \ No newline at end of file diff --git a/init.lua b/init.lua index 4dd8472..d18e0cb 100755 --- a/init.lua +++ b/init.lua @@ -1,9 +1,8 @@ local setmetatable = setmetatable local print , pairs = print , pairs local ipairs , type = ipairs , type -local string , unpack= string , unpack +local string , unpack= string , unpack or table.unpack local awful = require("awful") -require("tyrannical.extra.legacy") local capi,sn_callback = {client = client, tag = tag, awesome = awesome, screen = screen, mouse = mouse},awful.spawn and awful.spawn.snid_buffer or {} @@ -81,13 +80,15 @@ local function load_property(name,property) end end ---Check all focus policies then change focus (Awesome 3.5.3+) function module.focus_client(c,properties) - local properties = properties or (c_rules.instance[string.lower(c.instance or "N/A")] or {}).properties or (c_rules.class[string.lower(get_class(c))] or {}).properties or {} - if (((not c.transient_for) or (c.transient_for==capi.client.focus) or (not settings.block_children_focus_stealing)) and (not properties.no_autofocus)) then - if not awful.util.table.hasitem(c:tags(), (c.screen or capi.screen[1]).selected_tag) and (not prop(c:tags()[1],"no_focus_stealing_in")) then + + if (((not c.transient_for) or (c.transient_for==capi.client.focus) or (not settings.block_children_focus_stealing)) and (not c.no_autofocus)) then + local tags = c:tags() + + if #tags > 0 and not c:isvisible() and not tags[1].no_focus_stealing_in then c:tags()[1]:view_only() end + capi.client.focus = c c:raise() return true @@ -95,34 +96,32 @@ function module.focus_client(c,properties) end --Apply all properties -local function apply_properties(c,override,normal) - if not override and not normal then return nil,{} end - local props,ret = awful.util.table.join(settings.client,normal or {},override, - override.callback and override.callback(c) or (normal and normal.callback and normal.callback(c)) or {}),nil - --Set all 'c.something' properties, --TODO maybe eventually move to awful.rules.execute - for k,_ in pairs(props) do - c[k] = props[k] - end - --Center client - if props.centered == true then - awful.placement.centered(c, nil) +local function apply_properties(c, props, callbacks) + + local force_intrusive = settings.force_odd_as_intrusive + and c.type ~= "normal" + + local is_intrusive = force_intrusive + or type(props.intrusive) == "function" and props.intrusive(c) + or props.intrusive + + --Check if the client should be added to an existing tag (or tags) + if (not props.new_tag) and is_intrusive then + local tag = c.screen.selected_tag + or c.screen.tags[1]:view_only() + or c.screen.selected_tag + + if tag then --Can be false if there is no tags + props.tag, props.tags = tag, nil + end end + + awful.rules.execute(c, props, callbacks) + --Set slave or master if props.slave == true or props.master == true then awful.client["set"..(props.slave and "slave" or "master")](c, true) end - --Check if the client should be added to an existing tag (or tags) - if props.new_tag then - ret = c:tags({awful.tag.add(type(props.new_tag)=="table" and props.new_tag.name or c.class,type(props.new_tag)=="table" and props.new_tag or {screen=c.screen or 1})}) - elseif props.tag then - ret = c:tags(type(props.tag) == "function" and props.tag(c) or (type(props.tag) == "table" and props.tag or { props.tag })) - elseif props.intrusive == true or (settings.force_odd_as_intrusive and c.type ~= "normal") then - local tag = c.screen.selected_tag or c.screen.tags[1]:view_only() or c.screen.selected_tag - if tag then --Can be false if there is no tags - ret = c:tags({tag}) - end - end - return ret,props end local function select_screen(tag) @@ -152,16 +151,17 @@ local function select_screen(tag) end --Match client -local function match_client(c, startup) - if not c then return end - local startup = startup == nil and capi.awesome.startup or startup +local function match_client(c, forced_tags, hints) + if (not c) or #c:tags() > 0 then return end + local props = c.startup_id and sn_callback[tostring(c.startup_id)] or {} local low_i = string.lower(c.instance or "N/A") local low_c = string.lower(get_class(c)) local tags = props.tags or {props.tag} + local rules = c_rules.instance[low_i] or c_rules.class[low_c] - local forced_tags,props = apply_properties(c,props,rules and rules.properties) + if #tags == 0 and c.transient_for and (capi.mouse.screen or (rules and rules.properties.intrusive_popup)) then c.sticky = c.transient_for.sticky or false c:tags(awful.util.table.join(c.transient_for:tags(),(rules and rules.properties.intrusive_popup) and c.screen.selected_tags)) @@ -222,6 +222,7 @@ local function match_client(c, startup) return module.focus_client(c,props) end +capi.client.disconnect_signal("request::tag", awful.ewmh.tag) capi.client.connect_signal("request::tag", match_client) capi.client.connect_signal("untagged", function (c, t) @@ -235,23 +236,7 @@ capi.client.connect_signal("untagged", function (c, t) end end) -awful.tag.withcurrent,awful.tag._add = function(c, startup) - local tags,old_tags = {},c:tags() - --Safety to prevent - for k, t in ipairs(old_tags) do - tags[#tags+1] = (t.screen == c.screen) and t or nil - end - --Necessary when dragging clients - if startup == nil and old_tags[1] and old_tags[1].screen ~= c.screen then --nil != false - local sellist = c.screen.selected_tags - if #sellist > 0 then --Use already selected tag - tags = sellist - else --Select a tag - match_client(c, startup) - end - end - c:tags(tags) -end,awful.tag.add +awful.tag._add = awful.tag.add awful.tag.add = function(tag,props,override) props.screen,props.instances = props.screen or capi.mouse.screen,props.instances or setmetatable({}, { __mode = 'v' }) @@ -265,11 +250,9 @@ awful.tag.add = function(tag,props,override) end capi.tag.connect_signal("property::fallback",function(t) - fallbacks[awful.util.table.hasitem(fallbacks, t) or (#fallbacks+1)] = prop(t,"fallback") and t or nil + fallbacks[awful.util.table.hasitem(fallbacks, t) or (#fallbacks+1)] = t.fallback and t or nil end) -local is_init = setmetatable({}, { __mode = 'k' }) - local function contain_screen(tab, s) for _, v in ipairs(tab) do if type(v) ~= "number" or v <= capi.screen.count() then @@ -284,9 +267,7 @@ local function contain_screen(tab, s) end -- Add init tags to newly connected screens -awful.screen.connect_for_each_screen(function(s) --TODO remove the load code and use this - if is_init[s] then return end - +awful.screen.connect_for_each_screen(function(s) for _, def in pairs(tags_hash) do if def.init then if def.screen and (type(def.screen) == "table" and contain_screen(def.screen, s)) @@ -345,6 +326,68 @@ capi.tag.connect_signal("request::screen", function(t) end end) +capi.client.disconnect_signal("manage", awful.rules.apply) +capi.client.disconnect_signal("spawn::completed_with_payload", awful.rules.completed_with_payload_callback) +capi.client.disconnect_signal("manage",awful.spawn.on_snid_callback) + +--- Replace the default handler to take into account Tyrannical properties +function awful.rules.apply(c) + local low_i = string.lower(c.instance or "N/A") + local low_c = string.lower(get_class(c)) + + local callbacks, props = {}, {} + + local props_src = (c_rules.instance[low_i] + or c_rules.class[low_c] or {}).properties + or {} + + -- Add Tyrannical properties + awful.util.table.crush(props,props_src) + + -- Add the rules properties + for _, entry in ipairs(awful.rules.matching_rules(c, awful.rules.rules)) do + awful.util.table.crush(props,entry.properties or {}) + + if entry.callback then + table.insert(callbacks, entry.callback) + end + end + + -- Add startup_id overridden properties + if c.startup_id and awful.spawn.snid_buffer[c.startup_id] then + local snprops, sncb = unpack(awful.spawn.snid_buffer[c.startup_id]) + + -- The SNID tag(s) always have precedence over the rules one(s) + if snprops.tag or snprops.tags or snprops.new_tag then + props.tag, props.tags, props.new_tag, props.intrusive = nil, nil, nil, nil + end + + awful.util.table.crush(props,snprops) + awful.util.table.merge(callbacks, sncb) + end + + apply_properties(c,props, callbacks) +end + +capi.client.connect_signal("manage", awful.rules.apply) + +capi.client.disconnect_signal("request::activate",awful.ewmh.activate) +capi.client.connect_signal("request::activate",function(c,reason) + -- Always grant those request as it probably mean that it is a modal dialog + if c.transient_for and capi.client.focus == c.transient_for then + capi.client.focus = c + c:raise() + -- If it is not modal, then use the normal code path + elseif reason == "rule" or reason == "rules" or reason == "ewmh" then + module.focus_client(c) + -- Tyrannical doesn't have enough information, grant the request + else + capi.client.focus = c + c:raise() + end +end) + + --------------------------OBJECT GEARS--------------------------- local getter = {properties = setmetatable({}, {__newindex = function(table,k,v) load_property(k,v) end}), settings = settings, tags_by_name = tags_hash, sn_callback = sn_callback} diff --git a/shortcut.lua b/shortcut.lua index c120e2d..c5c0b26 100644 --- a/shortcut.lua +++ b/shortcut.lua @@ -12,9 +12,9 @@ local glib = require( "lgi" ).GLib local function get_current_screen() if capi.client.focus and capi.client.focus.screen == capi.mouse.screen then - return capi.mouse.screen - elseif (not aw_tag.selected(capi.mouse.screen)) or (#aw_tag.selected(capi.mouse.screen):clients() == 0) or (not capi.client.focus) then - return capi.mouse.screen + return capi.mouse.screen + elseif (capi.mouse.screen.selected_tag and #capi.mouse.screen.selected_tag:clients() == 0) or (not capi.client.focus) then + return capi.mouse.screen end return capi.client.focus.screen end @@ -70,11 +70,11 @@ local function rename_tag() end local function term_in_current_tag() - aw_spawn(terminal,{intrusive=true,slave=true}) + aw_spawn(terminal,{intrusive=true,slave=true,screen=get_current_screen()}) end local function new_tag_with_term() - aw_spawn(terminal,{new_tag={volatile = true}}) + aw_spawn(terminal,{new_tag={volatile = true,screen=get_current_screen()}}) end local function fork_tag() @@ -84,7 +84,7 @@ local function fork_tag() local clients = t:clients() local t2 = aw_tag.add(t.name,aw_tag.getdata(t)) t2:clients(clients) - aw_tag.viewonly(t2) + t2:view_only() end local function aero_tag()