event: handle reparent to the same parent

When a window is reparented to the same parent again, we should just
move it to the top of the stack, instead of add it again.

Also a slight refactor restack_win.

Fixes #164

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui
2019-04-27 13:36:42 +01:00
parent cfbd1819ed
commit ad8211e341
6 changed files with 193 additions and 162 deletions

View File

@ -631,71 +631,6 @@ static void rebuild_shadow_exclude_reg(session_t *ps) {
exit(1);
}
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)) {
old_above = list_next_entry(w, stack_neighbour)->id;
} else {
old_above = XCB_NONE;
}
log_debug("Restack %#010x (%s), old_above: %#010x, new_above: %#010x", w->id,
win_get_name_if_managed(w), old_above, new_above);
struct managed_win *mw = NULL;
if (w->managed) {
mw = (struct managed_win *)w;
}
if (old_above != new_above) {
if (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);
}
struct list_node *new_next;
if (!new_above) {
new_next = &ps->window_stack;
} else {
struct win *tmp_w = NULL;
HASH_FIND_INT(ps->windows, &new_above, tmp_w);
if (!tmp_w) {
log_error("(%#010x, %#010x): Failed to found new above "
"window.",
w->id, new_above);
return;
}
new_next = &tmp_w->stack_neighbour;
}
list_move_before(&w->stack_neighbour, new_next);
// add damage for this window
if (mw) {
add_damage_from_win(ps, mw);
}
#ifdef DEBUG_RESTACK
log_trace("Window stack modified. Current stack:");
for (auto c = ps->list; c; c = c->next) {
const char *desc = "";
if (c->state == WSTATE_DESTROYING) {
desc = "(D) ";
}
log_trace("%#010x \"%s\" %s", c->id, c->name, desc);
}
#endif
}
}
/// Free up all the images and deinit the backend
static void destroy_backend(session_t *ps) {
win_stack_foreach_managed_safe(w, &ps->window_stack) {
@ -826,89 +761,6 @@ void configure_root(session_t *ps, int width, int height) {
return;
}
/// Handle configure event of a regular window
void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
auto w = find_win(ps, ce->window);
region_t damage;
pixman_region32_init(&damage);
if (!w) {
return;
}
if (!w->managed) {
restack_win(ps, w, ce->above_sibling);
return;
}
auto mw = (struct managed_win *)w;
if (mw->state == WSTATE_UNMAPPED || mw->state == WSTATE_UNMAPPING ||
mw->state == WSTATE_DESTROYING) {
// Only restack the window to make sure we can handle future restack
// notification correctly
restack_win(ps, w, ce->above_sibling);
} else {
restack_win(ps, w, ce->above_sibling);
bool factor_change = false;
win_extents(mw, &damage);
// If window geometry change, free old extents
if (mw->g.x != ce->x || mw->g.y != ce->y || mw->g.width != ce->width ||
mw->g.height != ce->height || mw->g.border_width != ce->border_width) {
factor_change = true;
}
mw->g.x = ce->x;
mw->g.y = ce->y;
if (mw->g.width != ce->width || mw->g.height != ce->height ||
mw->g.border_width != ce->border_width) {
log_trace("Window size changed, %dx%d -> %dx%d", mw->g.width,
mw->g.height, ce->width, ce->height);
mw->g.width = ce->width;
mw->g.height = ce->height;
mw->g.border_width = ce->border_width;
win_on_win_size_change(ps, mw);
win_update_bounding_shape(ps, mw);
}
region_t new_extents;
pixman_region32_init(&new_extents);
win_extents(mw, &new_extents);
pixman_region32_union(&damage, &damage, &new_extents);
pixman_region32_fini(&new_extents);
if (factor_change) {
win_on_factor_change(ps, mw);
add_damage(ps, &damage);
win_update_screen(ps, mw);
}
}
pixman_region32_fini(&damage);
// override_redirect flag cannot be changed after window creation, as far
// as I know, so there's no point to re-match windows here.
mw->a.override_redirect = ce->override_redirect;
}
void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce) {
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, struct win, stack_neighbour)->id;
} else {
new_above = XCB_NONE;
}
restack_win(ps, w, new_above);
}
void root_damaged(session_t *ps) {
if (ps->root_tile_paint.pixmap) {
free_root_tile(ps);