win: add functions for delayed window updates
And a window update flag for mapping the window. Also make sure related functions consider the case where the given window has pending updates. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
16bff8ff41
commit
9f3d3f2fba
|
@ -1284,6 +1284,12 @@ static void handle_new_windows(session_t *ps) {
|
|||
}
|
||||
}
|
||||
|
||||
static void refresh_windows(session_t *ps) {
|
||||
win_stack_foreach_managed_safe(w, &ps->window_stack) {
|
||||
win_process_updates(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
static void refresh_stale_images(session_t *ps) {
|
||||
win_stack_foreach_managed(w, &ps->window_stack) {
|
||||
win_process_flags(ps, w);
|
||||
|
@ -1328,6 +1334,9 @@ static void handle_pending_updates(EV_P_ struct session *ps) {
|
|||
recheck_focus(ps);
|
||||
}
|
||||
|
||||
// Process window updates
|
||||
refresh_windows(ps);
|
||||
|
||||
// Refresh pixmaps and shadows
|
||||
refresh_stale_images(ps);
|
||||
|
||||
|
@ -1374,11 +1383,14 @@ static void _draw_callback(EV_P_ session_t *ps, int revents attr_unused) {
|
|||
|
||||
if (!was_redirected && ps->redirected) {
|
||||
// paint_preprocess redirected the screen, which might change the state of
|
||||
// some of the windows (e.g. the window image might fail to bind, and the
|
||||
// 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");
|
||||
bottom = paint_preprocess(ps, &fade_running);
|
||||
// some of the windows (e.g. the window image might become stale).
|
||||
// so we rerun _draw_callback to make sure the rendering decision we make
|
||||
// is up-to-date, and all the new flags got handled.
|
||||
//
|
||||
// TODO This is not ideal, we should try to avoid setting window flags in
|
||||
// paint_preprocess.
|
||||
log_debug("Re-run _draw_callback");
|
||||
return _draw_callback(EV_A_ ps, revents);
|
||||
}
|
||||
|
||||
// Start/stop fade timer depends on whether window are fading
|
||||
|
|
|
@ -546,8 +546,8 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
}
|
||||
|
||||
static inline void repair_win(session_t *ps, struct managed_win *w) {
|
||||
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE)
|
||||
return;
|
||||
// Only mapped window can receive damages
|
||||
assert(win_is_mapped_in_x(w));
|
||||
|
||||
region_t parts;
|
||||
pixman_region32_init(&parts);
|
||||
|
|
51
src/win.c
51
src/win.c
|
@ -1869,6 +1869,7 @@ bool destroy_win_start(session_t *ps, struct win *w) {
|
|||
}
|
||||
|
||||
void unmap_win_start(session_t *ps, struct managed_win *w) {
|
||||
auto internal_w = (struct managed_win_internal *)w;
|
||||
assert(w);
|
||||
assert(w->base.managed);
|
||||
assert(w->a._class != XCB_WINDOW_CLASS_INPUT_ONLY);
|
||||
|
@ -1881,10 +1882,14 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
|
|||
}
|
||||
|
||||
if (unlikely(w->state == WSTATE_UNMAPPING || w->state == WSTATE_UNMAPPED)) {
|
||||
log_warn("Trying to unmapping an already unmapped window %#010x "
|
||||
"\"%s\"",
|
||||
w->base.id, w->name);
|
||||
assert(false);
|
||||
if (internal_w->pending_updates & WIN_UPDATE_MAP) {
|
||||
internal_w->pending_updates &= ~(unsigned long)WIN_UPDATE_MAP;
|
||||
} else {
|
||||
log_warn("Trying to unmapping an already unmapped window %#010x "
|
||||
"\"%s\"",
|
||||
w->base.id, w->name);
|
||||
assert(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2079,7 +2084,10 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
|||
|
||||
win_determine_blur_background(ps, w);
|
||||
|
||||
w->ever_damaged = false;
|
||||
// Cannot set w->ever_damaged = false here, since window mapping could be
|
||||
// delayed, so a damage event might have already arrived before this function
|
||||
// is called. But this should be unnecessary in the first place, since
|
||||
// ever_damaged is set to false in unmap_win_finish anyway.
|
||||
|
||||
// We stopped listening on ShapeNotify events
|
||||
// when the window is unmapped (XXX we shouldn't),
|
||||
|
@ -2236,6 +2244,32 @@ win_is_fullscreen_xcb(xcb_connection_t *c, const struct atom *a, const xcb_windo
|
|||
return false;
|
||||
}
|
||||
|
||||
/// Queue an update on a window. A series of sanity checks are performed
|
||||
void win_queue_update(struct managed_win *_w, enum win_update update) {
|
||||
auto w = (struct managed_win_internal *)_w;
|
||||
assert(popcount(update) == 1);
|
||||
|
||||
if (unlikely(_w->state == WSTATE_DESTROYING)) {
|
||||
log_error("Updates queued on a destroyed window %#010x (%s)", _w->base.id,
|
||||
_w->name);
|
||||
return;
|
||||
}
|
||||
|
||||
w->pending_updates |= WIN_UPDATE_MAP;
|
||||
}
|
||||
|
||||
/// Process pending updates on a window. Has to be called in X critical section
|
||||
void win_process_updates(struct session *ps, struct managed_win *_w) {
|
||||
assert(ps->server_grabbed);
|
||||
auto w = (struct managed_win_internal *)_w;
|
||||
|
||||
if (w->pending_updates & WIN_UPDATE_MAP) {
|
||||
map_win_start(ps, _w);
|
||||
}
|
||||
|
||||
w->pending_updates = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a window is a fullscreen window.
|
||||
*
|
||||
|
@ -2267,3 +2301,10 @@ win_stack_find_next_managed(const session_t *ps, const struct list_node *i) {
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Return whether this window is mapped on the X server side
|
||||
bool win_is_mapped_in_x(const struct managed_win *w) {
|
||||
auto iw = (const struct managed_win_internal *)w;
|
||||
return w->state == WSTATE_MAPPING || w->state == WSTATE_FADING ||
|
||||
w->state == WSTATE_MAPPED || (iw->pending_updates & WIN_UPDATE_MAP);
|
||||
}
|
||||
|
|
|
@ -250,8 +250,12 @@ struct managed_win {
|
|||
#endif
|
||||
};
|
||||
|
||||
/// Process pending updates on a window. Has to be called in X critical section
|
||||
void win_process_updates(struct session *ps, struct managed_win *_w);
|
||||
/// Process pending images flags on a window. Has to be called in X critical section
|
||||
void win_process_flags(session_t *ps, struct managed_win *w);
|
||||
/// Queue an update on a window. A series of sanity checks are performed
|
||||
void win_queue_update(struct managed_win *_w, enum win_update update);
|
||||
|
||||
/// Start the unmap of a window. We cannot unmap immediately since we might need to fade
|
||||
/// the window out.
|
||||
|
@ -417,6 +421,9 @@ 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 struct managed_win *w);
|
||||
|
||||
/// Whether a given window is mapped on the X server side
|
||||
bool win_is_mapped_in_x(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);
|
||||
|
|
|
@ -27,6 +27,11 @@ typedef enum {
|
|||
WMODE_SOLID, // The window is opaque including the frame
|
||||
} winmode_t;
|
||||
|
||||
/// Pending window updates
|
||||
enum win_update {
|
||||
WIN_UPDATE_MAP = 1,
|
||||
};
|
||||
|
||||
/// Transition table:
|
||||
/// (DESTROYED is when the win struct is destroyed and freed)
|
||||
/// ('o' means in all other cases)
|
||||
|
|
Loading…
Reference in New Issue