summaryrefslogtreecommitdiffstats
path: root/sway
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 /sway
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.
Diffstat (limited to 'sway')
-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 }