client: rework all stacking stuff

- Stacking is now per attribute
- Fullscreen does not imply isfloating

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2008-08-21 17:52:44 +02:00
parent cfa9de3126
commit abb497fa56
11 changed files with 221 additions and 128 deletions

233
client.c
View File

@ -33,7 +33,6 @@
#include "screen.h"
#include "titlebar.h"
#include "lua.h"
#include "stack.h"
#include "mouse.h"
#include "systray.h"
#include "layouts/floating.h"
@ -269,6 +268,57 @@ client_focus(client_t *c)
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
}
/** Stack a window below.
* \param c The client.
* \param previous The previous window on the stack.
* \param return The next-previous!
*/
static xcb_window_t
client_stack_below(client_t *c, xcb_window_t previous)
{
uint32_t config_win_vals[2];
config_win_vals[0] = previous;
config_win_vals[1] = XCB_STACK_MODE_BELOW;
if(c->titlebar
&& c->titlebar->sw
&& c->titlebar->position)
{
xcb_configure_window(globalconf.connection,
c->titlebar->sw->window,
XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
config_win_vals);
config_win_vals[0] = c->titlebar->sw->window;
}
xcb_configure_window(globalconf.connection, c->win,
XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
config_win_vals);
config_win_vals[0] = c->win;
return c->win;
}
/** Get the real layer of a client according to its attribute (fullscreen, …)
* \param c The client.
* \return The real layer.
*/
static layer_t
client_layer_translator(client_t *c)
{
if(c->isontop)
return LAYER_ONTOP;
else if(c->ismodal)
return LAYER_MODAL;
else if(c->isfullscreen)
return LAYER_FULLSCREEN;
else if(c->isabove)
return LAYER_ABOVE;
else if(c->isfloating)
return LAYER_FLOAT;
return c->layer;
}
/** Restack clients.
* \todo It might be worth stopping to restack everyone and only stack `c'
* relatively to the first matching in the list.
@ -285,26 +335,11 @@ client_stack(void)
config_win_vals[0] = XCB_NONE;
config_win_vals[1] = XCB_STACK_MODE_BELOW;
/* first stack fullscreen and modal windows */
/* first stack modal and fullscreen windows */
for(layer = LAYER_OUTOFSPACE - 1; layer >= LAYER_FULLSCREEN; layer--)
for(node = globalconf.stack; node; node = node->next)
if(node->client->layer == layer)
{
if(node->client->titlebar
&& node->client->titlebar->sw
&& node->client->titlebar->position)
{
xcb_configure_window(globalconf.connection,
node->client->titlebar->sw->window,
XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
config_win_vals);
config_win_vals[0] = node->client->titlebar->sw->window;
}
xcb_configure_window(globalconf.connection, node->client->win,
XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
config_win_vals);
config_win_vals[0] = node->client->win;
}
if(client_layer_translator(node->client) == layer)
config_win_vals[0] = client_stack_below(node->client, config_win_vals[0]);
/* then stack statusbar window */
for(screen = 0; screen < globalconf.screens_info->nscreen; screen++)
@ -321,34 +356,8 @@ client_stack(void)
/* finally stack everything else */
for(layer = LAYER_FULLSCREEN - 1; layer >= LAYER_DESKTOP; layer--)
for(node = globalconf.stack; node; node = node->next)
if(node->client->layer == layer)
{
if(node->client->titlebar
&& node->client->titlebar->sw
&& node->client->titlebar->position)
{
xcb_configure_window(globalconf.connection,
node->client->titlebar->sw->window,
XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
config_win_vals);
config_win_vals[0] = node->client->titlebar->sw->window;
}
xcb_configure_window(globalconf.connection, node->client->win,
XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE,
config_win_vals);
config_win_vals[0] = node->client->win;
}
}
/** Put client on top of the stack
* \param c The client to raise.
*/
void
client_raise(client_t *c)
{
/* Push c on top of the stack. */
stack_client_push(c);
client_stack();
if(client_layer_translator(node->client) == layer)
config_win_vals[0] = client_stack_below(node->client, config_win_vals[0]);
}
/** Manage a new client.
@ -396,7 +405,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int screen)
c->geometry.y = c->f_geometry.y = c->m_geometry.y = wgeom->y;
c->geometry.width = c->f_geometry.width = c->m_geometry.width = wgeom->width;
c->geometry.height = c->f_geometry.height = c->m_geometry.height = wgeom->height;
c->layer = c->oldlayer = LAYER_TILE;
c->layer = LAYER_TILE;
client_setborder(c, wgeom->border_width);
c->icon = ewmh_window_icon_get_reply(ewmh_icon_cookie);
@ -526,7 +535,7 @@ client_resize(client_t *c, area_t geometry, bool hints)
* stored according to 'value_mask' */
uint32_t values[5];
if(c->titlebar && !c->ismoving && !c->isfloating && layout != layout_floating)
if(c->titlebar && !c->ismoving && !c->isfloating && !c->isfullscreen && layout != layout_floating)
geometry = titlebar_geometry_remove(c->titlebar, c->border, geometry);
if(hints)
@ -566,7 +575,7 @@ client_resize(client_t *c, area_t geometry, bool hints)
|| layout_get_current(new_screen) == layout_floating)
{
titlebar_update_geometry_floating(c);
if(!c->ismax)
if(!c->isfullscreen)
c->f_geometry = geometry;
}
@ -615,21 +624,16 @@ client_setfloating(client_t *c, bool floating)
{
if((c->isfloating = floating))
{
client_setlayer(c, MAX(c->layer, LAYER_FLOAT));
client_resize(c, c->f_geometry, false);
titlebar_update_geometry_floating(c);
if(!c->isfullscreen)
{
client_resize(c, c->f_geometry, false);
titlebar_update_geometry_floating(c);
}
}
else if(c->ismax)
{
c->ismax = false;
client_setlayer(c, c->oldlayer);
client_resize(c, c->m_geometry, false);
}
else
client_setlayer(c, c->oldlayer);
client_need_arrange(c);
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
client_saveprops(c);
client_stack();
}
}
@ -648,6 +652,106 @@ client_setsticky(client_t *c, bool s)
}
}
/** Set a client fullscreen, or not.
* \param c The client.
* \param s Set or not the client fullscreen.
*/
void
client_setfullscreen(client_t *c, bool s)
{
if(c->isfullscreen != s)
{
area_t geometry;
/* become fullscreen! */
if((c->isfullscreen = s))
{
/* disable titlebar and borders */
if(c->titlebar && c->titlebar->sw && (c->titlebar->oldposition = c->titlebar->position))
{
xcb_unmap_window(globalconf.connection, c->titlebar->sw->window);
c->titlebar->position = Off;
}
geometry = screen_area_get(&globalconf.screens[c->screen].geometry,
NULL,
&globalconf.screens[c->screen].padding);
c->m_geometry = c->geometry;
c->oldborder = c->border;
client_setborder(c, 0);
c->noborder = true;
}
else
{
/* restore borders and titlebar */
if(c->titlebar && c->titlebar->sw && (c->titlebar->position = c->titlebar->oldposition))
xcb_map_window(globalconf.connection, c->titlebar->sw->window);
geometry = c->m_geometry;
c->noborder = false;
client_setborder(c, c->oldborder);
client_resize(c, c->m_geometry, false);
}
client_resize(c, geometry, false);
client_need_arrange(c);
client_stack();
}
}
/** Set a client above, or not.
* \param c The client.
* \param s Set or not the client above.
*/
void
client_setabove(client_t *c, bool s)
{
if(c->isabove != s)
{
c->isabove = s;
client_stack();
}
}
/** Set a client below, or not.
* \param c The client.
* \param s Set or not the client below.
*/
void
client_setbelow(client_t *c, bool s)
{
if(c->isbelow != s)
{
c->isbelow = s;
client_stack();
}
}
/** Set a client modal, or not.
* \param c The client.
* \param s Set or not the client moda.
*/
void
client_setmodal(client_t *c, bool s)
{
if(c->ismodal != s)
{
c->ismodal = s;
client_stack();
}
}
/** Set a client ontop, or not.
* \param c The client.
* \param s Set or not the client moda.
*/
void
client_setontop(client_t *c, bool s)
{
if(c->isontop != s)
{
c->isontop = s;
client_stack();
}
}
/** Save client properties as an X property.
* \param c The client.
*/
@ -1207,6 +1311,9 @@ luaA_client_newindex(lua_State *L)
case A_TK_BORDER_WIDTH:
client_setborder(*c, luaL_checknumber(L, 3));
break;
case A_TK_ONTOP:
client_setontop(*c, luaA_checkboolean(L, 3));
break;
case A_TK_BORDER_COLOR:
if((buf = luaL_checklstring(L, 3, &len))
&& xcolor_init_reply(globalconf.connection,
@ -1272,6 +1379,7 @@ luaA_client_newindex(lua_State *L)
* \lfield urgent The client urgent state.
* \lfield focus The focused client.
* \lfield opacity The client opacity between 0 and 1.
* \lfield ontop The client is on top of every other windows.
*/
static int
luaA_client_index(lua_State *L)
@ -1371,6 +1479,9 @@ luaA_client_index(lua_State *L)
case A_TK_FLOATING:
lua_pushboolean(L, (*c)->isfloating);
break;
case A_TK_ONTOP:
lua_pushboolean(L, (*c)->isontop);
break;
case A_TK_STICKY:
lua_pushboolean(L, (*c)->issticky);
break;

View File

@ -25,6 +25,7 @@
#include <xcb/xcb_icccm.h>
#include "structs.h"
#include "stack.h"
#define client_need_arrange(c) \
do { \
@ -38,7 +39,6 @@ bool client_isvisible(client_t *, int);
client_t * client_getbywin(xcb_window_t);
void client_setlayer(client_t *, layer_t);
void client_stack(void);
void client_raise(client_t *);
void client_ban(client_t *);
void client_unban(client_t *);
void client_manage(xcb_window_t, xcb_get_geometry_reply_t *, int);
@ -52,6 +52,11 @@ void client_saveprops(client_t *);
void client_kill(client_t *);
void client_setfloating(client_t *, bool);
void client_setsticky(client_t *, bool);
void client_setabove(client_t *, bool);
void client_setbelow(client_t *, bool);
void client_setmodal(client_t *, bool);
void client_setontop(client_t *, bool);
void client_setfullscreen(client_t *, bool);
void client_setborder(client_t *, int);
int luaA_client_newindex(lua_State *);
@ -60,5 +65,17 @@ int luaA_client_userdata_new(lua_State *, client_t *);
DO_SLIST(client_t, client, client_unref)
/** Put client on top of the stack
* \param c The client to raise.
*/
static inline void
client_raise(client_t *c)
{
/* Push c on top of the stack. */
stack_client_push(c);
client_stack();
}
#endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -39,6 +39,7 @@ ncol
nmaster
name
on
ontop
opacity
pid
plot_data_add

View File

@ -214,7 +214,7 @@ event_handle_configurerequest(void *data __attribute__ ((unused)),
if(geometry.x != c->geometry.x || geometry.y != c->geometry.y
|| geometry.width != c->geometry.width || geometry.height != c->geometry.height)
{
if(c->isfloating || layout_get_current(c->screen) == layout_floating)
if(c->isfloating || c->isfullscreen || layout_get_current(c->screen) == layout_floating)
{
client_resize(c, geometry, false);
titlebar_draw(c);
@ -542,7 +542,7 @@ event_handle_propertynotify(void *data __attribute__ ((unused)),
{
if(ev->atom == WM_TRANSIENT_FOR)
{
if(!c->isfloating)
if(!c->isfloating && !c->isfullscreen)
{
xcb_window_t trans;
xcb_get_wm_transient_for_reply(connection,

59
ewmh.c
View File

@ -266,74 +266,31 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
}
else if(state == _NET_WM_STATE_FULLSCREEN)
{
area_t geometry = c->geometry;
if(set == _NET_WM_STATE_REMOVE)
{
/* restore geometry */
geometry = c->m_geometry;
/* restore borders and titlebar */
if(c->titlebar && c->titlebar->sw && (c->titlebar->position = c->titlebar->oldposition))
xcb_map_window(globalconf.connection, c->titlebar->sw->window);
c->noborder = false;
c->ismax = false;
client_setlayer(c, c->oldlayer);
client_setborder(c, c->oldborder);
client_setfloating(c, c->wasfloating);
}
client_setfullscreen(c, false);
else if(set == _NET_WM_STATE_ADD)
{
geometry = screen_area_get(&globalconf.screens[c->screen].geometry,
NULL,
&globalconf.screens[c->screen].padding);
/* save geometry */
c->m_geometry = c->geometry;
c->wasfloating = c->isfloating;
/* disable titlebar and borders */
if(c->titlebar && c->titlebar->sw && (c->titlebar->oldposition = c->titlebar->position))
{
xcb_unmap_window(globalconf.connection, c->titlebar->sw->window);
c->titlebar->position = Off;
}
c->ismax = true;
c->oldborder = c->border;
client_setborder(c, 0);
c->noborder = true;
c->oldlayer = c->layer;
client_setlayer(c, LAYER_FULLSCREEN);
client_setfloating(c, true);
}
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
client_resize(c, geometry, false);
client_setfullscreen(c, true);
}
else if(state == _NET_WM_STATE_ABOVE)
{
if(set == _NET_WM_STATE_REMOVE)
client_setlayer(c, c->oldlayer);
client_setabove(c, false);
else if(set == _NET_WM_STATE_ADD)
{
c->oldlayer = c->layer;
client_setlayer(c, LAYER_ABOVE);
}
client_setabove(c, true);
}
else if(state == _NET_WM_STATE_BELOW)
{
if(set == _NET_WM_STATE_REMOVE)
client_setlayer(c, c->oldlayer);
client_setbelow(c, false);
else if(set == _NET_WM_STATE_ADD)
{
c->oldlayer = c->layer;
client_setlayer(c, LAYER_BELOW);
}
client_setbelow(c, true);
}
else if(state == _NET_WM_STATE_MODAL)
{
if(set == _NET_WM_STATE_REMOVE)
client_setlayer(c, c->oldlayer);
client_setmodal(c, false);
else if(set == _NET_WM_STATE_ADD)
{
c->oldlayer = c->layer;
client_setlayer(c, LAYER_MODAL);
}
client_setmodal(c, true);
}
else if(state == _NET_WM_STATE_HIDDEN)
{

View File

@ -42,7 +42,6 @@ layout_fibonacci(int screen, int shape)
for(c = globalconf.clients; c; c = c->next)
if(IS_TILED(c, screen))
{
c->ismax = false;
if((i % 2 && geometry.height / 2 > 2 * c->border)
|| (!(i % 2) && geometry.width / 2 > 2 * c->border))
{

View File

@ -31,7 +31,7 @@ layout_floating(int screen)
client_t *c;
for(c = globalconf.clients; c; c = c->next)
if(client_isvisible(c, screen) && !c->ismax)
if(client_isvisible(c, screen) && !c->isfullscreen)
client_resize(c, c->f_geometry, false);
}
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -507,11 +507,9 @@ mouse_client_move(client_t *c, int snap, bool infobox)
mouse_query_pointer(root, &last_x, &last_y, NULL);
/* grab pointer */
if(!mouse_grab_pointer(root, CurMove))
if(c->isfullscreen || !mouse_grab_pointer(root, CurMove))
return;
c->ismax = false;
if(infobox && (c->isfloating || layout == layout_floating))
sw = mouse_infobox_new(c->phys_screen, c->border, c->geometry, &ctx);
@ -956,6 +954,9 @@ mouse_client_resize(client_t *c, corner_t corner, bool infobox)
layout_t *layout;
xcb_screen_t *s;
if(c->isfullscreen)
return;
curtags = tags_get_current(c->screen);
layout = curtags[0]->layout;
s = xutil_screen_get(globalconf.connection, c->phys_screen);
@ -966,7 +967,7 @@ mouse_client_resize(client_t *c, corner_t corner, bool infobox)
if(c->isfixed)
goto bailout;
c->ismax = false;
client_setfullscreen(c, false);
mouse_client_resize_floating(c, corner, infobox);
}

View File

@ -170,7 +170,7 @@ screen_client_moveto(client_t *c, int new_screen, bool doresize)
if(new_f_geometry.y + new_f_geometry.height >= to.y + to.height)
new_f_geometry.y = to.y + to.height - new_f_geometry.height - 2 * c->border;
if(c->ismax)
if(c->isfullscreen)
{
new_geometry = c->geometry;

View File

@ -44,6 +44,7 @@ typedef enum
LAYER_ABOVE,
LAYER_FULLSCREEN,
LAYER_MODAL,
LAYER_ONTOP,
LAYER_OUTOFSPACE
} layer_t;
@ -273,18 +274,24 @@ struct client_t
bool issticky;
/** Has urgency hint */
bool isurgent;
/** Store previous floating state before maximizing */
bool wasfloating;
/** true if the window is floating */
bool isfloating;
/** true if the window is fixed */
bool isfixed;
/** true if the window is maximized */
bool ismax;
/** true if the client is moving */
bool ismoving;
/** True if the client is hidden */
bool ishidden;
/** True if the client is fullscreen */
bool isfullscreen;
/** True if the client is above others */
bool isabove;
/** True if the client is below others */
bool isbelow;
/** True if the client is modal */
bool ismodal;
/** True if the client is on top */
bool isontop;
/** true if the client must be skipped from task bar client list */
bool skiptb;
/** Window of the client */
@ -294,7 +301,7 @@ struct client_t
/** Client physical screen */
int phys_screen;
/** Layer in the stacking order */
layer_t layer, oldlayer;
layer_t layer;
/** Path to an icon */
char *icon_path;
/** Titlebar */

2
tag.h
View File

@ -26,7 +26,7 @@
#include "common/refcount.h"
/** Check if a client is tiled */
#define IS_TILED(client, screen) (client && !client->isfloating && !client->ismax && client_isvisible(client, screen))
#define IS_TILED(client, screen) (client && !client->isfloating && !client->isfullscreen && client_isvisible(client, screen))
/* Contructor, destructor and referencors */
tag_t *tag_new(const char *, ssize_t, layout_t *, double, int, int);