Merge pull request #2941 from Elv13/api_stanard_p3_0

API standardization, part 3
This commit is contained in:
Emmanuel Lepage Vallée 2020-01-11 16:36:27 -08:00 committed by GitHub
commit e0bb29962d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
68 changed files with 2472 additions and 902 deletions

View File

@ -49,27 +49,6 @@ editor_cmd = terminal .. " -e " .. editor
-- I suggest you to remap Mod4 to another key using xmodmap or other tools.
-- However, you can use another modifier like Mod1, but it may interact with others.
modkey = "Mod4"
-- @DOC_LAYOUT@
-- Table of layouts to cover with awful.layout.inc, order matters.
awful.layout.layouts = {
awful.layout.suit.floating,
awful.layout.suit.tile,
awful.layout.suit.tile.left,
awful.layout.suit.tile.bottom,
awful.layout.suit.tile.top,
awful.layout.suit.fair,
awful.layout.suit.fair.horizontal,
awful.layout.suit.spiral,
awful.layout.suit.spiral.dwindle,
awful.layout.suit.max,
awful.layout.suit.max.fullscreen,
awful.layout.suit.magnifier,
awful.layout.suit.corner.nw,
-- awful.layout.suit.corner.ne,
-- awful.layout.suit.corner.sw,
-- awful.layout.suit.corner.se,
}
-- }}}
-- {{{ Menu
@ -95,10 +74,33 @@ mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
menubar.utils.terminal = terminal -- Set the terminal for applications that require it
-- }}}
-- {{{ Tag
-- @DOC_LAYOUT@
-- Table of layouts to cover with awful.layout.inc, order matters.
tag.connect_signal("request::default_layouts", function()
awful.layout.append_default_layouts({
awful.layout.suit.floating,
awful.layout.suit.tile,
awful.layout.suit.tile.left,
awful.layout.suit.tile.bottom,
awful.layout.suit.tile.top,
awful.layout.suit.fair,
awful.layout.suit.fair.horizontal,
awful.layout.suit.spiral,
awful.layout.suit.spiral.dwindle,
awful.layout.suit.max,
awful.layout.suit.max.fullscreen,
awful.layout.suit.magnifier,
awful.layout.suit.corner.nw,
})
end)
-- }}}
-- {{{ Wibar
-- Keyboard map indicator and switcher
mykeyboardlayout = awful.widget.keyboardlayout()
-- {{{ Wibar
-- Create a textclock widget
mytextclock = wibox.widget.textclock()
@ -157,21 +159,14 @@ screen.connect_signal("request::desktop_decoration", function(s)
}
}
-- @TASKLIST_BUTTON@
-- Create a tasklist widget
s.mytasklist = awful.widget.tasklist {
screen = s,
filter = awful.widget.tasklist.filter.currenttags,
buttons = {
awful.button({ }, 1, function (c)
if c == client.focus then
c.minimized = true
else
c:emit_signal(
"request::activate",
"tasklist",
{raise = true}
)
end
c:activate { context = "tasklist", action = "toggle_minimization" }
end),
awful.button({ }, 3, function() awful.menu.client_list { theme = { width = 250 } } end),
awful.button({ }, 4, function() awful.client.focus.byidx( 1) end),
@ -286,9 +281,7 @@ awful.keyboard.append_global_keybindings({
local c = awful.client.restore()
-- Focus restored client
if c then
c:emit_signal(
"request::activate", "key.unminimize", {raise = true}
)
c:activate { raise = true, context = "key.unminimize" }
end
end,
{description = "restore minimized", group = "client"}),
@ -383,15 +376,13 @@ awful.keyboard.append_global_keybindings({
client.connect_signal("request::default_mousebindings", function()
awful.mouse.append_client_mousebindings({
awful.button({ }, 1, function (c)
c:emit_signal("request::activate", "mouse_click", {raise = true})
c:activate { context = "mouse_click" }
end),
awful.button({ modkey }, 1, function (c)
c:emit_signal("request::activate", "mouse_click", {raise = true})
awful.mouse.client.move(c)
c:activate { context = "mouse_click", action = "mouse_move" }
end),
awful.button({ modkey }, 3, function (c)
c:emit_signal("request::activate", "mouse_click", {raise = true})
awful.mouse.client.resize(c)
c:activate { context = "mouse_click", action = "mouse_resize"}
end),
})
end)
@ -446,15 +437,13 @@ end)
-- }}}
-- {{{ Rules
-- Rules to apply to new clients (through the "manage" signal).
-- Rules to apply to new clients.
-- @DOC_RULES@
awful.rules.rules = {
-- @DOC_GLOBAL_RULE@
-- All clients will match this rule.
{ rule = { },
properties = { border_width = beautiful.border_width,
border_color = beautiful.border_normal,
focus = awful.client.focus.filter,
properties = { focus = awful.client.focus.filter,
raise = true,
screen = awful.screen.preferred,
placement = awful.placement.no_overlap+awful.placement.no_offscreen
@ -506,34 +495,17 @@ awful.rules.rules = {
}
-- }}}
-- {{{ Signals
-- Signal function to execute when a new client appears.
-- @DOC_MANAGE_HOOK@
client.connect_signal("manage", function (c)
-- Set the windows at the slave,
-- i.e. put it at the end of others instead of setting it master.
-- if not awesome.startup then awful.client.setslave(c) end
if awesome.startup
and not c.size_hints.user_position
and not c.size_hints.program_position then
-- Prevent clients from being unreachable after screen count changes.
awful.placement.no_offscreen(c)
end
end)
-- {{{ Titlebars
-- @DOC_TITLEBARS@
-- Add a titlebar if titlebars_enabled is set to true in the rules.
client.connect_signal("request::titlebars", function(c)
-- buttons for the titlebar
local buttons = {
awful.button({ }, 1, function()
c:emit_signal("request::activate", "titlebar", {raise = true})
awful.mouse.client.move(c)
c:activate { context = "titlebar", action = "mouse_move" }
end),
awful.button({ }, 3, function()
c:emit_signal("request::activate", "titlebar", {raise = true})
awful.mouse.client.resize(c)
c:activate { context = "titlebar", action = "mouse_resize"}
end),
}
@ -562,13 +534,4 @@ client.connect_signal("request::titlebars", function(c)
layout = wibox.layout.align.horizontal
}
end)
-- Enable sloppy focus, so that focus follows mouse.
client.connect_signal("mouse::enter", function(c)
c:emit_signal("request::activate", "mouse_enter", {raise = false})
end)
-- @DOC_BORDER@
client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
-- }}}

View File

@ -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,

View File

@ -208,12 +208,6 @@ sections.DOC_DIALOG_RULE = [[
 
]]
sections.DOC_MANAGE_HOOK = [[
 
]]
sections.DOC_TITLEBARS = [[
 
]]
@ -227,11 +221,6 @@ sections.DOC_CSD_TITLEBARS = [[
See `client.requests_no_titlebar` for more details.
]]
sections.DOC_BORDER = [[
 
]]
-- Ask ldoc to generate links
local function add_links(line)

View File

@ -62,6 +62,14 @@ This document was last updated at commit v4.3-197-g9085ed631.
objects. If you used these low level APIs to add keys and buttons dynamically,
please migrate your code to the corresponding `:append_` and `:remove_`
client methods.
* `beautiful.border_width` and `beautiful.border_color` are now honored even
when the part related to borders is removed from `rc.lua`. Set them
appropriately in your theme or disconnect the default `request::border`
handler.
* The order by which the client rules compute the geometry have changed
slightly. The border is now applied before the titlebar offset. This should
not affect most users unless you had mitigated the bug it fixes by adding
the titlebar offset in your rules.
<a name="v43"></a>
# Awesome window manager framework version 4.3 changes

View File

@ -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

View File

@ -0,0 +1,492 @@
*/
/**
* The fallback border color when the client is floating.
*
* @beautiful beautiful.border_color_floating
* @param color
* @see request::border
* @see beautiful.border_color_floating_active
* @see beautiful.border_color_floating_normal
* @see beautiful.border_color_floating_urgent
* @see beautiful.border_color_floating_new
*/
/**
* The fallback border color when the client is mazimized.
*
* @beautiful beautiful.border_color_mazimized
* @param color
* @see request::border
* @see beautiful.border_color_maximized_active
* @see beautiful.border_color_maximized_normal
* @see beautiful.border_color_maximized_urgent
* @see beautiful.border_color_maximized_new
*/
/**
* The border color when the client is active.
*
* @beautiful beautiful.border_color_active
* @param color
* @see request::border
*/
/**
* The border color when the client is not active.
*
* @beautiful beautiful.border_color_normal
* @param color
* @see request::border
*/
/**
* The border color when the client has the urgent property set.
*
* @beautiful beautiful.border_color_urgent
* @param color
* @see request::border
*/
/**
* The border color when the client is not active and new.
*
* @beautiful beautiful.border_color_new
* @param color
* @see request::border
*/
/**
* The border color when the (floating) client is active.
*
* @beautiful beautiful.border_color_floating_active
* @param color
* @see request::border
*/
/**
* The border color when the (floating) client is not active.
*
* @beautiful beautiful.border_color_floating_normal
* @param color
* @see request::border
*/
/**
* The border color when the (floating) client has the urgent property set.
*
* @beautiful beautiful.border_color_floating_urgent
* @param color
* @see request::border
*/
/**
* The border color when the (floating) client is not active and new.
*
* @beautiful beautiful.border_color_floating_new
* @param color
* @see request::border
*/
/**
* The border color when the (maximized) client is active.
*
* @beautiful beautiful.border_color_maximized_active
* @param color
* @see request::border
*/
/**
* The border color when the (maximized) client is not active.
*
* @beautiful beautiful.border_color_maximized_normal
* @param color
* @see request::border
*/
/**
* The border color when the (maximized) client has the urgent property set.
*
* @beautiful beautiful.border_color_maximized_urgent
* @param color
* @see request::border
*/
/**
* The border color when the (maximized) client is not active and new.
*
* @beautiful beautiful.border_color_maximized_new
* @param color
* @see request::border
*/
/**
* The border color when the (fullscreen) client is active.
*
* @beautiful beautiful.border_color_fullscreen_active
* @param color
* @see request::border
*/
/**
* The border color when the (fullscreen) client is not active.
*
* @beautiful beautiful.border_color_fullscreen_normal
* @param color
* @see request::border
*/
/**
* The border color when the (fullscreen) client has the urgent property set.
*
* @beautiful beautiful.border_color_fullscreen_urgent
* @param color
* @see request::border
*/
/**
* The border color when the (fullscreen) client is not active and new.
*
* @beautiful beautiful.border_color_fullscreen_new
* @param color
* @see request::border
*/
/**
* The fallback border width when nothing else is set.
*
* @beautiful beautiful.border_width
* @param integer
* @see request::border
* @see beautiful.border_width_floating
* @see beautiful.border_width_mazimized
* @see beautiful.border_width_floating_active
* @see beautiful.border_width_floating_normal
* @see beautiful.border_width_floating_urgent
* @see beautiful.border_width_floating_new
* @see beautiful.border_width_maximized_active
* @see beautiful.border_width_maximized_normal
* @see beautiful.border_width_maximized_urgent
* @see beautiful.border_width_maximized_new
*/
/**
* The fallback border width when the client is floating.
*
* @beautiful beautiful.border_width_floating
* @param integer
* @see request::border
* @see beautiful.border_width_floating_active
* @see beautiful.border_width_floating_normal
* @see beautiful.border_width_floating_urgent
* @see beautiful.border_width_floating_new
*/
/**
* The fallback border width when the client is mazimized.
*
* @beautiful beautiful.border_width_mazimized
* @param integer
* @see request::border
* @see beautiful.border_width_maximized_active
* @see beautiful.border_width_maximized_normal
* @see beautiful.border_width_maximized_urgent
* @see beautiful.border_width_maximized_new
*/
/**
* The client border width for the normal clients.
*
* @beautiful beautiful.border_width_normal
* @param integer
* @see request::border
*/
/**
* The client border width for the active client.
*
* @beautiful beautiful.border_width_active
* @param integer
* @see request::border
*/
/**
* The client border width for the urgent clients.
*
* @beautiful beautiful.border_width_urgent
* @param integer
* @see request::border
*/
/**
* The client border width for the new clients.
*
* @beautiful beautiful.border_width_new
* @param integer
* @see request::border
*/
/**
* The client border width for the normal floating clients.
*
* @beautiful beautiful.border_width_floating_normal
* @param integer
* @see request::border
*/
/**
* The client border width for the active floating client.
*
* @beautiful beautiful.border_width_floating_active
* @param integer
* @see request::border
*/
/**
* The client border width for the urgent floating clients.
*
* @beautiful beautiful.border_width_floating_urgent
* @param integer
* @see request::border
*/
/**
* The client border width for the new floating clients.
*
* @beautiful beautiful.border_width_floating_new
* @param integer
* @see request::border
*/
/**
* The client border width for the normal maximized clients.
*
* @beautiful beautiful.border_width_maximized_normal
* @param integer
* @see request::border
*/
/**
* The client border width for the active maximized client.
*
* @beautiful beautiful.border_width_maximized_active
* @param integer
* @see request::border
*/
/**
* The client border width for the urgent maximized clients.
*
* @beautiful beautiful.border_width_maximized_urgent
* @param integer
* @see request::border
*/
/**
* The client border width for the new maximized clients.
*
* @beautiful beautiful.border_width_maximized_new
* @param integer
* @see request::border
*/
/**
* The client border width for the normal fullscreen clients.
*
* @beautiful beautiful.border_width_fullscreen_normal
* @param integer
* @see request::border
*/
/**
* The client border width for the active fullscreen client.
*
* @beautiful beautiful.border_width_fullscreen_active
* @param integer
* @see request::border
*/
/**
* The client border width for the urgent fullscreen clients.
*
* @beautiful beautiful.border_width_fullscreen_urgent
* @param integer
* @see request::border
*/
/**
* The client border width for the new fullscreen clients.
*
* @beautiful beautiful.border_width_fullscreen_new
* @param integer
* @see request::border
*/
/**
* The client opacity for the normal clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_normal
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the active client.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_active
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the urgent clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_urgent
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the new clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_new
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the normal floating clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_floating_normal
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the active floating client.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_floating_active
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the urgent floating clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_floating_urgent
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the new floating clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_floating_new
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the normal maximized clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_maximized_normal
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the active maximized client.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_maximized_active
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the urgent maximized clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_maximized_urgent
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the new maximized clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_maximized_new
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the normal fullscreen clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_fullscreen_normal
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the active fullscreen client.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_fullscreen_active
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the urgent fullscreen clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_fullscreen_urgent
* @param[opt=1] number
* @see request::border
*/
/**
* The client opacity for the new fullscreen clients.
*
* A number between 0 and 1.
*
* @beautiful beautiful.opacity_fullscreen_new
* @param[opt=1] number
* @see request::border
*/
/**
* The marked clients border color.
* Note that only solid colors are supported.
* @beautiful beautiful.border_marked
* @param color
*/
/*

View File

@ -70,6 +70,8 @@ new_type("deprecatedproperty", "Deprecated object properties", false, "Type cons
new_type("method", "Object methods ", false, "Parameters")
-- New type for signals
new_type("signal", "Signals", false, "Arguments")
-- Deprecated signals.
new_type("deprecatedsignal", "Deprecated signals", false, "Arguments")
-- New type for signals connections
new_type("signalhandler", "Request handlers", false, "Arguments")
-- Allow objects to define a set of beautiful properties affecting them
@ -351,6 +353,12 @@ add_custom_tag {
hidden = true
}
-- Define when a signal is only emitted on a class rather than on objects.
add_custom_tag {
name = "classsignal",
hidden = true,
}
-- Specify when this an item was deprecated.
-- @deprecatedin 4.4 Optional message.
add_custom_tag {
@ -394,6 +402,20 @@ add_custom_tag {
},
}
add_custom_tag {
name = "request",
title = "Requested actions or permissions",
params = {
{ name = "class" },
{ name = "type" },
{ name = "context" },
{ name = "default" },
},
table = {
"Class", "Permission", "Context", "Default", "Description"
},
}
-- More fitting section names
kind_names={topic='Documentation', module='Libraries', script='Sample files'}
@ -442,6 +464,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',
@ -468,6 +491,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',
@ -497,12 +521,14 @@ local summarize = {
emits = {index = 1, title = "signals" },
propemits = {index = 2, title = "signals" },
usebeautiful = {index = 3, title = "theme variables"},
propbeautiful = {index = 4, title = "theme variables"}
propbeautiful = {index = 4, title = "theme variables"},
request = {index = 5, title = "permissions" },
}
local delimiter_for_tag = {
usebeautiful = { "table class='widget_list' border=1", "table", "tr", "tr", {"Theme variable", "Usage"}},
propbeautiful = { "table class='widget_list' border=1", "table", "tr", "tr", {"Theme variable", "Usage"}},
request = { "table class='widget_list' border=1", "table", "tr", "tr", {"Class", "Permission", "Context", "Default", "Description"}},
}
-- Use the first word of the subtag content to map it to its tag.
@ -736,6 +762,13 @@ local show_return = {
deprecated = true,
}
-- The different type of deprecation.
local is_deprecated = {
deprecated = true,
deprecatedproperty = true,
deprecatedsignal = true,
}
custom_display_name_handler = function(item, default_handler)
init_custom_types(item)
@ -776,7 +809,7 @@ custom_display_name_handler = function(item, default_handler)
end
end
if item.type == "deprecated" or item.type == "deprecatedproperty" then
if is_deprecated[item.type] then
return ret .. "<i class=\"deprecated_label\"> [deprecated]</i>"
end

View File

@ -478,7 +478,7 @@ event_handle_destroynotify(xcb_destroy_notify_event_t *ev)
client_t *c;
if((c = client_getbywin(ev->window)))
client_unmanage(c, false);
client_unmanage(c, CLIENT_UNMANAGE_DESTROYED);
else
for(int i = 0; i < globalconf.embedded.len; i++)
if(globalconf.embedded.tab[i].win == ev->window)
@ -856,7 +856,7 @@ event_handle_unmapnotify(xcb_unmap_notify_event_t *ev)
client_t *c;
if((c = client_getbywin(ev->window)))
client_unmanage(c, true);
client_unmanage(c, CLIENT_UNMANAGE_UNMAP);
}
/** The randr screen change notify event handler.
@ -993,7 +993,7 @@ event_handle_reparentnotify(xcb_reparent_notify_event_t *ev)
/* Ignore reparents to the root window, they *might* be caused by
* ourselves if a client quickly unmaps and maps itself again. */
if (ev->parent != globalconf.screen->root)
client_unmanage(c, true);
client_unmanage(c, CLIENT_UNMANAGE_REPARENT);
}
else if (ev->parent != globalconf.systray.window) {
/* Embedded window moved elsewhere, end of embedding */

14
ewmh.c
View File

@ -238,8 +238,8 @@ ewmh_init_lua(void)
luaA_class_connect_signal(L, &client_class, "focus", ewmh_update_net_active_window);
luaA_class_connect_signal(L, &client_class, "unfocus", ewmh_update_net_active_window);
luaA_class_connect_signal(L, &client_class, "manage", ewmh_update_net_client_list);
luaA_class_connect_signal(L, &client_class, "unmanage", ewmh_update_net_client_list);
luaA_class_connect_signal(L, &client_class, "request::manage", ewmh_update_net_client_list);
luaA_class_connect_signal(L, &client_class, "request::unmanage", ewmh_update_net_client_list);
luaA_class_connect_signal(L, &client_class, "property::modal" , ewmh_client_update_hints);
luaA_class_connect_signal(L, &client_class, "property::fullscreen" , ewmh_client_update_hints);
luaA_class_connect_signal(L, &client_class, "property::maximized_horizontal" , ewmh_client_update_hints);
@ -256,7 +256,7 @@ ewmh_init_lua(void)
luaA_class_connect_signal(L, &client_class, "property::titlebar_right" , ewmh_client_update_frame_extents);
luaA_class_connect_signal(L, &client_class, "property::titlebar_left" , ewmh_client_update_frame_extents);
luaA_class_connect_signal(L, &client_class, "property::border_width" , ewmh_client_update_frame_extents);
luaA_class_connect_signal(L, &client_class, "manage", ewmh_client_update_frame_extents);
luaA_class_connect_signal(L, &client_class, "request::manage", ewmh_client_update_frame_extents);
/* NET_CURRENT_DESKTOP handling */
luaA_class_connect_signal(L, &client_class, "focus", ewmh_update_net_current_desktop);
luaA_class_connect_signal(L, &client_class, "unfocus", ewmh_update_net_current_desktop);
@ -412,14 +412,17 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
{
if(set == _NET_WM_STATE_REMOVE) {
lua_pushboolean(L, false);
/*TODO v5: Add a context */
luaA_object_emit_signal(L, -2, "request::urgent", 1);
}
else if(set == _NET_WM_STATE_ADD) {
lua_pushboolean(L, true);
/*TODO v5: Add a context */
luaA_object_emit_signal(L, -2, "request::urgent", 1);
}
else if(set == _NET_WM_STATE_TOGGLE) {
lua_pushboolean(L, !c->urgent);
/*TODO v5: Add a context */
luaA_object_emit_signal(L, -2, "request::urgent", 1);
}
}
@ -436,6 +439,7 @@ ewmh_process_desktop(client_t *c, uint32_t desktop)
{
luaA_object_push(L, c);
lua_pushboolean(L, true);
/*TODO v5: Move the context argument to arg1 */
luaA_object_emit_signal(L, -2, "request::tag", 1);
/* Pop the client, arguments are already popped */
lua_pop(L, 1);
@ -444,6 +448,7 @@ ewmh_process_desktop(client_t *c, uint32_t desktop)
{
luaA_object_push(L, c);
luaA_object_push(L, globalconf.tags.tab[idx]);
/*TODO v5: Move the context argument to arg1 */
luaA_object_emit_signal(L, -2, "request::tag", 1);
/* Pop the client, arguments are already popped */
lua_pop(L, 1);
@ -462,7 +467,8 @@ ewmh_process_client_message(xcb_client_message_event_t *ev)
{
lua_State *L = globalconf_get_lua_State();
luaA_object_push(L, globalconf.tags.tab[idx]);
luaA_object_emit_signal(L, -1, "request::select", 0);
lua_pushstring(L, "ewmh");
luaA_object_emit_signal(L, -1, "request::select", 1);
lua_pop(L, 1);
}
}

View File

@ -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 &lt;julien@danjou.info&gt;
-- @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("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}
--)

View File

@ -14,6 +14,8 @@ local object = require("gears.object")
local grect = require("gears.geometry").rectangle
local gmath = require("gears.math")
local gtable = require("gears.table")
local amousec = require("awful.mouse.client")
local pcommon = require("awful.permissions._common")
local pairs = pairs
local type = type
local ipairs = ipairs
@ -169,6 +171,8 @@ end
-- first tag additionally) when the client is not visible.
-- If it is a function, it will be called with the client and its first
-- tag as arguments.
-- @request client activate client.jumpto granted When a client is activated
-- because `c:jump_to()` is called.
function client.object.jump_to(self, merge)
local s = get_screen(screen.focused())
-- focus the screen
@ -300,6 +304,8 @@ end
-- @staticfct awful.client.swap.global_bydirection
-- @param dir The direction, can be either "up", "down", "left" or "right".
-- @client[opt] sel The client.
-- @request client activate client.swap.global_bydirection granted When a client
-- could be activated because `awful.client.swap.global_bydirection` was called.
function client.swap.global_bydirection(dir, sel)
sel = sel or capi.client.focus
local scr = get_screen(sel and sel.screen or screen.focused())
@ -461,6 +467,8 @@ end
--- Move a client to a tag.
-- @method move_to_tag
-- @tparam tag target The tag to move the client to.
-- @request client activate client.movetotag granted When a client could be
-- activated because `c:move_to_tag()` was called.
function client.object.move_to_tag(self, target)
local s = target.screen
if self and s then
@ -524,6 +532,8 @@ end
-- @tparam[opt=c.screen.index+1] screen s The screen, default to current + 1.
-- @see screen
-- @see request::activate
-- @request client activate client.movetoscreen granted When a client could be
-- activated because `c:move_to_screen()` was called.
function client.object.move_to_screen(self, s)
if self then
local sc = capi.screen.count()
@ -535,7 +545,7 @@ function client.object.move_to_screen(self, s)
end
s = get_screen(s)
if get_screen(self.screen) ~= s then
local sel_is_focused = self == capi.client.focus
local sel_is_focused = self.active
self.screen = s
screen.focus(s)
@ -687,6 +697,12 @@ function client.object.set_floating(c, s)
c:geometry(client.property.get(c, "floating_geometry"))
end
c.screen = scr
if s then
c:emit_signal("request::border", "floating", {})
else
c:emit_signal("request::border", (c.active and "" or "in").."active", {})
end
end
end
@ -790,6 +806,7 @@ function client.floating.get(c)
end
--- The client floating state.
--
-- If the client is part of the tiled layout or free floating.
--
-- Note that some windows might be floating even if you
@ -801,7 +818,13 @@ end
-- * *property::floating*
--
-- @property floating
-- @param boolean The floating state
-- @tparam boolean floating The floating state.
-- @request client border floating granted When a border update is required
-- because the client focus status changed.
-- @request client border active granted When a client becomes active and is not
-- floating.
-- @request client border inactive granted When a client stop being active and
-- is not floating.
function client.object.get_floating(c)
c = c or capi.client.focus
@ -833,6 +856,17 @@ local function update_implicitly_floating(c)
if cur ~= new then
client.property.set(c, "_implicitly_floating", new)
c:emit_signal("property::floating")
-- Don't send the border signals as they would be sent twice (with this
-- one having the wrong context). There is some `property::` signal
-- sent before `request::manage`.
if client.property.get(c, "_border_init") then
if cur then
c:emit_signal("request::border", "floating", {})
else
c:emit_signal("request::border", (c.active and "" or "in").."active", {})
end
end
end
end
@ -842,7 +876,7 @@ capi.client.connect_signal("property::maximized_vertical", update_implicitly_flo
capi.client.connect_signal("property::maximized_horizontal", update_implicitly_floating)
capi.client.connect_signal("property::maximized", update_implicitly_floating)
capi.client.connect_signal("property::size_hints", update_implicitly_floating)
capi.client.connect_signal("manage", update_implicitly_floating)
capi.client.connect_signal("request::manage", update_implicitly_floating)
--- Toggle the floating state of a client between 'auto' and 'true'.
-- Use `c.floating = not c.floating`
@ -1388,7 +1422,182 @@ function client.object.set_shape(self, shape)
set_shape(self)
end
-- Register standards signals
-- Proxy those properties to decorate their accessors with an extra flag to
-- define when they are set by the user. This allows to "manage" the value of
-- those properties internally until they are manually overridden.
for _, prop in ipairs { "border_width", "border_color", "opacity" } do
client.object["get_"..prop] = function(self)
return self["_"..prop]
end
client.object["set_"..prop] = function(self, value)
self._private["_user_"..prop] = true
self["_"..prop] = value
end
end
--- Activate (focus) a client.
--
-- This method is the correct way to focus a client. While
-- `client.focus = my_client` works and is commonly used in older code, it has
-- some drawbacks. The most obvious one is that it bypasses the activate
-- filters. It also doesn't handle minimized clients well and requires a lot
-- of boilerplate code to make work properly.
--
-- The valid `args.actions` are:
--
-- * **mouse_move**: Move the client when the mouse cursor moves until the
-- mouse buttons are release.
-- * **mouse_resize**: Resize the client when the mouse cursor moves until the
-- mouse buttons are release.
-- * **mouse_center**: Move the mouse cursor to the center of the client if it
-- isn't already within its geometry,
-- * **toggle_minimization**: If the client is already active, minimize it.
--
-- @method activate
-- @tparam table args
-- @tparam[opt=other] string args.context Why was this activate called?
-- @tparam[opt=true] boolean args.raise Raise the client to the top of its layer.
-- @tparam[opt=false] boolean args.force Force the activation even for unfocusable
-- clients.
-- @tparam[opt=false] boolean args.switch_to_tags
-- @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.permissions.add_activate_filter
-- @see request::activate
-- @see active
function client.object.activate(c, args)
local new_args = setmetatable({}, {__index = args or {}})
-- Set the default arguments.
new_args.raise = new_args.raise == nil and true or args.raise
if c == capi.client.focus and new_args.action == "toggle_minimization" then
c.minimized = true
else
c:emit_signal(
"request::activate",
new_args.context or "other",
new_args
)
end
if new_args.action and new_args.action == "mouse_move" then
amousec.move(c)
elseif new_args.action and new_args.action == "mouse_resize" then
amousec.resize(c)
elseif new_args.action and new_args.action == "mouse_center" then
local coords, geo = mouse.mouse.coords(), c:geometry()
coords.width, coords.height = 1,1
if not grect.area_intersect_area(geo, coords) then
-- Do not use `awful.placement` to avoid an useless circular
-- dependency. Centering is *very* simple.
mouse.mouse.coords {
x = geo.x + math.ceil(geo.width /2),
y = geo.y + math.ceil(geo.height/2)
}
end
end
end
--- Grant a permission for a client.
--
-- @method grant
-- @tparam string permission The permission name (just the name, no `request::`).
-- @tparam string context The reason why this permission is requested.
-- @see awful.permissions
--- Deny a permission for a client.
--
-- @method deny
-- @tparam string permission The permission name (just the name, no `request::`).
-- @tparam string context The reason why this permission is requested.
-- @see awful.permissions
pcommon.setup_grant(client.object, "client")
--- Return true if the client is active (has focus).
--
-- This property is **READ ONLY**. Use `c:activate { context = "myreason" }`
-- to change the focus.
--
-- The reason for this is that directly setting the focus
-- (which can also be done using `client.focus = c`) will bypass the focus
-- stealing filters. This is easy at first, but as this gets called from more
-- and more places, it quickly become unmanageable. This coding style is
-- recommended for maintainable code:
--
-- -- Check if a client has focus:
-- if c.active then
-- -- do something
-- end
--
-- -- Check if there is a active (focused) client:
-- if client.focus ~= nil then
-- -- do something
-- end
--
-- -- Get the active (focused) client:
-- local c = client.focus
--
-- -- Set the focus:
-- c:activate {
-- context = "myreason",
-- switch_to_tag = true,
-- }
--
-- -- Get notified when a client gets or loses the focus:
-- c:connect_signal("property::active", function(c, is_active)
-- -- do something
-- end)
--
-- -- Get notified when any client gets or loses the focus:
-- client.connect_signal("property::active", function(c, is_active)
-- -- do something
-- end)
--
-- -- Get notified when any client gets the focus:
-- client.connect_signal("focus", function(c)
-- -- do something
-- end)
--
-- -- Get notified when any client loses the focus:
-- client.connect_signal("unfocus", function(c)
-- -- do something
-- end)
--
-- @property active
-- @tparam boolean active
-- @request client border active granted When a client becomes active.
-- @request client border inactive granted When a client stop being active.
-- @see activate
-- @see request::activate
-- @see awful.permissions.add_activate_filter
function client.object.get_active(c)
return capi.client.focus == c
end
function client.object.set_active(c, value)
if value then
-- Do it, but print an error popup. Setting the focus without a context
-- breaks the filters. This seems a good idea at first, then cause
-- endless pain. QtWidgets also enforces this.
c:activate()
assert(false, "You cannot set `active` directly, use `c:activate()`.")
else
-- Be permissive given the alternative is a bit convoluted.
capi.client.focus = nil
gdebug.print_warning(
"Consider using `client.focus = nil` instead of `c.active = false"
)
end
end
capi.client.connect_signal("property::active", function(c)
c:emit_signal("request::border", (c.active and "" or "in").."active", {})
end)
--- The last geometry when client was floating.
-- @signal property::floating_geometry
@ -1398,23 +1607,62 @@ end
-- @tparam[opt=nil] string content The context (like "rules")
-- @tparam[opt=nil] table hints Some hints.
--- The client marked signal (deprecated).
-- @signal marked
--- The client marked signal.
-- @deprecatedsignal marked
--- The client unmarked signal (deprecated).
-- @signal unmarked
--- The client unmarked signal.
-- @deprecatedsignal unmarked
--- Emited when the border client might need to be update.
--
-- The context are:
--
-- * **added**: When a new client is created.
-- * **active**: When client gains the focus (or stop being urgent/floating
-- but is active).
-- * **inactive**: When client loses the focus (or stop being urgent/floating
-- and is not active.
-- * **urgent**: When a client becomes urgent.
-- * **floating**: When the floating or maximization state changes.
--
-- @signal request::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("manage", function (c)
capi.client.connect_signal("request::manage", function (c)
if capi.awesome.startup
and not c.size_hints.user_position
and not c.size_hints.program_position then
-- Prevent clients from being unreachable after screen count changes.
require("awful.placement").no_offscreen(c)
end
if awesome.startup then
client.focus.history.add(c)
end
end)
capi.client.connect_signal("unmanage", client.focus.history.delete)
capi.client.connect_signal("unmanage", client.floating.delete)
client.property.set(c, "_border_init", true)
c:emit_signal("request::border", "added", {})
end)
capi.client.connect_signal("request::unmanage", client.focus.history.delete)
capi.client.connect_signal("request::unmanage", client.floating.delete)
-- Print a warning when the old `manage` signal is used.
capi.client.connect_signal("manage::connected", function()
gdebug.deprecate(
"Use `request::manage` rather than `manage`",
{deprecated_in=5}
)
end)
capi.client.connect_signal("unmanage::connected", function()
gdebug.deprecate(
"Use `request::unmanage` rather than `unmanage`",
{deprecated_in=5}
)
end)
-- Connect to "focus" signal, and allow to disable tracking.
do

View File

@ -60,6 +60,8 @@ end
-- @function awful.client.focus.byidx
-- @param i The index.
-- @client[opt] c The client.
-- @request client activate client.focus.byidx granted When `awful.focus.byidx`
-- is called.
function focus.byidx(i, c)
local target = client.next(i, c)
if target then
@ -141,6 +143,8 @@ end
--- Focus the previous client in history.
-- @function awful.client.focus.history.previous
-- @request client activate client.focus.history.previous granted When
-- `awful.focus.history.previous` is called.
function focus.history.previous()
local sel = capi.client.focus
local s = sel and sel.screen or screen.focused()
@ -158,6 +162,8 @@ end
-- @client[opt] c The client.
-- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
-- @function awful.client.focus.bydirection
-- @request client activate client.focus.bydirection granted When
-- `awful.focus.bydirection` is called.
function focus.bydirection(dir, c, stacked)
local sel = c or capi.client.focus
if sel then
@ -183,6 +189,8 @@ end
-- @client[opt] c The client.
-- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
-- @function awful.client.focus.global_bydirection
-- @request client activate client.focus.global_bydirection granted When
-- `awful.client.focus.global_bydirection` is called.
function focus.global_bydirection(dir, c, stacked)
local sel = c or capi.client.focus
local scr = get_screen(sel and sel.screen or screen.focused())

View File

@ -62,10 +62,30 @@ end
-- @function awful.urgent.add
-- @client c The client object.
-- @param prop The property which is updated.
-- @request client border active granted When a client becomes active and is no
-- longer urgent.
-- @request client border inactive granted When a client stop being active and
-- is no longer urgent.
-- @request client border urgent granted When a client stop becomes urgent.
function urgent.add(c, prop)
if type(c) == "client" and prop == "urgent" and c.urgent then
assert(
c.urgent ~= nil,
"`awful.client.urgent.add()` takes a client as first parameter"
)
if prop == "urgent" and c.urgent then
table.insert(data, c)
end
if c.urgent then
c:emit_signal("request::border", "urgent", {})
else
c:emit_signal(
"request::border",
(c.active and "" or "in").."active",
{}
)
end
end
--- Remove client from urgent stack.
@ -83,7 +103,7 @@ end
capi.client.connect_signal("property::urgent", urgent.add)
capi.client.connect_signal("focus", urgent.delete)
capi.client.connect_signal("unmanage", urgent.delete)
capi.client.connect_signal("request::unmanage", urgent.delete)
return urgent

View File

@ -1,472 +1,9 @@
---------------------------------------------------------------------------
--- Implements EWMH requests handling.
--
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @module awful.ewmh
---------------------------------------------------------------------------
local gdebug = require("gears.debug")
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 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
--- 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")
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)
screen.connect_signal("property::workarea", function(s)
for _, c in pairs(client.get(s)) do
repair_geometry(c)
end
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}
)

View File

@ -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

View File

@ -31,26 +31,17 @@ end
local layout = {}
layout.suit = require("awful.layout.suit")
-- Support `table.insert()` to avoid breaking old code.
local default_layouts = setmetatable({}, {
__newindex = function(self, key, value)
assert(key <= #self+1 and key > 0)
layout.layouts = {
layout.suit.floating,
layout.suit.tile,
layout.suit.tile.left,
layout.suit.tile.bottom,
layout.suit.tile.top,
layout.suit.fair,
layout.suit.fair.horizontal,
layout.suit.spiral,
layout.suit.spiral.dwindle,
layout.suit.max,
layout.suit.max.fullscreen,
layout.suit.magnifier,
layout.suit.corner.nw,
layout.suit.corner.ne,
layout.suit.corner.sw,
layout.suit.corner.se,
}
layout.append_default_layout(value)
end
})
layout.suit = require("awful.layout.suit")
--- The default list of layouts.
--
@ -256,6 +247,53 @@ function layout.arrange(screen)
end)
end
--- Append a layout to the list of default tag layouts.
--
-- @staticfct awful.layout.append_default_layout
-- @tparam layout to_add A valid tag layout.
-- @see awful.layout.layouts
function layout.append_default_layout(to_add)
rawset(default_layouts, #default_layouts+1, to_add)
capi.tag.emit_signal("property::layouts")
end
--- Remove a layout from the list of default layouts.
--
-- @DOC_text_awful_layout_remove_EXAMPLE@
--
-- @staticfct awful.layout.remove_default_layout
-- @tparam layout to_remove A valid tag layout.
-- @treturn boolean True if the layout was found and removed.
-- @see awful.layout.layouts
function layout.remove_default_layout(to_remove)
local ret, found = false, true
-- Remove all instances, just in case.
while found do
found = false
for k, l in ipairs(default_layouts) do
if l == to_remove then
table.remove(default_layouts, k)
ret, found = true, true
break
end
end
end
return ret
end
--- Append many layouts to the list of default tag layouts.
--
-- @staticfct awful.layout.append_default_layouts
-- @tparam table layouts A table of valid tag layout.
-- @see awful.layout.layouts
function layout.append_default_layouts(layouts)
for _, l in ipairs(layouts) do
rawset(default_layouts, #default_layouts+1, l)
end
end
--- Get the current layout name.
-- @param _layout The layout.
-- @return The layout name.
@ -365,6 +403,87 @@ capi.screen.connect_signal("property::geometry", function(s, old_geom)
end
end)
return layout
local init_layouts
init_layouts = function()
capi.tag.emit_signal("request::default_layouts", "startup")
capi.tag.disconnect_signal("new", init_layouts)
-- Fallback.
if #default_layouts == 0 then
layout.append_default_layouts({
layout.suit.floating,
layout.suit.tile,
layout.suit.tile.left,
layout.suit.tile.bottom,
layout.suit.tile.top,
layout.suit.fair,
layout.suit.fair.horizontal,
layout.suit.spiral,
layout.suit.spiral.dwindle,
layout.suit.max,
layout.suit.max.fullscreen,
layout.suit.magnifier,
layout.suit.corner.nw,
layout.suit.corner.ne,
layout.suit.corner.sw,
layout.suit.corner.se,
})
end
init_layouts = nil
end
-- "new" is emited before "activate", do it should be the very last opportunity
-- generate the list of default layout. With dynamic tag, this can happen later
-- than the first event loop iteration.
capi.tag.connect_signal("new", init_layouts)
-- Intercept the calls to `layouts` to both lazyload then and emit the proper
-- signals.
local mt = {
__index = function(_, key)
if key == "layouts" then
-- Lazy initialization to *at least* attempt to give modules a
-- chance to load before calling `request::default_layouts`. Note
-- that the old `rc.lua` called `awful.layout.layouts` in the global
-- context. If there was some module `require()` later in the code,
-- they will not get the signal.
if init_layouts then
init_layouts()
end
return default_layouts
end
end,
__newindex = function(_, key, value)
if key == "layouts" then
assert(type(value) == "table", "`awful.layout.layouts` needs a table.")
-- Do not ask for layouts if they were already provided.
if init_layouts then
gdebug.print_warning(
"`awful.layout.layouts` was set before `request::default_layouts` could "..
"be called. Please use `awful.layout.append_default_layouts` to "..
" avoid this problem"
)
capi.tag.disconnect_signal("new", init_layouts)
init_layouts = nil
elseif #default_layouts > 0 then
gdebug.print_warning(
"`awful.layout.layouts` was set after `request::default_layouts` was "..
"used to get the layouts. This is probably an accident. Use "..
"`awful.layout.remove_default_layout` to get rid of this warning."
)
end
default_layouts = value
else
rawset(layout, key, value)
end
end
}
return setmetatable(layout, mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -119,8 +119,8 @@ local function load_theme(a, b)
local fallback = beautiful.get()
if a.reset then b = fallback end
if a == "reset" then a = fallback end
ret.border = a.border_color or b.menu_border_color or b.border_normal or
fallback.menu_border_color or fallback.border_normal
ret.border = a.border_color or b.menu_border_color or b.border_color_normal or
fallback.menu_border_color or fallback.border_color_normal
ret.border_width= a.border_width or b.menu_border_width or b.border_width or
fallback.menu_border_width or fallback.border_width or dpi(0)
ret.fg_focus = a.fg_focus or b.menu_fg_focus or b.fg_focus or
@ -521,6 +521,8 @@ end
-- included in the menu.
-- @return The menu.
-- @constructorfct awful.menu.clients
-- @request client activate menu.clients granted When clicking on a clients menu
-- element.
function menu.clients(args, item_args, filter)
local cls_t = {}
for c in client_iterate(filter or function() return true end) do

View File

@ -15,7 +15,9 @@ local module = {}
-- @staticfct awful.mouse.client.move
-- @param c The client to move, or the focused one if nil.
-- @param snap The pixel to snap clients.
-- @param finished_cb Deprecated, do not use
-- @param finished_cb Deprecated, do not use.
-- @request client geometry mouse.move granted When `awful.mouse.client.move` is
-- called.
function module.move(c, snap, finished_cb) --luacheck: no unused args
if finished_cb then
gdebug.deprecate("The mouse.client.move `finished_cb` argument is no longer"..
@ -99,6 +101,8 @@ end
-- @tparam string corner The corner to grab on resize. Auto detected by default.
-- @tparam[opt={}] table args A set of `awful.placement` arguments
-- @treturn string The corner (or side) name
-- @request client geometry mouse.resize granted When `awful.mouse.client.resize`
-- is called.
function module.resize(c, corner, args)
c = c or capi.client.focus

View File

@ -103,7 +103,6 @@ end
-- @tparam client client A client.
-- @tparam[default=mouse.resize] string context The resizing context.
-- @tparam[opt={}] table args A set of `awful.placement` arguments.
local function handler(_, client, context, args) --luacheck: no unused_args
args = args or {}
context = context or "mouse.resize"

View File

@ -0,0 +1,82 @@
-- 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(object, 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
local ret = nil
if object._private.permissions and object._private.permissions[request] then
ret = object._private.permissions[request][context]
end
if ret ~= nil then return ret 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
local function set_object_permission_common(self, request, context, v)
self._private.permissions = self._private.permissions or {}
if not self._private.permissions[request] then
self._private.permissions[request] = {}
end
self._private.permissions[request][context] = v
end
-- Add the grant and deny methods to the objects.
function module.setup_grant(class, classname) -- luacheck: no unused
function class.grant(self, request, context)
set_object_permission_common(self, request, context, true)
end
function class.deny(self, request, context)
set_object_permission_common(self, request, context, false)
end
end
return module

View File

@ -0,0 +1,732 @@
---------------------------------------------------------------------------
--- Implements EWMH requests handling.
--
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @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
if not pcommon.check(c, "client", "activate", context) then return end
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)
if not pcommon.check(c, "client", "geometry", context) then return end
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 not pcommon.check(c, "client", "geometry", context) then return end
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 not pcommon.check(c, "client", "geometry", context) then return end
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(c, "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

View File

@ -708,7 +708,7 @@ local function get_relative_regions(geo, mode, is_absolute)
-- Detect various types of geometry table and (try) to get rid of the
-- differences so the code below don't have to care anymore.
if geo.drawin then
bw, dgeo = geo.drawin.border_width, geo.drawin:geometry()
bw, dgeo = geo.drawin._border_width, geo.drawin:geometry()
elseif geo.drawable and geo.drawable.get_wibox then
bw = geo.drawable.get_wibox().border_width
dgeo = geo.drawable.get_wibox():geometry()

View File

@ -529,6 +529,8 @@ end
-- @tab props Properties to apply.
-- @tab[opt] callbacks Callbacks to apply.
-- @staticfct awful.rules.execute
-- @request client titlebars rules granted The `titlebars_enabled` is set in the
-- rules.
crules._execute = function(_, c, props, callbacks)
@ -538,6 +540,12 @@ crules._execute = function(_, c, props, callbacks)
props.keys = props.keys or keys
props.buttons = props.buttons or btns
-- Border width will also cause geometry related properties to fail
if props.border_width then
c.border_width = type(props.border_width) == "function" and
props.border_width(c, props) or props.border_width
end
-- This has to be done first, as it will impact geometry related props.
if props.titlebars_enabled and (type(props.titlebars_enabled) ~= "function"
or props.titlebars_enabled(c,props)) then
@ -545,12 +553,6 @@ crules._execute = function(_, c, props, callbacks)
c._request_titlebars_called = true
end
-- Border width will also cause geometry related properties to fail
if props.border_width then
c.border_width = type(props.border_width) == "function" and
props.border_width(c, props) or props.border_width
end
-- Size hints will be re-applied when setting width/height unless it is
-- disabled first
if props.size_hints_honor ~= nil then
@ -657,7 +659,7 @@ function rules.completed_with_payload_callback(c, props, callbacks)
rules.execute(c, props, callbacks)
end
client.connect_signal("manage", rules.apply)
client.connect_signal("request::manage", rules.apply)
--@DOC_rule_COMMON@

View File

@ -89,6 +89,8 @@ end
-- or keeps its position relative to the current focused screen.
-- @staticfct awful.screen.focus
-- @screen _screen Screen number (defaults / falls back to mouse.screen).
-- @request client activate screen.focus granted The most recent focused client
-- for this screen should be re-activated.
function screen.focus(_screen)
client = client or require("awful.client")
if type(_screen) == "number" and _screen > capi.screen.count() then _screen = screen.focused() end
@ -771,7 +773,9 @@ end
-- The only default implementation is the one provided by `rc.lua`.
--
-- @signal request::desktop_decoration
-- @tparam screen s The screen object.
-- @tparam string context The context.
-- @request screen wallpaper added granted When the decorations needs to be
-- added to a new screen.
--- Emitted when a new screen needs a wallpaper.
--
@ -782,7 +786,13 @@ end
-- The only default implementation is the one provided by `rc.lua`.
--
-- @signal request::wallpaper
-- @tparam screen s The screen object.
-- @tparam string context The context.
-- @request screen wallpaper added granted When the wallpaper needs to be
-- added to a new screen.
-- @request screen wallpaper geometry granted When the wallpaper needs to be
-- updated because the resolution changed.
-- @request screen wallpaper dpi granted When the wallpaper needs to be
-- updated because the DPI changed.
--- When a new (physical) screen area has been added.
--
@ -965,15 +975,15 @@ capi.screen.connect_signal("_added", function(s)
-- metadata. Thus, the DPI may be wrong when setting the wallpaper.
if s._managed ~= "Lua" then
s:emit_signal("added")
s:emit_signal("request::desktop_decoration")
s:emit_signal("request::wallpaper")
s:emit_signal("request::desktop_decoration", "added")
s:emit_signal("request::wallpaper", "added")
end
end)
-- Resize the wallpaper(s)
for _, prop in ipairs {"geometry", "dpi" } do
capi.screen.connect_signal("property::"..prop, function(s)
s:emit_signal("request::wallpaper")
s:emit_signal("request::wallpaper", prop)
end)
end

View File

@ -712,6 +712,8 @@ local raise_rules = {focus = true, switch_to_tags = true, raise = true}
-- @see awful.rules
-- @treturn client The client if it already exists.
-- @staticfct awful.spawn.raise_or_spawn
-- @request client activate spawn.raise_or_spawn granted Activate a client when
-- `awful.spawn.raise_or_spawn` is called and the client exists.
function spawn.raise_or_spawn(cmd, rules, matcher, unique_id, callback)
local hash = unique_id or hash_command(cmd, rules)
@ -736,7 +738,7 @@ end
capi.awesome.connect_signal("spawn::canceled" , spawn.on_snid_cancel )
capi.awesome.connect_signal("spawn::timeout" , spawn.on_snid_cancel )
capi.client.connect_signal ("manage" , spawn.on_snid_callback )
capi.client.connect_signal ("request::manage" , spawn.on_snid_callback )
return setmetatable(spawn, { __call = function(_, ...) return spawn.spawn(...) end })
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -815,6 +815,8 @@ end
--
-- @property layouts
-- @param table
-- @request tag layouts awful granted When the `layouts` property is first called
-- and there is no layouts, then that signal is called.
-- @see awful.layout.layouts
-- @see layout
@ -867,6 +869,22 @@ function tag.object.get_layouts(self)
local cls = custom_layouts(self)
-- Request some layouts. Maybe a new module was added?
if #cls == 0 and not tag.getproperty(self, "_layouts_requested") then
tag.setproperty(self, "_layouts_requested", true)
local old_count = #cls
self:emit_signal("request::layouts", "awful", {})
-- When request::layouts is used, assume it takes precedence over
-- the fallback.
if #cls > old_count then
tag.setproperty(self, "_layouts", gtable.clone(cls, false))
return tag.getproperty(self, "_layouts")
end
return tag.object.get_layouts(self)
end
-- Without the clone, the custom_layouts would grow
return #cls > 0 and gtable.merge(gtable.clone(cls, false), alayout.layouts) or
alayout.layouts
@ -882,6 +900,60 @@ function tag.object.set_layouts(self, layouts)
self:emit_signal("property::layouts")
end
function tag.object.append_layout(self, layout)
-- If the layouts are manually modified, don't request more.
tag.setproperty(self, "_layouts_requested", true)
local cls = tag.getproperty(self, "_layouts")
if not cls then
cls = custom_layouts(self)
end
table.insert(cls, layout)
self:emit_signal("property::layouts")
end
function tag.object.append_layouts(self, layouts)
-- If the layouts are manually modified, don't request more.
tag.setproperty(self, "_layouts_requested", true)
local cls = tag.getproperty(self, "_layouts")
if not cls then
cls = custom_layouts(self)
end
for _, l in ipairs(layouts) do
table.insert(cls, l)
end
self:emit_signal("property::layouts")
end
function tag.object.remove_layout(self, layout)
local cls = tag.getproperty(self, "_layouts")
if not cls then
cls = custom_layouts(self)
end
local pos = {}
for k, l in ipairs(cls) do
if l == layout then
table.insert(pos, k)
end
end
if #pos > 0 then
for i=#pos, 1, -1 do
table.remove(cls, i)
end
self:emit_signal("property::layouts")
end
return #pos > 0
end
function tag.object.get_layout(t)
local l = tag.getproperty(t, "layout")
if l then return l end
@ -1627,6 +1699,7 @@ capi.client.connect_signal("property::screen", function(c)
end
if #new_tags == 0 then
--TODO v5: Add a context as first param
c:emit_signal("request::tag", nil, {reason="screen"})
elseif #new_tags < #tags then
c:tags(new_tags)
@ -1687,6 +1760,7 @@ capi.tag.connect_signal("request::select", tag.object.view_only)
-- this, an handler for this request must simply set a new screen
-- for the tag.
-- @signal request::screen
-- @tparam string context Why it was called.
--- Emitted after `request::screen` if no new screen has been set.
-- The tag will be deleted, this is a last chance to move its clients
@ -1706,7 +1780,7 @@ end)
capi.screen.connect_signal("removed", function(s)
-- First give other code a chance to move the tag to another screen
for _, t in pairs(s.tags) do
t:emit_signal("request::screen")
t:emit_signal("request::screen", "removed")
end
-- Everything that's left: Tell everyone that these tags go away (other code
-- could e.g. save clients)
@ -1715,6 +1789,7 @@ capi.screen.connect_signal("removed", function(s)
end
-- Give other code yet another change to save clients
for _, c in pairs(capi.client.get(s)) do
--TODO v5: Add a context as first param
c:emit_signal("request::tag", nil, { reason = "screen-removed" })
end
-- Then force all clients left to go somewhere random

View File

@ -443,7 +443,7 @@ local all_titlebars = setmetatable({}, { __mode = 'k' })
-- Get a color for a titlebar, this tests many values from the array and the theme
local function get_color(name, c, args)
local suffix = "_normal"
if capi.client.focus == c then
if c.active then
suffix = "_focus"
end
local function get(array)
@ -470,12 +470,13 @@ end
-- when `titlebars_enabled` is not set in the rules.
-- @tparam client c The client.
-- @tparam[opt=false] boolean hide_all Hide all titlebars except `keep`
-- @tparam string keep Keep the titlebar at this position
-- @tparam string keep Keep the titlebar at this position.
-- @tparam string context The reason why this was called.
-- @treturn boolean If the titlebars were loaded
local function load_titlebars(c, hide_all, keep)
local function load_titlebars(c, hide_all, keep, context)
if c._request_titlebars_called then return false end
c:emit_signal("request::titlebars", "awful.titlebar", {})
c:emit_signal("request::titlebars", context, {})
if hide_all then
-- Don't bother checking if it has been created, `.hide` don't works
@ -553,11 +554,12 @@ local function new(c, args)
}
-- Update the colors when focus changes
c:connect_signal("focus", update_colors)
c:connect_signal("unfocus", update_colors)
c:connect_signal("property::active", update_colors)
-- Inform the drawable when it becomes invisible
c:connect_signal("unmanage", function() ret:_inform_visible(false) end)
c:connect_signal("request::unmanage", function()
ret:_inform_visible(false)
end)
else
bars[position].args = args
ret = bars[position].drawable
@ -581,9 +583,11 @@ end
-- @param[opt] position The position of the titlebar. Must be one of "left",
-- "right", "top", "bottom". Default is "top".
-- @staticfct awful.titlebar.show
-- @request client titlebars show granted Called when `awful.titlebar.show` is
-- called.
function titlebar.show(c, position)
position = position or "top"
if load_titlebars(c, true, position) then return end
if load_titlebars(c, true, position, "show") then return end
local bars = all_titlebars[c]
local data = bars and bars[position]
local args = data and data.args
@ -605,9 +609,11 @@ end
-- @param[opt] position The position of the titlebar. Must be one of "left",
-- "right", "top", "bottom". Default is "top".
-- @staticfct awful.titlebar.toggle
-- @request client titlebars toggle granted Called when `awful.titlebar.toggle` is
-- called.
function titlebar.toggle(c, position)
position = position or "top"
if load_titlebars(c, true, position) then return end
if load_titlebars(c, true, position, "toggle") then return end
local _, size = get_titlebar_function(c, position)(c)
if size == 0 then
titlebar.show(c, position)
@ -705,7 +711,7 @@ function titlebar.widget.button(c, name, selector, action)
end
end
local prefix = "normal"
if capi.client.focus == c then
if c.active then
prefix = "focus"
end
if img ~= "" then
@ -832,7 +838,7 @@ function titlebar.widget.stickybutton(c)
return widget
end
client.connect_signal("unmanage", function(c)
client.connect_signal("request::unmanage", function(c)
all_titlebars[c] = nil
end)

View File

@ -694,7 +694,7 @@ function tooltip.new(args)
or beautiful.bg_focus or "#ffcb60"
local border_width = args.border_width or beautiful.tooltip_border_width or 0
local border_color = args.border_color or beautiful.tooltip_border_color
or beautiful.border_normal or "#ffcb60"
or beautiful.border_color_normal or "#ffcb60"
-- Set wibox default properties
self.wibox_properties = {

View File

@ -131,7 +131,7 @@ local function parse_cell_options(cell, args)
elseif prop == 'border_width' then
default = beautiful.border_width or 0
elseif prop == 'border_color' then
default = beautiful.border_normal or beautiful.fg_normal
default = beautiful.border_color_normal or beautiful.fg_normal
end
-- Get default

View File

@ -539,8 +539,7 @@ function taglist.new(args, filter, buttons, style, update_function, base_widget)
end
local uc = function (c) return u(c.screen) end
local ut = function (t) return u(t.screen) end
capi.client.connect_signal("focus", uc)
capi.client.connect_signal("unfocus", uc)
capi.client.connect_signal("property::active", uc)
tag.attached_connect_signal(nil, "property::selected", ut)
tag.attached_connect_signal(nil, "property::icon", ut)
tag.attached_connect_signal(nil, "property::hide", ut)
@ -555,7 +554,7 @@ function taglist.new(args, filter, buttons, style, update_function, base_widget)
end)
capi.client.connect_signal("tagged", uc)
capi.client.connect_signal("untagged", uc)
capi.client.connect_signal("unmanage", uc)
capi.client.connect_signal("request::unmanage", uc)
capi.screen.connect_signal("removed", function(s)
instances[get_screen(s)] = nil
end)

View File

@ -352,7 +352,7 @@ local function tasklist_label(c, args, tb)
end
end
local focused = capi.client.focus == c
local focused = c.active
-- Handle transient_for: the first parent that does not skip the taskbar
-- is considered to be focused, if the real client has skip_taskbar.
if not focused and capi.client.focus and capi.client.focus.skip_taskbar
@ -621,7 +621,7 @@ function tasklist.new(args, filter, buttons, style, update_function, base_widget
capi.client.connect_signal("property::hidden", u)
capi.client.connect_signal("tagged", u)
capi.client.connect_signal("untagged", u)
capi.client.connect_signal("unmanage", function(c)
capi.client.connect_signal("request::unmanage", function(c)
u(c)
for _, i in pairs(instances) do
for _, tlist in pairs(i) do
@ -630,8 +630,7 @@ function tasklist.new(args, filter, buttons, style, update_function, base_widget
end
end)
capi.client.connect_signal("list", u)
capi.client.connect_signal("focus", u)
capi.client.connect_signal("unfocus", u)
capi.client.connect_signal("property::active", u)
capi.screen.connect_signal("removed", function(s)
instances[get_screen(s)] = nil
end)
@ -723,7 +722,7 @@ end
-- @filterfunction awful.tasklist.filter.focused
function tasklist.filter.focused(c, screen)
-- Only print client on the same screen as this widget
return get_screen(c.screen) == get_screen(screen) and capi.client.focus == c
return get_screen(c.screen) == get_screen(screen) and c.active
end
--- Get all the clients in an undefined order.

View File

@ -132,23 +132,12 @@ local active_font
-- @beautiful beautiful.useless_gap
-- @param[opt=0] number
--- The client border width.
--- The fallback border width.
-- @beautiful beautiful.border_width
-- @param number
--- The default clients border color.
-- Note that only solid colors are supported.
-- @beautiful beautiful.border_normal
-- @param color
--- The focused client border color.
-- Note that only solid colors are supported.
-- @beautiful beautiful.border_focus
-- @param color
--- The marked clients border color.
-- Note that only solid colors are supported.
-- @beautiful beautiful.border_marked
--- The fallback border color.
-- @beautiful beautiful.border_color
-- @param color
--- The wallpaper path.

View File

@ -630,7 +630,7 @@ end
-- @string[opt=`beautiful.notification_fg` or `beautiful.fg_focus` or `'#ffffff'`] args.fg Foreground color.
-- @string[opt=`beautiful.notification_fg` or `beautiful.bg_focus` or `'#535d6c'`] args.bg Background color.
-- @int[opt=`beautiful.notification_border_width` or 1] args.border_width Border width.
-- @string[opt=`beautiful.notification_border_color` or `beautiful.border_focus` or `'#535d6c'`] args.border_color Border color.
-- @string[opt=`beautiful.notification_border_color` or `beautiful.border_color_active` or `'#535d6c'`] args.border_color Border color.
-- @tparam[opt=`beautiful.notification_shape`] gears.shape args.shape Widget shape.
-- @tparam[opt=`beautiful.notification_opacity`] gears.opacity args.opacity Widget opacity.
-- @tparam[opt=`beautiful.notification_margin`] gears.margin args.margin Widget margin.

View File

@ -777,7 +777,7 @@ end
-- @string[opt=`beautiful.notification_fg` or `beautiful.bg_focus` or `'#535d6c'`] args.bg Background color.
-- @int[opt=`beautiful.notification_border_width` or 1] args.border_width Border width.
-- @string[opt=`beautiful.notification_border_color` or
-- `beautiful.border_focus` or `'#535d6c'`] args.border_color Border color.
-- `beautiful.border_color_active` or `'#535d6c'`] args.border_color Border color.
-- @tparam[opt=`beautiful.notification_shape`] gears.shape args.shape Widget shape.
-- @tparam[opt=`beautiful.notification_opacity`] gears.opacity args.opacity Widget opacity.
-- @tparam[opt=`beautiful.notification_margin`] gears.margin args.margin Widget margin.

View File

@ -221,7 +221,20 @@ function wibox:get_children_by_id(name)
return {}
end
for _, k in pairs{ "struts", "geometry", "get_xproperty", "set_xproperty" } do
-- Proxy those properties to decorate their accessors with an extra flag to
-- define when they are set by the user. This allows to "manage" the value of
-- those properties internally until they are manually overridden.
for _, prop in ipairs { "border_width", "border_color", "opacity" } do
wibox["get_"..prop] = function(self)
return self["_"..prop]
end
wibox["set_"..prop] = function(self, value)
self._private["_user_"..prop] = true
self["_"..prop] = value
end
end
for _, k in ipairs{ "struts", "geometry", "get_xproperty", "set_xproperty" } do
wibox[k] = function(self, ...)
return self.drawin[k](self.drawin, ...)
end
@ -362,6 +375,14 @@ local function new(args)
ret.shape = args.shape
end
if args.border_width then
ret.border_width = args.border_width
end
if args.border_color then
ret.border_color = args.border_color
end
if args.input_passthrough then
ret.input_passthrough = args.input_passthrough
end

View File

@ -63,7 +63,7 @@
*
* To execute a callback when a new client is added, use the `manage` signal:
*
* client.connect_signal("manage", function(c)
* client.connect_signal("request::manage", function(c)
* -- do something
* end)
*
@ -164,7 +164,48 @@
*/
/** When a new client appears and gets managed by Awesome.
* @signal manage
*
* This request should be implemented by code which track the client. It isn't
* recommended to use this to initialize the client content. This use case is
* a better fit for `ruled.client`, which has built-in dependency management.
* Using this request to mutate the client state will likely conflict with
* `ruled.client`.
*
* @signal request::manage
* @tparam client c The client.
* @tparam string context What created the client. It is currently either "new"
* or "startup".
* @tparam table hints More metadata (currently empty, it exists for compliance
* with the other `request::` signals).
* @request client border added granted When a new client needs a its initial
* border settings.
*/
/** When a client is going away.
*
* Each places which store `client` objects in non-weak table or whose state
* depend on the current client should answer this request.
*
* The contexts are:
*
* * **user**: `c:unmanage()` was called.
* * **reparented**: The window was reparented to another window. It is no
* longer a stand alone client.
* * **destroyed**: The window was closed.
*
* @signal request::unmanage
* @tparam client c The client.
* @tparam string context Why was the client unmanaged.
* @tparam table hints More metadata (currently empty, it exists for compliance
* with the other `request::` signals).
*/
/** Use `request::manage`.
* @deprecatedsignal manage
*/
/** Use `request::unmanage`.
* @deprecatedsignal unmanage
*/
/**
@ -225,15 +266,41 @@
* @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?
* @request client activate ewmh granted When the client asks to be activated.
*/
/**
/** 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?
*
*/
/** When something request a client geometry to be modified.
*
* @signal request::geometry
* @tparam client c The client
* @tparam string context Why and what to resize. This is used for the
* handlers to know if they are capable of applying the new geometry.
* @tparam[opt={}] table Additional arguments. Each context handler may
* interpret this differently.
* @request client geometry client_maximize_horizontal granted When a client
* (programmatically) asks for the maximization to be changed.
* @request client geometry client_maximize_vertical granted When a client
* (programmatically) asks for the maximization to be changed.
*/
/**
@ -253,6 +320,7 @@
* @signal request::default_mousebindings
* @tparam string context The reason why the signal was sent (currently always
* `startup`).
* @classsignal
*/
/** Emitted during startup to gather the default client keybindings.
@ -264,6 +332,20 @@
* @signal request::default_keybindings
* @tparam string context The reason why the signal was sent (currently always
* `startup`).
* @classsignal
*/
/** Sent once when AwesomeWM starts to add default keybindings.
*
* Keybindings can be set directly on clients. Actually, older version of
* AwesomeWM did that through the rules. However this makes it impossible for
* auto-configured modules to add their own keybindings. Using the signals,
* `rc.lua` or any module can cleanly manage keybindings.
*
* @signal request::default_keybindings
* @tparam string context The context (currently always "startup").
* @classsignal
* @request client default_keybindings startup granted Sent when AwesomeWM starts.
*/
/** When a client gets tagged.
@ -275,10 +357,6 @@
* @signal unfocus
*/
/**
* @signal unmanage
*/
/** When a client gets untagged.
* @signal untagged
* @tag t The tag object.
@ -533,20 +611,19 @@
* The client border width.
* @property border_width
* @param integer
* @propemits false false
* @see request::border
*/
/**
* The client border color.
*
* **Signal:**
*
* * *property::border\_color*
*
* @see gears.color
*
* @property border_color
* @param pattern Any string, gradients and patterns will be converted to a
* @param color Any string, gradients and patterns will be converted to a
* cairo pattern.
* @propemits false false
* @see request::border
* @see gears.color
*/
/**
@ -558,6 +635,8 @@
*
* @property urgent
* @param boolean
* @propemits false false
* @see request::border
*/
/**
@ -584,6 +663,8 @@
*
* @property opacity
* @param number Between 0 (transparent) to 1 (opaque)
* @propemits false false
* @see request::border
*/
/**
@ -619,12 +700,11 @@
*
* @DOC_sequences_client_fullscreen_EXAMPLE@
*
* **Signal:**
*
* * *property::fullscreen*
*
* @property fullscreen
* @param boolean
* @tparam boolean fullscreen
* @propemits false false
* @request client geometry fullscreen granted When the client must be resized
* because it became (or stop being) fullscreen.
*/
/**
@ -632,12 +712,12 @@
*
* @DOC_sequences_client_maximized_EXAMPLE@
*
* **Signal:**
*
* * *property::maximized*
*
* @property maximized
* @param boolean
* @tparam boolean maximized
* @propemits false false
* @request client geometry maximized granted When the client must be resized
* because it became (or stop being) maximized.
* @see request::border
*/
/**
@ -645,12 +725,11 @@
*
* @DOC_sequences_client_maximized_horizontal_EXAMPLE@
*
* **Signal:**
*
* * *property::maximized\_horizontal*
*
* @property maximized_horizontal
* @param boolean
* @tparam boolean maximized_horizontal
* @propemits false false
* @request client geometry maximized_horizontal granted When the client must be resized
* because it became (or stop being) maximized horizontally.
*/
/**
@ -658,34 +737,27 @@
*
* @DOC_sequences_client_maximized_vertical_EXAMPLE@
*
* **Signal:**
*
* * *property::maximized\_vertical*
*
* @property maximized_vertical
* @param boolean
* @tparam boolean maximized_vertical
* @propemits false false
* @request client geometry maximized_vertical granted When the client must be resized
* because it became (or stop being) maximized vertically.
*/
/**
* The client the window is transient for.
*
* **Signal:**
*
* * *property::transient\_for*
*
* @property transient_for
* @param client
* @propemits false false
*/
/**
* Window identification unique to a group of windows.
*
* **Signal:**
*
* * *property::group\_window*
*
* @property group_window
* @param client
* @propemits false false
*/
/**
@ -697,10 +769,6 @@
/**
* A table with size hints of the client.
*
* **Signal:**
*
* * *property::size\_hints*
*
* @property size_hints
* @param table
* @tfield integer table.user_position
@ -713,6 +781,7 @@
* @tfield integer table.min_height
* @tfield integer table.width_inc
* @tfield integer table.height_inc
* @propemits false false
* @see size_hints_honor
*/
@ -727,10 +796,6 @@
* "resize" and "all" are set, this means that all but the resize function
* should be enabled.
*
* **Signal:**
*
* * *property::motif\_wm\_hints*
*
* @property motif_wm_hints
* @param table
* @tfield[opt] table table.functions
@ -751,51 +816,40 @@
* @tfield[opt] string table.input_mode
* @tfield[opt] table table.status
* @tfield[opt] boolean table.status.tearoff_window
* @propemits false false
*/
/**
* Set the client sticky, i.e. available on all tags.
*
* **Signal:**
*
* * *property::sticky*
*
* @property sticky
* @param boolean
* @propemits false false
*/
/**
* Indicate if the client is modal.
*
* **Signal:**
*
* * *property::modal*
*
* @property modal
* @param boolean
* @propemits false false
*/
/**
* True if the client can receive the input focus.
*
* **Signal:**
*
* * *property::focusable*
*
* @property focusable
* @param boolean
* @propemits false false
*/
/**
* The client's bounding shape as set by awesome as a (native) cairo surface.
*
* **Signal:**
*
* * *property::shape\_bounding*
*
* @see gears.surface.apply_shape_bounding
* @property shape_bounding
* @param surface
* @propemits false false
*/
/**
@ -941,27 +995,6 @@
* @see client.geometry
*/
/**
* The border color when the client is focused.
*
* @beautiful beautiful.border_focus
* @param string
*/
/**
* The border color when the client is not focused.
*
* @beautiful beautiful.border_normal
* @param string
*/
/**
* The client border width.
*
* @beautiful beautiful.border_width
* @param integer
*/
/** Return client struts (reserved space at the edge of the screen).
*
* @param struts A table with new strut values, or none.
@ -1217,6 +1250,9 @@ client_unfocus_internal(client_t *c)
globalconf.focus.client = NULL;
luaA_object_push(L, c);
lua_pushboolean(L, false);
luaA_object_emit_signal(L, -2, "property::active", 1);
luaA_object_emit_signal(L, -1, "unfocus", 0);
lua_pop(L, 1);
}
@ -1334,8 +1370,11 @@ client_focus_update(client_t *c)
luaA_object_push(L, c);
client_set_urgent(L, -1, false);
if(focused_new)
if(focused_new) {
lua_pushboolean(L, true);
luaA_object_emit_signal(L, -2, "property::active", 1);
luaA_object_emit_signal(L, -1, "focus", 0);
}
lua_pop(L, 1);
@ -1735,7 +1774,19 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, xcb_get_window_at
luaA_class_emit_signal(L, &client_class, "list", 0);
/* Add the context */
if (globalconf.loop == NULL)
lua_pushstring(L, "startup");
else
lua_pushstring(L, "new");
/* Hints */
lua_newtable(L);
/* client is still on top of the stack; emit signal */
luaA_object_emit_signal(L, -3, "request::manage", 2);
/*TODO v6: remove this*/
luaA_object_emit_signal(L, -1, "manage", 0);
xcb_generic_error_t *error = xcb_request_check(globalconf.connection, reparent_cookie);
@ -1744,7 +1795,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, xcb_get_window_at
NONULL(c->name), NONULL(c->class), NONULL(c->instance));
event_handle((xcb_generic_event_t *) error);
p_delete(&error);
client_unmanage(c, true);
client_unmanage(c, CLIENT_UNMANAGE_FAILED);
}
/* pop client */
@ -2354,10 +2405,10 @@ client_unban(client_t *c)
/** Unmanage a client.
* \param c The client.
* \param window_valid Is the client's window still valid?
* \param reason Why was the unmanage done.
*/
void
client_unmanage(client_t *c, bool window_valid)
client_unmanage(client_t *c, client_unmanage_t reason)
{
lua_State *L = globalconf_get_lua_State();
@ -2384,6 +2435,28 @@ client_unmanage(client_t *c, bool window_valid)
untag_client(c, globalconf.tags.tab[i]);
luaA_object_push(L, c);
/* Give the context to Lua */
switch (reason)
{
break;
case CLIENT_UNMANAGE_USER:
lua_pushstring(L, "user");
break;
case CLIENT_UNMANAGE_REPARENT:
lua_pushstring(L, "reparented");
break;
case CLIENT_UNMANAGE_UNMAP:
case CLIENT_UNMANAGE_FAILED:
case CLIENT_UNMANAGE_DESTROYED:
lua_pushstring(L, "destroyed");
break;
}
/* Hints */
lua_newtable(L);
luaA_object_emit_signal(L, -3, "request::unmanage", 2);
luaA_object_emit_signal(L, -1, "unmanage", 0);
lua_pop(L, 1);
@ -2413,7 +2486,7 @@ client_unmanage(client_t *c, bool window_valid)
/* Clear our event mask so that we don't receive any events from now on,
* especially not for the following requests. */
if(window_valid)
if(reason != CLIENT_UNMANAGE_DESTROYED)
xcb_change_window_attributes(globalconf.connection,
c->window,
XCB_CW_EVENT_MASK,
@ -2423,7 +2496,7 @@ client_unmanage(client_t *c, bool window_valid)
XCB_CW_EVENT_MASK,
(const uint32_t []) { 0 });
if(window_valid)
if(reason != CLIENT_UNMANAGE_DESTROYED)
{
xcb_unmap_window(globalconf.connection, c->window);
xcb_reparent_window(globalconf.connection, c->window, globalconf.screen->root,
@ -2434,7 +2507,7 @@ client_unmanage(client_t *c, bool window_valid)
window_array_append(&globalconf.destroy_later_windows, c->nofocus_window);
window_array_append(&globalconf.destroy_later_windows, c->frame_window);
if(window_valid)
if(reason != CLIENT_UNMANAGE_DESTROYED)
{
/* Remove this window from the save set since this shouldn't be made visible
* after a restart anymore. */
@ -2823,7 +2896,7 @@ static int
luaA_client_unmanage(lua_State *L)
{
client_t *c = luaA_checkudata(L, 1, &client_class);
client_unmanage(c, true);
client_unmanage(c, CLIENT_UNMANAGE_USER);
return 0;
}
@ -4020,4 +4093,6 @@ client_class_setup(lua_State *L)
/* @DOC_cobject_COMMON@ */
/* @DOC_client_theme_COMMON@ */
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -47,6 +47,14 @@ typedef enum {
CLIENT_TITLEBAR_COUNT = 4
} client_titlebar_t;
typedef enum {
CLIENT_UNMANAGE_DESTROYED = 0,
CLIENT_UNMANAGE_USER = 1,
CLIENT_UNMANAGE_REPARENT = 2,
CLIENT_UNMANAGE_UNMAP = 3,
CLIENT_UNMANAGE_FAILED = 4
} client_unmanage_t;
/* Special bit we invented to "fake" unset hints */
#define MWM_HINTS_AWESOME_SET (1L << 15)
@ -206,7 +214,7 @@ void client_ban_unfocus(client_t *);
void client_unban(client_t *);
void client_manage(xcb_window_t, xcb_get_geometry_reply_t *, xcb_get_window_attributes_reply_t *);
bool client_resize(client_t *, area_t, bool);
void client_unmanage(client_t *, bool);
void client_unmanage(client_t *, client_unmanage_t);
void client_kill(client_t *);
void client_set_sticky(lua_State *, int, bool);
void client_set_above(lua_State *, int, bool);

View File

@ -115,6 +115,8 @@
/**
* This signal is emitted when a screen is removed from the setup.
* @signal removed
* @request tag screen removed granted When a screen is removed, `request::screen`
* is called on all screen tags to try to relocate them.
*/
/** This signal is emitted when the list of available screens changes.

View File

@ -203,8 +203,39 @@
#include "ewmh.h"
#include "luaa.h"
/**
/** When a tag requests to be selected.
* @signal request::select
* @tparam string context The reason why it was called.
* @request tag select ewmh granted When the client request to be moved to a
* specific virtual desktop. AwesomeWM interprets virtual desktop as indexed
* tags.
*/
/**
* This signal is emitted to fill the list of default layouts.
*
* It is emitted on the global `tag` class rather than individual tag objects.
* The default handler is part of `rc.lua`. New modules can also use this signal
* to dynamically add new layouts to the list of default layouts.
*
* @signal request::default_layouts
* @tparam string context The context (currently always "startup").
* @classsignal
* @request tag default_layouts startup granted When AwesomeWM starts, it queries
* for default layout using this request.
* @see awful.layout.layouts
* @see awful.layout.append_default_layout
* @see awful.layout.remove_default_layout
*/
/** This signals is emitted when a tag needs layouts for the first time.
*
* If no handler implement it, it will fallback to the content added by
* `request::default_layouts`
*
* @signal request::layouts
* @tparam string context The context (currently always "awful").
* @tparam table hints A, currently empty, table with hints.
*/
/** When a client gets tagged with this tag.

View File

@ -530,15 +530,15 @@ window_class_setup(lua_State *L)
NULL,
(lua_class_propfunc_t) luaA_window_get_window,
NULL);
luaA_class_add_property(&window_class, "opacity",
luaA_class_add_property(&window_class, "_opacity",
(lua_class_propfunc_t) luaA_window_set_opacity,
(lua_class_propfunc_t) luaA_window_get_opacity,
(lua_class_propfunc_t) luaA_window_set_opacity);
luaA_class_add_property(&window_class, "border_color",
luaA_class_add_property(&window_class, "_border_color",
(lua_class_propfunc_t) luaA_window_set_border_color,
(lua_class_propfunc_t) luaA_window_get_border_color,
(lua_class_propfunc_t) luaA_window_set_border_color);
luaA_class_add_property(&window_class, "border_width",
luaA_class_add_property(&window_class, "_border_width",
(lua_class_propfunc_t) luaA_window_set_border_width,
(lua_class_propfunc_t) luaA_window_get_border_width,
(lua_class_propfunc_t) luaA_window_set_border_width);

View File

@ -199,6 +199,7 @@ property_update_wm_hints(client_t *c, xcb_get_property_cookie_t cookie)
luaA_object_push(L, c);
/*TODO v5: Add a context */
lua_pushboolean(L, xcb_icccm_wm_hints_get_urgency(&wmh));
luaA_object_emit_signal(L, -2, "request::urgent", 1);

View File

@ -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"] = {}
@ -11,36 +11,39 @@ describe("awful.ewmh.client_geometry_requests", function()
_G.screen = {
connect_signal = function() end,
}
_G.tag = {
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})

View File

@ -1,6 +1,9 @@
--DOC_GEN_OUTPUT --DOC_GEN_IMAGE --DOC_HIDE
local awful = {placement = require("awful.placement")} --DOC_HIDE
--DOC_HIDE no_offscreen is auto-called when startup is true, avoid this.
awesome.startup = false -- luacheck: globals awesome.startup --DOC_HIDE
local c = client.gen_fake {x = -30, y = -30, width= 100, height=100} --DOC_HIDE
print("Before:", "x="..c.x..", y="..c.y..", width="..c.width..", height="..c.height) --DOC_HIDE

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -70,7 +70,7 @@ function client.gen_fake(args)
ret.type = "normal"
ret.valid = true
ret.size_hints = {}
ret.border_width = 1
ret._border_width = 1
ret.icon_sizes = {{16,16}}
ret.name = "Example Client"
ret._private._struts = { top = 0, right = 0, left = 0, bottom = 0 }
@ -287,7 +287,11 @@ function client.gen_fake(args)
end
})
client.emit_signal("request::manage", ret)
--TODO v6 remove this.
client.emit_signal("manage", ret)
assert(not args.screen or (args.screen == ret.screen))
return ret

View File

@ -15,7 +15,7 @@ local function new_drawin(_, args)
ret.y=0
ret.width=1
ret.height=1
ret.border_width=0
ret._border_width=0
ret.ontop = false
ret.below = false
ret.above = false

View File

@ -0,0 +1,23 @@
--DOC_GEN_OUTPUT --DOC_HIDE
local awful = { layout = require("awful.layout"), --DOC_HIDE
suit= require("awful.layout.suit")} --DOC_HIDE
awful.layout.append_default_layouts({
awful.layout.suit.floating,
awful.layout.suit.tile,
awful.layout.suit.max,
})
for _, l in ipairs(awful.layout.layouts) do
print("Before:", l.name)
end
--DOC_NEWLINE
awful.layout.remove_default_layout(awful.layout.suit.tile)
--DOC_NEWLINE
for _, l in ipairs(awful.layout.layouts) do
print("After:", l.name)
end

View File

@ -0,0 +1,5 @@
Before: floating
Before: tile
Before: max
After: floating
After: max

View File

@ -4,6 +4,7 @@ local hotkeys_widget = require("awful.hotkeys_popup").widget
-- luacheck: globals modkey
local old_c = nil
local called = false
-- Get a tag and a client
@ -322,7 +323,50 @@ local steps = {
end
end
end,
-- Test the `c:activate{}` keybindings.
function()
client.connect_signal("request::activate", function()
called = true
end)
old_c = client.focus
root.fake_input("key_press", "Super_L")
awful.placement.centered(mouse, {parent=old_c})
root.fake_input("button_press",1)
root.fake_input("button_release",1)
root.fake_input("key_release", "Super_L")
return true
end,
function()
if not called then return end
client.focus = nil
called = false
root.fake_input("key_press", "Super_L")
root.fake_input("button_press",1)
root.fake_input("button_release",1)
root.fake_input("key_release", "Super_L")
return true
end,
-- Test resize.
function()
if not called then return end
called = false
root.fake_input("key_press", "Super_L")
root.fake_input("button_press",3)
root.fake_input("button_release",3)
root.fake_input("key_release", "Super_L")
return true
end,
function()
if not called then return end
return true
end
}
require("_runner").run_steps(steps)

View File

@ -133,7 +133,7 @@ table.insert(steps, function()
c1, c2 = client.get()[1], client.get()[2]
-- This should still be the case
assert(client.focus == c1)
assert(c1.active)
c2:emit_signal("request::activate", "i_said_so")
@ -143,11 +143,11 @@ end)
-- Check if writing a focus stealing filter works.
table.insert(steps, function()
-- This should still be the case
assert(client.focus == c2)
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)
@ -158,20 +158,20 @@ end)
table.insert(steps, function()
-- The request should have been denied
assert(client.focus == c2)
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")
return client.focus == c1
return c1.active
end)
local has_error

View File

@ -1,6 +1,4 @@
local awful = require("awful")
local gears = require("gears")
local beautiful = require("beautiful")
local test_client = require("_client")
local runner = require("_runner")
@ -14,8 +12,9 @@ end
local tests = {}
local tb_height = gears.math.round(beautiful.get_font_height() * 1.5)
local border_width = beautiful.border_width
-- Set it to something different than the default to make sure it doesn't change
-- due to some request::border.
local border_width = 3
local class = "test-awful-placement"
local rule = {
@ -24,6 +23,7 @@ local rule = {
},
properties = {
floating = true,
border_width = border_width,
placement = awful.placement.no_overlap + awful.placement.no_offscreen
}
}
@ -40,7 +40,7 @@ end
local function default_test(c, geometry)
check_geometry(c, geometry.expected_x, geometry.expected_y,
geometry.expected_width or geometry.width,
geometry.expected_height or (geometry.height + tb_height))
geometry.expected_height or (geometry.height))
return true
end
@ -242,7 +242,7 @@ for _, tag_num in ipairs{1, 2, 3} do
width = wa.width - 50,
height = 100,
expected_x = wa.x,
expected_y = wa.y + tb_height + 2*border_width + 100
expected_y = wa.y + 2*border_width + 100
}
end
}
@ -258,7 +258,7 @@ for _, tag_num in ipairs{1, 2, 3} do
width = wa.width - 10,
height = wa.height - 50,
expected_x = wa.x,
expected_y = wa.y + 50 - 2*border_width - tb_height
expected_y = (wa.y + wa.height) - (wa.height - 50 + 2*border_width)
}
end
}
@ -270,7 +270,7 @@ for _, tag_num in ipairs{1, 2, 3} do
return {
width = wa.width - 10,
height = wa.height - 50,
expected_x = wa.x + 10 - 2*border_width,
expected_x = (wa.x + wa.width) - (wa.width - 10 + 2*border_width),
expected_y = wa.y
}
end
@ -283,8 +283,8 @@ for _, tag_num in ipairs{1, 2, 3} do
return {
width = wa.width - 10,
height = wa.height - 50,
expected_x = wa.x + 10 - 2*border_width,
expected_y = wa.y + 50 - 2*border_width - tb_height
expected_x = (wa.x + wa.width ) - (wa.width - 10 + 2*border_width),
expected_y = (wa.y + wa.height) - (wa.height - 50 + 2*border_width)
}
end
}

View File

@ -1,6 +1,5 @@
local awful = require("awful")
local gears = require("gears")
local beautiful = require("beautiful")
local test_client = require("_client")
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
@ -10,10 +9,9 @@ local message_printed = false
-- Magic table to store tests
local tests = {}
local tb_height = gears.math.round(beautiful.get_font_height() * 1.5)
-- local border_width = beautiful.border_width
-- Detect "manage" race conditions
-- Detect "request::manage" race conditions
local real_apply = awful.rules.apply
function awful.rules.apply(c)
assert(#c:tags() == 0)
@ -74,7 +72,7 @@ test_rule {
-- The size should not have changed
local geo = get_client_by_class(class):geometry()
assert(geo.width == 100 and geo.height == 100+tb_height)
assert(geo.width == 100 and geo.height == 100)
return true
end

View File

@ -1,5 +1,6 @@
local awful = require("awful")
local gtable = require("gears.table")
local gdebug = require("gears.debug")
local beautiful = require("beautiful")
local function check_order()
@ -64,7 +65,7 @@ local steps = {
client.focus = client.get()[1]
local c = client.focus
assert(c and client.focus == c)
assert(c and c.active)
assert(beautiful.awesome_icon)
local t = awful.tag.add("Test", {clients={c}, icon = beautiful.awesome_icon})
@ -196,6 +197,26 @@ local steps = {
return true
end,
-- Test adding and removing layouts.
function()
local t = mouse.screen.tags[9]
local count = #t.layouts
t:append_layout(awful.layout.suit.floating)
assert(#t.layouts == count + 1)
t:append_layouts({
awful.layout.suit.floating,
awful.layout.suit.floating,
})
assert(#t.layouts == count + 3)
t:remove_layout(awful.layout.suit.floating)
assert(#t.layouts == count)
return true
end
}
local multi_screen_steps = {}
@ -313,6 +334,27 @@ local ms = require("_multi_screen")
ms.disable_wibox()
ms(steps, multi_screen_steps)
-- Check deprecation.
table.insert(steps, function()
assert(#awful.layout.layouts > 0)
local called1, called2 = false, false
gdebug.deprecate = function() called1 = true end
gdebug.print_warning = function() called2 = true end
awful.layout.layouts = {}
assert(called2)
assert(not called1)
assert(#awful.layout.layouts == 0)
-- Test the random property setter.
awful.layout.foo = "bar"
assert(awful.layout.foo == "bar")
return true
end)
require("_runner").run_steps(steps)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -76,7 +76,7 @@ local steps = {
-- Killing the client means the first selected tag counts
function(count)
if count == 1 then
assert(client.focus == c)
assert(c.active)
c:kill()
c = nil
return

View File

@ -3,10 +3,11 @@
local runner = require("_runner")
local awful = require("awful")
local gdebug = require("gears.debug")
local beautiful = require("beautiful")
beautiful.border_normal = "#0000ff"
beautiful.border_focus = "#00ff00"
beautiful.border_color_normal = "#0000ff"
beautiful.border_color_active = "#00ff00"
client.connect_signal("focus", function(c)
c.border_color = "#ff0000"
@ -64,8 +65,36 @@ local steps = {
test("#123456")
test("#12345678")
test("#123456ff", "#123456")
return true
end
end,
function()
assert(client.focus)
local called, called2 = false, false
gdebug.print_warning = function() called = true end
local c2 = client.focus
client.focus.active = false
assert(called)
assert(not client.focus)
assert(not c2.active)
called = false
local real_assert = assert
assert = function() called2 = true end --luacheck: globals assert
c2.active = true
assert = real_assert --luacheck: globals assert
assert(called2)
assert(not called)
assert(c2.active)
assert(client.focus == c2)
return true
end,
}
runner.run_steps(steps)

View File

@ -17,7 +17,7 @@ awful.rules.rules = {
y = 0,
width = 100,
height = 100,
border_color = beautiful.border_normal
border_color = beautiful.border_color_normal
}
}
}
@ -103,7 +103,7 @@ local steps = {
function()
local c = client.get()[1]
assert(not pcall(function() c.border_width = -2000 end))
assert(not pcall(function() c._border_width = -2000 end))
assert(c.border_width==0)
c.border_width = 125

View File

@ -52,7 +52,7 @@ local function create_titlebar(c)
end
-- "Enable" titlebars (so that the titlebar can prevent garbage collection)
client.connect_signal("manage", function (c)
client.connect_signal("request::manage", function (c)
create_titlebar(c)
end)

View File

@ -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})

View File

@ -5,7 +5,7 @@ local test_client = require("_client")
local manage_called, c_snid
client.connect_signal("manage", function(c)
client.connect_signal("request::manage", function(c)
manage_called = true
c_snid = c.startup_id
assert(c.machine == awesome.hostname,

View File

@ -16,7 +16,7 @@ client.connect_signal("property::urgent", function (c)
end)
local manage_cb_done
client.connect_signal("manage", function (c)
client.connect_signal("request::manage", function (c)
manage_cb_done = true
assert(c.class == "XTerm", "Client should be xterm!")
end)
@ -56,7 +56,7 @@ local steps = {
assert(#client.get() == 1)
local c = client.get()[1]
assert(not c.urgent, "Client is not urgent anymore.")
assert(c == client.focus, "Client is focused.")
assert(c.active, "Client is focused.")
assert(awful.tag.getproperty(awful.screen.focused().tags[2], "urgent") == false)
assert(awful.tag.getproperty(awful.screen.focused().tags[2], "urgent_count") == 0)
return true

View File

@ -26,8 +26,8 @@ theme.fg_minimize = "#ffffff"
theme.useless_gap = dpi(0)
theme.border_width = dpi(1)
theme.border_normal = "#000000"
theme.border_focus = "#535d6c"
theme.border_color_normal = "#000000"
theme.border_color_active = "#535d6c"
theme.border_marked = "#91231c"
-- There are other variable sets

View File

@ -120,9 +120,9 @@ theme.fg_minimize = mix(theme.wibar_fg, theme.wibar_bg, 0.9)
theme.bg_systray = theme.wibar_bg
theme.border_normal = theme.gtk.wm_border_unfocused_color
theme.border_focus = theme.gtk.wm_border_focused_color
theme.border_marked = theme.gtk.success_color
theme.border_color_normal = theme.gtk.wm_border_unfocused_color
theme.border_color_active = theme.gtk.wm_border_focused_color
theme.border_color_marked = theme.gtk.success_color
theme.border_width = dpi(theme.gtk.button_border_width or 1)
theme.border_radius = theme.gtk.button_border_radius

View File

@ -27,9 +27,9 @@ theme.fg_minimize = "#2e3436"
theme.useless_gap = dpi(0)
theme.border_width = dpi(2)
theme.border_normal = "#dae3e0"
theme.border_focus = "#729fcf"
theme.border_marked = "#eeeeec"
theme.border_color_normal = "#dae3e0"
theme.border_color_active = "#729fcf"
theme.border_color_marked = "#eeeeec"
-- IMAGES
theme.layout_fairh = themes_path .. "sky/layouts/fairh.png"

View File

@ -29,9 +29,9 @@ theme.fg_minimize = theme.bg_normal
theme.useless_gap = dpi(3)
theme.border_width = dpi(2)
theme.border_normal = xrdb.color0
theme.border_focus = theme.bg_focus
theme.border_marked = xrdb.color10
theme.border_color_normal = xrdb.color0
theme.border_color_active = theme.bg_focus
theme.border_color_marked = xrdb.color10
-- There are other variable sets
-- overriding the default one when

View File

@ -27,9 +27,9 @@ theme.bg_systray = theme.bg_normal
-- {{{ Borders
theme.useless_gap = dpi(0)
theme.border_width = dpi(2)
theme.border_normal = "#3F3F3F"
theme.border_focus = "#6F6F6F"
theme.border_marked = "#CC9393"
theme.border_color_normal = "#3F3F3F"
theme.border_color_active = "#6F6F6F"
theme.border_color_marked = "#CC9393"
-- }}}
-- {{{ Titlebars