client: reimplement client_{ban,unban} for more performance

- From now on clients shall remain mapped for their entire lifetime.
- This should seriously boost tag switching speed with composite active.
- A lesser improvement may be noticed in non-composite situations.
- Titlebars that are set to invisble are still unmapped.
  Since it would clutter the implementation and titlebars are cheap to render.
  Not to mention that invisible titlebars are pretty rare.
- It's safe to attach titlebars while the client is banned.
- Titlebars are explicitly removed at exit.

Signed-off-by: Maarten Maathuis <madman2003@gmail.com>
Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Maarten Maathuis 2008-11-20 22:11:13 +01:00 committed by Julien Danjou
parent dbe05e02ca
commit f9c2ee62a3
8 changed files with 162 additions and 23 deletions

View File

@ -39,6 +39,7 @@
#include "event.h" #include "event.h"
#include "property.h" #include "property.h"
#include "screen.h" #include "screen.h"
#include "titlebar.h"
#include "common/version.h" #include "common/version.h"
#include "common/atoms.h" #include "common/atoms.h"
#include "common/xcursor.h" #include "common/xcursor.h"
@ -79,7 +80,10 @@ awesome_atexit(void)
/* remap all clients since some WM won't handle them otherwise */ /* remap all clients since some WM won't handle them otherwise */
for(c = globalconf.clients; c; c = c->next) for(c = globalconf.clients; c; c = c->next)
{
client_unban(c); client_unban(c);
titlebar_client_detach(c);
}
xcb_flush(globalconf.connection); xcb_flush(globalconf.connection);

113
client.c
View File

