summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar wil <william.barsse@gmail.com>2017-01-14 17:42:55 +0100
committerLibravatar wil <william.barsse@gmail.com>2017-01-14 19:41:00 +0100
commitb74870f51653872b36dd31fc76bdb738979e58a9 (patch)
tree00dbbaec0408dafc6b7eb89f2f237d458ed4e313
parentMerge branch 'master' into master (diff)
downloadsway-b74870f51653872b36dd31fc76bdb738979e58a9.tar.gz
sway-b74870f51653872b36dd31fc76bdb738979e58a9.tar.zst
sway-b74870f51653872b36dd31fc76bdb738979e58a9.zip
Improved behavior of insert/remove child in auto layouts
Previous implementation would not preserve dimension of groups along the major axis. This should avoid weird behavior when using container motion commands.
-rw-r--r--sway/layout.c136
1 files changed, 108 insertions, 28 deletions
diff --git a/sway/layout.c b/sway/layout.c
index 4b30f729..e3de3354 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -71,6 +71,14 @@ void add_child(swayc_t *parent, swayc_t *child) {
71 } 71 }
72} 72}
73 73
74static double *get_height(swayc_t *cont) {
75 return &cont->height;
76}
77
78static double *get_width(swayc_t *cont) {
79 return &cont->width;
80}
81
74void insert_child(swayc_t *parent, swayc_t *child, int index) { 82void insert_child(swayc_t *parent, swayc_t *child, int index) {
75 if (index > parent->children->length) { 83 if (index > parent->children->length) {
76 index = parent->children->length; 84 index = parent->children->length;
@@ -86,7 +94,44 @@ void insert_child(swayc_t *parent, swayc_t *child, int index) {
86 if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) { 94 if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) {
87 child = new_container(child, parent->workspace_layout); 95 child = new_container(child, parent->workspace_layout);
88 } 96 }
89 97 if (is_auto_layout(parent->layout)) {
98 /* go through each group, adjust the size of the first child of each group */
99 double *(*get_maj_dim)(swayc_t *cont);
100 double *(*get_min_dim)(swayc_t *cont);
101 if (parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT) {
102 get_maj_dim = get_width;
103 get_min_dim = get_height;
104 } else {
105 get_maj_dim = get_height;
106 get_min_dim = get_width;
107 }
108 for (int i = index; i < parent->children->length;) {
109 int start = auto_group_start_index(parent, i);
110 int end = auto_group_end_index(parent, i);
111 swayc_t *first = parent->children->items[start];
112 if (start + 1 < parent->children->length) {
113 /* preserve the group's dimension along major axis */
114 *get_maj_dim(first) = *get_maj_dim(parent->children->items[start + 1]);
115 } else {
116 /* new group, let the apply_layout handle it */
117 first->height = first->width = 0;
118 break;
119 }
120 double remaining = *get_min_dim(parent);
121 for (int j = end - 1; j > start; --j) {
122 swayc_t *sibling = parent->children->items[j];
123 if (sibling == child) {
124 /* the inserted child won't yet have its minor
125 dimension set */
126 remaining -= *get_min_dim(parent) / (end - start);
127 } else {
128 remaining -= *get_min_dim(sibling);
129 }
130 }
131 *get_min_dim(first) = remaining;
132 i = end;
133 }
134 }
90} 135}
91 136
92void add_floating(swayc_t *ws, swayc_t *child) { 137void add_floating(swayc_t *ws, swayc_t *child) {
@@ -185,6 +230,42 @@ swayc_t *remove_child(swayc_t *child) {
185 break; 230 break;
186 } 231 }
187 } 232 }
233 if (is_auto_layout(parent->layout) && parent->children->length) {
234 /* go through each group, adjust the size of the last child of each group */
235 double *(*get_maj_dim)(swayc_t *cont);
236 double *(*get_min_dim)(swayc_t *cont);
237 if (parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT) {
238 get_maj_dim = get_width;
239 get_min_dim = get_height;
240 } else {
241 get_maj_dim = get_height;
242 get_min_dim = get_width;
243 }
244 for (int j = parent->children->length - 1; j >= i;) {
245 int start = auto_group_start_index(parent, j);
246 int end = auto_group_end_index(parent, j);
247 swayc_t *first = parent->children->items[start];
248 if (i == start) {
249 /* removed element was first child in the current group,
250 use its size along the major axis */
251 *get_maj_dim(first) = *get_maj_dim(child);
252 } else if (start > i) {
253 /* preserve the group's dimension along major axis */
254 *get_maj_dim(first) = *get_maj_dim(parent->children->items[start - 1]);
255 }
256 if (end != parent->children->length) {
257 double remaining = *get_min_dim(parent);
258 for (int k = start; k < end - 1; ++k) {
259 swayc_t *sibling = parent->children->items[k];
260 remaining -= *get_min_dim(sibling);
261 }
262 /* last element of the group gets remaining size, elements
263 that don't change groups keep their ratio */
264 *get_min_dim((swayc_t *) parent->children->items[end - 1]) = remaining;
265 } /* else last group, let apply_layout handle it */
266 j = start - 1;
267 }
268 }
188 } 269 }
189 // Set focused to new container 270 // Set focused to new container
190 if (parent->focused == child) { 271 if (parent->focused == child) {
@@ -250,6 +331,24 @@ void swap_geometry(swayc_t *a, swayc_t *b) {
250 b->height = h; 331 b->height = h;
251} 332}
252 333
334static void swap_children(swayc_t *container, int a, int b) {
335 if (a >= 0 && b >= 0 && a < container->children->length
336 && b < container->children->length
337 && a != b) {
338 swayc_t *pa = (swayc_t *)container->children->items[a];
339 swayc_t *pb = (swayc_t *)container->children->items[b];
340 container->children->items[a] = container->children->items[b];
341 container->children->items[b] = pa;
342 if (is_auto_layout(container->layout)) {
343 size_t ga = auto_group_index(container, a);
344 size_t gb = auto_group_index(container, b);
345 if (ga != gb) {
346 swap_geometry(pa, pb);
347 }
348 }
349 }
350}
351
253void move_container(swayc_t *container, enum movement_direction dir) { 352void move_container(swayc_t *container, enum movement_direction dir) {
254 enum swayc_layouts layout = L_NONE; 353 enum swayc_layouts layout = L_NONE;
255 swayc_t *parent = container->parent; 354 swayc_t *parent = container->parent;
@@ -319,29 +418,6 @@ void move_container(swayc_t *container, enum movement_direction dir) {
319 } else if (desired >= parent->children->length) { 418 } else if (desired >= parent->children->length) {
320 desired = 0; 419 desired = 0;
321 } 420 }
322 // if move command makes container change from master to slave
323 // (or the contrary), reset its geometry an the one of the replaced item.
324 if (parent->nb_master
325 && (size_t)parent->children->length > parent->nb_master) {
326 swayc_t *swap_geom = NULL;
327 // if child is being promoted/demoted, it will swap geometry
328 // with the sibling being demoted/promoted.
329 if ((dir == MOVE_NEXT && desired == 0)
330 || (dir == MOVE_PREV && (size_t)desired == parent->nb_master - 1)) {
331 swap_geom = parent->children->items[parent->nb_master - 1];
332 } else if ((dir == MOVE_NEXT && (size_t)desired == parent->nb_master)
333 || (dir == MOVE_PREV && desired == parent->children->length - 1)) {
334 swap_geom = parent->children->items[parent->nb_master];
335 }
336 if (swap_geom) {
337 double h = child->height;
338 double w = child->width;
339 child->width = swap_geom->width;
340 child->height = swap_geom->height;
341 swap_geom->width = w;
342 swap_geom->height = h;
343 }
344 }
345 } 421 }
346 // when it has ascended, legal insertion position is 0:len 422 // when it has ascended, legal insertion position is 0:len
347 // when it has not, legal insertion position is 0:len-1 423 // when it has not, legal insertion position is 0:len-1
@@ -365,10 +441,14 @@ void move_container(swayc_t *container, enum movement_direction dir) {
365 container->width = container->height = 0; 441 container->width = container->height = 0;
366 } 442 }
367 } 443 }
368 swayc_t *old_parent = remove_child(container); 444 if (container->parent == parent) {
369 insert_child(parent, container, desired); 445 swap_children(parent, idx, desired);
370 destroy_container(old_parent); 446 } else {
371 sway_log(L_DEBUG,"Moving to %p %d", parent, desired); 447 swayc_t *old_parent = remove_child(container);
448 insert_child(parent, container, desired);
449 destroy_container(old_parent);
450 sway_log(L_DEBUG,"Moving to %p %d", parent, desired);
451 }
372 break; 452 break;
373 } 453 }
374 } 454 }