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:
parent
dbe05e02ca
commit
f9c2ee62a3
|
@ -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
113
client.c
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
client.h
14
client.h
|
@ -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.
|
||||||
|
|
2
layout.c
2
layout.c
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
27
titlebar.c
27
titlebar.c
|
@ -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.
|
||||||
|
|
18
titlebar.h
18
titlebar.h
|
@ -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.
|
||||||
|
|
3
wibox.c
3
wibox.c
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue