autofocus: Modify `awful.autofocus` to be a request::.
This also pulls in part of the permission framework to ensure backward compatibility is kept. `awful.autofocus` was always weird. It is a module part of `awful`, but it was never part of `awful` `init.lua`. Rather, `rc.lua` was the sole place it was used. It behave exactly like a request, but predate them by years. As I cleanup the request:: API before the permissions API gets formalized, this has to be fixed now. It isn't deprecated in this commit because it makes too many tests fail. Another pull request will solve that by adding the "API level" concept to AwesomeWM so I can change the behavior without breaking existing configs. With that, the behavior of `autofocus` will be enabled by default with the permissions to disable it.
This commit is contained in:
parent
5ad0856fee
commit
efc42b1be1
|
@ -535,8 +535,3 @@ client.connect_signal("request::titlebars", function(c)
|
|||
}
|
||||
end)
|
||||
-- }}}
|
||||
|
||||
-- Enable sloppy focus, so that focus follows mouse.
|
||||
client.connect_signal("mouse::enter", function(c)
|
||||
c:activate { context = "mouse_enter", raise = false }
|
||||
end)
|
||||
|
|
|
@ -444,6 +444,7 @@ file = {
|
|||
'../lib/awful/screen/dpi.lua',
|
||||
'../lib/awful/startup_notification.lua',
|
||||
'../lib/awful/mouse/drag_to_tag.lua',
|
||||
'../lib/awful/permissions/_common.lua',
|
||||
'../lib/gears/init.lua',
|
||||
'../lib/wibox/layout/init.lua',
|
||||
'../lib/wibox/container/init.lua',
|
||||
|
|
|
@ -1,74 +1,15 @@
|
|||
---------------------------------------------------------------------------
|
||||
--- Autofocus functions.
|
||||
--
|
||||
-- When loaded, this module makes sure that there's always a client that will
|
||||
-- have focus on events such as tag switching, client unmanaging, etc.
|
||||
--
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @module awful.autofocus
|
||||
-- This module used to be a "require only" module which, when explicitly
|
||||
-- required, would allow handle focus when switching tags and other useful
|
||||
-- corner cases. This code has been migrated to a more standard request::
|
||||
-- API. The content itself is now in `awful.permissions`. This was required
|
||||
-- to preserve backward compatibility since this module may or may not have
|
||||
-- been loaded.
|
||||
---------------------------------------------------------------------------
|
||||
require("awful.permissions._common")._deprecated_autofocus_in_use()
|
||||
|
||||
local client = client
|
||||
local aclient = require("awful.client")
|
||||
local timer = require("gears.timer")
|
||||
|
||||
local function filter_sticky(c)
|
||||
return not c.sticky and aclient.focus.filter(c)
|
||||
end
|
||||
|
||||
--- Give focus when clients appear/disappear.
|
||||
--
|
||||
-- @param obj An object that should have a .screen property.
|
||||
local function check_focus(obj)
|
||||
if (not obj.screen) or not obj.screen.valid then return end
|
||||
-- When no visible client has the focus...
|
||||
if not client.focus or not client.focus:isvisible() then
|
||||
local c = aclient.focus.history.get(screen[obj.screen], 0, filter_sticky)
|
||||
if not c then
|
||||
c = aclient.focus.history.get(screen[obj.screen], 0, aclient.focus.filter)
|
||||
end
|
||||
if c then
|
||||
c:emit_signal("request::activate", "autofocus.check_focus",
|
||||
{raise=false})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Check client focus (delayed).
|
||||
-- @param obj An object that should have a .screen property.
|
||||
local function check_focus_delayed(obj)
|
||||
timer.delayed_call(check_focus, {screen = obj.screen})
|
||||
end
|
||||
|
||||
--- Give focus on tag selection change.
|
||||
--
|
||||
-- @tparam tag t A tag object
|
||||
local function check_focus_tag(t)
|
||||
local s = t.screen
|
||||
if (not s) or (not s.valid) then return end
|
||||
s = screen[s]
|
||||
check_focus({ screen = s })
|
||||
if client.focus and screen[client.focus.screen] ~= s then
|
||||
local c = aclient.focus.history.get(s, 0, filter_sticky)
|
||||
if not c then
|
||||
c = aclient.focus.history.get(s, 0, aclient.focus.filter)
|
||||
end
|
||||
if c then
|
||||
c:emit_signal("request::activate", "autofocus.check_focus_tag",
|
||||
{raise=false})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tag.connect_signal("property::selected", function (t)
|
||||
timer.delayed_call(check_focus_tag, t)
|
||||
end)
|
||||
client.connect_signal("request::unmanage", check_focus_delayed)
|
||||
client.connect_signal("tagged", check_focus_delayed)
|
||||
client.connect_signal("untagged", check_focus_delayed)
|
||||
client.connect_signal("property::hidden", check_focus_delayed)
|
||||
client.connect_signal("property::minimized", check_focus_delayed)
|
||||
client.connect_signal("property::sticky", check_focus_delayed)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
--require("gears.debug").deprecate(
|
||||
-- "The `awful.autofocus` module is deprecated, remove the require() and "..
|
||||
-- "look at the new `rc.lua` granted permission section in the client rules",
|
||||
-- {deprecated_in=5}
|
||||
--)
|
||||
|
|
|
@ -18,6 +18,7 @@ local beautiful = require("beautiful")
|
|||
local alayout = require("awful.layout")
|
||||
local atag = require("awful.tag")
|
||||
local gdebug = require("gears.debug")
|
||||
local pcommon = require("awful.permissions._common")
|
||||
|
||||
local ewmh = {
|
||||
generic_activate_filters = {},
|
||||
|
@ -75,6 +76,60 @@ local function repair_geometry(window)
|
|||
repair_geometry_lock = false
|
||||
end
|
||||
|
||||
local function filter_sticky(c)
|
||||
return not c.sticky and aclient.focus.filter(c)
|
||||
end
|
||||
|
||||
--- Give focus when clients appear/disappear.
|
||||
--
|
||||
-- @param obj An object that should have a .screen property.
|
||||
local function check_focus(obj)
|
||||
if (not obj.screen) or not obj.screen.valid then return end
|
||||
-- When no visible client has the focus...
|
||||
if not client.focus or not client.focus:isvisible() then
|
||||
local c = aclient.focus.history.get(screen[obj.screen], 0, filter_sticky)
|
||||
if not c then
|
||||
c = aclient.focus.history.get(screen[obj.screen], 0, aclient.focus.filter)
|
||||
end
|
||||
if c then
|
||||
c:emit_signal(
|
||||
"request::autoactivate",
|
||||
"history",
|
||||
{raise=false}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Check client focus (delayed).
|
||||
-- @param obj An object that should have a .screen property.
|
||||
local function check_focus_delayed(obj)
|
||||
timer.delayed_call(check_focus, {screen = obj.screen})
|
||||
end
|
||||
|
||||
--- Give focus on tag selection change.
|
||||
--
|
||||
-- @tparam tag t A tag object
|
||||
local function check_focus_tag(t)
|
||||
local s = t.screen
|
||||
if (not s) or (not s.valid) then return end
|
||||
s = screen[s]
|
||||
check_focus({ screen = s })
|
||||
if client.focus and screen[client.focus.screen] ~= s then
|
||||
local c = aclient.focus.history.get(s, 0, filter_sticky)
|
||||
if not c then
|
||||
c = aclient.focus.history.get(s, 0, aclient.focus.filter)
|
||||
end
|
||||
if c then
|
||||
c:emit_signal(
|
||||
"request::autoactivate",
|
||||
"switch_tag",
|
||||
{raise=false}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Activate a window.
|
||||
--
|
||||
-- This sets the focus only if the client is visible.
|
||||
|
@ -605,6 +660,32 @@ function ewmh.update_border(c, context)
|
|||
end
|
||||
end
|
||||
|
||||
local activate_context_map = {
|
||||
mouse_enter = "mouse.enter",
|
||||
switch_tag = "autofocus.check_focus_tag",
|
||||
history = "autofocus.check_focus"
|
||||
}
|
||||
|
||||
--- Default handler for the `request::autoactivate` signal.
|
||||
--
|
||||
-- All it does is to emit `request::activate` with the following context
|
||||
-- mapping:
|
||||
--
|
||||
-- * mouse_enter: *mouse.enter*
|
||||
-- * switch_tag : *autofocus.check_focus_tag*
|
||||
-- * history : *autofocus.check_focus*
|
||||
--
|
||||
-- @signalhandler awful.ewmh.autoactivate
|
||||
function ewmh.autoactivate(c, context, args)
|
||||
if not pcommon.check("client", "autoactivate", context) then return end
|
||||
|
||||
local ctx = activate_context_map[context] and
|
||||
activate_context_map[context] or context
|
||||
|
||||
c:emit_signal("request::activate", ctx, args)
|
||||
end
|
||||
|
||||
client.connect_signal("request::autoactivate", ewmh.autoactivate)
|
||||
client.connect_signal("request::border", ewmh.update_border)
|
||||
client.connect_signal("request::activate", ewmh.activate)
|
||||
client.connect_signal("request::tag", ewmh.tag)
|
||||
|
@ -614,12 +695,27 @@ client.connect_signal("request::geometry", ewmh.merge_maximization)
|
|||
client.connect_signal("request::geometry", ewmh.client_geometry_requests)
|
||||
client.connect_signal("property::border_width", repair_geometry)
|
||||
client.connect_signal("property::screen", repair_geometry)
|
||||
client.connect_signal("request::unmanage", check_focus_delayed)
|
||||
client.connect_signal("tagged", check_focus_delayed)
|
||||
client.connect_signal("untagged", check_focus_delayed)
|
||||
client.connect_signal("property::hidden", check_focus_delayed)
|
||||
client.connect_signal("property::minimized", check_focus_delayed)
|
||||
client.connect_signal("property::sticky", check_focus_delayed)
|
||||
tag.connect_signal("property::selected", function (t)
|
||||
timer.delayed_call(check_focus_tag, t)
|
||||
end)
|
||||
|
||||
screen.connect_signal("property::workarea", function(s)
|
||||
for _, c in pairs(client.get(s)) do
|
||||
repair_geometry(c)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Enable sloppy focus, so that focus follows mouse.
|
||||
client.connect_signal("mouse::enter", function(c)
|
||||
c:emit_signal("request::autoactivate", "mouse_enter", {raise=false})
|
||||
end)
|
||||
|
||||
return ewmh
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
-- Common code for the permission framework.
|
||||
-- It is in its own file to avoid circular dependencies.
|
||||
--
|
||||
-- It is **NOT** a public API.
|
||||
|
||||
local module = {}
|
||||
|
||||
-- The default permissions for all requests.
|
||||
-- If something is not in this list, then it is assumed it should be granted.
|
||||
local default_permissions = {
|
||||
client = {
|
||||
autoactivate = {
|
||||
-- To preserve the default from AwesomeWM 3.3-4.3, do not steal
|
||||
-- focus by default for these contexts:
|
||||
mouse_enter = false,
|
||||
switch_tag = false,
|
||||
history = false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function module.check(class, request, context)
|
||||
if not default_permissions[class] then return true end
|
||||
if not default_permissions[class][request] then return true end
|
||||
if default_permissions[class][request][context] == nil then return true end
|
||||
|
||||
return default_permissions[class][request][context]
|
||||
end
|
||||
|
||||
function module.set(class, request, context, granted)
|
||||
assert(type(granted) == "boolean")
|
||||
|
||||
if not default_permissions[class] then
|
||||
default_permissions[class] = {}
|
||||
end
|
||||
|
||||
if not default_permissions[class][request] then
|
||||
default_permissions[class][request] = {}
|
||||
end
|
||||
|
||||
default_permissions[class][request][context] = granted
|
||||
end
|
||||
|
||||
-- Awesome 3.3-4.3 had an `awful.autofocus` module. That module had no APIs, but
|
||||
-- was simply "enabled" when you `require()`d it for the first time. This was
|
||||
-- non-standard and was the only module in `awful` to only do things when
|
||||
-- explicitly `require()`d.
|
||||
--
|
||||
-- It is now a dummy module which will set the property to `true`.
|
||||
function module._deprecated_autofocus_in_use()
|
||||
module.set("client", "autoactivate", "mouse_enter", true)
|
||||
module.set("client", "autoactivate", "switch_tag" , true)
|
||||
module.set("client", "autoactivate", "history" , true)
|
||||
end
|
||||
|
||||
return module
|
|
@ -266,6 +266,26 @@
|
|||
* @tparam[opt=false] boolean hints.raise should the client be raised?
|
||||
*/
|
||||
|
||||
/** When an event could lead to the client being activated.
|
||||
*
|
||||
* This is an layer "on top" of `request::activate` for event which are not
|
||||
* actual request for activation/focus, but where "it would be nice" if the
|
||||
* client got the focus. This includes the focus-follow-mouse model and focusing
|
||||
* previous clients when the selected tag changes.
|
||||
*
|
||||
* This idea is that `request::autoactivate` will emit `request::activate`.
|
||||
* However it is much easier to replace the handler for `request::autoactivate`
|
||||
* than it is to replace the handler for `request::activate`. Thus it provides
|
||||
* a nice abstraction to simplify handling the focus when switching tags or
|
||||
* moving the mouse.
|
||||
*
|
||||
* @signal request::autoactivate
|
||||
* @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?
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @signal request::geometry
|
||||
* @tparam client c The client
|
||||
|
|
|
@ -11,6 +11,9 @@ describe("awful.ewmh.client_geometry_requests", function()
|
|||
_G.screen = {
|
||||
connect_signal = function() end,
|
||||
}
|
||||
_G.tag = {
|
||||
connect_signal = function() end,
|
||||
}
|
||||
|
||||
local ewmh = require("awful.ewmh")
|
||||
|
||||
|
|
Loading…
Reference in New Issue