win: split struct win

Currently compton handles window creation event by immediately query all
the information it needs and create a window struct with that
information. However, this is prone to race conditions.

In the future, we want to react to window creation event by creating a
placeholder in the window stack, and only query window information in a
critical section where the X server is grabbed by us.

This commit split struct win into two struct, one as placeholder, the
other for holding actual window information.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-04-17 23:14:45 +01:00
parent 27603343a1
commit bd4c242015
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
17 changed files with 699 additions and 514 deletions

View File

@ -50,7 +50,7 @@ region_t get_damage(session_t *ps, bool all_damage) {
} }
/// paint all windows /// paint all windows
void paint_all_new(session_t *ps, win *const t, bool ignore_damage) { void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
// All painting will be limited to the damage, if _some_ of // All painting will be limited to the damage, if _some_ of
// the paints bleed out of the damage region, it will destroy // the paints bleed out of the damage region, it will destroy
// part of the image we want to reuse // part of the image we want to reuse
@ -98,7 +98,7 @@ void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
// on top of that window. This is used to reduce the number of pixels painted. // on top of that window. This is used to reduce the number of pixels painted.
// //
// Whether this is beneficial is to be determined XXX // Whether this is beneficial is to be determined XXX
for (win *w = t; w; w = w->prev_trans) { for (auto w = t; w; w = w->prev_trans) {
pixman_region32_subtract(&reg_visible, &ps->screen_reg, w->reg_ignore); pixman_region32_subtract(&reg_visible, &ps->screen_reg, w->reg_ignore);
assert(!(w->flags & WIN_FLAGS_IMAGE_ERROR)); assert(!(w->flags & WIN_FLAGS_IMAGE_ERROR));

View File

@ -11,7 +11,7 @@
#include "x.h" #include "x.h"
typedef struct session session_t; typedef struct session session_t;
typedef struct win win; struct managed_win;
struct backend_operations; struct backend_operations;
@ -48,7 +48,7 @@ struct backend_operations {
/// 1) if ps->overlay is not XCB_NONE, use that /// 1) if ps->overlay is not XCB_NONE, use that
/// 2) use ps->root otherwise /// 2) use ps->root otherwise
/// TODO make the target window a parameter /// TODO make the target window a parameter
backend_t *(*init)(session_t *) attr_nonnull(1); backend_t *(*init)(session_t *)attr_nonnull(1);
void (*deinit)(backend_t *backend_data) attr_nonnull(1); void (*deinit)(backend_t *backend_data) attr_nonnull(1);
/// Called when rendering will be stopped for an unknown amount of /// Called when rendering will be stopped for an unknown amount of
@ -129,8 +129,7 @@ struct backend_operations {
// want to break that assumption as for now. We need to reconsider this. // want to break that assumption as for now. We need to reconsider this.
/// Free resources associated with an image data structure /// Free resources associated with an image data structure
void (*release_image)(backend_t *backend_data, void *img_data) void (*release_image)(backend_t *backend_data, void *img_data) attr_nonnull(1, 2);
attr_nonnull(1, 2);
// =========== Query =========== // =========== Query ===========
@ -179,12 +178,11 @@ struct backend_operations {
/// Let the backend hook into the event handling queue /// Let the backend hook into the event handling queue
}; };
typedef backend_t *(*backend_init_fn)(session_t *ps) attr_nonnull(1); typedef backend_t *(*backend_init_fn)(session_t *ps)attr_nonnull(1);
extern struct backend_operations *backend_list[]; extern struct backend_operations *backend_list[];
bool default_is_win_transparent(void *, win *, void *); void paint_all_new(session_t *ps, struct managed_win *const t, bool ignore_damage)
bool default_is_frame_transparent(void *, win *, void *); attr_nonnull(1);
void paint_all_new(session_t *ps, win *const t, bool ignore_damage) attr_nonnull(1);
// vim: set noet sw=8 ts=8 : // vim: set noet sw=8 ts=8 :

View File

@ -279,11 +279,3 @@ default_backend_render_shadow(backend_t *backend_data, int width, int height,
xcb_render_free_picture(backend_data->c, pict); xcb_render_free_picture(backend_data->c, pict);
return ret; return ret;
} }
bool default_is_win_transparent(void *backend_data, win *w, void *win_data) {
return w->mode != WMODE_SOLID;
}
bool default_is_frame_transparent(void *backend_data, win *w, void *win_data) {
return w->frame_opacity != 1;
}

View File

@ -310,7 +310,7 @@ static void attr_unused c2_dump(c2_ptr_t p);
static xcb_atom_t c2_get_atom_type(const c2_l_t *pleaf); static xcb_atom_t c2_get_atom_type(const c2_l_t *pleaf);
static bool c2_match_once(session_t *ps, const win *w, const c2_ptr_t cond); static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_ptr_t cond);
/** /**
* Parse a condition string. * Parse a condition string.
@ -1272,11 +1272,11 @@ static xcb_atom_t c2_get_atom_type(const c2_l_t *pleaf) {
* *
* For internal use. * For internal use.
*/ */
static inline void static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w,
c2_match_once_leaf(session_t *ps, const win *w, const c2_l_t *pleaf, bool *pres, bool *perr) { const c2_l_t *pleaf, bool *pres, bool *perr) {
assert(pleaf); assert(pleaf);
const xcb_window_t wid = (pleaf->tgt_onframe ? w->client_win : w->id); const xcb_window_t wid = (pleaf->tgt_onframe ? w->client_win : w->base.id);
// Return if wid is missing // Return if wid is missing
if (pleaf->predef == C2_L_PUNDEFINED && !wid) { if (pleaf->predef == C2_L_PUNDEFINED && !wid) {
@ -1468,7 +1468,7 @@ c2_match_once_leaf(session_t *ps, const win *w, const c2_l_t *pleaf, bool *pres,
* *
* @return true if matched, false otherwise. * @return true if matched, false otherwise.
*/ */
static bool c2_match_once(session_t *ps, const win *w, const c2_ptr_t cond) { static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_ptr_t cond) {
bool result = false; bool result = false;
bool error = true; bool error = true;
@ -1542,7 +1542,7 @@ static bool c2_match_once(session_t *ps, const win *w, const c2_ptr_t cond) {
* @param pdata a place to return the data * @param pdata a place to return the data
* @return true if matched, false otherwise. * @return true if matched, false otherwise.
*/ */
bool c2_match(session_t *ps, const win *w, const c2_lptr_t *condlst, void **pdata) { bool c2_match(session_t *ps, const struct managed_win *w, const c2_lptr_t *condlst, void **pdata) {
// Then go through the whole linked list // Then go through the whole linked list
for (; condlst; condlst = condlst->next) { for (; condlst; condlst = condlst->next) {
if (c2_match_once(ps, w, condlst->ptr)) { if (c2_match_once(ps, w, condlst->ptr)) {

View File

@ -15,12 +15,12 @@
typedef struct _c2_lptr c2_lptr_t; typedef struct _c2_lptr c2_lptr_t;
typedef struct session session_t; typedef struct session session_t;
typedef struct win win; struct managed_win;
c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data); c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data);
c2_lptr_t *c2_free_lptr(c2_lptr_t *lp); c2_lptr_t *c2_free_lptr(c2_lptr_t *lp);
bool c2_match(session_t *ps, const win *w, const c2_lptr_t *condlst, void **pdata); bool c2_match(session_t *ps, const struct managed_win *w, const c2_lptr_t *condlst, void **pdata);
bool c2_list_postprocess(session_t *ps, c2_lptr_t *list); bool c2_list_postprocess(session_t *ps, c2_lptr_t *list);

View File

@ -391,7 +391,7 @@ typedef struct session {
// === Window related === // === Window related ===
/// A hash table of all windows. /// A hash table of all windows.
win *windows; struct win *windows;
/// Windows in their stacking order /// Windows in their stacking order
struct list_node window_stack; struct list_node window_stack;
/// Pointer to <code>win</code> of current active window. Used by /// Pointer to <code>win</code> of current active window. Used by
@ -399,7 +399,7 @@ typedef struct session {
/// it's more reliable to store the window ID directly here, just in /// it's more reliable to store the window ID directly here, just in
/// case the WM does something extraordinary, but caching the pointer /// case the WM does something extraordinary, but caching the pointer
/// means another layer of complexity. /// means another layer of complexity.
win *active_win; struct managed_win *active_win;
/// Window ID of leader window of currently active window. Used for /// Window ID of leader window of currently active window. Used for
/// subsidiary window detection. /// subsidiary window detection.
xcb_window_t active_leader; xcb_window_t active_leader;
@ -742,34 +742,22 @@ static inline bool bkend_use_glx(session_t *ps) {
return BKEND_GLX == ps->o.backend || BKEND_XR_GLX_HYBRID == ps->o.backend; return BKEND_GLX == ps->o.backend || BKEND_XR_GLX_HYBRID == ps->o.backend;
} }
/**
* Check if a window is really focused.
*/
static inline bool win_is_focused_real(session_t *ps, const win *w) {
return w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->active_win == w;
}
/** /**
* Find out the currently focused window. * Find out the currently focused window.
* *
* @return struct win object of the found window, NULL if not found * @return struct win object of the found window, NULL if not found
*/ */
static inline win *find_focused(session_t *ps) { static inline struct managed_win *find_focused(session_t *ps) {
if (!ps->o.track_focus) if (!ps->o.track_focus) {
return NULL; return NULL;
}
if (ps->active_win && win_is_focused_real(ps, ps->active_win)) if (ps->active_win && win_is_focused_real(ps, ps->active_win)) {
return ps->active_win; return ps->active_win;
}
return NULL; return NULL;
} }
/**
* Check if a rectangle includes the whole screen.
*/
static inline bool rect_is_fullscreen(session_t *ps, int x, int y, int wid, int hei) {
return (x <= 0 && y <= 0 && (x + wid) >= ps->root_width && (y + hei) >= ps->root_height);
}
static void set_ignore(session_t *ps, unsigned long sequence) { static void set_ignore(session_t *ps, unsigned long sequence) {
if (ps->o.show_all_xerrors) if (ps->o.show_all_xerrors)
return; return;
@ -791,23 +779,6 @@ static inline void set_ignore_cookie(session_t *ps, xcb_void_cookie_t cookie) {
set_ignore(ps, cookie.sequence); set_ignore(ps, cookie.sequence);
} }
/**
* Check if a window is a fullscreen window.
*
* It's not using w->border_size for performance measures.
*/
static inline bool win_is_fullscreen(session_t *ps, const win *w) {
return rect_is_fullscreen(ps, w->g.x, w->g.y, w->widthb, w->heightb) &&
(!w->bounding_shaped || w->rounded_corners);
}
/**
* Check if a window will be painted solid.
*/
static inline bool win_is_solid(session_t *ps, const win *w) {
return WMODE_SOLID == w->mode && !ps->o.force_win_blend;
}
/** /**
* Determine if a window has a specific property. * Determine if a window has a specific property.
* *
@ -864,13 +835,6 @@ void vsync_deinit(session_t *ps);
/** @name DBus hooks /** @name DBus hooks
*/ */
///@{ ///@{
void win_set_shadow_force(session_t *ps, win *w, switch_t val);
void win_set_fade_force(session_t *ps, win *w, switch_t val);
void win_set_focused_force(session_t *ps, win *w, switch_t val);
void win_set_invert_color_force(session_t *ps, win *w, switch_t val);
void opts_init_track_focus(session_t *ps); void opts_init_track_focus(session_t *ps);

View File

@ -154,11 +154,11 @@ void cxinerama_upd_scrs(session_t *ps) {
* *
* XXX move to win.c * XXX move to win.c
*/ */
static inline win *find_win_all(session_t *ps, const xcb_window_t wid) { static inline struct managed_win *find_win_all(session_t *ps, const xcb_window_t wid) {
if (!wid || PointerRoot == wid || wid == ps->root || wid == ps->overlay) if (!wid || PointerRoot == wid || wid == ps->root || wid == ps->overlay)
return NULL; return NULL;
win *w = find_win(ps, wid); auto w = find_managed_win(ps, wid);
if (!w) if (!w)
w = find_toplevel(ps, wid); w = find_toplevel(ps, wid);
if (!w) if (!w)
@ -217,8 +217,8 @@ static double fade_timeout(session_t *ps) {
* @param steps steps of fading * @param steps steps of fading
* @return whether we are still in fading mode * @return whether we are still in fading mode
*/ */
static bool run_fade(session_t *ps, win **_w, long steps) { static bool run_fade(session_t *ps, struct managed_win **_w, long steps) {
win *w = *_w; auto w = *_w;
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) { if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
// We are not fading // We are not fading
assert(w->opacity_tgt == w->opacity); assert(w->opacity_tgt == w->opacity);
@ -226,14 +226,14 @@ static bool run_fade(session_t *ps, win **_w, long steps) {
} }
if (!win_should_fade(ps, w)) { if (!win_should_fade(ps, w)) {
log_debug("Window %#010x %s doesn't need fading", w->id, w->name); log_debug("Window %#010x %s doesn't need fading", w->base.id, w->name);
w->opacity = w->opacity_tgt; w->opacity = w->opacity_tgt;
} }
if (w->opacity == w->opacity_tgt) { if (w->opacity == w->opacity_tgt) {
// We have reached target opacity. // We have reached target opacity.
// We don't call win_check_fade_finished here because that could destroy // We don't call win_check_fade_finished here because that could destroy
// the window, but we still need the damage info from this window // the window, but we still need the damage info from this window
log_debug("Fading finished for window %#010x %s", w->id, w->name); log_debug("Fading finished for window %#010x %s", w->base.id, w->name);
return false; return false;
} }
@ -281,11 +281,11 @@ static int should_ignore(session_t *ps, unsigned long sequence) {
*/ */
uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) { uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) {
uint32_t evmask = 0; uint32_t evmask = 0;
win *w = NULL; struct managed_win *w = NULL;
// Check if it's a mapped frame window // Check if it's a mapped frame window
if (WIN_EVMODE_FRAME == mode || if (WIN_EVMODE_FRAME == mode ||
((w = find_win(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) { ((w = find_managed_win(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE; evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE;
if (ps->o.track_focus && !ps->o.use_ewmh_active_win) if (ps->o.track_focus && !ps->o.use_ewmh_active_win)
evmask |= XCB_EVENT_MASK_FOCUS_CHANGE; evmask |= XCB_EVENT_MASK_FOCUS_CHANGE;
@ -302,38 +302,6 @@ uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) {
return evmask; return evmask;
} }
/**
* Find out the WM frame of a client window by querying X.
*
* @param ps current session
* @param wid window ID
* @return struct _win object of the found window, NULL if not found
*/
win *find_toplevel2(session_t *ps, xcb_window_t wid) {
// TODO this should probably be an "update tree", then find_toplevel.
// current approach is a bit more "racy"
win *w = NULL;
// We traverse through its ancestors to find out the frame
while (wid && wid != ps->root && !(w = find_win(ps, wid))) {
xcb_query_tree_reply_t *reply;
// xcb_query_tree probably fails if you run compton when X is somehow
// initializing (like add it in .xinitrc). In this case
// just leave it alone.
reply = xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, wid), NULL);
if (reply == NULL) {
break;
}
wid = reply->parent;
free(reply);
}
return w;
}
/** /**
* Recheck currently focused window and set its <code>w->focused</code> * Recheck currently focused window and set its <code>w->focused</code>
* to true. * to true.
@ -341,7 +309,7 @@ win *find_toplevel2(session_t *ps, xcb_window_t wid) {
* @param ps current session * @param ps current session
* @return struct _win of currently focused window, NULL if not found * @return struct _win of currently focused window, NULL if not found
*/ */
win *recheck_focus(session_t *ps) { struct managed_win *recheck_focus(session_t *ps) {
// Use EWMH _NET_ACTIVE_WINDOW if enabled // Use EWMH _NET_ACTIVE_WINDOW if enabled
if (ps->o.use_ewmh_active_win) { if (ps->o.use_ewmh_active_win) {
update_ewmh_active_win(ps); update_ewmh_active_win(ps);
@ -359,10 +327,10 @@ win *recheck_focus(session_t *ps) {
free(reply); free(reply);
} }
win *w = find_win_all(ps, wid); auto w = find_win_all(ps, wid);
log_trace("%#010" PRIx32 " (%#010lx \"%s\") focused.", wid, log_trace("%#010" PRIx32 " (%#010lx \"%s\") focused.", wid,
(w ? w->id : XCB_NONE), (w ? w->name : NULL)); (w ? w->base.id : XCB_NONE), (w ? w->name : NULL));
// And we set the focus state here // And we set the focus state here
if (w) { if (w) {
@ -418,10 +386,10 @@ static void handle_root_flags(session_t *ps) {
} }
} }
static win *paint_preprocess(session_t *ps, bool *fade_running) { static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
// XXX need better, more general name for `fade_running`. It really // XXX need better, more general name for `fade_running`. It really
// means if fade is still ongoing after the current frame is rendered // means if fade is still ongoing after the current frame is rendered
win *t = NULL; struct managed_win *bottom = NULL;
*fade_running = false; *fade_running = false;
// Fading step calculation // Fading step calculation
@ -438,7 +406,7 @@ static win *paint_preprocess(session_t *ps, bool *fade_running) {
ps->fade_time += steps * ps->o.fade_delta; ps->fade_time += steps * ps->o.fade_delta;
// First, let's process fading // First, let's process fading
list_foreach_safe(win, w, &ps->window_stack, stack_neighbour) { win_stack_foreach_managed_safe(w, &ps->window_stack) {
const winmode_t mode_old = w->mode; const winmode_t mode_old = w->mode;
const bool was_painted = w->to_paint; const bool was_painted = w->to_paint;
const double opacity_old = w->opacity; const double opacity_old = w->opacity;
@ -491,7 +459,7 @@ static win *paint_preprocess(session_t *ps, bool *fade_running) {
// Track whether it's the highest window to paint // Track whether it's the highest window to paint
bool is_highest = true; bool is_highest = true;
bool reg_ignore_valid = true; bool reg_ignore_valid = true;
list_foreach(win, w, &ps->window_stack, stack_neighbour) { win_stack_foreach_managed(w, &ps->window_stack) {
__label__ skip_window; __label__ skip_window;
bool to_paint = true; bool to_paint = true;
// w->to_paint remembers whether this window is painted last time // w->to_paint remembers whether this window is painted last time
@ -520,10 +488,10 @@ static win *paint_preprocess(session_t *ps, bool *fade_running) {
// log_trace("%s %d %d %d", w->name, to_paint, w->opacity, // log_trace("%s %d %d %d", w->name, to_paint, w->opacity,
// w->paint_excluded); // w->paint_excluded);
if ((w->flags & WIN_FLAGS_STALE_IMAGE) != 0 && if ((w->flags & WIN_FLAGS_IMAGE_STALE) != 0 &&
(w->flags & WIN_FLAGS_IMAGE_ERROR) == 0 && to_paint) { (w->flags & WIN_FLAGS_IMAGE_ERROR) == 0 && to_paint) {
// Image needs to be updated, update it. // Image needs to be updated, update it.
w->flags &= ~WIN_FLAGS_STALE_IMAGE; w->flags &= ~WIN_FLAGS_IMAGE_STALE;
if (w->state != WSTATE_UNMAPPING && w->state != WSTATE_DESTROYING) { if (w->state != WSTATE_UNMAPPING && w->state != WSTATE_DESTROYING) {
// Rebind image only when the window does have an image // Rebind image only when the window does have an image
// available // available
@ -584,8 +552,8 @@ static win *paint_preprocess(session_t *ps, bool *fade_running) {
unredir_possible = true; unredir_possible = true;
} }
w->prev_trans = t; w->prev_trans = bottom;
t = w; bottom = w;
// If the screen is not redirected and the window has redir_ignore set, // If the screen is not redirected and the window has redir_ignore set,
// this window should not cause the screen to become redirected // this window should not cause the screen to become redirected
@ -633,7 +601,7 @@ static win *paint_preprocess(session_t *ps, bool *fade_running) {
} }
} }
return t; return bottom;
} }
/** /**
@ -652,7 +620,7 @@ static void rebuild_shadow_exclude_reg(session_t *ps) {
exit(1); exit(1);
} }
static void restack_win(session_t *ps, win *w, xcb_window_t new_above) { static void restack_win(session_t *ps, struct win *w, xcb_window_t new_above) {
xcb_window_t old_above; xcb_window_t old_above;
if (!list_node_is_last(&ps->window_stack, &w->stack_neighbour)) { if (!list_node_is_last(&ps->window_stack, &w->stack_neighbour)) {
@ -661,13 +629,21 @@ static void restack_win(session_t *ps, win *w, xcb_window_t new_above) {
old_above = XCB_NONE; old_above = XCB_NONE;
} }
log_debug("Restack %#010x (%s), old_above: %#010x, new_above: %#010x", w->id, log_debug("Restack %#010x (%s), old_above: %#010x, new_above: %#010x", w->id,
w->name, old_above, new_above); win_get_name_if_managed(w), old_above, new_above);
struct managed_win *mw = NULL;
if (w->managed) {
mw = (struct managed_win *)w;
}
if (old_above != new_above) { if (old_above != new_above) {
w->reg_ignore_valid = false; if (mw) {
rc_region_unref(&w->reg_ignore); mw->reg_ignore_valid = false;
if (!list_node_is_last(&ps->window_stack, &w->stack_neighbour)) { rc_region_unref(&mw->reg_ignore);
auto next_w = list_next_entry(w, stack_neighbour); }
auto next_w = win_stack_find_next_managed(ps, &w->stack_neighbour);
if (next_w) {
next_w->reg_ignore_valid = false; next_w->reg_ignore_valid = false;
rc_region_unref(&next_w->reg_ignore); rc_region_unref(&next_w->reg_ignore);
} }
@ -676,7 +652,7 @@ static void restack_win(session_t *ps, win *w, xcb_window_t new_above) {
if (!new_above) { if (!new_above) {
new_next = &ps->window_stack; new_next = &ps->window_stack;
} else { } else {
win *tmp_w = NULL; struct win *tmp_w = NULL;
HASH_FIND_INT(ps->windows, &new_above, tmp_w); HASH_FIND_INT(ps->windows, &new_above, tmp_w);
if (!tmp_w) { if (!tmp_w) {
@ -692,11 +668,13 @@ static void restack_win(session_t *ps, win *w, xcb_window_t new_above) {
list_move_before(&w->stack_neighbour, new_next); list_move_before(&w->stack_neighbour, new_next);
// add damage for this window // add damage for this window
add_damage_from_win(ps, w); if (mw) {
add_damage_from_win(ps, mw);
}
#ifdef DEBUG_RESTACK #ifdef DEBUG_RESTACK
log_trace("Window stack modified. Current stack:"); log_trace("Window stack modified. Current stack:");
for (win *c = ps->list; c; c = c->next) { for (auto c = ps->list; c; c = c->next) {
const char *desc = ""; const char *desc = "";
if (c->state == WSTATE_DESTROYING) { if (c->state == WSTATE_DESTROYING) {
desc = "(D) "; desc = "(D) ";
@ -709,7 +687,7 @@ static void restack_win(session_t *ps, win *w, xcb_window_t new_above) {
/// Free up all the images and deinit the backend /// Free up all the images and deinit the backend
static void destroy_backend(session_t *ps) { static void destroy_backend(session_t *ps) {
list_foreach_safe(win, w, &ps->window_stack, stack_neighbour) { win_stack_foreach_managed_safe(w, &ps->window_stack) {
// Wrapping up fading in progress // Wrapping up fading in progress
win_skip_fading(ps, &w); win_skip_fading(ps, &w);
@ -757,7 +735,11 @@ static bool initialize_backend(session_t *ps) {
// window_stack shouldn't include window that's not in the hash table at // window_stack shouldn't include window that's not in the hash table at
// this point. Since there cannot be any fading windows. // this point. Since there cannot be any fading windows.
HASH_ITER2(ps->windows, w) { HASH_ITER2(ps->windows, _w) {
if (!_w->managed) {
continue;
}
auto w = (struct managed_win *)_w;
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) { if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
if (!win_bind_image(ps, w)) { if (!win_bind_image(ps, w)) {
w->flags |= WIN_FLAGS_IMAGE_ERROR; w->flags |= WIN_FLAGS_IMAGE_ERROR;
@ -797,8 +779,8 @@ void configure_root(session_t *ps, int width, int height) {
ps->damage = ps->damage_ring + ps->ndamage - 1; ps->damage = ps->damage_ring + ps->ndamage - 1;
// Invalidate reg_ignore from the top // Invalidate reg_ignore from the top
if (!list_is_empty(&ps->window_stack)) { auto top_w = win_stack_find_next_managed(ps, &ps->window_stack);
auto top_w = list_entry(ps->window_stack.next, win, stack_neighbour); if (top_w) {
rc_region_unref(&top_w->reg_ignore); rc_region_unref(&top_w->reg_ignore);
top_w->reg_ignore_valid = false; top_w->reg_ignore_valid = false;
} }
@ -831,7 +813,7 @@ void configure_root(session_t *ps, int width, int height) {
/// Handle configure event of a regular window /// Handle configure event of a regular window
void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) { void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
win *w = find_win(ps, ce->window); auto w = find_managed_win(ps, ce->window);
region_t damage; region_t damage;
pixman_region32_init(&damage); pixman_region32_init(&damage);
@ -843,9 +825,9 @@ void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
w->state == WSTATE_DESTROYING) { w->state == WSTATE_DESTROYING) {
// Only restack the window to make sure we can handle future restack // Only restack the window to make sure we can handle future restack
// notification correctly // notification correctly
restack_win(ps, w, ce->above_sibling); restack_win(ps, &w->base, ce->above_sibling);
} else { } else {
restack_win(ps, w, ce->above_sibling); restack_win(ps, &w->base, ce->above_sibling);
bool factor_change = false; bool factor_change = false;
win_extents(w, &damage); win_extents(w, &damage);
@ -889,14 +871,14 @@ void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
} }
void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce) { void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce) {
win *w = find_win(ps, ce->window); auto w = find_win(ps, ce->window);
xcb_window_t new_above; xcb_window_t new_above;
if (!w) if (!w)
return; return;
if (ce->place == PlaceOnTop) { if (ce->place == PlaceOnTop) {
new_above = list_entry(ps->window_stack.next, win, stack_neighbour)->id; new_above = list_entry(ps->window_stack.next, struct win, stack_neighbour)->id;
} else { } else {
new_above = XCB_NONE; new_above = XCB_NONE;
} }
@ -962,48 +944,6 @@ void force_repaint(session_t *ps) {
*/ */
///@{ ///@{
/**
* Set w->shadow_force of a window.
*/
void win_set_shadow_force(session_t *ps, win *w, switch_t val) {
if (val != w->shadow_force) {
w->shadow_force = val;
win_determine_shadow(ps, w);
queue_redraw(ps);
}
}
/**
* Set w->fade_force of a window.
*
* Doesn't affect fading already in progress
*/
void win_set_fade_force(session_t *ps, win *w, switch_t val) {
w->fade_force = val;
}
/**
* Set w->focused_force of a window.
*/
void win_set_focused_force(session_t *ps, win *w, switch_t val) {
if (val != w->focused_force) {
w->focused_force = val;
win_update_focused(ps, w);
queue_redraw(ps);
}
}
/**
* Set w->invert_color_force of a window.
*/
void win_set_invert_color_force(session_t *ps, win *w, switch_t val) {
if (val != w->invert_color_force) {
w->invert_color_force = val;
win_determine_invert_color(ps, w);
queue_redraw(ps);
}
}
/** /**
* Enable focus tracking. * Enable focus tracking.
*/ */
@ -1017,7 +957,11 @@ void opts_init_track_focus(session_t *ps) {
if (!ps->o.use_ewmh_active_win) { if (!ps->o.use_ewmh_active_win) {
// Start listening to FocusChange events // Start listening to FocusChange events
HASH_ITER2(ps->windows, w) { HASH_ITER2(ps->windows, w) {
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) { if (!w->managed) {
continue;
}
auto mw = (struct managed_win *)w;
if (mw->a.map_state == XCB_MAP_STATE_VIEWABLE) {
xcb_change_window_attributes( xcb_change_window_attributes(
ps->c, w->id, XCB_CW_EVENT_MASK, ps->c, w->id, XCB_CW_EVENT_MASK,
(const uint32_t[]){ (const uint32_t[]){
@ -1053,11 +997,12 @@ void opts_set_no_fading_openclose(session_t *ps, bool newval) {
void update_ewmh_active_win(session_t *ps) { void update_ewmh_active_win(session_t *ps) {
// Search for the window // Search for the window
xcb_window_t wid = wid_get_prop_window(ps, ps->root, ps->atom_ewmh_active_win); xcb_window_t wid = wid_get_prop_window(ps, ps->root, ps->atom_ewmh_active_win);
win *w = find_win_all(ps, wid); auto w = find_win_all(ps, wid);
// Mark the window focused. No need to unfocus the previous one. // Mark the window focused. No need to unfocus the previous one.
if (w) if (w) {
win_set_focused(ps, w, true); win_set_focused(ps, w, true);
}
} }
// === Main === // === Main ===
@ -1437,12 +1382,12 @@ static void fade_timer_callback(EV_P_ ev_timer *w, int revents) {
static void _draw_callback(EV_P_ session_t *ps, int revents) { static void _draw_callback(EV_P_ session_t *ps, int revents) {
if (ps->o.benchmark) { if (ps->o.benchmark) {
if (ps->o.benchmark_wid) { if (ps->o.benchmark_wid) {
win *wi = find_win(ps, ps->o.benchmark_wid); auto w = find_managed_win(ps, ps->o.benchmark_wid);
if (!wi) { if (!w) {
log_fatal("Couldn't find specified benchmark window."); log_fatal("Couldn't find specified benchmark window.");
exit(1); exit(1);
} }
add_damage_from_win(ps, wi); add_damage_from_win(ps, w);
} else { } else {
force_repaint(ps); force_repaint(ps);
} }
@ -1458,7 +1403,7 @@ static void _draw_callback(EV_P_ session_t *ps, int revents) {
// should be redirected. // should be redirected.
bool fade_running = false; bool fade_running = false;
bool was_redirected = ps->redirected; bool was_redirected = ps->redirected;
win *t = paint_preprocess(ps, &fade_running); auto bottom = paint_preprocess(ps, &fade_running);
ps->tmout_unredir_hit = false; ps->tmout_unredir_hit = false;
if (!was_redirected && ps->redirected) { if (!was_redirected && ps->redirected) {
@ -1467,7 +1412,7 @@ static void _draw_callback(EV_P_ session_t *ps, int revents) {
// window would be put into an error state). so we rerun paint_preprocess // window would be put into an error state). so we rerun paint_preprocess
// here to make sure the rendering decision we make is up-to-date // here to make sure the rendering decision we make is up-to-date
log_debug("Re-run paint_preprocess"); log_debug("Re-run paint_preprocess");
t = paint_preprocess(ps, &fade_running); bottom = paint_preprocess(ps, &fade_running);
} }
// Start/stop fade timer depends on whether window are fading // Start/stop fade timer depends on whether window are fading
@ -1482,9 +1427,9 @@ static void _draw_callback(EV_P_ session_t *ps, int revents) {
if (ps->redirected && ps->o.stoppaint_force != ON) { if (ps->redirected && ps->o.stoppaint_force != ON) {
static int paint = 0; static int paint = 0;
if (ps->o.experimental_backends) { if (ps->o.experimental_backends) {
paint_all_new(ps, t, false); paint_all_new(ps, bottom, false);
} else { } else {
paint_all(ps, t, false); paint_all(ps, bottom, false);
} }
paint++; paint++;
@ -2122,21 +2067,29 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
children = NULL; children = NULL;
nchildren = 0; nchildren = 0;
} }
free(reply);
for (int i = 0; i < nchildren; i++) { for (int i = 0; i < nchildren; i++) {
add_win(ps, children[i], i ? children[i - 1] : XCB_NONE); auto w =
add_win_above(ps, children[i], i ? children[i - 1] : XCB_NONE);
fill_win(ps, w);
} }
HASH_ITER2(ps->windows, w) { HASH_ITER2(ps->windows, w) {
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) { assert(!w->is_new);
map_win(ps, w); if (!w->managed) {
continue;
}
auto mw = (struct managed_win *)w;
if (mw->a.map_state == XCB_MAP_STATE_VIEWABLE) {
map_win(ps, mw);
} }
} }
free(reply);
log_trace("Initial stack:"); log_trace("Initial stack:");
list_foreach(win, w, &ps->window_stack, stack_neighbour) { list_foreach(struct win, w, &ps->window_stack, stack_neighbour) {
log_trace("%#010x \"%s\"", w->id, w->name); log_trace("%#010x \"%s\"", w->id,
w->managed ? ((struct managed_win *)w)->name : "(null)");
} }
} }
@ -2186,13 +2139,16 @@ static void session_destroy(session_t *ps) {
// Free window linked list // Free window linked list
list_foreach_safe(win, w, &ps->window_stack, stack_neighbour) { list_foreach_safe(struct win, w, &ps->window_stack, stack_neighbour) {
if (w->state != WSTATE_DESTROYING) { if (!w->destroyed) {
win_ev_stop(ps, w); win_ev_stop(ps, w);
HASH_DEL(ps->windows, w); HASH_DEL(ps->windows, w);
} }
free_win_res(ps, w); if (w->managed) {
auto mw = (struct managed_win *)w;
free_win_res(ps, mw);
}
free(w); free(w);
} }
list_init_head(&ps->window_stack); list_init_head(&ps->window_stack);

View File

@ -42,9 +42,7 @@ uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode);
xcb_window_t find_client_win(session_t *ps, xcb_window_t w); xcb_window_t find_client_win(session_t *ps, xcb_window_t w);
win *find_toplevel2(session_t *ps, xcb_window_t wid); struct managed_win *recheck_focus(session_t *ps);
win *recheck_focus(session_t *ps);
/// Handle configure event of a root window /// Handle configure event of a root window
void configure_root(session_t *ps, int width, int height); void configure_root(session_t *ps, int width, int height);

View File

@ -21,13 +21,13 @@
#include "common.h" #include "common.h"
#include "compiler.h" #include "compiler.h"
#include "config.h" #include "config.h"
#include "list.h"
#include "log.h" #include "log.h"
#include "string_utils.h" #include "string_utils.h"
#include "types.h" #include "types.h"
#include "uthash_extra.h" #include "uthash_extra.h"
#include "utils.h" #include "utils.h"
#include "win.h" #include "win.h"
#include "list.h"
#include "dbus.h" #include "dbus.h"
@ -468,7 +468,7 @@ static bool cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data)
// Get the number of wids we are to include // Get the number of wids we are to include
unsigned count = 0; unsigned count = 0;
HASH_ITER2(ps->windows, w) { HASH_ITER2(ps->windows, w) {
assert(w->state != WSTATE_DESTROYING); assert(!w->destroyed);
++count; ++count;
} }
@ -483,7 +483,7 @@ static bool cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data)
// Build the array // Build the array
cdbus_window_t *pcur = arr; cdbus_window_t *pcur = arr;
HASH_ITER2(ps->windows, w) { HASH_ITER2(ps->windows, w) {
assert(w->state != WSTATE_DESTROYING); assert(!w->destroyed);
*pcur = w->id; *pcur = w->id;
++pcur; ++pcur;
} }
@ -743,7 +743,7 @@ static bool cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
return false; return false;
} }
win *w = find_win(ps, wid); auto w = find_managed_win(ps, wid);
if (!w) { if (!w) {
log_error("Window %#010x not found.", wid); log_error("Window %#010x not found.", wid);
@ -757,14 +757,16 @@ static bool cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
return true; \ return true; \
} }
cdbus_m_win_get_do(id, cdbus_reply_wid); cdbus_m_win_get_do(base.id, cdbus_reply_wid);
// next // next
if (!strcmp("next", target)) { if (!strcmp("next", target)) {
cdbus_reply_wid(ps, msg, cdbus_reply_wid(
(list_node_is_last(&ps->window_stack, &w->stack_neighbour) ps, msg,
(list_node_is_last(&ps->window_stack, &w->base.stack_neighbour)
? 0 ? 0
: list_next_entry(w, stack_neighbour)->id)); : list_entry(w->base.stack_neighbour.next, struct win, stack_neighbour)
->id));
return true; return true;
} }
@ -845,7 +847,7 @@ static bool cdbus_process_win_set(session_t *ps, DBusMessage *msg) {
return false; return false;
} }
win *w = find_win(ps, wid); auto w = find_managed_win(ps, wid);
if (!w) { if (!w) {
log_error("Window %#010x not found.", wid); log_error("Window %#010x not found.", wid);
@ -922,15 +924,17 @@ static bool cdbus_process_find_win(session_t *ps, DBusMessage *msg) {
cdbus_window_t client = XCB_NONE; cdbus_window_t client = XCB_NONE;
if (!cdbus_msg_get_arg(msg, 1, CDBUS_TYPE_WINDOW, &client)) if (!cdbus_msg_get_arg(msg, 1, CDBUS_TYPE_WINDOW, &client))
return false; return false;
win *w = find_toplevel(ps, client); auto w = find_toplevel(ps, client);
if (w) if (w) {
wid = w->id; wid = w->base.id;
}
} }
// Find focused window // Find focused window
else if (!strcmp("focused", target)) { else if (!strcmp("focused", target)) {
win *w = find_focused(ps); auto w = find_focused(ps);
if (w) if (w) {
wid = w->id; wid = w->base.id;
}
} else { } else {
log_error(CDBUS_ERROR_BADTGT_S, target); log_error(CDBUS_ERROR_BADTGT_S, target);
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target); cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
@ -1301,37 +1305,37 @@ static DBusHandlerResult cdbus_process(DBusConnection *c, DBusMessage *msg, void
/** @name Core callbacks /** @name Core callbacks
*/ */
///@{ ///@{
void cdbus_ev_win_added(session_t *ps, win *w) { void cdbus_ev_win_added(session_t *ps, struct win *w) {
struct cdbus_data *cd = ps->dbus_data; struct cdbus_data *cd = ps->dbus_data;
if (cd->dbus_conn) if (cd->dbus_conn)
cdbus_signal_wid(ps, "win_added", w->id); cdbus_signal_wid(ps, "win_added", w->id);
} }
void cdbus_ev_win_destroyed(session_t *ps, win *w) { void cdbus_ev_win_destroyed(session_t *ps, struct win *w) {
struct cdbus_data *cd = ps->dbus_data; struct cdbus_data *cd = ps->dbus_data;
if (cd->dbus_conn) if (cd->dbus_conn)
cdbus_signal_wid(ps, "win_destroyed", w->id); cdbus_signal_wid(ps, "win_destroyed", w->id);
} }
void cdbus_ev_win_mapped(session_t *ps, win *w) { void cdbus_ev_win_mapped(session_t *ps, struct win *w) {
struct cdbus_data *cd = ps->dbus_data; struct cdbus_data *cd = ps->dbus_data;
if (cd->dbus_conn) if (cd->dbus_conn)
cdbus_signal_wid(ps, "win_mapped", w->id); cdbus_signal_wid(ps, "win_mapped", w->id);
} }
void cdbus_ev_win_unmapped(session_t *ps, win *w) { void cdbus_ev_win_unmapped(session_t *ps, struct win *w) {
struct cdbus_data *cd = ps->dbus_data; struct cdbus_data *cd = ps->dbus_data;
if (cd->dbus_conn) if (cd->dbus_conn)
cdbus_signal_wid(ps, "win_unmapped", w->id); cdbus_signal_wid(ps, "win_unmapped", w->id);
} }
void cdbus_ev_win_focusout(session_t *ps, win *w) { void cdbus_ev_win_focusout(session_t *ps, struct win *w) {
struct cdbus_data *cd = ps->dbus_data; struct cdbus_data *cd = ps->dbus_data;
if (cd->dbus_conn) if (cd->dbus_conn)
cdbus_signal_wid(ps, "win_focusout", w->id); cdbus_signal_wid(ps, "win_focusout", w->id);
} }
void cdbus_ev_win_focusin(session_t *ps, win *w) { void cdbus_ev_win_focusin(session_t *ps, struct win *w) {
struct cdbus_data *cd = ps->dbus_data; struct cdbus_data *cd = ps->dbus_data;
if (cd->dbus_conn) if (cd->dbus_conn)
cdbus_signal_wid(ps, "win_focusin", w->id); cdbus_signal_wid(ps, "win_focusin", w->id);

View File

@ -14,7 +14,7 @@
#include <dbus/dbus.h> #include <dbus/dbus.h>
typedef struct session session_t; typedef struct session session_t;
typedef struct win win; struct win;
/** /**
* Return a string representation of a D-Bus message type. * Return a string representation of a D-Bus message type.
@ -34,21 +34,21 @@ bool cdbus_init(session_t *ps, const char *uniq_name);
void cdbus_destroy(session_t *ps); void cdbus_destroy(session_t *ps);
/// Generate dbus win_added signal /// Generate dbus win_added signal
void cdbus_ev_win_added(session_t *ps, win *w); void cdbus_ev_win_added(session_t *ps, struct win *w);
/// Generate dbus win_destroyed signal /// Generate dbus win_destroyed signal
void cdbus_ev_win_destroyed(session_t *ps, win *w); void cdbus_ev_win_destroyed(session_t *ps, struct win *w);
/// Generate dbus win_mapped signal /// Generate dbus win_mapped signal
void cdbus_ev_win_mapped(session_t *ps, win *w); void cdbus_ev_win_mapped(session_t *ps, struct win *w);
/// Generate dbus win_unmapped signal /// Generate dbus win_unmapped signal
void cdbus_ev_win_unmapped(session_t *ps, win *w); void cdbus_ev_win_unmapped(session_t *ps, struct win *w);
/// Generate dbus win_focusout signal /// Generate dbus win_focusout signal
void cdbus_ev_win_focusout(session_t *ps, win *w); void cdbus_ev_win_focusout(session_t *ps, struct win *w);
/// Generate dbus win_focusin signal /// Generate dbus win_focusin signal
void cdbus_ev_win_focusin(session_t *ps, win *w); void cdbus_ev_win_focusin(session_t *ps, struct win *w);
// vim: set noet sw=8 ts=8 : // vim: set noet sw=8 ts=8 :

View File

@ -50,7 +50,7 @@ static inline const char *ev_window_name(session_t *ps, xcb_window_t wid) {
} else if (ps->overlay == wid) { } else if (ps->overlay == wid) {
name = "(Overlay)"; name = "(Overlay)";
} else { } else {
win *w = find_win(ps, wid); auto w = find_managed_win(ps, wid);
if (!w) { if (!w) {
w = find_toplevel(ps, wid); w = find_toplevel(ps, wid);
} }
@ -169,7 +169,8 @@ static inline void ev_focus_out(session_t *ps, xcb_focus_out_event_t *ev) {
static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev) { static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev) {
assert(ev->parent == ps->root); assert(ev->parent == ps->root);
add_win(ps, ev->window, 0); // TODO delay fill_win
fill_win(ps, add_win_top(ps, ev->window));
} }
static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event_t *ev) { static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event_t *ev) {
@ -183,7 +184,7 @@ static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event
} }
static inline void ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *ev) { static inline void ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *ev) {
win *w = find_win(ps, ev->window); auto w = find_managed_win(ps, ev->window);
if (w) { if (w) {
unmap_win(ps, &w, true); unmap_win(ps, &w, true);
} }
@ -199,7 +200,7 @@ static inline void ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) {
} }
static inline void ev_unmap_notify(session_t *ps, xcb_unmap_notify_event_t *ev) { static inline void ev_unmap_notify(session_t *ps, xcb_unmap_notify_event_t *ev) {
win *w = find_win(ps, ev->window); auto w = find_managed_win(ps, ev->window);
if (w) { if (w) {
unmap_win(ps, &w, false); unmap_win(ps, &w, false);
} }
@ -211,12 +212,13 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
if (ev->parent == ps->root) { if (ev->parent == ps->root) {
// new window // new window
add_win(ps, ev->window, 0); // TODO delay fill_win
fill_win(ps, add_win_top(ps, ev->window));
} else { } else {
// otherwise, find and destroy the window first // otherwise, find and destroy the window first
win *w = find_win(ps, ev->window); auto w = find_win(ps, ev->window);
if (w) { if (w && w->managed) {
unmap_win(ps, &w, true); unmap_win(ps, (struct managed_win **)&w, true);
} }
// Reset event mask in case something wrong happens // Reset event mask in case something wrong happens
@ -228,10 +230,10 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
// Firstly, check if it's a known client window // Firstly, check if it's a known client window
if (!find_toplevel(ps, ev->window)) { if (!find_toplevel(ps, ev->window)) {
// If not, look for its frame window // If not, look for its frame window
win *w_top = find_toplevel2(ps, ev->parent); auto w_top = find_toplevel2(ps, ev->parent);
// If found, and the client window has not been determined, or its // If found, and the client window has not been determined, or its
// frame may not have a correct client, continue // frame may not have a correct client, continue
if (w_top && (!w_top->client_win || w_top->client_win == w_top->id)) { if (w_top && (!w_top->client_win || w_top->client_win == w_top->base.id)) {
// If it has WM_STATE, mark it the client window // If it has WM_STATE, mark it the client window
if (wid_has_prop(ps, ev->window, ps->atom_client)) { if (wid_has_prop(ps, ev->window, ps->atom_client)) {
w_top->wmwin = false; w_top->wmwin = false;
@ -328,9 +330,9 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
(const uint32_t[]){determine_evmask( (const uint32_t[]){determine_evmask(
ps, ev->window, WIN_EVMODE_UNKNOWN)}); ps, ev->window, WIN_EVMODE_UNKNOWN)});
win *w_top = find_toplevel2(ps, ev->window); auto w_top = find_toplevel2(ps, ev->window);
// Initialize client_win as early as possible // Initialize client_win as early as possible
if (w_top && (!w_top->client_win || w_top->client_win == w_top->id) && if (w_top && (!w_top->client_win || w_top->client_win == w_top->base.id) &&
wid_has_prop(ps, ev->window, ps->atom_client)) { wid_has_prop(ps, ev->window, ps->atom_client)) {
w_top->wmwin = false; w_top->wmwin = false;
win_unmark_client(ps, w_top); win_unmark_client(ps, w_top);
@ -342,14 +344,14 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
// If _NET_WM_WINDOW_TYPE changes... God knows why this would happen, but // If _NET_WM_WINDOW_TYPE changes... God knows why this would happen, but
// there are always some stupid applications. (#144) // there are always some stupid applications. (#144)
if (ev->atom == ps->atom_win_type) { if (ev->atom == ps->atom_win_type) {
win *w = NULL; struct managed_win *w = NULL;
if ((w = find_toplevel(ps, ev->window))) if ((w = find_toplevel(ps, ev->window)))
win_update_wintype(ps, w); win_update_wintype(ps, w);
} }
// If _NET_WM_OPACITY changes // If _NET_WM_OPACITY changes
if (ev->atom == ps->atom_opacity) { if (ev->atom == ps->atom_opacity) {
win *w = find_win(ps, ev->window) ?: find_toplevel(ps, ev->window); auto w = find_managed_win(ps, ev->window) ?: find_toplevel(ps, ev->window);
if (w) { if (w) {
win_update_opacity_prop(ps, w); win_update_opacity_prop(ps, w);
// we cannot receive OPACITY change when window is destroyed // we cannot receive OPACITY change when window is destroyed
@ -364,7 +366,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
// If frame extents property changes // If frame extents property changes
if (ps->o.frame_opacity > 0 && ev->atom == ps->atom_frame_extents) { if (ps->o.frame_opacity > 0 && ev->atom == ps->atom_frame_extents) {
win *w = find_toplevel(ps, ev->window); auto w = find_toplevel(ps, ev->window);
if (w) { if (w) {
win_update_frame_extents(ps, w, ev->window); win_update_frame_extents(ps, w, ev->window);
// If frame extents change, the window needs repaint // If frame extents change, the window needs repaint
@ -374,7 +376,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
// If name changes // If name changes
if (ps->o.track_wdata && (ps->atom_name == ev->atom || ps->atom_name_ewmh == ev->atom)) { if (ps->o.track_wdata && (ps->atom_name == ev->atom || ps->atom_name_ewmh == ev->atom)) {
win *w = find_toplevel(ps, ev->window); auto w = find_toplevel(ps, ev->window);
if (w && 1 == win_get_name(ps, w)) { if (w && 1 == win_get_name(ps, w)) {
win_on_factor_change(ps, w); win_on_factor_change(ps, w);
} }
@ -382,7 +384,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
// If class changes // If class changes
if (ps->o.track_wdata && ps->atom_class == ev->atom) { if (ps->o.track_wdata && ps->atom_class == ev->atom) {
win *w = find_toplevel(ps, ev->window); auto w = find_toplevel(ps, ev->window);
if (w) { if (w) {
win_get_class(ps, w); win_get_class(ps, w);
win_on_factor_change(ps, w); win_on_factor_change(ps, w);
@ -391,7 +393,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
// If role changes // If role changes
if (ps->o.track_wdata && ps->atom_role == ev->atom) { if (ps->o.track_wdata && ps->atom_role == ev->atom) {
win *w = find_toplevel(ps, ev->window); auto w = find_toplevel(ps, ev->window);
if (w && 1 == win_get_role(ps, w)) { if (w && 1 == win_get_role(ps, w)) {
win_on_factor_change(ps, w); win_on_factor_change(ps, w);
} }
@ -399,15 +401,16 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
// If _COMPTON_SHADOW changes // If _COMPTON_SHADOW changes
if (ps->o.respect_prop_shadow && ps->atom_compton_shadow == ev->atom) { if (ps->o.respect_prop_shadow && ps->atom_compton_shadow == ev->atom) {
win *w = find_win(ps, ev->window); auto w = find_managed_win(ps, ev->window);
if (w) if (w) {
win_update_prop_shadow(ps, w); win_update_prop_shadow(ps, w);
} }
}
// If a leader property changes // If a leader property changes
if ((ps->o.detect_transient && ps->atom_transient == ev->atom) || if ((ps->o.detect_transient && ps->atom_transient == ev->atom) ||
(ps->o.detect_client_leader && ps->atom_client_leader == ev->atom)) { (ps->o.detect_client_leader && ps->atom_client_leader == ev->atom)) {
win *w = find_toplevel(ps, ev->window); auto w = find_toplevel(ps, ev->window);
if (w) { if (w) {
win_update_leader(ps, w); win_update_leader(ps, w);
} }
@ -416,7 +419,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
// Check for other atoms we are tracking // Check for other atoms we are tracking
for (latom_t *platom = ps->track_atom_lst; platom; platom = platom->next) { for (latom_t *platom = ps->track_atom_lst; platom; platom = platom->next) {
if (platom->atom == ev->atom) { if (platom->atom == ev->atom) {
win *w = find_win(ps, ev->window); auto w = find_managed_win(ps, ev->window);
if (!w) if (!w)
w = find_toplevel(ps, ev->window); w = find_toplevel(ps, ev->window);
if (w) if (w)
@ -426,7 +429,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
} }
} }
static inline void repair_win(session_t *ps, win *w) { static inline void repair_win(session_t *ps, struct managed_win *w) {
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) if (w->a.map_state != XCB_MAP_STATE_VIEWABLE)
return; return;
@ -472,18 +475,20 @@ static inline void ev_damage_notify(session_t *ps, xcb_damage_notify_event_t *de
return; return;
} */ } */
win *w = find_win(ps, de->drawable); auto w = find_managed_win(ps, de->drawable);
if (!w) if (!w) {
return; return;
}
repair_win(ps, w); repair_win(ps, w);
} }
static inline void ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev) { static inline void ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev) {
win *w = find_win(ps, ev->affected_window); auto w = find_managed_win(ps, ev->affected_window);
if (!w || w->a.map_state == XCB_MAP_STATE_UNMAPPED) if (!w || w->a.map_state == XCB_MAP_STATE_UNMAPPED) {
return; return;
}
/* /*
* Empty bounding_shape may indicated an * Empty bounding_shape may indicated an

View File

@ -221,7 +221,7 @@ void glx_destroy(session_t *ps) {
return; return;
// Free all GLX resources of windows // Free all GLX resources of windows
list_foreach(win, w, &ps->window_stack, stack_neighbour) { win_stack_foreach_managed(w, &ps->window_stack) {
free_win_res_glx(ps, w); free_win_res_glx(ps, w);
} }

View File

@ -161,7 +161,7 @@ static inline void free_paint_glx(session_t *ps, paint_t *ppaint) {
/** /**
* Free GLX part of win. * Free GLX part of win.
*/ */
static inline void free_win_res_glx(session_t *ps, win *w) { static inline void free_win_res_glx(session_t *ps, struct managed_win *w) {
free_paint_glx(ps, &w->paint); free_paint_glx(ps, &w->paint);
free_paint_glx(ps, &w->shadow_paint); free_paint_glx(ps, &w->shadow_paint);
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL

View File

@ -197,8 +197,8 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, doubl
} }
static inline void static inline void
paint_region(session_t *ps, win *w, int x, int y, int wid, int hei, double opacity, paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, int hei,
const region_t *reg_paint, xcb_render_picture_t pict) { double opacity, const region_t *reg_paint, xcb_render_picture_t pict) {
const int dx = (w ? w->g.x : 0) + x; const int dx = (w ? w->g.x : 0) + x;
const int dy = (w ? w->g.y : 0) + y; const int dy = (w ? w->g.y : 0) + y;
const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend)); const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend));
@ -237,19 +237,19 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) {
/** /**
* Paint a window itself and dim it if asked. * Paint a window itself and dim it if asked.
*/ */
void paint_one(session_t *ps, win *w, const region_t *reg_paint) { void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) {
// Fetch Pixmap // Fetch Pixmap
if (!w->paint.pixmap) { if (!w->paint.pixmap) {
w->paint.pixmap = x_new_id(ps->c); w->paint.pixmap = x_new_id(ps->c);
set_ignore_cookie( set_ignore_cookie(ps, xcb_composite_name_window_pixmap(ps->c, w->base.id,
ps, xcb_composite_name_window_pixmap(ps->c, w->id, w->paint.pixmap)); w->paint.pixmap));
} }
xcb_drawable_t draw = w->paint.pixmap; xcb_drawable_t draw = w->paint.pixmap;
if (!draw) { if (!draw) {
log_error("Failed to get pixmap from window %#010x (%s), window won't be " log_error("Failed to get pixmap from window %#010x (%s), window won't be "
"visible", "visible",
w->id, w->name); w->base.id, w->name);
return; return;
} }
@ -269,12 +269,12 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) {
// causing the jittering issue M4he reported in #7. // causing the jittering issue M4he reported in #7.
if (!paint_bind_tex(ps, &w->paint, 0, 0, false, 0, w->a.visual, if (!paint_bind_tex(ps, &w->paint, 0, 0, false, 0, w->a.visual,
(!ps->o.glx_no_rebind_pixmap && w->pixmap_damaged))) { (!ps->o.glx_no_rebind_pixmap && w->pixmap_damaged))) {
log_error("Failed to bind texture for window %#010x.", w->id); log_error("Failed to bind texture for window %#010x.", w->base.id);
} }
w->pixmap_damaged = false; w->pixmap_damaged = false;
if (!paint_isvalid(ps, &w->paint)) { if (!paint_isvalid(ps, &w->paint)) {
log_error("Window %#010x is missing painting data.", w->id); log_error("Window %#010x is missing painting data.", w->base.id);
return; return;
} }
@ -504,7 +504,7 @@ static void paint_root(session_t *ps, const region_t *reg_paint) {
/** /**
* Generate shadow <code>Picture</code> for a window. * Generate shadow <code>Picture</code> for a window.
*/ */
static bool win_build_shadow(session_t *ps, win *w, double opacity) { static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacity) {
const int width = w->widthb; const int width = w->widthb;
const int height = w->heightb; const int height = w->heightb;
// log_trace("(): building shadow for %s %d %d", w->name, width, height); // log_trace("(): building shadow for %s %d %d", w->name, width, height);
@ -577,12 +577,13 @@ shadow_picture_err:
/** /**
* Paint the shadow of a window. * Paint the shadow of a window.
*/ */
static inline void win_paint_shadow(session_t *ps, win *w, region_t *reg_paint) { static inline void
win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
// Bind shadow pixmap to GLX texture if needed // Bind shadow pixmap to GLX texture if needed
paint_bind_tex(ps, &w->shadow_paint, 0, 0, false, 32, 0, false); paint_bind_tex(ps, &w->shadow_paint, 0, 0, false, 32, 0, false);
if (!paint_isvalid(ps, &w->shadow_paint)) { if (!paint_isvalid(ps, &w->shadow_paint)) {
log_error("Window %#010x is missing shadow data.", w->id); log_error("Window %#010x is missing shadow data.", w->base.id);
return; return;
} }
@ -664,8 +665,9 @@ static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t
/** /**
* Blur the background of a window. * Blur the background of a window.
*/ */
static inline void win_blur_background(session_t *ps, win *w, xcb_render_picture_t tgt_buffer, static inline void
const region_t *reg_paint) { win_blur_background(session_t *ps, struct managed_win *w,
xcb_render_picture_t tgt_buffer, const region_t *reg_paint) {
const int16_t x = w->g.x; const int16_t x = w->g.x;
const int16_t y = w->g.y; const int16_t y = w->g.y;
const auto wid = to_u16_checked(w->widthb); const auto wid = to_u16_checked(w->widthb);
@ -770,7 +772,7 @@ static inline void resize_region(region_t *region, short mod) {
/// paint all windows /// paint all windows
/// region = ?? /// region = ??
/// region_real = the damage region /// region_real = the damage region
void paint_all(session_t *ps, win *const t, bool ignore_damage) { void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
if (ps->o.xrender_sync_fence) { if (ps->o.xrender_sync_fence) {
if (ps->xsync_exists && !x_fence_sync(ps->c, ps->sync_fence)) { if (ps->xsync_exists && !x_fence_sync(ps->c, ps->sync_fence)) {
log_error("x_fence_sync failed, xrender-sync-fence will be " log_error("x_fence_sync failed, xrender-sync-fence will be "
@ -857,7 +859,7 @@ void paint_all(session_t *ps, win *const t, bool ignore_damage) {
// pixels painted. // pixels painted.
// //
// Whether this is beneficial is to be determined XXX // Whether this is beneficial is to be determined XXX
for (win *w = t; w; w = w->prev_trans) { for (auto w = t; w; w = w->prev_trans) {
region_t bshape = win_get_bounding_shape_global_by_val(w); region_t bshape = win_get_bounding_shape_global_by_val(w);
// Painting shadow // Painting shadow
if (w->shadow) { if (w->shadow) {

View File

@ -12,9 +12,10 @@
typedef struct _glx_texture glx_texture_t; typedef struct _glx_texture glx_texture_t;
typedef struct glx_prog_main glx_prog_main_t; typedef struct glx_prog_main glx_prog_main_t;
typedef struct win win;
typedef struct session session_t; typedef struct session session_t;
struct managed_win;
typedef struct paint { typedef struct paint {
xcb_pixmap_t pixmap; xcb_pixmap_t pixmap;
xcb_render_picture_t pict; xcb_render_picture_t pict;
@ -27,9 +28,9 @@ typedef struct paint {
void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, double opacity, void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, double opacity,
bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex, bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex,
const region_t *reg_paint, const glx_prog_main_t *pprogram); const region_t *reg_paint, const glx_prog_main_t *pprogram);
void paint_one(session_t *ps, win *w, const region_t *reg_paint); void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint);
void paint_all(session_t *ps, win *const t, bool ignore_damage); void paint_all(session_t *ps, struct managed_win *const t, bool ignore_damage);
void free_picture(xcb_connection_t *c, xcb_render_picture_t *p); void free_picture(xcb_connection_t *c, xcb_render_picture_t *p);

517
src/win.c

File diff suppressed because it is too large Load Diff

198
src/win.h
View File

@ -17,16 +17,23 @@
#include "backend/backend.h" #include "backend/backend.h"
#include "c2.h" #include "c2.h"
#include "compiler.h" #include "compiler.h"
#include "list.h"
#include "region.h" #include "region.h"
#include "render.h" #include "render.h"
#include "types.h" #include "types.h"
#include "utils.h" #include "utils.h"
#include "x.h" #include "x.h"
#include "list.h"
typedef struct session session_t; typedef struct session session_t;
typedef struct _glx_texture glx_texture_t; typedef struct _glx_texture glx_texture_t;
#define win_stack_foreach_managed(w, win_stack) \
list_foreach(struct managed_win, w, win_stack, base.stack_neighbour) if (w->base.managed)
#define win_stack_foreach_managed_safe(w, win_stack) \
list_foreach_safe(struct managed_win, w, win_stack, \
base.stack_neighbour) if (w->base.managed)
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
// FIXME this type should be in opengl.h // FIXME this type should be in opengl.h
// it is very unideal for it to be here // it is very unideal for it to be here
@ -108,15 +115,16 @@ typedef enum {
WSTATE_UNMAPPED, WSTATE_UNMAPPED,
} winstate_t; } winstate_t;
typedef enum win_flags { enum win_flags {
/// win_image/shadow_image is out of date /// win_image/shadow_image is out of date
WIN_FLAGS_STALE_IMAGE = 1, WIN_FLAGS_IMAGE_STALE = 1,
/// there was an error trying to bind the images /// there was an error trying to bind the images
WIN_FLAGS_IMAGE_ERROR = 2, WIN_FLAGS_IMAGE_ERROR = 2,
} win_flags_t; };
/// An entry in the window stack. May or may not correspond to a window we know about. /// An entry in the window stack. May or may not correspond to a window we know about.
struct window_stack_entry { struct window_stack_entry {
struct list_node stack_neighbour;
/// The actual window correspond to this stack entry. NULL if we didn't know about /// The actual window correspond to this stack entry. NULL if we didn't know about
/// this window (e.g. an InputOnly window, or we haven't handled the window /// this window (e.g. an InputOnly window, or we haven't handled the window
/// creation yet) /// creation yet)
@ -124,7 +132,6 @@ struct window_stack_entry {
/// The window id. Might not be unique in the stack, because there might be /// The window id. Might not be unique in the stack, because there might be
/// destroyed window still fading out in the stack. /// destroyed window still fading out in the stack.
xcb_window_t id; xcb_window_t id;
struct list_node stack_neighbour;
}; };
/** /**
@ -141,18 +148,30 @@ struct window_stack_entry {
/// Structure representing a top-level window compton manages. /// Structure representing a top-level window compton manages.
typedef struct win win; typedef struct win win;
struct win { struct win {
UT_hash_handle hh;
struct list_node stack_neighbour; struct list_node stack_neighbour;
/// ID of the top-level frame window.
xcb_window_t id;
/// Whether the window is destroyed from Xorg's perspective
bool destroyed : 1;
/// True if we just received CreateNotify, and haven't queried X for any info
/// about the window
bool is_new : 1;
/// True if this window is managed, i.e. this struct is actually a `managed_win`.
/// Always false if `is_new` is true.
bool managed : 1;
};
struct managed_win {
struct win base;
/// backend data attached to this window. Only available when /// backend data attached to this window. Only available when
/// `state` is not UNMAPPED /// `state` is not UNMAPPED
void *win_image; void *win_image;
void *shadow_image; void *shadow_image;
/// Pointer to the next higher window to paint. /// Pointer to the next higher window to paint.
win *prev_trans; struct managed_win *prev_trans;
// TODO rethink reg_ignore // TODO rethink reg_ignore
// Core members // Core members
/// ID of the top-level frame window.
xcb_window_t id;
/// The "mapped state" of this window, doesn't necessary /// The "mapped state" of this window, doesn't necessary
/// match X mapped state, because of fading. /// match X mapped state, because of fading.
winstate_t state; winstate_t state;
@ -299,64 +318,67 @@ struct win {
/// Textures and FBO background blur use. /// Textures and FBO background blur use.
glx_blur_cache_t glx_blur_cache; glx_blur_cache_t glx_blur_cache;
#endif #endif
UT_hash_handle hh;
}; };
void win_release_image(backend_t *base, win *w); void win_release_image(backend_t *base, struct managed_win *w);
bool must_use win_bind_image(session_t *ps, win *w); bool must_use win_bind_image(session_t *ps, struct managed_win *w);
/// Attempt a rebind of window's images. If that failed, the original images are kept. /// Attempt a rebind of window's images. If that failed, the original images are kept.
bool must_use win_try_rebind_image(session_t *ps, win *w); bool must_use win_try_rebind_image(session_t *ps, struct managed_win *w);
int win_get_name(session_t *ps, win *w); int win_get_name(session_t *ps, struct managed_win *w);
int win_get_role(session_t *ps, win *w); int win_get_role(session_t *ps, struct managed_win *w);
winmode_t attr_pure win_calc_mode(const win *w); winmode_t attr_pure win_calc_mode(const struct managed_win *w);
void win_set_shadow_force(session_t *ps, struct managed_win *w, switch_t val);
void win_set_fade_force(session_t *ps, struct managed_win *w, switch_t val);
void win_set_focused_force(session_t *ps, struct managed_win *w, switch_t val);
void win_set_invert_color_force(session_t *ps, struct managed_win *w, switch_t val);
/** /**
* Set real focused state of a window. * Set real focused state of a window.
*/ */
void win_set_focused(session_t *ps, win *w, bool focused); void win_set_focused(session_t *ps, struct managed_win *w, bool focused);
bool attr_pure win_should_fade(session_t *ps, const win *w); bool attr_pure win_should_fade(session_t *ps, const struct managed_win *w);
void win_update_prop_shadow_raw(session_t *ps, win *w); void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w);
void win_update_prop_shadow(session_t *ps, win *w); void win_update_prop_shadow(session_t *ps, struct managed_win *w);
void win_set_shadow(session_t *ps, win *w, bool shadow_new); void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new);
void win_determine_shadow(session_t *ps, win *w); void win_determine_shadow(session_t *ps, struct managed_win *w);
void win_set_invert_color(session_t *ps, win *w, bool invert_color_new); void win_set_invert_color(session_t *ps, struct managed_win *w, bool invert_color_new);
void win_determine_invert_color(session_t *ps, win *w); void win_determine_invert_color(session_t *ps, struct managed_win *w);
void win_set_blur_background(session_t *ps, win *w, bool blur_background_new); void win_set_blur_background(session_t *ps, struct managed_win *w, bool blur_background_new);
void win_determine_blur_background(session_t *ps, win *w); void win_determine_blur_background(session_t *ps, struct managed_win *w);
void win_on_wtype_change(session_t *ps, win *w); void win_on_wtype_change(session_t *ps, struct managed_win *w);
void win_on_factor_change(session_t *ps, win *w); void win_on_factor_change(session_t *ps, struct managed_win *w);
/** /**
* Update cache data in struct _win that depends on window size. * Update cache data in struct _win that depends on window size.
*/ */
void win_on_win_size_change(session_t *ps, win *w); void win_on_win_size_change(session_t *ps, struct managed_win *w);
void win_update_wintype(session_t *ps, win *w); void win_update_wintype(session_t *ps, struct managed_win *w);
void win_mark_client(session_t *ps, win *w, xcb_window_t client); void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client);
void win_unmark_client(session_t *ps, win *w); void win_unmark_client(session_t *ps, struct managed_win *w);
void win_recheck_client(session_t *ps, win *w); void win_recheck_client(session_t *ps, struct managed_win *w);
xcb_window_t win_get_leader_raw(session_t *ps, win *w, int recursions); xcb_window_t win_get_leader_raw(session_t *ps, struct managed_win *w, int recursions);
bool win_get_class(session_t *ps, win *w); bool win_get_class(session_t *ps, struct managed_win *w);
double attr_pure win_calc_opacity_target(session_t *ps, const win *w); double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w);
bool attr_pure win_should_dim(session_t *ps, const win *w); bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w);
void win_update_screen(session_t *, win *); void win_update_screen(session_t *, struct managed_win *);
/// Prepare window for fading because opacity target changed /// Prepare window for fading because opacity target changed
void win_start_fade(session_t *, win **); void win_start_fade(session_t *, struct managed_win **);
/** /**
* Reread opacity property of a window. * Reread opacity property of a window.
*/ */
void win_update_opacity_prop(session_t *ps, win *w); void win_update_opacity_prop(session_t *ps, struct managed_win *w);
/** /**
* Update leader of a window. * Update leader of a window.
*/ */
void win_update_leader(session_t *ps, win *w); void win_update_leader(session_t *ps, struct managed_win *w);
/** /**
* Update focused state of a window. * Update focused state of a window.
*/ */
void win_update_focused(session_t *ps, win *w); void win_update_focused(session_t *ps, struct managed_win *w);
/** /**
* Retrieve the bounding shape of a window. * Retrieve the bounding shape of a window.
*/ */
// XXX was win_border_size // XXX was win_border_size
void win_update_bounding_shape(session_t *ps, win *w); void win_update_bounding_shape(session_t *ps, struct managed_win *w);
/** /**
* Get a rectangular region in global coordinates a window (and possibly * Get a rectangular region in global coordinates a window (and possibly
* its shadow) occupies. * its shadow) occupies.
@ -364,71 +386,109 @@ void win_update_bounding_shape(session_t *ps, win *w);
* Note w->shadow and shadow geometry must be correct before calling this * Note w->shadow and shadow geometry must be correct before calling this
* function. * function.
*/ */
void win_extents(const win *w, region_t *res); void win_extents(const struct managed_win *w, region_t *res);
region_t win_extents_by_val(const win *w); region_t win_extents_by_val(const struct managed_win *w);
/** /**
* Add a window to damaged area. * Add a window to damaged area.
* *
* @param ps current session * @param ps current session
* @param w struct _win element representing the window * @param w struct _win element representing the window
*/ */
void add_damage_from_win(session_t *ps, win *w); void add_damage_from_win(session_t *ps, const struct managed_win *w);
/** /**
* Get a rectangular region a window occupies, excluding frame and shadow. * Get a rectangular region a window occupies, excluding frame and shadow.
* *
* Return region in global coordinates. * Return region in global coordinates.
*/ */
void win_get_region_noframe_local(const win *w, region_t *); void win_get_region_noframe_local(const struct managed_win *w, region_t *);
region_t win_get_region_noframe_local_by_val(const win *w); region_t win_get_region_noframe_local_by_val(const struct managed_win *w);
/// Get the region for the frame of the window /// Get the region for the frame of the window
void win_get_region_frame_local(const win *w, region_t *res); void win_get_region_frame_local(const struct managed_win *w, region_t *res);
/// Get the region for the frame of the window, by value /// Get the region for the frame of the window, by value
region_t win_get_region_frame_local_by_val(const win *w); region_t win_get_region_frame_local_by_val(const struct managed_win *w);
/** /**
* Retrieve frame extents from a window. * Retrieve frame extents from a window.
*/ */
void win_update_frame_extents(session_t *ps, win *w, xcb_window_t client); void win_update_frame_extents(session_t *ps, struct managed_win *w, xcb_window_t client);
void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev); /// Insert a new window above window with id `below`, if there is no window, add to top
/// New window will be in unmapped state
struct win *add_win_above(session_t *ps, xcb_window_t id, xcb_window_t below);
/// Insert a new win entry at the top of the stack
struct win *add_win_top(session_t *ps, xcb_window_t id);
/// Query the Xorg for information about window `win`
/// `win` pointer might become invalid after this function returns
void fill_win(session_t *ps, struct win *win);
/// Unmap or destroy a window /// Unmap or destroy a window
void unmap_win(session_t *ps, win **, bool destroy); void unmap_win(session_t *ps, struct managed_win **, bool destroy);
void map_win(session_t *ps, win *w); void map_win(session_t *ps, struct managed_win *w);
void map_win_by_id(session_t *ps, xcb_window_t id); void map_win_by_id(session_t *ps, xcb_window_t id);
/** /**
* Execute fade callback of a window if fading finished. * Execute fade callback of a window if fading finished.
*/ */
void win_check_fade_finished(session_t *ps, win **_w); void win_check_fade_finished(session_t *ps, struct managed_win **_w);
// Stop receiving events (except ConfigureNotify, XXX why?) from a window // Stop receiving events (except ConfigureNotify, XXX why?) from a window
void win_ev_stop(session_t *ps, const win *w); void win_ev_stop(session_t *ps, const struct win *w);
/// Skip the current in progress fading of window, /// Skip the current in progress fading of window,
/// transition the window straight to its end state /// transition the window straight to its end state
void win_skip_fading(session_t *ps, win **_w); void win_skip_fading(session_t *ps, struct managed_win **_w);
win *find_win(session_t *ps, xcb_window_t id); /**
win *find_toplevel(session_t *ps, xcb_window_t id); * Find a managed window from window id in window linked list of the session.
*/
struct managed_win *find_managed_win(session_t *ps, xcb_window_t id);
struct win *find_win(session_t *ps, xcb_window_t id);
struct managed_win *find_toplevel(session_t *ps, xcb_window_t id);
/**
* Find out the WM frame of a client window by querying X.
*
* @param ps current session
* @param wid window ID
* @return struct _win object of the found window, NULL if not found
*/
struct managed_win *find_toplevel2(session_t *ps, xcb_window_t wid);
/**
* Check if a window is a fullscreen window.
*
* It's not using w->border_size for performance measures.
*/
bool attr_pure win_is_fullscreen(const session_t *ps, const struct managed_win *w);
/**
* Check if a window will be painted solid.
*/
bool attr_pure win_is_solid(const session_t *ps, const struct managed_win *w);
/**
* Check if a window is really focused.
*/
bool attr_pure win_is_focused_real(const session_t *ps, const struct managed_win *w);
/** /**
* Get the leader of a window. * Get the leader of a window.
* *
* This function updates w->cache_leader if necessary. * This function updates w->cache_leader if necessary.
*/ */
static inline xcb_window_t win_get_leader(session_t *ps, win *w) { static inline xcb_window_t win_get_leader(session_t *ps, struct managed_win *w) {
return win_get_leader_raw(ps, w, 0); return win_get_leader_raw(ps, w, 0);
} }
/// check if window has ARGB visual /// check if window has ARGB visual
bool attr_pure win_has_alpha(const win *w); bool attr_pure win_has_alpha(const struct managed_win *w);
/// check if reg_ignore_valid is true for all windows above us /// check if reg_ignore_valid is true for all windows above us
bool attr_pure win_is_region_ignore_valid(session_t *ps, const win *w); bool attr_pure win_is_region_ignore_valid(session_t *ps, const struct managed_win *w);
// Find the managed window immediately below `w` in the window stack
struct managed_win *attr_pure win_stack_find_next_managed(const session_t *ps,
const struct list_node *w);
/// Free all resources in a struct win /// Free all resources in a struct win
void free_win_res(session_t *ps, win *w); void free_win_res(session_t *ps, struct managed_win *w);
static inline region_t win_get_bounding_shape_global_by_val(win *w) { static inline region_t win_get_bounding_shape_global_by_val(struct managed_win *w) {
region_t ret; region_t ret;
pixman_region32_init(&ret); pixman_region32_init(&ret);
pixman_region32_copy(&ret, &w->bounding_shape); pixman_region32_copy(&ret, &w->bounding_shape);
@ -440,7 +500,7 @@ static inline region_t win_get_bounding_shape_global_by_val(win *w) {
* Calculate the extents of the frame of the given window based on EWMH * Calculate the extents of the frame of the given window based on EWMH
* _NET_FRAME_EXTENTS and the X window border width. * _NET_FRAME_EXTENTS and the X window border width.
*/ */
static inline margin_t attr_pure win_calc_frame_extents(const win *w) { static inline margin_t attr_pure win_calc_frame_extents(const struct managed_win *w) {
margin_t result = w->frame_extents; margin_t result = w->frame_extents;
result.top = max2(result.top, w->g.border_width); result.top = max2(result.top, w->g.border_width);
result.left = max2(result.left, w->g.border_width); result.left = max2(result.left, w->g.border_width);
@ -452,7 +512,15 @@ static inline margin_t attr_pure win_calc_frame_extents(const win *w) {
/** /**
* Check whether a window has WM frames. * Check whether a window has WM frames.
*/ */
static inline bool attr_pure win_has_frame(const win *w) { static inline bool attr_pure win_has_frame(const struct managed_win *w) {
return w->g.border_width || w->frame_extents.top || w->frame_extents.left || return w->g.border_width || w->frame_extents.top || w->frame_extents.left ||
w->frame_extents.right || w->frame_extents.bottom; w->frame_extents.right || w->frame_extents.bottom;
} }
static inline const char *win_get_name_if_managed(const struct win *w) {
if (!w->managed) {
return "(unmanaged)";
}
auto mw = (struct managed_win *)w;
return mw->name;
}