void swap_nodes(node_t *n1, node_t *n2) { if (n1 == NULL || n2 == NULL || n1 == n2) return; PUTS("swap nodes"); /* (n1 and n2 are leaves) */ node_t *pn1 = n1->parent; node_t *pn2 = n2->parent; bool n1_first_child = is_first_child(n1); bool n2_first_child = is_first_child(n2); if (pn1 != NULL) { if (n1_first_child) pn1->first_child = n2; else pn1->second_child = n2; } if (pn2 != NULL) { if (n2_first_child) pn2->first_child = n1; else pn2->second_child = n1; } n1->parent = pn2; n2->parent = pn1; if (n1->vacant != n2->vacant) { update_vacant_state(n1->parent); update_vacant_state(n2->parent); } }
void set_visibility(monitor_t *m, desktop_t *d, node_t *n, bool visible) { PRINTF("set visibilty %X: %s\n", n->client->window, BOOLSTR(visible)); if (!n->client->floating) { n->vacant = !visible; update_vacant_state(n->parent); if (visible) rotate_brother(n); else unrotate_brother(n); } if (visible) { if (m->desk == d) window_show(n->client->window); if (d->focus == NULL) { if (mon->desk == d) focus_node(m, d, n); else pseudo_focus(d, n); } } else { if (m->desk == d || n->client->sticky) window_hide(n->client->window); if (d->focus == n) { node_t *f = history_get_node(d, n); if (f == NULL) f = closest_visible(d, n); if (mon->desk == d) focus_node(m, d, f); else pseudo_focus(d, f); } } }
void unlink_node(desktop_t *d, node_t *n) { if (d == NULL || n == NULL) return; PRINTF("unlink node %X\n", n->client->window); 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; bool n_first_child = is_first_child(n); if (n_first_child) { b = p->second_child; if (n->client->born_as == MODE_AUTOMATIC) rotate_tree(b, ROTATE_COUNTER_CLOCKWISE); } else { b = p->first_child; if (n->client->born_as == MODE_AUTOMATIC) rotate_tree(b, ROTATE_CLOCKWISE); } b->parent = g; if (g != NULL) { if (is_first_child(p)) g->first_child = b; else g->second_child = b; } else { d->root = b; } n->parent = NULL; free(p); if (n == d->last_focus) { d->last_focus = NULL; } else if (n == d->focus) { if (d->last_focus != NULL) d->focus = d->last_focus; else d->focus = (n_first_child ? first_extrema(b) : second_extrema(b)); d->last_focus = NULL; } update_vacant_state(b->parent); } }
void restore(char *file_path) { if (file_path == NULL) return; FILE *snapshot = fopen(file_path, "r"); if (snapshot == NULL) { warn("restore: can't open file\n"); return; } char line[MAXLEN]; monitor_t *m = NULL; desktop_t *d = NULL; node_t *n = NULL; num_clients = 0; unsigned int level, last_level = 0, max_uid = 0; bool aborted = false; while (!aborted && fgets(line, sizeof(line), snapshot) != NULL) { unsigned int len = strlen(line); level = 0; while (level < strlen(line) && isspace(line[level])) level++; if (level == 0) { if (m == NULL) m = mon_head; else m = m->next; if (len >= 2) switch (line[len - 2]) { case '#': mon = m; break; case '~': last_mon = m; break; } } else if (level == 2) { if (d == NULL) d = m->desk_head; else d = d->next; int i = len - 1; while (i > 0 && !isupper(line[i])) i--; if (line[i] == 'M') d->layout = LAYOUT_MONOCLE; else if (line[i] == 'T') d->layout = LAYOUT_TILED; if (len >= 2) switch (line[len - 2]) { case '@': m->desk = d; break; case '~': m->last_desk = d; break; } } else { node_t *birth = make_node(); if (level == 4) { empty_desktop(d); d->root = birth; } else { if (level > last_level) { n->first_child = birth; } else { do { n = n->parent; } while (n != NULL && n->second_child != NULL); if (n == NULL) { warn("restore: file is malformed\n"); aborted = true; } n->second_child = birth; } birth->parent = n; } n = birth; if (isupper(line[level])) { char st; sscanf(line + level, "%c %lf", &st, &n->split_ratio); if (st == 'H') n->split_type = TYPE_HORIZONTAL; else if (st == 'V') n->split_type = TYPE_VERTICAL; } else { client_t *c = make_client(XCB_NONE); num_clients++; char ba, floating, transient, fullscreen, urgent, locked; sscanf(line + level, "%c %s %X %u %u %hux%hu%hi%hi %c%c%c%c%c", &ba, c->class_name, &c->window, &c->uid, &c->border_width, &c->floating_rectangle.width, &c->floating_rectangle.height, &c->floating_rectangle.x, &c->floating_rectangle.y, &floating, &transient, &fullscreen, &urgent, &locked); if (ba == 'a') c->born_as = MODE_AUTOMATIC; else if (ba == 'm') c->born_as = MODE_MANUAL; c->floating = (floating == '-' ? false : true); c->transient = (transient == '-' ? false : true); c->fullscreen = (fullscreen == '-' ? false : true); c->urgent = (urgent == '-' ? false : true); c->locked = (locked == '-' ? false : true); if (c->uid > max_uid) max_uid = c->uid; n->client = c; if (len >= 2) switch (line[len - 2]) { case '*': d->focus = n; break; case '~': d->last_focus = n; break; } } } last_level = level; } if (!aborted) { client_uid = max_uid + 1; for (monitor_t *m = mon_head; m != NULL; m = m->next) for (desktop_t *d = m->desk_head; d != NULL; d = d->next) for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n)) { uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK_FFP : CLIENT_EVENT_MASK)}; xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values); if (n->client->floating) { n->vacant = true; update_vacant_state(n->parent); } } } fclose(snapshot); }
void insert_node(monitor_t *m, desktop_t *d, node_t *n) { if (d == NULL || n == NULL) return; PRINTF("insert node %X\n", n->client->window); 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; n->client->born_as = split_mode; switch (split_mode) { case MODE_AUTOMATIC: if (fopar == NULL) { dad->first_child = n; dad->second_child = focus; if (m->rectangle.width > m->rectangle.height) dad->split_type = TYPE_VERTICAL; else dad->split_type = TYPE_HORIZONTAL; 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_CLOCKWISE); } else { dad->first_child = fopar; dad->second_child = n; rotate_tree(fopar, ROTATE_COUNTER_CLOCKWISE); } } break; case MODE_MANUAL: if (fopar != NULL) { if (is_first_child(focus)) fopar->first_child = dad; else fopar->second_child = dad; } dad->split_ratio = focus->split_ratio; dad->parent = fopar; 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; } if (focus->vacant) update_vacant_state(fopar); } }
void restore_tree(char *file_path) { if (file_path == NULL) return; FILE *snapshot = fopen(file_path, "r"); if (snapshot == NULL) { warn("Restore tree: can't open file\n"); return; } PUTS("restore tree"); char line[MAXLEN]; char name[MAXLEN]; coordinates_t loc; monitor_t *m = NULL; desktop_t *d = NULL; node_t *n = NULL; num_clients = 0; unsigned int level, last_level = 0; while (fgets(line, sizeof(line), snapshot) != NULL) { unsigned int len = strlen(line); level = 0; while (level < len && isspace(line[level])) level++; if (level == 0) { int x, y, left, right, top, bottom; unsigned int w, h; char end = 0; name[0] = '\0'; sscanf(line + level, "%s %ux%u%i%i %i,%i,%i,%i %c", name, &w, &h, &x, &y, &top, &right, &bottom, &left, &end); m = find_monitor(name); if (m == NULL) continue; m->rectangle = (xcb_rectangle_t) {x, y, w, h}; m->top_padding = top; m->right_padding = right; m->bottom_padding = bottom; m->left_padding = left; if (end == '#') mon = m; else if (end == '~') last_mon = m; } else if (level == 2) { if (m == NULL) continue; int wg; char layout = 0, end = 0; name[0] = '\0'; loc.desktop = NULL; sscanf(line + level, "%s %i %c %c", name, &wg, &layout, &end); locate_desktop(name, &loc); d = loc.desktop; if (d == NULL) continue; d->window_gap = wg; if (layout == 'M') d->layout = LAYOUT_MONOCLE; else if (layout == 'T') d->layout = LAYOUT_TILED; if (end == '@') m->desk = d; else if (end == '~') m->last_desk = d; } else { if (m == NULL || d == NULL) continue; node_t *birth = make_node(); if (level == 4) { empty_desktop(d); d->root = birth; } else if (n != NULL) { if (level > last_level) { n->first_child = birth; } else { do { n = n->parent; } while (n != NULL && n->second_child != NULL); if (n == NULL) continue; n->second_child = birth; } birth->parent = n; } n = birth; char br; if (isupper(line[level])) { char st; sscanf(line + level, "%c %c %lf", &st, &br, &n->split_ratio); if (st == 'H') n->split_type = TYPE_HORIZONTAL; else if (st == 'V') n->split_type = TYPE_VERTICAL; } else { client_t *c = make_client(XCB_NONE); num_clients++; char floating, transient, fullscreen, urgent, locked, sd, sm, end = 0; sscanf(line + level, "%c %s %X %u %hux%hu%hi%hi %c %c%c%c%c%c%c %c", &br, c->class_name, &c->window, &c->border_width, &c->floating_rectangle.width, &c->floating_rectangle.height, &c->floating_rectangle.x, &c->floating_rectangle.y, &sd, &floating, &transient, &fullscreen, &urgent, &locked, &sm, &end); c->floating = (floating == '-' ? false : true); c->transient = (transient == '-' ? false : true); c->fullscreen = (fullscreen == '-' ? false : true); c->urgent = (urgent == '-' ? false : true); c->locked = (locked == '-' ? false : true); n->split_mode = (sm == '-' ? MODE_AUTOMATIC : MODE_MANUAL); if (sd == 'U') n->split_dir = DIR_UP; else if (sd == 'R') n->split_dir = DIR_RIGHT; else if (sd == 'D') n->split_dir = DIR_DOWN; else if (sd == 'L') n->split_dir = DIR_LEFT; n->client = c; if (end == '*') d->focus = n; } if (br == 'a') n->birth_rotation = 90; else if (br == 'c') n->birth_rotation = 270; else if (br == 'm') n->birth_rotation = 0; } last_level = level; } fclose(snapshot); for (monitor_t *m = mon_head; m != NULL; m = m->next) for (desktop_t *d = m->desk_head; d != NULL; d = d->next) for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) { uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK_FFP : CLIENT_EVENT_MASK)}; xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values); if (n->client->floating) { n->vacant = true; update_vacant_state(n->parent); } } ewmh_update_current_desktop(); }