This is the full thing, with no known regressions.
There is a minor semantics change (which is also changed in the man
page). Mod+m is now used to cycle through maximized clients, while
Mod+Shift+m is used to enable and disable it. The usual cycling avoids
maximized clients (because they are minimized).
The changes fall into:
- correctness fixes (some split up into a separate patch)
- get, is and next functions for maximized windows
- an override layout property
- some hooks to enable and disable the override when appropriate
I suggest you try it out to see the effects.
Sincerely,
Maarten.
>From e0805cf585d9db8573da3d8f695014cc6382d71d Mon Sep 17 00:00:00 2001
From: Maarten Maathuis <[EMAIL PROTECTED]>
Date: Thu, 4 Dec 2008 15:16:38 +0100
Subject: [PATCH] client: Improve handling of transient windows.
Signed-off-by: Maarten Maathuis <[EMAIL PROTECTED]>
---
client.c | 14 ++++++++++----
client.h | 34 ++++++++++++++++++++++++++++++----
2 files changed, 40 insertions(+), 8 deletions(-)
diff --git a/client.c b/client.c
index 68ef4b2..1cf4eea 100644
--- a/client.c
+++ b/client.c
@@ -414,7 +414,7 @@ void
client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int
phys_screen, int screen)
{
xcb_get_property_cookie_t ewmh_icon_cookie;
- client_t *c, *group = NULL;
+ client_t *c, *tc = NULL, *group = NULL;
image_t *icon;
const uint32_t select_input_val[] =
{
@@ -459,8 +459,14 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t
*wgeom, int phys_screen,
property_update_wm_transient_for(c, NULL);
property_update_wm_client_leader(c, NULL);
- if(c->transient_for)
- screen = c->transient_for->screen;
+ /* Recursively find the parent. */
+ if(c->transient_for) {
+ tc = c;
+ do {
+ tc = tc->transient_for;
+ } while (tc->transient_for);
+ screen = tc->screen;
+ }
/* Try to load props, if it fails check for group windows.
* transient_for windows are excluded, because they inherit the parent
tags. */
@@ -489,7 +495,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t
*wgeom, int phys_screen,
if (!c->issticky)
{
if(c->transient_for)
- client_duplicate_tags(c->transient_for, c);
+ client_duplicate_tags(tc, c);
else if (group)
client_duplicate_tags(group, c);
else
diff --git a/client.h b/client.h
index 5e403c0..c6ae25a 100644
--- a/client.h
+++ b/client.h
@@ -79,9 +79,28 @@ DO_SLIST(client_t, client, client_unref)
static inline void
client_raise(client_t *c)
{
+ client_t *tc = c;
+ int i, counter = 0;
+
+ /* Find number of transient layers. */
+ if(c->transient_for) {
+ do {
+ tc = tc->transient_for;
+ counter++;
+ } while (tc->transient_for);
+ }
+
+ /* Push them in reverse order. */
+ while (counter > 0) {
+ tc = c;
+ for (i = 0; i < counter; i++) {
+ tc = tc->transient_for;
+ }
+ stack_client_push(tc);
+ counter--;
+ }
+
/* Push c on top of the stack. */
- if(c->transient_for)
- stack_client_push(c->transient_for);
stack_client_push(c);
client_stack();
}
@@ -92,9 +111,16 @@ client_raise(client_t *c)
static inline void
client_lower(client_t *c)
{
+ client_t *tc = c;
stack_client_append(c);
- if(c->transient_for)
- stack_client_append(c->transient_for);
+ /* Traverse all transient layers. */
+ if(c->transient_for) {
+ do {
+ tc = tc->transient_for;
+ stack_client_append(tc);
+ } while (tc->transient_for);
+ }
+
client_stack();
}
--
1.6.0.4
>From 438f338c998953cd12c2c2007615cfbe5aa6dd83 Mon Sep 17 00:00:00 2001
From: Maarten Maathuis <[EMAIL PROTECTED]>
Date: Thu, 4 Dec 2008 19:11:37 +0100
Subject: [PATCH] client: Improved handling of maximized windows.
Signed-off-by: Maarten Maathuis <[EMAIL PROTECTED]>
---
awesome.1.txt | 4 +-
awesomerc.lua.in | 28 ++++++++++++-
client.h | 9 ++++-
lib/awful/client.lua.in | 57 ++++++++++++++++++++++++-
lib/awful/layout/init.lua.in | 93 +++++++++++++++++++++++++++++++++++++++++-
5 files changed, 183 insertions(+), 8 deletions(-)
diff --git a/awesome.1.txt b/awesome.1.txt
index 52303b0..d911c09 100644
--- a/awesome.1.txt
+++ b/awesome.1.txt
@@ -91,7 +91,7 @@ Clients
Print the client class and instance.
*Mod4 \+ Shift \+ r*::
Redraw the focused window.
-*Mod4 \+ m*::
+*Mod4 \+ Shift \+ m*::
Maximize client.
*Mod4 \+ f*::
Set client fullscreen.
@@ -106,6 +106,8 @@ Navigation
Focus next client.
*Mod4 \+ k*::
Focus previous client.
+*Mod4 \+ m*::
+ Focus next maximized client.
*Mod4 \+ u*::
Focus first urgent client.
*Mod4 \+ Left*::
diff --git a/awesomerc.lua.in b/awesomerc.lua.in
index 61d4ac2..6f202c9 100644
--- a/awesomerc.lua.in
+++ b/awesomerc.lua.in
@@ -217,8 +217,32 @@ keybinding({ modkey, "Control" }, "r", function ()
keybinding({ modkey, "Shift" }, "q", awesome.quit):add()
-- Client manipulation
-keybinding({ modkey }, "m", function () if client.focus then
client.focus.maximized_horizontal = not client.focus.maximized_horizontal
-
client.focus.maximized_vertical = not client.focus.maximized_vertical end
end):add()
+keybinding({ modkey }, "m",
+function()
+ local c = awful.client.next_maximized(1)
+ local cls = {}
+ if c == nil then
+ cls = awful.client.maximized()
+ if #cls > 0 then
+ c = cls[1]
+ end
+ end
+ if c then
+ client.focus = c
+ c:raise()
+ end
+end):add()
+keybinding({ modkey, "Shift" }, "m",
+function()
+ local c = client.focus
+ if c and awful.client.ismaximized(c) then
+ c.maximized_horizontal = false
+ c.maximized_vertical = false
+ elseif c then
+ c.maximized_horizontal = true
+ c.maximized_vertical = true
+ end
+end):add()
keybinding({ modkey }, "f", function () if client.focus then
client.focus.fullscreen = not client.focus.fullscreen end end):add()
keybinding({ modkey, "Shift" }, "c", function () if client.focus then
client.focus:kill() end end):add()
keybinding({ modkey }, "j", function () awful.client.focus.byidx(1); if
client.focus then client.focus:raise() end end):add()
diff --git a/client.h b/client.h
index c6ae25a..2895788 100644
--- a/client.h
+++ b/client.h
@@ -38,10 +38,13 @@ client_delete(client_t **c)
ARRAY_FUNCS(client_t *, client, DO_NOTHING)
DO_RCNT(client_t, client, client_delete)
+/* client_isvisible_exclude_banned was chosen with reason.
+ * Otherwise clients never become visible under certain conditions.
+*/
#define client_need_arrange(c) \
do { \
if(!globalconf.screens[(c)->screen].need_arrange \
- && client_isvisible(c, (c)->screen)) \
+ && client_isvisible_exclude_banned(c, (c)->screen)) \
globalconf.screens[(c)->screen].need_arrange = true; \
} while(0)
@@ -144,6 +147,10 @@ client_isfixed(client_t *c)
static inline bool
client_isvisible_exclude_banned(client_t *c, int screen)
{
+ /* If the parent is invisible, then so should the child. */
+ if(c->transient_for)
+ if(!client_isvisible_exclude_banned(c->transient_for, screen))
+ return false;
return (!c->ishidden && !c->isminimized && client_maybevisible(c, screen));
}
diff --git a/lib/awful/client.lua.in b/lib/awful/client.lua.in
index 5ad971f..0ad9d77 100644
--- a/lib/awful/client.lua.in
+++ b/lib/awful/client.lua.in
@@ -18,6 +18,7 @@ local capi =
client = client,
mouse = mouse,
screen = screen,
+ tag = tag,
hooks = hooks
}
local hooks = require("awful.hooks")
@@ -174,6 +175,38 @@ function focus.history.previous()
if c then capi.client.focus = c end
end
+--- Return true if client is maximized.
+-- @param c The client.
+-- @return A boolean.
+function ismaximized(c)
+ local ismax = false
+
+ if c and (c.maximized_horizontal or c.maximized_vertical) then
+ ismax = true
+ end
+
+ return ismax
+end
+
+--- Get maximized clients from a screen that would otherwise be visible.
+-- This means only maximized clients from the currently selected tags.
+-- @param screen The screen number, or nil for the current screen.
+-- @return A table with maximized clients.
+function maximized(screen)
+ local tls = tag.selectedlist(screen)
+ local cls = {}
+ local mcls = {}
+ for k, t in pairs(tls) do
+ cls = t:clients()
+ for l, c in pairs(cls) do
+ if ismaximized(c) then
+ table.insert(mcls, c)
+ end
+ end
+ end
+ return mcls
+end
+
--- Get visible clients from a screen.
-- @param screen The screen number, or nil for all screens.
-- @return A table with all visible clients.
@@ -203,6 +236,26 @@ function tiled(screen)
return tclients
end
+--- Get a maximized client by it's relative index to the focussed maximized
window.
+-- @usage Set i to 1 to get next, -1 to get previous.
+-- @param i The index.
+-- @param c Optional client.
+-- @return A client, or nil if no client is available.
+function next_maximized(i, c)
+ local sel = c or capi.client.focus
+ if sel and ismaximized(sel) then
+ -- Get maximized clients
+ local cls = maximized(sel.screen)
+ -- Loop upon each client
+ for idx, c in ipairs(cls) do
+ if c == sel then
+ -- Cycle
+ return cls[util.cycle(#cls, idx + i)]
+ end
+ end
+ end
+end
+
--- Get a client by its relative index to the focused window.
-- @usage Set i to 1 to get next, -1 to get previous.
-- @param i The index.
@@ -544,9 +597,7 @@ function floating.get(c)
return data.floating[c]
end
return (c.type ~= "normal"
- or c.fullscreen
- or c.maximized_vertical
- or c.maximized_horizontal)
+ or c.fullscreen)
end
end
diff --git a/lib/awful/layout/init.lua.in b/lib/awful/layout/init.lua.in
index 4b0bd40..4496bae 100644
--- a/lib/awful/layout/init.lua.in
+++ b/lib/awful/layout/init.lua.in
@@ -5,12 +5,15 @@
---------------------------------------------------------------------------
-- Grab environment we need
+local pairs = pairs
local ipairs = ipairs
local tag = require("awful.tag")
local util = require("awful.util")
local suit = require("awful.layout.suit")
+local client = require("awful.client")
local capi =
{
+ client = client,
hooks = hooks,
screen = screen
}
@@ -60,7 +63,7 @@ end
-- Register an arrange hook.
local function on_arrange (screen)
local t = tag.selected(screen)
- local l = tag.getproperty(t, "layout") or suit.tile
+ local l = tag.getproperty(t, "layout_override") or tag.getproperty(t,
"layout") or suit.tile
l(screen)
end
@@ -85,6 +88,94 @@ function getname(layout)
return layouts_name[layout]
end
+-- Set layout override and also clean up.
+-- Being a local function it shouldn't end up in luadoc.
+-- @param c The client, nil for no override.
+-- @param screen The screen, required.
+-- @param to Optionally, the tag where the override should be set.
+local function set_override(c, screen, to)
+ local t = to or tag.selected(screen)
+ local lo = tag.getproperty(t, "layout_override")
+ local co = tag.getproperty(t, "client_override")
+
+ -- Do we need to change?
+ if c ~= co then
+ -- Cleanup first
+ tag.setproperty(t, "layout_override", nil)
+ if co then
+ tag.setproperty(t, "client_override", nil)
+ -- An ex-override window may have become normal
+ if client.ismaximized(co) then
+ co.minimized = true
+ else
+ co.minimized = false
+ end
+ end
+
+ -- New override
+ if c then
+ tag.setproperty(t, "layout_override", suit.max)
+ tag.setproperty(t, "client_override", c)
+ c.minimized = false
+ end
+ end
+end
+
+hooks.focus.register(function(c)
+ local tc = c
+
+ -- Focussing the transient client should also expose the parent
+ if tc.transient_for then
+ while tc.transient_for do
+ tc = tc.transient_for
+ end
+ end
+
+ -- Stay away from floating clients
+ if not client.floating.get(tc) then
+ if client.ismaximized(tc) then
+ set_override(tc, tc.screen)
+ else
+ set_override(nil, tc.screen)
+ end
+ end
+end)
+
+-- We need to make sure any overrides are removed upon untagging.
+-- This covers screen switches and unmanages as well.
+hooks.tagged.register(function(c, t)
+ local tls = c:tags()
+ local co = tag.getproperty(t, "client_override")
+ local done = false
+
+ if co == c then
+ -- Are we part of this tag?
+ for k, t2 in pairs(tls) do
+ if t2 == t then
+ done = true
+ end
+ end
+
+ -- We're not part of this tag
+ if not done then
+ set_override(nil, c.screen, t)
+ end
+ end
+end)
+
+hooks.property.register(function(c, prop)
+ if prop == "maximized_horizontal" or prop == "maximized_vertical" then
+ -- Stay away from floating clients
+ if not client.floating.get(c) then
+ if client.ismaximized(c) then
+ set_override(c, c.screen)
+ else
+ set_override(nil, c.screen)
+ end
+ end
+ end
+end)
+
hooks.arrange.register(on_arrange)
-- vim:
filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
--
1.6.0.4