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) {
|
static void refresh_stale_images(session_t *ps) {
|
||||||
win_stack_foreach_managed(w, &ps->window_stack) {
|
win_stack_foreach_managed(w, &ps->window_stack) {
|
||||||
win_process_flags(ps, w);
|
win_process_flags(ps, w);
|
||||||
|
@ -1328,6 +1334,9 @@ static void handle_pending_updates(EV_P_ struct session *ps) {
|
||||||
recheck_focus(ps);
|
recheck_focus(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process window updates
|
||||||
|
refresh_windows(ps);
|
||||||
|
|
||||||
// Refresh pixmaps and shadows
|
// Refresh pixmaps and shadows
|
||||||
refresh_stale_images(ps);
|
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) {
|
if (!was_redirected && ps->redirected) {
|
||||||
// paint_preprocess redirected the screen, which might change the state of
|
// 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
|
// some of the windows (e.g. the window image might become stale).
|
||||||
// window would be put into an error state). so we rerun paint_preprocess
|
// so we rerun _draw_callback to make sure the rendering decision we make
|
||||||
// here to make sure the rendering decision we make is up-to-date
|
// is up-to-date, and all the new flags got handled.
|
||||||
log_debug("Re-run paint_preprocess");
|
//
|
||||||
bottom = paint_preprocess(ps, &fade_running);
|
// 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
|
// 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) {
|
static inline void repair_win(session_t *ps, struct managed_win *w) {
|
||||||
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE)
|
// Only mapped window can receive damages
|
||||||
return;
|
assert(win_is_mapped_in_x(w));
|
||||||
|
|
||||||
region_t parts;
|
region_t parts;
|
||||||
pixman_region32_init(&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) {
|
void unmap_win_start(session_t *ps, struct managed_win *w) {
|
||||||
|
auto internal_w = (struct managed_win_internal *)w;
|
||||||
assert(w);
|
assert(w);
|
||||||
assert(w->base.managed);
|
assert(w->base.managed);
|
||||||
assert(w->a._class != XCB_WINDOW_CLASS_INPUT_ONLY);
|
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)) {
|
if (unlikely(w->state == WSTATE_UNMAPPING || w->state == WSTATE_UNMAPPED)) {
|
||||||
log_warn("Trying to unmapping an already unmapped window %#010x "
|
if (internal_w->pending_updates & WIN_UPDATE_MAP) {
|
||||||
"\"%s\"",
|
internal_w->pending_updates &= ~(unsigned long)WIN_UPDATE_MAP;
|
||||||
w->base.id, w->name);
|
} else {
|
||||||
assert(false);
|
log_warn("Trying to unmapping an already unmapped window %#010x "
|
||||||
|
"\"%s\"",
|
||||||
|
w->base.id, w->name);
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2079,7 +2084,10 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
||||||
|
|
||||||
win_determine_blur_background(ps, 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
|
// We stopped listening on ShapeNotify events
|
||||||
// when the window is unmapped (XXX we shouldn't),
|
// 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;
|
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.
|
* 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 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
|
#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
|
/// 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);
|
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
|
/// Start the unmap of a window. We cannot unmap immediately since we might need to fade
|
||||||
/// the window out.
|
/// 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
|
/// 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);
|
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
|
// 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,
|
struct managed_win *attr_pure win_stack_find_next_managed(const session_t *ps,
|
||||||
const struct list_node *w);
|
const struct list_node *w);
|
||||||
|
|
|
@ -27,6 +27,11 @@ typedef enum {
|
||||||
WMODE_SOLID, // The window is opaque including the frame
|
WMODE_SOLID, // The window is opaque including the frame
|
||||||
} winmode_t;
|
} winmode_t;
|
||||||
|
|
||||||
|
/// Pending window updates
|
||||||
|
enum win_update {
|
||||||
|
WIN_UPDATE_MAP = 1,
|
||||||
|
};
|
||||||
|
|
||||||
/// Transition table:
|
/// Transition table:
|
||||||
/// (DESTROYED is when the win struct is destroyed and freed)
|
/// (DESTROYED is when the win struct is destroyed and freed)
|
||||||
/// ('o' means in all other cases)
|
/// ('o' means in all other cases)
|
||||||
|
|
Loading…
Reference in New Issue