The birth_rotation attribute replaces birth_mode

The `birth_mode` was not sufficient for properly unrotate the brother of
a removed node. The `birth_rotation` stores the rotation applied to the
brother subtree when the node was inserted.

This should help to enforce that (L + n) - n = L in every possible
cases. Which means that adding a node and removing it should leave the
layout unchanged.
This commit is contained in:
Bastien Dejean 2013-05-08 14:10:53 +02:00
parent 365c17b429
commit 82bd5644cb
8 changed files with 94 additions and 68 deletions

View file

@ -83,7 +83,7 @@ The following messages are handled:
- `list_monitors [--quiet]` — Perform a dump of each monitor.
- `list_history [DESKTOP_NAME]` — Return the node focus history.
- `list_history` — Return the node focus history of each desktop.
- `list_windows` — Return the list of managed windows (i.e. their identifiers).

View file

@ -106,6 +106,9 @@ Perform a dump of each desktop for the current monitor.
.BI list_monitors " [--quiet]"
Perform a dump of each monitor.
.TP
.BI list_history
Return the node focus history of each desktop.
.TP
.BI list_windows
Return the list of managed windows (i.e. their identifiers).
.TP

View file

@ -55,14 +55,7 @@ void process_message(char *msg, char *rsp)
list_windows(rsp);
return;
} else if (strcmp(cmd, "list_history") == 0) {
char *name = strtok(NULL, TOK_SEP);
if (name != NULL) {
desktop_location_t loc;
if (locate_desktop(name, &loc))
list_history(loc.desktop, rsp);
} else {
list_history(mon->desk, rsp);
}
list_history(rsp);
return;
} else if (strcmp(cmd, "list_rules") == 0) {
list_rules(rsp);

121
tree.c
View file

@ -252,6 +252,41 @@ void rotate_tree(node_t *n, rotate_t rot)
rotate_tree(n->second_child, rot);
}
void rotate_brother(node_t *n)
{
if (n == NULL || n->parent == NULL)
return;
if (is_first_child(n))
rotate_tree(n->parent->second_child, n->birth_rotation);
else
rotate_tree(n->parent->first_child, n->birth_rotation);
}
void unrotate_tree(node_t *n, rotate_t rot)
{
switch(rot) {
case ROTATE_CLOCKWISE:
rotate_tree(n, ROTATE_COUNTER_CLOCKWISE);
break;
case ROTATE_COUNTER_CLOCKWISE:
rotate_tree(n, ROTATE_CLOCKWISE);
break;
case ROTATE_IDENTITY:
case ROTATE_FULL_CYCLE:
break;
}
}
void unrotate_brother(node_t *n)
{
if (n == NULL || n->parent == NULL)
return;
if (is_first_child(n))
unrotate_tree(n->parent->second_child, n->birth_rotation);
else
unrotate_tree(n->parent->first_child, n->birth_rotation);
}
void flip_tree(node_t *n, flip_t flp)
{
if (n == NULL || is_leaf(n))
@ -271,13 +306,18 @@ void flip_tree(node_t *n, flip_t flp)
flip_tree(n->second_child, flp);
}
void list_history(desktop_t *d, char *rsp)
void list_history(char *rsp)
{
char line[MAXLEN];
for (node_list_t *a = d->history->head; a != NULL; a = a->next) {
snprintf(line, sizeof(line), "%s %X\n", a->node->client->class_name, a->node->client->window);
strncat(rsp, line, REMLEN(rsp));
}
for (monitor_t *m = mon_head; m != NULL; m = m->next)
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
snprintf(line, sizeof(line), "%s\n", d->name);
strncat(rsp, line, REMLEN(rsp));
for (node_list_t *a = d->history->tail; a != NULL; a = a->prev) {
snprintf(line, sizeof(line), " %X\n", a->node->client->window);
strncat(rsp, line, REMLEN(rsp));
}
}
}
int balance_tree(node_t *n)
@ -383,7 +423,6 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n)
PRINTF("insert node %X\n", n->client->window);
node_t *focus = d->focus;
n->birth_mode = split_mode;
if (focus == NULL) {
d->root = n;
@ -391,7 +430,7 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n)
node_t *dad = make_node();
node_t *fopar = focus->parent;
n->parent = dad;
dad->birth_mode = focus->birth_mode;
dad->birth_rotation = focus->birth_rotation;
switch (split_mode) {
case MODE_AUTOMATIC:
if (fopar == NULL) {
@ -417,15 +456,18 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n)
dad->split_type = fopar->split_type;
dad->split_ratio = fopar->split_ratio;
fopar->parent = dad;
rotate_t rot;
if (is_first_child(focus)) {
dad->first_child = n;
dad->second_child = fopar;
rotate_tree(fopar, ROTATE_CLOCKWISE);
rot = ROTATE_CLOCKWISE;
} else {
dad->first_child = fopar;
dad->second_child = n;
rotate_tree(fopar, ROTATE_COUNTER_CLOCKWISE);
rot = ROTATE_COUNTER_CLOCKWISE;
}
rotate_tree(fopar, rot);
n->birth_rotation = rot;
}
break;
case MODE_MANUAL:
@ -438,7 +480,7 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n)
dad->split_ratio = focus->split_ratio;
dad->parent = fopar;
focus->parent = dad;
focus->birth_mode = MODE_MANUAL;
focus->birth_rotation = ROTATE_IDENTITY;
switch (split_dir) {
case DIR_LEFT:
dad->split_type = TYPE_VERTICAL;
@ -546,15 +588,14 @@ void unlink_node(desktop_t *d, node_t *n)
} else {
node_t *b;
node_t *g = p->parent;
bool n_first_child = is_first_child(n);
if (n_first_child) {
if (is_first_child(n)) {
b = p->second_child;
if (n->birth_mode == MODE_AUTOMATIC && !n->vacant)
rotate_tree(b, ROTATE_COUNTER_CLOCKWISE);
if (!n->vacant)
unrotate_tree(b, n->birth_rotation);
} else {
b = p->first_child;
if (n->birth_mode == MODE_AUTOMATIC && !n->vacant)
rotate_tree(b, ROTATE_CLOCKWISE);
if (!n->vacant)
unrotate_tree(b, n->birth_rotation);
}
b->parent = g;
if (g != NULL) {
@ -566,19 +607,12 @@ void unlink_node(desktop_t *d, node_t *n)
d->root = b;
}
b->birth_mode = p->birth_mode;
b->birth_rotation = p->birth_rotation;
n->parent = NULL;
free(p);
if (n == d->focus) {
node_t *last_focus = history_get(d->history, 1);
if (last_focus != NULL) {
d->focus = last_focus;
} else {
d->focus = (n_first_child ? first_extrema(b) : second_extrema(b));
history_add(d->history, d->focus);
}
}
if (n == d->focus)
d->focus = history_get(d->history, 1);
update_vacant_state(b->parent);
}
@ -629,8 +663,8 @@ void swap_nodes(node_t *n1, node_t *n2)
node_t *pn2 = n2->parent;
bool n1_first_child = is_first_child(n1);
bool n2_first_child = is_first_child(n2);
split_mode_t bm1 = n1->birth_mode;
split_mode_t bm2 = n2->birth_mode;
rotate_t br1 = n1->birth_rotation;
rotate_t br2 = n2->birth_rotation;
if (pn1 != NULL) {
if (n1_first_child)
@ -648,8 +682,8 @@ void swap_nodes(node_t *n1, node_t *n2)
n1->parent = pn2;
n2->parent = pn1;
n1->birth_mode = bm2;
n2->birth_mode = bm1;
n1->birth_rotation = br2;
n2->birth_rotation = br1;
if (n1->vacant != n2->vacant) {
update_vacant_state(n1->parent);
@ -946,9 +980,9 @@ void list(desktop_t *d, node_t *n, char *rsp, unsigned int depth)
if (is_leaf(n)) {
client_t *c = n->client;
snprintf(line, sizeof(line), "%c %s %X %u %u %ux%u%+i%+i %c%c%c%c%c", (n->birth_mode == MODE_AUTOMATIC ? 'a' : 'm'), 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, (c->floating ? 'f' : '-'), (c->transient ? 't' : '-'), (c->fullscreen ? 'F' : '-'), (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'));
snprintf(line, sizeof(line), "%c %s %X %u %u %ux%u%+i%+i %c%c%c%c%c", (n->birth_rotation == ROTATE_CLOCKWISE ? 'a' : (n->birth_rotation == ROTATE_COUNTER_CLOCKWISE ? 'c' : 'm')), 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, (c->floating ? 'f' : '-'), (c->transient ? 't' : '-'), (c->fullscreen ? 'F' : '-'), (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'));
} else {
snprintf(line, sizeof(line), "%c %c %.2f", (n->split_type == TYPE_HORIZONTAL ? 'H' : 'V'), (n->birth_mode == MODE_AUTOMATIC ? 'a' : 'm'), n->split_ratio);
snprintf(line, sizeof(line), "%c %c %.2f", (n->split_type == TYPE_HORIZONTAL ? 'H' : 'V'), (n->birth_rotation == ROTATE_CLOCKWISE ? 'a' : (n->birth_rotation == ROTATE_COUNTER_CLOCKWISE ? 'c' : 'm')), n->split_ratio);
}
strncat(rsp, line, REMLEN(rsp));
@ -1043,26 +1077,19 @@ void restore(char *file_path)
}
n = birth;
char br;
if (isupper(line[level])) {
char st, bm;
sscanf(line + level, "%c %c %lf", &st, &bm, &n->split_ratio);
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;
if (bm == 'a')
n->birth_mode = MODE_AUTOMATIC;
else if (bm == 'm')
n->birth_mode = MODE_MANUAL;
} else {
client_t *c = make_client(XCB_NONE);
num_clients++;
char bm, floating, transient, fullscreen, urgent, locked;
sscanf(line + level, "%c %s %X %u %u %hux%hu%hi%hi %c%c%c%c%c", &bm, 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 (bm == 'a')
n->birth_mode = MODE_AUTOMATIC;
else if (bm == 'm')
n->birth_mode = MODE_MANUAL;
char floating, transient, fullscreen, urgent, locked;
sscanf(line + level, "%c %s %X %u %u %hux%hu%hi%hi %c%c%c%c%c", &br, 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);
c->floating = (floating == '-' ? false : true);
c->transient = (transient == '-' ? false : true);
c->fullscreen = (fullscreen == '-' ? false : true);
@ -1074,6 +1101,12 @@ void restore(char *file_path)
if (len >= 2 && line[len - 2] == '*')
d->focus = n;
}
if (br == 'a')
n->birth_rotation = ROTATE_CLOCKWISE;
else if (br == 'c')
n->birth_rotation = ROTATE_COUNTER_CLOCKWISE;
else if (br == 'm')
n->birth_rotation = ROTATE_IDENTITY;
}
last_level = level;
}

5
tree.h
View file

@ -22,6 +22,9 @@ int tiled_area(node_t *);
node_t *find_by_area(desktop_t *, swap_arg_t);
void move_fence(node_t *, direction_t, fence_move_t);
void rotate_tree(node_t *, rotate_t);
void rotate_brother(node_t *);
void unrotate_tree(node_t *, rotate_t);
void unrotate_brother(node_t *);
void flip_tree(node_t *, flip_t);
int balance_tree(node_t *);
void arrange(monitor_t *, desktop_t *);
@ -44,7 +47,7 @@ void nearest_leaf(monitor_t *, desktop_t *, node_t *, nearest_arg_t, skip_client
void circulate_leaves(monitor_t *, desktop_t *, circulate_dir_t);
void update_vacant_state(node_t *);
void put_status(void);
void list_history(desktop_t *, char *);
void list_history(char *);
void list_monitors(list_option_t, char *);
void list_desktops(monitor_t *, list_option_t, unsigned int, char *);
void list(desktop_t *, node_t *, char *, unsigned int);

View file

@ -14,6 +14,7 @@ node_t *make_node(void)
n->parent = n->first_child = n->second_child = NULL;
n->split_ratio = split_ratio;
n->split_type = TYPE_VERTICAL;
n->birth_rotation = ROTATE_IDENTITY;
n->client = NULL;
n->vacant = false;
return n;

View file

@ -80,6 +80,7 @@ typedef enum {
} circulate_dir_t;
typedef enum {
ROTATE_IDENTITY,
ROTATE_CLOCKWISE,
ROTATE_COUNTER_CLOCKWISE,
ROTATE_FULL_CYCLE
@ -137,7 +138,7 @@ typedef struct node_t node_t;
struct node_t {
split_type_t split_type;
double split_ratio;
split_mode_t birth_mode;
rotate_t birth_rotation;
xcb_rectangle_t rectangle;
bool vacant; /* vacant nodes only hold floating clients */
node_t *first_child;

View file

@ -144,9 +144,6 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
node_t *birth = make_node();
birth->client = c;
if (floating)
split_mode = MODE_MANUAL;
insert_node(m, d, birth);
disable_shadow(c->window);
@ -364,19 +361,14 @@ void toggle_floating(node_t *n)
c->floating = !c->floating;
n->vacant = !n->vacant;
update_vacant_state(n->parent);
if (c->floating)
if (c->floating) {
window_raise(c->window);
else if (is_tiled(c))
window_lower(c->window);
if (c->floating)
enable_shadow(c->window);
else
unrotate_brother(n);
} else {
window_lower(c->window);
disable_shadow(c->window);
if (n->parent != NULL && n->birth_mode == MODE_AUTOMATIC) {
if (is_first_child(n))
rotate_tree(n->parent->second_child, c->floating ? ROTATE_COUNTER_CLOCKWISE : ROTATE_CLOCKWISE);
else
rotate_tree(n->parent->first_child, c->floating ? ROTATE_CLOCKWISE : ROTATE_COUNTER_CLOCKWISE);
rotate_brother(n);
}
update_current();
}