From 5818de41ce181f36207bb0d7b090aff292737089 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 17 Nov 2019 18:46:22 -0500 Subject: [PATCH] awful: Rename awful.ewmh to awful.permissions. It has nothing to do with EWMH since a long time. It was already used for the requests, so lets formalize this. --- build-utils/check_for_invalid_requires.lua | 3 + docs/90-FAQ.md | 8 +- docs/config.ld | 1 + lib/awful/client.lua | 8 +- lib/awful/ewmh.lua | 726 +----------------- lib/awful/init.lua | 19 +- lib/awful/permissions/init.lua | 724 +++++++++++++++++ .../{ewmh_spec.lua => permissions_spec.lua} | 16 +- .../examples/sequences/client/fullscreen.lua | 2 +- tests/examples/sequences/client/maximized.lua | 2 +- .../sequences/client/maximized_horizontal.lua | 2 +- .../sequences/client/maximized_vertical.lua | 2 +- tests/test-awful-client.lua | 12 +- tests/test-maximize.lua | 4 +- 14 files changed, 779 insertions(+), 750 deletions(-) create mode 100644 lib/awful/permissions/init.lua rename spec/awful/{ewmh_spec.lua => permissions_spec.lua} (71%) diff --git a/build-utils/check_for_invalid_requires.lua b/build-utils/check_for_invalid_requires.lua index dd33443b..741d1ad3 100755 --- a/build-utils/check_for_invalid_requires.lua +++ b/build-utils/check_for_invalid_requires.lua @@ -32,6 +32,9 @@ local allowed_deps = { gears = true, lgi = true, wibox = true, + + -- Necessary to lazy-load the deprecated modules. + ["awful.*"] = true }, naughty = { awful = true, diff --git a/docs/90-FAQ.md b/docs/90-FAQ.md index 7e7d1c2b..9257632d 100644 --- a/docs/90-FAQ.md +++ b/docs/90-FAQ.md @@ -315,17 +315,17 @@ You can call the `awful.layout.set()` function, here's an example: ### Why are new clients urgent by default? -You can change this by redefining `awful.ewmh.activate(c)` in your rc.lua. If +You can change this by redefining `awful.permissions.activate(c)` in your rc.lua. If you don't want new clients to be urgent by default put this in your rc.lua: - client.disconnect_signal("request::activate", awful.ewmh.activate) - function awful.ewmh.activate(c) + client.disconnect_signal("request::activate", awful.permissions.activate) + function awful.permissions.activate(c) if c:isvisible() then client.focus = c c:raise() end end - client.connect_signal("request::activate", awful.ewmh.activate) + client.connect_signal("request::activate", awful.permissions.activate) ## Usage diff --git a/docs/config.ld b/docs/config.ld index 6a1470a8..c4c6c307 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -471,6 +471,7 @@ file = { '../lib/awful/widget/progressbar.lua', '../lib/awful/widget/textclock.lua', '../lib/awful/wibox.lua', + '../lib/awful/ewmh.lua', '../lib/wibox/layout/constraint.lua', '../lib/wibox/layout/margin.lua', '../lib/wibox/layout/mirror.lua', diff --git a/lib/awful/client.lua b/lib/awful/client.lua index 53041540..fc06f612 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -1447,7 +1447,7 @@ end -- @tparam[opt=false] boolean args.switch_to_tag -- @tparam[opt=false] boolean args.action Once activated, perform an action. -- @tparam[opt=false] boolean args.toggle_minimization --- @see awful.ewmh.add_activate_filter +-- @see awful.permissions.add_activate_filter -- @see request::activate -- @see active function client.object.activate(c, args) @@ -1539,7 +1539,7 @@ end -- @tparam boolean active -- @see activate -- @see request::activate --- @see awful.ewmh.add_activate_filter +-- @see awful.permissions.add_activate_filter function client.object.get_active(c) return capi.client.focus == c @@ -1592,10 +1592,10 @@ end) -- * **floating**: When the floating or maximization state changes. -- -- @signal request::border --- @see awful.ewmh.update_border +-- @see awful.permissions.update_border -- Add clients during startup to focus history. --- This used to happen through ewmh.activate, but that only handles visible +-- This used to happen through permissions.activate, but that only handles visible -- clients now. capi.client.connect_signal("request::manage", function (c) if capi.awesome.startup diff --git a/lib/awful/ewmh.lua b/lib/awful/ewmh.lua index c39fb242..5cd71a36 100644 --- a/lib/awful/ewmh.lua +++ b/lib/awful/ewmh.lua @@ -1,721 +1,9 @@ ---------------------------------------------------------------------------- ---- Implements EWMH requests handling. --- --- @author Julien Danjou <julien@danjou.info> --- @copyright 2009 Julien Danjou --- @module awful.ewmh ---------------------------------------------------------------------------- - -local client = client -local screen = screen -local ipairs = ipairs -local timer = require("gears.timer") -local gtable = require("gears.table") -local aclient = require("awful.client") -local aplace = require("awful.placement") -local asuit = require("awful.layout.suit") -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 = {}, - contextual_activate_filters = {}, -} - ---- Honor the screen padding when maximizing. --- @beautiful beautiful.maximized_honor_padding --- @tparam[opt=true] boolean maximized_honor_padding - ---- Hide the border on fullscreen clients. --- @beautiful beautiful.fullscreen_hide_border --- @tparam[opt=true] boolean fullscreen_hide_border - ---- Hide the border on maximized clients. --- @beautiful beautiful.maximized_hide_border --- @tparam[opt=false] boolean maximized_hide_border - ---- 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 --- resulting from calls within. -local repair_geometry_lock = false - -local function repair_geometry(window) - if repair_geometry_lock then return end - repair_geometry_lock = true - - -- Re-apply the geometry locking properties to what they should be. - for _, prop in ipairs { - "fullscreen", "maximized", "maximized_vertical", "maximized_horizontal" - } do - if window[prop] then - window:emit_signal("request::geometry", prop, { - store_geometry = false - }) - break - end - end - - 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. --- --- It is the default signal handler for `request::activate` on a `client`. --- --- @signalhandler awful.ewmh.activate --- @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? --- @tparam[opt=false] boolean hints.switch_to_tag should the client's first tag --- be selected if none of the client's tags are selected? --- @tparam[opt=false] boolean hints.switch_to_tags Select all tags associated --- with the client. -function ewmh.activate(c, context, hints) -- luacheck: no unused args - hints = hints or {} - - if c.focusable == false and not hints.force then - if hints.raise then - c:raise() - end - - return - end - - local found, ret = false - - -- 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 - - -- Minimized clients can be requested to have focus by, for example, 3rd - -- party toolbars and they might not try to unminimize it first. - if ret ~= false and hints.raise then - c.minimized = false - end - - if ret ~= false and c:isvisible() then - client.focus = c - elseif ret == false and not hints.force then - return - end - - if hints.raise then - c:raise() - if not awesome.startup and not c:isvisible() then - c.urgent = true - end - end - - -- The rules use `switchtotag`. For consistency and code re-use, support it, - -- but keep undocumented. --TODO v5 remove switchtotag - if hints.switchtotag or hints.switch_to_tag or hints.switch_to_tags then - atag.viewmore(c:tags(), c.screen, (not hints.switch_to_tags) and 0 or nil) - 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. If the callback --- returns `false`, the activation request is cancelled unless the `force` hint is --- set. 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) --- if c.class == "Firefox" then return false end --- end, "ewmh") --- --- @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 --- @staticfct awful.ewmh.add_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 --- @staticfct awful.ewmh.remove_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_ --- always return the same content as c:tags(). -local function get_valid_tags(c, s) - local tags, new_tags = c:tags(), {} - - for _, t in ipairs(tags) do - if s == t.screen then - table.insert(new_tags, t) - end - end - - return new_tags -end - ---- Tag a window with its requested tag. --- --- It is the default signal handler for `request::tag` on a `client`. --- --- @signalhandler awful.ewmh.tag --- @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 ewmh.tag(c, t, hints) --luacheck: no unused - -- There is nothing to do - if not t and #get_valid_tags(c, c.screen) > 0 then return end - - if not t then - if c.transient_for and not (hints and hints.reason == "screen") then - c.screen = c.transient_for.screen - if not c.sticky then - local tags = c.transient_for:tags() - c:tags(#tags > 0 and tags or c.transient_for.screen.selected_tags) - end - else - c:to_selected_tags() - end - elseif type(t) == "boolean" and t then - c.sticky = true - else - c.screen = t.screen - c:tags({ t }) - end -end - ---- Handle client urgent request --- @signalhandler awful.ewmh.urgent --- @client c A client --- @tparam boolean urgent If the client should be urgent -function ewmh.urgent(c, urgent) - if c ~= client.focus and not aclient.property.get(c,"ignore_urgent") then - c.urgent = urgent - end -end - --- Map the state to the action name -local context_mapper = { - maximized_vertical = "maximize_vertically", - maximized_horizontal = "maximize_horizontally", - maximized = "maximize", - fullscreen = "maximize" -} - ---- Move and resize the client. --- --- This is the default geometry request handler. --- --- @signalhandler awful.ewmh.geometry --- @tparam client c The client --- @tparam string context The context --- @tparam[opt={}] table hints The hints to pass to the handler -function ewmh.geometry(c, context, hints) - local layout = c.screen.selected_tag and c.screen.selected_tag.layout or nil - - -- Setting the geometry will not work unless the client is floating. - if (not c.floating) and (not layout == asuit.floating) then - return - end - - context = context or "" - - local original_context = context - - -- Now, map it to something useful - context = context_mapper[context] or context - - local props = gtable.clone(hints or {}, false) - props.store_geometry = props.store_geometry==nil and true or props.store_geometry - - -- If it is a known placement function, then apply it, otherwise let - -- other potential handler resize the client (like in-layout resize or - -- floating client resize) - if aplace[context] then - - -- Check if it corresponds to a boolean property. - local state = c[original_context] - - -- If the property is boolean and it corresponds to the undo operation, - -- restore the stored geometry. - if state == false then - local original = repair_geometry_lock - repair_geometry_lock = true - aplace.restore(c, {context=context}) - repair_geometry_lock = original - return - end - - local honor_default = original_context ~= "fullscreen" - - if props.honor_workarea == nil then - props.honor_workarea = honor_default - end - - if props.honor_padding == nil and props.honor_workarea and context:match("maximize") then - props.honor_padding = beautiful.maximized_honor_padding ~= false - end - - if (original_context == "fullscreen" and beautiful.fullscreen_hide_border ~= false) or - (original_context == "maximized" and beautiful.maximized_hide_border == true) then - props.ignore_border_width = true - props.zap_border_width = true - end - - local original = repair_geometry_lock - repair_geometry_lock = true - aplace[context](c, props) - repair_geometry_lock = original - end -end - ---- Merge the 2 requests sent by clients wanting to be maximized. --- --- The X clients set 2 flags (atoms) when they want to be maximized. This caused --- 2 request::geometry to be sent. This code gives some time for them to arrive --- and send a new `request::geometry` (through the property change) with the --- combined state. --- --- @signalhandler awful.ewmh.merge_maximization --- @tparam client c The client --- @tparam string context The context --- @tparam[opt={}] table hints The hints to pass to the handler -function ewmh.merge_maximization(c, context, hints) - if context ~= "client_maximize_horizontal" and context ~= "client_maximize_vertical" then - return - end - - if not c._delay_maximization then - c._delay_maximization = function() - -- Computes the actual X11 atoms before/after - local before_max_h = c.maximized or c.maximized_horizontal - local before_max_v = c.maximized or c.maximized_vertical - local after_max_h, after_max_v - if c._delayed_max_h ~= nil then - after_max_h = c._delayed_max_h - else - after_max_h = before_max_h - end - if c._delayed_max_v ~= nil then - after_max_v = c._delayed_max_v - else - after_max_v = before_max_v - end - -- Interprets the client's intention based on the client's view - if after_max_h and after_max_v then - c.maximized = true - elseif before_max_h and before_max_v then - -- At this point, c.maximized must be true, and the client is - -- trying to unmaximize the window, and potentially partial - -- maximized the window - c.maximized = false - if after_max_h ~= after_max_v then - c.maximized_horizontal = after_max_h - c.maximized_vertical = after_max_v - end - else - -- At this point, c.maximized must be false, and the client is - -- not trying to fully maximize the window - c.maximized_horizontal = after_max_h - c.maximized_vertical = after_max_v - end - end - - timer { - timeout = 1/60, - autostart = true, - single_shot = true, - callback = function() - if not c.valid then return end - - c._delay_maximization(c) - c._delay_maximization = nil - c._delayed_max_h = nil - c._delayed_max_v = nil - end - } - end - - local function get_value(suffix, long_suffix) - if hints.toggle and c["_delayed_max_"..suffix] ~= nil then - return not c["_delayed_max_"..suffix] - elseif hints.toggle then - return not (c["maximized"] or c["maximized_"..long_suffix]) - else - return hints.status - end - end - - if context == "client_maximize_horizontal" then - c._delayed_max_h = get_value("h", "horizontal") - elseif context == "client_maximize_vertical" then - c._delayed_max_v = get_value("v", "vertical") - end -end - ---- Allow the client to move itself. --- --- This is the default geometry request handler when the context is `ewmh`. --- --- @signalhandler awful.ewmh.client_geometry_requests --- @tparam client c The client --- @tparam string context The context --- @tparam[opt={}] table hints The hints to pass to the handler -function ewmh.client_geometry_requests(c, context, hints) - if context == "ewmh" and hints then - if c.immobilized_horizontal then - hints = gtable.clone(hints) - hints.x = nil - hints.width = nil - end - if c.immobilized_vertical then - hints = gtable.clone(hints) - hints.y = nil - hints.height = nil - end - c:geometry(hints) - end -end - --- The magnifier layout doesn't work with focus follow mouse. -ewmh.add_activate_filter(function(c) - if alayout.get(c.screen) ~= alayout.suit.magnifier - and aclient.focus.filter(c) then - return nil - else - return false - end -end, "mouse_enter") - ---- The default client `request::border` handler. --- --- To replace this handler with your own, use: --- --- client.disconnect_signal("request::border", awful.ewmh.update_border) --- --- The default implementation chooses from dozens beautiful theme variables --- depending if the client is tiled, floating, maximized and then from its state --- (urgent, new, active, normal) --- --- @signalhandler awful.ewmh.update_border --- @usebeautiful beautiful.border_color_active --- @usebeautiful beautiful.border_color_normal --- @usebeautiful beautiful.border_color_new --- @usebeautiful beautiful.border_color_urgent --- @usebeautiful beautiful.border_color_floating --- @usebeautiful beautiful.border_color_floating_active --- @usebeautiful beautiful.border_color_floating_normal --- @usebeautiful beautiful.border_color_floating_new --- @usebeautiful beautiful.border_color_floating_urgent --- @usebeautiful beautiful.border_color_maximized --- @usebeautiful beautiful.border_color_maximized_active --- @usebeautiful beautiful.border_color_maximized_normal --- @usebeautiful beautiful.border_color_maximized_new --- @usebeautiful beautiful.border_color_maximized_urgent --- @usebeautiful beautiful.border_color_fullscreen --- @usebeautiful beautiful.border_color_fullscreen_active --- @usebeautiful beautiful.border_color_fullscreen_normal --- @usebeautiful beautiful.border_color_fullscreen_new --- @usebeautiful beautiful.border_color_fullscreen_urgent --- @usebeautiful beautiful.border_width_active --- @usebeautiful beautiful.border_width_normal --- @usebeautiful beautiful.border_width_new --- @usebeautiful beautiful.border_width_urgent --- @usebeautiful beautiful.border_width_floating --- @usebeautiful beautiful.border_width_floating_active --- @usebeautiful beautiful.border_width_floating_normal --- @usebeautiful beautiful.border_width_floating_new --- @usebeautiful beautiful.border_width_floating_urgent --- @usebeautiful beautiful.border_width_maximized --- @usebeautiful beautiful.border_width_maximized_active --- @usebeautiful beautiful.border_width_maximized_normal --- @usebeautiful beautiful.border_width_maximized_new --- @usebeautiful beautiful.border_width_maximized_urgent --- @usebeautiful beautiful.border_width_fullscreen --- @usebeautiful beautiful.border_width_fullscreen_active --- @usebeautiful beautiful.border_width_fullscreen_normal --- @usebeautiful beautiful.border_width_fullscreen_new --- @usebeautiful beautiful.border_width_fullscreen_urgent --- @usebeautiful beautiful.opacity_floating --- @usebeautiful beautiful.opacity_floating_active --- @usebeautiful beautiful.opacity_floating_normal --- @usebeautiful beautiful.opacity_floating_new --- @usebeautiful beautiful.opacity_floating_urgent --- @usebeautiful beautiful.opacity_maximized --- @usebeautiful beautiful.opacity_maximized_active --- @usebeautiful beautiful.opacity_maximized_normal --- @usebeautiful beautiful.opacity_maximized_new --- @usebeautiful beautiful.opacity_maximized_urgent --- @usebeautiful beautiful.opacity_fullscreen --- @usebeautiful beautiful.opacity_fullscreen_active --- @usebeautiful beautiful.opacity_fullscreen_normal --- @usebeautiful beautiful.opacity_fullscreen_new --- @usebeautiful beautiful.opacity_fullscreen_urgent --- @usebeautiful beautiful.opacity_active --- @usebeautiful beautiful.opacity_normal --- @usebeautiful beautiful.opacity_new --- @usebeautiful beautiful.opacity_urgent - -function ewmh.update_border(c, context) - local suffix, fallback = "", "" - - -- Add the sub-namespace. - if c.fullscreen then - suffix, fallback = "_fullscreen", "_fullscreen" - elseif c.maximized then - suffix, fallback = "_maximized", "_maximized" - elseif c.floating then - suffix, fallback = "_floating", "_floating" - end - - -- Add the state suffix. - if c.urgent then - suffix = suffix .. "_urgent" - elseif c.active then - suffix = suffix .. "_active" - elseif context == "added" then - suffix = suffix .. "_new" - else - suffix = suffix .. "_normal" - end - - if not c._private._user_border_width then - c._border_width = beautiful["border_width"..suffix] - or beautiful["border_width"..fallback] - or beautiful.border_width - end - - if not c._private._user_border_color then - -- First, check marked clients. This is a concept that should probably - -- never have been added to the core. The documentation claims it works, - -- even if it has been broken for 90% of AwesomeWM releases ever since - -- it was added. - if c.marked and beautiful.border_marked then - c._border_color = beautiful.border_marked - return - end - - local tv = beautiful["border_color"..suffix] - - if fallback ~= "" and not tv then - tv = beautiful["border_color"..fallback] - end - - -- The old theme variable did not have "color" in its name. - if (not tv) and beautiful.border_normal and (not c.active) then - gdebug.deprecate( - "Use `beautiful.border_color_normal` instead of `beautiful.border_normal`", - {deprecated_in=5} - ) - tv = beautiful.border_normal - elseif (not tv) and beautiful.border_focus then - gdebug.deprecate( - "Use `beautiful.border_color_active` instead of `beautiful.border_focus`", - {deprecated_in=5} - ) - tv = beautiful.border_focus - end - - if not tv then - tv = beautiful.border_color - end - - if tv then - c._border_color = tv - end - end - - if not c._private._user_opacity then - local tv = beautiful["opacity"..suffix] - - if fallback ~= "" and not tv then - tv = beautiful["opacity"..fallback] - end - - if tv then - c._opacity = tv - end - 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) -client.connect_signal("request::urgent", ewmh.urgent) -client.connect_signal("request::geometry", ewmh.geometry) -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 +-- It diverged over time to the point where it had nothing to do with EWMH. +return gdebug.deprecate_class( + require("awful.permissions"), + "awful.ewmh", + "awful.permissions", + { deprecated_in = 5} +) diff --git a/lib/awful/init.lua b/lib/awful/init.lua index 99259032..cff95db1 100644 --- a/lib/awful/init.lua +++ b/lib/awful/init.lua @@ -8,8 +8,11 @@ require("awful._compat") -return -{ +local deprecated = { + ewmh = true +} + +local ret = { client = require("awful.client"); completion = require("awful.completion"); layout = require("awful.layout"); @@ -30,11 +33,21 @@ return wibox = require("awful.wibox"); startup_notification = require("awful.startup_notification"); tooltip = require("awful.tooltip"); - ewmh = require("awful.ewmh"); + permissions = require("awful.permissions"); titlebar = require("awful.titlebar"); rules = require("awful.rules"); popup = require("awful.popup"); spawn = require("awful.spawn"); } +-- Lazy load deprecated modules to reduce the numbers of loop dependencies. +return setmetatable(ret,{ + __index = function(_, key) + if deprecated[key] then + rawset(ret, key, require("awful."..key)) + end + return rawget(ret, key) + end +}) + -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/awful/permissions/init.lua b/lib/awful/permissions/init.lua new file mode 100644 index 00000000..3b284b3c --- /dev/null +++ b/lib/awful/permissions/init.lua @@ -0,0 +1,724 @@ +--------------------------------------------------------------------------- +--- Implements EWMH requests handling. +-- +-- @author Julien Danjou <julien@danjou.info> +-- @copyright 2009 Julien Danjou +-- @module awful.permissions +--------------------------------------------------------------------------- + +local client = client +local screen = screen +local ipairs = ipairs +local timer = require("gears.timer") +local gtable = require("gears.table") +local aclient = require("awful.client") +local aplace = require("awful.placement") +local asuit = require("awful.layout.suit") +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 permissions = { + generic_activate_filters = {}, + contextual_activate_filters = {}, +} + +--- Honor the screen padding when maximizing. +-- @beautiful beautiful.maximized_honor_padding +-- @tparam[opt=true] boolean maximized_honor_padding + +--- Hide the border on fullscreen clients. +-- @beautiful beautiful.fullscreen_hide_border +-- @tparam[opt=true] boolean fullscreen_hide_border + +--- Hide the border on maximized clients. +-- @beautiful beautiful.maximized_hide_border +-- @tparam[opt=false] boolean maximized_hide_border + +--- The list of all registered generic request::activate (focus stealing) +-- filters. If a filter is added to only one context, it will be in +-- `permissions.contextual_activate_filters`["context_name"]. +-- @table[opt={}] generic_activate_filters +-- @see permissions.activate +-- @see permissions.add_activate_filter +-- @see permissions.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 +-- `permissions.generic_activate_filters`. +-- @table[opt={}] contextual_activate_filters +-- @see permissions.activate +-- @see permissions.add_activate_filter +-- @see permissions.remove_activate_filter + +--- Update a client's settings when its geometry changes, skipping signals +-- resulting from calls within. +local repair_geometry_lock = false + +local function repair_geometry(window) + if repair_geometry_lock then return end + repair_geometry_lock = true + + -- Re-apply the geometry locking properties to what they should be. + for _, prop in ipairs { + "fullscreen", "maximized", "maximized_vertical", "maximized_horizontal" + } do + if window[prop] then + window:emit_signal("request::geometry", prop, { + store_geometry = false + }) + break + end + end + + 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. +-- +-- It is the default signal handler for `request::activate` on a `client`. +-- +-- @signalhandler awful.permissions.activate +-- @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? +-- @tparam[opt=false] boolean hints.switch_to_tag should the client's first tag +-- be selected if none of the client's tags are selected? +-- @tparam[opt=false] boolean hints.switch_to_tags Select all tags associated +-- with the client. +function permissions.activate(c, context, hints) -- luacheck: no unused args + hints = hints or {} + + if c.focusable == false and not hints.force then + if hints.raise then + c:raise() + end + + return + end + + local found, ret = false + + -- Execute the filters until something handle the request + for _, tab in ipairs { + permissions.contextual_activate_filters[context] or {}, + permissions.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 + + -- Minimized clients can be requested to have focus by, for example, 3rd + -- party toolbars and they might not try to unminimize it first. + if ret ~= false and hints.raise then + c.minimized = false + end + + if ret ~= false and c:isvisible() then + client.focus = c + elseif ret == false and not hints.force then + return + end + + if hints.raise then + c:raise() + if not awesome.startup and not c:isvisible() then + c.urgent = true + end + end + + -- The rules use `switchtotag`. For consistency and code re-use, support it, + -- but keep undocumented. --TODO v5 remove switchtotag + if hints.switchtotag or hints.switch_to_tag or hints.switch_to_tags then + atag.viewmore(c:tags(), c.screen, (not hints.switch_to_tags) and 0 or nil) + 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. If the callback +-- returns `false`, the activation request is cancelled unless the `force` hint is +-- set. 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.permissions.add_activate_filter(function(c) +-- if c.class == "Firefox" then return false end +-- end, "permissions") +-- +-- @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 +-- @staticfct awful.permissions.add_activate_filter +function permissions.add_activate_filter(f, context) + if not context then + table.insert(permissions.generic_activate_filters, f) + else + permissions.contextual_activate_filters[context] = + permissions.contextual_activate_filters[context] or {} + + table.insert(permissions.contextual_activate_filters[context], f) + end +end + +--- Remove an activate (focus stealing) filter function. +-- This is an helper to avoid dealing with `permissions.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 +-- @staticfct awful.permissions.remove_activate_filter +function permissions.remove_activate_filter(f, context) + local tab = context and (permissions.contextual_activate_filters[context] or {}) + or permissions.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. + permissions.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_ +-- always return the same content as c:tags(). +local function get_valid_tags(c, s) + local tags, new_tags = c:tags(), {} + + for _, t in ipairs(tags) do + if s == t.screen then + table.insert(new_tags, t) + end + end + + return new_tags +end + +--- Tag a window with its requested tag. +-- +-- It is the default signal handler for `request::tag` on a `client`. +-- +-- @signalhandler awful.permissions.tag +-- @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 + -- There is nothing to do + if not t and #get_valid_tags(c, c.screen) > 0 then return end + + if not t then + if c.transient_for and not (hints and hints.reason == "screen") then + c.screen = c.transient_for.screen + if not c.sticky then + local tags = c.transient_for:tags() + c:tags(#tags > 0 and tags or c.transient_for.screen.selected_tags) + end + else + c:to_selected_tags() + end + elseif type(t) == "boolean" and t then + c.sticky = true + else + c.screen = t.screen + c:tags({ t }) + end +end + +--- Handle client urgent request +-- @signalhandler awful.permissions.urgent +-- @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 + c.urgent = urgent + end +end + +-- Map the state to the action name +local context_mapper = { + maximized_vertical = "maximize_vertically", + maximized_horizontal = "maximize_horizontally", + maximized = "maximize", + fullscreen = "maximize" +} + +--- Move and resize the client. +-- +-- This is the default geometry request handler. +-- +-- @signalhandler awful.permissions.geometry +-- @tparam client c The client +-- @tparam string context The context +-- @tparam[opt={}] table hints The hints to pass to the handler +function permissions.geometry(c, context, hints) + local layout = c.screen.selected_tag and c.screen.selected_tag.layout or nil + + -- Setting the geometry will not work unless the client is floating. + if (not c.floating) and (not layout == asuit.floating) then + return + end + + context = context or "" + + local original_context = context + + -- Now, map it to something useful + context = context_mapper[context] or context + + local props = gtable.clone(hints or {}, false) + props.store_geometry = props.store_geometry==nil and true or props.store_geometry + + -- If it is a known placement function, then apply it, otherwise let + -- other potential handler resize the client (like in-layout resize or + -- floating client resize) + if aplace[context] then + + -- Check if it corresponds to a boolean property. + local state = c[original_context] + + -- If the property is boolean and it corresponds to the undo operation, + -- restore the stored geometry. + if state == false then + local original = repair_geometry_lock + repair_geometry_lock = true + aplace.restore(c, {context=context}) + repair_geometry_lock = original + return + end + + local honor_default = original_context ~= "fullscreen" + + if props.honor_workarea == nil then + props.honor_workarea = honor_default + end + + if props.honor_padding == nil and props.honor_workarea and context:match("maximize") then + props.honor_padding = beautiful.maximized_honor_padding ~= false + end + + if (original_context == "fullscreen" and beautiful.fullscreen_hide_border ~= false) or + (original_context == "maximized" and beautiful.maximized_hide_border == true) then + props.ignore_border_width = true + props.zap_border_width = true + end + + local original = repair_geometry_lock + repair_geometry_lock = true + aplace[context](c, props) + repair_geometry_lock = original + end +end + +--- Merge the 2 requests sent by clients wanting to be maximized. +-- +-- The X clients set 2 flags (atoms) when they want to be maximized. This caused +-- 2 request::geometry to be sent. This code gives some time for them to arrive +-- and send a new `request::geometry` (through the property change) with the +-- combined state. +-- +-- @signalhandler awful.permissions.merge_maximization +-- @tparam client c The client +-- @tparam string context The context +-- @tparam[opt={}] table hints The hints to pass to the handler +function permissions.merge_maximization(c, context, hints) + if context ~= "client_maximize_horizontal" and context ~= "client_maximize_vertical" then + return + end + + if not c._delay_maximization then + c._delay_maximization = function() + -- Computes the actual X11 atoms before/after + local before_max_h = c.maximized or c.maximized_horizontal + local before_max_v = c.maximized or c.maximized_vertical + local after_max_h, after_max_v + if c._delayed_max_h ~= nil then + after_max_h = c._delayed_max_h + else + after_max_h = before_max_h + end + if c._delayed_max_v ~= nil then + after_max_v = c._delayed_max_v + else + after_max_v = before_max_v + end + -- Interprets the client's intention based on the client's view + if after_max_h and after_max_v then + c.maximized = true + elseif before_max_h and before_max_v then + -- At this point, c.maximized must be true, and the client is + -- trying to unmaximize the window, and potentially partial + -- maximized the window + c.maximized = false + if after_max_h ~= after_max_v then + c.maximized_horizontal = after_max_h + c.maximized_vertical = after_max_v + end + else + -- At this point, c.maximized must be false, and the client is + -- not trying to fully maximize the window + c.maximized_horizontal = after_max_h + c.maximized_vertical = after_max_v + end + end + + timer { + timeout = 1/60, + autostart = true, + single_shot = true, + callback = function() + if not c.valid then return end + + c._delay_maximization(c) + c._delay_maximization = nil + c._delayed_max_h = nil + c._delayed_max_v = nil + end + } + end + + local function get_value(suffix, long_suffix) + if hints.toggle and c["_delayed_max_"..suffix] ~= nil then + return not c["_delayed_max_"..suffix] + elseif hints.toggle then + return not (c["maximized"] or c["maximized_"..long_suffix]) + else + return hints.status + end + end + + if context == "client_maximize_horizontal" then + c._delayed_max_h = get_value("h", "horizontal") + elseif context == "client_maximize_vertical" then + c._delayed_max_v = get_value("v", "vertical") + end +end + +--- Allow the client to move itself. +-- +-- This is the default geometry request handler when the context is `permissions`. +-- +-- @signalhandler awful.permissions.client_geometry_requests +-- @tparam client c The client +-- @tparam string context The context +-- @tparam[opt={}] table hints The hints to pass to the handler +function permissions.client_geometry_requests(c, context, hints) + if context == "ewmh" and hints then + if c.immobilized_horizontal then + hints = gtable.clone(hints) + hints.x = nil + hints.width = nil + end + if c.immobilized_vertical then + hints = gtable.clone(hints) + hints.y = nil + hints.height = nil + end + c:geometry(hints) + end +end + +-- The magnifier layout doesn't work with focus follow mouse. +permissions.add_activate_filter(function(c) + if alayout.get(c.screen) ~= alayout.suit.magnifier + and aclient.focus.filter(c) then + return nil + else + return false + end +end, "mouse_enter") + +--- The default client `request::border` handler. +-- +-- To replace this handler with your own, use: +-- +-- client.disconnect_signal("request::border", awful.ewmh.update_border) +-- +-- The default implementation chooses from dozens beautiful theme variables +-- depending if the client is tiled, floating, maximized and then from its state +-- (urgent, new, active, normal) +-- +-- @signalhandler awful.ewmh.update_border +-- @usebeautiful beautiful.border_color_active +-- @usebeautiful beautiful.border_color_normal +-- @usebeautiful beautiful.border_color_new +-- @usebeautiful beautiful.border_color_urgent +-- @usebeautiful beautiful.border_color_floating +-- @usebeautiful beautiful.border_color_floating_active +-- @usebeautiful beautiful.border_color_floating_normal +-- @usebeautiful beautiful.border_color_floating_new +-- @usebeautiful beautiful.border_color_floating_urgent +-- @usebeautiful beautiful.border_color_maximized +-- @usebeautiful beautiful.border_color_maximized_active +-- @usebeautiful beautiful.border_color_maximized_normal +-- @usebeautiful beautiful.border_color_maximized_new +-- @usebeautiful beautiful.border_color_maximized_urgent +-- @usebeautiful beautiful.border_color_fullscreen +-- @usebeautiful beautiful.border_color_fullscreen_active +-- @usebeautiful beautiful.border_color_fullscreen_normal +-- @usebeautiful beautiful.border_color_fullscreen_new +-- @usebeautiful beautiful.border_color_fullscreen_urgent +-- @usebeautiful beautiful.border_width_active +-- @usebeautiful beautiful.border_width_normal +-- @usebeautiful beautiful.border_width_new +-- @usebeautiful beautiful.border_width_urgent +-- @usebeautiful beautiful.border_width_floating +-- @usebeautiful beautiful.border_width_floating_active +-- @usebeautiful beautiful.border_width_floating_normal +-- @usebeautiful beautiful.border_width_floating_new +-- @usebeautiful beautiful.border_width_floating_urgent +-- @usebeautiful beautiful.border_width_maximized +-- @usebeautiful beautiful.border_width_maximized_active +-- @usebeautiful beautiful.border_width_maximized_normal +-- @usebeautiful beautiful.border_width_maximized_new +-- @usebeautiful beautiful.border_width_maximized_urgent +-- @usebeautiful beautiful.border_width_fullscreen +-- @usebeautiful beautiful.border_width_fullscreen_active +-- @usebeautiful beautiful.border_width_fullscreen_normal +-- @usebeautiful beautiful.border_width_fullscreen_new +-- @usebeautiful beautiful.border_width_fullscreen_urgent +-- @usebeautiful beautiful.opacity_floating +-- @usebeautiful beautiful.opacity_floating_active +-- @usebeautiful beautiful.opacity_floating_normal +-- @usebeautiful beautiful.opacity_floating_new +-- @usebeautiful beautiful.opacity_floating_urgent +-- @usebeautiful beautiful.opacity_maximized +-- @usebeautiful beautiful.opacity_maximized_active +-- @usebeautiful beautiful.opacity_maximized_normal +-- @usebeautiful beautiful.opacity_maximized_new +-- @usebeautiful beautiful.opacity_maximized_urgent +-- @usebeautiful beautiful.opacity_fullscreen +-- @usebeautiful beautiful.opacity_fullscreen_active +-- @usebeautiful beautiful.opacity_fullscreen_normal +-- @usebeautiful beautiful.opacity_fullscreen_new +-- @usebeautiful beautiful.opacity_fullscreen_urgent +-- @usebeautiful beautiful.opacity_active +-- @usebeautiful beautiful.opacity_normal +-- @usebeautiful beautiful.opacity_new +-- @usebeautiful beautiful.opacity_urgent + +function permissions.update_border(c, context) + if not pcommon.check(c, "client", "border", context) then return end + + local suffix, fallback = "", "" + + -- Add the sub-namespace. + if c.fullscreen then + suffix, fallback = "_fullscreen", "_fullscreen" + elseif c.maximized then + suffix, fallback = "_maximized", "_maximized" + elseif c.floating then + suffix, fallback = "_floating", "_floating" + end + + -- Add the state suffix. + if c.urgent then + suffix = suffix .. "_urgent" + elseif c.active then + suffix = suffix .. "_active" + elseif context == "added" then + suffix = suffix .. "_new" + else + suffix = suffix .. "_normal" + end + + if not c._private._user_border_width then + c._border_width = beautiful["border_width"..suffix] + or beautiful["border_width"..fallback] + or beautiful.border_width + end + + if not c._private._user_border_color then + -- First, check marked clients. This is a concept that should probably + -- never have been added to the core. The documentation claims it works, + -- even if it has been broken for 90% of AwesomeWM releases ever since + -- it was added. + if c.marked and beautiful.border_marked then + c._border_color = beautiful.border_marked + return + end + + local tv = beautiful["border_color"..suffix] + + if fallback ~= "" and not tv then + tv = beautiful["border_color"..fallback] + end + + -- The old theme variable did not have "color" in its name. + if (not tv) and beautiful.border_normal and (not c.active) then + gdebug.deprecate( + "Use `beautiful.border_color_normal` instead of `beautiful.border_normal`", + {deprecated_in=5} + ) + tv = beautiful.border_normal + elseif (not tv) and beautiful.border_focus then + gdebug.deprecate( + "Use `beautiful.border_color_active` instead of `beautiful.border_focus`", + {deprecated_in=5} + ) + tv = beautiful.border_focus + end + + if not tv then + tv = beautiful.border_color + end + + if tv then + c._border_color = tv + end + end + + if not c._private._user_opacity then + local tv = beautiful["opacity"..suffix] + + if fallback ~= "" and not tv then + tv = beautiful["opacity"..fallback] + end + + if tv then + c._opacity = tv + end + 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.permissions.autoactivate +function permissions.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" , permissions.autoactivate) +client.connect_signal("request::border" , permissions.update_border) +client.connect_signal("request::activate" , permissions.activate) +client.connect_signal("request::tag" , permissions.tag) +client.connect_signal("request::urgent" , permissions.urgent) +client.connect_signal("request::geometry" , permissions.geometry) +client.connect_signal("request::geometry" , permissions.merge_maximization) +client.connect_signal("request::geometry" , permissions.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 permissions + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/spec/awful/ewmh_spec.lua b/spec/awful/permissions_spec.lua similarity index 71% rename from spec/awful/ewmh_spec.lua rename to spec/awful/permissions_spec.lua index 67c0328f..fb58f3f9 100644 --- a/spec/awful/ewmh_spec.lua +++ b/spec/awful/permissions_spec.lua @@ -1,4 +1,4 @@ -describe("awful.ewmh.client_geometry_requests", function() +describe("awful.permissions.client_geometry_requests", function() package.loaded["awful.client"] = {} package.loaded["awful.layout"] = {} package.loaded["awful.screen"] = {} @@ -15,35 +15,35 @@ describe("awful.ewmh.client_geometry_requests", function() connect_signal = function() end, } - local ewmh = require("awful.ewmh") + local permissions = require("awful.permissions") it("removes x/y/width/height when immobilized", function() local c = {} local s = stub.new(c, "geometry") - ewmh.client_geometry_requests(c, "ewmh", {}) + permissions.client_geometry_requests(c, "ewmh", {}) assert.stub(s).was_called_with(c, {}) - ewmh.client_geometry_requests(c, "ewmh", {x=0, width=400}) + permissions.client_geometry_requests(c, "ewmh", {x=0, width=400}) assert.stub(s).was_called_with(c, {x=0, width=400}) c.immobilized_horizontal = true c.immobilized_vertical = false - ewmh.client_geometry_requests(c, "ewmh", {x=0, width=400}) + permissions.client_geometry_requests(c, "ewmh", {x=0, width=400}) assert.stub(s).was_called_with(c, {}) - ewmh.client_geometry_requests(c, "ewmh", {x=0, width=400, y=0}) + permissions.client_geometry_requests(c, "ewmh", {x=0, width=400, y=0}) assert.stub(s).was_called_with(c, {y=0}) c.immobilized_horizontal = true c.immobilized_vertical = true - ewmh.client_geometry_requests(c, "ewmh", {x=0, width=400, y=0}) + permissions.client_geometry_requests(c, "ewmh", {x=0, width=400, y=0}) assert.stub(s).was_called_with(c, {}) c.immobilized_horizontal = false c.immobilized_vertical = true local hints = {x=0, width=400, y=0} - ewmh.client_geometry_requests(c, "ewmh", hints) + permissions.client_geometry_requests(c, "ewmh", hints) assert.stub(s).was_called_with(c, {x=0, width=400}) -- Table passed as argument should not have been modified. assert.is.same(hints, {x=0, width=400, y=0}) diff --git a/tests/examples/sequences/client/fullscreen.lua b/tests/examples/sequences/client/fullscreen.lua index 3ac6744b..c7eea1d1 100644 --- a/tests/examples/sequences/client/fullscreen.lua +++ b/tests/examples/sequences/client/fullscreen.lua @@ -2,7 +2,7 @@ local module = ... --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 +require("awful.permissions") --DOC_HIDE screen[1]:fake_resize(0, 0, 1024/2, 768/2) --DOC_HIDE screen.fake_add(1034/2, 0, 1024/2, 768/2).outputs = {["eVGA1"] = {mm_height=60/2, mm_width=80/2 }} --DOC_HIDE screen.fake_add(2074/2, 0, 1024/2, 768/2).outputs = {["DVI1" ] = {mm_height=60/2, mm_width=80/2 }} --DOC_HIDE diff --git a/tests/examples/sequences/client/maximized.lua b/tests/examples/sequences/client/maximized.lua index c6370605..7a778f2b 100644 --- a/tests/examples/sequences/client/maximized.lua +++ b/tests/examples/sequences/client/maximized.lua @@ -2,7 +2,7 @@ local module = ... --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 +require("awful.permissions") --DOC_HIDE screen[1]:fake_resize(0, 0, 1024/2, 768/2) --DOC_HIDE screen.fake_add(1034/2, 0, 1024/2, 768/2).outputs = {["eVGA1"] = {mm_height=60/2, mm_width=80/2 }} --DOC_HIDE screen.fake_add(2074/2, 0, 1024/2, 768/2).outputs = {["DVI1" ] = {mm_height=60/2, mm_width=80/2 }} --DOC_HIDE diff --git a/tests/examples/sequences/client/maximized_horizontal.lua b/tests/examples/sequences/client/maximized_horizontal.lua index fe642fab..a655de52 100644 --- a/tests/examples/sequences/client/maximized_horizontal.lua +++ b/tests/examples/sequences/client/maximized_horizontal.lua @@ -2,7 +2,7 @@ local module = ... --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 +require("awful.permissions") --DOC_HIDE screen[1]:fake_resize(0, 0, 1024/2, 768/2) --DOC_HIDE screen.fake_add(1034/2, 0, 1024/2, 768/2).outputs = {["eVGA1"] = {mm_height=60/2, mm_width=80/2 }} --DOC_HIDE screen.fake_add(2074/2, 0, 1024/2, 768/2).outputs = {["DVI1" ] = {mm_height=60/2, mm_width=80/2 }} --DOC_HIDE diff --git a/tests/examples/sequences/client/maximized_vertical.lua b/tests/examples/sequences/client/maximized_vertical.lua index 8573eaa2..8a15a6c0 100644 --- a/tests/examples/sequences/client/maximized_vertical.lua +++ b/tests/examples/sequences/client/maximized_vertical.lua @@ -2,7 +2,7 @@ local module = ... --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 +require("awful.permissions") --DOC_HIDE screen[1]:fake_resize(0, 0, 1024/2, 768/2) --DOC_HIDE screen.fake_add(1034/2, 0, 1024/2, 768/2).outputs = {["eVGA1"] = {mm_height=60/2, mm_width=80/2 }} --DOC_HIDE screen.fake_add(2074/2, 0, 1024/2, 768/2).outputs = {["DVI1" ] = {mm_height=60/2, mm_width=80/2 }} --DOC_HIDE diff --git a/tests/test-awful-client.lua b/tests/test-awful-client.lua index 8f3db43d..e69a7ca0 100644 --- a/tests/test-awful-client.lua +++ b/tests/test-awful-client.lua @@ -145,9 +145,9 @@ table.insert(steps, function() -- This should still be the case assert(c2.active) - original_count = #awful.ewmh.generic_activate_filters + original_count = #awful.permissions.generic_activate_filters - awful.ewmh.add_activate_filter(function(c) + awful.permissions.add_activate_filter(function(c) if c == c1 then return false end end) @@ -161,13 +161,13 @@ table.insert(steps, function() assert(c2.active) -- Test the remove function - awful.ewmh.remove_activate_filter(function() end) + awful.permissions.remove_activate_filter(function() end) - awful.ewmh.add_activate_filter(awful.ewmh.generic_activate_filters[1]) + awful.permissions.add_activate_filter(awful.permissions.generic_activate_filters[1]) - awful.ewmh.remove_activate_filter(awful.ewmh.generic_activate_filters[1]) + awful.permissions.remove_activate_filter(awful.permissions.generic_activate_filters[1]) - assert(original_count == #awful.ewmh.generic_activate_filters) + assert(original_count == #awful.permissions.generic_activate_filters) c1:emit_signal("request::activate", "i_said_so") diff --git a/tests/test-maximize.lua b/tests/test-maximize.lua index f3f249e8..8f28b25d 100644 --- a/tests/test-maximize.lua +++ b/tests/test-maximize.lua @@ -358,8 +358,8 @@ gears.table.merge(steps, { -- Remove the default handler and replace it with a testing one. -- **WARNING**: add tests **BEFORE** this function if you want them -- to be relevant. - client.disconnect_signal("request::geometry", awful.ewmh.geometry) - client.disconnect_signal("request::geometry", awful.ewmh.merge_maximization) + client.disconnect_signal("request::geometry", awful.permissions.geometry) + client.disconnect_signal("request::geometry", awful.permissions.merge_maximization) client.connect_signal("request::geometry", geometry_handler) test_client(nil,nil,nil,nil,nil,{maximize_after=true})