@ -158,8 +158,13 @@ client_getbywin(xcb_window_t w)
static void static void
client_unfocus(client_t *c) client_unfocus(client_t *c)
{ {
xcb_window_t root_win = xutil_screen_get(globalconf.connection, c->phys_screen)->root;
globalconf.screens[c->phys_screen].client_focus = NULL; globalconf.screens[c->phys_screen].client_focus = NULL;
/* Set focus on root window, so no events leak to the current window. */
xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT,
root_win, XCB_CURRENT_TIME);
/* Call hook */ /* Call hook */
if(globalconf.hooks.unfocus != LUA_REFNIL) if(globalconf.hooks.unfocus != LUA_REFNIL)
{ {
@ -170,21 +175,45 @@ client_unfocus(client_t *c)
ewmh_update_net_active_window(c->phys_screen); ewmh_update_net_active_window(c->phys_screen);
} }
/** Ban client and unmap it. /** Ban client and move it out of the viewport.
* \param c The client. * \param c The client.
*/ */
void void
client_ban(client_t *c) client_ban(client_t *c)
{ {
if(globalconf.screen_focus->client_focus == c) if(!c->isbanned)
{
/* Move all clients out of the physical viewport into negative coordinate space. */
/* They will all be put on top of each other. */
uint32_t request[2] = { - (c->geometry.width + 2 * c->border),
- (c->geometry.height + 2 * c->border) };
xcb_configure_window(globalconf.connection, c->win,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
request);
/* Do it manually because client geometry remains unchanged. */
if (c->titlebar)
{
simple_window_t *sw = &c->titlebar->sw;
if (sw->window)
{
request[0] = - (sw->geometry.width);
request[1] = - (sw->geometry.height);
/* Move the titlebar to the same place as the window. */
xcb_configure_window(globalconf.connection, sw->window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
request);
}
}
c->isbanned = true;
}
/* Wait until the last moment to take away the focus from the window. */
if (globalconf.screens[c->phys_screen].client_focus == c)
client_unfocus(c); client_unfocus(c);
xcb_unmap_window(globalconf.connection, c->win);
if(c->ishidden)
window_state_set(c->win, XCB_WM_STATE_ICONIC);
else
window_state_set(c->win, XCB_WM_STATE_WITHDRAWN);
if(c->titlebar)
xcb_unmap_window(globalconf.connection, c->titlebar->sw.window);
} }
/** Give focus to client, or to first client if client is NULL. /** Give focus to client, or to first client if client is NULL.
@ -496,6 +525,29 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int phys_screen,
ewmh_update_net_client_list(c->phys_screen); ewmh_update_net_client_list(c->phys_screen);
/* Always stay in NORMAL_STATE. Even though iconified seems more
* appropriate sometimes. The only possible loss is that clients not using
* visibility events may continue to proces data (when banned).
* Without any exposes or other events the cost should be fairly limited though.
*
* Some clients may expect the window to be unmapped when STATE_ICONIFIED.
* Two conflicting parts of the ICCCM v2.0 (section 4.1.4):
*
* "Normal -> Iconic - The client should send a ClientMessage event as described later in this section."
* (note no explicit mention of unmapping, while Normal->Widthdrawn does mention that)
*
* "Once a client's window has left the Withdrawn state, the window will be mapped
* if it is in the Normal state and the window will be unmapped if it is in the Iconic state."
*
* At this stage it's just safer to keep it in normal state and avoid confusion.
*/
window_state_set(c->win, XCB_WM_STATE_NORMAL);
/* Move window outside the viewport before mapping it. */
/* This also sets the state to iconified. */
client_ban(c);
xcb_map_window(globalconf.connection, c->win);
/* Call hook to notify list change */ /* Call hook to notify list change */
if(globalconf.hooks.clients != LUA_REFNIL) if(globalconf.hooks.clients != LUA_REFNIL)
luaA_dofunction(globalconf.L, globalconf.hooks.clients, 0, 0); luaA_dofunction(globalconf.L, globalconf.hooks.clients, 0, 0);
@ -620,6 +672,15 @@ client_resize(client_t *c, area_t geometry, bool hints)
titlebar_update_geometry_floating(c); titlebar_update_geometry_floating(c);
/* The idea is to give a client a resize even when banned. */
/* We just have to move the (x,y) to keep it out of the viewport. */
/* This at least doesn't break expectations about events. */
if (c->isbanned)
{
geometry.x = values[0] = - (geometry.width + 2 * c->border);
geometry.y = values[1] = - (geometry.height + 2 * c->border);
}
xcb_configure_window(globalconf.connection, c->win, xcb_configure_window(globalconf.connection, c->win,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
@ -813,20 +874,38 @@ client_saveprops_tags(client_t *c)
xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, c->win, _AWESOME_TAGS, STRING, 8, i, prop); xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, c->win, _AWESOME_TAGS, STRING, 8, i, prop);
} }
/** Unban a client. /** Unban a client and move it back into the viewport.
* \param c The client. * \param c The client.
*/ */
void void
client_unban(client_t *c) client_unban(client_t *c)
{ {
xcb_map_window(globalconf.connection, c->win); if(c->isbanned)
window_state_set(c->win, XCB_WM_STATE_NORMAL);
if(c->titlebar)
{ {
if(c->isfullscreen || !c->titlebar->isvisible) /* Move the client back where it belongs. */
xcb_unmap_window(globalconf.connection, c->titlebar->sw.window); uint32_t request[2] = { c->geometry.x, c->geometry.y };
else
xcb_map_window(globalconf.connection, c->titlebar->sw.window); xcb_configure_window(globalconf.connection, c->win,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
request);
window_configure(c->win, c->geometry, c->border);
/* Do this manually because the system doesn't know we moved the toolbar.
* Note that !isvisible titlebars are unmapped and for fullscreen it'll
* end up offscreen anyway. */
if(c->titlebar)
{
simple_window_t *sw = &c->titlebar->sw;
/* All resizing is done, so only move now. */
request[0] = sw->geometry.x;
request[1] = sw->geometry.y;
xcb_configure_window(globalconf.connection, sw->window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
request);
}
c->isbanned = false;
} }
} }

View File

@ -127,11 +127,23 @@ client_isfloating(client_t *c)
* \return true if the client is visible, false otherwise. * \return true if the client is visible, false otherwise.
*/ */
static inline bool static inline bool
client_isvisible(client_t *c, int screen) client_isvisible_exclude_banned(client_t *c, int screen)
{ {
return (!c->ishidden && !c->isminimized && client_maybevisible(c, screen)); return (!c->ishidden && !c->isminimized && client_maybevisible(c, screen));
} }
/** Returns true if a client is tagged
* with one of the tags of the specified screen and is not hidden or banned.
* \param c The client to check.
* \param screen Virtual screen number.
* \return true if the client is visible, false otherwise.
*/
static inline bool
client_isvisible(client_t *c, int screen)
{
return (client_isvisible_exclude_banned(c, screen) && !c->isbanned);
}
/** Check if a client has strut information. /** Check if a client has strut information.
* \param c A client. * \param c A client.
* \return A boolean value, true if the client has strut information. * \return A boolean value, true if the client has strut information.

View File

@ -40,7 +40,7 @@ arrange(int screen)
for(c = globalconf.clients; c; c = c->next) for(c = globalconf.clients; c; c = c->next)
{ {
if(client_isvisible(c, screen)) if(client_isvisible_exclude_banned(c, screen))
client_unban(c); client_unban(c);
/* we don't touch other screens windows */ /* we don't touch other screens windows */
else if(c->screen == screen) else if(c->screen == screen)

