client: handle struts (a lot) better

- WINDOW_TYPE_DOCK are chosen first.
- Top/Bottom take precedence over Left/Right.
- Struts are automatically updated.
- Automatically avoid overlap with other struts or wibox'es.

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Maarten Maathuis 2009-03-30 19:40:01 +02:00 committed by Julien Danjou
parent addfd7b39f
commit 264a81f3fb
7 changed files with 197 additions and 16 deletions

189
client.c
View File

@ -779,6 +779,195 @@ client_resize(client_t *c, area_t geometry, bool hints)
return false;
}
/** Update the position of all window with struts on a specific screen.
* \param screen The screen that should be processed.
*/
void
client_update_strut_positions(int screen)
{
client_t *c;
area_t allowed_area, geom;
/* Ignore all struts for starters. */
for(c = globalconf.clients; c; c = c->next)
if(c->screen == screen && client_hasstrut(c))
c->ignore_strut = true;
/* Rationale:
* Top and bottom panels are common, so they take precendence.
* WINDOW_TYPE_DOCK really wants to be at the side, so choose them first.
*/
/* WINDOW_TYPE_DOCK: top + bottom. */
for(c = globalconf.clients; c; c = c->next)
{
if(c->screen != screen || !client_hasstrut(c) || c->type != WINDOW_TYPE_DOCK)
continue;
/* Screen area, minus padding, wibox'es and already processed struts. */
allowed_area = screen_area_get(c->screen,
&globalconf.screens[c->screen].wiboxes,
&globalconf.screens[c->screen].padding,
true);
geom = c->geometry;
if(c->strut.top || c->strut.top_start_x || c->strut.top_end_x)
{
geom.y = allowed_area.y;
if(geom.x < allowed_area.x
|| geom.x + geom.width > allowed_area.x + allowed_area.width)
{
geom.x = allowed_area.x;
if(geom.width > allowed_area.width)
geom.width = allowed_area.width;
}
c->ignore_strut = false;
client_resize(c, geom, false);
}
else if(c->strut.bottom || c->strut.bottom_start_x || c->strut.bottom_end_x)
{
geom.y = allowed_area.y + allowed_area.height - geom.height;
if(geom.x < allowed_area.x
|| geom.x + geom.width > allowed_area.x + allowed_area.width)
{
geom.x = allowed_area.x;
if(geom.width > allowed_area.width)
geom.width = allowed_area.width;
}
c->ignore_strut = false;
client_resize(c, geom, false);
}
}
/* WINDOW_TYPE_DOCK: left + right. */
for(c = globalconf.clients; c; c = c->next)
{
if(c->screen != screen || !client_hasstrut(c) || c->type != WINDOW_TYPE_DOCK)
continue;
/* Screen area, minus padding, wibox'es and already processed struts. */
allowed_area = screen_area_get(c->screen,
&globalconf.screens[c->screen].wiboxes,
&globalconf.screens[c->screen].padding,
true);
geom = c->geometry;
if(c->strut.left || c->strut.left_start_y || c->strut.left_end_y)
{
geom.x = allowed_area.x;
if(geom.y < allowed_area.y
|| geom.y + geom.height > allowed_area.y + allowed_area.height)
{
geom.y = allowed_area.y;
if (geom.height > allowed_area.height)
geom.height = allowed_area.height;
}
c->ignore_strut = false;
client_resize(c, geom, false);
}
else if(c->strut.right || c->strut.right_start_y || c->strut.right_end_y)
{
geom.x = allowed_area.x + allowed_area.width - geom.width;
if(geom.y < allowed_area.y
|| geom.y + geom.height > allowed_area.y + allowed_area.height)
{
geom.y = allowed_area.y;
if (geom.height > allowed_area.height)
geom.height = allowed_area.height;
}
c->ignore_strut = false;
client_resize(c, geom, false);
}
}
/* not WINDOW_TYPE_DOCK: top + bottom. */
for(c = globalconf.clients; c; c = c->next)
{
if(c->screen != screen || !client_hasstrut(c) || c->type == WINDOW_TYPE_DOCK)
continue;
/* Screen area, minus padding, wibox'es and already processed struts. */
allowed_area = screen_area_get(c->screen,
&globalconf.screens[c->screen].wiboxes,
&globalconf.screens[c->screen].padding,
true);
geom = c->geometry;
if(c->strut.top || c->strut.top_start_x || c->strut.top_end_x)
{
geom.y = allowed_area.y;
if(geom.x < allowed_area.x
|| geom.x + geom.width > allowed_area.x + allowed_area.width)
{
geom.x = allowed_area.x;
if(geom.width > allowed_area.width)
geom.width = allowed_area.width;
}
c->ignore_strut = false;
client_resize(c, geom, false);
}
else if(c->strut.bottom || c->strut.bottom_start_x || c->strut.bottom_end_x)
{
geom.y = allowed_area.y + allowed_area.height - geom.height;
if(geom.x < allowed_area.x
|| geom.x + geom.width > allowed_area.x + allowed_area.width)
{
geom.x = allowed_area.x;
if(geom.width > allowed_area.width)
geom.width = allowed_area.width;
}
c->ignore_strut = false;
client_resize(c, geom, false);
}
}
/* not WINDOW_TYPE_DOCK: left + right. */
for(c = globalconf.clients; c; c = c->next)
{
if(c->screen != screen || !client_hasstrut(c) || c->type == WINDOW_TYPE_DOCK)
continue;
/* Screen area, minus padding, wibox'es and already processed struts. */
allowed_area = screen_area_get(c->screen,
&globalconf.screens[c->screen].wiboxes,
&globalconf.screens[c->screen].padding,
true);
geom = c->geometry;
if(c->strut.left || c->strut.left_start_y || c->strut.left_end_y)
{
geom.x = allowed_area.x;
if(geom.y < allowed_area.y
|| geom.y + geom.height > allowed_area.y + allowed_area.height)
{
geom.y = allowed_area.y;
if (geom.height > allowed_area.height)
geom.height = allowed_area.height;
}
c->ignore_strut = false;
client_resize(c, geom, false);
}
else if(c->strut.right || c->strut.right_start_y || c->strut.right_end_y)
{
geom.x = allowed_area.x + allowed_area.width - geom.width;
if(geom.y < allowed_area.y
|| geom.y + geom.height > allowed_area.y + allowed_area.height)
{
geom.y = allowed_area.y;
if (geom.height > allowed_area.height)
geom.height = allowed_area.height;
}
c->ignore_strut = false;
client_resize(c, geom, false);
}
}
}
/** Set a client minimized, or not.
* \param c The client.
* \param s Set or not the client minimized.

View File

@ -59,6 +59,7 @@ void client_unban(client_t *);
void client_manage(xcb_window_t, xcb_get_geometry_reply_t *, int, bool);
area_t client_geometry_hints(client_t *, area_t);
bool client_resize(client_t *, area_t, bool);
void client_update_strut_positions(int);
void client_unmanage(client_t *);
void client_kill(client_t *);
void client_setsticky(client_t *, bool);

View File

@ -59,6 +59,8 @@ arrange(int screen)
client_ban(c);
}
client_update_strut_positions(screen);
/* Reset status before calling arrange hook.
* This is needed if you call a function that relies
* on need_arrange while arrange is in progress.

View File

@ -574,18 +574,4 @@ function client.resize(c, corner)
end
end
-- Disable struts when resizing
local function update_struts(c, prop)
if prop == "geometry" then
local struts = c:struts()
struts['left'] = 0
struts['right'] = 0
struts['top'] = 0
struts['bottom'] = 0
c:struts(struts)
end
end
hooks.property.register(update_struts)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -181,7 +181,7 @@ screen_area_get(int screen, wibox_array_t *wiboxes,
{
client_t *c;
for(c = globalconf.clients; c; c = c->next)
if(client_isvisible(c, screen))
if(client_isvisible(c, screen) && !c->ignore_strut)
{
if(c->strut.top_start_x || c->strut.top_end_x)
{

View File

@ -180,6 +180,8 @@ struct client_t
} geometries;
/** Strut */
strut_t strut;
/** Ignore strut temporarily. */
bool ignore_strut;
/** Border width and pre-fullscreen border width */
int border, border_fs;
xcolor_t border_color;

View File

@ -294,8 +294,9 @@ wibox_position_update(wibox_t *wibox)
globalconf.screens[wibox->screen].need_arrange = true;
/* Place wibox'es at the edge of the screen, struts come later. */
area = screen_area_get(wibox->screen, NULL,
&globalconf.screens[wibox->screen].padding, true);
&globalconf.screens[wibox->screen].padding, false);
/* Top and Bottom wibox_t have prio */
if(wibox->position != Floating)