mirror of
https://github.com/yshui/picom.git
synced 2025-04-14 17:53:25 -04:00
wm/tree: split wm_tree_new_window and wm_tree_reparent
wm_tree_new_window is splitted into 3 steps: creating the window object (wm_tree_new_window), adding it to the hash table (wm_tree_add_window), and attaching it to its parent (wm_tree_attach). wm_tree_reparent is splitted into wm_tree_detach and then wm_tree_attach. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
de52cbd0e6
commit
7d216657d0
3 changed files with 70 additions and 69 deletions
110
src/wm/tree.c
110
src/wm/tree.c
|
@ -234,33 +234,19 @@ void wm_tree_set_wm_state(struct wm_tree *tree, struct wm_tree_node *node, bool
|
|||
}
|
||||
}
|
||||
|
||||
struct wm_tree_node *
|
||||
wm_tree_new_window(struct wm_tree *tree, xcb_window_t id, struct wm_tree_node *parent) {
|
||||
struct wm_tree_node *wm_tree_new_window(struct wm_tree *tree, xcb_window_t id) {
|
||||
auto node = ccalloc(1, struct wm_tree_node);
|
||||
node->id.x = id;
|
||||
node->id.gen = tree->gen++;
|
||||
node->has_wm_state = false;
|
||||
list_init_head(&node->children);
|
||||
|
||||
BUG_ON(parent == NULL && tree->nodes != NULL); // Trying to create a second
|
||||
// root window
|
||||
HASH_ADD_INT(tree->nodes, id.x, node);
|
||||
|
||||
node->parent = parent;
|
||||
if (parent != NULL) {
|
||||
list_insert_after(&parent->children, &node->siblings);
|
||||
if (parent->parent == NULL) {
|
||||
// Parent is root, this is a new toplevel window
|
||||
wm_tree_enqueue_change(tree, (struct wm_tree_change){
|
||||
.toplevel = node->id,
|
||||
.type = WM_TREE_CHANGE_TOPLEVEL_NEW,
|
||||
.new_ = node,
|
||||
});
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void wm_tree_add_window(struct wm_tree *tree, struct wm_tree_node *node) {
|
||||
HASH_ADD_INT(tree->nodes, id.x, node);
|
||||
}
|
||||
|
||||
static void
|
||||
wm_tree_refresh_client_and_queue_change(struct wm_tree *tree, struct wm_tree_node *toplevel) {
|
||||
BUG_ON_NULL(toplevel);
|
||||
|
@ -307,6 +293,30 @@ void wm_tree_detach(struct wm_tree *tree, struct wm_tree_node *subroot) {
|
|||
.killed = zombie,
|
||||
});
|
||||
}
|
||||
subroot->parent = NULL;
|
||||
}
|
||||
|
||||
void wm_tree_attach(struct wm_tree *tree, struct wm_tree_node *child,
|
||||
struct wm_tree_node *parent) {
|
||||
BUG_ON_NULL(parent);
|
||||
BUG_ON(child->parent != NULL); // Trying to attach a window that's already
|
||||
// attached
|
||||
child->parent = parent;
|
||||
list_insert_after(&parent->children, &child->siblings);
|
||||
|
||||
auto toplevel = wm_tree_find_toplevel_for(child);
|
||||
if (child == toplevel) {
|
||||
// This node could have a stale `->win` if it was a toplevel at
|
||||
// some point in the past.
|
||||
child->win = NULL;
|
||||
wm_tree_enqueue_change(tree, (struct wm_tree_change){
|
||||
.toplevel = child->id,
|
||||
.type = WM_TREE_CHANGE_TOPLEVEL_NEW,
|
||||
.new_ = child,
|
||||
});
|
||||
} else {
|
||||
wm_tree_refresh_client_and_queue_change(tree, toplevel);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_tree_destroy_window(struct wm_tree *tree, struct wm_tree_node *node) {
|
||||
|
@ -386,38 +396,6 @@ void wm_tree_move_to_above(struct wm_tree *tree, struct wm_tree_node *node,
|
|||
}
|
||||
}
|
||||
|
||||
void wm_tree_reparent(struct wm_tree *tree, struct wm_tree_node *node,
|
||||
struct wm_tree_node *new_parent) {
|
||||
BUG_ON(node == NULL);
|
||||
BUG_ON(new_parent == NULL); // Trying make `node` a root window
|
||||
|
||||
if (node->parent == new_parent) {
|
||||
// Reparent to the same parent moves the window to the top of the stack
|
||||
wm_tree_move_to_end(tree, node, false);
|
||||
return;
|
||||
}
|
||||
|
||||
wm_tree_detach(tree, node);
|
||||
|
||||
// Reparented window always becomes the topmost child of the new parent
|
||||
list_insert_after(&new_parent->children, &node->siblings);
|
||||
node->parent = new_parent;
|
||||
|
||||
auto toplevel = wm_tree_find_toplevel_for(node);
|
||||
if (node == toplevel) {
|
||||
// This node could have a stale `->win` if it was a toplevel at
|
||||
// some point in the past.
|
||||
node->win = NULL;
|
||||
wm_tree_enqueue_change(tree, (struct wm_tree_change){
|
||||
.toplevel = node->id,
|
||||
.type = WM_TREE_CHANGE_TOPLEVEL_NEW,
|
||||
.new_ = node,
|
||||
});
|
||||
} else {
|
||||
wm_tree_refresh_client_and_queue_change(tree, toplevel);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_tree_clear(struct wm_tree *tree) {
|
||||
struct wm_tree_node *cur, *tmp;
|
||||
HASH_ITER(hh, tree->nodes, cur, tmp) {
|
||||
|
@ -438,7 +416,7 @@ TEST_CASE(tree_manipulation) {
|
|||
struct wm_tree tree;
|
||||
wm_tree_init(&tree);
|
||||
|
||||
wm_tree_new_window(&tree, 1, NULL);
|
||||
wm_tree_add_window(&tree, wm_tree_new_window(&tree, 1));
|
||||
auto root = wm_tree_find(&tree, 1);
|
||||
assert(root != NULL);
|
||||
assert(root->parent == NULL);
|
||||
|
@ -446,9 +424,11 @@ TEST_CASE(tree_manipulation) {
|
|||
auto change = wm_tree_dequeue_change(&tree);
|
||||
assert(change.type == WM_TREE_CHANGE_NONE);
|
||||
|
||||
wm_tree_new_window(&tree, 2, root);
|
||||
auto node2 = wm_tree_find(&tree, 2);
|
||||
auto node2 = wm_tree_new_window(&tree, 2);
|
||||
wm_tree_add_window(&tree, node2);
|
||||
wm_tree_attach(&tree, node2, root);
|
||||
assert(node2 != NULL);
|
||||
assert(node2 == wm_tree_find(&tree, 2));
|
||||
assert(node2->parent == root);
|
||||
|
||||
change = wm_tree_dequeue_change(&tree);
|
||||
|
@ -456,15 +436,16 @@ TEST_CASE(tree_manipulation) {
|
|||
assert(change.type == WM_TREE_CHANGE_TOPLEVEL_NEW);
|
||||
assert(wm_treeid_eq(node2->id, change.toplevel));
|
||||
|
||||
wm_tree_new_window(&tree, 3, root);
|
||||
auto node3 = wm_tree_find(&tree, 3);
|
||||
assert(node3 != NULL);
|
||||
auto node3 = wm_tree_new_window(&tree, 3);
|
||||
wm_tree_add_window(&tree, node3);
|
||||
wm_tree_attach(&tree, node3, root);
|
||||
|
||||
change = wm_tree_dequeue_change(&tree);
|
||||
assert(change.toplevel.x == 3);
|
||||
assert(change.type == WM_TREE_CHANGE_TOPLEVEL_NEW);
|
||||
|
||||
wm_tree_reparent(&tree, node2, node3);
|
||||
wm_tree_detach(&tree, node2);
|
||||
wm_tree_attach(&tree, node2, node3);
|
||||
assert(node2->parent == node3);
|
||||
assert(node3->children.next == &node2->siblings);
|
||||
|
||||
|
@ -481,8 +462,9 @@ TEST_CASE(tree_manipulation) {
|
|||
assert(wm_treeid_eq(change.client.old, WM_TREEID_NONE));
|
||||
assert(change.client.new_.x == 2);
|
||||
|
||||
wm_tree_new_window(&tree, 4, node3);
|
||||
auto node4 = wm_tree_find(&tree, 4);
|
||||
auto node4 = wm_tree_new_window(&tree, 4);
|
||||
wm_tree_add_window(&tree, node4);
|
||||
wm_tree_attach(&tree, node4, node3);
|
||||
change = wm_tree_dequeue_change(&tree);
|
||||
assert(change.type == WM_TREE_CHANGE_NONE);
|
||||
|
||||
|
@ -500,7 +482,9 @@ TEST_CASE(tree_manipulation) {
|
|||
|
||||
// Test window ID reuse
|
||||
wm_tree_destroy_window(&tree, node4);
|
||||
node4 = wm_tree_new_window(&tree, 4, node3);
|
||||
node4 = wm_tree_new_window(&tree, 4);
|
||||
wm_tree_add_window(&tree, node4);
|
||||
wm_tree_attach(&tree, node4, node3);
|
||||
wm_tree_set_wm_state(&tree, node4, true);
|
||||
|
||||
change = wm_tree_dequeue_change(&tree);
|
||||
|
@ -509,7 +493,9 @@ TEST_CASE(tree_manipulation) {
|
|||
assert(change.client.old.x == 4);
|
||||
assert(change.client.new_.x == 4);
|
||||
|
||||
auto node5 = wm_tree_new_window(&tree, 5, root);
|
||||
auto node5 = wm_tree_new_window(&tree, 5);
|
||||
wm_tree_add_window(&tree, node5);
|
||||
wm_tree_attach(&tree, node5, root);
|
||||
wm_tree_destroy_window(&tree, node5);
|
||||
change = wm_tree_dequeue_change(&tree);
|
||||
assert(change.type == WM_TREE_CHANGE_NONE); // Changes cancelled out
|
||||
|
|
19
src/wm/wm.c
19
src/wm/wm.c
|
@ -286,7 +286,16 @@ void wm_reparent(struct wm *wm, xcb_window_t wid, xcb_window_t parent) {
|
|||
return;
|
||||
}
|
||||
|
||||
wm_tree_reparent(&wm->tree, window, new_parent);
|
||||
if (new_parent == window->parent) {
|
||||
log_debug("Reparenting window %#010x to its current parent %#010x, "
|
||||
"moving it to the top.",
|
||||
wid, parent);
|
||||
wm_tree_move_to_end(&wm->tree, window, false);
|
||||
return;
|
||||
}
|
||||
|
||||
wm_tree_detach(&wm->tree, window);
|
||||
wm_tree_attach(&wm->tree, window, new_parent);
|
||||
}
|
||||
|
||||
void wm_set_has_wm_state(struct wm *wm, struct wm_ref *cursor, bool has_wm_state) {
|
||||
|
@ -313,7 +322,9 @@ void wm_import_incomplete(struct wm *wm, xcb_window_t wid, xcb_window_t parent)
|
|||
}
|
||||
}
|
||||
log_debug("Importing window %#010x with parent %#010x", wid, parent);
|
||||
auto new = wm_tree_new_window(&wm->tree, wid, parent_cursor);
|
||||
auto new = wm_tree_new_window(&wm->tree, wid);
|
||||
wm_tree_add_window(&wm->tree, new);
|
||||
wm_tree_attach(&wm->tree, new, parent_cursor);
|
||||
dynarr_push(wm->incompletes, new);
|
||||
if (parent == XCB_NONE) {
|
||||
BUG_ON(wm->root != NULL); // Can't have more than one root
|
||||
|
@ -383,7 +394,9 @@ static bool wm_complete_import_subtree(struct wm *wm, struct x_connection *c,
|
|||
children[i], curr->id.x);
|
||||
wm_tree_destroy_window(&wm->tree, existing);
|
||||
}
|
||||
existing = wm_tree_new_window(&wm->tree, children[i], curr);
|
||||
existing = wm_tree_new_window(&wm->tree, children[i]);
|
||||
wm_tree_add_window(&wm->tree, existing);
|
||||
wm_tree_attach(&wm->tree, existing, curr);
|
||||
wm_complete_import_single(wm, c, atoms, existing);
|
||||
}
|
||||
free(tree);
|
||||
|
|
|
@ -24,6 +24,7 @@ struct wm_tree {
|
|||
uint64_t gen;
|
||||
/// wm tree nodes indexed by their X window ID.
|
||||
struct wm_tree_node *nodes;
|
||||
struct wm_tree_node *root;
|
||||
|
||||
struct list_node changes;
|
||||
struct list_node free_changes;
|
||||
|
@ -85,15 +86,16 @@ struct wm_tree_node *attr_pure wm_tree_next(struct wm_tree_node *node,
|
|||
/// permitted, and the root window cannot be destroyed once created, until
|
||||
/// `wm_tree_clear` is called. If `parent` is not NULL, the new node will be put at the
|
||||
/// top of the stacking order among its siblings.
|
||||
struct wm_tree_node *
|
||||
wm_tree_new_window(struct wm_tree *tree, xcb_window_t id, struct wm_tree_node *parent);
|
||||
struct wm_tree_node *wm_tree_new_window(struct wm_tree *tree, xcb_window_t id);
|
||||
void wm_tree_add_window(struct wm_tree *tree, struct wm_tree_node *node);
|
||||
void wm_tree_destroy_window(struct wm_tree *tree, struct wm_tree_node *node);
|
||||
/// Detach the subtree rooted at `subroot` from `tree`. The subtree root is removed from
|
||||
/// its parent, and the disconnected tree nodes won't be able to be found via
|
||||
/// `wm_tree_find`. Relevant events will be generated.
|
||||
void wm_tree_detach(struct wm_tree *tree, struct wm_tree_node *subroot);
|
||||
void wm_tree_reparent(struct wm_tree *tree, struct wm_tree_node *node,
|
||||
struct wm_tree_node *new_parent);
|
||||
/// Attach `node` to `parent`. `node` becomes the topmost child of `parent`.
|
||||
void wm_tree_attach(struct wm_tree *tree, struct wm_tree_node *child,
|
||||
struct wm_tree_node *parent);
|
||||
void wm_tree_move_to_above(struct wm_tree *tree, struct wm_tree_node *node,
|
||||
struct wm_tree_node *other);
|
||||
/// Move `node` to the top or the bottom of its parent's child window stack.
|
||||
|
|
Loading…
Add table
Reference in a new issue