Add support for spawing with Tyrannical arguments (Finally!!!)
It is now possible to spawn with an array of properties, see the README.md for more details. It require Awesome 3.5.3+, some patch will get into 3.5.6 to make this even better. I also added the 'new_tag' property to be used with spawn. * Also fix issue #37, sorry about that one...
This commit is contained in:
parent
c22a1e528c
commit
d97eff6ffa
61
README.md
61
README.md
|
@ -52,7 +52,7 @@ can also to other value by using the class name as table key:
|
||||||
Tyrannical focus model is very fine tuned. It is possible to add rules on how
|
Tyrannical focus model is very fine tuned. It is possible to add rules on how
|
||||||
the focus will be attributes to clients and tags.
|
the focus will be attributes to clients and tags.
|
||||||
|
|
||||||
**block_transient_for_focus_stealing:**
|
**block_children_focus_stealing:**
|
||||||
This is a fancy X11 name for something very common: modal dialogs and popups.
|
This is a fancy X11 name for something very common: modal dialogs and popups.
|
||||||
If this is set to `true`, then a dialog wont be able to steal the focus from
|
If this is set to `true`, then a dialog wont be able to steal the focus from
|
||||||
whatever your doing. This is useful for some misbehaving apps such as Firefox
|
whatever your doing. This is useful for some misbehaving apps such as Firefox
|
||||||
|
@ -277,7 +277,7 @@ Then edit this section to fit your needs.
|
||||||
|
|
||||||
| Property | Description | Type |
|
| Property | Description | Type |
|
||||||
| -------------------------------------- | --------------------------------------------------- |:----------------:|
|
| -------------------------------------- | --------------------------------------------------- |:----------------:|
|
||||||
| **block_transient_for_focus_stealing** | Prevent popups from stealing focus | boolean |
|
| **block_children_focus_stealing** | Prevent popups from stealing focus | boolean |
|
||||||
| **default_layout** | The default layout for tags | layout |
|
| **default_layout** | The default layout for tags | layout |
|
||||||
| **group_children** | Add dialogs to the same tags as their parent client | boolean |
|
| **group_children** | Add dialogs to the same tags as their parent client | boolean |
|
||||||
| **mwfact** | The default master/slave ratio | float (0-1) |
|
| **mwfact** | The default master/slave ratio | float (0-1) |
|
||||||
|
@ -320,6 +320,63 @@ name"].name,tyrannical.tags_by_name["your tag name"])```. Tyrannical's purpose
|
||||||
is not to duplicate or change ```awful.tag``` behavior, it is simply a
|
is not to duplicate or change ```awful.tag``` behavior, it is simply a
|
||||||
configuration wrapper.
|
configuration wrapper.
|
||||||
|
|
||||||
|
#### Is it possible to directly launch clients in the current tag or a new one?
|
||||||
|
|
||||||
|
This feature is mostly available for Awesome 3.5.3+, 3.5.6+ is recommanded.
|
||||||
|
Tyrannical will use the "startup notification" feild in clients that support it
|
||||||
|
to track a spawn request. Some applications, such as GVim and XTerm, doesn't
|
||||||
|
support this. URxvt, Konsole and Gnome terminal does.
|
||||||
|
|
||||||
|
Here are some example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- Spawn in a new tag
|
||||||
|
awful.util.spawn("urxvt",{new_tag=true})
|
||||||
|
|
||||||
|
-- Or for more advanced use case, you can use a full tag definition too
|
||||||
|
awful.util.spawn("urxvt",{ new_tag= {
|
||||||
|
name = "MyNewTag",
|
||||||
|
exclusive = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Spawn in the current tag, floating and on top
|
||||||
|
awful.util.spawn(terminal,{intrusive=true, floating=true, ontop=true})
|
||||||
|
```
|
||||||
|
|
||||||
|
For Awesome 3.5.6+, it is possible to replace the default mod4+r keybinding with
|
||||||
|
a more powerful one:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
awful.key({ modkey }, "r",
|
||||||
|
function ()
|
||||||
|
awful.prompt.run({ prompt = "Run: ", hooks = {
|
||||||
|
{{ },"Return",function(command)
|
||||||
|
local result = awful.util.spawn(command)
|
||||||
|
mypromptbox[mouse.screen].widget:set_text(type(result) == "string" and result or "")
|
||||||
|
return true
|
||||||
|
end},
|
||||||
|
{{"Mod1" },"Return",function(command)
|
||||||
|
local result = awful.util.spawn(command,{intrusive=true})
|
||||||
|
mypromptbox[mouse.screen].widget:set_text(type(result) == "string" and result or "")
|
||||||
|
return true
|
||||||
|
end},
|
||||||
|
{{"Shift" },"Return",function(command)
|
||||||
|
local result = awful.util.spawn(command,{intrusive=true,ontop=true,floating=true})
|
||||||
|
mypromptbox[mouse.screen].widget:set_text(type(result) == "string" and result or "")
|
||||||
|
return true
|
||||||
|
end}
|
||||||
|
}},
|
||||||
|
mypromptbox[mouse.screen].widget,nil,
|
||||||
|
awful.completion.shell,
|
||||||
|
awful.util.getdir("cache") .. "/history")
|
||||||
|
end),
|
||||||
|
```
|
||||||
|
|
||||||
|
When using this, instead of pressing `Return` to spawn the application, you can
|
||||||
|
use `Alt+Return` to launch it as an `intrusive` client. You can add more sections
|
||||||
|
to support more use case (such as `Shift+Return` to launch as `floating` as shown
|
||||||
|
above)
|
||||||
|
|
||||||
#### What is Tyrannical license?
|
#### What is Tyrannical license?
|
||||||
|
|
||||||
Tyrannical is licensed under the [2 clause BSD](http://opensource.org/licenses/BSD-2-Clause)
|
Tyrannical is licensed under the [2 clause BSD](http://opensource.org/licenses/BSD-2-Clause)
|
||||||
|
|
|
@ -27,4 +27,35 @@ awful.tag.swap = function(tag1,tag2)
|
||||||
awful.tag.move(idx1,tag2)
|
awful.tag.move(idx1,tag2)
|
||||||
awful.tag.setscreen(tag1,scr2)
|
awful.tag.setscreen(tag1,scr2)
|
||||||
awful.tag.move(idx2,tag1)
|
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
|
end
|
|
@ -4,17 +4,22 @@ local tyrannical = nil
|
||||||
|
|
||||||
-- Use Tyrannical policies instead of the default ones
|
-- Use Tyrannical policies instead of the default ones
|
||||||
capi.client.disconnect_signal("request::activate",ewmh.activate)
|
capi.client.disconnect_signal("request::activate",ewmh.activate)
|
||||||
capi.client.connect_signal("request::activate",function(c)
|
capi.client.connect_signal("request::activate",function(c,reason)
|
||||||
if not tyrannical then
|
if not tyrannical then
|
||||||
tyrannical = require("tyrannical")
|
tyrannical = require("tyrannical")
|
||||||
end
|
end
|
||||||
local sel_tags = nil --TODO check if the current tag prevent _out stealing
|
-- Always grant those request as it probably mean that it is a modal dialog
|
||||||
local tags = c:tags()
|
if c.transient_for and capi.client.focus == c.transient_for then
|
||||||
-- for k,t in ipairs(tags) do
|
capi.client.focus = c
|
||||||
--TODO check if one of them is selected
|
c:raise()
|
||||||
-- end
|
-- If it is not modal, then use the normal code path
|
||||||
capi.client.focus = c
|
elseif reason == "rule" or reason == "ewmh" then
|
||||||
c:raise()
|
tyrannical.focus_client(c)
|
||||||
|
-- Tyrannical doesn't have enough information, grant the request
|
||||||
|
else
|
||||||
|
capi.client.focus = c
|
||||||
|
c:raise()
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
|
22
init.lua
22
init.lua
|
@ -6,6 +6,8 @@ local awful = require("awful")
|
||||||
|
|
||||||
local capi = {client = client , tag = tag , awesome = awesome,
|
local capi = {client = client , tag = tag , awesome = awesome,
|
||||||
screen = screen , mouse = mouse }
|
screen = screen , mouse = mouse }
|
||||||
|
-- Patch Awesome < 3.5.3
|
||||||
|
require("tyrannical.extra.legacy")
|
||||||
|
|
||||||
-------------------------------INIT------------------------------
|
-------------------------------INIT------------------------------
|
||||||
|
|
||||||
|
@ -14,7 +16,7 @@ local signals,module,class_client,tags_hash,settings,sn_callback,fallbacks,prop
|
||||||
"locked" , "class" , "spawn" , "position" , "force_screen" ,
|
"locked" , "class" , "spawn" , "position" , "force_screen" ,
|
||||||
"max_clients" , "exec_once" , "clone_on" , "clone_of" , "no_focus_stealing",
|
"max_clients" , "exec_once" , "clone_on" , "clone_of" , "no_focus_stealing",
|
||||||
"fallback" , "no_focus_stealing_out","no_focus_stealing_in"
|
"fallback" , "no_focus_stealing_out","no_focus_stealing_in"
|
||||||
},{},{},{},{},{},{},awful.tag.getproperty
|
},{},{},{},{},awful.spawn and awful.spawn.snid_buffer or {},{},awful.tag.getproperty
|
||||||
|
|
||||||
for _,sig in ipairs(signals) do
|
for _,sig in ipairs(signals) do
|
||||||
capi.tag.add_signal("property::"..sig)
|
capi.tag.add_signal("property::"..sig)
|
||||||
|
@ -76,18 +78,19 @@ end
|
||||||
--Check all focus policies then change focus (Awesome 3.5.3+)
|
--Check all focus policies then change focus (Awesome 3.5.3+)
|
||||||
function module.focus_client(c,properties)
|
function module.focus_client(c,properties)
|
||||||
local properties = properties or (class_client[string.lower(c.class or "N/A")] or {}).properties or {}
|
local properties = properties or (class_client[string.lower(c.class or "N/A")] or {}).properties or {}
|
||||||
if (((not c.transient_for) or (not settings.block_transient_for_focus_stealing)) and (not properties.no_autofocus)) then
|
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(), awful.tag.selected(c.screen or 1)) and (not prop(tags[1],"no_focus_stealing_in")) then
|
if not awful.util.table.hasitem(c:tags(), awful.tag.selected(c.screen or 1)) and (not prop(c:tags()[1],"no_focus_stealing_in")) then
|
||||||
awful.tag.viewonly(c:tags()[1])
|
awful.tag.viewonly(c:tags()[1])
|
||||||
end
|
end
|
||||||
capi.client.focus = c
|
capi.client.focus = c
|
||||||
|
c:raise()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--Apply all properties
|
--Apply all properties
|
||||||
local function apply_properties(c,override,normal)
|
local function apply_properties(c,override,normal)
|
||||||
local props,ret = awful.util.table.join(normal,override),nil
|
local props,ret = awful.util.table.join(normal,override),nil
|
||||||
--Set all 'c.something' properties
|
--Set all 'c.something' properties, --TODO maybe eventually move to awful.rules.execute
|
||||||
for k,_ in pairs(props) do
|
for k,_ in pairs(props) do
|
||||||
if override[k] ~= nil then props[k] = override[k] else props[k] = normal[k] end
|
if override[k] ~= nil then props[k] = override[k] else props[k] = normal[k] end
|
||||||
c[k] = props[k]
|
c[k] = props[k]
|
||||||
|
@ -104,8 +107,10 @@ local function apply_properties(c,override,normal)
|
||||||
if props.slave == true or props.master == true then
|
if props.slave == true or props.master == true then
|
||||||
awful.client["set"..(props.slave and "slave" or "master")](c, true)
|
awful.client["set"..(props.slave and "slave" or "master")](c, true)
|
||||||
end
|
end
|
||||||
|
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 {})})
|
||||||
--Add to the current tag if the client is intrusive, ignore exclusive
|
--Add to the current tag if the client is intrusive, ignore exclusive
|
||||||
if props.intrusive == true or (settings.force_odd_as_intrusive and c.type ~= "normal") then
|
elseif props.intrusive == true or (settings.force_odd_as_intrusive and c.type ~= "normal") then
|
||||||
local tag = awful.tag.selected(c.screen) or awful.tag.viewonly(awful.tag.gettags(c.screen)[1]) or awful.tag.selected(c.screen)
|
local tag = awful.tag.selected(c.screen) or awful.tag.viewonly(awful.tag.gettags(c.screen)[1]) or awful.tag.selected(c.screen)
|
||||||
if tag then --Can be false if there is no tags
|
if tag then --Can be false if there is no tags
|
||||||
ret = c:tags({tag})
|
ret = c:tags({tag})
|
||||||
|
@ -118,7 +123,7 @@ end
|
||||||
local function match_client(c, startup)
|
local function match_client(c, startup)
|
||||||
if not c then return end
|
if not c then return end
|
||||||
local startup = startup == nil and capi.awesome.startup or startup
|
local startup = startup == nil and capi.awesome.startup or startup
|
||||||
local props = (c.startup_id and sn_callback[c.startup_id]) and sn_callback[c.startup_id](c,startup) or {}
|
local props = c.startup_id and sn_callback[tostring(c.startup_id)] or {}
|
||||||
|
|
||||||
local low,tags = string.lower(c.class or "N/A"),props.tags or {props.tag}
|
local low,tags = string.lower(c.class or "N/A"),props.tags or {props.tag}
|
||||||
local rules = class_client[low]
|
local rules = class_client[low]
|
||||||
|
@ -139,7 +144,7 @@ local function match_client(c, startup)
|
||||||
tag.screen = (tag.force_screen ~= true and c_src) or (has_screen and c_src or type(tag.screen)=="table" and tag.screen[1] or tag.screen)
|
tag.screen = (tag.force_screen ~= true and c_src) or (has_screen and c_src or type(tag.screen)=="table" and tag.screen[1] or tag.screen)
|
||||||
tag.screen,match = (tag.screen <= capi.screen.count()) and tag.screen or mouse_s,tag.instances[tag.screen]
|
tag.screen,match = (tag.screen <= capi.screen.count()) and tag.screen or mouse_s,tag.instances[tag.screen]
|
||||||
if (not match and not (fav_scr == true and mouse_s ~= tag.screen)) or (match and (prop(match,"max_clients") or 999) <= #match:clients()) then
|
if (not match and not (fav_scr == true and mouse_s ~= tag.screen)) or (match and (prop(match,"max_clients") or 999) <= #match:clients()) then
|
||||||
awful.tag.add(tag.name,tag)
|
awful.tag.setproperty(awful.tag.add(tag.name,tag),"volatile",match and (prop(match,"max_clients") ~= nil) or tag.volatile)
|
||||||
end
|
end
|
||||||
tags_src[tag.screen],fav_scr = tags_src[tag.screen] or {},fav_scr or (tag.screen == mouse_s) --Reset if a better screen is found
|
tags_src[tag.screen],fav_scr = tags_src[tag.screen] or {},fav_scr or (tag.screen == mouse_s) --Reset if a better screen is found
|
||||||
tags_src[tag.screen][#tags_src[tag.screen]+1] = tag.instances[tag.screen]
|
tags_src[tag.screen][#tags_src[tag.screen]+1] = tag.instances[tag.screen]
|
||||||
|
@ -221,9 +226,6 @@ awful.tag.add,awful.tag._setscreen,awful.tag._viewonly = function(tag,props)
|
||||||
return t
|
return t
|
||||||
end,awful.tag.setscreen,awful.tag.viewonly
|
end,awful.tag.setscreen,awful.tag.viewonly
|
||||||
|
|
||||||
-- Patch Awesome < 3.5.3
|
|
||||||
require("tyrannical.extra.legacy")
|
|
||||||
|
|
||||||
awful.tag.viewonly = function(t)
|
awful.tag.viewonly = function(t)
|
||||||
if not t then return end
|
if not t then return end
|
||||||
if not awful.tag.getscreen(t) then awful.tag.setscreen(capi.mouse.screen) end
|
if not awful.tag.getscreen(t) then awful.tag.setscreen(capi.mouse.screen) end
|
||||||
|
|
Loading…
Reference in New Issue