From 53fd3a2f7a40ad781170b005a5361ed9ad4a767d Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sun, 14 Apr 2019 22:36:23 +0100 Subject: [PATCH] tmp --- src/backend/backend.c | 4 +- src/backend/backend.h | 16 +- src/backend/backend_common.c | 8 - src/c2.c | 12 +- src/c2.h | 4 +- src/common.h | 50 +--- src/compton.c | 218 ++++++-------- src/compton.h | 4 +- src/dbus.c | 48 ++-- src/dbus.h | 14 +- src/event.c | 59 ++-- src/opengl.c | 2 +- src/opengl.h | 2 +- src/render.c | 32 ++- src/render.h | 7 +- src/win.c | 535 ++++++++++++++++++++++++----------- src/win.h | 198 ++++++++----- 17 files changed, 699 insertions(+), 514 deletions(-) diff --git a/src/backend/backend.c b/src/backend/backend.c index ceba1704..8399142e 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -50,7 +50,7 @@ region_t get_damage(session_t *ps, bool all_damage) { } /// 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 // the paints bleed out of the damage region, it will destroy // 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. // // 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(®_visible, &ps->screen_reg, w->reg_ignore); assert(!(w->flags & WIN_FLAGS_IMAGE_ERROR)); diff --git a/src/backend/backend.h b/src/backend/backend.h index 6c956786..fded6ff5 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -11,7 +11,7 @@ #include "x.h" typedef struct session session_t; -typedef struct win win; +struct managed_win; struct backend_operations; @@ -48,7 +48,7 @@ struct backend_operations { /// 1) if ps->overlay is not XCB_NONE, use that /// 2) use ps->root otherwise /// 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); /// Called when rendering will be stopped for an unknown amount of @@ -92,7 +92,7 @@ struct backend_operations { /// Fill rectangle of target, mostly for debug purposes, optional. void (*fill)(backend_t *backend_data, double r, double g, double b, double a, - const region_t *clip); + const region_t *clip); /// Blur a given region of the target. bool (*blur)(backend_t *backend_data, double opacity, const region_t *reg_blur, @@ -129,8 +129,7 @@ struct backend_operations { // want to break that assumption as for now. We need to reconsider this. /// Free resources associated with an image data structure - void (*release_image)(backend_t *backend_data, void *img_data) - attr_nonnull(1, 2); + void (*release_image)(backend_t *backend_data, void *img_data) attr_nonnull(1, 2); // =========== Query =========== @@ -179,12 +178,11 @@ struct backend_operations { /// 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[]; -bool default_is_win_transparent(void *, win *, void *); -bool default_is_frame_transparent(void *, win *, void *); -void paint_all_new(session_t *ps, win *const t, bool ignore_damage) attr_nonnull(1); +void paint_all_new(session_t *ps, struct managed_win *const t, bool ignore_damage) + attr_nonnull(1); // vim: set noet sw=8 ts=8 : diff --git a/src/backend/backend_common.c b/src/backend/backend_common.c index 90ad52e1..128fff4c 100644 --- a/src/backend/backend_common.c +++ b/src/backend/backend_common.c @@ -279,11 +279,3 @@ default_backend_render_shadow(backend_t *backend_data, int width, int height, xcb_render_free_picture(backend_data->c, pict); 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; -} diff --git a/src/c2.c b/src/c2.c index b51acf01..8ebbe416 100644 --- a/src/c2.c +++ b/src/c2.c @@ -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 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. @@ -1272,11 +1272,11 @@ static xcb_atom_t c2_get_atom_type(const c2_l_t *pleaf) { * * For internal use. */ -static inline void -c2_match_once_leaf(session_t *ps, const win *w, const c2_l_t *pleaf, bool *pres, bool *perr) { +static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w, + const c2_l_t *pleaf, bool *pres, bool *perr) { 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 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. */ -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 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 * @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 for (; condlst; condlst = condlst->next) { if (c2_match_once(ps, w, condlst->ptr)) { diff --git a/src/c2.h b/src/c2.h index 21eb112a..d6b1d372 100644 --- a/src/c2.h +++ b/src/c2.h @@ -15,12 +15,12 @@ typedef struct _c2_lptr c2_lptr_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_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); diff --git a/src/common.h b/src/common.h index fa3bc4bd..93ab2a88 100644 --- a/src/common.h +++ b/src/common.h @@ -391,7 +391,7 @@ typedef struct session { // === Window related === /// A hash table of all windows. - win *windows; + struct win *windows; /// Windows in their stacking order struct list_node window_stack; /// Pointer to win 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 /// case the WM does something extraordinary, but caching the pointer /// means another layer of complexity. - win *active_win; + struct managed_win *active_win; /// Window ID of leader window of currently active window. Used for /// subsidiary window detection. 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; } -/** - * 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. * * @return struct win object of the found window, NULL if not found */ -static inline win *find_focused(session_t *ps) { - if (!ps->o.track_focus) +static inline struct managed_win *find_focused(session_t *ps) { + if (!ps->o.track_focus) { 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 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) { if (ps->o.show_all_xerrors) return; @@ -791,23 +779,6 @@ static inline void set_ignore_cookie(session_t *ps, xcb_void_cookie_t cookie) { 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. * @@ -864,13 +835,6 @@ void vsync_deinit(session_t *ps); /** @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); diff --git a/src/compton.c b/src/compton.c index 17e17ace..8a419378 100644 --- a/src/compton.c +++ b/src/compton.c @@ -154,11 +154,11 @@ void cxinerama_upd_scrs(session_t *ps) { * * 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) return NULL; - win *w = find_win(ps, wid); + auto w = find_managed_win(ps, wid); if (!w) w = find_toplevel(ps, wid); if (!w) @@ -217,8 +217,8 @@ static double fade_timeout(session_t *ps) { * @param steps steps of fading * @return whether we are still in fading mode */ -static bool run_fade(session_t *ps, win **_w, long steps) { - win *w = *_w; +static bool run_fade(session_t *ps, struct managed_win **_w, long steps) { + auto w = *_w; if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) { // We are not fading 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)) { - 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; } if (w->opacity == w->opacity_tgt) { // We have reached target opacity. // 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 - 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; } @@ -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 evmask = 0; - win *w = NULL; + struct managed_win *w = NULL; // Check if it's a mapped frame window 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; if (ps->o.track_focus && !ps->o.use_ewmh_active_win) 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; } -/** - * 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 w->focused * to true. @@ -341,7 +309,7 @@ win *find_toplevel2(session_t *ps, xcb_window_t wid) { * @param ps current session * @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 if (ps->o.use_ewmh_active_win) { update_ewmh_active_win(ps); @@ -359,10 +327,10 @@ win *recheck_focus(session_t *ps) { free(reply); } - win *w = find_win_all(ps, wid); + auto w = find_win_all(ps, 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 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 // means if fade is still ongoing after the current frame is rendered - win *t = NULL; + struct managed_win *bottom = NULL; *fade_running = false; // 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; // 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 bool was_painted = w->to_paint; 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 bool is_highest = 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; bool to_paint = true; // 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, // 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) { // 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) { // Rebind image only when the window does have an image // available @@ -584,8 +552,8 @@ static win *paint_preprocess(session_t *ps, bool *fade_running) { unredir_possible = true; } - w->prev_trans = t; - t = w; + w->prev_trans = bottom; + bottom = w; // If the screen is not redirected and the window has redir_ignore set, // 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); } -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; 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; } 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) { - w->reg_ignore_valid = false; - rc_region_unref(&w->reg_ignore); - if (!list_node_is_last(&ps->window_stack, &w->stack_neighbour)) { - auto next_w = list_next_entry(w, stack_neighbour); + if (mw) { + mw->reg_ignore_valid = false; + rc_region_unref(&mw->reg_ignore); + } + + auto next_w = win_stack_find_next_managed(ps, &w->stack_neighbour); + if (next_w) { next_w->reg_ignore_valid = false; 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) { new_next = &ps->window_stack; } else { - win *tmp_w = NULL; + struct win *tmp_w = NULL; HASH_FIND_INT(ps->windows, &new_above, 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); // add damage for this window - add_damage_from_win(ps, w); + if (mw) { + add_damage_from_win(ps, mw); + } #ifdef DEBUG_RESTACK 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 = ""; if (c->state == WSTATE_DESTROYING) { 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 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 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 // 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 (!win_bind_image(ps, w)) { 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; // Invalidate reg_ignore from the top - if (!list_is_empty(&ps->window_stack)) { - auto top_w = list_entry(ps->window_stack.next, win, stack_neighbour); + auto top_w = win_stack_find_next_managed(ps, &ps->window_stack); + if (top_w) { rc_region_unref(&top_w->reg_ignore); 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 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; pixman_region32_init(&damage); @@ -843,9 +825,9 @@ void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) { w->state == WSTATE_DESTROYING) { // Only restack the window to make sure we can handle future restack // notification correctly - restack_win(ps, w, ce->above_sibling); + restack_win(ps, &w->base, ce->above_sibling); } else { - restack_win(ps, w, ce->above_sibling); + restack_win(ps, &w->base, ce->above_sibling); bool factor_change = false; 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) { - win *w = find_win(ps, ce->window); + auto w = find_win(ps, ce->window); xcb_window_t new_above; if (!w) return; 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 { 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. */ @@ -1017,7 +957,11 @@ void opts_init_track_focus(session_t *ps) { if (!ps->o.use_ewmh_active_win) { // Start listening to FocusChange events 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( ps->c, w->id, XCB_CW_EVENT_MASK, (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) { // Search for the window 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. - if (w) + if (w) { win_set_focused(ps, w, true); + } } // === 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) { if (ps->o.benchmark) { if (ps->o.benchmark_wid) { - win *wi = find_win(ps, ps->o.benchmark_wid); - if (!wi) { + auto w = find_managed_win(ps, ps->o.benchmark_wid); + if (!w) { log_fatal("Couldn't find specified benchmark window."); exit(1); } - add_damage_from_win(ps, wi); + add_damage_from_win(ps, w); } else { force_repaint(ps); } @@ -1458,7 +1403,7 @@ static void _draw_callback(EV_P_ session_t *ps, int revents) { // should be redirected. bool fade_running = false; bool was_redirected = ps->redirected; - win *t = paint_preprocess(ps, &fade_running); + auto bottom = paint_preprocess(ps, &fade_running); ps->tmout_unredir_hit = false; 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 // here to make sure the rendering decision we make is up-to-date 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 @@ -1482,9 +1427,9 @@ static void _draw_callback(EV_P_ session_t *ps, int revents) { if (ps->redirected && ps->o.stoppaint_force != ON) { static int paint = 0; if (ps->o.experimental_backends) { - paint_all_new(ps, t, false); + paint_all_new(ps, bottom, false); } else { - paint_all(ps, t, false); + paint_all(ps, bottom, false); } paint++; @@ -2122,21 +2067,29 @@ static session_t *session_init(int argc, char **argv, Display *dpy, children = NULL; nchildren = 0; } + free(reply); 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) { - if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) { - map_win(ps, w); + assert(!w->is_new); + 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:"); - list_foreach(win, w, &ps->window_stack, stack_neighbour) { - log_trace("%#010x \"%s\"", w->id, w->name); + list_foreach(struct win, w, &ps->window_stack, stack_neighbour) { + 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 - list_foreach_safe(win, w, &ps->window_stack, stack_neighbour) { - if (w->state != WSTATE_DESTROYING) { + list_foreach_safe(struct win, w, &ps->window_stack, stack_neighbour) { + if (!w->destroyed) { win_ev_stop(ps, 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); } list_init_head(&ps->window_stack); diff --git a/src/compton.h b/src/compton.h index a6c47599..8ab7fecd 100644 --- a/src/compton.h +++ b/src/compton.h @@ -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); -win *find_toplevel2(session_t *ps, xcb_window_t wid); - -win *recheck_focus(session_t *ps); +struct managed_win *recheck_focus(session_t *ps); /// Handle configure event of a root window void configure_root(session_t *ps, int width, int height); diff --git a/src/dbus.c b/src/dbus.c index b60934fd..cc11e797 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -21,13 +21,13 @@ #include "common.h" #include "compiler.h" #include "config.h" +#include "list.h" #include "log.h" #include "string_utils.h" #include "types.h" #include "uthash_extra.h" #include "utils.h" #include "win.h" -#include "list.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 unsigned count = 0; HASH_ITER2(ps->windows, w) { - assert(w->state != WSTATE_DESTROYING); + assert(!w->destroyed); ++count; } @@ -483,7 +483,7 @@ static bool cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data) // Build the array cdbus_window_t *pcur = arr; HASH_ITER2(ps->windows, w) { - assert(w->state != WSTATE_DESTROYING); + assert(!w->destroyed); *pcur = w->id; ++pcur; } @@ -743,7 +743,7 @@ static bool cdbus_process_win_get(session_t *ps, DBusMessage *msg) { return false; } - win *w = find_win(ps, wid); + auto w = find_managed_win(ps, wid); if (!w) { log_error("Window %#010x not found.", wid); @@ -757,14 +757,16 @@ static bool cdbus_process_win_get(session_t *ps, DBusMessage *msg) { return true; \ } - cdbus_m_win_get_do(id, cdbus_reply_wid); + cdbus_m_win_get_do(base.id, cdbus_reply_wid); // next if (!strcmp("next", target)) { - cdbus_reply_wid(ps, msg, - (list_node_is_last(&ps->window_stack, &w->stack_neighbour) - ? 0 - : list_next_entry(w, stack_neighbour)->id)); + cdbus_reply_wid( + ps, msg, + (list_node_is_last(&ps->window_stack, &w->base.stack_neighbour) + ? 0 + : list_entry(w->base.stack_neighbour.next, struct win, stack_neighbour) + ->id)); return true; } @@ -845,7 +847,7 @@ static bool cdbus_process_win_set(session_t *ps, DBusMessage *msg) { return false; } - win *w = find_win(ps, wid); + auto w = find_managed_win(ps, wid); if (!w) { 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; if (!cdbus_msg_get_arg(msg, 1, CDBUS_TYPE_WINDOW, &client)) return false; - win *w = find_toplevel(ps, client); - if (w) - wid = w->id; + auto w = find_toplevel(ps, client); + if (w) { + wid = w->base.id; + } } // Find focused window else if (!strcmp("focused", target)) { - win *w = find_focused(ps); - if (w) - wid = w->id; + auto w = find_focused(ps); + if (w) { + wid = w->base.id; + } } else { log_error(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 */ ///@{ -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; if (cd->dbus_conn) 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; if (cd->dbus_conn) 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; if (cd->dbus_conn) 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; if (cd->dbus_conn) 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; if (cd->dbus_conn) 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; if (cd->dbus_conn) cdbus_signal_wid(ps, "win_focusin", w->id); diff --git a/src/dbus.h b/src/dbus.h index d60b47e0..54a58af5 100644 --- a/src/dbus.h +++ b/src/dbus.h @@ -14,7 +14,7 @@ #include typedef struct session session_t; -typedef struct win win; +struct win; /** * 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); /// 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 -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 -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 -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 -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 -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 : diff --git a/src/event.c b/src/event.c index 13b491c5..1804c247 100644 --- a/src/event.c +++ b/src/event.c @@ -50,7 +50,7 @@ static inline const char *ev_window_name(session_t *ps, xcb_window_t wid) { } else if (ps->overlay == wid) { name = "(Overlay)"; } else { - win *w = find_win(ps, wid); + auto w = find_managed_win(ps, wid); if (!w) { 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) { 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) { @@ -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) { - win *w = find_win(ps, ev->window); + auto w = find_managed_win(ps, ev->window); if (w) { 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) { - win *w = find_win(ps, ev->window); + auto w = find_managed_win(ps, ev->window); if (w) { 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) { // new window - add_win(ps, ev->window, 0); + // TODO delay fill_win + fill_win(ps, add_win_top(ps, ev->window)); } else { // otherwise, find and destroy the window first - win *w = find_win(ps, ev->window); - if (w) { - unmap_win(ps, &w, true); + auto w = find_win(ps, ev->window); + if (w && w->managed) { + unmap_win(ps, (struct managed_win **)&w, true); } // 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 if (!find_toplevel(ps, ev->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 // 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 (wid_has_prop(ps, ev->window, ps->atom_client)) { 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( 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 - 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)) { w_top->wmwin = false; 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 // there are always some stupid applications. (#144) if (ev->atom == ps->atom_win_type) { - win *w = NULL; + struct managed_win *w = NULL; if ((w = find_toplevel(ps, ev->window))) win_update_wintype(ps, w); } // If _NET_WM_OPACITY changes 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) { win_update_opacity_prop(ps, w); // 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 (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) { win_update_frame_extents(ps, w, ev->window); // 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 (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)) { 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 (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) { win_get_class(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 (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)) { 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 (ps->o.respect_prop_shadow && ps->atom_compton_shadow == ev->atom) { - win *w = find_win(ps, ev->window); - if (w) + auto w = find_managed_win(ps, ev->window); + if (w) { win_update_prop_shadow(ps, w); + } } // If a leader property changes if ((ps->o.detect_transient && ps->atom_transient == 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) { 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 for (latom_t *platom = ps->track_atom_lst; platom; platom = platom->next) { if (platom->atom == ev->atom) { - win *w = find_win(ps, ev->window); + auto w = find_managed_win(ps, ev->window); if (!w) w = find_toplevel(ps, ev->window); 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) return; @@ -472,18 +475,20 @@ static inline void ev_damage_notify(session_t *ps, xcb_damage_notify_event_t *de return; } */ - win *w = find_win(ps, de->drawable); + auto w = find_managed_win(ps, de->drawable); - if (!w) + if (!w) { return; + } repair_win(ps, w); } static inline void ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev) { - win *w = find_win(ps, ev->affected_window); - if (!w || w->a.map_state == XCB_MAP_STATE_UNMAPPED) + auto w = find_managed_win(ps, ev->affected_window); + if (!w || w->a.map_state == XCB_MAP_STATE_UNMAPPED) { return; + } /* * Empty bounding_shape may indicated an diff --git a/src/opengl.c b/src/opengl.c index 8683827c..11e4030c 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -221,7 +221,7 @@ void glx_destroy(session_t *ps) { return; // 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); } diff --git a/src/opengl.h b/src/opengl.h index 8c746d35..863a84d6 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -161,7 +161,7 @@ static inline void free_paint_glx(session_t *ps, paint_t *ppaint) { /** * 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->shadow_paint); #ifdef CONFIG_OPENGL diff --git a/src/render.c b/src/render.c index 2565824e..96c9fa81 100644 --- a/src/render.c +++ b/src/render.c @@ -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 -paint_region(session_t *ps, win *w, int x, int y, int wid, int hei, double opacity, - const region_t *reg_paint, xcb_render_picture_t pict) { +paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, int hei, + double opacity, const region_t *reg_paint, xcb_render_picture_t pict) { const int dx = (w ? w->g.x : 0) + x; const int dy = (w ? w->g.y : 0) + y; 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. */ -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 if (!w->paint.pixmap) { w->paint.pixmap = x_new_id(ps->c); - set_ignore_cookie( - ps, xcb_composite_name_window_pixmap(ps->c, w->id, w->paint.pixmap)); + set_ignore_cookie(ps, xcb_composite_name_window_pixmap(ps->c, w->base.id, + w->paint.pixmap)); } xcb_drawable_t draw = w->paint.pixmap; if (!draw) { log_error("Failed to get pixmap from window %#010x (%s), window won't be " "visible", - w->id, w->name); + w->base.id, w->name); 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. if (!paint_bind_tex(ps, &w->paint, 0, 0, false, 0, w->a.visual, (!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; 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; } @@ -504,7 +504,7 @@ static void paint_root(session_t *ps, const region_t *reg_paint) { /** * Generate shadow Picture 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 height = w->heightb; // 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. */ -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 paint_bind_tex(ps, &w->shadow_paint, 0, 0, false, 32, 0, false); 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; } @@ -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. */ -static inline void win_blur_background(session_t *ps, win *w, xcb_render_picture_t tgt_buffer, - const region_t *reg_paint) { +static inline void +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 y = w->g.y; 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 /// 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->xsync_exists && !x_fence_sync(ps->c, ps->sync_fence)) { 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. // // 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); // Painting shadow if (w->shadow) { diff --git a/src/render.h b/src/render.h index 430e670d..92b71c8e 100644 --- a/src/render.h +++ b/src/render.h @@ -12,9 +12,10 @@ typedef struct _glx_texture glx_texture_t; typedef struct glx_prog_main glx_prog_main_t; -typedef struct win win; typedef struct session session_t; +struct managed_win; + typedef struct paint { xcb_pixmap_t pixmap; 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, bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex, 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); diff --git a/src/win.c b/src/win.c index ca001d4d..b4daf32e 100644 --- a/src/win.c +++ b/src/win.c @@ -20,6 +20,7 @@ #include "compiler.h" #include "compton.h" #include "config.h" +#include "list.h" #include "log.h" #include "region.h" #include "render.h" @@ -28,7 +29,6 @@ #include "uthash_extra.h" #include "utils.h" #include "x.h" -#include "list.h" #ifdef CONFIG_DBUS #include "dbus.h" @@ -47,7 +47,7 @@ /// region via a region_t pointer argument. /// Function signature has to be (win *, region_t *) #define gen_by_val(fun) \ - region_t fun##_by_val(const win *w) { \ + region_t fun##_by_val(const struct managed_win *w) { \ region_t ret; \ pixman_region32_init(&ret); \ fun(w, &ret); \ @@ -58,7 +58,7 @@ * Clear leader cache of all windows. */ static inline void clear_cache_win_leaders(session_t *ps) { - list_foreach(win, w, &ps->window_stack, stack_neighbour) { + win_stack_foreach_managed(w, &ps->window_stack) { w->cache_leader = XCB_NONE; } } @@ -83,9 +83,13 @@ static inline void group_update_focused(session_t *ps, xcb_window_t leader) { return; HASH_ITER2(ps->windows, w) { - assert(w->state != WSTATE_DESTROYING); - if (win_get_leader(ps, w) == leader) { - win_update_focused(ps, w); + assert(!w->destroyed); + if (!w->managed) { + continue; + } + auto mw = (struct managed_win *)w; + if (win_get_leader(ps, mw) == leader) { + win_update_focused(ps, mw); } } @@ -99,12 +103,17 @@ static inline void group_update_focused(session_t *ps, xcb_window_t leader) { * @return true if the window group is focused, false otherwise */ static inline bool group_is_focused(session_t *ps, xcb_window_t leader) { - if (!leader) + if (!leader) { return false; + } HASH_ITER2(ps->windows, w) { - assert(w->state != WSTATE_DESTROYING); - if (win_get_leader(ps, w) == leader && win_is_focused_real(ps, w)) { + assert(!w->destroyed); + if (!w->managed) { + continue; + } + auto mw = (struct managed_win *)w; + if (win_get_leader(ps, mw) == leader && win_is_focused_real(ps, mw)) { return true; } } @@ -115,7 +124,7 @@ static inline bool group_is_focused(session_t *ps, xcb_window_t leader) { /** * Get a rectangular region a window occupies, excluding shadow. */ -static void win_get_region_local(const win *w, region_t *res) { +static void win_get_region_local(const struct managed_win *w, region_t *res) { assert(w->widthb >= 0 && w->heightb >= 0); pixman_region32_fini(res); pixman_region32_init_rect(res, 0, 0, (uint)w->widthb, (uint)w->heightb); @@ -124,7 +133,7 @@ static void win_get_region_local(const win *w, region_t *res) { /** * Get a rectangular region a window occupies, excluding frame and shadow. */ -void win_get_region_noframe_local(const win *w, region_t *res) { +void win_get_region_noframe_local(const struct managed_win *w, region_t *res) { const margin_t extents = win_calc_frame_extents(w); int x = extents.left; @@ -140,7 +149,7 @@ void win_get_region_noframe_local(const win *w, region_t *res) { gen_by_val(win_get_region_noframe_local); -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) { const margin_t extents = win_calc_frame_extents(w); pixman_region32_fini(res); pixman_region32_init_rects( @@ -172,7 +181,7 @@ gen_by_val(win_get_region_frame_local); * @param ps current session * @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) { // XXX there was a cached extents region, investigate // if that's better region_t extents; @@ -183,7 +192,7 @@ void add_damage_from_win(session_t *ps, win *w) { } /// Release the images attached to this window -void win_release_image(backend_t *base, win *w) { +void win_release_image(backend_t *base, struct managed_win *w) { assert(w->win_image || (w->flags & WIN_FLAGS_IMAGE_ERROR)); if (w->win_image) { base->ops->release_image(base, w->win_image); @@ -199,12 +208,12 @@ void win_release_image(backend_t *base, win *w) { } static inline bool -_win_bind_image(session_t *ps, win *w, void **win_image, void **shadow_image) { +_win_bind_image(session_t *ps, struct managed_win *w, void **win_image, void **shadow_image) { auto pixmap = x_new_id(ps->c); auto e = xcb_request_check( - ps->c, xcb_composite_name_window_pixmap_checked(ps->c, w->id, pixmap)); + ps->c, xcb_composite_name_window_pixmap_checked(ps->c, w->base.id, pixmap)); if (e) { - log_error("Failed to get named pixmap for window %#010x(%s)", w->id, w->name); + log_error("Failed to get named pixmap for window %#010x(%s)", w->base.id, w->name); free(e); return false; } @@ -228,12 +237,12 @@ _win_bind_image(session_t *ps, win *w, void **win_image, void **shadow_image) { return true; } -bool win_bind_image(session_t *ps, win *w) { +bool win_bind_image(session_t *ps, struct managed_win *w) { assert(!w->win_image && !w->shadow_image); return _win_bind_image(ps, w, &w->win_image, &w->shadow_image); } -bool win_try_rebind_image(session_t *ps, win *w) { +bool win_try_rebind_image(session_t *ps, struct managed_win *w) { log_trace("Freeing old window image"); // Must release first, otherwise breaks NVIDIA driver win_release_image(ps->backend_data, w); @@ -245,7 +254,7 @@ bool win_try_rebind_image(session_t *ps, win *w) { * Check if a window has rounded corners. * XXX This is really dumb */ -static bool attr_pure win_has_rounded_corners(const win *w) { +static bool attr_pure win_has_rounded_corners(const struct managed_win *w) { if (!w->bounding_shaped) { return false; } @@ -278,7 +287,7 @@ static bool attr_pure win_has_rounded_corners(const win *w) { return false; } -int win_get_name(session_t *ps, win *w) { +int win_get_name(session_t *ps, struct managed_win *w) { XTextProperty text_prop = {NULL, XCB_NONE, 0, 0}; char **strlst = NULL; int nstr = 0; @@ -314,11 +323,11 @@ int win_get_name(session_t *ps, win *w) { log_trace("(%#010x): client = %#010x, name = \"%s\", " "ret = %d", - w->id, w->client_win, w->name, ret); + w->base.id, w->client_win, w->name, ret); return ret; } -int win_get_role(session_t *ps, win *w) { +int win_get_role(session_t *ps, struct managed_win *w) { char **strlst = NULL; int nstr = 0; @@ -336,7 +345,7 @@ int win_get_role(session_t *ps, win *w) { log_trace("(%#010x): client = %#010x, role = \"%s\", " "ret = %d", - w->id, w->client_win, w->role, ret); + w->base.id, w->client_win, w->role, ret); return ret; } @@ -394,12 +403,12 @@ wid_get_opacity_prop(session_t *ps, xcb_window_t wid, opacity_t def, opacity_t * } // XXX should distinguish between frame has alpha and window body has alpha -bool win_has_alpha(const win *w) { +bool win_has_alpha(const struct managed_win *w) { return w->pictfmt && w->pictfmt->type == XCB_RENDER_PICT_TYPE_DIRECT && w->pictfmt->direct.alpha_mask; } -winmode_t win_calc_mode(const win *w) { +winmode_t win_calc_mode(const struct managed_win *w) { if (win_has_alpha(w) || w->opacity < 1.0) { return WMODE_TRANS; } @@ -429,7 +438,7 @@ winmode_t win_calc_mode(const win *w) { * * @return target opacity */ -double win_calc_opacity_target(session_t *ps, const win *w) { +double win_calc_opacity_target(session_t *ps, const struct managed_win *w) { double opacity = 1; if (w->state == WSTATE_UNMAPPED) { @@ -463,7 +472,7 @@ double win_calc_opacity_target(session_t *ps, const win *w) { /** * Determine whether a window is to be dimmed. */ -bool win_should_dim(session_t *ps, const win *w) { +bool win_should_dim(session_t *ps, const struct managed_win *w) { // Make sure we do nothing if the window is unmapped / being destroyed if (w->state == WSTATE_UNMAPPED) { return false; @@ -479,7 +488,7 @@ bool win_should_dim(session_t *ps, const win *w) { /** * Determine if a window should fade on opacity change. */ -bool win_should_fade(session_t *ps, const win *w) { +bool win_should_fade(session_t *ps, const struct managed_win *w) { // To prevent it from being overwritten by last-paint value if the window is if (w->fade_force != UNSET) { return w->fade_force; @@ -488,7 +497,7 @@ bool win_should_fade(session_t *ps, const win *w) { return false; } if (ps->o.no_fading_destroyed_argb && w->state == WSTATE_DESTROYING && - win_has_alpha(w) && w->client_win && w->client_win != w->id) { + win_has_alpha(w) && w->client_win && w->client_win != w->base.id) { // deprecated return false; } @@ -507,9 +516,9 @@ bool win_should_fade(session_t *ps, const win *w) { * * The property must be set on the outermost window, usually the WM frame. */ -void win_update_prop_shadow_raw(session_t *ps, win *w) { +void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w) { winprop_t prop = - wid_get_prop(ps, w->id, ps->atom_compton_shadow, 1, XCB_ATOM_CARDINAL, 32); + wid_get_prop(ps, w->base.id, ps->atom_compton_shadow, 1, XCB_ATOM_CARDINAL, 32); if (!prop.nitems) { w->prop_shadow = -1; @@ -524,7 +533,7 @@ void win_update_prop_shadow_raw(session_t *ps, win *w) { * Reread _COMPTON_SHADOW property from a window and update related * things. */ -void win_update_prop_shadow(session_t *ps, win *w) { +void win_update_prop_shadow(session_t *ps, struct managed_win *w) { long attr_shadow_old = w->prop_shadow; win_update_prop_shadow_raw(ps, w); @@ -533,12 +542,12 @@ void win_update_prop_shadow(session_t *ps, win *w) { win_determine_shadow(ps, 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) { if (w->shadow == shadow_new) { return; } - log_debug("Updating shadow property of window %#010x (%s) to %d", w->id, w->name, + log_debug("Updating shadow property of window %#010x (%s) to %d", w->base.id, w->name, shadow_new); if (ps->o.experimental_backends && ps->redirected && w->state != WSTATE_UNMAPPED && !(w->flags & WIN_FLAGS_IMAGE_ERROR)) { @@ -580,8 +589,8 @@ void win_set_shadow(session_t *ps, win *w, bool shadow_new) { * Determine if a window should have shadow, and update things depending * on shadow state. */ -void win_determine_shadow(session_t *ps, win *w) { - log_debug("Determining shadow of window %#010x (%s)", w->id, w->name); +void win_determine_shadow(session_t *ps, struct managed_win *w) { + log_debug("Determining shadow of window %#010x (%s)", w->base.id, w->name); bool shadow_new = w->shadow; if (w->shadow_force != UNSET) { @@ -607,7 +616,7 @@ void win_determine_shadow(session_t *ps, win *w) { win_set_shadow(ps, w, shadow_new); } -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) { if (w->invert_color == invert_color_new) return; @@ -616,10 +625,52 @@ void win_set_invert_color(session_t *ps, win *w, bool invert_color_new) { add_damage_from_win(ps, w); } +/** + * Set w->invert_color_force of a window. + */ +void win_set_invert_color_force(session_t *ps, struct managed_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); + } +} + +/** + * Set w->fade_force of a window. + * + * Doesn't affect fading already in progress + */ +void win_set_fade_force(session_t *ps, struct managed_win *w, switch_t val) { + w->fade_force = val; +} + +/** + * Set w->focused_force of a window. + */ +void win_set_focused_force(session_t *ps, struct managed_win *w, switch_t val) { + if (val != w->focused_force) { + w->focused_force = val; + win_update_focused(ps, w); + queue_redraw(ps); + } +} + +/** + * Set w->shadow_force of a window. + */ +void win_set_shadow_force(session_t *ps, struct managed_win *w, switch_t val) { + if (val != w->shadow_force) { + w->shadow_force = val; + win_determine_shadow(ps, w); + queue_redraw(ps); + } +} + /** * Determine if a window should have color inverted. */ -void win_determine_invert_color(session_t *ps, win *w) { +void win_determine_invert_color(session_t *ps, struct managed_win *w) { bool invert_color_new = w->invert_color; if (UNSET != w->invert_color_force) @@ -630,7 +681,7 @@ void win_determine_invert_color(session_t *ps, win *w) { win_set_invert_color(ps, w, invert_color_new); } -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) { if (w->blur_background == blur_background_new) return; @@ -645,7 +696,7 @@ void win_set_blur_background(session_t *ps, win *w, bool blur_background_new) { /** * Determine if a window should have background blurred. */ -void win_determine_blur_background(session_t *ps, win *w) { +void win_determine_blur_background(session_t *ps, struct managed_win *w) { if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) return; @@ -661,7 +712,7 @@ void win_determine_blur_background(session_t *ps, win *w) { * TODO This override the window's opacity property, may not be * a good idea. */ -void win_update_opacity_rule(session_t *ps, win *w) { +void win_update_opacity_rule(session_t *ps, struct managed_win *w) { if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) return; @@ -678,16 +729,17 @@ void win_update_opacity_rule(session_t *ps, win *w) { w->opacity_set = opacity; w->opacity_is_set = is_set; - if (!is_set) - wid_rm_opacity_prop(ps, w->id); - else - wid_set_opacity_prop(ps, w->id, (opacity_t)(opacity * OPAQUE)); + if (!is_set) { + wid_rm_opacity_prop(ps, w->base.id); + } else { + wid_set_opacity_prop(ps, w->base.id, (opacity_t)(opacity * OPAQUE)); + } } /** * Function to be called on window type changes. */ -void win_on_wtype_change(session_t *ps, win *w) { +void win_on_wtype_change(session_t *ps, struct managed_win *w) { win_determine_shadow(ps, w); win_update_focused(ps, w); if (ps->o.invert_color_list) @@ -701,7 +753,7 @@ void win_on_wtype_change(session_t *ps, win *w) { * * TODO need better name */ -void win_on_factor_change(session_t *ps, win *w) { +void win_on_factor_change(session_t *ps, struct managed_win *w) { if (ps->o.shadow_blacklist) win_determine_shadow(ps, w); if (ps->o.invert_color_list) @@ -723,7 +775,7 @@ void win_on_factor_change(session_t *ps, win *w) { /** * 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) { w->widthb = w->g.width + w->g.border_width * 2; w->heightb = w->g.height + w->g.border_width * 2; w->shadow_dx = ps->o.shadow_offset_x; @@ -734,7 +786,7 @@ void win_on_win_size_change(session_t *ps, win *w) { if (ps->o.experimental_backends && ps->redirected) { if (w->state == WSTATE_MAPPED || w->state == WSTATE_MAPPING || w->state == WSTATE_FADING) { - w->flags |= WIN_FLAGS_STALE_IMAGE; + w->flags |= WIN_FLAGS_IMAGE_STALE; } else { assert(w->state == WSTATE_UNMAPPED); } @@ -746,7 +798,7 @@ void win_on_win_size_change(session_t *ps, win *w) { /** * Update window type. */ -void win_update_wintype(session_t *ps, win *w) { +void win_update_wintype(session_t *ps, struct managed_win *w) { const wintype_t wtype_old = w->window_type; // Detect window type here @@ -774,7 +826,7 @@ void win_update_wintype(session_t *ps, win *w) { * @param w struct _win of the parent window * @param client window ID of the client window */ -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) { w->client_win = client; // If the window isn't mapped yet, stop here, as the function will be @@ -821,7 +873,7 @@ void win_mark_client(session_t *ps, win *w, xcb_window_t client) { * @param ps current session * @param w struct _win of the parent window */ -void win_unmark_client(session_t *ps, win *w) { +void win_unmark_client(session_t *ps, struct managed_win *w) { xcb_window_t client = w->client_win; w->client_win = XCB_NONE; @@ -838,7 +890,7 @@ void win_unmark_client(session_t *ps, win *w) { * @param ps current session * @param w struct _win of the parent window */ -void win_recheck_client(session_t *ps, win *w) { +void win_recheck_client(session_t *ps, struct managed_win *w) { // Initialize wmwin to false w->wmwin = false; @@ -846,15 +898,16 @@ void win_recheck_client(session_t *ps, win *w) { // Always recursively look for a window with WM_STATE, as Fluxbox // sets override-redirect flags on all frame windows. - xcb_window_t cw = find_client_win(ps, w->id); - if (cw) - log_trace("(%#010x): client %#010x", w->id, cw); + xcb_window_t cw = find_client_win(ps, w->base.id); + if (cw) { + log_trace("(%#010x): client %#010x", w->base.id, cw); + } // Set a window's client window to itself if we couldn't find a // client window if (!cw) { - cw = w->id; + cw = w->base.id; w->wmwin = !w->a.override_redirect; - log_trace("(%#010x): client self (%s)", w->id, + log_trace("(%#010x): client self (%s)", w->base.id, (w->wmwin ? "wmwin" : "override-redirected")); } @@ -869,7 +922,7 @@ void win_recheck_client(session_t *ps, win *w) { /** * 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) { // No need to call backend release_image here because // finish_unmap_win should've done that for us. // XXX unless we are called by session_destroy @@ -890,9 +943,46 @@ void free_win_res(session_t *ps, win *w) { free(w->role); } -// TODO: probably split into win_new (in win.c) and add_win (in compton.c) -void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) { - static const win win_def = { +/// 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) { + struct win *w = NULL; + HASH_FIND_INT(ps->windows, &below, w); + if (!w && !list_is_empty(&ps->window_stack)) { + // `below` window is not found even if the window stack is not empty + return NULL; + } + + auto new_w = cmalloc(struct win); + if (list_is_empty(&ps->window_stack)) { + assert(w == NULL); + list_insert_after(&ps->window_stack, &new_w->stack_neighbour); + } else { + list_insert_before(&w->stack_neighbour, &new_w->stack_neighbour); + } + new_w->id = id; + new_w->managed = false; + new_w->is_new = true; + new_w->destroyed = false; + + HASH_ADD_INT(ps->windows, id, new_w); + return new_w; +} + +/// Insert a new win entry at the top of the stack +struct win *add_win_top(session_t *ps, xcb_window_t id) { + if (!list_is_empty(&ps->window_stack)) { + auto first = list_entry(ps->window_stack.next, struct win, stack_neighbour); + return add_win_above(ps, id, first->id); + } else { + return add_win_above(ps, id, 0); + } +} + +/// 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 *w) { + static const struct managed_win win_def = { // No need to initialize. (or, you can think that // they are initialized right here). // The following ones are updated during paint or paint preprocess @@ -919,7 +1009,6 @@ void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) { .invert_color_force = UNSET, // Initialized in this function - .id = XCB_NONE, .a = {0}, .pictfmt = NULL, .widthb = 0, @@ -970,20 +1059,24 @@ void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) { .shadow_paint = PAINT_INIT, }; + assert(!w->destroyed); + assert(w->is_new); + // Reject overlay window and already added windows - if (id == ps->overlay) { + if (w->id == ps->overlay) { return; } - auto duplicated_win = find_win(ps, id); + auto duplicated_win = find_managed_win(ps, w->id); if (duplicated_win) { - log_debug("Window %#010x (recorded name: %s) added multiple times", id, + log_debug("Window %#010x (recorded name: %s) added multiple times", w->id, duplicated_win->name); return; } - log_debug("Adding window %#010x, prev %#010x", id, prev); - xcb_get_window_attributes_cookie_t acookie = xcb_get_window_attributes(ps->c, id); + log_debug("Adding window %#010x", w->id); + xcb_get_window_attributes_cookie_t acookie = + xcb_get_window_attributes(ps->c, w->id); xcb_get_window_attributes_reply_t *a = xcb_get_window_attributes_reply(ps->c, acookie, NULL); if (!a || a->map_state == XCB_MAP_STATE_UNVIEWABLE) { @@ -996,51 +1089,51 @@ void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) { return; } + if (a->_class == XCB_WINDOW_CLASS_INPUT_ONLY) { + // No need to manage this window, but we still keep it on the window stack + w->managed = false; + w->is_new = false; + return; + } + // Allocate and initialize the new win structure - auto new = cmalloc(win); + auto new = cmalloc(struct managed_win); // Fill structure // We only need to initialize the part that are not initialized // by map_win *new = win_def; - new->id = id; + new->base = *w; + new->base.is_new = false; + new->base.managed = true; new->a = *a; pixman_region32_init(&new->bounding_shape); free(a); // Create Damage for window (if not Input Only) - if (new->a._class != XCB_WINDOW_CLASS_INPUT_ONLY) { - new->damage = x_new_id(ps->c); - xcb_generic_error_t *e = xcb_request_check( - ps->c, xcb_damage_create_checked(ps->c, new->damage, id, - XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY)); - if (e) { - free(e); - free(new); - return; - } - - new->pictfmt = x_get_pictform_for_visual(ps->c, new->a.visual); + new->damage = x_new_id(ps->c); + xcb_generic_error_t *e = xcb_request_check( + ps->c, xcb_damage_create_checked(ps->c, new->damage, w->id, + XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY)); + if (e) { + free(e); + free(new); + return; } - // Find window insertion point - struct list_node *p = NULL; - if (prev) { - win *w = NULL; - HASH_FIND_INT(ps->windows, &prev, w); - assert(w); - p = w->stack_neighbour.prev; - } else { - p = &ps->window_stack; - } - list_insert_after(p, &new->stack_neighbour); - HASH_ADD_INT(ps->windows, id, new); + new->pictfmt = x_get_pictform_for_visual(ps->c, new->a.visual); + + list_replace(&w->stack_neighbour, &new->base.stack_neighbour); + struct win *replaced = NULL; + HASH_REPLACE_INT(ps->windows, id, &new->base, replaced); + assert(replaced == w); + free(w); #ifdef CONFIG_DBUS // Send D-Bus signal if (ps->o.dbus) { - cdbus_ev_win_added(ps, new); + cdbus_ev_win_added(ps, &new->base); } #endif return; @@ -1049,7 +1142,7 @@ void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) { /** * 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) { if (UNSET != w->focused_force) { w->focused = w->focused_force; } else { @@ -1059,7 +1152,7 @@ void win_update_focused(session_t *ps, win *w) { // windows specially if (ps->o.wintype_option[w->window_type].focus || (ps->o.mark_wmwin_focused && w->wmwin) || - (ps->o.mark_ovredir_focused && w->id == w->client_win && !w->wmwin) || + (ps->o.mark_ovredir_focused && w->base.id == w->client_win && !w->wmwin) || (w->a.map_state == XCB_MAP_STATE_VIEWABLE && c2_match(ps, w, ps->o.focus_blacklist, NULL))) w->focused = true; @@ -1088,7 +1181,7 @@ void win_update_focused(session_t *ps, win *w) { /** * Set leader of a window. */ -static inline void win_set_leader(session_t *ps, win *w, xcb_window_t nleader) { +static inline void win_set_leader(session_t *ps, struct managed_win *w, xcb_window_t nleader) { // If the leader changes if (w->leader != nleader) { xcb_window_t cache_leader_old = win_get_leader(ps, w); @@ -1121,7 +1214,7 @@ static inline void win_set_leader(session_t *ps, win *w, xcb_window_t nleader) { /** * 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) { xcb_window_t leader = XCB_NONE; // Read the leader properties @@ -1133,14 +1226,14 @@ void win_update_leader(session_t *ps, win *w) { win_set_leader(ps, w, leader); - log_trace("(%#010x): client %#010x, leader %#010x, cache %#010x", w->id, + log_trace("(%#010x): client %#010x, leader %#010x, cache %#010x", w->base.id, w->client_win, w->leader, win_get_leader(ps, w)); } /** * Internal function of win_get_leader(). */ -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) { // Rebuild the cache if needed if (!w->cache_leader && (w->client_win || w->leader)) { // Leader defaults to client window @@ -1149,7 +1242,7 @@ xcb_window_t win_get_leader_raw(session_t *ps, win *w, int recursions) { // If the leader of this window isn't itself, look for its ancestors if (w->cache_leader && w->cache_leader != w->client_win) { - win *wp = find_toplevel(ps, w->cache_leader); + auto wp = find_toplevel(ps, w->cache_leader); if (wp) { // Dead loop? if (recursions > WIN_GET_LEADER_MAX_RECURSION) @@ -1167,7 +1260,7 @@ xcb_window_t win_get_leader_raw(session_t *ps, win *w, int recursions) { * Retrieve the WM_CLASS of a window and update its * win structure. */ -bool win_get_class(session_t *ps, win *w) { +bool win_get_class(session_t *ps, struct managed_win *w) { char **strlst = NULL; int nstr = 0; @@ -1195,7 +1288,7 @@ bool win_get_class(session_t *ps, win *w) { log_trace("(%#010x): client = %#010x, " "instance = \"%s\", general = \"%s\"", - w->id, w->client_win, w->class_instance, w->class_general); + w->base.id, w->client_win, w->class_instance, w->class_general); return true; } @@ -1203,7 +1296,7 @@ bool win_get_class(session_t *ps, win *w) { /** * Handle window focus change. */ -static void win_on_focus_change(session_t *ps, win *w) { +static void win_on_focus_change(session_t *ps, struct managed_win *w) { // If window grouping detection is enabled if (ps->o.track_leader) { xcb_window_t leader = win_get_leader(ps, w); @@ -1239,9 +1332,9 @@ static void win_on_focus_change(session_t *ps, win *w) { // Send D-Bus signal if (ps->o.dbus) { if (win_is_focused_real(ps, w)) - cdbus_ev_win_focusin(ps, w); + cdbus_ev_win_focusin(ps, &w->base); else - cdbus_ev_win_focusout(ps, w); + cdbus_ev_win_focusout(ps, &w->base); } #endif } @@ -1249,7 +1342,7 @@ static void win_on_focus_change(session_t *ps, win *w) { /** * 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) { // Unmapped windows will have their focused state reset on map if (w->a.map_state == XCB_MAP_STATE_UNMAPPED) return; @@ -1275,7 +1368,7 @@ void win_set_focused(session_t *ps, win *w, bool focused) { * Note w->shadow and shadow geometry must be correct before calling this * function. */ -void win_extents(const win *w, region_t *res) { +void win_extents(const struct managed_win *w, region_t *res) { pixman_region32_clear(res); pixman_region32_union_rect(res, res, w->g.x, w->g.y, (uint)w->widthb, (uint)w->heightb); @@ -1294,9 +1387,9 @@ gen_by_val(win_extents); * * Mark the window shape as updated */ -void win_update_bounding_shape(session_t *ps, win *w) { +void win_update_bounding_shape(session_t *ps, struct managed_win *w) { if (ps->shape_exists) - w->bounding_shaped = win_bounding_shaped(ps, w->id); + w->bounding_shaped = win_bounding_shaped(ps, w->base.id); pixman_region32_clear(&w->bounding_shape); // Start with the window rectangular region @@ -1311,7 +1404,8 @@ void win_update_bounding_shape(session_t *ps, win *w) { */ xcb_shape_get_rectangles_reply_t *r = xcb_shape_get_rectangles_reply( - ps->c, xcb_shape_get_rectangles(ps->c, w->id, XCB_SHAPE_SK_BOUNDING), NULL); + ps->c, + xcb_shape_get_rectangles(ps->c, w->base.id, XCB_SHAPE_SK_BOUNDING), NULL); if (!r) break; @@ -1353,7 +1447,7 @@ void win_update_bounding_shape(session_t *ps, win *w) { // Note we only do this when screen is redirected, because // otherwise win_data is not valid assert(w->state != WSTATE_UNMAPPING && w->state != WSTATE_DESTROYING); - w->flags |= WIN_FLAGS_STALE_IMAGE; + w->flags |= WIN_FLAGS_IMAGE_STALE; } } else { free_paint(ps, &w->paint); @@ -1366,15 +1460,15 @@ void win_update_bounding_shape(session_t *ps, win *w) { /** * 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) { // get frame opacity first - w->has_opacity_prop = wid_get_opacity_prop(ps, w->id, OPAQUE, &w->opacity_prop); + w->has_opacity_prop = wid_get_opacity_prop(ps, w->base.id, OPAQUE, &w->opacity_prop); if (w->has_opacity_prop) // opacity found return; - if (ps->o.detect_client_opacity && w->client_win && w->id == w->client_win) + if (ps->o.detect_client_opacity && w->client_win && w->base.id == w->client_win) // checking client opacity not allowed return; @@ -1386,7 +1480,7 @@ void win_update_opacity_prop(session_t *ps, win *w) { /** * 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) { winprop_t prop = wid_get_prop(ps, client, ps->atom_frame_extents, 4L, XCB_ATOM_CARDINAL, 32); @@ -1412,14 +1506,14 @@ void win_update_frame_extents(session_t *ps, win *w, xcb_window_t client) { w->reg_ignore_valid = false; } - log_trace("(%#010x): %d, %d, %d, %d", w->id, w->frame_extents.left, + log_trace("(%#010x): %d, %d, %d, %d", w->base.id, w->frame_extents.left, w->frame_extents.right, w->frame_extents.top, w->frame_extents.bottom); free_winprop(&prop); } -bool win_is_region_ignore_valid(session_t *ps, const win *w) { - list_foreach(win, i, &ps->window_stack, stack_neighbour) { +bool win_is_region_ignore_valid(session_t *ps, const struct managed_win *w) { + win_stack_foreach_managed(i, &ps->window_stack) { if (i == w) break; if (!i->reg_ignore_valid) @@ -1431,11 +1525,16 @@ bool win_is_region_ignore_valid(session_t *ps, const win *w) { /** * Stop listening for events on a particular window. */ -void win_ev_stop(session_t *ps, const win *w) { +void win_ev_stop(session_t *ps, const struct win *w) { xcb_change_window_attributes(ps->c, w->id, XCB_CW_EVENT_MASK, (const uint32_t[]){0}); - if (w->client_win) { - xcb_change_window_attributes(ps->c, w->client_win, XCB_CW_EVENT_MASK, + if (!w->managed) { + return; + } + + auto mw = (struct managed_win *)w; + if (mw->client_win) { + xcb_change_window_attributes(ps->c, mw->client_win, XCB_CW_EVENT_MASK, (const uint32_t[]){0}); } @@ -1444,8 +1543,8 @@ void win_ev_stop(session_t *ps, const win *w) { } } -static void finish_unmap_win(session_t *ps, win **_w) { - win *w = *_w; +static void finish_unmap_win(session_t *ps, struct managed_win **_w) { + auto w = *_w; w->ever_damaged = false; w->reg_ignore_valid = false; w->state = WSTATE_UNMAPPED; @@ -1463,8 +1562,8 @@ static void finish_unmap_win(session_t *ps, win **_w) { w->flags = 0; } -static void finish_destroy_win(session_t *ps, win **_w) { - win *w = *_w; +static void finish_destroy_win(session_t *ps, struct managed_win **_w) { + auto w = *_w; if (w->state != WSTATE_UNMAPPED) { // Only UNMAPPED state has window resources freed, otherwise @@ -1479,14 +1578,14 @@ static void finish_destroy_win(session_t *ps, win **_w) { // paint happened at least once, w->reg_ignore_valid would // be true, and there is no need to invalid w->next->reg_ignore // when w is destroyed. - if (!list_node_is_last(&ps->window_stack, &w->stack_neighbour)) { - auto next_w = list_next_entry(w, stack_neighbour); + if (!list_node_is_last(&ps->window_stack, &w->base.stack_neighbour)) { + auto next_w = list_next_entry(w, base.stack_neighbour); // XXX rc_region_unref(&next_w->reg_ignore); next_w->reg_ignore_valid = false; } - log_trace("Trying to destroy (%#010x)", w->id); - list_remove(&w->stack_neighbour); + log_trace("Trying to destroy (%#010x)", w->base.id); + list_remove(&w->base.stack_neighbour); if (w == ps->active_win) { ps->active_win = NULL; @@ -1497,7 +1596,7 @@ static void finish_destroy_win(session_t *ps, win **_w) { // Drop w from all prev_trans to avoid accessing freed memory in // repair_win() // TODO there can only be one prev_trans pointing to w - list_foreach(win, w2, &ps->window_stack, stack_neighbour) { + win_stack_foreach_managed(w2, &ps->window_stack) { if (w == w2->prev_trans) { w2->prev_trans = NULL; } @@ -1509,14 +1608,14 @@ static void finish_destroy_win(session_t *ps, win **_w) { assert(false); } -static void finish_map_win(session_t *ps, win **_w) { - win *w = *_w; +static void finish_map_win(session_t *ps, struct managed_win **_w) { + auto w = *_w; w->in_openclose = false; w->state = WSTATE_MAPPED; } -void unmap_win(session_t *ps, win **_w, bool destroy) { - win *w = *_w; +void unmap_win(session_t *ps, struct managed_win **_w, bool destroy) { + auto w = *_w; winstate_t target_state = destroy ? WSTATE_DESTROYING : WSTATE_UNMAPPING; @@ -1532,7 +1631,7 @@ void unmap_win(session_t *ps, win **_w, bool destroy) { return; } - log_trace("Unmapping %#010x \"%s\", destroy = %d", w->id, (w ? w->name : NULL), destroy); + log_trace("Unmapping %#010x \"%s\", destroy = %d", w->base.id, (w ? w->name : NULL), destroy); if (unlikely(w->state == WSTATE_DESTROYING && !destroy)) { log_warn("Trying to undestroy a window?"); @@ -1551,13 +1650,13 @@ void unmap_win(session_t *ps, win **_w, bool destroy) { // Keep the window in the window stack, since we might still need to // render it (fading out). Window will be removed from the stack when // fading finishes. - HASH_DEL(ps->windows, w); + HASH_DEL(ps->windows, &w->base); } if (unlikely(w->state == WSTATE_UNMAPPED) || w->a._class == XCB_WINDOW_CLASS_INPUT_ONLY) { if (unlikely(!destroy)) { log_warn("Unmapping an already unmapped window %#010x %s twice", - w->id, w->name); + w->base.id, w->name); return; } // Window is already unmapped, or is an Input Only window, just destroy it @@ -1576,16 +1675,16 @@ void unmap_win(session_t *ps, win **_w, bool destroy) { // don't care about properties anymore if (!destroy) { - win_ev_stop(ps, w); + win_ev_stop(ps, &w->base); } #ifdef CONFIG_DBUS // Send D-Bus signal if (ps->o.dbus) { if (destroy) { - cdbus_ev_win_destroyed(ps, w); + cdbus_ev_win_destroyed(ps, &w->base); } else { - cdbus_ev_win_unmapped(ps, w); + cdbus_ev_win_unmapped(ps, &w->base); } } #endif @@ -1598,8 +1697,8 @@ void unmap_win(session_t *ps, win **_w, bool destroy) { /** * Execute fade callback of a window if fading finished. */ -void win_check_fade_finished(session_t *ps, win **_w) { - win *w = *_w; +void win_check_fade_finished(session_t *ps, struct managed_win **_w) { + auto w = *_w; if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) { // No fading in progress assert(w->opacity_tgt == w->opacity); @@ -1618,13 +1717,13 @@ void win_check_fade_finished(session_t *ps, win **_w) { /// Skip the current in progress fading of window, /// transition the window straight to its end state -void win_skip_fading(session_t *ps, win **_w) { - win *w = *_w; +void win_skip_fading(session_t *ps, struct managed_win **_w) { + auto w = *_w; if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) { assert(w->opacity_tgt == w->opacity); return; } - log_trace("Skipping fading process of window %#010x (%s)", w->id, w->name); + log_trace("Skipping fading process of window %#010x (%s)", w->base.id, w->name); w->opacity = w->opacity_tgt; win_check_fade_finished(ps, _w); } @@ -1637,7 +1736,7 @@ void win_skip_fading(session_t *ps, win **_w) { * TODO move to x.c * TODO use xrandr */ -void win_update_screen(session_t *ps, win *w) { +void win_update_screen(session_t *ps, struct managed_win *w) { w->xinerama_scr = -1; if (!ps->xinerama_scrs) @@ -1661,7 +1760,7 @@ void win_update_screen(session_t *ps, win *w) { void configure_win(session_t *, xcb_configure_notify_event_t *); /// Map an already registered window -void map_win(session_t *ps, win *w) { +void map_win(session_t *ps, struct managed_win *w) { assert(w); // Don't care about window mapping if it's an InputOnly window @@ -1670,7 +1769,7 @@ void map_win(session_t *ps, win *w) { return; } - log_debug("Mapping (%#010x \"%s\")", w->id, w->name); + log_debug("Mapping (%#010x \"%s\")", w->base.id, w->name); assert(w->state != WSTATE_DESTROYING); if (w->state != WSTATE_UNMAPPED && w->state != WSTATE_UNMAPPING) { @@ -1688,11 +1787,11 @@ void map_win(session_t *ps, win *w) { // We stopped processing window size change when we were unmapped, refresh the // size of the window - xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(ps->c, w->id); + xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(ps->c, w->base.id); xcb_get_geometry_reply_t *g = xcb_get_geometry_reply(ps->c, gcookie, NULL); if (!g) { - log_error("Failed to get the geometry of window %#010x", w->id); + log_error("Failed to get the geometry of window %#010x", w->base.id); return; } @@ -1717,12 +1816,12 @@ void map_win(session_t *ps, win *w) { // Set window event mask before reading properties so that no property // changes are lost xcb_change_window_attributes( - ps->c, w->id, XCB_CW_EVENT_MASK, - (const uint32_t[]){determine_evmask(ps, w->id, WIN_EVMODE_FRAME)}); + ps->c, w->base.id, XCB_CW_EVENT_MASK, + (const uint32_t[]){determine_evmask(ps, w->base.id, WIN_EVMODE_FRAME)}); // Notify compton when the shape of a window changes if (ps->shape_exists) { - xcb_shape_select_input(ps->c, w->id, 1); + xcb_shape_select_input(ps->c, w->base.id, 1); } // Update window mode here to check for ARGB windows @@ -1738,7 +1837,7 @@ void map_win(session_t *ps, win *w) { } assert(w->client_win); - log_debug("Window (%#010x) has type %s", w->id, WINTYPES[w->window_type]); + log_debug("Window (%#010x) has type %s", w->base.id, WINTYPES[w->window_type]); // Update window focus state win_update_focused(ps, w); @@ -1759,7 +1858,7 @@ void map_win(session_t *ps, win *w) { w->state = WSTATE_MAPPING; w->opacity_tgt = win_calc_opacity_target(ps, w); - log_debug("Window %#010x has opacity %f, opacity target is %f", w->id, w->opacity, + log_debug("Window %#010x has opacity %f, opacity target is %f", w->base.id, w->opacity, w->opacity_tgt); win_determine_blur_background(ps, w); @@ -1777,7 +1876,7 @@ void map_win(session_t *ps, win *w) { // // Also because NVIDIA driver doesn't like seeing the same pixmap under different // ids, so avoid naming the pixmap again when it didn't actually change. - w->flags &= ~WIN_FLAGS_STALE_IMAGE; + w->flags &= ~WIN_FLAGS_IMAGE_STALE; // Bind image after update_bounding_shape, so the shadow has the correct size. if (ps->redirected && ps->o.experimental_backends) { @@ -1789,7 +1888,7 @@ void map_win(session_t *ps, win *w) { #ifdef CONFIG_DBUS // Send D-Bus signal if (ps->o.dbus) { - cdbus_ev_win_mapped(ps, w); + cdbus_ev_win_mapped(ps, &w->base); } #endif @@ -1813,7 +1912,7 @@ void map_win_by_id(session_t *ps, xcb_window_t id) { return; } - win *w = find_win(ps, id); + auto w = find_managed_win(ps, id); if (!w) { return; } @@ -1822,36 +1921,134 @@ void map_win_by_id(session_t *ps, xcb_window_t id) { } /** - * Find a window from window id in window linked list of the session. + * Find a managed window from window id in window linked list of the session. */ -win *find_win(session_t *ps, xcb_window_t id) { +struct win *find_win(session_t *ps, xcb_window_t id) { if (!id) { return NULL; } - win *w = NULL; + struct win *w = NULL; HASH_FIND_INT(ps->windows, &id, w); - assert(w == NULL || w->state != WSTATE_DESTROYING); + assert(w == NULL || !w->destroyed); return w; } +/** + * 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 *w = find_win(ps, id); + if (!w || !w->managed) { + return NULL; + } + + auto mw = (struct managed_win *)w; + assert(mw->state != WSTATE_DESTROYING); + return mw; +} + /** * Find out the WM frame of a client window using existing data. * * @param id window ID * @return struct win object of the found window, NULL if not found */ -win *find_toplevel(session_t *ps, xcb_window_t id) { +struct managed_win *find_toplevel(session_t *ps, xcb_window_t id) { if (!id) { return NULL; } HASH_ITER2(ps->windows, w) { - assert(w->state != WSTATE_DESTROYING); - if (w->client_win == id) { - return w; + assert(!w->destroyed); + if (!w->managed) { + continue; + } + + auto mw = (struct managed_win *)w; + if (mw->client_win == id) { + return mw; } } return NULL; } + +/** + * 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) { + // TODO this should probably be an "update tree", then find_toplevel. + // current approach is a bit more "racy" + struct win *w = NULL; + + // We traverse through its ancestors to find out the frame + // Using find_win here because if we found a unmanaged window we know about, we + // can stop early. + while (wid && wid != ps->root && !(w = find_win(ps, wid))) { + // 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. + auto reply = xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, wid), NULL); + if (reply == NULL) { + break; + } + + wid = reply->parent; + free(reply); + } + + if (w == NULL || !w->managed) { + return NULL; + } + + return (struct managed_win *)w; +} + +/** + * Check if a rectangle includes the whole screen. + */ +static inline bool rect_is_fullscreen(const 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); +} + +/** + * Check if a window is a fullscreen window. + * + * It's not using w->border_size for performance measures. + */ +bool win_is_fullscreen(const session_t *ps, const struct managed_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. + */ +bool win_is_solid(const session_t *ps, const struct managed_win *w) { + return WMODE_SOLID == w->mode && !ps->o.force_win_blend; +} + +/** + * Check if a window is really focused. + */ +bool win_is_focused_real(const session_t *ps, const struct managed_win *w) { + return w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->active_win == w; +} + +// Find the managed window immediately below `i` in the window stack +struct managed_win * +win_stack_find_next_managed(const session_t *ps, const struct list_node *i) { + while (!list_node_is_last(&ps->window_stack, i)) { + auto next = list_entry(i->next, struct win, stack_neighbour); + if (next->managed) { + return (struct managed_win *)next; + } + i = &next->stack_neighbour; + } + return NULL; +} diff --git a/src/win.h b/src/win.h index d258975d..43fdde31 100644 --- a/src/win.h +++ b/src/win.h @@ -17,16 +17,23 @@ #include "backend/backend.h" #include "c2.h" #include "compiler.h" +#include "list.h" #include "region.h" #include "render.h" #include "types.h" #include "utils.h" #include "x.h" -#include "list.h" typedef struct session session_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 // FIXME this type should be in opengl.h // it is very unideal for it to be here @@ -108,15 +115,16 @@ typedef enum { WSTATE_UNMAPPED, } winstate_t; -typedef enum win_flags { +enum win_flags { /// 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 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. struct window_stack_entry { + struct list_node stack_neighbour; /// 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 /// creation yet) @@ -124,7 +132,6 @@ struct window_stack_entry { /// The window id. Might not be unique in the stack, because there might be /// destroyed window still fading out in the stack. 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. typedef struct win win; struct win { + UT_hash_handle hh; 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 /// `state` is not UNMAPPED void *win_image; void *shadow_image; /// Pointer to the next higher window to paint. - win *prev_trans; + struct managed_win *prev_trans; // TODO rethink reg_ignore // Core members - /// ID of the top-level frame window. - xcb_window_t id; /// The "mapped state" of this window, doesn't necessary /// match X mapped state, because of fading. winstate_t state; @@ -299,64 +318,67 @@ struct win { /// Textures and FBO background blur use. glx_blur_cache_t glx_blur_cache; #endif - UT_hash_handle hh; }; -void win_release_image(backend_t *base, win *w); -bool must_use win_bind_image(session_t *ps, win *w); +void win_release_image(backend_t *base, struct managed_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. -bool must_use win_try_rebind_image(session_t *ps, win *w); -int win_get_name(session_t *ps, win *w); -int win_get_role(session_t *ps, win *w); -winmode_t attr_pure win_calc_mode(const win *w); +bool must_use win_try_rebind_image(session_t *ps, struct managed_win *w); +int win_get_name(session_t *ps, struct managed_win *w); +int win_get_role(session_t *ps, struct managed_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. */ -void win_set_focused(session_t *ps, win *w, bool focused); -bool attr_pure win_should_fade(session_t *ps, const win *w); -void win_update_prop_shadow_raw(session_t *ps, win *w); -void win_update_prop_shadow(session_t *ps, win *w); -void win_set_shadow(session_t *ps, win *w, bool shadow_new); -void win_determine_shadow(session_t *ps, win *w); -void win_set_invert_color(session_t *ps, win *w, bool invert_color_new); -void win_determine_invert_color(session_t *ps, win *w); -void win_set_blur_background(session_t *ps, win *w, bool blur_background_new); -void win_determine_blur_background(session_t *ps, win *w); -void win_on_wtype_change(session_t *ps, win *w); -void win_on_factor_change(session_t *ps, win *w); +void win_set_focused(session_t *ps, struct managed_win *w, bool focused); +bool attr_pure win_should_fade(session_t *ps, const struct managed_win *w); +void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w); +void win_update_prop_shadow(session_t *ps, struct managed_win *w); +void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new); +void win_determine_shadow(session_t *ps, struct managed_win *w); +void win_set_invert_color(session_t *ps, struct managed_win *w, bool invert_color_new); +void win_determine_invert_color(session_t *ps, struct managed_win *w); +void win_set_blur_background(session_t *ps, struct managed_win *w, bool blur_background_new); +void win_determine_blur_background(session_t *ps, struct managed_win *w); +void win_on_wtype_change(session_t *ps, struct managed_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. */ -void win_on_win_size_change(session_t *ps, win *w); -void win_update_wintype(session_t *ps, win *w); -void win_mark_client(session_t *ps, win *w, xcb_window_t client); -void win_unmark_client(session_t *ps, win *w); -void win_recheck_client(session_t *ps, win *w); -xcb_window_t win_get_leader_raw(session_t *ps, win *w, int recursions); -bool win_get_class(session_t *ps, win *w); -double attr_pure win_calc_opacity_target(session_t *ps, const win *w); -bool attr_pure win_should_dim(session_t *ps, const win *w); -void win_update_screen(session_t *, win *); +void win_on_win_size_change(session_t *ps, struct managed_win *w); +void win_update_wintype(session_t *ps, struct managed_win *w); +void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client); +void win_unmark_client(session_t *ps, struct managed_win *w); +void win_recheck_client(session_t *ps, struct managed_win *w); +xcb_window_t win_get_leader_raw(session_t *ps, struct managed_win *w, int recursions); +bool win_get_class(session_t *ps, struct managed_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 struct managed_win *w); +void win_update_screen(session_t *, struct managed_win *); /// 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. */ -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. */ -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. */ -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. */ // 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 * 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 * function. */ -void win_extents(const win *w, region_t *res); -region_t win_extents_by_val(const win *w); +void win_extents(const struct managed_win *w, region_t *res); +region_t win_extents_by_val(const struct managed_win *w); /** * Add a window to damaged area. * * @param ps current session * @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. * * Return region in global coordinates. */ -void win_get_region_noframe_local(const win *w, region_t *); -region_t win_get_region_noframe_local_by_val(const win *w); +void win_get_region_noframe_local(const struct managed_win *w, region_t *); +region_t win_get_region_noframe_local_by_val(const struct managed_win *w); /// 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 -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. */ -void win_update_frame_extents(session_t *ps, win *w, xcb_window_t client); -void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev); +void win_update_frame_extents(session_t *ps, struct managed_win *w, xcb_window_t client); +/// 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 -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); /** * 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 -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, /// transition the window straight to its end state -void win_skip_fading(session_t *ps, win **_w); -win *find_win(session_t *ps, xcb_window_t id); -win *find_toplevel(session_t *ps, xcb_window_t id); +void win_skip_fading(session_t *ps, struct managed_win **_w); +/** + * 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. * * 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); } /// 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 -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 -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; pixman_region32_init(&ret); 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 * _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; result.top = max2(result.top, 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. */ -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 || 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; +}