From fa6c050be3c1272cd5b9d5fc4d1a94a67eaba294 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Fri, 28 Dec 2018 03:15:53 -0500 Subject: [PATCH 01/16] depgraph: Allow underscores in module names. --- build-utils/check_for_invalid_requires.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-utils/check_for_invalid_requires.lua b/build-utils/check_for_invalid_requires.lua index 924c902eb..dd33443b0 100755 --- a/build-utils/check_for_invalid_requires.lua +++ b/build-utils/check_for_invalid_requires.lua @@ -54,7 +54,7 @@ local allowed_deps = { -- Turn "foo.bar.baz" into "foo.bar". Returns nil if there is nothing more to -- remove. local function get_supermodule(module) - return string.match(module, "(.+)%.%a+") + return string.match(module, "(.+)%.[a-z_]+") end -- Check if "module" (or one of its parents) is allowed to depend on From 96c4d001f160b01de429a57fa2556a24c4f5f773 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Tue, 25 Dec 2018 00:49:22 -0500 Subject: [PATCH 02/16] doc: Remove capi.button/capi.key from the official doc. `awful.button` is always the one used and it's confusing. --- docs/config.ld | 7 +++++-- lib/awful/button.lua | 1 - lib/awful/key.lua | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/config.ld b/docs/config.ld index 398ef1a24..3a264f90c 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -118,10 +118,8 @@ file = { '../spawn.c', '../xkb.c', '../common/luaobject.c', - '../objects/button.c', '../objects/client.c', '../objects/drawable.c', - '../objects/key.c', '../objects/screen.c', '../objects/tag.c', '../objects/window.c', @@ -155,6 +153,11 @@ file = { '../lib/naughty/list/init.lua', '../lib/naughty/widget/_default.lua', + -- Ignore components that provide no value to users and have confusing + -- names + '../objects/button.c', + '../objects/key.c', + -- Deprecated classes for one years or more don't deserve entries -- in the index '../lib/awful/widget/graph.lua', diff --git a/lib/awful/button.lua b/lib/awful/button.lua index 39a035653..b59303f05 100644 --- a/lib/awful/button.lua +++ b/lib/awful/button.lua @@ -35,7 +35,6 @@ local ignore_modifiers = { "Lock", "Mod2" } -- will return 2 button objects: one with CapsLock on, and the other one with -- CapsLock off. -- --- @see button -- @treturn table A table with one or several button objects. function button.new(mod, _button, press, release) local ret = {} diff --git a/lib/awful/key.lua b/lib/awful/key.lua index 6e0a56919..5826a7c97 100644 --- a/lib/awful/key.lua +++ b/lib/awful/key.lua @@ -103,7 +103,7 @@ end -- ignored by default by this function), creating a key binding with this -- function will return 2 key objects: one with CapsLock on, and another one -- with CapsLock off. --- @see key.key +-- -- @tparam table mod A list of modifier keys. Valid modifiers are: Any, Mod1, -- Mod2, Mod3, Mod4, Mod5, Shift, Lock and Control. -- @tparam string _key The key to trigger an event. @@ -113,6 +113,7 @@ end -- for example {description="select next tag", group="tag"}. -- @treturn table A table with one or several key objects. -- @constructorfct awful.key + function key.new(mod, _key, press, release, data) if type(release)=='table' then data=release From 4cab9f8c3871e92ad34b6783b40c7466b80a8b61 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Thu, 18 Apr 2019 18:11:31 -0400 Subject: [PATCH 03/16] widget: Return `nil` in case of failure. Instead of an assert. If there is a "real" error, then a warning is still printed, but otherwise this relax the requirements. --- lib/wibox/widget/base.lua | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/wibox/widget/base.lua b/lib/wibox/widget/base.lua index d3958b2d8..a3389804b 100644 --- a/lib/wibox/widget/base.lua +++ b/lib/wibox/widget/base.lua @@ -7,6 +7,7 @@ local object = require("gears.object") local cache = require("gears.cache") local matrix = require("gears.matrix") +local gdebug = require("gears.debug") local protected_call = require("gears.protected_call") local gtable = require("gears.table") local setmetatable = setmetatable @@ -609,17 +610,22 @@ end -- -- @param wdg The value. -- @param[opt=nil] ... Arguments passed to the contructor (if any). --- @treturn The new widget. -- @constructorfct wibox.widget.base.make_widget_from_value +-- @treturn widget|nil The new widget or `nil` in case of failure. function base.make_widget_from_value(wdg, ...) + if not wdg then return nil end + local is_function, t = is_callable(wdg) if is_function then wdg = wdg(...) - elseif t == "table" and not wdg.is_widget then - wdg = base.make_widget_declarative(wdg) + elseif t == "table" then + wdg = wdg.is_widget and wdg or base.make_widget_declarative(wdg) else - assert(wdg.is_widget, "The argument is not a function, table, or widget.") + gdebug.print_warning( + "The argument is not a function, table, or widget." + ) + return nil end return wdg From 0cb22fd20395fd6c586fda6117177a2d7b2ed8e1 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 22:26:05 -0500 Subject: [PATCH 04/16] awful: Move the backward compatibility code into its own file. The reason for this is that as more of CAPI is brought in line with the current API guidelines, it is more and more likely the tests will hit APIs shims (either to test them or because the prototype remains the same and only the implementation moved to Lua). --- docs/config.ld | 1 + lib/awful/_compat.lua | 27 +++++++++++++++++++++++++++ lib/awful/init.lua | 31 ++----------------------------- 3 files changed, 30 insertions(+), 29 deletions(-) create mode 100644 lib/awful/_compat.lua diff --git a/docs/config.ld b/docs/config.ld index 3a264f90c..120ba85c4 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -133,6 +133,7 @@ file = { -- documentation '../lib/awful/autofocus.lua', '../lib/awful/dbus.lua', + '../lib/awful/_compat.lua', '../lib/awful/init.lua', '../lib/awful/remote.lua', '../lib/awful/screen/dpi.lua', diff --git a/lib/awful/_compat.lua b/lib/awful/_compat.lua new file mode 100644 index 000000000..07016b14b --- /dev/null +++ b/lib/awful/_compat.lua @@ -0,0 +1,27 @@ +-- This file contains all global backward compatibility workarounds for the +-- Core API changes. +local gtimer = require("gears.timer") +local util = require("awful.util" ) +local spawn = require("awful.spawn") +local gdebug = require("gears.debug") + +function timer(...) -- luacheck: ignore + gdebug.deprecate("gears.timer", {deprecated_in=4}) + return gtimer(...) +end + +util.spawn = function(...) + gdebug.deprecate("awful.spawn", {deprecated_in=4}) + return spawn.spawn(...) +end + +util.spawn_with_shell = function(...) + gdebug.deprecate("awful.spawn.with_shell", {deprecated_in=4}) + return spawn.with_shell(...) +end + +util.pread = function() + gdebug.deprecate("Use io.popen() directly or look at awful.spawn.easy_async() " + .. "for an asynchronous alternative", {deprecated_in=4}) + return "" +end diff --git a/lib/awful/init.lua b/lib/awful/init.lua index da63275c4..cf5764273 100644 --- a/lib/awful/init.lua +++ b/lib/awful/init.lua @@ -6,34 +6,7 @@ -- @module awful --------------------------------------------------------------------------- --- TODO: This is a hack for backwards-compatibility with 3.5, remove! -local util = require("awful.util") -local gtimer = require("gears.timer") -local gdebug = require("gears.debug") -function timer(...) -- luacheck: ignore - gdebug.deprecate("gears.timer", {deprecated_in=4}) - return gtimer(...) -end - ---TODO: This is a hack for backwards-compatibility with 3.5, remove! --- Set awful.util.spawn* and awful.util.pread. -local spawn = require("awful.spawn") - -util.spawn = function(...) - gdebug.deprecate("awful.spawn", {deprecated_in=4}) - return spawn.spawn(...) -end - -util.spawn_with_shell = function(...) - gdebug.deprecate("awful.spawn.with_shell", {deprecated_in=4}) - return spawn.with_shell(...) -end - -util.pread = function() - gdebug.deprecate("Use awful.spawn.easy_async() " - .. "for an asynchronous alternative", {deprecated_in=4}) - return "" -end +require("awful._compat") return { @@ -60,7 +33,7 @@ return titlebar = require("awful.titlebar"); rules = require("awful.rules"); popup = require("awful.popup"); - spawn = spawn; + spawn = require("awful.spawn"); } -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 From 3aafa64ea72554fbb87ca0ac36929a79222fa38f Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 22:29:16 -0500 Subject: [PATCH 05/16] tests: Import the backward compatibility API for all the tests. This isn't very nice and pulls all sort of almost useless code into the shims, making them less atomic. However the next few commits will start another round of API standardization and the compatibility layer wont be optional anymore. --- tests/examples/shims/_common_template.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/examples/shims/_common_template.lua b/tests/examples/shims/_common_template.lua index 283978d23..50c73d0c8 100644 --- a/tests/examples/shims/_common_template.lua +++ b/tests/examples/shims/_common_template.lua @@ -33,6 +33,8 @@ return function(_, _) -- backend. local bg = require("wibox.container.background") bg._use_fallback_algorithm() + + require("awful._compat") end -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 From 95500ea71caeb1893228dcfaf71a9a511dd424d1 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 15:50:21 -0500 Subject: [PATCH 06/16] root: Add support for setting a miss handler. This will allow to port some functions from C to Lua, such as supporting `awful.key` directly when setting the buttons. --- luaa.c | 6 +-- root.c | 75 +++++++++++++++++++++++++++++++++-- tests/examples/shims/root.lua | 9 +++++ 3 files changed, 84 insertions(+), 6 deletions(-) diff --git a/luaa.c b/luaa.c index 78e30844c..3e9455f74 100644 --- a/luaa.c +++ b/luaa.c @@ -80,9 +80,10 @@ extern const struct luaL_Reg awesome_dbus_lib[]; #endif extern const struct luaL_Reg awesome_keygrabber_lib[]; extern const struct luaL_Reg awesome_mousegrabber_lib[]; -extern const struct luaL_Reg awesome_root_lib[]; extern const struct luaL_Reg awesome_mouse_methods[]; extern const struct luaL_Reg awesome_mouse_meta[]; +extern const struct luaL_Reg awesome_root_methods[]; +extern const struct luaL_Reg awesome_root_meta[]; /** A call into the Lua code aborted with an error. * @@ -995,8 +996,7 @@ luaA_init(xdgHandle* xdg, string_array_t *searchpath) setup_awesome_signals(L); /* Export root lib */ - luaA_registerlib(L, "root", awesome_root_lib); - lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */ + luaA_openlib(L, "root", awesome_root_methods, awesome_root_meta); #ifdef WITH_DBUS /* Export D-Bus lib */ diff --git a/root.c b/root.c index 4da0f6605..3c467a3ed 100644 --- a/root.c +++ b/root.c @@ -31,6 +31,7 @@ #include "common/xcursor.h" #include "common/xutil.h" #include "objects/button.h" +#include "common/luaclass.h" #include "xwindow.h" #include "math.h" @@ -39,6 +40,10 @@ #include #include +static int miss_index_handler = LUA_REFNIL; +static int miss_newindex_handler = LUA_REFNIL; +static int miss_call_handler = LUA_REFNIL; + static void root_set_wallpaper_pixmap(xcb_connection_t *c, xcb_pixmap_t p) { @@ -525,7 +530,62 @@ luaA_root_tags(lua_State *L) return 1; } -const struct luaL_Reg awesome_root_lib[] = +/** +* Add a custom call handler. +*/ +static int +luaA_root_set_call_handler(lua_State *L) +{ + return luaA_registerfct(L, 1, &miss_call_handler); +} + +/** +* Add a custom property handler (getter). +*/ +static int +luaA_root_set_index_miss_handler(lua_State *L) +{ + return luaA_registerfct(L, 1, &miss_index_handler); +} + +/** +* Add a custom property handler (setter). +*/ +static int +luaA_root_set_newindex_miss_handler(lua_State *L) +{ + return luaA_registerfct(L, 1, &miss_newindex_handler); +} + +/** Root library. + * \param L The Lua VM state. + * \return The number of elements pushed on stack. + * \luastack + */ +static int +luaA_root_index(lua_State *L) +{ + if (miss_index_handler != LUA_REFNIL) + return luaA_call_handler(L, miss_index_handler); + + return luaA_default_index(L); +} + +/** Newindex for root. + * \param L The Lua VM state. + * \return The number of elements pushed on stack. + */ +static int +luaA_root_newindex(lua_State *L) +{ + /* Call the lua root property handler */ + if (miss_newindex_handler != LUA_REFNIL) + return luaA_call_handler(L, miss_newindex_handler); + + return luaA_default_newindex(L); +} + +const struct luaL_Reg awesome_root_methods[] = { { "buttons", luaA_root_buttons }, { "keys", luaA_root_keys }, @@ -536,8 +596,17 @@ const struct luaL_Reg awesome_root_lib[] = { "size", luaA_root_size }, { "size_mm", luaA_root_size_mm }, { "tags", luaA_root_tags }, - { "__index", luaA_default_index }, - { "__newindex", luaA_default_newindex }, + { "__index", luaA_root_index }, + { "__newindex", luaA_root_newindex }, + { "set_index_miss_handler", luaA_root_set_index_miss_handler}, + { "set_call_handler", luaA_root_set_call_handler}, + { "set_newindex_miss_handler", luaA_root_set_newindex_miss_handler}, + + { NULL, NULL } +}; + +const struct luaL_Reg awesome_root_meta[] = +{ { NULL, NULL } }; diff --git a/tests/examples/shims/root.lua b/tests/examples/shims/root.lua index e79e9652e..6ceaf787c 100644 --- a/tests/examples/shims/root.lua +++ b/tests/examples/shims/root.lua @@ -174,6 +174,15 @@ function root._write_string(string, c) end end + +function root.set_newindex_miss_handler(h) + rawset(mouse, "_ni_handler", h) +end + +function root.set_index_miss_handler(h) + rawset(mouse, "_i_handler", h) +end + return root -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 From b1c81c4258918240a3a1e36d10f3c2330ab20b10 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 15:52:34 -0500 Subject: [PATCH 07/16] awful: Set a miss handler for capi.root There is no better place to put it and need to always be required for backward compatibility. Given Awesome no longer works properly without `awful`, I put the code there. --- .luacheckrc | 2 +- lib/awful/_compat.lua | 31 +++++++++++++++++++++++++++++++ tests/examples/shims/root.lua | 22 +++++++++++++++++++--- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/.luacheckrc b/.luacheckrc index aa7e4f10b..6cbe09f91 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -26,7 +26,6 @@ read_globals = { "key", "keygrabber", "mousegrabber", - "root", "selection", "tag", "window", @@ -43,6 +42,7 @@ read_globals = { globals = { "screen", "mouse", + "root", "client" } diff --git a/lib/awful/_compat.lua b/lib/awful/_compat.lua index 07016b14b..b4226826c 100644 --- a/lib/awful/_compat.lua +++ b/lib/awful/_compat.lua @@ -5,6 +5,8 @@ local util = require("awful.util" ) local spawn = require("awful.spawn") local gdebug = require("gears.debug") +local capi = {root = root} + function timer(...) -- luacheck: ignore gdebug.deprecate("gears.timer", {deprecated_in=4}) return gtimer(...) @@ -25,3 +27,32 @@ util.pread = function() .. "for an asynchronous alternative", {deprecated_in=4}) return "" end + +-- Allow properties to be set on the root object. This helps to migrate some +-- capi function to an higher level Lua implementation. +do + local root_props, root_object = {}, {} + + capi.root.set_newindex_miss_handler(function(_,key,value) + if root_object["set_"..key] then + root_object["set_"..key](value) + elseif not root_object["get_"..key] then + root_props[key] = value + else + -- If there is a getter, but no setter, then the property is read-only + error("Cannot set '" .. tostring(key) .. " because it is read-only") + end + end) + + capi.root.set_index_miss_handler(function(_,key) + if root_object["get_"..key] then + return root_object["get_"..key]() + else + return root_props[key] + end + end) + + root._private = {} + root.object = root_object + assert(root.object == root_object) +end diff --git a/tests/examples/shims/root.lua b/tests/examples/shims/root.lua index 6ceaf787c..78ca955e1 100644 --- a/tests/examples/shims/root.lua +++ b/tests/examples/shims/root.lua @@ -176,13 +176,29 @@ end function root.set_newindex_miss_handler(h) - rawset(mouse, "_ni_handler", h) + rawset(root, "_ni_handler", h) end function root.set_index_miss_handler(h) - rawset(mouse, "_i_handler", h) + rawset(root, "_i_handler", h) end -return root +return setmetatable(root, { + __index = function(self, key) + if key == "screen" then + return screen[1] + end + local h = rawget(root,"_i_handler") + if h then + return h(self, key) + end + end, + __newindex = function(...) + local h = rawget(root,"_ni_handler") + if h then + h(...) + end + end, +}) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 From 141aca243208e31c56dc1511500dee083597aad7 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 15:57:01 -0500 Subject: [PATCH 08/16] root.buttons: Move to Lua. This is the groundwork commit to support using `awful.button` objects in `root.buttons`. --- lib/awful/_compat.lua | 18 ++++++++++++++++++ root.c | 4 ++-- tests/examples/shims/button.lua | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/awful/_compat.lua b/lib/awful/_compat.lua index b4226826c..4b3bb2816 100644 --- a/lib/awful/_compat.lua +++ b/lib/awful/_compat.lua @@ -56,3 +56,21 @@ do root.object = root_object assert(root.object == root_object) end + +-- root.bottons() used to be a capi function. However this proved confusing +-- as rc.lua used `awful.button` and `root.buttons()` used capi.button. There +-- was a little documented hack to "flatten" awful.button into a pair of +-- capi.button. A consequence of this, beside being ugly, was that it was +-- de-facto read-only due the confusion related the difference between the +-- capi and "high level" format difference. + + +--- Get or set global mouse bindings. +-- +-- This binding will be available when you click on the root window (usually +-- the wallpaper area). +-- @tparam[opt=nil] table|nil The list of `button` objects to set. +-- @treturn table The list of root window buttons. +function root.buttons(btns) + return root._buttons(btns) +end diff --git a/root.c b/root.c index 3c467a3ed..c9ed472d9 100644 --- a/root.c +++ b/root.c @@ -374,7 +374,7 @@ luaA_root_keys(lua_State *L) return 1; } -/** Get or set global mouse bindings. +/* Get or set global mouse bindings. * This binding will be available when you click on the root window. * * @param button_table An array of mouse button bindings objects, or nothing. @@ -587,7 +587,7 @@ luaA_root_newindex(lua_State *L) const struct luaL_Reg awesome_root_methods[] = { - { "buttons", luaA_root_buttons }, + { "_buttons", luaA_root_buttons }, { "keys", luaA_root_keys }, { "cursor", luaA_root_cursor }, { "fake_input", luaA_root_fake_input }, diff --git a/tests/examples/shims/button.lua b/tests/examples/shims/button.lua index fb5e995af..5f41d1e7c 100644 --- a/tests/examples/shims/button.lua +++ b/tests/examples/shims/button.lua @@ -1,5 +1,6 @@ return function() return { data = {}, + _is_capi_button = true, connect_signal = function() end } end From 78c349677099e06f6059c7a6ea5adee3e6c1713b Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 17:09:02 -0500 Subject: [PATCH 09/16] object: Add support for the legacy accessors as r/w methods. Many legacy Awesome APIs such as `client:tags()`, `root.buttons()`, `client:keys()`, `drawin:geometry()`, etc used functions for both the getter and setter. This contrast with just about everything else that came after it and is an artifact of an earlier time before we had "good" Lua object support. Because both consistency and backward compatibility are important, this table wrapper allows to support both the legacy method based accessors and key/value based accessors. It isn't part of the public API, has a sledgehammer function prototype and is intended for internal use only. It's ugly, but backward compatibility is more important than anything else. --- lib/gears/object/properties.lua | 123 ++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/lib/gears/object/properties.lua b/lib/gears/object/properties.lua index 3b740fd44..8f29ee018 100644 --- a/lib/gears/object/properties.lua +++ b/lib/gears/object/properties.lua @@ -7,7 +7,10 @@ -- @submodule gears.object --------------------------------------------------------------------------- +local gtable = require("gears.table") +-- local gdebug = require("gears.debug") local object = {} +local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) --- Add the missing properties handler to a CAPI object such as client/tag/screen. @@ -84,6 +87,126 @@ function object.capi_index_fallback(class, args) class.set_newindex_miss_handler(setter) end + +-- (private api) +-- Many legacy Awesome APIs such as `client:tags()`, `root.buttons()`, +-- `client:keys()`, `drawin:geometry()`, etc used functions for both the getter +-- and setter. This contrast with just about everything else that came after +-- it and is an artifact of an earlier time before we had "good" Lua object +-- support. +-- +-- Because both consistency and backward compatibility are important, this +-- table wrapper allows to support both the legacy method based accessors +-- and key/value based accessors. +-- +-- TO BE USED FOR DEPRECATION ONLY. + +local function copy_object(obj, to_set, name, capi_name, is_object, join_if, set_empty) + local ret = gtable.clone(to_set, false) + + -- .buttons used to be a function taking the result of `gears.table.join`. + -- For compatibility, support this, but from now on, it's a property. + return setmetatable(ret, { + __call = function(_, self, new_objs) +--TODO uncomment +-- gdebug.deprecate("`"..name.."` is no longer a function, it is a property. ".. +-- "Remove the `gears.table.join` and use a brace enclosed table", +-- {deprecated_in=5} +-- ) + + new_objs, self = is_object and new_objs or self, is_object and self or obj + + -- Setter + if new_objs and #new_objs > 0 then + if (not set_empty) and not next(new_objs) then return end + + local is_formatted = join_if(new_objs) + + -- Because modules may rely on :buttons taking a list of + -- `capi.buttons`/`capi.key` and now the user passes a list of + -- `awful.button`/`awful.key` convert this. + + local result = is_formatted and + new_objs or gtable.join(unpack(new_objs)) + + if capi_name and is_object then + return self[capi_name](self, result) + elseif capi_name then + return self[capi_name](result) + else + self._private[name.."_formatted"] = result + return self._private[name.."_formatted"] + end + end + + -- Getter + if capi_name and is_object then + return self[capi_name](self) + elseif capi_name then + return self[capi_name]() + else + return self._private[name.."_formatted"] or {} + end + end + }) +end + +function object._legacy_accessors(obj, name, capi_name, is_object, join_if, set_empty) + + -- Some objects have a special "object" property to add more properties, but + -- not all. + + local magic_obj = obj.object and obj.object or obj + + magic_obj["get_"..name] = function(self) + self = is_object and self or obj + + self._private[name] = self._private[name] or copy_object( + obj, {}, name, capi_name, is_object, join_if, set_empty + ) + + assert(self._private[name]) + return self._private[name] + end + + magic_obj["set_"..name] = function(self, objs) + if (not set_empty) and not next(objs) then return end + + if not is_object then + objs, self = self, obj + end + assert(objs) + + -- When called from a declarative property list, "buttons" will be set + -- using the result of gears.table.join, detect this + local is_formatted = join_if(objs) + +-- if is_formatted then +--TODO uncomment +-- gdebug.deprecate("Remove the `gears.table.join` and replace it with braces", +-- {deprecated_in=5} +-- ) +-- end + + + --TODO v6 Use the original directly and drop this legacy copy + local result = is_formatted and objs + or gtable.join(unpack(objs)) + + if is_object and capi_name then + self[capi_name](self, result) + elseif capi_name then + obj[capi_name](result) + else + self._private[name.."_formatted"] = result + end + + self._private[name] = copy_object( + obj, objs, name, capi_name, is_object, join_if, set_empty + ) + end +end + return setmetatable( object, {__call = function(_,...) object.capi_index_fallback(...) end}) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 From 3230a414507238e146d083be2a0da347dc67f448 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 17:36:54 -0500 Subject: [PATCH 10/16] root: Turn root.button() into a property. This is the first commit of a series to turn all function based accessors into object properties. This will bring consistency across the codebase. --- lib/awful/_compat.lua | 18 +++++++----------- root.c | 19 ++++++++++++++----- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/lib/awful/_compat.lua b/lib/awful/_compat.lua index 4b3bb2816..135e32b17 100644 --- a/lib/awful/_compat.lua +++ b/lib/awful/_compat.lua @@ -1,9 +1,10 @@ -- This file contains all global backward compatibility workarounds for the -- Core API changes. local gtimer = require("gears.timer") -local util = require("awful.util" ) +local util = require("awful.util") local spawn = require("awful.spawn") local gdebug = require("gears.debug") +local gprop = require("gears.object.properties") local capi = {root = root} @@ -64,13 +65,8 @@ end -- de-facto read-only due the confusion related the difference between the -- capi and "high level" format difference. - ---- Get or set global mouse bindings. --- --- This binding will be available when you click on the root window (usually --- the wallpaper area). --- @tparam[opt=nil] table|nil The list of `button` objects to set. --- @treturn table The list of root window buttons. -function root.buttons(btns) - return root._buttons(btns) -end +gprop._legacy_accessors(capi.root, "buttons", "_buttons", false, function(new_btns) + return new_btns[1] and ( + type(new_btns[1]) == "button" or new_btns[1]._is_capi_button + ) or false +end, true) diff --git a/root.c b/root.c index c9ed472d9..778838d9d 100644 --- a/root.c +++ b/root.c @@ -374,13 +374,22 @@ luaA_root_keys(lua_State *L) return 1; } -/* Get or set global mouse bindings. - * This binding will be available when you click on the root window. +/** + * Store the list of mouse buttons to be applied on the wallpaper (also + * known as root window). * - * @param button_table An array of mouse button bindings objects, or nothing. - * @return The array of mouse button bindings objects. - * @staticfct buttons + * @property buttons + * @tparam[opt={}] table buttons The list of buttons. + * @see awful.button + * + * @usage + * root.buttons = { + * awful.button({ }, 3, function () mymainmenu:toggle() end), + * awful.button({ }, 4, awful.tag.viewnext), + * awful.button({ }, 5, awful.tag.viewprev), + * } */ + static int luaA_root_buttons(lua_State *L) { From d5dd3fc79425f15d672d5da02aaad2adbe8957ca Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 17:38:05 -0500 Subject: [PATCH 11/16] tests: Test root.buttons Try both legacy and standardized code paths. Also try invalid mixes of them in case some modules abuse of rc.lua and ingest the wrong format by accident. --- tests/examples/shims/root.lua | 3 +++ tests/test-miss-handlers.lua | 50 ++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/examples/shims/root.lua b/tests/examples/shims/root.lua index 78ca955e1..ef7031567 100644 --- a/tests/examples/shims/root.lua +++ b/tests/examples/shims/root.lua @@ -128,6 +128,9 @@ function root.fake_input(event_type, detail, x, y) fake_input_handlers[event_type](detail, x, y) end +function root._buttons() + return {} +end -- Send an artificial set of key events to trigger a key combination. -- It only works in the shims and should not be used with UTF-8 chars. diff --git a/tests/test-miss-handlers.lua b/tests/test-miss-handlers.lua index c6b2baffa..7bbfea256 100644 --- a/tests/test-miss-handlers.lua +++ b/tests/test-miss-handlers.lua @@ -4,7 +4,10 @@ local mouse = mouse local class = tag local obj = class({}) local handler = require("gears.object.properties") +local abutton = require("awful.button") +local gtable = require("gears.table") local wibox = require("wibox") +local runner = require("_runner") awesome.connect_signal("debug::index::miss", error) awesome.connect_signal("debug::newindex::miss", error) @@ -68,6 +71,51 @@ assert(w2:get_children_by_id("main_textbox")[1]) assert(w2.main_background.main_textbox) assert(w2.main_background == w2:get_children_by_id("main_background")[1]) -require("_runner").run_steps({ function() return true end }) +-- You can't retry this, so if the assert above were false, assume it never +-- reaches this. + +local steps = { function() return true end } + +-- Try each combinations of current and legacy style accessors. +table.insert(steps, function()local b1, b2 = button({}, 1, function() end), button({}, 2, function() end) + root.buttons = {b1} + + assert(#root.buttons == 1 ) + assert(#root.buttons() == 1 ) + assert(root.buttons[1] == b1) + + root.buttons{b2} + + assert(#root.buttons == 1 ) + assert(#root.buttons() == 1 ) + assert(root.buttons()[1] == b2) + + local ab1, ab2 = abutton({}, 1, function() end), abutton({}, 2, function() end) + + root.buttons = {ab1} + assert(#root.buttons == 1) + assert(#root.buttons() == 4) + for i=1, 4 do + assert(root.buttons()[i] == ab1[i]) + end + + root.buttons(gtable.join(ab2)) + assert(#root.buttons == 1) + assert(#root.buttons() == 4) + for i=1, 4 do + assert(root.buttons()[i] == ab2[i]) + end + + root.buttons{ab1} + assert(#root.buttons == 1) + assert(#root.buttons() == 4) + for i=1, 4 do + assert(root.buttons()[i] == ab1[i]) + end + + return true +end) + +runner.run_steps(steps) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 From 3d918258e2fefdb6696fa6c35150235144561c18 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 18:30:08 -0500 Subject: [PATCH 12/16] widget: Turn `:buttons()` into a normal property. --- docs/common/widget.ldoc | 10 +++++++--- lib/awful/widget/common.lua | 24 +++++++++++++++--------- lib/wibox/widget/base.lua | 33 ++++++++++++++++++++------------- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/docs/common/widget.ldoc b/docs/common/widget.ldoc index bab763514..acd6bc7c8 100644 --- a/docs/common/widget.ldoc +++ b/docs/common/widget.ldoc @@ -40,9 +40,13 @@ -- @property visible -- @param boolean ---- Set/get a widget's buttons. --- @param _buttons The table of buttons that should bind to the widget. --- @method buttons +--- The widget buttons. +-- +-- The table contains a list of `awful.button` objects. +-- +-- @property buttons +-- @param table +-- @see awful.button --- Emit a signal and ensure all parent widgets in the hierarchies also -- forward the signal. This is useful to track signals when there is a dynamic diff --git a/lib/awful/widget/common.lua b/lib/awful/widget/common.lua index 35dbfb7ce..3b8dc6a6e 100644 --- a/lib/awful/widget/common.lua +++ b/lib/awful/widget/common.lua @@ -21,17 +21,23 @@ local common = {} -- @param object -- @treturn table function common.create_buttons(buttons, object) + local is_formatted = buttons and buttons[1] and ( + type(buttons[1]) == "button" or buttons[1]._is_capi_button) or false + if buttons then local btns = {} - for _, b in ipairs(buttons) do - -- Create a proxy button object: it will receive the real - -- press and release events, and will propagate them to the - -- button object the user provided, but with the object as - -- argument. - local btn = capi.button { modifiers = b.modifiers, button = b.button } - btn:connect_signal("press", function () b:emit_signal("press", object) end) - btn:connect_signal("release", function () b:emit_signal("release", object) end) - btns[#btns + 1] = btn + for _, src in ipairs(buttons) do + --TODO v6 Remove this legacy overhead + for _, b in ipairs(is_formatted and {src} or src) do + -- Create a proxy button object: it will receive the real + -- press and release events, and will propagate them to the + -- button object the user provided, but with the object as + -- argument. + local btn = capi.button { modifiers = b.modifiers, button = b.button } + btn:connect_signal("press", function () b:emit_signal("press", object) end) + btn:connect_signal("release", function () b:emit_signal("release", object) end) + btns[#btns + 1] = btn + end end return btns diff --git a/lib/wibox/widget/base.lua b/lib/wibox/widget/base.lua index a3389804b..bf4b87f8c 100644 --- a/lib/wibox/widget/base.lua +++ b/lib/wibox/widget/base.lua @@ -22,15 +22,11 @@ local base = {} -- Functions available on all widgets. base.widget = {} ---- Set/get a widget's buttons. --- @tab _buttons The table of buttons that is bound to the widget. --- @method buttons -function base.widget:buttons(_buttons) - if _buttons then - self._private.widget_buttons = _buttons - end - return self._private.widget_buttons -end +object.properties._legacy_accessors(base.widget, "buttons", nil, true, function(new_btns) + return new_btns[1] and ( + type(new_btns[1]) == "button" or new_btns[1]._is_capi_button + ) or false +end, true) --- Set a widget's visibility. -- @tparam boolean b Whether the widget is visible. @@ -368,7 +364,7 @@ function base.handle_button(event, widget, x, y, button, modifiers, geometry) -- Find all matching button objects. local matches = {} - for _, v in pairs(widget._private.widget_buttons) do + for _, v in pairs(widget._private.buttons_formatted or {}) do local match = true -- Is it the right button? if v.button ~= 0 and v.button ~= button then match = false end @@ -662,9 +658,6 @@ function base.make_widget(proxy, widget_name, args) -- Create a table used to store the widgets internal data. rawset(ret, "_private", {}) - -- No buttons yet. - ret._private.widget_buttons = {} - -- Widget is visible. ret._private.visible = true @@ -719,6 +712,20 @@ function base.make_widget(proxy, widget_name, args) mt.__tostring = function() return string.format("%s (%s)", ret.widget_name, orig_string) end + + -- Even when properties are disabled, buttons is required for backward + -- compatibility. + --TODO v6 Remove this + if not args.enable_properties then + mt.__index = function(_, key) + if key == "buttons" then + return base.widget.get_buttons(ret) + end + + return rawget(ret, key) + end + end + return setmetatable(ret, mt) end From 29e804a4f83ab3ad9d10771a32708f4cb3850c37 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 21:16:33 -0500 Subject: [PATCH 13/16] drawin: Turn `:buttons()` into a property. --- lib/awful/client.lua | 6 ++++++ lib/awful/wibar.lua | 2 ++ lib/wibox/init.lua | 16 +++++++++++++++- objects/client.c | 6 +++--- objects/window.c | 2 +- tests/examples/shims/drawin.lua | 2 +- 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/awful/client.lua b/lib/awful/client.lua index c4ff1f005..033898517 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -1344,6 +1344,12 @@ function client.object.is_transient_for(self, c2) return nil end +object.properties._legacy_accessors(client, "buttons", "_buttons", true, function(new_btns) + return new_btns[1] and ( + type(new_btns[1]) == "button" or new_btns[1]._is_capi_button + ) or false +end, true) + --- Set the client shape. -- @property shape -- @tparam gears.shape A gears.shape compatible function. diff --git a/lib/awful/wibar.lua b/lib/awful/wibar.lua index b29d6d846..4b4e9bb62 100644 --- a/lib/awful/wibar.lua +++ b/lib/awful/wibar.lua @@ -421,6 +421,8 @@ function awfulwibar.new(args) w:connect_signal("property::visible", function() reattach(w) end) + assert(w.buttons) + return w end diff --git a/lib/wibox/init.lua b/lib/wibox/init.lua index f55a899e3..3f68d5cb4 100644 --- a/lib/wibox/init.lua +++ b/lib/wibox/init.lua @@ -19,6 +19,7 @@ local beautiful = require("beautiful") local base = require("wibox.widget.base") local cairo = require("lgi").cairo + --- This provides widget box windows. Every wibox can also be used as if it were -- a drawin. All drawin functions and properties are also available on wiboxes! -- wibox @@ -63,6 +64,10 @@ function wibox:find_widgets(x, y) return self._drawable:find_widgets(x, y) end +function wibox:_buttons(btns) + return self.drawin:_buttons(btns) +end + --- Create a widget that reflects the current state of this wibox. -- @treturn widget A new widget. -- @method to_widget @@ -207,12 +212,18 @@ function wibox:get_children_by_id(name) return {} end -for _, k in pairs{ "buttons", "struts", "geometry", "get_xproperty", "set_xproperty" } do +for _, k in pairs{ "struts", "geometry", "get_xproperty", "set_xproperty" } do wibox[k] = function(self, ...) return self.drawin[k](self.drawin, ...) end end +object.properties._legacy_accessors(wibox.object, "buttons", "_buttons", true, function(new_btns) + return new_btns[1] and ( + type(new_btns[1]) == "button" or new_btns[1]._is_capi_button + ) or false +end, true) + local function setup_signals(_wibox) local obj local function clone_signal(name) @@ -264,6 +275,7 @@ local function new(args) return ret end + w._private = {} ret.drawin = w ret._drawable = wibox.drawable(w.drawable, { wibox = ret }, "wibox drawable (" .. object.modulename(3) .. ")") @@ -365,6 +377,8 @@ object.properties(capi.drawin, { auto_emit = true, }) +capi.drawin.object = wibox.object + return setmetatable(wibox, wibox.mt) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/objects/client.c b/objects/client.c index 5f5d9de9e..6a881a625 100644 --- a/objects/client.c +++ b/objects/client.c @@ -949,9 +949,9 @@ /** Get or set mouse buttons bindings for a client. * - * @param buttons_table An array of mouse button bindings objects, or nothing. - * @return A table with all buttons. - * @method buttons + * @property buttons + * @param table + * @see awful.button */ /** Get the number of instances. diff --git a/objects/window.c b/objects/window.c index 3c0432730..623cdbb6e 100644 --- a/objects/window.c +++ b/objects/window.c @@ -515,7 +515,7 @@ window_class_setup(lua_State *L) static const struct luaL_Reg window_meta[] = { { "struts", luaA_window_struts }, - { "buttons", luaA_window_buttons }, + { "_buttons", luaA_window_buttons }, { "set_xproperty", luaA_window_set_xproperty }, { "get_xproperty", luaA_window_get_xproperty }, { NULL, NULL } diff --git a/tests/examples/shims/drawin.lua b/tests/examples/shims/drawin.lua index 2147b6232..0a9780ff6 100644 --- a/tests/examples/shims/drawin.lua +++ b/tests/examples/shims/drawin.lua @@ -37,7 +37,7 @@ local function new_drawin(_, args) ret.data.drawable.refresh = function() end ret.data._struts = { top = 0, right = 0, left = 0, bottom = 0 } - for _, k in pairs{ "buttons", "get_xproperty", "set_xproperty" } do + for _, k in pairs{ "_buttons", "get_xproperty", "set_xproperty" } do ret[k] = function() end end From f7474388790df81671c338758801d64fa2929da1 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 21:38:08 -0500 Subject: [PATCH 14/16] layoutbox: Modernize the constructor. Another step in the long running project to unify all constructors design. --- lib/awful/widget/layoutbox.lua | 35 +++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/awful/widget/layoutbox.lua b/lib/awful/widget/layoutbox.lua index 5583e6836..07b12d629 100644 --- a/lib/awful/widget/layoutbox.lua +++ b/lib/awful/widget/layoutbox.lua @@ -1,5 +1,6 @@ --------------------------------------------------------------------------- ---- Layoutbox widget. +--- Display the current client layout (`awful.layout`) icon or name +-- -- -- @author Julien Danjou <julien@danjou.info> -- @copyright 2009 Julien Danjou @@ -13,6 +14,8 @@ local tooltip = require("awful.tooltip") local beautiful = require("beautiful") local wibox = require("wibox") local surface = require("gears.surface") +-- local gdebug = require("gears.debug") +local gtable = require("gears.table") local function get_screen(s) return s and capi.screen[s] @@ -42,10 +45,25 @@ end --- Create a layoutbox widget. It draws a picture with the current layout -- symbol of the current tag. --- @param screen The screen number that the layout will be represented for. --- @return An imagebox widget configured as a layoutbox. --- @constructorfct awful.widget.layoutbox -function layoutbox.new(screen) +-- @tparam table args The arguments. +-- @tparam screen args.screen The screen number that the layout will be represented for. +-- @tparam table args.buttons The `awful.button`s for this layoutbox. +-- @return The layoutbox. +function layoutbox.new(args) + args = args or {} + local screen = nil + + if type(args) == "number" or type(args) == "screen" or args.fake_remove then + screen, args = args, {} +--TODO uncomment +-- gdebug.deprecate( +-- "Use awful.widget.layoutbox{screen=s} instead of awful.widget.layoutbox(screen)", +-- {deprecated_in=5} +-- ) + end + + assert(type(args) == "table") + screen = get_screen(screen or 1) -- Do we already have the update callbacks registered? @@ -80,6 +98,9 @@ function layoutbox.new(screen) w._layoutbox_tooltip = tooltip {objects = {w}, delay_show = 1} + -- Apply the buttons, visible, forced_width and so on + gtable.crush(w, args) + update(w, screen) boxes[screen] = w end @@ -91,6 +112,10 @@ function layoutbox.mt:__call(...) return layoutbox.new(...) end +--@DOC_widget_COMMON@ + +--@DOC_object_COMMON@ + return setmetatable(layoutbox, layoutbox.mt) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 From 296ad189225ffda25908b8c17bbbee3a9efd4fd9 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 21:58:34 -0500 Subject: [PATCH 15/16] client: Move the `c:keys()` method to a property. --- lib/awful/client.lua | 6 ++++++ objects/client.c | 8 ++++---- tests/examples/shims/key.lua | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/awful/client.lua b/lib/awful/client.lua index 033898517..ccf28325a 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -1350,6 +1350,12 @@ object.properties._legacy_accessors(client, "buttons", "_buttons", true, functio ) or false end, true) +object.properties._legacy_accessors(client, "keys", "_keys", true, function(new_btns) + return new_btns[1] and ( + type(new_btns[1]) == "key" or new_btns[1]._is_capi_key + ) or false +end, true) + --- Set the client shape. -- @property shape -- @tparam gears.shape A gears.shape compatible function. diff --git a/objects/client.c b/objects/client.c index 6a881a625..e9b47a15c 100644 --- a/objects/client.c +++ b/objects/client.c @@ -3677,9 +3677,9 @@ luaA_client_set_shape_input(lua_State *L, client_t *c) /** Get or set keys bindings for a client. * - * @param keys_table An array of key bindings objects, or nothing. - * @return A table with all keys. - * @method keys + * @property keys + * @param table + * @see awful.key */ static int luaA_client_keys(lua_State *L) @@ -3813,7 +3813,7 @@ client_class_setup(lua_State *L) { LUA_OBJECT_META(client) LUA_CLASS_META - { "keys", luaA_client_keys }, + { "_keys", luaA_client_keys }, { "isvisible", luaA_client_isvisible }, { "geometry", luaA_client_geometry }, { "apply_size_hints", luaA_client_apply_size_hints }, diff --git a/tests/examples/shims/key.lua b/tests/examples/shims/key.lua index 2936189dc..ff2866aab 100644 --- a/tests/examples/shims/key.lua +++ b/tests/examples/shims/key.lua @@ -1,6 +1,6 @@ local gobject = require("gears.object") local gtable = require("gears.table") -return setmetatable({}, {__call = function(_, args) +return setmetatable({_is_capi_key = true}, {__call = function(_, args) return gtable.crush(gobject(), args) end}) From cbb90d8bd172375b1f8caa68ac2ed5f34dc6c132 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 26 Dec 2018 22:51:58 -0500 Subject: [PATCH 16/16] root: Turn `root.keys()` into a property. --- lib/awful/_compat.lua | 8 ++++++++ root.c | 11 ++++++----- tests/examples/shims/root.lua | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/awful/_compat.lua b/lib/awful/_compat.lua index 135e32b17..b7af2bb2d 100644 --- a/lib/awful/_compat.lua +++ b/lib/awful/_compat.lua @@ -70,3 +70,11 @@ gprop._legacy_accessors(capi.root, "buttons", "_buttons", false, function(new_bt type(new_btns[1]) == "button" or new_btns[1]._is_capi_button ) or false end, true) + +gprop._legacy_accessors(capi.root, "keys", "_keys", false, function(new_btns) + return new_btns[1] and ( + type(new_btns[1]) == "key" or new_btns[1]._is_capi_button + ) or false +end, true) + +assert(root.keys) diff --git a/root.c b/root.c index 778838d9d..9c1b14655 100644 --- a/root.c +++ b/root.c @@ -335,11 +335,12 @@ luaA_root_fake_input(lua_State *L) } /** Get or set global key bindings. - * These bindings will be available when you press keys on the root window. + * These bindings will be available when you press keys on the root window + * (the wallpaper). * - * @tparam table|nil keys_array An array of key binding objects, or nothing. - * @return The array of key bindings objects of this client. - * @staticfct keys + * @property keys + * @param table + * @see awful.key */ static int luaA_root_keys(lua_State *L) @@ -597,7 +598,7 @@ luaA_root_newindex(lua_State *L) const struct luaL_Reg awesome_root_methods[] = { { "_buttons", luaA_root_buttons }, - { "keys", luaA_root_keys }, + { "_keys", luaA_root_keys }, { "cursor", luaA_root_cursor }, { "fake_input", luaA_root_fake_input }, { "drawins", luaA_root_drawins }, diff --git a/tests/examples/shims/root.lua b/tests/examples/shims/root.lua index ef7031567..47ee71b32 100644 --- a/tests/examples/shims/root.lua +++ b/tests/examples/shims/root.lua @@ -32,7 +32,7 @@ function root.cursor() end local keys = {} -function root.keys(k) +function root._keys(k) keys = k or keys return keys end