rules: Move `awful.rules` to `ruled.client`.
From now on, all core object will have their own rules. `awful.rules` hardcodes some client specific code. All `rules` module have some form of class specific code. This code will now be part of a new module called `ruled`. Since a year or so, a lot of work has been done to refactor the rules on top of the shared `gears.matcher` class. This way there wont be as much duplication.
This commit is contained in:
parent
39c90b8303
commit
71c230035c
|
@ -70,6 +70,9 @@ This document was last updated at commit v4.3-197-g9085ed631.
|
||||||
slightly. The border is now applied before the titlebar offset. This should
|
slightly. The border is now applied before the titlebar offset. This should
|
||||||
not affect most users unless you had mitigated the bug it fixes by adding
|
not affect most users unless you had mitigated the bug it fixes by adding
|
||||||
the titlebar offset in your rules.
|
the titlebar offset in your rules.
|
||||||
|
* Setting `awful.rules.rules` now append the rules to the existing set.
|
||||||
|
Clearing the rules was never officially supported. If you *really* want the
|
||||||
|
old behavior, use `awful.rules.rules = {}; awful.rules.rules = my_new_rules`.
|
||||||
|
|
||||||
<a name="v43"></a>
|
<a name="v43"></a>
|
||||||
# Awesome window manager framework version 4.3 changes
|
# Awesome window manager framework version 4.3 changes
|
||||||
|
|
|
@ -147,7 +147,7 @@ additions to the path you want to use in Awesome.
|
||||||
### How to remove gaps between windows?
|
### How to remove gaps between windows?
|
||||||
|
|
||||||
You can add `size_hints_honor = false` to the `properties` section in your
|
You can add `size_hints_honor = false` to the `properties` section in your
|
||||||
`awful.rules.rules` table in your `rc.lua`. It will match and apply this rule
|
`ruled.client.rules` table in your `rc.lua`. It will match and apply this rule
|
||||||
to all clients.
|
to all clients.
|
||||||
|
|
||||||
See [the mailing list archive](http://www.mail-archive.com/awesome@naquadah.org/msg01767.html)
|
See [the mailing list archive](http://www.mail-archive.com/awesome@naquadah.org/msg01767.html)
|
||||||
|
@ -173,8 +173,8 @@ your `globalkeys`:
|
||||||
### How to control titlebars?
|
### How to control titlebars?
|
||||||
|
|
||||||
To disable titlebars on all clients remove the `titlebars_enabled=true` from the
|
To disable titlebars on all clients remove the `titlebars_enabled=true` from the
|
||||||
`awful.rules.rules` table in your config. If you want a titlebar only on
|
`ruled.client.rules` table in your config. If you want a titlebar only on
|
||||||
certain clients, you can use `awful.rules` to set this property only for certain
|
certain clients, you can use `ruled.client` to set this property only for certain
|
||||||
clients.
|
clients.
|
||||||
|
|
||||||
### How to toggle titlebar visibility?
|
### How to toggle titlebar visibility?
|
||||||
|
@ -208,7 +208,7 @@ their last invocation. The default key binding to toggle maximized state is
|
||||||
"Mod4 + m".
|
"Mod4 + m".
|
||||||
|
|
||||||
You can ensure no application ever starts maximized in the first rule of your
|
You can ensure no application ever starts maximized in the first rule of your
|
||||||
`awful.rules.rules` table, which applies to all clients, by adding:
|
`ruled.client.rules` table, which applies to all clients, by adding:
|
||||||
|
|
||||||
-- Search for this rule,
|
-- Search for this rule,
|
||||||
keys = clientkeys,
|
keys = clientkeys,
|
||||||
|
@ -267,14 +267,14 @@ terminal output you can use the following to match clients in Awesome:
|
||||||
|--- name
|
|--- name
|
||||||
|
|
||||||
You can use the above identifiers (instance, class and name) in your
|
You can use the above identifiers (instance, class and name) in your
|
||||||
`awful.rules.rules` table to do matching, tagging and other client manipulation.
|
`ruled.client.rules` table to do matching, tagging and other client manipulation.
|
||||||
See the next FAQ answer for some examples.
|
See the next FAQ answer for some examples.
|
||||||
|
|
||||||
### How to start clients on specific tags and others as floating?
|
### How to start clients on specific tags and others as floating?
|
||||||
|
|
||||||
You can add matching rules to your `awful.rules.rules` table. The default
|
You can add matching rules to your `ruled.client.rules` table. The default
|
||||||
`rc.lua` already has several examples, but some more can be found in the
|
`rc.lua` already has several examples, but some more can be found in the
|
||||||
@{awful.rules.rules|documentation}.
|
@{ruled.client.rules|documentation}.
|
||||||
|
|
||||||
### How to start clients as slave windows instead of master?
|
### How to start clients as slave windows instead of master?
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ layout and allows to change it by clicking on it.
|
||||||
|
|
||||||
### How to make windows spawn under the mouse cursor?
|
### How to make windows spawn under the mouse cursor?
|
||||||
|
|
||||||
In the default `awful.rules`-rule, the following placement is specified:
|
In the default `ruled.client`-rule, the following placement is specified:
|
||||||
|
|
||||||
placement = awful.placement.no_overlap+awful.placement.no_offscreen
|
placement = awful.placement.no_overlap+awful.placement.no_offscreen
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
|
|
||||||
--- A table which content will be compared to the target object current properties.
|
--- A table which content will be compared to the target object current properties.
|
||||||
--
|
--
|
||||||
-- The comparison will be made using the lesser (`>`) operator.
|
-- The comparison will be made using the greater (`>`) operator.
|
||||||
--
|
--
|
||||||
-- @rulecomponent rule_greater
|
-- @rulecomponent rule_greater
|
||||||
-- @param table
|
-- @param table
|
||||||
|
|
|
@ -19,7 +19,7 @@ local tmux = {}
|
||||||
-- will show tmux hotkeys for any window that has 'tmux' in its title.
|
-- will show tmux hotkeys for any window that has 'tmux' in its title.
|
||||||
-- If no rules are provided then tmux hotkeys will be shown always!
|
-- If no rules are provided then tmux hotkeys will be shown always!
|
||||||
-- @function add_rules_for_terminal
|
-- @function add_rules_for_terminal
|
||||||
-- @see awful.rules.rules
|
-- @see ruled.client.rules
|
||||||
-- @tparam table rule Rules to match a window containing a tmux session.
|
-- @tparam table rule Rules to match a window containing a tmux session.
|
||||||
function tmux.add_rules_for_terminal(rule)
|
function tmux.add_rules_for_terminal(rule)
|
||||||
for group_name, group_data in pairs({
|
for group_name, group_data in pairs({
|
||||||
|
|
|
@ -687,13 +687,13 @@ end
|
||||||
-- -- a particular rule.
|
-- -- a particular rule.
|
||||||
-- -- Bound to a key, it can be used to select from dozens of terminals open on
|
-- -- Bound to a key, it can be used to select from dozens of terminals open on
|
||||||
-- -- several tags.
|
-- -- several tags.
|
||||||
-- -- When using @{awful.rules.match_any} instead of @{awful.rules.match},
|
-- -- When using @{ruled.client.match_any} instead of @{ruled.client.match},
|
||||||
-- -- a menu of clients with different classes could be build.
|
-- -- a menu of clients with different classes could be build.
|
||||||
--
|
--
|
||||||
-- function terminal_menu ()
|
-- function terminal_menu ()
|
||||||
-- terms = {}
|
-- terms = {}
|
||||||
-- for i, c in pairs(client.get()) do
|
-- for i, c in pairs(client.get()) do
|
||||||
-- if awful.rules.match(c, {class = "URxvt"}) then
|
-- if ruled.client.match(c, {class = "URxvt"}) then
|
||||||
-- terms[i] =
|
-- terms[i] =
|
||||||
-- {c.name,
|
-- {c.name,
|
||||||
-- function()
|
-- function()
|
||||||
|
|
|
@ -1,668 +1,15 @@
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
--- Rules for clients.
|
--- This module has been moved to `ruled.client`
|
||||||
--
|
|
||||||
-- This module applies @{rules} to clients during startup (via @{client.manage},
|
|
||||||
-- but its functions can be used for client matching in general.
|
|
||||||
--
|
|
||||||
-- All existing `client` properties can be used in rules. It is also possible
|
|
||||||
-- to add random properties that will be later accessible as `c.property_name`
|
|
||||||
-- (where `c` is a valid client object)
|
|
||||||
--
|
|
||||||
-- Syntax
|
|
||||||
-- ===
|
|
||||||
-- You should fill this table with your rule and properties to apply.
|
|
||||||
-- For example, if you want to set xterm maximized at startup, you can add:
|
|
||||||
--
|
|
||||||
-- { rule = { class = "xterm" },
|
|
||||||
-- properties = { maximized_vertical = true, maximized_horizontal = true } }
|
|
||||||
--
|
|
||||||
-- If you want to set mplayer floating at startup, you can add:
|
|
||||||
--
|
|
||||||
-- { rule = { name = "MPlayer" },
|
|
||||||
-- properties = { floating = true } }
|
|
||||||
--
|
|
||||||
-- If you want to put Firefox on a specific tag at startup, you can add:
|
|
||||||
--
|
|
||||||
-- { rule = { instance = "firefox" },
|
|
||||||
-- properties = { tag = mytagobject } }
|
|
||||||
--
|
|
||||||
-- Alternatively, you can specify the tag by name:
|
|
||||||
--
|
|
||||||
-- { rule = { instance = "firefox" },
|
|
||||||
-- properties = { tag = "3" } }
|
|
||||||
--
|
|
||||||
-- If you want to put Thunderbird on a specific screen at startup, use:
|
|
||||||
--
|
|
||||||
-- { rule = { instance = "Thunderbird" },
|
|
||||||
-- properties = { screen = 1 } }
|
|
||||||
--
|
|
||||||
-- Assuming that your X11 server supports the RandR extension, you can also specify
|
|
||||||
-- the screen by name:
|
|
||||||
--
|
|
||||||
-- { rule = { instance = "Thunderbird" },
|
|
||||||
-- properties = { screen = "VGA1" } }
|
|
||||||
--
|
|
||||||
-- If you want to put Emacs on a specific tag at startup, and immediately switch
|
|
||||||
-- to that tag you can add:
|
|
||||||
--
|
|
||||||
-- { rule = { class = "Emacs" },
|
|
||||||
-- properties = { tag = mytagobject, switchtotag = true } }
|
|
||||||
--
|
|
||||||
-- If you want to apply a custom callback to execute when a rule matched,
|
|
||||||
-- for example to pause playing music from mpd when you start dosbox, you
|
|
||||||
-- can add:
|
|
||||||
--
|
|
||||||
-- { rule = { class = "dosbox" },
|
|
||||||
-- callback = function(c)
|
|
||||||
-- awful.spawn('mpc pause')
|
|
||||||
-- end }
|
|
||||||
--
|
|
||||||
-- Note that all "rule" entries need to match. If any of the entry does not
|
|
||||||
-- match, the rule won't be applied.
|
|
||||||
--
|
|
||||||
-- If a client matches multiple rules, they are applied in the order they are
|
|
||||||
-- put in this global rules table. If the value of a rule is a string, then the
|
|
||||||
-- match function is used to determine if the client matches the rule.
|
|
||||||
--
|
|
||||||
-- If the value of a property is a function, that function gets called and
|
|
||||||
-- function's return value is used for the property.
|
|
||||||
--
|
|
||||||
-- To match multiple clients to a rule one need to use slightly different
|
|
||||||
-- syntax:
|
|
||||||
--
|
|
||||||
-- { rule_any = { class = { "MPlayer", "Nitrogen" }, instance = { "xterm" } },
|
|
||||||
-- properties = { floating = true } }
|
|
||||||
--
|
|
||||||
-- To match multiple clients with an exception one can couple `rules.except` or
|
|
||||||
-- `rules.except_any` with the rules:
|
|
||||||
--
|
|
||||||
-- { rule = { class = "Firefox" },
|
|
||||||
-- except = { instance = "Navigator" },
|
|
||||||
-- properties = {floating = true},
|
|
||||||
-- },
|
|
||||||
--
|
|
||||||
-- { rule_any = { class = { "Pidgin", "Xchat" } },
|
|
||||||
-- except_any = { role = { "conversation" } },
|
|
||||||
-- properties = { tag = "1" }
|
|
||||||
-- }
|
|
||||||
--
|
|
||||||
-- { rule = {},
|
|
||||||
-- except_any = { class = { "Firefox", "Vim" } },
|
|
||||||
-- properties = { floating = true }
|
|
||||||
-- }
|
|
||||||
--
|
|
||||||
-- Applicable client properties
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- The table below holds the list of default client properties along with
|
|
||||||
-- some extra properties that are specific to the rules. Note that any property
|
|
||||||
-- can be set in the rules and interpreted by user provided code. This table
|
|
||||||
-- only represent those offered by default.
|
|
||||||
--
|
|
||||||
--@DOC_rules_index_COMMON@
|
|
||||||
--
|
--
|
||||||
-- @author Julien Danjou <julien@danjou.info>
|
-- @author Julien Danjou <julien@danjou.info>
|
||||||
-- @copyright 2009 Julien Danjou
|
-- @copyright 2009 Julien Danjou
|
||||||
-- @module awful.rules
|
-- @module awful.rules
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
-- Grab environment we need
|
|
||||||
local client = client
|
|
||||||
local awesome = awesome
|
|
||||||
local screen = screen
|
|
||||||
local table = table
|
|
||||||
local type = type
|
|
||||||
local ipairs = ipairs
|
|
||||||
local pairs = pairs
|
|
||||||
local atag = require("awful.tag")
|
|
||||||
local gtable = require("gears.table")
|
|
||||||
local a_place = require("awful.placement")
|
|
||||||
local protected_call = require("gears.protected_call")
|
|
||||||
local aspawn = require("awful.spawn")
|
|
||||||
local gdebug = require("gears.debug")
|
local gdebug = require("gears.debug")
|
||||||
local gmatcher = require("gears.matcher")
|
|
||||||
local amouse = require("awful.mouse")
|
|
||||||
local akeyboard = require("awful.keyboard")
|
|
||||||
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
|
|
||||||
|
|
||||||
local rules = {}
|
return gdebug.deprecate_class(
|
||||||
|
require("ruled.client"),
|
||||||
--- This is the global rules table.
|
"awful.rules",
|
||||||
rules.rules = {}
|
"ruled.client",
|
||||||
|
{ deprecated_in = 5}
|
||||||
local crules = gmatcher()
|
)
|
||||||
|
|
||||||
--- Check if a client matches a rule.
|
|
||||||
-- @client c The client.
|
|
||||||
-- @tab rule The rule to check.
|
|
||||||
-- @treturn bool True if it matches, false otherwise.
|
|
||||||
-- @staticfct awful.rules.match
|
|
||||||
function rules.match(c, rule)
|
|
||||||
return crules:_match(c, rule)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Check if a client matches any part of a rule.
|
|
||||||
-- @client c The client.
|
|
||||||
-- @tab rule The rule to check.
|
|
||||||
-- @treturn bool True if at least one rule is matched, false otherwise.
|
|
||||||
-- @staticfct awful.rules.match_any
|
|
||||||
function rules.match_any(c, rule)
|
|
||||||
return crules:_match_any(c, rule)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Does a given rule entry match a client?
|
|
||||||
-- @client c The client.
|
|
||||||
-- @tab entry Rule entry (with keys `rule`, `rule_any`, `except` and/or
|
|
||||||
-- `except_any`).
|
|
||||||
-- @treturn bool
|
|
||||||
-- @staticfct awful.rules.matches
|
|
||||||
function rules.matches(c, entry)
|
|
||||||
return crules:matches_rule(c, entry)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get list of matching rules for a client.
|
|
||||||
-- @client c The client.
|
|
||||||
-- @tab _rules The rules to check. List with "rule", "rule_any", "except" and
|
|
||||||
-- "except_any" keys.
|
|
||||||
-- @treturn table The list of matched rules.
|
|
||||||
-- @staticfct awful.rules.matching_rules
|
|
||||||
function rules.matching_rules(c, _rules)
|
|
||||||
return crules:matching_rules(c, _rules)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Check if a client matches a given set of rules.
|
|
||||||
-- @client c The client.
|
|
||||||
-- @tab _rules The rules to check. List of tables with `rule`, `rule_any`,
|
|
||||||
-- `except` and `except_any` keys.
|
|
||||||
-- @treturn bool True if at least one rule is matched, false otherwise.
|
|
||||||
-- @staticfct awful.rules.matches_list
|
|
||||||
function rules.matches_list(c, _rules)
|
|
||||||
return crules:matches_rules(c, _rules)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Remove a source.
|
|
||||||
-- @tparam string name The source name.
|
|
||||||
-- @treturn boolean If the source was removed.
|
|
||||||
-- @staticfct awful.rules.remove_rule_source
|
|
||||||
function rules.remove_rule_source(name)
|
|
||||||
return crules:remove_matching_source(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Apply awful.rules.rules to a client.
|
|
||||||
-- @client c The client.
|
|
||||||
-- @staticfct awful.rules.apply
|
|
||||||
function rules.apply(c)
|
|
||||||
return crules:apply(c)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Add a new rule source.
|
|
||||||
--
|
|
||||||
-- A rule source is a provider called when a client is managed (started). It
|
|
||||||
-- allows to configure the client by providing properties that should be applied.
|
|
||||||
-- By default, Awesome provides 2 sources:
|
|
||||||
--
|
|
||||||
-- * `awful.rules`: A declarative matcher
|
|
||||||
-- * `awful.spawn`: Launch clients with pre-defined properties
|
|
||||||
--
|
|
||||||
-- It is possible to register new callbacks to modify the properties table
|
|
||||||
-- before it is applied. Each provider is executed sequentially and modifies the
|
|
||||||
-- same table. If the first provider set a property, then the second can
|
|
||||||
-- override it, then the third, etc. Once the providers are exhausted, the
|
|
||||||
-- properties are applied on the client.
|
|
||||||
--
|
|
||||||
-- It is important to note that properties themselves have their own
|
|
||||||
-- dependencies. For example, a `tag` property implies a `screen`. Therefor, if
|
|
||||||
-- a `screen` is already specified, then it will be ignored when the rule is
|
|
||||||
-- executed. Properties also have their own priorities. For example, the
|
|
||||||
-- `titlebar` and `border_width` need to be applied before the `x` and `y`
|
|
||||||
-- positions are set. Otherwise, it will be off or the client will shift
|
|
||||||
-- upward everytime Awesome is restarted. A rule source *cannot* change this.
|
|
||||||
-- It is up to the callback to be aware of the dependencies and avoid to
|
|
||||||
-- introduce issues. For example, if the source wants to set a `screen`, it has
|
|
||||||
-- to check if the `tag`, `tags` or `new_tag` are on that `screen` or remove
|
|
||||||
-- those properties. Otherwise, they will be ignored once the rule is applied.
|
|
||||||
--
|
|
||||||
-- @tparam string name The provider name. It must be unique.
|
|
||||||
-- @tparam function callback The callback that is called to produce properties.
|
|
||||||
-- @tparam client callback.c The client
|
|
||||||
-- @tparam table callback.properties The current properties. The callback should
|
|
||||||
-- add to and overwrite properties in this table
|
|
||||||
-- @tparam table callback.callbacks A table of all callbacks scheduled to be
|
|
||||||
-- executed after the main properties are applied.
|
|
||||||
-- @tparam[opt={}] table depends_on A list of names of sources this source depends on
|
|
||||||
-- (sources that must be executed *before* `name`.
|
|
||||||
-- @tparam[opt={}] table precede A list of names of sources this source have a
|
|
||||||
-- priority over.
|
|
||||||
-- @treturn boolean Returns false if a dependency conflict was found.
|
|
||||||
-- @staticfct awful.rules.add_rule_source
|
|
||||||
|
|
||||||
function rules.add_rule_source(name, cb, ...)
|
|
||||||
local function callback(_, ...)
|
|
||||||
cb(...)
|
|
||||||
end
|
|
||||||
return crules:add_matching_function(name, callback, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add the rules properties
|
|
||||||
local function apply_awful_rules(c, props, callbacks)
|
|
||||||
for _, entry in ipairs(rules.matching_rules(c, rules.rules)) do
|
|
||||||
gtable.crush(props,entry.properties or {})
|
|
||||||
|
|
||||||
if entry.callback then
|
|
||||||
table.insert(callbacks, entry.callback)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- The default `awful.rules` source.
|
|
||||||
--
|
|
||||||
-- **Has priority over:**
|
|
||||||
--
|
|
||||||
-- *nothing*
|
|
||||||
--
|
|
||||||
-- @rulesources awful.rules
|
|
||||||
|
|
||||||
rules.add_rule_source("awful.rules", apply_awful_rules, {"awful.spawn"}, {})
|
|
||||||
|
|
||||||
-- Add startup_id overridden properties
|
|
||||||
local function apply_spawn_rules(c, props, callbacks)
|
|
||||||
if c.startup_id and aspawn.snid_buffer[c.startup_id] then
|
|
||||||
local snprops, sncb = unpack(aspawn.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 = nil, nil, nil
|
|
||||||
end
|
|
||||||
|
|
||||||
gtable.crush(props, snprops)
|
|
||||||
gtable.merge(callbacks, sncb)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- The rule source for clients spawned by `awful.spawn`.
|
|
||||||
--
|
|
||||||
-- **Has priority over:**
|
|
||||||
--
|
|
||||||
-- * `awful.rules`
|
|
||||||
--
|
|
||||||
-- @rulesources awful.spawn
|
|
||||||
|
|
||||||
rules.add_rule_source("awful.spawn", apply_spawn_rules, {}, {"awful.rules"})
|
|
||||||
|
|
||||||
local function apply_singleton_rules(c, props, callbacks)
|
|
||||||
local persis_id, info = c.single_instance_id, nil
|
|
||||||
|
|
||||||
-- This is a persistent property set by `awful.spawn`
|
|
||||||
if awesome.startup and persis_id then
|
|
||||||
info = aspawn.single_instance_manager.by_uid[persis_id]
|
|
||||||
elseif c.startup_id then
|
|
||||||
info = aspawn.single_instance_manager.by_snid[c.startup_id]
|
|
||||||
aspawn.single_instance_manager.by_snid[c.startup_id] = nil
|
|
||||||
elseif aspawn.single_instance_manager.by_pid[c.pid] then
|
|
||||||
info = aspawn.single_instance_manager.by_pid[c.pid].matcher(c) and
|
|
||||||
aspawn.single_instance_manager.by_pid[c.pid] or nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if info then
|
|
||||||
c.single_instance_id = info.hash
|
|
||||||
if info.rules then
|
|
||||||
gtable.crush(props, info.rules)
|
|
||||||
end
|
|
||||||
table.insert(callbacks, info.callback)
|
|
||||||
table.insert(info.instances, c)
|
|
||||||
|
|
||||||
-- Prevent apps with multiple clients from re-using this too often in
|
|
||||||
-- the first 30 seconds before the PID is cleared.
|
|
||||||
aspawn.single_instance_manager.by_pid[c.pid] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- The rule source for clients spawned by `awful.spawn.once` and `single_instance`.
|
|
||||||
--
|
|
||||||
-- **Has priority over:**
|
|
||||||
--
|
|
||||||
-- * `awful.rules`
|
|
||||||
--
|
|
||||||
-- **Depends on:**
|
|
||||||
--
|
|
||||||
-- * `awful.spawn`
|
|
||||||
--
|
|
||||||
-- @rulesources awful.spawn_once
|
|
||||||
|
|
||||||
rules.add_rule_source("awful.spawn_once", apply_singleton_rules, {"awful.spawn"}, {"awful.rules"})
|
|
||||||
|
|
||||||
local function add_to_tag(c, t)
|
|
||||||
if not t then return end
|
|
||||||
|
|
||||||
local tags = c:tags()
|
|
||||||
table.insert(tags, t)
|
|
||||||
c:tags(tags)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Extra rules properties.
|
|
||||||
--
|
|
||||||
-- These properties are used in the rules only and are not sent to the client
|
|
||||||
-- afterward.
|
|
||||||
--
|
|
||||||
-- To add a new properties, just do:
|
|
||||||
--
|
|
||||||
-- function awful.rules.extra_properties.my_new_property(c, value, props)
|
|
||||||
-- -- do something
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- By default, the table has the following functions:
|
|
||||||
--
|
|
||||||
-- * geometry
|
|
||||||
-- * placement
|
|
||||||
--
|
|
||||||
-- @tfield table awful.rules.extra_properties
|
|
||||||
rules.extra_properties = {}
|
|
||||||
|
|
||||||
--- Extra high priority properties.
|
|
||||||
--
|
|
||||||
-- Some properties, such as anything related to tags, geometry or focus, will
|
|
||||||
-- cause a race condition if set in the main property section. This is why
|
|
||||||
-- they have a section for them.
|
|
||||||
--
|
|
||||||
-- To add a new properties, just do:
|
|
||||||
--
|
|
||||||
-- function awful.rules.high_priority_properties.my_new_property(c, value, props)
|
|
||||||
-- -- do something
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- By default, the table has the following functions:
|
|
||||||
--
|
|
||||||
-- * tag
|
|
||||||
-- * new_tag
|
|
||||||
--
|
|
||||||
-- @tfield table awful.rules.high_priority_properties
|
|
||||||
rules.high_priority_properties = {}
|
|
||||||
|
|
||||||
--- Delayed properties.
|
|
||||||
-- Properties applied after all other categories.
|
|
||||||
-- @tfield table awful.rules.delayed_properties
|
|
||||||
-- By default, the table has the following functions:
|
|
||||||
--
|
|
||||||
-- * switch_to_tags
|
|
||||||
rules.delayed_properties = {}
|
|
||||||
|
|
||||||
local force_ignore = {
|
|
||||||
titlebars_enabled=true, focus=true, screen=true, x=true,
|
|
||||||
y=true, width=true, height=true, geometry=true,placement=true,
|
|
||||||
border_width=true,floating=true,size_hints_honor=true
|
|
||||||
}
|
|
||||||
|
|
||||||
function rules.high_priority_properties.tag(c, value, props)
|
|
||||||
if value then
|
|
||||||
if type(value) == "string" then
|
|
||||||
local name = value
|
|
||||||
value = atag.find_by_name(c.screen, value)
|
|
||||||
if not value and not props.screen then
|
|
||||||
value = atag.find_by_name(nil, name)
|
|
||||||
end
|
|
||||||
if not value then
|
|
||||||
require("gears.debug").print_error("awful.rules-rule specified "
|
|
||||||
.. "tag = '" .. name .. "', but no such tag exists")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- In case the tag has been forced to another screen, move the client
|
|
||||||
if c.screen ~= value.screen then
|
|
||||||
c.screen = value.screen
|
|
||||||
props.screen = value.screen -- In case another rule query it
|
|
||||||
end
|
|
||||||
|
|
||||||
c:tags{ value }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function rules.delayed_properties.switch_to_tags(c, value)
|
|
||||||
if not value then return end
|
|
||||||
atag.viewmore(c:tags(), c.screen)
|
|
||||||
end
|
|
||||||
|
|
||||||
function rules.delayed_properties.switchtotag(c, value)
|
|
||||||
gdebug.deprecate("Use switch_to_tags instead of switchtotag", {deprecated_in=5})
|
|
||||||
|
|
||||||
rules.delayed_properties.switch_to_tags(c, value)
|
|
||||||
end
|
|
||||||
|
|
||||||
function rules.extra_properties.geometry(c, _, props)
|
|
||||||
local cur_geo = c:geometry()
|
|
||||||
|
|
||||||
local new_geo = type(props.geometry) == "function"
|
|
||||||
and props.geometry(c, props) or props.geometry or {}
|
|
||||||
|
|
||||||
for _, v in ipairs {"x", "y", "width", "height"} do
|
|
||||||
new_geo[v] = type(props[v]) == "function" and props[v](c, props)
|
|
||||||
or props[v] or new_geo[v] or cur_geo[v]
|
|
||||||
end
|
|
||||||
|
|
||||||
c:geometry(new_geo) --TODO use request::geometry
|
|
||||||
end
|
|
||||||
|
|
||||||
function rules.high_priority_properties.new_tag(c, value, props)
|
|
||||||
local ty = type(value)
|
|
||||||
local t = nil
|
|
||||||
|
|
||||||
if ty == "boolean" then
|
|
||||||
-- Create a new tag named after the client class
|
|
||||||
t = atag.add(c.class or "N/A", {screen=c.screen, volatile=true})
|
|
||||||
elseif ty == "string" then
|
|
||||||
-- Create a tag named after "value"
|
|
||||||
t = atag.add(value, {screen=c.screen, volatile=true})
|
|
||||||
elseif ty == "table" then
|
|
||||||
-- Assume a table of tags properties. Set the right screen, but
|
|
||||||
-- avoid editing the original table
|
|
||||||
local values = value.screen and value or gtable.clone(value)
|
|
||||||
values.screen = values.screen or c.screen
|
|
||||||
|
|
||||||
t = atag.add(value.name or c.class or "N/A", values)
|
|
||||||
|
|
||||||
-- In case the tag has been forced to another screen, move the client
|
|
||||||
c.screen = t.screen
|
|
||||||
props.screen = t.screen -- In case another rule query it
|
|
||||||
else
|
|
||||||
assert(false)
|
|
||||||
end
|
|
||||||
|
|
||||||
add_to_tag(c, t)
|
|
||||||
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
|
|
||||||
function rules.extra_properties.placement(c, value, props)
|
|
||||||
-- Avoid problems
|
|
||||||
if awesome.startup and
|
|
||||||
(c.size_hints.user_position or c.size_hints.program_position) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local ty = type(value)
|
|
||||||
|
|
||||||
local args = {
|
|
||||||
honor_workarea = props.honor_workarea ~= false,
|
|
||||||
honor_padding = props.honor_padding ~= false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ty == "function" or (ty == "table" and
|
|
||||||
getmetatable(value) and getmetatable(value).__call
|
|
||||||
) then
|
|
||||||
value(c, args)
|
|
||||||
elseif ty == "string" and a_place[value] then
|
|
||||||
a_place[value](c, args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function rules.high_priority_properties.tags(c, value, props)
|
|
||||||
local current = c:tags()
|
|
||||||
|
|
||||||
local tags, s = {}, nil
|
|
||||||
|
|
||||||
for _, t in ipairs(value) do
|
|
||||||
if type(t) == "string" then
|
|
||||||
t = atag.find_by_name(c.screen, t)
|
|
||||||
end
|
|
||||||
|
|
||||||
if t and ((not s) or t.screen == s) then
|
|
||||||
table.insert(tags, t)
|
|
||||||
s = s or t.screen
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if s and s ~= c.screen then
|
|
||||||
c.screen = s
|
|
||||||
props.screen = s -- In case another rule query it
|
|
||||||
end
|
|
||||||
|
|
||||||
if #current == 0 or (value[1] and value[1].screen ~= current[1].screen) then
|
|
||||||
c:tags(tags)
|
|
||||||
else
|
|
||||||
c:tags(gtable.merge(current, tags))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Apply properties and callbacks to a client.
|
|
||||||
-- @client c The client.
|
|
||||||
-- @tab props Properties to apply.
|
|
||||||
-- @tab[opt] callbacks Callbacks to apply.
|
|
||||||
-- @staticfct awful.rules.execute
|
|
||||||
-- @request client titlebars rules granted The `titlebars_enabled` is set in the
|
|
||||||
-- rules.
|
|
||||||
|
|
||||||
crules._execute = function(_, c, props, callbacks)
|
|
||||||
|
|
||||||
-- Set the default buttons and keys
|
|
||||||
local btns = amouse._get_client_mousebindings()
|
|
||||||
local keys = akeyboard._get_client_keybindings()
|
|
||||||
props.keys = props.keys or keys
|
|
||||||
props.buttons = props.buttons or btns
|
|
||||||
|
|
||||||
-- Border width will also cause geometry related properties to fail
|
|
||||||
if props.border_width then
|
|
||||||
c.border_width = type(props.border_width) == "function" and
|
|
||||||
props.border_width(c, props) or props.border_width
|
|
||||||
end
|
|
||||||
|
|
||||||
-- This has to be done first, as it will impact geometry related props.
|
|
||||||
if props.titlebars_enabled and (type(props.titlebars_enabled) ~= "function"
|
|
||||||
or props.titlebars_enabled(c,props)) then
|
|
||||||
c:emit_signal("request::titlebars", "rules", {properties=props})
|
|
||||||
c._request_titlebars_called = true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Size hints will be re-applied when setting width/height unless it is
|
|
||||||
-- disabled first
|
|
||||||
if props.size_hints_honor ~= nil then
|
|
||||||
c.size_hints_honor = type(props.size_hints_honor) == "function" and props.size_hints_honor(c,props)
|
|
||||||
or props.size_hints_honor
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Geometry will only work if floating is true, otherwise the "saved"
|
|
||||||
-- geometry will be restored.
|
|
||||||
if props.floating ~= nil then
|
|
||||||
c.floating = type(props.floating) == "function" and props.floating(c,props)
|
|
||||||
or props.floating
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Before requesting a tag, make sure the screen is right
|
|
||||||
if props.screen then
|
|
||||||
c.screen = type(props.screen) == "function" and screen[props.screen(c,props)]
|
|
||||||
or screen[props.screen]
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Some properties need to be handled first. For example, many properties
|
|
||||||
-- require that the client is tagged, this isn't yet the case.
|
|
||||||
for prop, handler in pairs(rules.high_priority_properties) do
|
|
||||||
local value = props[prop]
|
|
||||||
if value ~= nil then
|
|
||||||
if type(value) == "function" then
|
|
||||||
value = value(c, props)
|
|
||||||
end
|
|
||||||
handler(c, value, props)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Make sure the tag is selected before the main rules are called.
|
|
||||||
-- Otherwise properties like "urgent" or "focus" may fail (if they were
|
|
||||||
-- overridden by other callbacks).
|
|
||||||
-- Previously this was done in a second client.manage callback, but caused
|
|
||||||
-- a race condition where the order of modules being loaded would change
|
|
||||||
-- the outcome.
|
|
||||||
c:emit_signal("request::tag", nil, {reason="rules"})
|
|
||||||
|
|
||||||
-- By default, rc.lua uses no_overlap+no_offscreen placement. This has to
|
|
||||||
-- be executed before x/y/width/height/geometry as it would otherwise
|
|
||||||
-- always override the user specified position with the default rule.
|
|
||||||
if props.placement then
|
|
||||||
-- It may be a function, so this one doesn't execute it like others
|
|
||||||
rules.extra_properties.placement(c, props.placement, props)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Handle the geometry (since tags and screen are set).
|
|
||||||
if props.height or props.width or props.x or props.y or props.geometry then
|
|
||||||
rules.extra_properties.geometry(c, nil, props)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Apply the remaining properties (after known race conditions are handled).
|
|
||||||
for property, value in pairs(props) do
|
|
||||||
if property ~= "focus" and property ~= "shape" and type(value) == "function" then
|
|
||||||
value = value(c, props)
|
|
||||||
end
|
|
||||||
|
|
||||||
local ignore = rules.high_priority_properties[property] or
|
|
||||||
rules.delayed_properties[property] or force_ignore[property]
|
|
||||||
|
|
||||||
if not ignore then
|
|
||||||
if rules.extra_properties[property] then
|
|
||||||
rules.extra_properties[property](c, value, props)
|
|
||||||
elseif type(c[property]) == "function" then
|
|
||||||
c[property](c, value)
|
|
||||||
else
|
|
||||||
c[property] = value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Apply all callbacks.
|
|
||||||
if callbacks then
|
|
||||||
for _, callback in pairs(callbacks) do
|
|
||||||
protected_call(callback, c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Apply the delayed properties
|
|
||||||
for prop, handler in pairs(rules.delayed_properties) do
|
|
||||||
if not force_ignore[prop] then
|
|
||||||
local value = props[prop]
|
|
||||||
if value ~= nil then
|
|
||||||
if type(value) == "function" then
|
|
||||||
value = value(c, props)
|
|
||||||
end
|
|
||||||
handler(c, value, props)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Do this at last so we do not erase things done by the focus signal.
|
|
||||||
if props.focus and (type(props.focus) ~= "function" or props.focus(c)) then
|
|
||||||
c:emit_signal('request::activate', "rules", {raise=not awesome.startup})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function rules.execute(...) crules:_execute(...) end
|
|
||||||
|
|
||||||
-- TODO v5 deprecate this
|
|
||||||
function rules.completed_with_payload_callback(c, props, callbacks)
|
|
||||||
rules.execute(c, props, callbacks)
|
|
||||||
end
|
|
||||||
|
|
||||||
client.connect_signal("request::manage", rules.apply)
|
|
||||||
|
|
||||||
--@DOC_rule_COMMON@
|
|
||||||
|
|
||||||
return rules
|
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
||||||
|
|
|
@ -0,0 +1,712 @@
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
--- Rules for clients.
|
||||||
|
--
|
||||||
|
-- This module applies @{rules} to clients during startup (via @{client.manage},
|
||||||
|
-- but its functions can be used for client matching in general.
|
||||||
|
--
|
||||||
|
-- All existing `client` properties can be used in rules. It is also possible
|
||||||
|
-- to add random properties that will be later accessible as `c.property_name`
|
||||||
|
-- (where `c` is a valid client object)
|
||||||
|
--
|
||||||
|
-- Syntax
|
||||||
|
-- ===
|
||||||
|
-- You should fill this table with your rule and properties to apply.
|
||||||
|
-- For example, if you want to set xterm maximized at startup, you can add:
|
||||||
|
--
|
||||||
|
-- @DOC_sequences_client_rules_maximized_EXAMPLE@
|
||||||
|
--
|
||||||
|
-- If you want to set mplayer floating at startup, you can add:
|
||||||
|
--
|
||||||
|
-- @DOC_sequences_client_rules_floating_EXAMPLE@
|
||||||
|
--
|
||||||
|
-- If you want to put Firefox on a specific tag at startup. It is possible to
|
||||||
|
-- specify the tag with it's object or by name:
|
||||||
|
--
|
||||||
|
-- @DOC_sequences_client_rules_tags_EXAMPLE@
|
||||||
|
--
|
||||||
|
-- If you want to put Thunderbird on a specific screen at startup, use:
|
||||||
|
--
|
||||||
|
-- @DOC_sequences_client_rules_screens_EXAMPLE@
|
||||||
|
--
|
||||||
|
-- If you want to put Emacs on a specific tag at startup, and immediately switch
|
||||||
|
-- to that tag you can add:
|
||||||
|
--
|
||||||
|
-- @DOC_sequences_client_rules_switch_to_tags_EXAMPLE@
|
||||||
|
--
|
||||||
|
-- If you want to apply a custom callback to execute when a rule matched,
|
||||||
|
-- for example to pause playing music from mpd when you start dosbox, you
|
||||||
|
-- can add:
|
||||||
|
--
|
||||||
|
-- { rule = { class = "dosbox" },
|
||||||
|
-- callback = function(c)
|
||||||
|
-- awful.spawn('mpc pause')
|
||||||
|
-- end }
|
||||||
|
--
|
||||||
|
-- Note that all "rule" entries need to match. If any of the entry does not
|
||||||
|
-- match, the rule won't be applied.
|
||||||
|
--
|
||||||
|
-- If a client matches multiple rules, they are applied in the order they are
|
||||||
|
-- put in this global rules table. If the value of a rule is a string, then the
|
||||||
|
-- match function is used to determine if the client matches the rule.
|
||||||
|
--
|
||||||
|
-- If the value of a property is a function, that function gets called and
|
||||||
|
-- function's return value is used for the property.
|
||||||
|
--
|
||||||
|
-- To match multiple clients to a rule one need to use slightly different
|
||||||
|
-- syntax:
|
||||||
|
--
|
||||||
|
-- { rule_any = { class = { "MPlayer", "Nitrogen" }, instance = { "xterm" } },
|
||||||
|
-- properties = { floating = true } }
|
||||||
|
--
|
||||||
|
-- To match multiple clients with an exception one can couple `rules.except` or
|
||||||
|
-- `rules.except_any` with the rules:
|
||||||
|
--
|
||||||
|
-- { rule = { class = "Firefox" },
|
||||||
|
-- except = { instance = "Navigator" },
|
||||||
|
-- properties = {floating = true},
|
||||||
|
-- },
|
||||||
|
--
|
||||||
|
-- { rule_any = { class = { "Pidgin", "Xchat" } },
|
||||||
|
-- except_any = { role = { "conversation" } },
|
||||||
|
-- properties = { tag = "1" }
|
||||||
|
-- }
|
||||||
|
--
|
||||||
|
-- { rule = {},
|
||||||
|
-- except_any = { class = { "Firefox", "Vim" } },
|
||||||
|
-- properties = { floating = true }
|
||||||
|
-- }
|
||||||
|
--
|
||||||
|
-- Note that all rules can have an `id` field. This can then be used to find
|
||||||
|
-- the rule. For example, it can be used in `remove_rule` instead of the table.
|
||||||
|
--
|
||||||
|
-- Applicable client properties
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- The table below holds the list of default client properties along with
|
||||||
|
-- some extra properties that are specific to the rules. Note that any property
|
||||||
|
-- can be set in the rules and interpreted by user provided code. This table
|
||||||
|
-- only represent those offered by default.
|
||||||
|
--
|
||||||
|
--@DOC_client_rules_index_COMMON@
|
||||||
|
--
|
||||||
|
-- @author Julien Danjou <julien@danjou.info>
|
||||||
|
-- @copyright 2009 Julien Danjou
|
||||||
|
-- @ruleslib ruled.client
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Grab environment we need
|
||||||
|
|
||||||
|
local capi = {client = client, awesome = awesome, screen = screen, tag = tag}
|
||||||
|
local table = table
|
||||||
|
local type = type
|
||||||
|
local ipairs = ipairs
|
||||||
|
local pairs = pairs
|
||||||
|
local atag = require("awful.tag")
|
||||||
|
local gobject = require("gears.object")
|
||||||
|
local gtable = require("gears.table")
|
||||||
|
local a_place = require("awful.placement")
|
||||||
|
local protected_call = require("gears.protected_call")
|
||||||
|
local aspawn = require("awful.spawn")
|
||||||
|
local gdebug = require("gears.debug")
|
||||||
|
local gmatcher = require("gears.matcher")
|
||||||
|
local amouse = require("awful.mouse")
|
||||||
|
local akeyboard = require("awful.keyboard")
|
||||||
|
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
|
||||||
|
|
||||||
|
local module = {}
|
||||||
|
|
||||||
|
local crules = gmatcher()
|
||||||
|
|
||||||
|
--- Check if a client matches a rule.
|
||||||
|
-- @client c The client.
|
||||||
|
-- @tab rule The rule to check.
|
||||||
|
-- @treturn bool True if it matches, false otherwise.
|
||||||
|
-- @staticfct ruled.client.match
|
||||||
|
function module.match(c, rule)
|
||||||
|
return crules:_match(c, rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a client matches any part of a rule.
|
||||||
|
-- @client c The client.
|
||||||
|
-- @tab rule The rule to check.
|
||||||
|
-- @treturn bool True if at least one rule is matched, false otherwise.
|
||||||
|
-- @staticfct ruled.client.match_any
|
||||||
|
function module.match_any(c, rule)
|
||||||
|
return crules:_match_any(c, rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Does a given rule entry match a client?
|
||||||
|
-- @client c The client.
|
||||||
|
-- @tab entry Rule entry (with keys `rule`, `rule_any`, `except` and/or
|
||||||
|
-- `except_any`).
|
||||||
|
-- @treturn bool
|
||||||
|
-- @staticfct ruled.client.matches
|
||||||
|
function module.matches(c, entry)
|
||||||
|
return crules:matches_rule(c, entry)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get list of matching rules for a client.
|
||||||
|
-- @client c The client.
|
||||||
|
-- @tab _rules The rules to check. List with "rule", "rule_any", "except" and
|
||||||
|
-- "except_any" keys.
|
||||||
|
-- @treturn table The list of matched rules.
|
||||||
|
-- @staticfct ruled.client.matching_rules
|
||||||
|
function module.matching_rules(c, _rules)
|
||||||
|
return crules:matching_rules(c, _rules)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a client matches a given set of rules.
|
||||||
|
-- @client c The client.
|
||||||
|
-- @tab _rules The rules to check. List of tables with `rule`, `rule_any`,
|
||||||
|
-- `except` and `except_any` keys.
|
||||||
|
-- @treturn bool True if at least one rule is matched, false otherwise.
|
||||||
|
-- @staticfct ruled.client.matches_list
|
||||||
|
function module.matches_list(c, _rules)
|
||||||
|
return crules:matches_rules(c, _rules)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove a source.
|
||||||
|
-- @tparam string name The source name.
|
||||||
|
-- @treturn boolean If the source was removed.
|
||||||
|
-- @staticfct ruled.client.remove_rule_source
|
||||||
|
function module.remove_rule_source(name)
|
||||||
|
return crules:remove_matching_source(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Apply ruled.client.rules to a client.
|
||||||
|
-- @client c The client.
|
||||||
|
-- @staticfct ruled.client.apply
|
||||||
|
function module.apply(c)
|
||||||
|
return crules:apply(c)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a new rule to the default set.
|
||||||
|
--
|
||||||
|
-- @tparam table rule A valid rule.
|
||||||
|
function module.append_rule(rule)
|
||||||
|
crules:append_rule("awful.rules", rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a new rules to the default set.
|
||||||
|
-- @tparam table rules A table with rules.
|
||||||
|
function module.append_rules(rules)
|
||||||
|
crules:append_rules("awful.rules", rules)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove a new rule to the default set.
|
||||||
|
-- @tparam table|string rule A valid rule or a name passed in the `id` value
|
||||||
|
-- when calling `append_rule`.
|
||||||
|
function module.remove_rule(rule)
|
||||||
|
crules:remove_rule("awful.rules", rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a new rule source.
|
||||||
|
--
|
||||||
|
-- A rule source is a provider called when a client is managed (started). It
|
||||||
|
-- allows to configure the client by providing properties that should be applied.
|
||||||
|
-- By default, Awesome provides 2 sources:
|
||||||
|
--
|
||||||
|
-- * `awful.rules`: A declarative matcher
|
||||||
|
-- * `awful.spawn`: Launch clients with pre-defined properties
|
||||||
|
--
|
||||||
|
-- It is possible to register new callbacks to modify the properties table
|
||||||
|
-- before it is applied. Each provider is executed sequentially and modifies the
|
||||||
|
-- same table. If the first provider set a property, then the second can
|
||||||
|
-- override it, then the third, etc. Once the providers are exhausted, the
|
||||||
|
-- properties are applied on the client.
|
||||||
|
--
|
||||||
|
-- It is important to note that properties themselves have their own
|
||||||
|
-- dependencies. For example, a `tag` property implies a `screen`. Therefor, if
|
||||||
|
-- a `screen` is already specified, then it will be ignored when the rule is
|
||||||
|
-- executed. Properties also have their own priorities. For example, the
|
||||||
|
-- `titlebar` and `border_width` need to be applied before the `x` and `y`
|
||||||
|
-- positions are set. Otherwise, it will be off or the client will shift
|
||||||
|
-- upward everytime Awesome is restarted. A rule source *cannot* change this.
|
||||||
|
-- It is up to the callback to be aware of the dependencies and avoid to
|
||||||
|
-- introduce issues. For example, if the source wants to set a `screen`, it has
|
||||||
|
-- to check if the `tag`, `tags` or `new_tag` are on that `screen` or remove
|
||||||
|
-- those properties. Otherwise, they will be ignored once the rule is applied.
|
||||||
|
--
|
||||||
|
-- @tparam string name The provider name. It must be unique.
|
||||||
|
-- @tparam function callback The callback that is called to produce properties.
|
||||||
|
-- @tparam client callback.c The client
|
||||||
|
-- @tparam table callback.properties The current properties. The callback should
|
||||||
|
-- add to and overwrite properties in this table
|
||||||
|
-- @tparam table callback.callbacks A table of all callbacks scheduled to be
|
||||||
|
-- executed after the main properties are applied.
|
||||||
|
-- @tparam[opt={}] table depends_on A list of names of sources this source depends on
|
||||||
|
-- (sources that must be executed *before* `name`.
|
||||||
|
-- @tparam[opt={}] table precede A list of names of sources this source have a
|
||||||
|
-- priority over.
|
||||||
|
-- @treturn boolean Returns false if a dependency conflict was found.
|
||||||
|
-- @staticfct ruled.client.add_rule_source
|
||||||
|
|
||||||
|
function module.add_rule_source(name, cb, ...)
|
||||||
|
local function callback(_, ...)
|
||||||
|
cb(...)
|
||||||
|
end
|
||||||
|
return crules:add_matching_function(name, callback, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- The default `ruled.client` source.
|
||||||
|
--
|
||||||
|
-- It is called `awful.rules` for historical reasons.
|
||||||
|
--
|
||||||
|
-- **Has priority over:**
|
||||||
|
--
|
||||||
|
-- *nothing*
|
||||||
|
--
|
||||||
|
-- @rulesources awful.rules
|
||||||
|
|
||||||
|
crules:add_matching_rules("awful.rules", {}, {"awful.spawn"}, {})
|
||||||
|
|
||||||
|
-- Add startup_id overridden properties
|
||||||
|
local function apply_spawn_rules(c, props, callbacks)
|
||||||
|
if c.startup_id and aspawn.snid_buffer[c.startup_id] then
|
||||||
|
local snprops, sncb = unpack(aspawn.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 = nil, nil, nil
|
||||||
|
end
|
||||||
|
|
||||||
|
gtable.crush(props, snprops)
|
||||||
|
gtable.merge(callbacks, sncb)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- The rule source for clients spawned by `awful.spawn`.
|
||||||
|
--
|
||||||
|
-- **Has priority over:**
|
||||||
|
--
|
||||||
|
-- * `awful.rules`
|
||||||
|
--
|
||||||
|
-- @rulesources awful.spawn
|
||||||
|
|
||||||
|
module.add_rule_source("awful.spawn", apply_spawn_rules, {}, {"awful.rules"})
|
||||||
|
|
||||||
|
local function apply_singleton_rules(c, props, callbacks)
|
||||||
|
local persis_id, info = c.single_instance_id, nil
|
||||||
|
|
||||||
|
-- This is a persistent property set by `awful.spawn`
|
||||||
|
if capi.awesome.startup and persis_id then
|
||||||
|
info = aspawn.single_instance_manager.by_uid[persis_id]
|
||||||
|
elseif c.startup_id then
|
||||||
|
info = aspawn.single_instance_manager.by_snid[c.startup_id]
|
||||||
|
aspawn.single_instance_manager.by_snid[c.startup_id] = nil
|
||||||
|
elseif aspawn.single_instance_manager.by_pid[c.pid] then
|
||||||
|
info = aspawn.single_instance_manager.by_pid[c.pid].matcher(c) and
|
||||||
|
aspawn.single_instance_manager.by_pid[c.pid] or nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if info then
|
||||||
|
c.single_instance_id = info.hash
|
||||||
|
if info.rules then
|
||||||
|
gtable.crush(props, info.rules)
|
||||||
|
end
|
||||||
|
table.insert(callbacks, info.callback)
|
||||||
|
table.insert(info.instances, c)
|
||||||
|
|
||||||
|
-- Prevent apps with multiple clients from re-using this too often in
|
||||||
|
-- the first 30 seconds before the PID is cleared.
|
||||||
|
aspawn.single_instance_manager.by_pid[c.pid] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- The rule source for clients spawned by `awful.spawn.once` and `single_instance`.
|
||||||
|
--
|
||||||
|
-- **Has priority over:**
|
||||||
|
--
|
||||||
|
-- * `awful.rules`
|
||||||
|
--
|
||||||
|
-- **Depends on:**
|
||||||
|
--
|
||||||
|
-- * `awful.spawn`
|
||||||
|
--
|
||||||
|
-- @rulesources awful.spawn_once
|
||||||
|
|
||||||
|
module.add_rule_source("awful.spawn_once", apply_singleton_rules, {"awful.spawn"}, {"awful.rules"})
|
||||||
|
|
||||||
|
local function add_to_tag(c, t)
|
||||||
|
if not t then return end
|
||||||
|
|
||||||
|
local tags = c:tags()
|
||||||
|
table.insert(tags, t)
|
||||||
|
c:tags(tags)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Extra rules properties.
|
||||||
|
--
|
||||||
|
-- These properties are used in the rules only and are not sent to the client
|
||||||
|
-- afterward.
|
||||||
|
--
|
||||||
|
-- To add a new properties, just do:
|
||||||
|
--
|
||||||
|
-- function ruled.client.extra_properties.my_new_property(c, value, props)
|
||||||
|
-- -- do something
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- By default, the table has the following functions:
|
||||||
|
--
|
||||||
|
-- * geometry
|
||||||
|
-- * placement
|
||||||
|
--
|
||||||
|
-- @tfield table ruled.client.extra_properties
|
||||||
|
module.extra_properties = {}
|
||||||
|
|
||||||
|
--- Extra high priority properties.
|
||||||
|
--
|
||||||
|
-- Some properties, such as anything related to tags, geometry or focus, will
|
||||||
|
-- cause a race condition if set in the main property section. This is why
|
||||||
|
-- they have a section for them.
|
||||||
|
--
|
||||||
|
-- To add a new properties, just do:
|
||||||
|
--
|
||||||
|
-- function ruled.client.high_priority_properties.my_new_property(c, value, props)
|
||||||
|
-- -- do something
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- By default, the table has the following functions:
|
||||||
|
--
|
||||||
|
-- * tag
|
||||||
|
-- * new_tag
|
||||||
|
--
|
||||||
|
-- @tfield table ruled.client.high_priority_properties
|
||||||
|
module.high_priority_properties = {}
|
||||||
|
|
||||||
|
--- Delayed properties.
|
||||||
|
-- Properties applied after all other categories.
|
||||||
|
-- @tfield table ruled.client.delayed_properties
|
||||||
|
-- By default, the table has the following functions:
|
||||||
|
--
|
||||||
|
-- * switch_to_tags
|
||||||
|
module.delayed_properties = {}
|
||||||
|
|
||||||
|
local force_ignore = {
|
||||||
|
titlebars_enabled=true, focus=true, screen=true, x=true,
|
||||||
|
y=true, width=true, height=true, geometry=true,placement=true,
|
||||||
|
border_width=true,floating=true,size_hints_honor=true
|
||||||
|
}
|
||||||
|
|
||||||
|
function module.high_priority_properties.tag(c, value, props)
|
||||||
|
if value then
|
||||||
|
if type(value) == "string" then
|
||||||
|
local name = value
|
||||||
|
value = atag.find_by_name(c.screen, value)
|
||||||
|
if not value and not props.screen then
|
||||||
|
value = atag.find_by_name(nil, name)
|
||||||
|
end
|
||||||
|
if not value then
|
||||||
|
gdebug.print_error("ruled.client-rule specified "
|
||||||
|
.. "tag = '" .. name .. "', but no such tag exists")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- In case the tag has been forced to another screen, move the client
|
||||||
|
if c.screen ~= value.screen then
|
||||||
|
c.screen = value.screen
|
||||||
|
props.screen = value.screen -- In case another rule query it
|
||||||
|
end
|
||||||
|
|
||||||
|
c:tags{ value }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.delayed_properties.switch_to_tags(c, value)
|
||||||
|
if not value then return end
|
||||||
|
atag.viewmore(c:tags(), c.screen)
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.delayed_properties.switchtotag(c, value)
|
||||||
|
gdebug.deprecate("Use switch_to_tags instead of switchtotag", {deprecated_in=5})
|
||||||
|
|
||||||
|
module.delayed_properties.switch_to_tags(c, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.extra_properties.geometry(c, _, props)
|
||||||
|
local cur_geo = c:geometry()
|
||||||
|
|
||||||
|
local new_geo = type(props.geometry) == "function"
|
||||||
|
and props.geometry(c, props) or props.geometry or {}
|
||||||
|
|
||||||
|
for _, v in ipairs {"x", "y", "width", "height"} do
|
||||||
|
new_geo[v] = type(props[v]) == "function" and props[v](c, props)
|
||||||
|
or props[v] or new_geo[v] or cur_geo[v]
|
||||||
|
end
|
||||||
|
|
||||||
|
c:geometry(new_geo) --TODO use request::geometry
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.high_priority_properties.new_tag(c, value, props)
|
||||||
|
local ty = type(value)
|
||||||
|
local t = nil
|
||||||
|
|
||||||
|
if ty == "boolean" then
|
||||||
|
-- Create a new tag named after the client class
|
||||||
|
t = atag.add(c.class or "N/A", {screen=c.screen, volatile=true})
|
||||||
|
elseif ty == "string" then
|
||||||
|
-- Create a tag named after "value"
|
||||||
|
t = atag.add(value, {screen=c.screen, volatile=true})
|
||||||
|
elseif ty == "table" then
|
||||||
|
-- Assume a table of tags properties. Set the right screen, but
|
||||||
|
-- avoid editing the original table
|
||||||
|
local values = value.screen and value or gtable.clone(value)
|
||||||
|
values.screen = values.screen or c.screen
|
||||||
|
|
||||||
|
t = atag.add(value.name or c.class or "N/A", values)
|
||||||
|
|
||||||
|
-- In case the tag has been forced to another screen, move the client
|
||||||
|
c.screen = t.screen
|
||||||
|
props.screen = t.screen -- In case another rule query it
|
||||||
|
else
|
||||||
|
assert(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
add_to_tag(c, t)
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.extra_properties.placement(c, value, props)
|
||||||
|
-- Avoid problems
|
||||||
|
if capi.awesome.startup and
|
||||||
|
(c.size_hints.user_position or c.size_hints.program_position) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local ty = type(value)
|
||||||
|
|
||||||
|
local args = {
|
||||||
|
honor_workarea = props.honor_workarea ~= false,
|
||||||
|
honor_padding = props.honor_padding ~= false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ty == "function" or (ty == "table" and
|
||||||
|
getmetatable(value) and getmetatable(value).__call
|
||||||
|
) then
|
||||||
|
value(c, args)
|
||||||
|
elseif ty == "string" and a_place[value] then
|
||||||
|
a_place[value](c, args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.high_priority_properties.tags(c, value, props)
|
||||||
|
local current = c:tags()
|
||||||
|
|
||||||
|
local tags, s = {}, nil
|
||||||
|
|
||||||
|
for _, t in ipairs(value) do
|
||||||
|
if type(t) == "string" then
|
||||||
|
t = atag.find_by_name(c.screen, t)
|
||||||
|
end
|
||||||
|
|
||||||
|
if t and ((not s) or t.screen == s) then
|
||||||
|
table.insert(tags, t)
|
||||||
|
s = s or t.screen
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if s and s ~= c.screen then
|
||||||
|
c.screen = s
|
||||||
|
props.screen = s -- In case another rule query it
|
||||||
|
end
|
||||||
|
|
||||||
|
if #current == 0 or (value[1] and value[1].screen ~= current[1].screen) then
|
||||||
|
c:tags(tags)
|
||||||
|
else
|
||||||
|
c:tags(gtable.merge(current, tags))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Apply properties and callbacks to a client.
|
||||||
|
-- @client c The client.
|
||||||
|
-- @tab props Properties to apply.
|
||||||
|
-- @tab[opt] callbacks Callbacks to apply.
|
||||||
|
-- @staticfct ruled.client.execute
|
||||||
|
-- @request client titlebars rules granted The `titlebars_enabled` is set in the
|
||||||
|
-- rules.
|
||||||
|
|
||||||
|
crules._execute = function(_, c, props, callbacks)
|
||||||
|
|
||||||
|
-- Set the default buttons and keys
|
||||||
|
local btns = amouse._get_client_mousebindings()
|
||||||
|
local keys = akeyboard._get_client_keybindings()
|
||||||
|
props.keys = props.keys or keys
|
||||||
|
props.buttons = props.buttons or btns
|
||||||
|
|
||||||
|
-- Border width will also cause geometry related properties to fail
|
||||||
|
if props.border_width then
|
||||||
|
c.border_width = type(props.border_width) == "function" and
|
||||||
|
props.border_width(c, props) or props.border_width
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This has to be done first, as it will impact geometry related props.
|
||||||
|
if props.titlebars_enabled and (type(props.titlebars_enabled) ~= "function"
|
||||||
|
or props.titlebars_enabled(c,props)) then
|
||||||
|
c:emit_signal("request::titlebars", "rules", {properties=props})
|
||||||
|
c._request_titlebars_called = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Size hints will be re-applied when setting width/height unless it is
|
||||||
|
-- disabled first
|
||||||
|
if props.size_hints_honor ~= nil then
|
||||||
|
c.size_hints_honor = type(props.size_hints_honor) == "function" and props.size_hints_honor(c,props)
|
||||||
|
or props.size_hints_honor
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Geometry will only work if floating is true, otherwise the "saved"
|
||||||
|
-- geometry will be restored.
|
||||||
|
if props.floating ~= nil then
|
||||||
|
c.floating = type(props.floating) == "function" and props.floating(c,props)
|
||||||
|
or props.floating
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Before requesting a tag, make sure the screen is right
|
||||||
|
if props.screen then
|
||||||
|
c.screen = type(props.screen) == "function" and capi.screen[props.screen(c,props)]
|
||||||
|
or capi.screen[props.screen]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Some properties need to be handled first. For example, many properties
|
||||||
|
-- require that the client is tagged, this isn't yet the case.
|
||||||
|
for prop, handler in pairs(module.high_priority_properties) do
|
||||||
|
local value = props[prop]
|
||||||
|
if value ~= nil then
|
||||||
|
if type(value) == "function" then
|
||||||
|
value = value(c, props)
|
||||||
|
end
|
||||||
|
handler(c, value, props)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Make sure the tag is selected before the main rules are called.
|
||||||
|
-- Otherwise properties like "urgent" or "focus" may fail (if they were
|
||||||
|
-- overridden by other callbacks).
|
||||||
|
-- Previously this was done in a second client.manage callback, but caused
|
||||||
|
-- a race condition where the order of modules being loaded would change
|
||||||
|
-- the outcome.
|
||||||
|
c:emit_signal("request::tag", nil, {reason="rules", screen = c.screen})
|
||||||
|
|
||||||
|
-- By default, rc.lua uses no_overlap+no_offscreen placement. This has to
|
||||||
|
-- be executed before x/y/width/height/geometry as it would otherwise
|
||||||
|
-- always override the user specified position with the default rule.
|
||||||
|
if props.placement then
|
||||||
|
-- It may be a function, so this one doesn't execute it like others
|
||||||
|
module.extra_properties.placement(c, props.placement, props)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Handle the geometry (since tags and screen are set).
|
||||||
|
if props.height or props.width or props.x or props.y or props.geometry then
|
||||||
|
module.extra_properties.geometry(c, nil, props)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply the remaining properties (after known race conditions are handled).
|
||||||
|
for property, value in pairs(props) do
|
||||||
|
if property ~= "focus" and property ~= "shape" and type(value) == "function" then
|
||||||
|
value = value(c, props)
|
||||||
|
end
|
||||||
|
|
||||||
|
local ignore = module.high_priority_properties[property] or
|
||||||
|
module.delayed_properties[property] or force_ignore[property]
|
||||||
|
|
||||||
|
if not ignore then
|
||||||
|
if module.extra_properties[property] then
|
||||||
|
module.extra_properties[property](c, value, props)
|
||||||
|
elseif type(c[property]) == "function" then
|
||||||
|
c[property](c, value)
|
||||||
|
else
|
||||||
|
c[property] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply all callbacks.
|
||||||
|
if callbacks then
|
||||||
|
for _, callback in pairs(callbacks) do
|
||||||
|
protected_call(callback, c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply the delayed properties
|
||||||
|
for prop, handler in pairs(module.delayed_properties) do
|
||||||
|
if not force_ignore[prop] then
|
||||||
|
local value = props[prop]
|
||||||
|
if value ~= nil then
|
||||||
|
if type(value) == "function" then
|
||||||
|
value = value(c, props)
|
||||||
|
end
|
||||||
|
handler(c, value, props)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Do this at last so we do not erase things done by the focus signal.
|
||||||
|
if props.focus and (type(props.focus) ~= "function" or props.focus(c)) then
|
||||||
|
c:emit_signal('request::activate', "rules", {raise=not capi.awesome.startup})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.execute(...) crules:_execute(...) end
|
||||||
|
|
||||||
|
-- TODO v5 deprecate this
|
||||||
|
function module.completed_with_payload_callback(c, props, callbacks)
|
||||||
|
module.execute(c, props, callbacks)
|
||||||
|
end
|
||||||
|
|
||||||
|
gobject._setup_class_signals(module)
|
||||||
|
|
||||||
|
capi.client.connect_signal("request::manage", module.apply)
|
||||||
|
|
||||||
|
-- Request rules to be added **after** all modules are loaded, but before the
|
||||||
|
-- clients are managed. This allows module to listen to rules being added and
|
||||||
|
-- either modify them or add their own in the right order.
|
||||||
|
local function request_rules()
|
||||||
|
module.emit_signal("request::rules")
|
||||||
|
end
|
||||||
|
|
||||||
|
capi.client.connect_signal("scanning", request_rules)
|
||||||
|
|
||||||
|
--@DOC_rule_COMMON@
|
||||||
|
|
||||||
|
return setmetatable(module, {
|
||||||
|
__newindex = function(_, k, v)
|
||||||
|
if k == "rules" then
|
||||||
|
gdebug.deprecate(
|
||||||
|
"Use ruled.client.append_rules instead awful.rules.rules",
|
||||||
|
{deprecated_in=5}
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Clearing the rule was supported, so it still has to be. This is
|
||||||
|
-- a bad idea. There is no plan to make this API public.
|
||||||
|
if not next(v) then
|
||||||
|
-- It isn't possible to just set it to {}, there is other
|
||||||
|
-- references to the table.
|
||||||
|
for k2 in pairs(crules._matching_rules["awful.rules"]) do
|
||||||
|
crules._matching_rules["awful.rules"][k2] = nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
crules:append_rules("awful.rules", v)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
rawset(k, v)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
__index = function(_, k)
|
||||||
|
if k == "rules" then
|
||||||
|
gdebug.deprecate(
|
||||||
|
"Accessing `ruled.rules` isn't recommended, to modify rules, "..
|
||||||
|
"use `ruled.client.remove_rule()` and add a new one.",
|
||||||
|
{deprecated_in=5}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not crules._matching_rules["awful.rules"] then
|
||||||
|
crules:add_matching_rules("awful.rules", {}, {}, {})
|
||||||
|
end
|
||||||
|
|
||||||
|
return crules._matching_rules["awful.rules"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -1 +1,3 @@
|
||||||
return {}
|
return {
|
||||||
|
client = require("ruled.client");
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
local timer = require("gears.timer")
|
local timer = require("gears.timer")
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
local gtable = require("gears.table")
|
local gtable = require("gears.table")
|
||||||
|
local gdebug = require("gears.debug")
|
||||||
|
|
||||||
local runner = {
|
local runner = {
|
||||||
quit_awesome_on_error = os.getenv('TEST_PAUSE_ON_ERRORS') ~= '1',
|
quit_awesome_on_error = os.getenv('TEST_PAUSE_ON_ERRORS') ~= '1',
|
||||||
|
@ -11,10 +12,16 @@ local verbose = os.getenv('VERBOSE') == '1'
|
||||||
-- Helpers.
|
-- Helpers.
|
||||||
|
|
||||||
--- Add some rules to awful.rules.rules, after the defaults.
|
--- Add some rules to awful.rules.rules, after the defaults.
|
||||||
|
local dep = gdebug.deprecate
|
||||||
|
gdebug.deprecate = function() end
|
||||||
local default_rules = gtable.clone(awful.rules.rules)
|
local default_rules = gtable.clone(awful.rules.rules)
|
||||||
|
gdebug.deprecate = dep
|
||||||
|
|
||||||
runner.add_to_default_rules = function(r)
|
runner.add_to_default_rules = function(r)
|
||||||
|
gdebug.deprecate = function() end
|
||||||
awful.rules.rules = gtable.clone(default_rules)
|
awful.rules.rules = gtable.clone(default_rules)
|
||||||
table.insert(awful.rules.rules, r)
|
table.insert(awful.rules.rules, r)
|
||||||
|
gdebug.deprecate = dep
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Was the runner started already?
|
-- Was the runner started already?
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
local runner = require("_runner")
|
local runner = require("_runner")
|
||||||
local titlebar = require("awful.titlebar")
|
local titlebar = require("awful.titlebar")
|
||||||
local rules = require("awful.rules")
|
local rules = require("ruled.client")
|
||||||
local spawn = require("awful.spawn")
|
local spawn = require("awful.spawn")
|
||||||
|
local gdebug = require("gears.debug")
|
||||||
|
|
||||||
local tiny_client_code_template = [[
|
local tiny_client_code_template = [[
|
||||||
pcall(require, 'luarocks.loader')
|
pcall(require, 'luarocks.loader')
|
||||||
|
@ -25,7 +26,10 @@ window.decorated = false
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Use the test client props
|
-- Use the test client props
|
||||||
|
local dep = gdebug.deprecate
|
||||||
|
gdebug.deprecate = function() end
|
||||||
rules.rules = {}
|
rules.rules = {}
|
||||||
|
gdebug.deprecate = dep
|
||||||
|
|
||||||
-- Too bad there's no way to disconnect the rc.lua request::titlebars function
|
-- Too bad there's no way to disconnect the rc.lua request::titlebars function
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue