diff --git a/lib/awful/button.lua b/lib/awful/button.lua
index aadf7c7a..c4c05f67 100644
--- a/lib/awful/button.lua
+++ b/lib/awful/button.lua
@@ -2,6 +2,8 @@
--- Create easily new buttons objects ignoring certain modifiers.
--
-- @author Julien Danjou <julien@danjou.info>
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2018 Emmanuel Lepage Vallee
-- @copyright 2009 Julien Danjou
-- @inputmodule awful.button
---------------------------------------------------------------------------
@@ -15,6 +17,13 @@ local gtable = require("gears.table")
local button = { mt = {} }
+-- Due to non trivial abuse or `pairs` in older code, the private data cannot
+-- be stored in the object itself without creating subtle bugs. This cannot be
+-- fixed internally because the default `rc.lua` uses `gears.table.join`, which
+-- is affected.
+--TODO v6: Drop this
+local reverse_map = setmetatable({}, {__mode="k"})
+
--- Modifiers to ignore.
--
-- By default this is initialized as `{ "Lock", "Mod2" }`
@@ -24,19 +33,172 @@ local button = { mt = {} }
-- @table ignore_modifiers
local ignore_modifiers = { "Lock", "Mod2" }
+--- The mouse buttons names.
+--
+-- It can be used instead of the button ids.
+--
+-- @table names
+button.names = {
+ LEFT = 1,-- The left mouse button.
+ MIDDLE = 2,-- The scrollwheel button.
+ RIGHT = 3,-- The context menu button.
+ SCROLL_UP = 4,-- A scroll up increment.
+ SCROLL_DOWN = 5,-- A scroll down increment.
+}
+
+--- The table of modifier keys.
+--
+-- A modifier, such as `Control` are a predetermined set of keys that can be
+-- used to implement keybindings. Note that this list is fix and cannot be
+-- extended using random key names, code or characters.
+--
+-- Common modifiers are:
+--
+--
+--
+-- Please note that Awesome ignores the status of "Lock" and "Mod2" (Num Lock).
+--
+-- @property modifiers
+
+--- The mouse button identifier.
+--
+-- ![Mouse buttons](../images/mouse.svg)
+--
+-- @property button
+-- @param integer
+
+--- The button description.
+--
+-- @property description
+-- @param string
+
+--- The button name.
+--
+-- @property name
+-- @param string
+
+--- The button group.
+--
+-- @property group
+-- @param string
+
+--- The callback when this button is pressed.
+--
+-- @property on_press
+-- @param function
+
+--- The callback when this button is released.
+--
+-- @property on_release
+-- @param function
+
+--- Execute this mousebinding.
+-- @function button:trigger
+
+function button:set_button(b)
+ for _, v in ipairs(self) do
+ v.button = b
+ end
+end
+
+function button:set_modifiers(mod)
+ local subsets = gmath.subsets(ignore_modifiers)
+ for k, set in ipairs(subsets) do
+ self[k].modifiers = gtable.join(mod, set)
+ end
+end
+
+for _, prop in ipairs { "description", "group", "on_press", "on_release", "name" } do
+ button["get_"..prop] = function(self)
+ return reverse_map[self][prop]
+ end
+ button["set_"..prop] = function(self, value)
+ reverse_map[self][prop] = value
+ end
+end
+
+function button:get_button()
+ return self[1].button
+end
+
+function button:trigger()
+ local data = reverse_map[self]
+ if data.press then
+ data.press()
+ end
+
+ if data.release then
+ data.release()
+ end
+end
+
+local function index_handler(self, k)
+ if button["get_"..k] then
+ return button["get_"..k](self)
+ end
+
+ if type(button[k]) == "function" then
+ return button[k]
+ end
+
+ local data = reverse_map[self]
+ assert(data)
+
+ return data[k]
+end
+
+local function newindex_handler(self, key, value)
+ if button["set_"..key] then
+ return button["set_"..key](self, value)
+ end
+
+ local data = reverse_map[self]
+ assert(data)
+
+ data[key] = value
+end
+
+local obj_mt = {
+ __index = index_handler,
+ __newindex = newindex_handler
+}
+
--- Create a new button to use as binding.
--
--- This function is useful to create several buttons from one, because it will use
--- the ignore_modifier variable to create more button with or without the ignored
--- modifiers activated.
+-- @constructorfct awful.button
+-- @tparam table mod A list of modifier keys. Valid modifiers are:
+-- `Any`, `Mod1`, Mod2`, `Mod3`, `Mod4`, `Mod5`, `Shift`, `Lock` and `Control`.
+-- This argument is (**mandatory**).
+-- @tparam number button The mouse button (it is recommended to use the
+-- `awful.button.names` constants.
+-- @tparam function press Callback for when the button is pressed.
+-- @tparam function release Callback for when the button is released.
+-- @treturn table An `awful.button` object.
+
+--- Create a new button to use as binding.
--
--- For example if you want to ignore CapsLock in your buttonbinding (which is
--- ignored by default by this function), creating button binding with this function
--- will return 2 button objects: one with CapsLock on, and the other one with
--- CapsLock off.
---
--- @treturn table A table with one or several button objects.
-function button.new(mod, _button, press, release)
+-- @constructorfct2 awful.button
+-- @tparam table args
+-- @tparam table args.modifiers A list of modifier keys. Valid modifiers are:
+-- `Any`, `Mod1`, Mod2`, `Mod3`, `Mod4`, `Mod5`, `Shift`, `Lock` and `Control`.
+-- This argument is (**mandatory**).
+-- @tparam number args.button The mouse button (it is recommended to use the
+-- `awful.button.names` constants.
+-- @tparam function args.on_press Callback for when the button is pressed.
+-- @tparam function args.on_release Callback for when the button is released.
+-- @treturn table An `awful.button` object.
+
+local function new_common(mod, _button, press, release)
local ret = {}
local subsets = gmath.subsets(ignore_modifiers)
for _, set in ipairs(subsets) do
@@ -49,7 +211,25 @@ function button.new(mod, _button, press, release)
ret[#ret]:connect_signal("release", function (_, ...) release(...) end)
end
end
- return ret
+
+ reverse_map[ret] = {_is_capi_button = false}
+
+ return setmetatable(ret, obj_mt)
+end
+
+function button.new(args, _button, press, release)
+ -- Assume this is the new constructor.
+ if not _button then
+ assert(not (press or release), "Calling awful.button() requires a button name")
+ return new_common(
+ args.modifiers,
+ args.button,
+ args.on_press,
+ args.on_release
+ )
+ else
+ return new_common(args, _button, press, release)
+ end
end
function button.mt:__call(...)
diff --git a/spec/awful/keyboardlayout_spec.lua b/spec/awful/keyboardlayout_spec.lua
index e2a5c966..4cf8739d 100644
--- a/spec/awful/keyboardlayout_spec.lua
+++ b/spec/awful/keyboardlayout_spec.lua
@@ -3,6 +3,14 @@
-- @copyright 2015 Uli Schlachter and Kazunobu Kuriyama
---------------------------------------------------------------------------
+-- luacheck: globals button
+_G.button = setmetatable({
+ set_index_miss_handler = function() end,
+ set_newindex_miss_handler = function() end
+}, {
+ __call = function() return {} end
+})
+
local kb = require("awful.widget.keyboardlayout")
describe("awful.widget.keyboardlayout get_groups_from_group_names", function()