View File

@ -181,6 +181,10 @@ struct client_t
bool ismodal; bool ismodal;
/** True if the client is on top */ /** True if the client is on top */
bool isontop; bool isontop;
/** True if a client is banned to a position outside the viewport.
* Note that the geometry remains unchanged and that the window is still mapped.
*/
bool isbanned;
/** true if the client must be skipped from task bar client list */ /** true if the client must be skipped from task bar client list */
bool skiptb; bool skiptb;
/** True if the client cannot have focus */ /** True if the client cannot have focus */

View File

@ -200,7 +200,6 @@ titlebar_client_attach(client_t *c, wibox_t *t)
break; break;
} }
titlebar_geometry_compute(c, c->geometry, &wingeom); titlebar_geometry_compute(c, c->geometry, &wingeom);
simplewindow_init(&t->sw, c->phys_screen, simplewindow_init(&t->sw, c->phys_screen,
@ -210,6 +209,9 @@ titlebar_client_attach(client_t *c, wibox_t *t)
t->need_update = true; t->need_update = true;
/* This may seem useless, but it's the cleanest way to avoid seeing titlebars for banned clients. */
titlebar_update_geometry_floating(c);
if(t->isvisible) if(t->isvisible)
xcb_map_window(globalconf.connection, t->sw.window); xcb_map_window(globalconf.connection, t->sw.window);
@ -218,6 +220,29 @@ titlebar_client_attach(client_t *c, wibox_t *t)
} }
} }
/** Map or unmap a titlebar wibox.
* \param t The wibox/titlebar.
* \param visible The new state of the titlebar.
*/
void
titlebar_set_visible(wibox_t *t, bool visible)
{
if (visible != t->isvisible)
{
/* The price of (un)mapping something small like a titlebar is pretty cheap.
* It would complicate matters if this rare case was treated like clients.
* Clients are moved out of the viewport when banned.
*/
if ((t->isvisible = visible))
xcb_map_window(globalconf.connection, t->sw.window);
else
xcb_unmap_window(globalconf.connection, t->sw.window);
globalconf.screens[t->screen].need_arrange = true;
client_stack();
}
}
/** Titlebar newindex. /** Titlebar newindex.
* \param L The Lua VM state. * \param L The Lua VM state.
* \param titlebar The wibox titlebar. * \param titlebar The wibox titlebar.

View File

@ -30,6 +30,7 @@ void titlebar_geometry_compute(client_t *, area_t, area_t *);
void titlebar_init(client_t *); void titlebar_init(client_t *);
void titlebar_client_detach(client_t *); void titlebar_client_detach(client_t *);
void titlebar_client_attach(client_t *, wibox_t *); void titlebar_client_attach(client_t *, wibox_t *);
void titlebar_set_visible(wibox_t *t, bool visible);
int luaA_titlebar_newindex(lua_State *, wibox_t *, awesome_token_t); int luaA_titlebar_newindex(lua_State *, wibox_t *, awesome_token_t);
@ -130,7 +131,22 @@ titlebar_update_geometry_tiled(client_t *c, area_t geometry)
return; return;
titlebar_geometry_compute(c, geometry, &geom); titlebar_geometry_compute(c, geometry, &geom);
wibox_moveresize(c->titlebar, geom); /* Can't actually move titlebar right now, but we will resize it. */
if(c->isbanned)
{
area_t moved_geom = geom;
/* Make sure it stays outside the viewport. */
moved_geom.x = - geom.width;
moved_geom.y = - geom.height;
wibox_moveresize(c->titlebar, moved_geom);
/* Store the real geometry. */
c->titlebar->sw.geometry = geom;
}
else
wibox_moveresize(c->titlebar, geom);
} }
/** Update the titlebar geometry for a floating client. /** Update the titlebar geometry for a floating client.

View File

@ -1004,8 +1004,7 @@ luaA_wibox_newindex(lua_State *L)
wibox_setvisible(*wibox, b); wibox_setvisible(*wibox, b);
break; break;
case WIBOX_TYPE_TITLEBAR: case WIBOX_TYPE_TITLEBAR:
(*wibox)->isvisible = b; titlebar_set_visible(*wibox, b);
globalconf.screens[(*wibox)->screen].need_arrange = true;
break; break;
} }
break; break;