From da8daa8dfcbb21280d9ea40a772be82336246b22 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sat, 29 Jun 2019 23:10:34 -0400 Subject: [PATCH 01/20] debug: Allow "deprecated_in" for class deprecation. --- lib/gears/debug.lua | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/gears/debug.lua b/lib/gears/debug.lua index 4b6e328df..54bbeba3f 100644 --- a/lib/gears/debug.lua +++ b/lib/gears/debug.lua @@ -130,12 +130,23 @@ end --- Create a class proxy with deprecation messages. -- This is useful when a class has moved somewhere else. --- @tparam table fallback The new class --- @tparam string old_name The old class name --- @tparam string new_name The new class name +-- @tparam table fallback The new class. +-- @tparam string old_name The old class name. +-- @tparam string new_name The new class name. +-- @tparam[opt={}] args The name. +-- @tparam[opt] number args.deprecated_in The version which deprecated this +-- class. -- @treturn table A proxy class. -- @staticfct gears.debug.deprecate_class -function debug.deprecate_class(fallback, old_name, new_name) +function debug.deprecate_class(fallback, old_name, new_name, args) + args = args or {} + if args.deprecated_in then + local dep_ver = "v" .. tostring(args.deprecated_in) + if awesome.version < dep_ver then + return fallback + end + end + local message = old_name.." has been renamed to "..new_name local function call(_,...) From 6ee294fd5ab68b5a969388f2bfdaa4ca29e031a7 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 6 Oct 2019 19:22:17 -0400 Subject: [PATCH 02/20] doc: Make sure the ruled module init.lua is ignored. This has to be in its own commit otherwise Travis will fail. This is because it will keep the file in the build directory when iterating all commits. Then `ldoc` will fail because the file doesn't have documentation. If `config.ld` is updated first, then it will fail because `ruled/init.lua` doesn't exist yet. When it is done in a separate commit, then `config.ld` is already updated and comes with `init.lua`. --- docs/config.ld | 1 + lib/ruled/init.lua | 1 + 2 files changed, 2 insertions(+) create mode 100644 lib/ruled/init.lua diff --git a/docs/config.ld b/docs/config.ld index 35faea832..1d25384f4 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -471,6 +471,7 @@ file = { '../lib/naughty/constants.lua', '../lib/naughty/dbus.lua', '../lib/beautiful/gtk.lua', + '../lib/ruled/init.lua', -- Ignore some parts of the widget library '../lib/awful/widget/init.lua', diff --git a/lib/ruled/init.lua b/lib/ruled/init.lua new file mode 100644 index 000000000..a56470754 --- /dev/null +++ b/lib/ruled/init.lua @@ -0,0 +1 @@ +return {} From 2b11fcfd1c4d145990386d68618ca3febd2f387b Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 18 Aug 2019 04:39:01 -0400 Subject: [PATCH 03/20] doc: Add a section for rules matching properties. It also change the text of "clientproperties" to be more generic so it can apply to other type of rules. --- docs/config.ld | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/config.ld b/docs/config.ld index 1d25384f4..fff56a873 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -93,7 +93,9 @@ new_type("rulecomponent", "Rule components", false, "Type") -- Filter functions for the taglist/tasklist/layoutlist new_type("filterfunction", "List filters", false) -- Extra client properties available only in awful.rules/spawn constructs -new_type("clientruleproperty", "Extra properties available in awful.rules and awful.spawn", false, "Type") +new_type("clientruleproperty", "Extra properties available in the rules", false, "Type") +-- Extra *matching* properties for rules. +new_type("matchingproperty", "Extra matching properties used in rules", false, "Type") -- Simulate the default "params" parser format, except the optional "[]" section -- needs a space. From 104eac0bece96a14017ffed5e63defe9058d0893 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 18 Aug 2019 01:53:07 -0400 Subject: [PATCH 04/20] doc: Update the ldoc config to handle the new ruled module. --- docs/config.ld | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/config.ld b/docs/config.ld index fff56a873..37fa7a8ac 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -427,7 +427,8 @@ sort_modules=true -- Add more project level (left side index) types. new_type("coreclassmod", "Core_components" , true) new_type("inputmodule" , "Input handling" , true) -new_type("widgetmod" , "Widgets" , true) +new_type("ruleslib" , "Declarative_rules", true) +new_type("widgetmod" , "Widgets" , true) new_type("containermod", "Widget_containers", true) new_type("layoutmod" , "Widget_layouts" , true) new_type("popupmod" , "Popups_and_bars" , true) @@ -753,6 +754,8 @@ local display_type = { beautiful = true, field = true, deprecatedproperty = true, + clientruleproperty = true, + matchingproperty = true, } -- Show return values. From fc526d2aefba86a8639a6a4952156728b23505cc Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 18 Aug 2019 19:16:21 -0400 Subject: [PATCH 05/20] build: Configure the `ruled` module dependency graph. It is the topmost module, it can use everything, but nothing can use it. --- build-utils/check_for_invalid_requires.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/build-utils/check_for_invalid_requires.lua b/build-utils/check_for_invalid_requires.lua index 741d1ad37..1c9cd29c7 100755 --- a/build-utils/check_for_invalid_requires.lua +++ b/build-utils/check_for_invalid_requires.lua @@ -34,7 +34,10 @@ local allowed_deps = { wibox = true, -- Necessary to lazy-load the deprecated modules. - ["awful.*"] = true + ["awful.*"] = true, + + -- For legacy reasons. + ruled = true }, naughty = { awful = true, @@ -50,6 +53,14 @@ local allowed_deps = { lgi = true, wibox = true, }, + ruled = { + awful = true, + beautiful = true, + gears = true, + lgi = true, + wibox = true, + naughty = true, + }, -- TODO: Get rid of these ["gears.surface"] = { ["wibox.hierarchy"] = true }, } From 84e6bbb86d176b71bf52832e1bf233478e61045e Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 18 Aug 2019 19:27:50 -0400 Subject: [PATCH 06/20] doc: Improve the common documentation between all rules modules. It was missing lesser/greater and the `id` type wasn't rendered properly. --- docs/common/rule.ldoc | 20 +++++++++++++++++++- docs/config.ld | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/common/rule.ldoc b/docs/common/rule.ldoc index ec0fa7a54..ebab28c41 100644 --- a/docs/common/rule.ldoc +++ b/docs/common/rule.ldoc @@ -50,6 +50,24 @@ -- @see rule -- @see except +--- A table which content will be compared to the target object current properties. +-- +-- The comparison will be made using the lesser (`<`) operator. +-- +-- @rulecomponent rule_lesser +-- @param table +-- @see rule +-- @see except + +--- A table which content will be compared to the target object current properties. +-- +-- The comparison will be made using the lesser (`>`) operator. +-- +-- @rulecomponent rule_greater +-- @param table +-- @see rule +-- @see except + --- An identifier for this rule. -- -- It can be anything. It will be compared with the `==` operator. Strings are @@ -60,4 +78,4 @@ -- modify or disable a rule. -- -- @rulecomponent id --- @param table|string|number|function +-- @tparam table|string|number|function id diff --git a/docs/config.ld b/docs/config.ld index 37fa7a8ac..afceff201 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -756,6 +756,7 @@ local display_type = { deprecatedproperty = true, clientruleproperty = true, matchingproperty = true, + rulecomponent = true, } -- Show return values. From 39c90b830315dd2f3f9468d3fa5b79e2f8c38941 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 19 Jan 2020 02:36:33 -0500 Subject: [PATCH 07/20] hotkeys: Port away from awful.rules --- lib/awful/hotkeys_popup/widget.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index b0ab3b76f..8c25148ed 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -17,6 +17,7 @@ local wibox = require("wibox") local beautiful = require("beautiful") local dpi = beautiful.xresources.apply_dpi +local matcher = require("gears.matcher")() -- Stripped copy of this module https://github.com/copycat-killer/lain/blob/master/util/markup.lua: local markup = {} @@ -522,7 +523,7 @@ function widget.new(args) if group_name==group and ( data.rule or data.rule_any or data.except or data.except_any ) then - if not c or not awful.rules.matches(c, { + if not c or not matcher:matches_rule(c, { rule=data.rule, rule_any=data.rule_any, except=data.except, From 71c230035c47de30edcb53232d108495ad1b1bb9 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 6 Oct 2019 19:24:56 -0400 Subject: [PATCH 08/20] 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. --- docs/89-NEWS.md | 3 + docs/90-FAQ.md | 16 +- docs/common/rule.ldoc | 2 +- lib/awful/hotkeys_popup/keys/tmux.lua | 2 +- lib/awful/menu.lua | 4 +- lib/awful/rules.lua | 667 +----------------------- lib/ruled/client.lua | 712 ++++++++++++++++++++++++++ lib/ruled/init.lua | 4 +- tests/_runner.lua | 7 + tests/test-titlebar.lua | 6 +- 10 files changed, 749 insertions(+), 674 deletions(-) create mode 100644 lib/ruled/client.lua diff --git a/docs/89-NEWS.md b/docs/89-NEWS.md index 7089f99fa..1b5b93d90 100644 --- a/docs/89-NEWS.md +++ b/docs/89-NEWS.md @@ -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 not affect most users unless you had mitigated the bug it fixes by adding 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`. # Awesome window manager framework version 4.3 changes diff --git a/docs/90-FAQ.md b/docs/90-FAQ.md index 9257632df..fa8d5b83f 100644 --- a/docs/90-FAQ.md +++ b/docs/90-FAQ.md @@ -147,7 +147,7 @@ additions to the path you want to use in Awesome. ### How to remove gaps between windows? 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. 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? 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 -certain clients, you can use `awful.rules` to set this property only for certain +`ruled.client.rules` table in your config. If you want a titlebar only on +certain clients, you can use `ruled.client` to set this property only for certain clients. ### How to toggle titlebar visibility? @@ -208,7 +208,7 @@ their last invocation. The default key binding to toggle maximized state is "Mod4 + m". 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, keys = clientkeys, @@ -267,14 +267,14 @@ terminal output you can use the following to match clients in Awesome: |--- name 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. ### 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 -@{awful.rules.rules|documentation}. +@{ruled.client.rules|documentation}. ### 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? -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 diff --git a/docs/common/rule.ldoc b/docs/common/rule.ldoc index ebab28c41..082458a3a 100644 --- a/docs/common/rule.ldoc +++ b/docs/common/rule.ldoc @@ -61,7 +61,7 @@ --- 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 -- @param table diff --git a/lib/awful/hotkeys_popup/keys/tmux.lua b/lib/awful/hotkeys_popup/keys/tmux.lua index e3b771e03..787294f42 100644 --- a/lib/awful/hotkeys_popup/keys/tmux.lua +++ b/lib/awful/hotkeys_popup/keys/tmux.lua @@ -19,7 +19,7 @@ local tmux = {} -- 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! -- @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. function tmux.add_rules_for_terminal(rule) for group_name, group_data in pairs({ diff --git a/lib/awful/menu.lua b/lib/awful/menu.lua index 9cfe6b10c..f4e8ca0a2 100644 --- a/lib/awful/menu.lua +++ b/lib/awful/menu.lua @@ -687,13 +687,13 @@ end -- -- a particular rule. -- -- Bound to a key, it can be used to select from dozens of terminals open on -- -- 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. -- -- function terminal_menu () -- terms = {} -- 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] = -- {c.name, -- function() diff --git a/lib/awful/rules.lua b/lib/awful/rules.lua index 2fe0ad249..b685d288a 100644 --- a/lib/awful/rules.lua +++ b/lib/awful/rules.lua @@ -1,668 +1,15 @@ --------------------------------------------------------------------------- ---- 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: --- --- { 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@ +--- This module has been moved to `ruled.client` -- -- @author Julien Danjou <julien@danjou.info> -- @copyright 2009 Julien Danjou -- @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 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 = {} - ---- This is the global rules table. -rules.rules = {} - -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 +return gdebug.deprecate_class( + require("ruled.client"), + "awful.rules", + "ruled.client", + { deprecated_in = 5} +) diff --git a/lib/ruled/client.lua b/lib/ruled/client.lua new file mode 100644 index 000000000..be848fdf8 --- /dev/null +++ b/lib/ruled/client.lua @@ -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 diff --git a/lib/ruled/init.lua b/lib/ruled/init.lua index a56470754..32e8d1ccd 100644 --- a/lib/ruled/init.lua +++ b/lib/ruled/init.lua @@ -1 +1,3 @@ -return {} +return { + client = require("ruled.client"); +} diff --git a/tests/_runner.lua b/tests/_runner.lua index 688ebe1cc..5b357773c 100644 --- a/tests/_runner.lua +++ b/tests/_runner.lua @@ -1,6 +1,7 @@ local timer = require("gears.timer") local awful = require("awful") local gtable = require("gears.table") +local gdebug = require("gears.debug") local runner = { quit_awesome_on_error = os.getenv('TEST_PAUSE_ON_ERRORS') ~= '1', @@ -11,10 +12,16 @@ local verbose = os.getenv('VERBOSE') == '1' -- Helpers. --- 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) +gdebug.deprecate = dep + runner.add_to_default_rules = function(r) + gdebug.deprecate = function() end awful.rules.rules = gtable.clone(default_rules) table.insert(awful.rules.rules, r) + gdebug.deprecate = dep end -- Was the runner started already? diff --git a/tests/test-titlebar.lua b/tests/test-titlebar.lua index f577eca5d..9359ce8b9 100644 --- a/tests/test-titlebar.lua +++ b/tests/test-titlebar.lua @@ -1,7 +1,8 @@ local runner = require("_runner") local titlebar = require("awful.titlebar") -local rules = require("awful.rules") +local rules = require("ruled.client") local spawn = require("awful.spawn") +local gdebug = require("gears.debug") local tiny_client_code_template = [[ pcall(require, 'luarocks.loader') @@ -25,7 +26,10 @@ window.decorated = false } -- Use the test client props +local dep = gdebug.deprecate +gdebug.deprecate = function() end rules.rules = {} +gdebug.deprecate = dep -- Too bad there's no way to disconnect the rc.lua request::titlebars function From 171a14dbc82c39e8597a91de79580699f10fca8e Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 6 Oct 2019 21:53:52 -0400 Subject: [PATCH 09/20] tests: Port the hardcoded awful.rules test to the sequence template. --- .../sequences/client_rules/floating.lua | 55 ++++++++++++ .../sequences/client_rules/maximized.lua | 38 +++++++++ .../sequences/client_rules/new_tag.lua | 68 +++++++++++++++ .../sequences/client_rules/placement.lua | 43 ++++++++++ .../sequences/client_rules/screens.lua | 85 +++++++++++++++++++ .../sequences/client_rules/switch_to_tags.lua | 40 +++++++++ .../examples/sequences/client_rules/tags.lua | 51 +++++++++++ 7 files changed, 380 insertions(+) create mode 100644 tests/examples/sequences/client_rules/floating.lua create mode 100644 tests/examples/sequences/client_rules/maximized.lua create mode 100644 tests/examples/sequences/client_rules/new_tag.lua create mode 100644 tests/examples/sequences/client_rules/placement.lua create mode 100644 tests/examples/sequences/client_rules/screens.lua create mode 100644 tests/examples/sequences/client_rules/switch_to_tags.lua create mode 100644 tests/examples/sequences/client_rules/tags.lua diff --git a/tests/examples/sequences/client_rules/floating.lua b/tests/examples/sequences/client_rules/floating.lua new file mode 100644 index 000000000..cef528bbb --- /dev/null +++ b/tests/examples/sequences/client_rules/floating.lua @@ -0,0 +1,55 @@ + --DOC_GEN_IMAGE --DOC_NO_USAGE +local module = ... --DOC_HIDE +local ruled = {client = require("ruled.client") } --DOC_HIDE +local awful = {tag = require("awful.tag"), layout = require("awful.layout")} --DOC_HIDE +awful.placement = require("awful.placement") --DOC_HIDE +require("awful.ewmh") --DOC_HIDE +screen[1]:fake_resize(0, 0, 1280, 720) --DOC_HIDE +awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, screen[1], awful.layout.suit.corner.nw) --DOC_HIDE + +function awful.spawn(name) --DOC_HIDE + client.gen_fake{class = name, name = name, x = 10, y=10, width = 60, height =50} --DOC_HIDE +end --DOC_HIDE + +client.connect_signal("request::rules", function() --DOC_HIDE + ruled.client.append_rule { + rule = { class = "mplayer" }, + properties = { + floating = true, + placement = awful.placement.centered, + width = 640, + height = 480, + }, + } +end) --DOC_HIDE + +client.emit_signal("request::rules") --DOC_HIDE + +--DOC_NEWLINE + +module.add_event("Spawn xterm", function() --DOC_HIDE + -- Spawn xterm + for _=1, 5 do + awful.spawn("xterm") + end + +end) --DOC_HIDE + +--DOC_NEWLINE + +module.display_tags() --DOC_HIDE + +module.add_event("Spawn mplayer", function() --DOC_HIDE + -- Spawn mplayer + awful.spawn("mplayer") + + for _, c in ipairs(client.get()) do --DOC_HIDE + assert(#c:tags() == 1) --DOC_HIDE + assert(c.floating == (c.class == "mplayer")) --DOC_HIDE + end --DOC_HIDE +end) --DOC_HIDE + +module.display_tags() --DOC_HIDE + +module.execute { display_screen = true , display_clients = true , --DOC_HIDE + display_label = false, display_client_name = true } --DOC_HIDE diff --git a/tests/examples/sequences/client_rules/maximized.lua b/tests/examples/sequences/client_rules/maximized.lua new file mode 100644 index 000000000..793afecc8 --- /dev/null +++ b/tests/examples/sequences/client_rules/maximized.lua @@ -0,0 +1,38 @@ + --DOC_GEN_IMAGE --DOC_NO_USAGE +local module = ... --DOC_HIDE +local ruled = {client = require("ruled.client") } --DOC_HIDE +local awful = {tag = require("awful.tag"), layout = require("awful.layout")} --DOC_HIDE +require("awful.ewmh") --DOC_HIDE +screen[1]:fake_resize(0, 0, 1280, 720) --DOC_HIDE +awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, screen[1], awful.layout.layouts[1]) --DOC_HIDE + +function awful.spawn(name) --DOC_HIDE + client.gen_fake{class = name, name = name, x = 10, y=10, width = 60, height =50} --DOC_HIDE +end --DOC_HIDE + +client.connect_signal("request::rules", function() --DOC_HIDE + ruled.client.append_rule { + rule = { class = "xterm" }, + properties = { + maximized_vertical = true, + maximized_horizontal = true + }, + } +end) --DOC_HIDE + +client.emit_signal("request::rules") --DOC_HIDE + +--DOC_NEWLINE + +module.add_event("Spawn xterm", function() --DOC_HIDE + -- Spawn xterm + awful.spawn("xterm") + + assert(client.get()[1].maximized_vertical ) --DOC_HIDE + assert(client.get()[1].maximized_horizontal) --DOC_HIDE +end) --DOC_HIDE + +module.display_tags() --DOC_HIDE + +module.execute { display_screen = true , display_clients = true , --DOC_HIDE + display_label = false, display_client_name = true } --DOC_HIDE diff --git a/tests/examples/sequences/client_rules/new_tag.lua b/tests/examples/sequences/client_rules/new_tag.lua new file mode 100644 index 000000000..350c2010d --- /dev/null +++ b/tests/examples/sequences/client_rules/new_tag.lua @@ -0,0 +1,68 @@ + --DOC_GEN_IMAGE --DOC_NO_USAGE +local module = ... --DOC_HIDE +local ruled = {client = require("ruled.client") } --DOC_HIDE +local awful = {tag = require("awful.tag"), layout = require("awful.layout")} --DOC_HIDE +require("awful.ewmh") --DOC_HIDE +screen[1]._resize {x = 0, width = 128, height = 96} --DOC_HIDE +awful.tag({ "one", "two", "three", "four", "five" }, screen[1], awful.layout.layouts[1]) --DOC_HIDE + + +function awful.spawn(name) --DOC_HIDE + client.gen_fake{class = name, name = name, x = 10, y=10, width = 60, height =50} --DOC_HIDE +end --DOC_HIDE + +module.display_tags() --DOC_HIDE + +client.connect_signal("request::rules", function() --DOC_HIDE + -- Create a new tags with some properties: + ruled.client.append_rule { + rule = { class = "firefox" }, + properties = { + switch_to_tags = true, + new_tag = { + name = "My_new_tag!", -- The tag name. + layout = awful.layout.suit.max, -- Set the tag layout. + volatile = true, -- Remove the tag when the client is closed. + } + } + } + +--DOC_NEWLINE + + -- Create a new tag with just a name: + ruled.client.append_rule { + rule = { class = "thunderbird" }, + properties = { + switch_to_tags = true, + new_tag = "JUST_A_NAME!", + } + } + +--DOC_NEWLINE + + -- Create a new tag using the client metadata: + ruled.client.append_rule { + rule = { class = "xterm" }, + properties = { + switch_to_tags = true, + new_tag = true, + } + } + +end) --DOC_HIDE + +client.emit_signal("request::rules") --DOC_HIDE + +--DOC_NEWLINE + +module.add_event("Spawn some apps", function() --DOC_HIDE + -- Spawn firefox + awful.spawn("firefox") + awful.spawn("thunderbird") + awful.spawn("xterm") +end) --DOC_HIDE + +module.display_tags() --DOC_HIDE + +module.execute { display_screen = false, display_clients = true , --DOC_HIDE + display_label = false, display_client_name = true } --DOC_HIDE diff --git a/tests/examples/sequences/client_rules/placement.lua b/tests/examples/sequences/client_rules/placement.lua new file mode 100644 index 000000000..ad3c1d912 --- /dev/null +++ b/tests/examples/sequences/client_rules/placement.lua @@ -0,0 +1,43 @@ + --DOC_GEN_IMAGE --DOC_NO_USAGE +local module = ... --DOC_HIDE +local ruled = {client = require("ruled.client") } --DOC_HIDE +local awful = {tag = require("awful.tag"), layout = require("awful.layout")} --DOC_HIDE +awful.placement = require("awful.placement") --DOC_HIDE +require("awful.ewmh") --DOC_HIDE +screen[1]:fake_resize(0, 0, 1280, 720) --DOC_HIDE +awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, screen[1], awful.layout.suit.corner.nw) --DOC_HIDE + +function awful.spawn(name) --DOC_HIDE + client.gen_fake{class = name, name = name, x = 10, y=10, width = 60, height =50} --DOC_HIDE +end --DOC_HIDE + +client.connect_signal("request::rules", function() --DOC_HIDE + ruled.client.append_rule { + rule = { class = "mplayer" }, + properties = { + floating = true, + placement = awful.placement.centered, + width = 640, + height = 480, + }, + } +end) --DOC_HIDE + +client.emit_signal("request::rules") --DOC_HIDE + +--DOC_NEWLINE + +module.add_event("Spawn mplayer", function() --DOC_HIDE + -- Spawn mplayer + awful.spawn("mplayer") + + for _, c in ipairs(client.get()) do --DOC_HIDE + assert(#c:tags() == 1) --DOC_HIDE + assert(c.floating == (c.class == "mplayer")) --DOC_HIDE + end --DOC_HIDE +end) --DOC_HIDE + +module.display_tags() --DOC_HIDE + +module.execute { display_screen = true , display_clients = true , --DOC_HIDE + display_label = false, display_client_name = true } --DOC_HIDE diff --git a/tests/examples/sequences/client_rules/screens.lua b/tests/examples/sequences/client_rules/screens.lua new file mode 100644 index 000000000..354f1b379 --- /dev/null +++ b/tests/examples/sequences/client_rules/screens.lua @@ -0,0 +1,85 @@ + --DOC_GEN_IMAGE --DOC_NO_USAGE +local module = ... --DOC_HIDE +local ruled = {client = require("ruled.client") } --DOC_HIDE +local awful = {tag = require("awful.tag"), layout = require("awful.layout")} --DOC_HIDE +awful.placement = require("awful.placement") --DOC_HIDE +require("awful.ewmh") --DOC_HIDE +screen[1]:fake_resize(0, 0, 1024, 768) --DOC_HIDE +screen.fake_add(1034, 0, 1024, 768).outputs = {["eVGA1"] = {mm_height=60, mm_width=80 }} --DOC_HIDE +screen.fake_add(2074, 0, 1024, 768).outputs = {["DVI1" ] = {mm_height=60, mm_width=80 }} --DOC_HIDE +awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, screen[1], awful.layout.suit.corner.nw) --DOC_HIDE +awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, screen[2], awful.layout.suit.corner.nw) --DOC_HIDE +awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, screen[3], awful.layout.suit.corner.nw) --DOC_HIDE + +function awful.spawn(name) --DOC_HIDE + client.gen_fake{class = name, name = name, x = 10, y=10, width = 60, height =50} --DOC_HIDE +end --DOC_HIDE + + mouse.coords {x = 2500, y = 100 } +assert(mouse.screen == screen[3]) --DOC_HIDE + +--DOC_NEWLINE + +client.connect_signal("request::rules", function() --DOC_HIDE + -- Screen by IDs: + ruled.client.append_rule { + rule_any = { + class = {"firefox"} + }, + properties = { + screen = 2, + tag = "1", --DOC_HIDE + width = 640, height =480, floating = true, --DOC_HIDE + }, + } +--DOC_NEWLINE + -- Screen by object: + ruled.client.append_rule { + rule_any = { + class = {"thunderbird"} + }, + properties = { + screen = mouse.screen, + tag = "1", --DOC_HIDE + width = 640, height =480, floating = true, --DOC_HIDE + }, + } +--DOC_NEWLINE + -- Screen by output name: + ruled.client.append_rule { + rule_any = { + class = {"xterm"} + }, + properties = { + screen = "LVDS1", + tag = "1", --DOC_HIDE + width = 640, height =480, floating = true, --DOC_HIDE + }, + } + +end) --DOC_HIDE + +client.emit_signal("request::rules") --DOC_HIDE + +--DOC_NEWLINE + +module.add_event("Spawn some applications", function() --DOC_HIDE + -- Spawn firefox, thunderbird and xterm + awful.spawn("firefox") + awful.spawn("thunderbird") + awful.spawn("xterm") + + assert(client.get()[1].screen == screen[2]) --DOC_HIDE + assert(client.get()[2].screen == screen[3]) --DOC_HIDE + assert(client.get()[3].screen == screen[1]) --DOC_HIDE + assert(client.get()[1]:tags()[1] == screen[2].selected_tag) --DOC_HIDE + assert(client.get()[2]:tags()[1] == screen[3].selected_tag) --DOC_HIDE + assert(client.get()[3]:tags()[1] == screen[1].selected_tag) --DOC_HIDE +end) --DOC_HIDE + +module.display_tags() --DOC_HIDE + +module.execute { display_screen = true , display_clients = true, --DOC_HIDE + display_label = true , display_client_name = true, --DOC_HIDE + display_mouse = true , --DOC_HIDE +} --DOC_HIDE diff --git a/tests/examples/sequences/client_rules/switch_to_tags.lua b/tests/examples/sequences/client_rules/switch_to_tags.lua new file mode 100644 index 000000000..8bb529a81 --- /dev/null +++ b/tests/examples/sequences/client_rules/switch_to_tags.lua @@ -0,0 +1,40 @@ + --DOC_GEN_IMAGE --DOC_NO_USAGE +local module = ... --DOC_HIDE +local ruled = {client = require("ruled.client") } --DOC_HIDE +local awful = {tag = require("awful.tag"), layout = require("awful.layout")} --DOC_HIDE +require("awful.ewmh") --DOC_HIDE +screen[1]._resize {x = 0, width = 128, height = 96} --DOC_HIDE +awful.tag({ "one", "two", "three", "four", "five" }, screen[1], awful.layout.layouts[1]) --DOC_HIDE + + +function awful.spawn(name) --DOC_HIDE + client.gen_fake{class = name, name = name, x = 10, y=10, width = 60, height =50} --DOC_HIDE +end --DOC_HIDE + +module.display_tags() --DOC_HIDE + +client.connect_signal("request::rules", function() --DOC_HIDE + -- Select tag by object reference: + ruled.client.append_rule { + rule = { class = "firefox" }, + properties = { + tag = screen[1].tags[4], + switch_to_tags = true + } + } + +end) --DOC_HIDE + +client.emit_signal("request::rules") --DOC_HIDE + +--DOC_NEWLINE + +module.add_event("Spawn xterm", function() --DOC_HIDE + -- Spawn firefox + awful.spawn("firefox") +end) --DOC_HIDE + +module.display_tags() --DOC_HIDE + +module.execute { display_screen = false, display_clients = true , --DOC_HIDE + display_label = false, display_client_name = true } --DOC_HIDE diff --git a/tests/examples/sequences/client_rules/tags.lua b/tests/examples/sequences/client_rules/tags.lua new file mode 100644 index 000000000..a284ed869 --- /dev/null +++ b/tests/examples/sequences/client_rules/tags.lua @@ -0,0 +1,51 @@ + --DOC_GEN_IMAGE --DOC_NO_USAGE +local module = ... --DOC_HIDE +local ruled = {client = require("ruled.client") } --DOC_HIDE +local awful = {tag = require("awful.tag"), layout = require("awful.layout")} --DOC_HIDE +require("awful.ewmh") --DOC_HIDE +screen[1]._resize {x = 0, width = 128, height = 96} --DOC_HIDE +awful.tag({ "one", "two", "three", "four", "five" }, screen[1], awful.layout.layouts[1]) --DOC_HIDE + + +function awful.spawn(name) --DOC_HIDE + client.gen_fake{class = name, name = name, x = 10, y=10, width = 60, height =50} --DOC_HIDE +end --DOC_HIDE + + +client.connect_signal("request::rules", function() --DOC_HIDE + -- Select tag by object reference: + ruled.client.append_rule { + rule_any = { + class = {"firefox"} + }, + properties = { + tag = screen[1].tags[3], + }, + } +--DOC_NEWLINE + -- Select tag by name: + ruled.client.append_rule { + rule_any = { + class = {"thunderbird"} + }, + properties = { + tag = "five", + }, + } + +end) --DOC_HIDE + +client.emit_signal("request::rules") --DOC_HIDE + +--DOC_NEWLINE + +module.add_event("Spawn xterm", function() --DOC_HIDE + -- Spawn firefox and thunderbird + awful.spawn("firefox") + awful.spawn("thunderbird") +end) --DOC_HIDE + +module.display_tags() --DOC_HIDE + +module.execute { display_screen = false, display_clients = true , --DOC_HIDE + display_label = false, display_client_name = true } --DOC_HIDE From b1a4b1dd9abb7557dfe9d22569edc428d1c54477 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 6 Oct 2019 21:18:40 -0400 Subject: [PATCH 10/20] doc: Add a flowchart for ruled.client. --- docs/diagrams/client_rules.dia | Bin 0 -> 4922 bytes docs/images/client_rules.svg | 4155 ++++++++++++++++++++++++++++++++ lib/ruled/client.lua | 5 + 3 files changed, 4160 insertions(+) create mode 100644 docs/diagrams/client_rules.dia create mode 100644 docs/images/client_rules.svg diff --git a/docs/diagrams/client_rules.dia b/docs/diagrams/client_rules.dia new file mode 100644 index 0000000000000000000000000000000000000000..c98db2e5e1e79676111e375b305f13d2edf63768 GIT binary patch literal 4922 zcmV-A6UFQwiwFP!000021MOW)bK6LgzUx;o)K_-7D(h{IyQ6!jCwe0`W+Qfb4?7nH zL_!jGKvDyOmbHid?UM;mw)g-A0w~y$i_vy8=@LFBRLIOPD<6OQ`O_jBeN6N9e6{>= zDHy*TrOWARHecR;xcu)w{_>-{{Q0MgKh5UJd;D{oCyNpO#BxpVK3v`v#r^wt?;ai= zSoXM1idD|C`G&32cmJPcS@I4Sy}SJBVl;Ywfmu={^x5{)q$u+F^`=Ni%Vd#$xV%oL z|G3Rpo8|1XTD4s_U1h6$^fAdkT>fxVzAoQwFY|8aIw!7upWLR`d7AvA{?Z&@-nY5* zeVXrIc5%O2&v8ldcz>{@<~sEEvo+gQYh1Lv{pp8a)DP8H+J5lmTF1UV{_rFQ9brS)qk3TQtX^9&R`D zS-O5Ub%&sdibS@M|X+sps@#Y~U3zu>LL870$V{_*ME zvwO0-{@-+3Y=!+xwtAS}C3!LWarEoz)8!W@1YMB%?8D`M^4+_&FCShF72(0{x?g?X zQ-*2jy&fCply_qPP8{lyI+*M0eUuypNtU-+`h=wX7KtO$L;!wZ)z~ousx5MwrHiZS zDqkKt4Sfq)LX|q^P|zp+qL~+##C&?`4p?{T{PwP>2NTT763c3BfO~D*fnBfiS(?8j z8fV;AGC2^!8E)F*t?yP3S4TY92IlP?nEPZl+qKOH61Dv86zQjfU(3Fp+FMh1D@qS_ zXWgDN``cn(j4l_+620=v(RzNnOtKpH_JmESb1+uR;utu6KDtR3^Xw77W3pT$a`8yY z3-wO*qra!w$F!JFljl12{BLlu$B+J=%{SCUf>QH zduBl@9n_#XTOk>TNMz6iSU(mD&5e;^4O$OEHZy3#0!aKzpAqDI*SBxre%;Ko*{HZnNBJg8FVLU9zl#Pgyn)kPSUnbkdBlzuu5Sx> zoUTE4>!!4lZY&&=N|~^9O*|oSWlHPjycz>%R<}iNYTbGevYB-=XlS0jWI*c%Oqz-l z3IR%Zp`vwrb9C*O*{rl<>(NcVT8xtA#pp75xY=Z^{1na1YLidXXyC#dILU=W9fJR} zqpqTXYj5EGh6ZAmtM+}_oYT%H0)9KGxqxo@G1~hOUsg3o3NYXlOCZ0KN zWf>&&UbaM@u9nNIbU7;}Y9;6KV1)A9xM@p|9=Fc)e*fznJ6Jg9q8aXi;p`CJ)vF}W zR}cGON1uyUSH8;9fqciXKmQIr{R? zc*E4e#yj%UV*As4?}yFdxyjyl>PM-l9+V0_(&bTu7GZUYQ{EzwcA7iVDMBehaT==( zgx4uY#XL^`IBFjXU1{N>PKi3DwN5#q6<$^;B8WIo?HriC91j-NXll8E;rWD_E8n9!iQ2QC|)n>w(-ofBL->5Pd){0$QE`}^#% z3@a~J`2xRs$-g7-4$ZqkFfBBB7Mf1SBJUn1uxvWpGs~1RehiiY2piI#Arh~UgcEiG z5;dgNW62p96V{&fA!M__vi7Lxg?3ySX%#>~dxrOqmrps~K4-wiG@v({287n^B2WLh zN!P{u_r<)(((5E&U&N%KflM1JD14H~;232@MAJ5mX|p|0H75knQGgL%hNWuOR!G`< zNmLD#vtx3Kw3mUYT6ZCvnKp^fTu^%E`OZs3d-f*JNsCp<&x+(W^0GmA8TYf5HNJ2T{Wll+auNepLf*P+rgluBGi1+P;8BMIu zh=#16IO84ehS7aKU*+@SF@_rl<7C34+e@CdQPHdoWY&BSoJ=Zi$BH3oF`&m8AP-8hRxb6rHba+MKox`ou7F%){H8l zbTnwg>N%-wkI;HiL0aTTf zrVop|i<{MSvqplPmR$%hZsu8miXxKq&?H?7#=R8O=|yQBqt1Pk^grmadDe0F$>?>i zF8%zA(+rFbd7Aoci#V>`;u`+f@Ip7Rp()(F53M!MUK!G{JT31UgWDiRfIPEfoXj%N}A@ z%AlS;CHYrK#!K|{5z$#mnYNAx&H3*|#wNy%Xzosai3w`mIC$Z}SSRqA^E_I&w`bk{ zMlq{0zod*|MMDUQ}#S#ok5n{5MSara|)}6*{lv@AKQgC%1dL<#RaP_TVHNX$A?0 zE2jMx2`C(Hn3EFdad#lwX3OQp-POyQrB29`OQqnawa}A2J!5GnDnhcZ^7*bUJY@$@ z1!Vit6UnAnp|4vUaYy^|cB4vt?JD)G4wGUpAqVtJ{?EgmKUl#-5av@8QS~nO!-bekBrh zLMe~@I2A*e$f9)%-XWFLf2H)hiArjKil@3w8I{zxtfWp-Q|Mey^+cMgQrT~8%SyG`B7srV|3^s*TUjQx4BNb}4=`9ksLeU^g$DN@zzTEks4S;$PvRMNlZL@%At zN_#8uznGu(9hkL$N2~VKaQrG=Cf8XyyC4o0?c4yPEWx3>T9!*V8&kIiO5K7UW?7=^ z&t)|-8A94Phx#9RP1W5O#Dw@17n%$YaPET7ovV@a#9r=V5o7XJ3=5UR)H_6lVDG2- zps8EX!$`~RgM?nJ@;c~DOHfZpXzwP%GW4hMY4?oFw)1G4#m8%fJh{|@IvGm;JOyZf z>064A$DFJ0NfSbCi2G$txYt?D4yy>e58?!74bgdxbe;zdkOO7W7&=#T+?t6n%oqoR zETA=VBSly%Oui@t~7Nz950)ZX&2Rd-a~CrhogE}zGeMX7wmU^bn52DROwUR zhV9fXaHo$24b1jXcIpN%s_ZF0M5pefa@Nm+$1f^%+p*L!*dIArl}Xtl+P|MbDhKM) z2i*r{X(lKeT~OBp7nGGDlGq|?hpdba73sZVLdmf6ANvrpVg9Grcpwo+O$W?U#WA!Jn{d#-~PdDRMedg%+TNOEqFm!TuER3Hl=T^WZJzHG5-v{ysK zVUJ09qEOBy#>mc<98^0-r7)qA74kGXqM zJ)PK&Q9ZrdmTt0hrAApdA-mQPG;*ROwQ{pmkP2FvNttN8tzIylsuy0SWpzRxS&H9E zx$~Byb8lWCdx`-+wlr31L^k@?*r@AJ_hv)4h5IAT7xQJ39aE;At2MwgE2+ZYFy|p? zD__ry-y&%c6A4UtrN`xHP16#2krv5I9^Y&}ErQMl?c)|U$vUFCLGVgwE>Y1tD?$zj z6-zs-utbmxO)s_(6Wb^y0J9Nzd4>uHg7J(E@34=}xZO33B z>&^8VFP~nv)>AzlINDxD^f^(@Ggl(?j6UkLq?j_Q9MOl!OUHhcrQE^fl#qu6v(UWtAOEhR?T^LEEG%SprF#UQI=>8b280$GSD} zx4`oHxPeVbo?{%T-IvauZOc8HwHA+@E^@la>FPM$FQaApFq&o*zaGukqbbT0XE_bh zs#ZDA?HD~oYhz3H$nzTUJTy5ktCe2QGJW^9(!un;Bg9gfVw_d{pkyVL| zoG)ay;$XvdxP9sQPu4ehw9kht-lVtXEaNGct2O3A>Di;oL=wBaKv zQG3=>bUeYIF6smtx1$c1elO{8(F6Q`J;1XX7sJ;n&QhK0J&_qJFAQayOV2}c@y|$# zdCAK|5+$kgo?+H<`5KBJO8@VI{J)FJ|BLQl@M?&<{TbcAZ_fQ|HvUp|FDNxkYLH`z z=F^27T0uaf0+O!G7_m;Ou|?`CtO=T4+k=Qr4qoZ05<(&a$3Nc7POS=GI(S7YXQk8{ zlmX`u&&8&G-@{C2>hU+aSxq2!pooj@d1EZR)a>L`kBXjIg#W3tVgu++&}Zw_f`>mesGB{I@{d_aAN zgC6u-dSgXMr9wbZ0s#U|q@@P?=reNxBIv;QJ|t}7Gb-D@B01U1OVq)4~Tu%ojayu=ELur+$Dn72F1BRb1Lon_NQ`H}nV2Wh2mOCO@I9DU^@{_a_4VoHC_;mE3c zW#ZN*7_4O> z{`#@w&Ud6vPmI!PkY&1;WWa|?GH^W{*a1~E(b=uS#}12; z?48(-F{j`aHh@*W4-QHDL6NS|DlmtvkQ8bsMeV>0C^`b+x;1iaQ2qA${T$zqQ9r%f zly}X0Xj)jF=Uen-T4x_Mb)q + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/ruled/client.lua b/lib/ruled/client.lua index be848fdf8..f8b13331e 100644 --- a/lib/ruled/client.lua +++ b/lib/ruled/client.lua @@ -79,6 +79,11 @@ -- 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. -- +-- Flowchart +-- ========= +-- +-- ![Client rules](../images/client_rules.svg) +-- -- Applicable client properties -- === -- From e309059f4c9ac29fbed622e8855eab480e84169f Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 6 Oct 2019 21:21:46 -0400 Subject: [PATCH 11/20] doc: Add more example to awful.client. --- lib/awful/client.lua | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/awful/client.lua b/lib/awful/client.lua index b142a3aa8..9bf775aec 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -67,6 +67,8 @@ client.focus = require("awful.client.focus") -- -- awful.placement.no_overlap+awful.placement.no_offscreen -- +-- @DOC_sequences_client_rules_placement_EXAMPLE@ +-- -- @clientruleproperty placement -- @see awful.placement @@ -84,6 +86,9 @@ client.focus = require("awful.client.focus") -- @see awful.placement --- The client default tag. +-- +-- @DOC_sequences_client_rules_tags_EXAMPLE@ +-- -- @clientruleproperty tag -- @param tag -- @see tag @@ -111,11 +116,7 @@ client.focus = require("awful.client.focus") -- If a table is used, all of its properties will be passed to the tag -- constructor: -- --- new_tag = { --- name = "My new tag!", -- The tag name. --- layout = awful.layout.suit.max, -- Set the tag layout. --- volatile = true, -- Remove the tag when the client is closed. --- } +-- @DOC_sequences_client_rules_new_tag_EXAMPLE@ -- -- @tparam[opt=false] table|string|boolean new_tag -- @clientruleproperty new_tag @@ -125,6 +126,9 @@ client.focus = require("awful.client.focus") --- Unselect the current tags and select this client tags. -- Note that this property was called `switchtotag` in previous Awesome versions. +-- +-- @DOC_sequences_client_rules_switch_to_tags_EXAMPLE@ +-- -- @clientruleproperty switch_to_tags -- @param[opt=false] boolean -- @see tag.selected From 20743a9a16a9648d5c87b0ed0920f1cd9887f8f5 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 6 Oct 2019 21:53:08 -0400 Subject: [PATCH 12/20] Remove all usage of the now deprecated `awful.rules`. --- lib/awful/client.lua | 4 +-- lib/awful/spawn.lua | 16 +++++----- lib/awful/tag.lua | 4 +-- lib/gears/matcher.lua | 8 ++--- objects/client.c | 8 ++--- tests/_client.lua | 2 +- tests/_runner.lua | 17 ---------- tests/examples/awful/titlebar/default.lua | 2 +- tests/test-awful-client.lua | 7 +++- tests/test-awful-placement.lua | 4 ++- tests/test-awful-rules.lua | 17 +++++----- tests/test-geometry.lua | 39 ++++++++++++++++------- tests/test-urgent.lua | 8 +++-- 13 files changed, 73 insertions(+), 63 deletions(-) diff --git a/lib/awful/client.lua b/lib/awful/client.lua index 9bf775aec..ae74a9f46 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -1296,7 +1296,7 @@ end -- @staticfct awful.client.iterate -- @usage -- un-minimize all urxvt instances -- local urxvt = function (c) --- return awful.rules.match(c, {class = "URxvt"}) +-- return ruled.client.match(c, {class = "URxvt"}) -- end -- -- for c in awful.client.iterate(urxvt) do @@ -1326,7 +1326,7 @@ end -- @usage -- run or raise urxvt (perhaps, with tabs) on modkey + semicolon -- awful.key({ modkey, }, 'semicolon', function () -- local matcher = function (c) --- return awful.rules.match(c, {class = 'URxvt'}) +-- return ruled.client.match(c, {class = 'URxvt'}) -- end -- awful.client.run_or_raise('urxvt', matcher) -- end); diff --git a/lib/awful/spawn.lua b/lib/awful/spawn.lua index 2899636f3..ff41e0ea0 100644 --- a/lib/awful/spawn.lua +++ b/lib/awful/spawn.lua @@ -185,7 +185,7 @@ -- -- This should (if the program correctly implements the protocol) result in -- `c.startup_id` to at least match `something`. --- This identifier can then be used in `awful.rules` to configure the client. +-- This identifier can then be used in `ruled.client` to configure the client. -- -- Awesome can automatically set the `DESKTOP_STARTUP_ID` variable. This is used -- by `awful.spawn` to specify additional rules for the startup. For example: @@ -206,7 +206,7 @@ -- })' -- -- This table contains the client properties that are valid when used the --- `sn_rules` or `prop` function argument. They are the same as in `awful.rules`. +-- `sn_rules` or `prop` function argument. They are the same as in `ruled.client`. -- --@DOC_rules_index_COMMON@ -- @@ -334,7 +334,7 @@ end -- Applying properties or running a callback requires the program/client to -- support startup notifications. -- --- See `awful.rules.execute` for more details about the format of `sn_rules`. +-- See `ruled.client.execute` for more details about the format of `sn_rules`. -- -- @tparam string|table cmd The command. -- @tparam[opt=true] table|boolean sn_rules A table of properties to be applied @@ -636,7 +636,7 @@ end -- command and rules, you need to specify an UID or only the first one will be -- executed. -- --- The `rules` are standard `awful.rules`. +-- The `rules` are standard `ruled.client`. -- -- This function depends on the startup notification protocol to be correctly -- implemented by the command. See `client.startup_id` for more information. @@ -649,7 +649,7 @@ end -- @tparam[opt] string unique_id A string to identify the client so it isn't executed -- multiple time. -- @tparam[opt] function callback A callback function when the client is created. --- @see awful.rules +-- @see ruled.client -- @staticfct awful.spawn.once function spawn.once(cmd, rules, matcher, unique_id, callback) local hash = unique_id or hash_command(cmd, rules) @@ -666,7 +666,7 @@ end -- This is like `awful.spawn.once`, but will spawn new instances if the previous -- has finished. -- --- The `rules` are standard `awful.rules`. +-- The `rules` are standard `ruled.client`. -- -- This function depends on the startup notification protocol to be correctly -- implemented by the command. See `client.startup_id` for more information. @@ -682,7 +682,7 @@ end -- @tparam[opt] string unique_id A string to identify the client so it isn't executed -- multiple time. -- @tparam[opt] function callback A callback function when the client is created. --- @see awful.rules +-- @see ruled.client -- @staticfct awful.spawn.single_instance function spawn.single_instance(cmd, rules, matcher, unique_id, callback) local hash = unique_id or hash_command(cmd, rules) @@ -709,7 +709,7 @@ local raise_rules = {focus = true, switch_to_tags = true, raise = true} -- @tparam[opt] string unique_id A string to identify the client so it isn't executed -- multiple time. -- @tparam[opt] function callback A callback function when the client is created. --- @see awful.rules +-- @see ruled.client -- @treturn client The client if it already exists. -- @staticfct awful.spawn.raise_or_spawn -- @request client activate spawn.raise_or_spawn granted Activate a client when diff --git a/lib/awful/tag.lua b/lib/awful/tag.lua index fe831453c..05f199f20 100644 --- a/lib/awful/tag.lua +++ b/lib/awful/tag.lua @@ -1684,8 +1684,8 @@ end -- Register standard signals. capi.client.connect_signal("property::screen", function(c) -- First, the delayed timer is necessary to avoid a race condition with - -- awful.rules. It is also messing up the tags before the user have a chance - -- to set them manually. + -- `ruled.client`. It is also messing up the tags before the user have a + -- chance to set them manually. timer.delayed_call(function() if not c.valid then return diff --git a/lib/gears/matcher.lua b/lib/gears/matcher.lua index 8bc9feac3..a0ad4bb48 100644 --- a/lib/gears/matcher.lua +++ b/lib/gears/matcher.lua @@ -3,7 +3,7 @@ -- Sources -- ======= -- --- This module holds the business logic used by `awful.rules`. It provides an +-- This module holds the business logic used by `ruled.client`. It provides an -- object on which one can add sets of rules or, alternatively, functions. -- In this module, the sets of rules or custom functions are called sources. -- @@ -29,11 +29,11 @@ -- -- @DOC_text_gears_matcher_types_EXAMPLE@ -- --- More examples are available in `awful.rules`. +-- More examples are available in `ruled.client`. -- -- @author Julien Danjou <julien@danjou.info> -- @copyright 2009 Julien Danjou --- @see awful.rules +-- @see ruled.client -- @module gears.matcher local gtable = require("gears.table") @@ -445,7 +445,7 @@ function matcher:remove_matching_source(name) return false end ---- Apply awful.rules.rules to an object. +--- Apply ruled.client.rules to an object. -- -- Calling this will apply all properties provided by the matching functions -- and rules. diff --git a/objects/client.c b/objects/client.c index 4178235b0..7856eb630 100644 --- a/objects/client.c +++ b/objects/client.c @@ -255,7 +255,7 @@ * (from `awful.client.focus.history.previous`). * * *menu.clients*: When using the builtin client menu * (from `awful.menu.clients`). - * * *rules*: When a new client is focused from a rule (from `awful.rules`). + * * *rules*: When a new client is focused from a rule (from `ruled.client`). * * *screen.focus*: When a screen is focused (from `awful.screen.focus`). * * Default implementation: `awful.ewmh.activate`. @@ -596,7 +596,7 @@ * multiple of the character size. Honoring size hints will cause the terminal * window to have a small gap at the bottom. * - * This is enabled by default. To disable it by default, see `awful.rules`. + * This is enabled by default. To disable it by default, see `ruled.client`. * * **Signal:** * @@ -946,8 +946,8 @@ * blacklisted_snid[snid] = c * end * - * awful.rules.add_rule_source( - * "snid", fix_startup_id, {}, {"awful.spawn", "awful.rules"} + * ruled.client.add_rule_source( + * "snid", fix_startup_id, {}, {"awful.spawn", "ruled.client"} * ) * * **Signal:** diff --git a/tests/_client.lua b/tests/_client.lua index f2b6eac11..31b9c6188 100644 --- a/tests/_client.lua +++ b/tests/_client.lua @@ -1,7 +1,7 @@ local spawn = require("awful.spawn") -- This file provide a simple, yet flexible, test client. --- It is used to test the `awful.rules` +-- It is used to test the `ruled.client` local test_client_source = [[ pcall(require, 'luarocks.loader') diff --git a/tests/_runner.lua b/tests/_runner.lua index 5b357773c..193348d75 100644 --- a/tests/_runner.lua +++ b/tests/_runner.lua @@ -1,7 +1,5 @@ local timer = require("gears.timer") -local awful = require("awful") local gtable = require("gears.table") -local gdebug = require("gears.debug") local runner = { quit_awesome_on_error = os.getenv('TEST_PAUSE_ON_ERRORS') ~= '1', @@ -9,21 +7,6 @@ local runner = { local verbose = os.getenv('VERBOSE') == '1' --- Helpers. - ---- 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) -gdebug.deprecate = dep - -runner.add_to_default_rules = function(r) - gdebug.deprecate = function() end - awful.rules.rules = gtable.clone(default_rules) - table.insert(awful.rules.rules, r) - gdebug.deprecate = dep -end - -- Was the runner started already? local running = false diff --git a/tests/examples/awful/titlebar/default.lua b/tests/examples/awful/titlebar/default.lua index eaffd68c8..f13477136 100644 --- a/tests/examples/awful/titlebar/default.lua +++ b/tests/examples/awful/titlebar/default.lua @@ -11,7 +11,7 @@ local c = client.gen_fake {hide_first=true} --DOC_HIDE place.maximize(c, {honor_padding=true, honor_workarea=true}) --DOC_HIDE -- Create a titlebar for the client. - -- By default, `awful.rules` will create one, but all it does is to call this + -- By default, `ruled.client` will create one, but all it does is to call this -- function. local top_titlebar = awful.titlebar(c, { diff --git a/tests/test-awful-client.lua b/tests/test-awful-client.lua index e69a7ca03..7c7c80dab 100644 --- a/tests/test-awful-client.lua +++ b/tests/test-awful-client.lua @@ -1,5 +1,7 @@ local awful = require("awful") local test_client = require("_client") +local cruled = require("ruled.client") +local gdebug = require("gears.debug") local has_spawned = false local steps = { @@ -177,7 +179,10 @@ end) local has_error -- Disable awful.screen.preferred(c) -awful.rules.rules[1].properties.screen = nil +local dep = gdebug.deprecate +gdebug.deprecate = function() end +cruled.rules[1].properties.screen = nil +gdebug.deprecate = dep table.insert(steps, function() -- Make sure there is no extra callbacks that causes double screen changes diff --git a/tests/test-awful-placement.lua b/tests/test-awful-placement.lua index 6aedf95c3..007766de8 100644 --- a/tests/test-awful-placement.lua +++ b/tests/test-awful-placement.lua @@ -1,6 +1,7 @@ local awful = require("awful") local test_client = require("_client") local runner = require("_runner") +local cruled = require("ruled.client") -- This test makes some assumptions about the no_overlap behavior which may not -- be correct if the screen is in the portrait orientation. @@ -27,7 +28,8 @@ local rule = { placement = awful.placement.no_overlap + awful.placement.no_offscreen } } -table.insert(awful.rules.rules, rule) + +cruled.append_rule(rule) local function check_geometry(c, x, y, width, height) local g = c:geometry() diff --git a/tests/test-awful-rules.lua b/tests/test-awful-rules.lua index 2482363da..fbf783b49 100644 --- a/tests/test-awful-rules.lua +++ b/tests/test-awful-rules.lua @@ -1,4 +1,5 @@ local awful = require("awful") +local ruledc = require("ruled.client") local gears = require("gears") local test_client = require("_client") local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) @@ -12,8 +13,8 @@ local tests = {} -- local border_width = beautiful.border_width -- Detect "request::manage" race conditions -local real_apply = awful.rules.apply -function awful.rules.apply(c) +local real_apply = ruledc.apply +function ruledc.apply(c) assert(#c:tags() == 0) return real_apply(c) end @@ -33,7 +34,7 @@ local function test_rule(rule) rule.test = nil end - table.insert(awful.rules.rules, rule) + ruledc.append_rule(rule) end -- Helper function to search clients @@ -263,20 +264,20 @@ test_rule { } -- Test the custom sources -assert(awful.rules.add_rule_source("high_priority", function(c, props, _) +assert(ruledc.add_rule_source("high_priority", function(c, props, _) assert(type(c) == "client") assert(props.random2) props.random1 = true end, {"awful.spawn"}, {"awful.rules", "low_priority"})) -assert(awful.rules.add_rule_source("before2", function() +assert(ruledc.add_rule_source("before2", function() error("This function should not be called") end, {"awful.spawn"}, {"awful.rules"})) -assert(awful.rules.remove_rule_source("before2")) +assert(ruledc.remove_rule_source("before2")) -assert(awful.rules.add_rule_source("low_priority", function(c, props, _) +assert(ruledc.add_rule_source("low_priority", function(c, props, _) assert(type(c) == "client") assert(not props.random1) @@ -285,7 +286,7 @@ end, {"awful.spawn", "high_priority"}, {"void", "awful.rules"})) local temp = gears.debug.print_warning gears.debug.print_warning = function() end -assert(not awful.rules.add_rule_source("invalid_source", function() +assert(not ruledc.add_rule_source("invalid_source", function() assert(false, "This cannot happen") end, {"awful.rules"}, {"awful.spawn"})) gears.debug.print_warning = temp diff --git a/tests/test-geometry.lua b/tests/test-geometry.lua index a97491a88..b9ed5ea52 100644 --- a/tests/test-geometry.lua +++ b/tests/test-geometry.lua @@ -4,21 +4,38 @@ local runner = require( "_runner" ) local awful = require( "awful" ) local wibox = require( "wibox" ) local beautiful = require( "beautiful" ) +local cruled = require("ruled.client") +local gdebug = require("gears.debug") local w = nil local w1_draw, w2_draw +-- Replacing the rules is not supported anymore. +local dep = gdebug.deprecate + +local function set_rules(new_rules) + gdebug.deprecate = function() end + + cruled.rules = {} + + cruled.append_rules(new_rules) + + gdebug.deprecate = dep +end + -- Disable automatic placement -awful.rules.rules = { - { rule = { }, properties = { - border_width = 0, - size_hints_honor = false, - x = 0, - y = 0, - width = 100, - height = 100, - border_color = beautiful.border_color_normal -} +set_rules { + { + rule = { }, + properties = { + border_width = 0, + size_hints_honor = false, + x = 0, + y = 0, + width = 100, + height = 100, + border_color = beautiful.border_color_normal + } } } @@ -52,7 +69,7 @@ local steps = { end end, function() - awful.rules.rules = { + set_rules { -- All clients will match this rule. { rule = { },properties = { titlebars_enabled = true, diff --git a/tests/test-urgent.lua b/tests/test-urgent.lua index 169c2512c..292d78f41 100644 --- a/tests/test-urgent.lua +++ b/tests/test-urgent.lua @@ -2,6 +2,8 @@ local awful = require("awful") local runner = require("_runner") +local cruled = require("ruled.client") + -- Some basic assertion that the tag is not marked "urgent" already. assert(awful.tag.getproperty(awful.screen.focused().tags[2], "urgent") == nil) @@ -31,7 +33,7 @@ local steps = { -- Select first tag. awful.screen.focused().tags[1]:view_only() - runner.add_to_default_rules({ rule = { class = "XTerm" }, + cruled.append_rule({ rule = { class = "XTerm" }, properties = { tag = "2", focus = true } }) awful.spawn("xterm") @@ -71,7 +73,7 @@ local steps = { -- Select first tag. awful.screen.focused().tags[1]:view_only() - runner.add_to_default_rules({ rule = { class = "XTerm" }, + cruled.append_rule({ rule = { class = "XTerm" }, properties = { tag = "2", focus = true, switch_to_tags = true }}) awful.spawn("xterm") @@ -93,7 +95,7 @@ local steps = { client.get()[1]:kill() manage_cb_done = false - runner.add_to_default_rules({rule = { class = "XTerm" }, + cruled.append_rule({rule = { class = "XTerm" }, properties = { tag = "2", focus = false }}) awful.spawn("xterm") From 5e720c974491d6f0ae39f1490c720efeaa038266 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage-Vallee Date: Mon, 30 Dec 2019 15:17:23 -0800 Subject: [PATCH 13/20] doc: Major client documentation backfill. This commit mostly rewrite the client documentation and pay the technical debt accumulated over the years. Most of the client documentation was still one-liners from the luadoc era. It now has all the new tags, type. It also has actual description of what the properties do beyond the name. --- lib/awful/client.lua | 242 +++++++++------ objects/client.c | 698 +++++++++++++++++++++++++++++-------------- 2 files changed, 618 insertions(+), 322 deletions(-) diff --git a/lib/awful/client.lua b/lib/awful/client.lua index ae74a9f46..246b7f245 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -74,7 +74,7 @@ client.focus = require("awful.client.focus") --- When applying the placement, honor the screen padding. -- @clientruleproperty honor_padding --- @param[opt=true] boolean +-- @tparam[opt=true] boolean honor_padding -- @see awful.placement --- When applying the placement, honor the screen work area. @@ -82,7 +82,7 @@ client.focus = require("awful.client.focus") -- The workarea is the part of the screen that excludes the bars and docks. -- -- @clientruleproperty honor_workarea --- @param[opt=true] boolean +-- @tparam[opt=true] boolean honor_workarea -- @see awful.placement --- The client default tag. @@ -90,7 +90,7 @@ client.focus = require("awful.client.focus") -- @DOC_sequences_client_rules_tags_EXAMPLE@ -- -- @clientruleproperty tag --- @param tag +-- @tparam tag tag -- @see tag -- @see new_tag -- @see tags @@ -102,7 +102,7 @@ client.focus = require("awful.client.focus") -- issues. -- -- @clientruleproperty tags --- @param[opt={tag}] table +-- @tparam[opt={tag}] table tags -- @see tag -- @see new_tag -- @see tags @@ -130,7 +130,7 @@ client.focus = require("awful.client.focus") -- @DOC_sequences_client_rules_switch_to_tags_EXAMPLE@ -- -- @clientruleproperty switch_to_tags --- @param[opt=false] boolean +-- @tparam[opt=false] boolean switch_to_tags -- @see tag.selected --- Define if the client should grab focus by default. @@ -138,11 +138,11 @@ client.focus = require("awful.client.focus") -- The `request::activate` context for this call is `rules`. -- -- @clientruleproperty focus --- @param[opt=false] boolean +-- @tparam[opt=false] boolean focus --- Should this client have a titlebar by default. -- @clientruleproperty titlebars_enabled --- @param[opt=false] boolean +-- @tparam[opt=false] boolean titlebars_enabled -- @see awful.titlebar --- A function to call when this client is ready. @@ -177,6 +177,8 @@ end -- tag as arguments. -- @request client activate client.jumpto granted When a client is activated -- because `c:jump_to()` is called. +-- @see activate +-- @see active function client.object.jump_to(self, merge) local s = get_screen(screen.focused()) -- focus the screen @@ -251,7 +253,7 @@ end -- @tparam int i The index. Use 1 to get the next, -1 to get the previous. -- @client[opt] sel The client. -- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom) --- @return A client, or nil if no client is available. +-- @treturn[opt] client|nil A client, or nil if no client is available. -- -- @usage -- focus the next window in the index -- awful.client.next(1) @@ -282,10 +284,16 @@ function client.next(i, sel, stacked) end --- Swap a client with another client in the given direction. +-- -- @staticfct awful.client.swap.bydirection -- @tparam string dir The direction, can be either "up", "down", "left" or "right". -- @client[opt=focused] c The client. -- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom) +-- @see swap +-- @see swapped +-- @see awful.client.swap.global_bydirection +-- @see awful.client.swap.byidx +-- @see awful.client.cycle function client.swap.bydirection(dir, c, stacked) local sel = c or capi.client.focus if sel then @@ -304,12 +312,18 @@ function client.swap.bydirection(dir, c, stacked) end --- Swap a client with another client in the given direction. +-- -- Swaps across screens. -- @staticfct awful.client.swap.global_bydirection --- @param dir The direction, can be either "up", "down", "left" or "right". +-- @tparam string dir The direction, can be either "up", "down", "left" or "right". -- @client[opt] sel The client. -- @request client activate client.swap.global_bydirection granted When a client -- could be activated because `awful.client.swap.global_bydirection` was called. +-- @see swap +-- @see swapped +-- @see awful.client.swap.bydirection +-- @see awful.client.swap.byidx +-- @see awful.client.cycle function client.swap.global_bydirection(dir, sel) sel = sel or capi.client.focus local scr = get_screen(sel and sel.screen or screen.focused()) @@ -340,9 +354,15 @@ function client.swap.global_bydirection(dir, sel) end --- Swap a client by its relative index. +-- -- @staticfct awful.client.swap.byidx --- @param i The index. +-- @tparam integer i The index. -- @client[opt] c The client, otherwise focused one is used. +-- @see swap +-- @see swapped +-- @see awful.client.swap.bydirection +-- @see awful.client.swap.global_bydirection +-- @see awful.client.cycle function client.swap.byidx(i, c) local sel = c or capi.client.focus local target = client.next(i, sel) @@ -351,12 +371,20 @@ function client.swap.byidx(i, c) end end ---- Cycle clients. +--- Cycle through the clients to change the focus. +-- +-- This will swap the client from one position to the next +-- in the layout. -- -- @staticfct awful.client.cycle --- @param clockwise True to cycle clients clockwise. --- @param[opt] s The screen where to cycle clients. +-- @tparam boolean clockwise True to cycle clients clockwise. +-- @tparam[opt] screen s The screen where to cycle clients. -- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom) +-- @see swap +-- @see swapped +-- @see awful.client.swap.bydirection +-- @see awful.client.swap.global_bydirection +-- @see awful.client.swap.byidx function client.cycle(clockwise, s, stacked) s = s or screen.focused() local cls = client.visible(s, stacked) @@ -402,7 +430,7 @@ end -- -- @legacylayout awful.client.getmaster -- @screen_or_idx[opt=awful.screen.focused()] s The screen. --- @return The master window. +-- @treturn client The master client. function client.getmaster(s) s = s or screen.focused() return client.visible(s)[1] @@ -431,10 +459,10 @@ end --- Move/resize a client relative to current coordinates. -- @deprecated awful.client.moveresize --- @param x The relative x coordinate. --- @param y The relative y coordinate. --- @param w The relative width. --- @param h The relative height. +-- @tparam integer x The relative x coordinate. +-- @tparam integer y The relative y coordinate. +-- @tparam integer w The relative width. +-- @tparam integer h The relative height. -- @client[opt] c The client, otherwise focused one is used. -- @see client.relative_move function client.moveresize(x, y, w, h, c) @@ -460,7 +488,7 @@ end --- Move a client to a tag. -- @deprecated awful.client.movetotag --- @param target The tag to move the client to. +-- @tparam tag target The tag to move the client to. -- @client[opt] c The client to move, otherwise the focused one is used. -- @see client.move_to_tag function client.movetotag(target, c) @@ -469,10 +497,12 @@ function client.movetotag(target, c) end --- Move a client to a tag. +-- -- @method move_to_tag -- @tparam tag target The tag to move the client to. -- @request client activate client.movetotag granted When a client could be -- activated because `c:move_to_tag()` was called. +-- @see tags function client.object.move_to_tag(self, target) local s = target.screen if self and s then @@ -486,18 +516,22 @@ function client.object.move_to_tag(self, target) end --- Toggle a tag on a client. +-- -- @deprecated awful.client.toggletag --- @param target The tag to toggle. +-- @tparam tag target The tag to toggle. -- @client[opt] c The client to toggle, otherwise the focused one is used. -- @see client.toggle_tag +-- @see tags function client.toggletag(target, c) gdebug.deprecate("Use c:toggle_tag(target) instead of awful.client.toggletag", {deprecated_in=4}) client.object.toggle_tag(c or capi.client.focus, target) end --- Toggle a tag on a client. +-- -- @method toggle_tag -- @tparam tag target The tag to move the client to. +-- @see tags function client.object.toggle_tag(self, target) -- Check that tag and client screen are identical if self and get_screen(self.screen) == get_screen(target.screen) then @@ -523,7 +557,7 @@ end --- Move a client to a screen. Default is next screen, cycling. -- @deprecated awful.client.movetoscreen -- @client c The client to move. --- @param s The screen, default to current + 1. +-- @tparam screen s The screen, default to current + 1. -- @see screen -- @see client.move_to_screen function client.movetoscreen(c, s) @@ -590,14 +624,11 @@ end --- If a client is marked or not. -- --- **Signal:** --- --- * *marked* (for legacy reasons, use `property::marked`) --- * *unmarked* (for legacy reasons, use `property::marked`) --- * *property::marked* --- -- @property marked --- @param boolean +-- @tparam boolean marked +-- @emits marked (for legacy reasons, use `property::marked`) +-- @emits unmarker (for legacy reasons, use `property::marked`) +-- @emits property::marked --- The border color when the client is focused. -- @@ -664,7 +695,7 @@ end --- Return the marked clients and empty the marked table. -- @deprecated awful.client.getmarked --- @return A table with all marked clients. +-- @treturn table A table with all marked clients. function client.getmarked() local copy = gtable.clone(client.data.marked, false) @@ -682,7 +713,7 @@ end -- Floating client are not handled by tiling layouts. -- @deprecated awful.client.floating.set -- @client c A client. --- @param s True or false. +-- @tparam boolean s True or false. function client.floating.set(c, s) gdebug.deprecate("Use c.floating = true instead of awful.client.floating.set", {deprecated_in=4}) client.object.set_floating(c, s) @@ -691,7 +722,7 @@ end -- Set a client floating state, overriding auto-detection. -- Floating client are not handled by tiling layouts. -- @client c A client. --- @param s True or false. +-- @tparam boolan s True or false. function client.object.set_floating(c, s) c = c or capi.client.focus if c and client.property.get(c, "floating") ~= s then @@ -741,13 +772,10 @@ end --- Return if a client has a fixed size or not. -- --- **Signal:** --- --- * *property::is_fixed* --- -- This property is read only. -- @property is_fixed --- @param boolean The fixed size state +-- @tparam[opt=false] boolean is_fixed The fixed size state +-- @propemits false false -- @see size_hints -- @see size_hints_honor @@ -772,7 +800,7 @@ end -- -- This property is read only. -- @property immobilized_horizontal --- @param boolean The immobilized state +-- @tparam[opt=false] boolean immobilized_horizontal The immobilized state -- @see maximized -- @see maximized_horizontal -- @see fullscreen @@ -788,7 +816,7 @@ end -- -- This property is read only. -- @property immobilized_vertical --- @param boolean The immobilized state +-- @tparam[opt=false] boolean immobilized_vertical The immobilized state -- @see maximized -- @see maximized_vertical -- @see fullscreen @@ -801,7 +829,7 @@ end -- @client c A client. -- @see floating -- @deprecated awful.client.floating.get --- @return True or false. Note that some windows might be floating even if you +-- @treturn boolean True or false. Note that some windows might be floating even if you -- did not set them manually. For example, windows with a type different than -- normal. function client.floating.get(c) @@ -817,10 +845,6 @@ end -- did not set them manually. For example, windows with a type different than -- normal. -- --- **Signal:** --- --- * *property::floating* --- -- @property floating -- @tparam boolean floating The floating state. -- @request client border floating granted When a border update is required @@ -829,6 +853,7 @@ end -- floating. -- @request client border inactive granted When a client stop being active and -- is not floating. +-- @propemits false false function client.object.get_floating(c) c = c or capi.client.focus @@ -901,39 +926,43 @@ end --- The x coordinates. -- --- **Signal:** --- --- * *property::x* --- -- @property x --- @param integer +-- @tparam integer x +-- @emits property::geometry +-- @emitstparam property::geometry table geo The +-- geometry (with `x`, `y`, `width`, `height`). +-- @emits property::x +-- @emits property::position --- The y coordinates. -- --- **Signal:** --- --- * *property::y* --- -- @property y --- @param integer +-- @tparam integer y +-- @emits property::geometry +-- @emitstparam property::geometry table geo The +-- geometry (with `x`, `y`, `width`, `height`). +-- @emits property::y +-- @emits property::position --- The width of the client. -- --- **Signal:** --- --- * *property::width* --- -- @property width --- @param width +-- @tparam integer width +-- @emits property::geometry +-- @emitstparam property::geometry table geo The +-- geometry (with `x`, `y`, `width`, `height`). +-- @emits property::width +-- @emits property::size --- The height of the client. -- --- **Signal:** --- --- * *property::height* --- -- @property height --- @param height +-- @tparam integer height +-- @emits property::geometry +-- @emitstparam property::geometry table geo The +-- geometry (with `x`, `y`, `width`, `height`). +-- @emits property::height +-- @emits property::size -- Add the geometry helpers to match the wibox API for _, v in ipairs {"x", "y", "width", "height"} do @@ -949,8 +978,8 @@ end --- Restore (=unminimize) a random client. -- @staticfct awful.client.restore --- @param s The screen to use. --- @return The restored client if some client was restored, otherwise nil. +-- @tparam screen s The screen to use. +-- @treturn client The restored client if some client was restored, otherwise nil. function client.restore(s) s = s or screen.focused() local cls = capi.client.get(s) @@ -970,8 +999,8 @@ function client.restore(s) end --- Normalize a set of numbers to 1. --- @param set the set of numbers to normalize --- @param num the number of numbers to normalize +-- @tparam table set the set of numbers to normalize. +-- @tparam number num the number of numbers to normalize. local function normalize(set, num) num = num or #set local total = 0 @@ -998,9 +1027,9 @@ end -- -- @legacylayout awful.client.idx -- @client c the client --- @return col the column number --- @return idx index of the client in the column --- @return num the number of visible clients in the column +-- @treturn integer col The column number. +-- @treturn integer idx Index of the client in the column. +-- @treturn integer num The number of visible clients in the column. function client.idx(c) c = c or capi.client.focus if not c then return end @@ -1058,8 +1087,9 @@ end --- Set the window factor of a client -- -- @legacylayout awful.client.setwfact --- @param wfact the window factor value +-- @tparam number wfact the window factor value -- @client c the client +-- @emits property::windowfact function client.setwfact(wfact, c) -- get the currently selected window c = c or capi.client.focus @@ -1114,7 +1144,8 @@ end -- @tparam number add Amount to increase/decrease the client's window factor. -- Should be between `-current_window_factor` and something close to -- infinite. The normalisation then ensures that the sum of all factors is 1. --- @client c the client +-- @client c the client. +-- @emits property::windowfact function client.incwfact(add, c) c = c or capi.client.focus if not c then return end @@ -1152,12 +1183,9 @@ end -- Clients with a type of "utility", "toolbar" or "dock" are dockable by -- default. -- --- **Signal:** --- --- * *property::dockable* --- -- @property dockable --- @param boolean The dockable state +-- @tparam boolean dockable The dockable state +-- @propemits false false function client.object.get_dockable(c) local value = client.property.get(c, "dockable") @@ -1180,7 +1208,7 @@ end -- to the edge of the workarea. -- -- @client c A client. --- @param value True or false. +-- @tparam boolean value True or false. -- @deprecated awful.client.dockable.set function client.dockable.set(c, value) gdebug.deprecate("Use c.dockable = value instead of awful.client.dockable.set", {deprecated_in=4}) @@ -1193,12 +1221,10 @@ end -- various ways. This property uses the motif MWM_DECOR_TITLE hint and -- interprets it as the client (not) wanting a titlebar. -- --- **Signal:** --- --- * *property::requests_no_titlebar* --- -- @property requests_no_titlebar --- @param boolean Whether the client requests not to get a titlebar +-- @tparam boolean requests_no_titlebar Whether the client +-- requests not to get a titlebar. +-- @propemits false false function client.object.get_requests_no_titlebar(c) local hints = c.motif_wm_hints @@ -1224,8 +1250,8 @@ end) -- This method is deprecated. It is now possible to use `c.value` directly. -- -- @client c The client. --- @param prop The property name. --- @return The property. +-- @tparam string prop The property name. +-- @return The property value. -- @deprecated awful.client.property.get function client.property.get(c, prop) if not c._private._persistent_properties_loaded then @@ -1248,8 +1274,8 @@ end -- directly. -- -- @client c The client. --- @param prop The property name. --- @param value The value. +-- @tparam string prop The property name. +-- @param value The property value. -- @deprecated awful.client.property.set function client.property.set(c, prop, value) if not c._private.awful_client_properties then @@ -1267,8 +1293,8 @@ end --- Set a client property to be persistent across restarts (via X properties). -- -- @staticfct awful.client.property.persist --- @param prop The property name. --- @param kind The type (used for register_xproperty). +-- @tparam string prop The property name. +-- @tparam string kind The type (used for register_xproperty). -- One of "string", "number" or "boolean". function client.property.persist(prop, kind) local xprop = "awful.client.property." .. prop @@ -1288,10 +1314,10 @@ end -- Starting from the client in focus or the given index, all clients that match -- a given criteria. -- --- @param filter a function that returns true to indicate a positive match --- @param start what index to start iterating from. Defaults to using the +-- @tparam function filter a function that returns true to indicate a positive match. +-- @tparam integer start what index to start iterating from. Defaults to using the -- index of the currently focused client. --- @param s which screen to use. nil means all screens. +-- @tparam screen s which screen to use. nil means all screens. -- -- @staticfct awful.client.iterate -- @usage -- un-minimize all urxvt instances @@ -1313,8 +1339,8 @@ end -- If multiple clients match the given condition then the next one is -- focussed. -- --- @param cmd the command to execute --- @param matcher a function that returns true to indicate a matching client +-- @tparam string cmd the command to execute +-- @tparam function matcher a function that returns true to indicate a matching client -- @tparam bool|function merge If true then merge tags (select the client's -- first tag additionally) when the client is not visible. -- If it is a function, it will be called with the client as argument. @@ -1354,7 +1380,7 @@ end -- @client c The client. -- @tparam function matcher A function that should return true, if -- a matching parent client is found. --- @treturn client.client|nil The matching parent client or nil. +-- @treturn client|nil The matching parent client or nil. function client.get_transient_for_matching(c, matcher) gdebug.deprecate("Use c:get_transient_for_matching(matcher) instead of".. "awful.client.get_transient_for_matching", {deprecated_in=4}) @@ -1366,7 +1392,10 @@ end -- @method get_transient_for_matching -- @tparam function matcher A function that should return true, if -- a matching parent client is found. --- @treturn client.client|nil The matching parent client or nil. +-- @treturn client|nil The matching parent client or nil. +-- @see transient_for +-- @see modal +-- @see is_transient_for function client.object.get_transient_for_matching(self, matcher) local tc = self.transient_for while tc do @@ -1379,11 +1408,12 @@ function client.object.get_transient_for_matching(self, matcher) end --- Is a client transient for another one? +-- -- @deprecated awful.client.is_transient_for -- @see client.is_transient_for -- @client c The child client (having transient_for). -- @client c2 The parent client to check. --- @treturn client.client|nil The parent client or nil. +-- @treturn client|nil The parent client or nil. function client.is_transient_for(c, c2) gdebug.deprecate("Use c:is_transient_for(c2) instead of".. "awful.client.is_transient_for", {deprecated_in=4}) @@ -1391,9 +1421,20 @@ function client.is_transient_for(c, c2) end --- Is a client transient for another one? +-- +-- This will traverse the chain of `transient_for` client +-- until a client which is transient for `c2` is found. If +-- one is found, it will be returned. If none is found, then +-- `nil` will be returned. Most of the time there is no +-- long chain of clients, so `self` or `nil` are the most +-- likely return values. +-- -- @method is_transient_for -- @client c2 The parent client to check. --- @treturn client.client|nil The parent client or nil. +-- @treturn client|nil The parent client or nil. +-- @see transient_for +-- @see modal +-- @see client.get_transient_for_matching function client.object.is_transient_for(self, c2) local tc = self while tc.transient_for do @@ -1418,12 +1459,15 @@ object.properties._legacy_accessors(client, "keys", "_keys", true, function(new_ end, true, true, "keybinding") --- Set the client shape. +-- -- @property shape -- @tparam gears.shape A gears.shape compatible function. +-- @propemits true false -- @see gears.shape function client.object.set_shape(self, shape) client.property.set(self, "_shape", shape) set_shape(self) + self:emit_signal("property::shape", shape) end -- Proxy those properties to decorate their accessors with an extra flag to @@ -1643,7 +1687,7 @@ capi.client.connect_signal("request::manage", function (c) require("awful.placement").no_offscreen(c) end - if awesome.startup then + if capi.awesome.startup then client.focus.history.add(c) end diff --git a/objects/client.c b/objects/client.c index 7856eb630..7bd1cd359 100644 --- a/objects/client.c +++ b/objects/client.c @@ -140,6 +140,7 @@ * initialized, but before clients are added. * * @signal scanning + * @classsignal */ /** AwesomeWM is done scanning for clients. @@ -147,14 +148,17 @@ * This is emitted before the `startup` signal and after the `scanning` signal. * * @signal scanned + * @classsignal */ /** When a client gains focus. * @signal focus + * @classsignal */ /** Before manage, after unmanage, and when clients swap. * @signal list + * @classsignal */ /** When 2 clients are swapped @@ -179,6 +183,7 @@ * with the other `request::` signals). * @request client border added granted When a new client needs a its initial * border settings. + * @classsignal */ /** When a client is going away. @@ -198,6 +203,7 @@ * @tparam string context Why was the client unmanaged. * @tparam table hints More metadata (currently empty, it exists for compliance * with the other `request::` signals). + * @classsignal */ /** Use `request::manage`. @@ -208,30 +214,31 @@ * @deprecatedsignal unmanage */ -/** +/** When a mouse button is pressed in a client. * @signal button::press */ -/** +/** When a mouse button is released in a client. + * * @signal button::release */ -/** +/** When the mouse enters a client. + * * @signal mouse::enter */ -/** +/** When the mouse leaves a client. + * * @signal mouse::leave */ /** + * When the mouse moves within a client. + * * @signal mouse::move */ -/** - * @signal property::window - */ - /** When a client should get activated (focused and/or raised). * * **Contexts are:** @@ -267,6 +274,7 @@ * @tparam[opt] table hints A table with additional hints: * @tparam[opt=false] boolean hints.raise should the client be raised? * @request client activate ewmh granted When the client asks to be activated. + * @classsignal */ /** When an event could lead to the client being activated. @@ -286,6 +294,7 @@ * @tparam string context The context where this signal was used. * @tparam[opt] table hints A table with additional hints: * @tparam[opt=false] boolean hints.raise should the client be raised? + * @classsignal * */ @@ -301,14 +310,19 @@ * (programmatically) asks for the maximization to be changed. * @request client geometry client_maximize_vertical granted When a client * (programmatically) asks for the maximization to be changed. + * @classsignal */ -/** +/** When the tag requests to be moved to a tag or needs a new tag. + * * @signal request::tag + * @classsignal */ -/** +/** When the client requests to become urgent. + * * @signal request::urgent + * @classsignal */ /** Emitted during startup to gather the default client mousebindings. @@ -363,151 +377,231 @@ */ /** + * Emitted when the client is raised within its layer. + * * @signal raised + * @see below + * @see above + * @see ontop + * @see raise + * @see lower + * @see lowered */ -/** +/** Emitted when the client is lowered within its layer. + * * @signal lowered + * @see below + * @see above + * @see ontop + * @see raise + * @see lower + * @see raised */ /** * The focused `client` or nil (in case there is none). * + * It is not recommanded to set the focused client using + * this property. Please use `c:activate{}` instead of + * `client.focus = c`. Setting the focus directly bypasses + * all the filters and emits fewer signals, which tend to + * cause unwanted side effects and make it harder to alter + * the code behavior in the future. It usually takes *more* + * code to use this rather than `:activate{}` because all + * the boilerplate code (such as `c:raise()`) needs to be + * added everywhere. + * + * The main use case for this field is to check *when* there + * is an active client. + * + * if client.focus ~= nil then + * -- do something + * end + * + * If you want to check if a client is active, use: + * + * if c.active then + * -- do something + * end + * * @tfield client focus + * @see active + * @see activate + * @see request::activate */ /** * The X window id. * - * **Signal:** - * - * * *property::window* + * This is rarely useful, but some DBus protocols will + * have this ID in their API, so it can be useful when + * writing AwesomeWM bindings for them. * * @property window - * @param string + * @tparam integer window + * @propemits false false */ /** * The client title. * - * **Signal:** - * - * * *property::name* + * This is the text which will be shown in the `awful.widget.tasklist` + * and the `awful.titlebar`. * * @property name - * @param string + * @tparam string name + * @propemits false false + * @see awful.titlebar + * @see awful.widget.tasklist */ /** * True if the client does not want to be in taskbar. * - * **Signal:** + * Some clients, like docked bars or some `sticky` clients + * such as wallpaper sensors like Conky have no value in + * the `awful.widget.tasklist` and should not be shown there. * - * * *property::skip\_taskbar* + * The default value of this property reflects the value of the + * `_NET_WM_STATE_SKIP_TASKBAR` X11 protocol xproperty. * * @property skip_taskbar - * @param boolean + * @tparam[opt=false] boolean skip_taskbar + * @propemits false false + * @see sticky */ +//TODO v5: Rename to skip_tasklist? + /** * The window type. * + * This is useful in, among other places, the `ruled.client` rules to apply + * different properties depending on the client types. It is also used + * throughout the API to alter the client (and `wibox`) behavior depending on + * the `type`. For example, clients with the `dock` type are placed on the side + * of the screen while other like `combo` are totally ignored and never + * considered `client`s in the first place. + * * Valid types are: * - * * **desktop**: The root client, it cannot be moved or resized. - * * **dock**: A client attached to the side of the screen. - * * **splash**: A client, usually without titlebar shown when an application starts. - * * **dialog**: A dialog, see `transient_for`. - * * **menu**: A context menu. - * * **toolbar**: A floating toolbar. - * * **utility**: - * * **dropdown_menu**: A context menu attached to a parent position. - * * **popup_menu**: A context menu. - * * **notification**: A notification popup. - * * **combo**: A combobox list menu. - * * **dnd**: A drag and drop indicator. - * * **normal**: A normal application main window. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
NameDescription
desktopThe root client, it cannot be moved or resized.
dockA client attached to the side of the screen.
splashA client, usually without titlebar shown when an application starts.
dialogA dialog, see `transient_for`.
menuA context menu.
toolbarA floating toolbar.
utility
dropdown_menuA context menu attached to a parent position.
popup_menuA context menu.
notificationA notification popup.
comboA combobox list menu.
dndA drag and drop indicator.
normalA normal application main window.
* * More information can be found [here](https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm140200472629520) * - * **Signal:** - * - * * *property::type* - * * @property type - * @param string + * @tparam string type + * @propemits false false + * @see ruled.client */ /** * The client class. * - * To get a client class from the command line, use the command `xprop - * WM_CLASS`. The class will be the second string. + * A class usually maps to the application name. It is useful in, among other + * places, the rules to apply different properties to different clients. It + * is also useful, along with `instance`, so implement "windows counter" + * used in many popular docks and Alt-Tab like popups. * - * **Signal:** + * To get a client class from the command line, use the command: * - * * *property::class* + * xprop WM_CLASS + * + * The class will be the second string. + * + * This *should* never change after the client is created, but some + * buggy application like the Spotify desktop client are known to + * violate the specification and do it anyway. There *is* a signal for + * this property, but it should hopefully never be useful. If your + * applications change their classes, please report a bug to them. + * It tends to break `ruled.client` and other AwesomeWM APIs. * * @property class - * @param string + * @tparam string class + * @propemits false false + * @see instance + * @see ruled.client */ /** * The client instance. * - * To get a client instance from the command line, use the command `xprop - * WM_CLASS`. The instance will be the first string. + * The `instance` is a subtype of the `class`. Each `class` can have + * multiple instances. This is useful in the `ruled.client` rules to + * filter clients and apply different properties to them. * - * **Signal:** + * To get a client instance from the command line, use the command: * - * * *property::instance* + * xprop WM_CLASS + * + * The instance will be the first string. * * @property instance - * @param string + * @tparam string instance + * @propemits false false + * @see class + * @see ruled.client */ /** * The client PID, if available. * - * **Signal:** - * - * * *property::pid* + * This will never change. * * @property pid - * @param number + * @tparam integer pid + * @propemits false false */ /** * The window role, if available. * - * **Signal:** - * - * * *property::role* - * * @property role - * @param string + * @tparam string role + * @propemits false false + * @see instance + * @see class */ /** * The machine client is running on. * - * **Signal:** - * - * * *property::machine* + * X11 windows can "live" in another computer but shown + * in another one. This is called "network transparency" + * and is either used directly by allowing remote windows + * using the `xhosts` command for using proxies such as + * `ssh -X` or `ssh -Y`. * * @property machine - * @param string + * @tparam string machine + * @propemits false false */ /** * The client name when iconified. * - * **Signal:** - * - * * *property::icon\_name* - * * @property icon_name - * @param string + * @tparam string icon_name + * @propemits false false */ /** @@ -526,67 +620,65 @@ * the same icon, it will cause a double-free error and Awesome will crash. To * get a copy of the icon, you can use: * - * local s = gears.surface(c.icon) - * local img = cairo.ImageSurface.create(cairo.Format.ARGB32, s:get_width(), s:get_height()) - * local cr = cairo.Context(img) - * cr:set_source_surface(s, 0, 0) - * cr:paint() - * - * **Signal:** - * - * * *property::icon* + * local s = gears.surface(c.icon) + * local img = cairo.ImageSurface.create(cairo.Format.ARGB32, s:get_width(), s:get_height()) + * local cr = cairo.Context(img) + * cr:set_source_surface(s, 0, 0) + * cr:paint() * * @property icon - * @param surface + * @tparam surface icon + * @propemits false false * @usage local ib = wibox.widget.imagebox(c.icon) + * @see awful.widget.clienticon */ /** * The available sizes of client icons. This is a table where each entry * contains the width and height of an icon. * - * **Signal:** - * - * * *property::icon\_sizes* - * * @property icon_sizes * @tparam table sizes + * @propemits false false + * @see awful.widget.clienticon * @see get_icon */ /** * Client screen. * - * **Signal:** + * The `screen` corresponds to the top-left corner of the window. * - * * *property::screen* + * Please note that clients can only be on one screen at once. X11 + * does not natively allow clients to be in multiple locations at + * once. Changing the screen directly will affect the tags and may + * cause several other changes to the state in order to ensure no + * screen specific code is changing the other screens clients. * * @property screen - * @param screen + * @tparam screen screen + * @propemits false false + * @see move_to_screen */ /** * Define if the client must be hidden, i.e. never mapped, * invisible in taskbar. * - * **Signal:** - * - * * *property::hidden* - * * @property hidden - * @param boolean + * @tparam boolean hidden + * @propemits false false + * @see minimized */ /** * Define it the client must be iconify, i.e. only visible in * taskbar. * - * **Signal:** - * - * * *property::minimized* - * * @property minimized - * @param boolean + * @tparam boolean minimized + * @propemits false false + * @see hidden */ /** @@ -598,19 +690,17 @@ * * This is enabled by default. To disable it by default, see `ruled.client`. * - * **Signal:** - * - * * *property::size\_hints\_honor* - * * @property size_hints_honor - * @param boolean + * @tparam boolean size_hints_honor + * @propemits false false * @see size_hints */ /** * The client border width. + * * @property border_width - * @param integer + * @tparam integer border_width * @propemits false false * @see request::border */ @@ -619,7 +709,7 @@ * The client border color. * * @property border_color - * @param color Any string, gradients and patterns will be converted to a + * @tparam color border_color Any string, gradients and patterns will be converted to a * cairo pattern. * @propemits false false * @see request::border @@ -629,12 +719,8 @@ /** * The client urgent state. * - * **Signal:** - * - * * *property::urgent* - * * @property urgent - * @param boolean + * @tparam boolean urgent * @propemits false false * @see request::border */ @@ -650,49 +736,58 @@ * * gears.surface(c.content):write_to_png(path) * + * Please note that once taken, the surface wont be + * updated when the client content changes. Since + * AwesomeWM does not have a compositor, the only way + * to get an animated client screenshot widget is to + * poll this property multiple time per seconds. This + * is very slow and should be used only when the said + * widget is visible rather than all the time. + * + * This property has no signals when the content changes. + * * @property content - * @param surface + * @tparam surface content + * @see gears.surface */ /** * The client opacity. * - * **Signal:** - * - * * *property::opacity* - * * @property opacity - * @param number Between 0 (transparent) to 1 (opaque) + * @tparam number opacity Between 0 (transparent) to 1 (opaque). * @propemits false false * @see request::border */ /** * The client is on top of every other windows. + * * @property ontop - * @param boolean + * @tparam boolean ontop + * @propemits false false + * @see below + * @see above */ /** * The client is above normal windows. * - * **Signal:** - * - * * *property::above* - * * @property above - * @param boolean + * @tparam boolean above + * @propemits false false + * @see below + * @see ontop */ /** * The client is below normal windows. * - * **Signal:** - * - * * *property::below* - * * @property below - * @param boolean + * @tparam boolean below + * @propemits false false + * @see above + * @see ontop */ /** @@ -747,42 +842,98 @@ /** * The client the window is transient for. * + * A transient window is a client that "belongs" to another + * client. If the client is also `modal`, then it always has + * to be on top of the other window *and* the parent client + * cannot be focused while the child client exists. + * This is common for "Save as" dialogs or other dialogs where + * isn't possible to modify the content of the "parent" client + * while the dialog is open. + * + * However, `modal` isn't a requirement for using the `transient_for` + * concept. "Tools" such as popup palette in canvas-and-palettes + * applications can belong to each other without being modal. + * + * However this it is also + * possible to have + * * @property transient_for - * @param client + * @tparam client transient_for * @propemits false false + * @see modal + * @see type + * @see is_transient_for + * @see get_transient_for_matching */ /** * Window identification unique to a group of windows. * + * This is the ID of the group window, not a client object. + * * @property group_window - * @param client + * @tparam integer group_window * @propemits false false + * @see leader_window */ /** * Identification unique to windows spawned by the same command. + * + * This is the ID of the group window, not a client object. + * * @property leader_window - * @param client + * @tparam number leader_window + * @propemits false false + * @see transient_for + * @see modal + * @see group_window */ /** * A table with size hints of the client. * + * Please note that most fields are optional and may or may not be set. + * + * When the client is tiled, the `size_hints` usually get in the way and + * cause the layouts to behave incorrectly. To mitigate this, it is often + * advised to set `size_hints_honor` to `false` in the `ruled.client` rules. + * * @property size_hints - * @param table - * @tfield integer table.user_position - * @tfield integer table.user_size - * @tfield integer table.program_position - * @tfield integer table.program_size - * @tfield integer table.max_width - * @tfield integer table.max_height - * @tfield integer table.min_width - * @tfield integer table.min_height - * @tfield integer table.width_inc - * @tfield integer table.height_inc + * @tparam[opt] table|nil hints The hints. + * @tparam[opt] table|nil hints.user_position A table with `x` and `y` keys. It + * contains the preferred position of the client. This is set when the + * position has been modified by the user. See `program_position`. + * @tparam[opt] table|nil hints.program_position A table with `x` and `y` keys. It + * contains the preferred position of the client. This is set when the + * application itself requests a specific position. See `user_position`. + * @tparam[opt] table|nil hints.user_size A table with `width` and `height`. This + * contains the client preferred size when it has previously been set by + * the user. See `program_size` for the equivalent when the applications + * itself wants to specify its preferred size. + * @tparam[opt] table|nil hints.program_size A table with `width` and `height`. This + * contains the client preferred size as specified by the application. + * @tparam[opt] integer|nil hints.max_width The maximum width (in pixels). + * @tparam[opt] integer|nil hints.max_height The maximum height (in pixels). + * @tparam[opt] integer|nil hints.min_width The minimum width (in pixels). + * @tparam[opt] integer|nil hints.min_height The minimum height (in pixels). + * @tparam[opt] integer|nil hints.width_inc The number of pixels by which the + * client width may be increased or decreased. For example, for terminals, + * the size has to be proportional with the monospace font size. + * @tparam[opt] integer|nil hints.height_inc The number of pixels by which the + * client height may be increased or decreased. For example, for terminals, + * the size has to be proportional with the monospace font size. + * @tparam[opt] string|nil hints.win_gravity The client `gravity` defines the corder + * from which the size is computed. For most clients, it is `north_west`, which + * corresponds to the top-left of the window. This will affect how the client + * is resized and other size related operations. + * @tparam[opt] integer|nil hints.min_aspect_num + * @tparam[opt] integer|nil hints.min_aspect_den + * @tparam[opt] integer|nil hints.max_aspect_num + * @tparam[opt] integer|nil hints.max_aspect_den * @propemits false false * @see size_hints_honor + * @see geometry */ /** @@ -797,103 +948,168 @@ * should be enabled. * * @property motif_wm_hints - * @param table - * @tfield[opt] table table.functions - * @tfield[opt] boolean table.functions.all - * @tfield[opt] boolean table.functions.resize - * @tfield[opt] boolean table.functions.move - * @tfield[opt] boolean table.functions.minimize - * @tfield[opt] boolean table.functions.maximize - * @tfield[opt] boolean table.functions.close - * @tfield[opt] table table.decorations - * @tfield[opt] boolean table.decorations.all - * @tfield[opt] boolean table.decorations.border - * @tfield[opt] boolean table.decorations.resizeh - * @tfield[opt] boolean table.decorations.title - * @tfield[opt] boolean table.decorations.menu - * @tfield[opt] boolean table.decorations.minimize - * @tfield[opt] boolean table.decorations.maximize - * @tfield[opt] string table.input_mode - * @tfield[opt] table table.status - * @tfield[opt] boolean table.status.tearoff_window + * @tparam table hints The hints. + * @tparam[opt] boolean hints.functions.all + * @tparam[opt] boolean hints.functions.resize + * @tparam[opt] boolean hints.functions.move + * @tparam[opt] boolean hints.functions.minimize + * @tparam[opt] boolean hints.functions.maximize + * @tparam[opt] boolean hints.functions.close + * @tparam[opt] boolean hints.decorations.all + * @tparam[opt] boolean hints.decorations.border + * @tparam[opt] boolean hints.decorations.resizeh + * @tparam[opt] boolean hints.decorations.title + * @tparam[opt] boolean hints.decorations.menu + * @tparam[opt] boolean hints.decorations.minimize + * @tparam[opt] boolean hints.decorations.maximize + * @tparam[opt] string hints.input_mode This is either `modeless`, + * `primary_application_modal`, `system_modal`, + * `full_application_modal` or `unknown`. + * @tparam[opt] boolean hints.status.tearoff_window * @propemits false false */ /** * Set the client sticky, i.e. available on all tags. * + * Please note that AwesomeWM implements `sticky` clients + * per screens rather than globally like some other + * implementations. + * * @property sticky - * @param boolean + * @tparam boolean sticky * @propemits false false + * @see skip_taskbar */ /** * Indicate if the client is modal. * + * A transient window is a client that "belongs" to another + * client. If the client is also `modal`, then it always has + * to be on top of the other window *and* the parent client + * cannot be focused while the child client exists. + * This is common for "Save as" dialogs or other dialogs where + * isn't possible to modify the content of the "parent" client + * while the dialog is open. + * + * However, `modal` isn't a requirement for using the `transient_for` + * concept. "Tools" such as popup palette in canvas-and-palettes + * applications can belong to each other without being modal. + * * @property modal - * @param boolean + * @tparam boolean modal * @propemits false false + * @see transient_for */ /** * True if the client can receive the input focus. * + * The client wont get focused even when the user + * click on it. + * * @property focusable - * @param boolean + * @tparam boolean focusable * @propemits false false + * @see shape_input + * @see client.focus + * @see active + * @see activate */ /** * The client's bounding shape as set by awesome as a (native) cairo surface. * - * @see gears.surface.apply_shape_bounding + * The bounding shape is the outer shape of the client. It is outside of the + * border. + * + * Do not use this directly unless you want total control over the shape (such + * as shape with holes). Even then, it is usually recommended to use transparency + * in the titlebars and a compositing manager. For the vast majority use use + * cases, use the `shape` property. + * * @property shape_bounding - * @param surface + * @tparam surface shape_bounding * @propemits false false + * @see shape + * @see gears.surface.apply_shape_bounding + * @see gears.shape + * @see shape_clip + * @see shape_input + * @see client_shape_bounding + * @see client_shape_clip + * @see gears.surface */ /** * The client's clip shape as set by awesome as a (native) cairo surface. * - * **Signal:** - * - * * *property::shape\_clip* + * The shape_clip is the shape of the client *content*. It is *inside* the + * border. * * @property shape_clip - * @param surface + * @tparam surface shape_clip + * @propemits false false + * @see shape_bounding + * @see shape_input + * @see shape + * @see gears.surface.apply_shape_bounding + * @see gears.shape + * @see client_shape_bounding + * @see client_shape_clip + * @see gears.surface */ /** * The client's input shape as set by awesome as a (native) cairo surface. * - * **Signal:** - * - * * *property::shape\_input* + * The input shape is the shape where mouse input will be passed to the + * client rather than propagated below it. * * @property shape_input - * @param surface + * @tparam surface shape_input + * @propemits false false + * @see shape_bounding + * @see shape_clip + * @see shape + * @see gears.surface.apply_shape_bounding + * @see gears.shape + * @see client_shape_bounding + * @see client_shape_clip + * @see gears.surface */ /** * The client's bounding shape as set by the program as a (native) cairo surface. * - * **Signal:** - * - * * *property::shape\_client\_bounding* - * * @property client_shape_bounding - * @param surface + * @tparam surface client_shape_bounding + * @propemits false false + * @see shape_bounding + * @see shape_clip + * @see shape_input + * @see shape + * @see gears.surface.apply_shape_bounding + * @see gears.shape + * @see client_shape_clip + * @see gears.surface */ /** * The client's clip shape as set by the program as a (native) cairo surface. * - * **Signal:** - * - * * *property::shape\_client\_clip* - * * @property client_shape_clip - * @param surface + * @tparam surface client_shape_clip + * @propemits false false + * @see shape_bounding + * @see shape_clip + * @see shape_input + * @see shape + * @see gears.surface.apply_shape_bounding + * @see gears.shape + * @see client_shape_bounding + * @see gears.surface */ /** @@ -950,12 +1166,9 @@ * "snid", fix_startup_id, {}, {"awful.spawn", "ruled.client"} * ) * - * **Signal:** - * - * * *property::startup\_id* - * * @property startup_id - * @param string + * @tparam string startup_id + * @propemits false false * @see awful.spawn */ @@ -966,52 +1179,49 @@ * * local is_valid = pcall(function() return c.valid end) and c.valid * - * **Signal:** - * - * * *property::valid* - * * @property valid - * @param boolean + * @tparam boolean valid + * @propemits false false + * @see kill */ /** - * The first tag of the client. Optimized form of `c:tags()[1]`. + * The first tag of the client. * - * **Signal:** - * - * * *property::first\_tag* + * Optimized form of `c:tags()[1]`. Not every workflow uses the + * ability to set multiple tags to a client. It is often enough + * to only get the first tag and ignore everything else. * * @property first_tag - * @param tag - */ - -/** When the height or width changed. - * @signal property::size - * @see client.geometry - */ - -/** When the x or y coordinate changed. - * @signal property::position - * @see client.geometry + * @tparam tag first_tag + * @propemits false false + * @see tags */ /** Return client struts (reserved space at the edge of the screen). * - * @param struts A table with new strut values, or none. - * @return A table with strut values. + * The struts area is a table with a `left`, `right`, `top` and `bottom` + * keys to define how much space of the screen `workarea` this client + * should reserve for itself. + * + * @tparam table struts A table with new strut values, or none. + * @treturn table A table with strut values. * @method struts + * @see geometry + * @see screen.workarea */ /** Get or set mouse buttons bindings for a client. * * @property buttons - * @param table + * @tparam table buttons + * @propemits false false * @see awful.button */ /** Get the number of instances. * - * @return The number of client objects alive. + * @treturn integer The number of client objects alive. * @staticfct instances */ @@ -2561,6 +2771,9 @@ client_kill(client_t *c) * top to bottom). * @treturn table A table with clients. * @staticfct get + * @usage for _, c in client.get() do + * -- do something + * end */ static int luaA_client_get(lua_State *L) @@ -2600,7 +2813,7 @@ luaA_client_get(lua_State *L) /** Check if a client is visible on its screen. * - * @return A boolean value, true if the client is visible, false otherwise. + * @treturn boolean A boolean value, true if the client is visible, false otherwise. * @method isvisible */ static int @@ -2710,8 +2923,13 @@ out: /** Kill a client. + * + * This method can be used to close (kill) a **client** using the + * X11 protocol. To use the POSIX way to kill a **process**, use + * `awesome.kill`. * * @method kill + * @see awesome.kill */ static int luaA_client_kill(lua_State *L) @@ -2724,6 +2942,17 @@ luaA_client_kill(lua_State *L) /** Swap a client with another one in global client list. * @client c A client to swap with. * @method swap + * @emits swapped + * @emitstparam swapped client The other client. + * @emitstparam swapped boolean `true` when `:swap()` was called + * on *self* rather than the other client. `false` when + * `:swap()` was called on the other client. + * @emits list + * @see swapped + * @see awful.client.swap.bydirection + * @see awful.client.swap.global_bydirection + * @see awful.client.swap.byidx + * @see awful.client.cycle */ static int luaA_client_swap(lua_State *L) @@ -2766,14 +2995,13 @@ luaA_client_swap(lua_State *L) * * Use the `first_tag` field to access the first tag of a client directly. * - * **Signal:** - * - * * *property::tags* - * * @tparam table tags_table A table with tags to set, or `nil` to get the * current tags. * @treturn table A table with all tags. * @method tags + * @emits property::tags + * @see first_tag + * @see toggle_tag */ static int luaA_client_tags(lua_State *L) @@ -2843,6 +3071,11 @@ luaA_client_get_first_tag(lua_State *L, client_t *c) /** Raise a client on top of others which are on the same layer. * * @method raise + * @emits raised + * @see above + * @see below + * @see ontop + * @see lower */ static int luaA_client_raise(lua_State *L) @@ -2864,6 +3097,11 @@ luaA_client_raise(lua_State *L) /** Lower a client on bottom of others which are on the same layer. * * @method lower + * @emits lowered + * @see above + * @see below + * @see ontop + * @see raise */ static int luaA_client_lower(lua_State *L) @@ -3119,8 +3357,17 @@ HANDLE_TITLEBAR(left, CLIENT_TITLEBAR_LEFT) /** Return or set client geometry. * * @tparam table|nil geo A table with new coordinates, or nil. + * @tparam integer geo.x The horizontal position. + * @tparam integer geo.y The vertical position. + * @tparam integer geo.width The width. + * @tparam integer geo.width The height. * @treturn table A table with client geometry and coordinates. * @method geometry + * @see struts + * @see x + * @see y + * @see width + * @see height */ static int luaA_client_geometry(lua_State *L) @@ -3153,11 +3400,19 @@ luaA_client_geometry(lua_State *L) /** Apply size hints to a size. * - * @param width Desired width of client - * @param height Desired height of client - * @return Actual width of client - * @return Actual height of client + * This method applies the client size hints. The client + * will be resized according to the size hints as long + * as `size_hints_honor` is true. Regardless of the + * status of `size_hints_honor`, this method will + * return the size with the size hints applied. + * + * @tparam integer width Desired width of client + * @tparam integer height Desired height of client + * @treturn integer Actual width of client + * @treturn integer Actual height of client * @method apply_size_hints + * @see size_hints + * @see size_hints_honor */ static int luaA_client_apply_size_hints(lua_State *L) @@ -3773,7 +4028,8 @@ luaA_client_set_shape_input(lua_State *L, client_t *c) /** Get or set keys bindings for a client. * * @property keys - * @param table + * @tparam table keys + * @propemits false false * @see awful.key */ static int @@ -3816,10 +4072,6 @@ luaA_client_get_icon_sizes(lua_State *L, client_t *c) } /** Get the client's n-th icon. - * - * **Signal:** - * - * * *property::icon* * * @tparam interger index The index in the list of icons to get. * @treturn surface A lightuserdata for a cairo surface. This reference must be From 575b0f12dc02d24b9d85aafc89d215d2d863994b Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage-Vallee Date: Mon, 30 Dec 2019 22:09:39 -0800 Subject: [PATCH 14/20] doc: Remove all type aliases. They render poorly and serve no purpose. #!/bin/bash for FILE in $(git ls-files | grep -E "\.(h|c|lua)" | grep -v tests | grep -v spec); do sed -i 's/^[ ]*--*[ ]*@client /-- @tparam client /g' $FILE done --- docs/02-contributing.md | 5 --- docs/common/rules_index.ldoc | 1 + docs/config.ld | 8 ----- lib/awful/client.lua | 66 +++++++++++++++++----------------- lib/awful/client/focus.lua | 12 +++---- lib/awful/client/shape.lua | 8 ++--- lib/awful/client/urgent.lua | 4 +-- lib/awful/permissions/init.lua | 6 ++-- lib/awful/placement.lua | 2 +- lib/awful/screen.lua | 8 ++--- lib/awful/spawn.lua | 6 ++-- lib/awful/tag.lua | 2 +- lib/awful/widget/common.lua | 8 ++--- lib/naughty/core.lua | 2 +- lib/naughty/notification.lua | 2 +- lib/ruled/client.lua | 28 +++++++-------- lib/wibox/widget/base.lua | 10 +++--- objects/client.c | 6 ++-- objects/screen.c | 2 +- objects/tag.c | 4 +-- 20 files changed, 89 insertions(+), 101 deletions(-) diff --git a/docs/02-contributing.md b/docs/02-contributing.md index ceb31e37d..dcde71447 100644 --- a/docs/02-contributing.md +++ b/docs/02-contributing.md @@ -83,11 +83,6 @@ Parameters of functions should be documented using For a more comprehensive description of the available tags see the [LDoc documentation](https://stevedonovan.github.io/ldoc/manual/doc.md.html). -In addition to the regular tags provided by LDoc there are also some aliases -for typed parameters defined in `docs/config.ld`, e.g. `@client` for -`@tparam client.object`, `@tag` for `@tparam tag` and `@tab` for -`@tparam table`). - ## Patches If you plan to submit patches, you should follow the following guidelines. diff --git a/docs/common/rules_index.ldoc b/docs/common/rules_index.ldoc index eeecdbda3..207e562e6 100644 --- a/docs/common/rules_index.ldoc +++ b/docs/common/rules_index.ldoc @@ -25,6 +25,7 @@ -- dockableIf the client is dockable -- requests\_no\_titlebarIf the client requests not to be decorated with a titlebar -- shapeSet the client shape +-- activeReturn true if the client is active (has focus) -- windowThe X window id -- nameThe client title -- skip\_taskbarTrue if the client does not want to be in taskbar diff --git a/docs/config.ld b/docs/config.ld index afceff201..8e1c9f0b3 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -44,14 +44,6 @@ topics={ '89-NEWS.md', } --- Setup @client to be an alias for "@tparam client.object" -tparam_alias('client', 'client.object') -tparam_alias('tag', 'tag') --- Should be default, but is not. Sets up "@tab" => "@tparam table". -tparam_alias('tab', 'table') -tparam_alias('screen', 'screen') -tparam_alias('screen_or_idx', 'screen|int') - -- The first stereotype are the constructors. new_type("constructorfct", "Constructors", false, "Parameters") new_type("constructorfct2", "ldoc_skip", false, "Parameters") diff --git a/lib/awful/client.lua b/lib/awful/client.lua index 246b7f245..1bf8a6593 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -157,7 +157,7 @@ client.focus = require("awful.client.focus") -- -- @deprecated awful.client.jumpto -- @see client.jump_to --- @client c the client to jump to +-- @tparam client c the client to jump to -- @tparam bool|function merge If true then merge tags (select the client's -- first tag additionally) when the client is not visible. -- If it is a function, it will be called with the client and its first @@ -251,7 +251,7 @@ end -- -- @staticfct awful.client.next -- @tparam int i The index. Use 1 to get the next, -1 to get the previous. --- @client[opt] sel The client. +-- @tparam[opt] client sel The client. -- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom) -- @treturn[opt] client|nil A client, or nil if no client is available. -- @@ -287,7 +287,7 @@ end -- -- @staticfct awful.client.swap.bydirection -- @tparam string dir The direction, can be either "up", "down", "left" or "right". --- @client[opt=focused] c The client. +-- @tparam[opt=focused] client c The client. -- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom) -- @see swap -- @see swapped @@ -316,7 +316,7 @@ end -- Swaps across screens. -- @staticfct awful.client.swap.global_bydirection -- @tparam string dir The direction, can be either "up", "down", "left" or "right". --- @client[opt] sel The client. +-- @tparam[opt] client sel The client. -- @request client activate client.swap.global_bydirection granted When a client -- could be activated because `awful.client.swap.global_bydirection` was called. -- @see swap @@ -357,7 +357,7 @@ end -- -- @staticfct awful.client.swap.byidx -- @tparam integer i The index. --- @client[opt] c The client, otherwise focused one is used. +-- @tparam[opt] client c The client, otherwise focused one is used. -- @see swap -- @see swapped -- @see awful.client.swap.bydirection @@ -429,7 +429,7 @@ end --- Get the master window. -- -- @legacylayout awful.client.getmaster --- @screen_or_idx[opt=awful.screen.focused()] s The screen. +-- @tparam[opt=awful.screen.focused()] screen s The screen. -- @treturn client The master client. function client.getmaster(s) s = s or screen.focused() @@ -439,7 +439,7 @@ end --- Set the client as master: put it at the beginning of other windows. -- -- @legacylayout awful.client.setmaster --- @client c The window to set as master. +-- @tparam client c The window to set as master. function client.setmaster(c) local cls = gtable.reverse(capi.client.get(c.screen)) for _, v in pairs(cls) do @@ -449,7 +449,7 @@ end --- Set the client as slave: put it at the end of other windows. -- @legacylayout awful.client.setslave --- @client c The window to set as slave. +-- @tparam client c The window to set as slave. function client.setslave(c) local cls = capi.client.get(c.screen) for _, v in pairs(cls) do @@ -463,7 +463,7 @@ end -- @tparam integer y The relative y coordinate. -- @tparam integer w The relative width. -- @tparam integer h The relative height. --- @client[opt] c The client, otherwise focused one is used. +-- @tparam[opt] client c The client, otherwise focused one is used. -- @see client.relative_move function client.moveresize(x, y, w, h, c) gdebug.deprecate("Use c:relative_move(x, y, w, h) instead of awful.client.moveresize", {deprecated_in=4}) @@ -489,7 +489,7 @@ end --- Move a client to a tag. -- @deprecated awful.client.movetotag -- @tparam tag target The tag to move the client to. --- @client[opt] c The client to move, otherwise the focused one is used. +-- @tparam[opt] client c The client to move, otherwise the focused one is used. -- @see client.move_to_tag function client.movetotag(target, c) gdebug.deprecate("Use c:move_to_tag(target) instead of awful.client.movetotag", {deprecated_in=4}) @@ -519,7 +519,7 @@ end -- -- @deprecated awful.client.toggletag -- @tparam tag target The tag to toggle. --- @client[opt] c The client to toggle, otherwise the focused one is used. +-- @tparam[opt] client c The client to toggle, otherwise the focused one is used. -- @see client.toggle_tag -- @see tags function client.toggletag(target, c) @@ -556,7 +556,7 @@ end --- Move a client to a screen. Default is next screen, cycling. -- @deprecated awful.client.movetoscreen --- @client c The client to move. +-- @tparam client c The client to move. -- @tparam screen s The screen, default to current + 1. -- @see screen -- @see client.move_to_screen @@ -660,7 +660,7 @@ end --- Mark a client, and then call 'marked' hook. -- @deprecated awful.client.mark --- @client c The client to mark, the focused one if not specified. +-- @tparam client c The client to mark, the focused one if not specified. function client.mark(c) gdebug.deprecate("Use c.marked = true instead of awful.client.mark", {deprecated_in=4}) client.object.set_marked(c or capi.client.focus, true) @@ -668,7 +668,7 @@ end --- Unmark a client and then call 'unmarked' hook. -- @deprecated awful.client.unmark --- @client c The client to unmark, or the focused one if not specified. +-- @tparam client c The client to unmark, or the focused one if not specified. function client.unmark(c) gdebug.deprecate("Use c.marked = false instead of awful.client.unmark", {deprecated_in=4}) client.object.set_marked(c or capi.client.focus, false) @@ -676,7 +676,7 @@ end --- Check if a client is marked. -- @deprecated awful.client.ismarked --- @client c The client to check, or the focused one otherwise. +-- @tparam client c The client to check, or the focused one otherwise. function client.ismarked(c) gdebug.deprecate("Use c.marked instead of awful.client.ismarked", {deprecated_in=4}) return client.object.get_marked(c or capi.client.focus) @@ -684,7 +684,7 @@ end --- Toggle a client as marked. -- @deprecated awful.client.togglemarked --- @client c The client to toggle mark. +-- @tparam client c The client to toggle mark. function client.togglemarked(c) gdebug.deprecate("Use c.marked = not c.marked instead of awful.client.togglemarked", {deprecated_in=4}) c = c or capi.client.focus @@ -712,7 +712,7 @@ end --- Set a client floating state, overriding auto-detection. -- Floating client are not handled by tiling layouts. -- @deprecated awful.client.floating.set --- @client c A client. +-- @tparam client c A client. -- @tparam boolean s True or false. function client.floating.set(c, s) gdebug.deprecate("Use c.floating = true instead of awful.client.floating.set", {deprecated_in=4}) @@ -721,7 +721,7 @@ end -- Set a client floating state, overriding auto-detection. -- Floating client are not handled by tiling layouts. --- @client c A client. +-- @tparam client c A client. -- @tparam boolan s True or false. function client.object.set_floating(c, s) c = c or capi.client.focus @@ -760,7 +760,7 @@ capi.client.connect_signal("property::geometry", store_floating_geometry) --- Return if a client has a fixed size or not. -- This function is deprecated, use `c.is_fixed` --- @client c The client. +-- @tparam client c The client. -- @deprecated awful.client.isfixed -- @see is_fixed -- @see size_hints_honor @@ -826,7 +826,7 @@ function client.object.is_immobilized_vertical(c) end --- Get a client floating state. --- @client c A client. +-- @tparam client c A client. -- @see floating -- @deprecated awful.client.floating.get -- @treturn boolean True or false. Note that some windows might be floating even if you @@ -910,7 +910,7 @@ capi.client.connect_signal("request::manage", update_implicitly_floating) --- Toggle the floating state of a client between 'auto' and 'true'. -- Use `c.floating = not c.floating` -- @deprecated awful.client.floating.toggle --- @client c A client. +-- @tparam client c A client. -- @see floating function client.floating.toggle(c) c = c or capi.client.focus @@ -919,7 +919,7 @@ function client.floating.toggle(c) end -- Remove the floating information on a client. --- @client c The client. +-- @tparam client c The client. function client.floating.delete(c) client.object.set_floating(c, nil) end @@ -1026,7 +1026,7 @@ end -- number of visible clients in this column. -- -- @legacylayout awful.client.idx --- @client c the client +-- @tparam client c the client -- @treturn integer col The column number. -- @treturn integer idx Index of the client in the column. -- @treturn integer num The number of visible clients in the column. @@ -1088,7 +1088,7 @@ end -- -- @legacylayout awful.client.setwfact -- @tparam number wfact the window factor value --- @client c the client +-- @tparam client c the client -- @emits property::windowfact function client.setwfact(wfact, c) -- get the currently selected window @@ -1144,7 +1144,7 @@ end -- @tparam number add Amount to increase/decrease the client's window factor. -- Should be between `-current_window_factor` and something close to -- infinite. The normalisation then ensures that the sum of all factors is 1. --- @client c the client. +-- @tparam client c the client. -- @emits property::windowfact function client.incwfact(add, c) c = c or capi.client.focus @@ -1167,7 +1167,7 @@ end --- Get a client's dockable state. -- --- @client c A client. +-- @tparam client c A client. -- @treturn bool -- @deprecated awful.client.dockable.get function client.dockable.get(c) @@ -1207,7 +1207,7 @@ end -- With this enabled you can dock windows by moving them from the center -- to the edge of the workarea. -- --- @client c A client. +-- @tparam client c A client. -- @tparam boolean value True or false. -- @deprecated awful.client.dockable.set function client.dockable.set(c, value) @@ -1249,7 +1249,7 @@ end) -- -- This method is deprecated. It is now possible to use `c.value` directly. -- --- @client c The client. +-- @tparam client c The client. -- @tparam string prop The property name. -- @return The property value. -- @deprecated awful.client.property.get @@ -1273,7 +1273,7 @@ end -- This method is deprecated. It is now possible to use `c.value = value` -- directly. -- --- @client c The client. +-- @tparam client c The client. -- @tparam string prop The property name. -- @param value The property value. -- @deprecated awful.client.property.set @@ -1377,7 +1377,7 @@ end --- Get a matching transient_for client (if any). -- @deprecated awful.client.get_transient_for_matching -- @see client.get_transient_for_matching --- @client c The client. +-- @tparam client c The client. -- @tparam function matcher A function that should return true, if -- a matching parent client is found. -- @treturn client|nil The matching parent client or nil. @@ -1411,8 +1411,8 @@ end -- -- @deprecated awful.client.is_transient_for -- @see client.is_transient_for --- @client c The child client (having transient_for). --- @client c2 The parent client to check. +-- @tparam client c The child client (having transient_for). +-- @tparam client c2 The parent client to check. -- @treturn client|nil The parent client or nil. function client.is_transient_for(c, c2) gdebug.deprecate("Use c:is_transient_for(c2) instead of".. @@ -1430,7 +1430,7 @@ end -- likely return values. -- -- @method is_transient_for --- @client c2 The parent client to check. +-- @tparam client c2 The parent client to check. -- @treturn client|nil The parent client or nil. -- @see transient_for -- @see modal diff --git a/lib/awful/client/focus.lua b/lib/awful/client/focus.lua index 4ba75221a..f9dbb0ecc 100644 --- a/lib/awful/client/focus.lua +++ b/lib/awful/client/focus.lua @@ -44,7 +44,7 @@ end --- Remove a client from the focus history -- --- @client c The client that must be removed. +-- @tparam client c The client that must be removed. -- @function awful.client.focus.history.delete function focus.history.delete(c) for k, v in ipairs(focus.history.list) do @@ -59,7 +59,7 @@ end -- -- @function awful.client.focus.byidx -- @param i The index. --- @client[opt] c The client. +-- @tparam[opt] client c The client. -- @request client activate client.focus.byidx granted When `awful.focus.byidx` -- is called. function focus.byidx(i, c) @@ -74,7 +74,7 @@ end -- This usually means that desktop, dock and splash windows are -- not registered and cannot get focus. -- --- @client c A client. +-- @tparam client c A client. -- @return The same client if it's ok, nil otherwise. -- @function awful.client.focus.filter function focus.filter(c) @@ -89,7 +89,7 @@ end --- Update client focus history. -- --- @client c The client that has been focused. +-- @tparam client c The client that has been focused. -- @function awful.client.focus.history.add function focus.history.add(c) -- Remove the client if its in stack @@ -159,7 +159,7 @@ end -- -- @tparam string dir The direction, can be either -- `"up"`, `"down"`, `"left"` or `"right"`. --- @client[opt] c The client. +-- @tparam[opt] client c The client. -- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom) -- @function awful.client.focus.bydirection -- @request client activate client.focus.bydirection granted When @@ -186,7 +186,7 @@ end --- Focus a client by the given direction. Moves across screens. -- -- @param dir The direction, can be either "up", "down", "left" or "right". --- @client[opt] c The client. +-- @tparam[opt] client c The client. -- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom) -- @function awful.client.focus.global_bydirection -- @request client activate client.focus.global_bydirection granted When diff --git a/lib/awful/client/shape.lua b/lib/awful/client/shape.lua index 6dcb563e4..ec0fd3db2 100644 --- a/lib/awful/client/shape.lua +++ b/lib/awful/client/shape.lua @@ -19,7 +19,7 @@ shape.update = {} --- Get one of a client's shapes and transform it to include window decorations. -- @function awful.client.shape.get_transformed --- @client c The client whose shape should be retrieved +-- @tparam client c The client whose shape should be retrieved -- @tparam string shape_name Either "bounding" or "clip" function shape.get_transformed(c, shape_name) local border = shape_name == "bounding" and c.border_width or 0 @@ -91,7 +91,7 @@ end --- Update all of a client's shapes from the shapes the client set itself. -- @function awful.client.shape.update.all --- @client c The client to act on +-- @tparam client c The client to act on function shape.update.all(c) shape.update.bounding(c) shape.update.clip(c) @@ -99,7 +99,7 @@ end --- Update a client's bounding shape from the shape the client set itself. -- @function awful.client.shape.update.bounding --- @client c The client to act on +-- @tparam client c The client to act on function shape.update.bounding(c) local res = shape.get_transformed(c, "bounding") c.shape_bounding = res and res._native @@ -111,7 +111,7 @@ end --- Update a client's clip shape from the shape the client set itself. -- @function awful.client.shape.update.clip --- @client c The client to act on +-- @tparam client c The client to act on function shape.update.clip(c) local res = shape.get_transformed(c, "clip") c.shape_clip = res and res._native diff --git a/lib/awful/client/urgent.lua b/lib/awful/client/urgent.lua index dd1602d7a..49cf36470 100644 --- a/lib/awful/client/urgent.lua +++ b/lib/awful/client/urgent.lua @@ -60,7 +60,7 @@ end --- Adds client to urgent stack. -- -- @function awful.urgent.add --- @client c The client object. +-- @tparam client c The client object. -- @param prop The property which is updated. -- @request client border active granted When a client becomes active and is no -- longer urgent. @@ -91,7 +91,7 @@ end --- Remove client from urgent stack. -- -- @function awful.urgent.delete --- @client c The client object. +-- @tparam client c The client object. function urgent.delete(c) for k, cl in ipairs(data) do if c == cl then diff --git a/lib/awful/permissions/init.lua b/lib/awful/permissions/init.lua index cf4fcab65..1a2fc3c02 100644 --- a/lib/awful/permissions/init.lua +++ b/lib/awful/permissions/init.lua @@ -137,7 +137,7 @@ end -- It is the default signal handler for `request::activate` on a `client`. -- -- @signalhandler awful.permissions.activate --- @client c A client to use +-- @tparam client c A client to use -- @tparam string context The context where this signal was used. -- @tparam[opt] table hints A table with additional hints: -- @tparam[opt=false] boolean hints.raise should the client be raised? @@ -283,7 +283,7 @@ end -- It is the default signal handler for `request::tag` on a `client`. -- -- @signalhandler awful.permissions.tag --- @client c A client to tag +-- @tparam client c A client to tag -- @tparam[opt] tag|boolean t A tag to use. If true, then the client is made sticky. -- @tparam[opt={}] table hints Extra information function permissions.tag(c, t, hints) --luacheck: no unused @@ -310,7 +310,7 @@ end --- Handle client urgent request -- @signalhandler awful.permissions.urgent --- @client c A client +-- @tparam client c A client -- @tparam boolean urgent If the client should be urgent function permissions.urgent(c, urgent) if c ~= client.focus and not aclient.property.get(c,"ignore_urgent") then diff --git a/lib/awful/placement.lua b/lib/awful/placement.lua index 354c81a41..fc79d5b9b 100644 --- a/lib/awful/placement.lua +++ b/lib/awful/placement.lua @@ -849,7 +849,7 @@ end --- Place the client so no part of it will be outside the screen (workarea). --@DOC_awful_placement_no_offscreen_EXAMPLE@ --- @client c The client. +-- @tparam client c The client. -- @tparam[opt={}] table args The arguments -- @tparam[opt=client's screen] integer args.screen The screen. -- @treturn table The new client geometry. diff --git a/lib/awful/screen.lua b/lib/awful/screen.lua index a1dfda78c..06ec07359 100644 --- a/lib/awful/screen.lua +++ b/lib/awful/screen.lua @@ -88,7 +88,7 @@ end -- This moves the mouse pointer to the last known position on the new screen, -- or keeps its position relative to the current focused screen. -- @staticfct awful.screen.focus --- @screen _screen Screen number (defaults / falls back to mouse.screen). +-- @tparam screen _screen Screen number (defaults / falls back to mouse.screen). -- @request client activate screen.focus granted The most recent focused client -- for this screen should be re-activated. function screen.focus(_screen) @@ -361,9 +361,9 @@ end -- @tparam[opt] int|table args.margins Apply some margins on the output. -- This can either be a number or a table with *left*, *right*, *top* -- and *bottom* keys. --- @tag[opt] args.tag Use this tag's screen. +-- @tparam[opt] tag args.tag Use this tag's screen. -- @tparam[opt] drawable args.parent A parent drawable to use as base geometry. --- @tab[opt] args.bounding_rect A bounding rectangle. This parameter is +-- @tparam[opt] table args.bounding_rect A bounding rectangle. This parameter is -- incompatible with `honor_workarea`. -- @treturn table A table with *x*, *y*, *width* and *height*. -- @usage local geo = screen:get_bounding_geometry { @@ -516,7 +516,7 @@ end -- -- @staticfct awful.screen.connect_for_each_screen -- @tparam function func The function to call. --- @screen func.screen The screen. +-- @tparam screen func.screen The screen. function screen.connect_for_each_screen(func) for s in capi.screen do func(s) diff --git a/lib/awful/spawn.lua b/lib/awful/spawn.lua index ff41e0ea0..2ba1903f9 100644 --- a/lib/awful/spawn.lua +++ b/lib/awful/spawn.lua @@ -374,7 +374,7 @@ end --- Spawn a program and asynchronously capture its output line by line. -- @tparam string|table cmd The command. --- @tab callbacks Table containing callbacks that should be invoked on +-- @tparam table callbacks Table containing callbacks that should be invoked on -- various conditions. -- @tparam[opt] function callbacks.stdout Function that is called with each -- line of output on stdout, e.g. `stdout(line)`. @@ -428,7 +428,7 @@ end --- Asynchronously spawn a program and capture its output. -- (wraps `spawn.with_line_callback`). -- @tparam string|table cmd The command. --- @tab callback Function with the following arguments +-- @tparam table callback Function with the following arguments -- @tparam string callback.stdout Output on stdout. -- @tparam string callback.stderr Output on stderr. -- @tparam string callback.exitreason Exit reason ("exit" or "signal"). @@ -479,7 +479,7 @@ end --- Call `spawn.easy_async` with a shell. -- This calls `cmd` with `$SHELL -c` (via `awful.util.shell`). -- @tparam string cmd The command. --- @tab callback Function with the following arguments +-- @tparam table callback Function with the following arguments -- @tparam string callback.stdout Output on stdout. -- @tparam string callback.stderr Output on stderr. -- @tparam string callback.exitreason Exit reason ("exit" or "signal"). diff --git a/lib/awful/tag.lua b/lib/awful/tag.lua index 05f199f20..4bedff293 100644 --- a/lib/awful/tag.lua +++ b/lib/awful/tag.lua @@ -1670,7 +1670,7 @@ end -- future. When a tag is detached from the screen, its signal is removed. -- -- @staticfct awful.tag.attached_connect_signal --- @screen screen The screen concerned, or all if nil. +-- @tparam screen screen The screen concerned, or all if nil. -- @tparam[opt] string signal The signal name. -- @tparam[opt] function Callback function tag.attached_connect_signal(screen, ...) diff --git a/lib/awful/widget/common.lua b/lib/awful/widget/common.lua index db67b0629..138a8c6bb 100644 --- a/lib/awful/widget/common.lua +++ b/lib/awful/widget/common.lua @@ -17,7 +17,7 @@ local base = require("wibox.widget.base") local common = {} --- Common method to create buttons. --- @tab buttons +-- @tparam table buttons -- @param object -- @treturn table function common.create_buttons(buttons, object) @@ -112,12 +112,12 @@ end --- Common update method. -- @param w The widget. --- @tab buttons +-- @tparam table buttons -- @func label Function to generate label parameters from an object. -- The function gets passed an object from `objects`, and -- has to return `text`, `bg`, `bg_image`, `icon`. --- @tab data Current data/cache, indexed by objects. --- @tab objects Objects to be displayed / updated. +-- @tparam table data Current data/cache, indexed by objects. +-- @tparam table objects Objects to be displayed / updated. -- @tparam[opt={}] table args function common.list_update(w, buttons, label, data, objects, args) -- update the widgets, creating them if needed diff --git a/lib/naughty/core.lua b/lib/naughty/core.lua index 92342f9e3..497528790 100644 --- a/lib/naughty/core.lua +++ b/lib/naughty/core.lua @@ -611,7 +611,7 @@ end -- -- local notif = naughty.notification(args) -- --- @tab args The argument table containing any of the arguments below. +-- @tparam table args The argument table containing any of the arguments below. -- @string[opt=""] args.text Text of the notification. -- @string[opt] args.title Title of the notification. -- @int[opt=5] args.timeout Time in seconds after which popup expires. diff --git a/lib/naughty/notification.lua b/lib/naughty/notification.lua index 5edb45e70..4d2fba6d7 100644 --- a/lib/naughty/notification.lua +++ b/lib/naughty/notification.lua @@ -757,7 +757,7 @@ end --- Create a notification. -- --- @tab args The argument table containing any of the arguments below. +-- @tparam table args The argument table containing any of the arguments below. -- @string[opt=""] args.text Text of the notification. -- @string[opt] args.title Title of the notification. -- @int[opt=5] args.timeout Time in seconds after which popup expires. diff --git a/lib/ruled/client.lua b/lib/ruled/client.lua index f8b13331e..c0cca1433 100644 --- a/lib/ruled/client.lua +++ b/lib/ruled/client.lua @@ -123,8 +123,8 @@ local module = {} local crules = gmatcher() --- Check if a client matches a rule. --- @client c The client. --- @tab rule The rule to check. +-- @tparam client c The client. +-- @tparam table rule The rule to check. -- @treturn bool True if it matches, false otherwise. -- @staticfct ruled.client.match function module.match(c, rule) @@ -132,8 +132,8 @@ function module.match(c, rule) end --- Check if a client matches any part of a rule. --- @client c The client. --- @tab rule The rule to check. +-- @tparam client c The client. +-- @tparam table 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) @@ -141,8 +141,8 @@ function module.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 +-- @tparam client c The client. +-- @tparam table entry Rule entry (with keys `rule`, `rule_any`, `except` and/or -- `except_any`). -- @treturn bool -- @staticfct ruled.client.matches @@ -151,8 +151,8 @@ function module.matches(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 +-- @tparam client c The client. +-- @tparam table _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 @@ -161,8 +161,8 @@ function module.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`, +-- @tparam client c The client. +-- @tparam table _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 @@ -179,7 +179,7 @@ function module.remove_rule_source(name) end --- Apply ruled.client.rules to a client. --- @client c The client. +-- @tparam client c The client. -- @staticfct ruled.client.apply function module.apply(c) return crules:apply(c) @@ -525,9 +525,9 @@ function module.high_priority_properties.tags(c, value, props) end --- Apply properties and callbacks to a client. --- @client c The client. --- @tab props Properties to apply. --- @tab[opt] callbacks Callbacks to apply. +-- @tparam client c The client. +-- @tparam table props Properties to apply. +-- @tparam[opt] table callbacks Callbacks to apply. -- @staticfct ruled.client.execute -- @request client titlebars rules granted The `titlebars_enabled` is set in the -- rules. diff --git a/lib/wibox/widget/base.lua b/lib/wibox/widget/base.lua index ec4a491ef..37f450e5c 100644 --- a/lib/wibox/widget/base.lua +++ b/lib/wibox/widget/base.lua @@ -150,7 +150,7 @@ end -- -- The default implementation does nothing, this must be re-implemented by -- all layout and container widgets. --- @tab children A table composed of valid widgets. +-- @tparam table children A table composed of valid widgets. -- @method set_children function base.widget:set_children(children) -- luacheck: no unused -- Nothing on purpose @@ -309,7 +309,7 @@ end -- This calls the widget's `:fit` callback and caches the result for later use. -- Never call `:fit` directly, but always through this function! -- @tparam widget parent The parent widget which requests this information. --- @tab context The context in which we are fit. +-- @tparam table context The context in which we are fit. -- @tparam widget widget The widget to fit (this uses -- `widget:fit(context, width, height)`). -- @tparam number width The available width for the widget. @@ -358,7 +358,7 @@ end -- However, normally there shouldn't be any reason why you need to use this -- function. -- @tparam widget parent The parent widget which requests this information. --- @tab context The context in which we are laid out. +-- @tparam table context The context in which we are laid out. -- @tparam widget widget The widget to layout (this uses -- `widget:layout(context, width, height)`). -- @tparam number width The available width for the widget. @@ -574,7 +574,7 @@ end --- Set a declarative widget hierarchy description. -- -- See [The declarative layout system](../documentation/03-declarative-layout.md.html). --- @tab args A table containing the widget's disposition. +-- @tparam table args A table containing the widget's disposition. -- @method setup function base.widget:setup(args) local f,ids = self.set_widget or self.add or self.set_first,{} @@ -601,7 +601,7 @@ end --- Create a widget from a declarative description. -- -- See [The declarative layout system](../documentation/03-declarative-layout.md.html). --- @tab args A table containing the widgets disposition. +-- @tparam table args A table containing the widgets disposition. -- @constructorfct wibox.widget.base.make_widget_declarative function base.make_widget_declarative(args) local ids = {} diff --git a/objects/client.c b/objects/client.c index 7bd1cd359..bde2695b9 100644 --- a/objects/client.c +++ b/objects/client.c @@ -364,7 +364,7 @@ /** When a client gets tagged. * @signal tagged - * @tag t The tag object. + * @tparam tag t The tag object. */ /** When a client gets unfocused. @@ -373,7 +373,7 @@ /** When a client gets untagged. * @signal untagged - * @tag t The tag object. + * @tparam tag t The tag object. */ /** @@ -2940,7 +2940,7 @@ luaA_client_kill(lua_State *L) } /** Swap a client with another one in global client list. - * @client c A client to swap with. + * @tparam client c A client to swap with. * @method swap * @emits swapped * @emitstparam swapped client The other client. diff --git a/objects/screen.c b/objects/screen.c index 230683684..5fd2b501b 100644 --- a/objects/screen.c +++ b/objects/screen.c @@ -1803,7 +1803,7 @@ luaA_screen_fake_resize(lua_State *L) * * @DOC_sequences_screen_swap_EXAMPLE@ * - * @client s A screen to swap with. + * @tparam client s A screen to swap with. * @method swap */ static int diff --git a/objects/tag.c b/objects/tag.c index f4747071b..a0050cc2a 100644 --- a/objects/tag.c +++ b/objects/tag.c @@ -240,12 +240,12 @@ /** When a client gets tagged with this tag. * @signal tagged - * @client c The tagged client. + * @tparam client c The tagged client. */ /** When a client gets untagged with this tag. * @signal untagged - * @client c The untagged client. + * @tparam client c The untagged client. */ /** From 74ba84b29937ac4869167732dda0f5924ddac136 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage-Vallee Date: Mon, 30 Dec 2019 22:45:43 -0800 Subject: [PATCH 15/20] doc: Make use of the @classsignal tag. It wasn't doing anything until now. --- docs/config.ld | 17 ++++++++++------- docs/ldoc.ltp | 4 ++-- lib/awful/client.lua | 4 ++++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/config.ld b/docs/config.ld index 8e1c9f0b3..e9266e6e0 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -514,11 +514,12 @@ local named_args = { -- Sections which are hidden by default, but visible when clicked. local summarize = { - emits = {index = 1, title = "signals" }, - propemits = {index = 2, title = "signals" }, - usebeautiful = {index = 3, title = "theme variables"}, - propbeautiful = {index = 4, title = "theme variables"}, - request = {index = 5, title = "permissions" }, + emits = {index = 1, title = "signals" , count = true }, + propemits = {index = 2, title = "signals" , count = true }, + usebeautiful = {index = 3, title = "theme variables" , count = true }, + propbeautiful = {index = 4, title = "theme variables" , count = true }, + request = {index = 5, title = "permissions" , count = true }, + classsignal = {index = 6, title = "Class level only", count = false}, } local delimiter_for_tag = { @@ -545,7 +546,7 @@ local function generate_summary(item) local tgs = {} for k, v in pairs(summarize) do - tgs[v.index] = {title=v.title, count=0} + tgs[v.index] = {title=v.title, count=0, showcount=v.count} end for tag, value in pairs(item.tags) do @@ -554,15 +555,17 @@ local function generate_summary(item) end end - local ret = {} + local ret, has_show_more = {}, false for k, v in ipairs(tgs) do if v.count > 0 then ret[#ret+1] = v + has_show_more = v.showcount or has_show_more end end item.extra_summary = #ret > 0 and ret or nil + item.has_show_more = has_show_more end -- We have custom types, sub-types and different rendering. diff --git a/docs/ldoc.ltp b/docs/ldoc.ltp index 7cab17878..477af6763 100644 --- a/docs/ldoc.ltp +++ b/docs/ldoc.ltp @@ -225,7 +225,7 @@ # end # if item.extra_summary then # for _, col in ldoc.ipairs(item.extra_summary) do - · $(col.count.." "..col.title) + · $((col.showcount and col.count.." " or "")..col.title) # end -- summary col # end -- summary @@ -324,7 +324,7 @@ # end -- if usage -# if item.extra_summary then +# if item.has_show_more then
diff --git a/lib/awful/client.lua b/lib/awful/client.lua index 1bf8a6593..32715baf3 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -1654,6 +1654,7 @@ end) -- @signal request::titlebars -- @tparam[opt=nil] string content The context (like "rules") -- @tparam[opt=nil] table hints Some hints. +-- @classsignal --- The client marked signal. -- @deprecatedsignal marked @@ -1674,6 +1675,9 @@ end) -- * **floating**: When the floating or maximization state changes. -- -- @signal request::border +-- @tparam string context The context. +-- @tparam table hints The hints. +-- @classsignal -- @see awful.permissions.update_border -- Add clients during startup to focus history. From 31e0a3e67b72ee249b2232009f24e64d5386dfcf Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage-Vallee Date: Mon, 30 Dec 2019 23:07:22 -0800 Subject: [PATCH 16/20] doc: Fix the item summary rendering. * Correctly count the elements * Use singular and plural tense properly --- docs/config.ld | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/config.ld b/docs/config.ld index e9266e6e0..fd7a9ac68 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -514,11 +514,11 @@ local named_args = { -- Sections which are hidden by default, but visible when clicked. local summarize = { - emits = {index = 1, title = "signals" , count = true }, - propemits = {index = 2, title = "signals" , count = true }, - usebeautiful = {index = 3, title = "theme variables" , count = true }, - propbeautiful = {index = 4, title = "theme variables" , count = true }, - request = {index = 5, title = "permissions" , count = true }, + emits = {index = 1, title = "signal" , count = true }, + propemits = {index = 2, title = "signal" , count = true }, + usebeautiful = {index = 3, title = "theme variable" , count = true }, + propbeautiful = {index = 4, title = "theme variable" , count = true }, + request = {index = 5, title = "permission" , count = true }, classsignal = {index = 6, title = "Class level only", count = false}, } @@ -551,7 +551,7 @@ local function generate_summary(item) for tag, value in pairs(item.tags) do if summarize[tag] then - tgs[summarize[tag].index].count = tgs[summarize[tag].index].count + 1 + tgs[summarize[tag].index].count = #value end end @@ -559,6 +559,11 @@ local function generate_summary(item) for k, v in ipairs(tgs) do if v.count > 0 then + + if v.count > 1 then + v.title = v.title .. "s" + end + ret[#ret+1] = v has_show_more = v.showcount or has_show_more end From 46026ccc2ec6fba8c3c7cb609b28cd18d2597079 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage-Vallee Date: Mon, 30 Dec 2019 23:13:25 -0800 Subject: [PATCH 17/20] doc: Fix a regression that added another space in the URL. This will break some existing links, but oh well, it isn't the first time and some websites cannot render URLs with spaces in them. This means external references to some of the input doc are currently impossible. --- docs/config.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.ld b/docs/config.ld index fd7a9ac68..f06d603a7 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -418,7 +418,7 @@ sort_modules=true -- Add more project level (left side index) types. new_type("coreclassmod", "Core_components" , true) -new_type("inputmodule" , "Input handling" , true) +new_type("inputmodule" , "Input_handling" , true) new_type("ruleslib" , "Declarative_rules", true) new_type("widgetmod" , "Widgets" , true) new_type("containermod", "Widget_containers", true) From cb9c33cda86ea8e165018ce88e1d1d6f2b4fa9fc Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage-Vallee Date: Tue, 31 Dec 2019 13:01:10 -0800 Subject: [PATCH 18/20] "Really" deprecate the client marked and unmarked signals. The doc said they were deprecated in 4.0, but back then there was no API to deprecate signals. --- lib/awful/client.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/awful/client.lua b/lib/awful/client.lua index 32715baf3..1a7e51f90 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -1716,6 +1716,15 @@ capi.client.connect_signal("unmanage::connected", function() ) end) +for _, sig in ipairs {"marked", "unmarked"} do + capi.client.connect_signal(sig.."::connected", function() + gdebug.deprecate( + "Use `property::marked` rather than `".. sig .. "`", + {deprecated_in=4} + ) + end) +end + -- Connect to "focus" signal, and allow to disable tracking. do local disabled_count = 1 From 8df463f971b4a7094938aaa1883ff28626a0b6a6 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sat, 18 Jan 2020 19:34:10 -0500 Subject: [PATCH 19/20] doc: Improve the client documentation. --- docs/common/rule.ldoc | 8 ++--- lib/awful/client.lua | 12 +++---- objects/client.c | 74 +++++++++++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/docs/common/rule.ldoc b/docs/common/rule.ldoc index 082458a3a..357b27fc9 100644 --- a/docs/common/rule.ldoc +++ b/docs/common/rule.ldoc @@ -1,6 +1,6 @@ --- ---- A table which content will be used to set the target object properties. +--- A table whose content will be used to set the target object properties. -- -- @rulecomponent properties -- @param table @@ -14,7 +14,7 @@ -- @param table -- @see properties ---- A table which content will be compared to the target object current properties. +--- A table whose content will be compared to the target object current properties. -- -- @rulecomponent rule -- @param table @@ -50,7 +50,7 @@ -- @see rule -- @see except ---- A table which content will be compared to the target object current properties. +--- A table whose content will be compared to the target object current properties. -- -- The comparison will be made using the lesser (`<`) operator. -- @@ -59,7 +59,7 @@ -- @see rule -- @see except ---- A table which content will be compared to the target object current properties. +--- A table whose content will be compared to the target object current properties. -- -- The comparison will be made using the greater (`>`) operator. -- diff --git a/lib/awful/client.lua b/lib/awful/client.lua index 1a7e51f90..243b9fbce 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -1422,12 +1422,12 @@ end --- Is a client transient for another one? -- --- This will traverse the chain of `transient_for` client --- until a client which is transient for `c2` is found. If --- one is found, it will be returned. If none is found, then --- `nil` will be returned. Most of the time there is no --- long chain of clients, so `self` or `nil` are the most --- likely return values. +-- This will traverse the chain formed by the `transient_for` property of `self` +-- until a client `c` with `c.transient_for == c2` is found. The found client +-- `c` is returned. If no client is found, `nil` is returned. +-- +-- While `transient_for` chains are technically possible, they are unlikely, so +-- the most likely return values are `self` and `nil`. -- -- @method is_transient_for -- @tparam client c2 The parent client to check. diff --git a/objects/client.c b/objects/client.c index bde2695b9..7b2d3a202 100644 --- a/objects/client.c +++ b/objects/client.c @@ -446,8 +446,8 @@ /** * The client title. * - * This is the text which will be shown in the `awful.widget.tasklist` - * and the `awful.titlebar`. + * This is the text which will be shown in `awful.widget.tasklist` + * and `awful.titlebar.widget.titlewidget`. * * @property name * @tparam string name @@ -464,7 +464,8 @@ * the `awful.widget.tasklist` and should not be shown there. * * The default value of this property reflects the value of the - * `_NET_WM_STATE_SKIP_TASKBAR` X11 protocol xproperty. + * `_NET_WM_STATE_SKIP_TASKBAR` X11 protocol xproperty. Clients can modify this + * state through this property. * * @property skip_taskbar * @tparam[opt=false] boolean skip_taskbar @@ -472,8 +473,6 @@ * @see sticky */ -//TODO v5: Rename to skip_tasklist? - /** * The window type. * @@ -519,7 +518,7 @@ * * A class usually maps to the application name. It is useful in, among other * places, the rules to apply different properties to different clients. It - * is also useful, along with `instance`, so implement "windows counter" + * is also useful, along with `instance`, to implement "windows counter" * used in many popular docks and Alt-Tab like popups. * * To get a client class from the command line, use the command: @@ -532,7 +531,8 @@ * buggy application like the Spotify desktop client are known to * violate the specification and do it anyway. There *is* a signal for * this property, but it should hopefully never be useful. If your - * applications change their classes, please report a bug to them. + * applications change their classes, please report a bug to them + * and point to ICCCM §4.1.2.5. * It tends to break `ruled.client` and other AwesomeWM APIs. * * @property class @@ -555,6 +555,12 @@ * * The instance will be the first string. * + * This *should* never change after the client is created. There + * *is* a signal for * this property, but it should hopefully never + * be useful. If your applications change their classes, please + * report a bug to them and point to ICCCM §4.1.2.5. + * It tends to break `ruled.client` and other AwesomeWM APIs. + * * @property instance * @tparam string instance * @propemits false false @@ -591,6 +597,10 @@ * using the `xhosts` command for using proxies such as * `ssh -X` or `ssh -Y`. * + * According to EWMH, this property contains the value + * returned by `gethostname()` on the computer that the + * client is running on. + * * @property machine * @tparam string machine * @propemits false false @@ -652,8 +662,8 @@ * Please note that clients can only be on one screen at once. X11 * does not natively allow clients to be in multiple locations at * once. Changing the screen directly will affect the tags and may - * cause several other changes to the state in order to ensure no - * screen specific code is changing the other screens clients. + * cause several other changes to the state in order to ensure that + * a client's position and its screen are consistent. * * @property screen * @tparam screen screen @@ -736,13 +746,16 @@ * * gears.surface(c.content):write_to_png(path) * - * Please note that once taken, the surface wont be - * updated when the client content changes. Since - * AwesomeWM does not have a compositor, the only way - * to get an animated client screenshot widget is to - * poll this property multiple time per seconds. This - * is very slow and should be used only when the said - * widget is visible rather than all the time. + * Please note that this only creates a new cairo surface + * referring to the client's content. This means that + * changes to the client's content may or may not become + * visible in the returned surface. If you want to take a + * screenshot, a copy of the surface's content needs to + * be taken. Note that the content of parts of a window + * that are currently not visible are undefined. + * + * The only way to get an animated client screenshot widget is to poll this + * property multiple time per seconds. This is obviously a bad idea. * * This property has no signals when the content changes. * @@ -843,20 +856,16 @@ * The client the window is transient for. * * A transient window is a client that "belongs" to another - * client. If the client is also `modal`, then it always has - * to be on top of the other window *and* the parent client + * client. If the client is also `modal`, then the parent client * cannot be focused while the child client exists. - * This is common for "Save as" dialogs or other dialogs where - * isn't possible to modify the content of the "parent" client + * This is common for "Save as" dialogs or other dialogs where it + * is not possible to modify the content of the "parent" client * while the dialog is open. * - * However, `modal` isn't a requirement for using the `transient_for` + * However, `modal` is not a requirement for using the `transient_for` * concept. "Tools" such as popup palette in canvas-and-palettes * applications can belong to each other without being modal. * - * However this it is also - * possible to have - * * @property transient_for * @tparam client transient_for * @propemits false false @@ -870,6 +879,8 @@ * Window identification unique to a group of windows. * * This is the ID of the group window, not a client object. + * The group window is most likely not a visible client, but + * only an invisible and internal window. * * @property group_window * @tparam integer group_window @@ -893,6 +904,9 @@ /** * A table with size hints of the client. * + * For details on the meaning of the fields, refer to ICCCM § 4.1.2.3 + * `WM_NORMAL_HINTS`. + * * Please note that most fields are optional and may or may not be set. * * When the client is tiled, the `size_hints` usually get in the way and @@ -931,6 +945,8 @@ * @tparam[opt] integer|nil hints.min_aspect_den * @tparam[opt] integer|nil hints.max_aspect_num * @tparam[opt] integer|nil hints.max_aspect_den + * @tparam[opt] integer|nil hints.base_width + * @tparam[opt] integer|nil hints.base_height * @propemits false false * @see size_hints_honor * @see geometry @@ -990,10 +1006,10 @@ * to be on top of the other window *and* the parent client * cannot be focused while the child client exists. * This is common for "Save as" dialogs or other dialogs where - * isn't possible to modify the content of the "parent" client + * is not possible to modify the content of the "parent" client * while the dialog is open. * - * However, `modal` isn't a requirement for using the `transient_for` + * However, `modal` is not a requirement for using the `transient_for` * concept. "Tools" such as popup palette in canvas-and-palettes * applications can belong to each other without being modal. * @@ -1006,7 +1022,7 @@ /** * True if the client can receive the input focus. * - * The client wont get focused even when the user + * The client will not get focused even when the user * click on it. * * @property focusable @@ -1026,7 +1042,7 @@ * * Do not use this directly unless you want total control over the shape (such * as shape with holes). Even then, it is usually recommended to use transparency - * in the titlebars and a compositing manager. For the vast majority use use + * in the titlebars and a compositing manager. For the vast majority of use * cases, use the `shape` property. * * @property shape_bounding @@ -1204,6 +1220,8 @@ * keys to define how much space of the screen `workarea` this client * should reserve for itself. * + * This corresponds to EWMH's `_NET_WM_STRUT` and `_NET_WM_STRUT_PARTIAL`. + * * @tparam table struts A table with new strut values, or none. * @treturn table A table with strut values. * @method struts From b8fbeb95c648a5c9ac9b24db520d97015f98761c Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 6 Oct 2019 19:03:47 -0400 Subject: [PATCH 20/20] rc.lua: Switch from `awful.rules` to `ruled.client`. It's the same module, but with a new name. The commit also switches from the "one off" rule write to the incremental and signal based one. This allows modules to add their own rules without having a race condition against `rc.lua` and other modules. Previously, if a module wasn't designed to prevent it, rules got destroyed each time. --- awesomerc.lua | 88 ++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/awesomerc.lua b/awesomerc.lua index 578a9a37f..65e48b4d6 100644 --- a/awesomerc.lua +++ b/awesomerc.lua @@ -13,6 +13,8 @@ local wibox = require("wibox") local beautiful = require("beautiful") -- Notification library local naughty = require("naughty") +-- Declarative object management +local ruled = require("ruled") local menubar = require("menubar") local hotkeys_popup = require("awful.hotkeys_popup") -- Enable hotkeys help widget for VIM and other apps @@ -439,60 +441,60 @@ end) -- {{{ Rules -- Rules to apply to new clients. -- @DOC_RULES@ -awful.rules.rules = { +ruled.client.connect_signal("request::rules", function() -- @DOC_GLOBAL_RULE@ -- All clients will match this rule. - { rule = { }, - properties = { focus = awful.client.focus.filter, - raise = true, - screen = awful.screen.preferred, - placement = awful.placement.no_overlap+awful.placement.no_offscreen - } - }, + ruled.client.append_rule { + id = "global", + rule = { }, + properties = { + focus = awful.client.focus.filter, + raise = true, + screen = awful.screen.preferred, + placement = awful.placement.no_overlap+awful.placement.no_offscreen + } + } -- @DOC_FLOATING_RULE@ -- Floating clients. - { rule_any = { - instance = { - "DTA", -- Firefox addon DownThemAll. - "copyq", -- Includes session name in class. - "pinentry", + ruled.client.append_rule { + id = "floating", + rule_any = { + instance = { "copyq", "pinentry" }, + class = { + "Arandr", "Blueman-manager", "Gpick", "Kruler", "Sxiv", + "Tor Browser", "Wpa_gui", "veromix", "xtightvncviewer" + }, + -- Note that the name property shown in xprop might be set slightly after creation of the client + -- and the name shown there might not match defined rules here. + name = { + "Event Tester", -- xev. + }, + role = { + "AlarmWindow", -- Thunderbird's calendar. + "ConfigManager", -- Thunderbird's about:config. + "pop-up", -- e.g. Google Chrome's (detached) Developer Tools. + } }, - class = { - "Arandr", - "Blueman-manager", - "Gpick", - "Kruler", - "MessageWin", -- kalarm. - "Sxiv", - "Tor Browser", -- Needs a fixed window size to avoid fingerprinting by screen size. - "Wpa_gui", - "veromix", - "xtightvncviewer"}, - - -- Note that the name property shown in xprop might be set slightly after creation of the client - -- and the name shown there might not match defined rules here. - name = { - "Event Tester", -- xev. - }, - role = { - "AlarmWindow", -- Thunderbird's calendar. - "ConfigManager", -- Thunderbird's about:config. - "pop-up", -- e.g. Google Chrome's (detached) Developer Tools. - } - }, properties = { floating = true }}, + properties = { floating = true } + } -- @DOC_DIALOG_RULE@ -- Add titlebars to normal clients and dialogs - { rule_any = {type = { "normal", "dialog" } - -- @DOC_CSD_TITLEBARS@ - }, properties = { titlebars_enabled = true } - }, + ruled.client.append_rule { + -- @DOC_CSD_TITLEBARS@ + id = "titlebars", + rule_any = { type = { "normal", "dialog" } }, + properties = { titlebars_enabled = true } + } -- Set Firefox to always map on the tag named "2" on screen 1. - -- { rule = { class = "Firefox" }, - -- properties = { screen = 1, tag = "2" } }, -} + -- ruled.tag.append_rule { + -- rule = { class = "Firefox" }, + -- properties = { screen = 1, tag = "2" } + -- } +end) + -- }}} -- {{{ Titlebars