Bugfix: Correctly set the _NET_CLIENT_LIST_STACKING hint (fixes chromium tabbar)
Fixes #287
This commit is contained in:
parent
04a4d7c44a
commit
192dbdabd6
|
@ -11,6 +11,7 @@ xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR)
|
||||||
xmacro(_NET_WM_WINDOW_TYPE_SPLASH)
|
xmacro(_NET_WM_WINDOW_TYPE_SPLASH)
|
||||||
xmacro(_NET_WM_DESKTOP)
|
xmacro(_NET_WM_DESKTOP)
|
||||||
xmacro(_NET_WM_STRUT_PARTIAL)
|
xmacro(_NET_WM_STRUT_PARTIAL)
|
||||||
|
xmacro(_NET_CLIENT_LIST_STACKING)
|
||||||
xmacro(_NET_CURRENT_DESKTOP)
|
xmacro(_NET_CURRENT_DESKTOP)
|
||||||
xmacro(_NET_ACTIVE_WINDOW)
|
xmacro(_NET_ACTIVE_WINDOW)
|
||||||
xmacro(_NET_WORKAREA)
|
xmacro(_NET_WORKAREA)
|
||||||
|
|
|
@ -39,4 +39,16 @@ void ewmh_update_active_window(xcb_window_t window);
|
||||||
*/
|
*/
|
||||||
void ewmh_update_workarea();
|
void ewmh_update_workarea();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the _NET_CLIENT_LIST_STACKING hint. Necessary to move tabs in
|
||||||
|
* Chromium correctly.
|
||||||
|
*
|
||||||
|
* EWMH: These arrays contain all X Windows managed by the Window Manager.
|
||||||
|
* _NET_CLIENT_LIST has initial mapping order, starting with the oldest window.
|
||||||
|
* _NET_CLIENT_LIST_STACKING has bottom-to-top stacking order. These properties
|
||||||
|
* SHOULD be set and updated by the Window Manager.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ewmh_update_client_list_stacking(xcb_window_t *stack, int num_windows);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
17
src/ewmh.c
17
src/ewmh.c
|
@ -110,3 +110,20 @@ void ewmh_update_workarea() {
|
||||||
free(workarea);
|
free(workarea);
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the _NET_CLIENT_LIST_STACKING hint.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ewmh_update_client_list_stacking(xcb_window_t *stack, int num_windows) {
|
||||||
|
DLOG("Updating _NET_CLIENT_LIST_STACKING\n");
|
||||||
|
xcb_change_property(
|
||||||
|
conn,
|
||||||
|
XCB_PROP_MODE_REPLACE,
|
||||||
|
root,
|
||||||
|
A__NET_CLIENT_LIST_STACKING,
|
||||||
|
A_WINDOW,
|
||||||
|
32,
|
||||||
|
num_windows,
|
||||||
|
stack);
|
||||||
|
}
|
||||||
|
|
|
@ -397,7 +397,7 @@ int main(int argc, char *argv[]) {
|
||||||
#include "atoms.xmacro"
|
#include "atoms.xmacro"
|
||||||
#undef xmacro
|
#undef xmacro
|
||||||
};
|
};
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, A_ATOM, 32, 15, supported_atoms);
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, A_ATOM, 32, 16, supported_atoms);
|
||||||
/* Set up the window manager’s name */
|
/* Set up the window manager’s name */
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTING_WM_CHECK, A_WINDOW, 32, 1, &root);
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTING_WM_CHECK, A_WINDOW, 32, 1, &root);
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
|
||||||
|
|
39
src/x.c
39
src/x.c
|
@ -7,6 +7,11 @@
|
||||||
/* Stores the X11 window ID of the currently focused window */
|
/* Stores the X11 window ID of the currently focused window */
|
||||||
xcb_window_t focused_id = XCB_NONE;
|
xcb_window_t focused_id = XCB_NONE;
|
||||||
|
|
||||||
|
/* The bottom-to-top window stack of all windows which are managed by i3.
|
||||||
|
* Used for x_get_window_stack(). */
|
||||||
|
static xcb_window_t *btt_stack;
|
||||||
|
static int btt_stack_num;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Describes the X11 state we may modify (map state, position, window stack).
|
* Describes the X11 state we may modify (map state, position, window stack).
|
||||||
* There is one entry per container. The state represents the current situation
|
* There is one entry per container. The state represents the current situation
|
||||||
|
@ -21,6 +26,9 @@ typedef struct con_state {
|
||||||
bool unmap_now;
|
bool unmap_now;
|
||||||
bool child_mapped;
|
bool child_mapped;
|
||||||
|
|
||||||
|
/** The con for which this state is. */
|
||||||
|
Con *con;
|
||||||
|
|
||||||
/* For reparenting, we have a flag (need_reparent) and the X ID of the old
|
/* For reparenting, we have a flag (need_reparent) and the X ID of the old
|
||||||
* frame this window was in. The latter is necessary because we need to
|
* frame this window was in. The latter is necessary because we need to
|
||||||
* ignore UnmapNotify events (by changing the window event mask). */
|
* ignore UnmapNotify events (by changing the window event mask). */
|
||||||
|
@ -112,6 +120,7 @@ void x_reinit(Con *con) {
|
||||||
DLOG("resetting state %p to initial\n", state);
|
DLOG("resetting state %p to initial\n", state);
|
||||||
state->initial = true;
|
state->initial = true;
|
||||||
state->child_mapped = false;
|
state->child_mapped = false;
|
||||||
|
state->con = con;
|
||||||
memset(&(state->window_rect), 0, sizeof(Rect));
|
memset(&(state->window_rect), 0, sizeof(Rect));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +157,9 @@ void x_move_win(Con *src, Con *dest) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state_dest->con = state_src->con;
|
||||||
|
state_src->con = NULL;
|
||||||
|
|
||||||
Rect zero = { 0, 0, 0, 0 };
|
Rect zero = { 0, 0, 0, 0 };
|
||||||
if (memcmp(&(state_dest->window_rect), &(zero), sizeof(Rect)) == 0) {
|
if (memcmp(&(state_dest->window_rect), &(zero), sizeof(Rect)) == 0) {
|
||||||
memcpy(&(state_dest->window_rect), &(state_src->window_rect), sizeof(Rect));
|
memcpy(&(state_dest->window_rect), &(state_src->window_rect), sizeof(Rect));
|
||||||
|
@ -753,14 +765,31 @@ void x_push_changes(Con *con) {
|
||||||
}
|
}
|
||||||
//DLOG("Done, EnterNotify disabled\n");
|
//DLOG("Done, EnterNotify disabled\n");
|
||||||
bool order_changed = false;
|
bool order_changed = false;
|
||||||
|
|
||||||
|
/* count first, necessary to (re)allocate memory for the bottom-to-top
|
||||||
|
* stack afterwards */
|
||||||
|
int cnt = 0;
|
||||||
|
CIRCLEQ_FOREACH_REVERSE(state, &state_head, state)
|
||||||
|
if (state->con && state->con->window)
|
||||||
|
cnt++;
|
||||||
|
|
||||||
|
if (cnt != btt_stack_num) {
|
||||||
|
btt_stack = srealloc(btt_stack, sizeof(xcb_window_t) * cnt);
|
||||||
|
btt_stack_num = cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_window_t *walk = btt_stack;
|
||||||
|
|
||||||
/* X11 correctly represents the stack if we push it from bottom to top */
|
/* X11 correctly represents the stack if we push it from bottom to top */
|
||||||
CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
|
CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
|
||||||
|
if (state->con && state->con->window)
|
||||||
|
memcpy(walk++, &(state->con->window->id), sizeof(xcb_window_t));
|
||||||
|
|
||||||
//DLOG("stack: 0x%08x\n", state->id);
|
//DLOG("stack: 0x%08x\n", state->id);
|
||||||
con_state *prev = CIRCLEQ_PREV(state, state);
|
con_state *prev = CIRCLEQ_PREV(state, state);
|
||||||
con_state *old_prev = CIRCLEQ_PREV(state, old_state);
|
con_state *old_prev = CIRCLEQ_PREV(state, old_state);
|
||||||
if (prev != old_prev)
|
if ((prev != old_prev || state->initial) && prev != CIRCLEQ_END(&state_head)) {
|
||||||
order_changed = true;
|
order_changed = true;
|
||||||
if ((state->initial || order_changed) && prev != CIRCLEQ_END(&state_head)) {
|
|
||||||
DLOG("Stacking 0x%08x above 0x%08x\n", prev->id, state->id);
|
DLOG("Stacking 0x%08x above 0x%08x\n", prev->id, state->id);
|
||||||
uint32_t mask = 0;
|
uint32_t mask = 0;
|
||||||
mask |= XCB_CONFIG_WINDOW_SIBLING;
|
mask |= XCB_CONFIG_WINDOW_SIBLING;
|
||||||
|
@ -771,6 +800,12 @@ void x_push_changes(Con *con) {
|
||||||
}
|
}
|
||||||
state->initial = false;
|
state->initial = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we re-stacked something (or a new window appeared), we need to update
|
||||||
|
* the _NET_CLIENT_LIST_STACKING hint */
|
||||||
|
if (order_changed)
|
||||||
|
ewmh_update_client_list_stacking(btt_stack, btt_stack_num);
|
||||||
|
|
||||||
//DLOG("Re-enabling EnterNotify\n");
|
//DLOG("Re-enabling EnterNotify\n");
|
||||||
values[0] = FRAME_EVENT_MASK;
|
values[0] = FRAME_EVENT_MASK;
|
||||||
CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
|
CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
|
||||||
|
|
Loading…
Reference in New Issue