X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;ds=sidebyside;f=tree.c;h=3ece2f659563ffbf10f2251b5708656e829f6b58;hb=b2de47054b8409ddded660515299a295b1adbf02;hp=90f118c1624c04226dc0619e75f8c4029e154133;hpb=6a5594c5e07dc8512b8ca3ac4b10acae778d4586;p=bspwm.git diff --git a/tree.c b/tree.c index 90f118c..3ece2f6 100644 --- a/tree.c +++ b/tree.c @@ -1,6 +1,36 @@ +#include +#include +#include +#include +#include +#include "settings.h" +#include "helpers.h" +#include "utils.h" +#include "types.h" +#include "bspwm.h" #include "tree.h" -Node *first_extrema(Node *n) +bool is_leaf(node_t *n) +{ + return (n != NULL && n->first_child == NULL && n->second_child == NULL); +} + +bool is_first_child(node_t *n) +{ + return (n != NULL && n->parent != NULL && n->parent->first_child == n); +} + +bool is_second_child(node_t *n) +{ + return (n != NULL && n->parent != NULL && n->parent->second_child == n); +} + + +void change_split_ratio(node_t *n, value_change_t chg) { + n->split_ratio = pow(n->split_ratio, (chg == CHANGE_INCREASE ? INC_EXP : DEC_EXP)); +} + +node_t *first_extrema(node_t *n) { if (n == NULL) return NULL; @@ -10,7 +40,7 @@ Node *first_extrema(Node *n) return first_extrema(n->first_child); } -Node *second_extrema(Node *n) +node_t *second_extrema(node_t *n) { if (n == NULL) return NULL; @@ -20,19 +50,296 @@ Node *second_extrema(Node *n) return second_extrema(n->second_child); } -Node *find_neighbor(Node *n, direction_t dir) +node_t *next_leaf(node_t *n) { if (n == NULL) return NULL; - switch (dir) { - case DIR_UP: - break; - case DIR_LEFT: - break; - case DIR_DOWN: - break; - case DIR_RIGHT: - break; + node_t *p = n; + while (is_second_child(p)) + p = p->parent; + if (p->parent == NULL) + return NULL; + return first_extrema(p->parent->second_child); +} + +node_t *prev_leaf(node_t *n) +{ + if (n == NULL) + return NULL; + node_t *p = n; + while (is_first_child(p)) + p = p->parent; + if (p->parent == NULL) + return NULL; + return second_extrema(p->parent->first_child); +} + +node_t *find_fence(node_t *n, direction_t dir) +{ + node_t *p; + + if (n == NULL) + return NULL; + + p = n->parent; + + while (p != NULL) { + if ((dir == DIR_UP && p->split_type == TYPE_HORIZONTAL && p->rectangle.y < n->rectangle.y) + || (dir == DIR_LEFT && p->split_type == TYPE_VERTICAL && p->rectangle.x < n->rectangle.x) + || (dir == DIR_DOWN && p->split_type == TYPE_HORIZONTAL && (p->rectangle.y + p->rectangle.height) > (n->rectangle.y + n->rectangle.height)) + || (dir == DIR_RIGHT && p->split_type == TYPE_VERTICAL && (p->rectangle.x + p->rectangle.width) > (n->rectangle.x + n->rectangle.width))) + return p; + p = p->parent; } + + return NULL; +} + +node_t *find_neighbor(node_t *n, direction_t dir) +{ + node_t *fence = find_fence(n, dir); + + if (fence == NULL) + return NULL; + + if (dir == DIR_UP || dir == DIR_LEFT) + return second_extrema(fence->first_child); + else if (dir == DIR_DOWN || dir == DIR_RIGHT) + return first_extrema(fence->second_child); + return NULL; } + +void move_fence(node_t *n, direction_t dir, fence_move_t mov) +{ + node_t *fence = find_fence(n, dir); + + if (fence == NULL) + return; + + if ((mov == MOVE_PUSH && (dir == DIR_RIGHT || dir == DIR_DOWN)) + || (mov == MOVE_PULL && (dir == DIR_LEFT || dir == DIR_UP))) + change_split_ratio(fence, CHANGE_INCREASE); + else + change_split_ratio(fence, CHANGE_DECREASE); +} + + +void rotate_tree(node_t *n, rotate_t rot) +{ + if (n == NULL || is_leaf(n)) + return; + + node_t *tmp; + + if ((rot == ROTATE_CLOCK_WISE && n->split_type == TYPE_HORIZONTAL) + || (rot == ROTATE_COUNTER_CW && n->split_type == TYPE_VERTICAL) + || rot == ROTATE_FULL_CYCLE) { + tmp = n->first_child; + n->first_child = n->second_child; + n->second_child = tmp; + n->split_ratio = 1.0 - n->split_ratio; + } + + if (rot != ROTATE_FULL_CYCLE) { + if (n->split_type == TYPE_HORIZONTAL) + n->split_type = TYPE_VERTICAL; + else if (n->split_type == TYPE_VERTICAL) + n->split_type = TYPE_HORIZONTAL; + } + + rotate_tree(n->first_child, rot); + rotate_tree(n->second_child, rot); +} + +void dump_tree(node_t *n, char *rsp, int depth) +{ + if (n == NULL) + return; + + for (int i = 0; i < depth; i++) + sprintf(rsp, "%s", " "); + + if (n->client == NULL) + sprintf(rsp, "%s %.2f\n", (n->split_type == TYPE_HORIZONTAL ? "H" : "V"), n->split_ratio); + else + sprintf(rsp, "%X\n", n->client->window); + + dump_tree(n->first_child, rsp, depth + 1); + dump_tree(n->second_child, rsp, depth + 1); +} + +void update_root_dimensions(void) +{ + desktop_t *d = desk_head; + while (d != NULL) { + d->root->rectangle = (xcb_rectangle_t) {left_padding, top_padding, screen_width - (left_padding + right_padding), screen_height - (top_padding + bottom_padding)}; + d = d->next; + } +} + +void apply_layout(desktop_t *d, node_t *n) +{ + if (n == NULL) + return; + if (is_leaf(n)) { + uint32_t values[4]; + xcb_rectangle_t rect; + if (desk->layout == LAYOUT_TILED) + rect = n->rectangle; + else if (desk->layout == LAYOUT_MONOCLE) + rect = d->root->rectangle; + values[0] = rect.x; + values[1] = rect.y; + values[2] = rect.width; + values[3] = rect.height; + xcb_configure_window(dpy, n->client->window, MOVE_RESIZE_MASK, values); + } else { + unsigned int fence; + xcb_rectangle_t rect = n->rectangle; + if (n->split_type == TYPE_VERTICAL) { + fence = rect.width * n->split_ratio; + n->first_child->rectangle = (xcb_rectangle_t) {rect.x, rect.y, fence, rect.height}; + n->second_child->rectangle = (xcb_rectangle_t) {rect.x + fence, rect.y, rect.width - fence, rect.height}; + + } else if (n->split_type == TYPE_HORIZONTAL) { + fence = rect.height * n->split_ratio; + n->first_child->rectangle = (xcb_rectangle_t) {rect.x, rect.y, rect.width, fence}; + n->second_child->rectangle = (xcb_rectangle_t) {rect.x, rect.y + fence, rect.width, rect.height - fence}; + } + apply_layout(d, n->first_child); + apply_layout(d, n->second_child); + } +} + +void insert_node(desktop_t *d, node_t *n) +{ + if (d == NULL || n == NULL) + return; + + node_t *focus = d->focus; + + if (focus == NULL) { + d->root = n; + } else { + node_t *dad = make_node(); + node_t *fopar = focus->parent; + n->parent = dad; + switch (split_mode) { + case MODE_AUTOMATIC: + if (fopar == NULL) { + dad->first_child = n; + dad->second_child = focus; + dad->split_type = TYPE_VERTICAL; + focus->parent = dad; + d->root = dad; + } else { + node_t *grandpa = fopar->parent; + dad->parent = grandpa; + if (grandpa != NULL) { + if (is_first_child(fopar)) + grandpa->first_child = dad; + else + grandpa->second_child = dad; + } else { + d->root = dad; + } + dad->split_type = fopar->split_type; + dad->split_ratio = fopar->split_ratio; + fopar->parent = dad; + if (is_first_child(focus)) { + dad->first_child = n; + dad->second_child = fopar; + rotate_tree(fopar, ROTATE_CLOCK_WISE); + } else { + dad->first_child = fopar; + dad->second_child = n; + rotate_tree(fopar, ROTATE_COUNTER_CW); + } + } + break; + case MODE_MANUAL: + focus->parent = dad; + switch (split_dir) { + case DIR_LEFT: + dad->split_type = TYPE_VERTICAL; + dad->first_child = n; + dad->second_child = focus; + break; + case DIR_RIGHT: + dad->split_type = TYPE_VERTICAL; + dad->first_child = focus; + dad->second_child = n; + break; + case DIR_UP: + dad->split_type = TYPE_HORIZONTAL; + dad->first_child = n; + dad->second_child = focus; + break; + case DIR_DOWN: + dad->split_type = TYPE_HORIZONTAL; + dad->first_child = focus; + dad->second_child = n; + break; + } + if (d->root == focus) + d->root = dad; + split_mode = MODE_AUTOMATIC; + break; + } + } +} + +void focus_node(desktop_t *d, node_t *n) +{ + if (d == NULL || n == NULL || d->focus == n) + return; + + draw_triple_border(d->focus, normal_border_color_pxl); + draw_triple_border(n, active_border_color_pxl); + + xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, n->client->window, XCB_CURRENT_TIME); +} + +void select_desktop(desktop_t *d) +{ + if (d == NULL) + return; +} + +void remove_node(desktop_t *d, node_t *n) +{ + if (d == NULL || n == NULL) + return; + + node_t *p = n->parent; + + if (p == NULL) { + d->root = NULL; + d->focus = NULL; + d->last_focus = NULL; + } else { + node_t *b; + node_t *g = p->parent; + if (is_first_child(n)) + b = p->second_child; + else + b = p->first_child; + b->parent = g; + if (g != NULL) { + if (is_first_child(p)) + g->first_child = b; + else + g->second_child = b; + } else { + d->root = b; + } + free(p->client); + free(p); + } + + free(n->client); + free(n); +} + +