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:
Yuxuan Shui 2019-09-20 01:59:25 +01:00
parent 16bff8ff41
commit 9f3d3f2fba
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
5 changed files with 77 additions and 12 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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)