Merge pull request #1123 from Elv13/focus_stealing_filter
Support focus stealing filters
This commit is contained in:
commit
26d3c5eb1a
|
@ -15,7 +15,26 @@ local aclient = require("awful.client")
|
||||||
local aplace = require("awful.placement")
|
local aplace = require("awful.placement")
|
||||||
local asuit = require("awful.layout.suit")
|
local asuit = require("awful.layout.suit")
|
||||||
|
|
||||||
local ewmh = {}
|
local ewmh = {
|
||||||
|
generic_activate_filters = {},
|
||||||
|
contextual_activate_filters = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
--- The list of all registered generic request::activate (focus stealing)
|
||||||
|
-- filters. If a filter is added to only one context, it will be in
|
||||||
|
-- `ewmh.contextual_activate_filters`["context_name"].
|
||||||
|
-- @table[opt={}] generic_activate_filters
|
||||||
|
-- @see ewmh.activate
|
||||||
|
-- @see ewmh.add_activate_filter
|
||||||
|
-- @see ewmh.remove_activate_filter
|
||||||
|
|
||||||
|
--- The list of all registered contextual request::activate (focus stealing)
|
||||||
|
-- filters. If a filter is added to only one context, it will be in
|
||||||
|
-- `ewmh.generic_activate_filters`.
|
||||||
|
-- @table[opt={}] contextual_activate_filters
|
||||||
|
-- @see ewmh.activate
|
||||||
|
-- @see ewmh.add_activate_filter
|
||||||
|
-- @see ewmh.remove_activate_filter
|
||||||
|
|
||||||
--- Update a client's settings when its geometry changes, skipping signals
|
--- Update a client's settings when its geometry changes, skipping signals
|
||||||
-- resulting from calls within.
|
-- resulting from calls within.
|
||||||
|
@ -57,9 +76,27 @@ function ewmh.activate(c, context, hints) -- luacheck: no unused args
|
||||||
|
|
||||||
if c.focusable == false and not hints.force then return end
|
if c.focusable == false and not hints.force then return end
|
||||||
|
|
||||||
if c:isvisible() then
|
local found, ret = false
|
||||||
client.focus = c
|
|
||||||
|
-- Execute the filters until something handle the request
|
||||||
|
for _, tab in ipairs {
|
||||||
|
ewmh.contextual_activate_filters[context] or {},
|
||||||
|
ewmh.generic_activate_filters
|
||||||
|
} do
|
||||||
|
for i=#tab, 1, -1 do
|
||||||
|
ret = tab[i](c, context, hints)
|
||||||
|
if ret ~= nil then found=true; break end
|
||||||
|
end
|
||||||
|
|
||||||
|
if found then break end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if ret ~= false and c:isvisible() then
|
||||||
|
client.focus = c
|
||||||
|
elseif ret == false and not hints.force then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if hints and hints.raise then
|
if hints and hints.raise then
|
||||||
c:raise()
|
c:raise()
|
||||||
if not awesome.startup and not c:isvisible() then
|
if not awesome.startup and not c:isvisible() then
|
||||||
|
@ -68,6 +105,69 @@ function ewmh.activate(c, context, hints) -- luacheck: no unused args
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add an activate (focus stealing) filter function.
|
||||||
|
--
|
||||||
|
-- The callback takes the following parameters:
|
||||||
|
--
|
||||||
|
-- * **c** (*client*) The client requesting the activation
|
||||||
|
-- * **context** (*string*) The activation context.
|
||||||
|
-- * **hints** (*table*) Some additional hints (depending on the context)
|
||||||
|
--
|
||||||
|
-- If the callback returns `true`, the client will be activated unless the `force`
|
||||||
|
-- hint is set. If the callback returns `false`, the activation request is
|
||||||
|
-- cancelled. If the callback returns `nil`, the previous callback will be
|
||||||
|
-- executed. This will continue until either a callback handles the request or
|
||||||
|
-- when it runs out of callbacks. In that case, the request will be granted if
|
||||||
|
-- the client is visible.
|
||||||
|
--
|
||||||
|
-- For example, to block Firefox from stealing the focus, use:
|
||||||
|
--
|
||||||
|
-- awful.ewmh.add_activate_filter(function(c, "ewmh")
|
||||||
|
-- if c.class == "Firefox" then return false end
|
||||||
|
-- end)
|
||||||
|
--
|
||||||
|
-- @tparam function f The callback
|
||||||
|
-- @tparam[opt] string context The `request::activate` context
|
||||||
|
-- @see generic_activate_filters
|
||||||
|
-- @see contextual_activate_filters
|
||||||
|
-- @see remove_activate_filter
|
||||||
|
function ewmh.add_activate_filter(f, context)
|
||||||
|
if not context then
|
||||||
|
table.insert(ewmh.generic_activate_filters, f)
|
||||||
|
else
|
||||||
|
ewmh.contextual_activate_filters[context] =
|
||||||
|
ewmh.contextual_activate_filters[context] or {}
|
||||||
|
|
||||||
|
table.insert(ewmh.contextual_activate_filters[context], f)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove an activate (focus stealing) filter function.
|
||||||
|
-- This is an helper to avoid dealing with `ewmh.add_activate_filter` directly.
|
||||||
|
-- @tparam function f The callback
|
||||||
|
-- @tparam[opt] string context The `request::activate` context
|
||||||
|
-- @treturn boolean If the callback existed
|
||||||
|
-- @see generic_activate_filters
|
||||||
|
-- @see contextual_activate_filters
|
||||||
|
-- @see add_activate_filter
|
||||||
|
function ewmh.remove_activate_filter(f, context)
|
||||||
|
local tab = context and (ewmh.contextual_activate_filters[context] or {})
|
||||||
|
or ewmh.generic_activate_filters
|
||||||
|
|
||||||
|
for k, v in ipairs(tab) do
|
||||||
|
if v == f then
|
||||||
|
table.remove(tab, k)
|
||||||
|
|
||||||
|
-- In case the callback is there multiple time.
|
||||||
|
ewmh.remove_activate_filter(f, context)
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
-- Get tags that are on the same screen as the client. This should _almost_
|
-- Get tags that are on the same screen as the client. This should _almost_
|
||||||
-- always return the same content as c:tags().
|
-- always return the same content as c:tags().
|
||||||
local function get_valid_tags(c, s)
|
local function get_valid_tags(c, s)
|
||||||
|
|
|
@ -152,8 +152,34 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** When a client should get activated (focused and/or raised).
|
/** When a client should get activated (focused and/or raised).
|
||||||
|
*
|
||||||
|
* **Contexts are:**
|
||||||
|
*
|
||||||
|
* * *ewmh*: When a client ask for focus (from `X11` events)
|
||||||
|
* * *autofocus.check_focus*: When autofocus is enabled(from `awful.autofocus`)
|
||||||
|
* * *autofocus.check_focus_tag*: When autofocus is enabled
|
||||||
|
* (from `awful.autofocus`)
|
||||||
|
* * *client.jumpto*: When a custom lua extension ask a client to be focused
|
||||||
|
* (from `client.jump_to`)
|
||||||
|
* * *client.swap.global_bydirection*: When client swapping require a focus
|
||||||
|
* change (from `awful.client.swap.bydirection`)
|
||||||
|
* * *client.movetotag*: When a client is moved to a new tag
|
||||||
|
* (from `client.move_to_tag`)
|
||||||
|
* * *client.movetoscreen*: When the client is moved to a new screen
|
||||||
|
* (from `client.move_to_screen`)
|
||||||
|
* * *client.focus.byidx*: When selecting a client using its index
|
||||||
|
* (from `awful.client.focus.byidx`)
|
||||||
|
* * *client.focus.history.previous*: When cycling through history
|
||||||
|
* (from `awful.client.focus.history.previous`)
|
||||||
|
* * *menu.clients*: When using the build in client menu
|
||||||
|
* (from `awful.menu.clients`)
|
||||||
|
* * *rules*: When a new client is focused from a rule (from `awful.rules`)
|
||||||
|
* * *screen.focus*: When a screen is focused (from `awful.screen.focus`)
|
||||||
*
|
*
|
||||||
* Default implementation: `awful.ewmh.activate`.
|
* Default implementation: `awful.ewmh.activate`.
|
||||||
|
*
|
||||||
|
* To implement focus stealing filters see `awful.ewmh.add_activate_filter`.
|
||||||
|
*
|
||||||
* @signal request::activate
|
* @signal request::activate
|
||||||
* @tparam string context The context where this signal was used.
|
* @tparam string context The context where this signal was used.
|
||||||
* @tparam[opt] table hints A table with additional hints:
|
* @tparam[opt] table hints A table with additional hints:
|
||||||
|
|
|
@ -77,6 +77,54 @@ end
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local original_count, c1, c2 = 0
|
||||||
|
|
||||||
|
-- Check request::activate
|
||||||
|
table.insert(steps, function()
|
||||||
|
c1, c2 = client.get()[1], client.get()[2]
|
||||||
|
|
||||||
|
-- This should still be the case
|
||||||
|
assert(client.focus == c1)
|
||||||
|
|
||||||
|
c2:emit_signal("request::activate", "i_said_so")
|
||||||
|
|
||||||
|
return true
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Check if writing a focus stealing filter works.
|
||||||
|
table.insert(steps, function()
|
||||||
|
-- This should still be the case
|
||||||
|
assert(client.focus == c2)
|
||||||
|
|
||||||
|
original_count = #awful.ewmh.generic_activate_filters
|
||||||
|
|
||||||
|
awful.ewmh.add_activate_filter(function(c)
|
||||||
|
if c == c1 then return false end
|
||||||
|
end)
|
||||||
|
|
||||||
|
c1:emit_signal("request::activate", "i_said_so")
|
||||||
|
|
||||||
|
return true
|
||||||
|
end)
|
||||||
|
|
||||||
|
table.insert(steps, function()
|
||||||
|
-- The request should have been denied
|
||||||
|
assert(client.focus == c2)
|
||||||
|
|
||||||
|
-- Test the remove function
|
||||||
|
awful.ewmh.remove_activate_filter(function() end)
|
||||||
|
|
||||||
|
awful.ewmh.add_activate_filter(awful.ewmh.generic_activate_filters[1])
|
||||||
|
|
||||||
|
awful.ewmh.remove_activate_filter(awful.ewmh.generic_activate_filters[1])
|
||||||
|
|
||||||
|
assert(original_count == #awful.ewmh.generic_activate_filters)
|
||||||
|
|
||||||
|
c1:emit_signal("request::activate", "i_said_so")
|
||||||
|
|
||||||
|
return client.focus == c1
|
||||||
|
end)
|
||||||
|
|
||||||
local has_error
|
local has_error
|
||||||
|
|
||||||
-- Disable awful.screen.preferred(c)
|
-- Disable awful.screen.preferred(c)
|
||||||
|
|
Loading…
Reference in New Issue