diff options
-rw-r--r-- | sway/commands/resize.c | 397 |
1 files changed, 194 insertions, 203 deletions
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index 2c5b3f6b..c850575b 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c | |||
@@ -62,225 +62,216 @@ static bool resize_floating(int amount, bool use_width) { | |||
62 | return false; | 62 | return false; |
63 | } | 63 | } |
64 | 64 | ||
65 | static bool resize_tiled(int amount, bool use_width) { | 65 | /** |
66 | swayc_t *parent = get_focused_view(swayc_active_workspace()); | 66 | * returns the index of the container's child that is first in a group. |
67 | swayc_t *focused = parent; | 67 | * This index is > to the <after> argument. |
68 | swayc_t *sibling; | 68 | * This makes the function usable to walk through the groups in a container. |
69 | if (!parent) { | 69 | */ |
70 | return true; | 70 | static int next_group_index(swayc_t *container, int after) { |
71 | } | 71 | if (after < 0) { |
72 | // Find the closest parent container which has siblings of the proper layout. | 72 | return 0; |
73 | // Then apply the resize to all of them. | 73 | } else if (is_auto_layout(container->layout)) { |
74 | int i; | 74 | if ((uint_fast32_t) after < container->nb_master) { |
75 | if (use_width) { | 75 | return container->nb_master; |
76 | int lnumber = 0; | 76 | } else { |
77 | int rnumber = 0; | 77 | uint_fast32_t grp_idx = 0; |
78 | while (parent->parent) { | 78 | for (int i = container->nb_master; i < container->children->length; ) { |
79 | if (parent->parent->layout == L_HORIZ && parent->parent->children) { | 79 | uint_fast32_t grp_sz = (container->children->length - i) / |
80 | for (i = 0; i < parent->parent->children->length; i++) { | 80 | (container->nb_slave_groups - grp_idx); |
81 | sibling = parent->parent->children->items[i]; | 81 | if (after - i < (int) grp_sz) { |
82 | if (sibling->x != focused->x) { | 82 | return i + grp_sz; |
83 | if (sibling->x < parent->x) { | ||
84 | lnumber++; | ||
85 | } else if (sibling->x > parent->x) { | ||
86 | rnumber++; | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | if (rnumber || lnumber) { | ||
91 | break; | ||
92 | } | 83 | } |
84 | i += grp_sz; | ||
93 | } | 85 | } |
94 | parent = parent->parent; | 86 | return container->children->length; |
87 | } | ||
88 | } else { | ||
89 | // return after + 1; | ||
90 | return container->children->length; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Return the number of children in the slave groups. This corresponds to the children | ||
96 | * that are not members of the master group. | ||
97 | */ | ||
98 | static inline uint_fast32_t slave_count(swayc_t *container) { | ||
99 | return container->children->length - container->nb_master; | ||
100 | |||
101 | } | ||
102 | |||
103 | /** | ||
104 | * given the index of a container's child, return the index of the first child of the group | ||
105 | * which index is a member of. | ||
106 | */ | ||
107 | static int group_start_index(swayc_t *container, int index) { | ||
108 | if (index < 0 || ! is_auto_layout(container->layout) || (uint_fast32_t) index < container->nb_master) { | ||
109 | return 0; | ||
110 | } else { | ||
111 | uint_fast32_t grp_sz = slave_count(container) / container->nb_slave_groups; | ||
112 | uint_fast32_t remainder = slave_count(container) % container->nb_slave_groups; | ||
113 | if ((index - container->nb_master) / grp_sz < container->nb_slave_groups - remainder) { | ||
114 | return ((index - container->nb_master) / grp_sz) * grp_sz + container->nb_master; | ||
115 | } else { | ||
116 | int idx2 = (container->nb_slave_groups - remainder) * grp_sz + container->nb_master; | ||
117 | return idx2 + ((idx2 - index) / (grp_sz + 1)) * (grp_sz + 1); | ||
95 | } | 118 | } |
96 | if (parent == &root_container) { | 119 | } |
97 | return true; | 120 | } |
121 | |||
122 | /** | ||
123 | * given the index of a container's child, return the index of the first child of the group | ||
124 | * that follows the one which index is a member of. | ||
125 | */ | ||
126 | static int group_end_index(swayc_t *container, int index) { | ||
127 | if (index < 0 || ! is_auto_layout(container->layout)) { | ||
128 | return container->children->length; | ||
129 | } else { | ||
130 | uint_fast32_t grp_sz = slave_count(container) / container->nb_slave_groups; | ||
131 | uint_fast32_t remainder = slave_count(container) % container->nb_slave_groups; | ||
132 | if ((index - container->nb_master) / grp_sz < container->nb_slave_groups - remainder) { | ||
133 | return ((index - container->nb_master) / grp_sz + 1) * grp_sz + container->nb_master; | ||
134 | } else { | ||
135 | int idx2 = (container->nb_slave_groups - remainder) * grp_sz + container->nb_master; | ||
136 | return idx2 + ((idx2 - index) / (grp_sz + 1) + 1) * (grp_sz + 1); | ||
98 | } | 137 | } |
99 | sway_log(L_DEBUG, "Found the proper parent: %p. It has %d l conts, and %d r conts", parent->parent, lnumber, rnumber); | 138 | } |
100 | //TODO: Ensure rounding is done in such a way that there are NO pixel leaks | 139 | } |
101 | bool valid = true; | 140 | |
102 | for (i = 0; i < parent->parent->children->length; i++) { | 141 | /** |
103 | sibling = parent->parent->children->items[i]; | 142 | * Return the combined number of master and slave groups in the container. |
104 | if (sibling->x != focused->x) { | 143 | */ |
105 | if (sibling->x < parent->x) { | 144 | static inline uint_fast32_t group_count(swayc_t *container) { |
106 | double pixels = -1 * amount; | 145 | return MIN(container->nb_slave_groups, slave_count(container)) + (container->nb_master ? 1 : 0); |
107 | pixels /= lnumber; | 146 | } |
108 | if (rnumber) { | 147 | |
109 | if ((sibling->width + pixels/2) < min_sane_w) { | 148 | /** |
110 | valid = false; | 149 | * return the index of the Group containing <index>th child of <container>. |
111 | break; | 150 | * The index is the order of the group along the container's major axis (starting at 0). |
112 | } | 151 | */ |
113 | } else { | 152 | static uint_fast32_t group_index(swayc_t *container, int index) { |
114 | if ((sibling->width + pixels) < min_sane_w) { | 153 | bool master_first = (container->layout == L_AUTO_LEFT || container->layout == L_AUTO_TOP); |
115 | valid = false; | 154 | int nb_slaves = slave_count(container); |
116 | break; | 155 | if (index < (int) container->nb_master) { |
117 | } | 156 | if (master_first || nb_slaves <= 0) { |
118 | } | 157 | return 0; |
119 | } else if (sibling->x > parent->x) { | 158 | } else { |
120 | double pixels = -1 * amount; | 159 | return MIN(container->nb_slave_groups, nb_slaves); |
121 | pixels /= rnumber; | 160 | } |
122 | if (lnumber) { | 161 | } else { |
123 | if ((sibling->width + pixels/2) < min_sane_w) { | 162 | uint_fast32_t grp_idx = 0; |
124 | valid = false; | 163 | for (int i = container->nb_master; i < container->children->length; ) { |
125 | break; | 164 | uint_fast32_t grp_sz = (container->children->length - i) / |
126 | } | 165 | (container->nb_slave_groups - grp_idx); |
127 | } else { | 166 | if (index - i < (int) grp_sz) { |
128 | if ((sibling->width + pixels) < min_sane_w) { | 167 | break; |
129 | valid = false; | ||
130 | break; | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | } else { | ||
135 | double pixels = amount; | ||
136 | if (parent->width + pixels < min_sane_w) { | ||
137 | valid = false; | ||
138 | break; | ||
139 | } | ||
140 | } | 168 | } |
141 | } | 169 | } |
142 | if (valid) { | 170 | return grp_idx + (master_first ? 1 : 0); |
143 | for (i = 0; i < parent->parent->children->length; i++) { | 171 | } |
144 | sibling = parent->parent->children->items[i]; | 172 | } |
145 | if (sibling->x != focused->x) { | 173 | |
146 | if (sibling->x < parent->x) { | 174 | static bool resize_tiled(int amount, bool use_width) { |
147 | double pixels = -1 * amount; | 175 | swayc_t *container = get_focused_view(swayc_active_workspace()); |
148 | pixels /= lnumber; | 176 | swayc_t *parent = container->parent; |
149 | if (rnumber) { | 177 | int idx_focused = 0; |
150 | recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_RIGHT); | 178 | bool use_major = false; |
151 | } else { | 179 | uint_fast32_t nb_before = 0; |
152 | recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_RIGHT); | 180 | uint_fast32_t nb_after = 0; |
153 | } | 181 | |
154 | } else if (sibling->x > parent->x) { | 182 | // 1. Identify a container ancestor that will allow the focused child to grow in the requested |
155 | double pixels = -1 * amount; | 183 | // direction. |
156 | pixels /= rnumber; | 184 | while (container->parent) { |
157 | if (lnumber) { | 185 | parent = container->parent; |
158 | recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_LEFT); | 186 | if ((parent->children && parent->children->length > 1) && |
159 | } else { | 187 | (is_auto_layout(parent->layout) || (use_width ? parent->layout == L_HORIZ : |
160 | recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_LEFT); | 188 | parent->layout == L_VERT))) { |
161 | } | 189 | // check if container has siblings that can provide/absorb the space needed for |
162 | } | 190 | // the resize operation. |
163 | } else { | 191 | use_major = use_width |
164 | if (rnumber != 0 && lnumber != 0) { | 192 | ? parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT |
165 | double pixels = amount; | 193 | : parent->layout == L_AUTO_TOP || parent->layout == L_AUTO_BOTTOM; |
166 | pixels /= 2; | 194 | // Note: use_major will be false for L_HORIZ and L_VERT |
167 | recursive_resize(parent, pixels, WLC_RESIZE_EDGE_LEFT); | 195 | |
168 | recursive_resize(parent, pixels, WLC_RESIZE_EDGE_RIGHT); | 196 | idx_focused = index_child(container); |
169 | } else if (rnumber) { | 197 | if (idx_focused < 0) { |
170 | recursive_resize(parent, amount, WLC_RESIZE_EDGE_RIGHT); | 198 | sway_log(L_ERROR, "Something weird is happening, child container not " |
171 | } else if (lnumber) { | 199 | "present in its parent's children list."); |
172 | recursive_resize(parent, amount, WLC_RESIZE_EDGE_LEFT); | 200 | continue; |
173 | } | 201 | } |
174 | } | 202 | if (use_major) { |
203 | nb_before = group_index(parent, idx_focused); | ||
204 | nb_after = group_count(parent) - nb_before - 1; | ||
205 | } else { | ||
206 | nb_before = idx_focused - group_start_index(parent, idx_focused); | ||
207 | nb_after = next_group_index(parent, idx_focused) - idx_focused - 1; | ||
208 | } | ||
209 | if (nb_before || nb_after) { | ||
210 | break; | ||
175 | } | 211 | } |
176 | // Recursive resize does not handle positions, let arrange_windows | ||
177 | // take care of that. | ||
178 | arrange_windows(swayc_active_workspace(), -1, -1); | ||
179 | } | 212 | } |
213 | container = parent; /* continue up the tree to the next ancestor */ | ||
214 | } | ||
215 | if (parent == &root_container) { | ||
180 | return true; | 216 | return true; |
181 | } else { | 217 | } |
182 | int tnumber = 0; | 218 | sway_log(L_DEBUG, "Found the proper parent: %p. It has %" PRIuFAST32 " before conts, and %" |
183 | int bnumber = 0; | 219 | PRIuFAST32 " after conts", parent, nb_before, nb_after); |
184 | while (parent->parent) { | 220 | // 2. Ensure that the resize operation will not make one of the resized containers drop |
185 | if (parent->parent->layout == L_VERT) { | 221 | // below the "sane" size threshold. |
186 | for (i = 0; i < parent->parent->children->length; i++) { | 222 | bool valid = true; |
187 | sibling = parent->parent->children->items[i]; | 223 | swayc_t *focused = parent->children->items[idx_focused]; |
188 | if (sibling->y != focused->y) { | 224 | int start = use_major ? 0 : group_start_index(parent, idx_focused); |
189 | if (sibling->y < parent->y) { | 225 | int end = use_major ? parent->children->length : group_end_index(parent, idx_focused); |
190 | bnumber++; | 226 | for (int i = start; i < end; ) { |
191 | } else if (sibling->y > parent->y) { | 227 | swayc_t *sibling = parent->children->items[i]; |
192 | tnumber++; | 228 | double pixels = amount; |
193 | } | 229 | bool is_before = use_width ? sibling->x < focused->x : sibling->y < focused->y; |
194 | } | 230 | bool is_after = use_width ? sibling->x > focused->x : sibling->y > focused->y; |
195 | } | 231 | if (is_before || is_after) { |
196 | if (bnumber || tnumber) { | 232 | pixels = -pixels; |
197 | break; | 233 | pixels /= is_before ? nb_before : nb_after; |
198 | } | 234 | if (nb_after != 0 && nb_before != 0) { |
235 | pixels /= 2; | ||
199 | } | 236 | } |
200 | parent = parent->parent; | ||
201 | } | 237 | } |
202 | if (parent->parent == NULL || parent->parent->children == NULL) { | 238 | if (use_width ? |
203 | return true; | 239 | sibling->width + pixels < min_sane_w : |
240 | sibling->height + pixels < min_sane_h) { | ||
241 | valid = false; | ||
242 | break; | ||
204 | } | 243 | } |
205 | sway_log(L_DEBUG, "Found the proper parent: %p. It has %d b conts, and %d t conts", parent->parent, bnumber, tnumber); | 244 | i = use_major ? next_group_index(parent, i) : (i + 1); |
206 | //TODO: Ensure rounding is done in such a way that there are NO pixel leaks | 245 | } |
207 | bool valid = true; | 246 | // 3. Apply the size change |
208 | for (i = 0; i < parent->parent->children->length; i++) { | 247 | if (valid) { |
209 | sibling = parent->parent->children->items[i]; | 248 | for (int i = 0; i < parent->children->length; ++i) { |
210 | if (sibling->y != focused->y) { | 249 | swayc_t *sibling = parent->children->items[i]; |
211 | if (sibling->y < parent->y) { | 250 | double pixels = amount; |
212 | double pixels = -1 * amount; | 251 | bool is_before = use_width ? sibling->x < focused->x : sibling->y < focused->y; |
213 | pixels /= bnumber; | 252 | bool is_after = use_width ? sibling->x > focused->x : sibling->y > focused->y; |
214 | if (tnumber) { | 253 | if (is_before || is_after) { |
215 | if ((sibling->height + pixels/2) < min_sane_h) { | 254 | pixels = -pixels; |
216 | valid = false; | 255 | pixels /= is_before ? nb_before : nb_after; |
217 | break; | 256 | if (nb_after != 0 && nb_before != 0) { |
218 | } | 257 | pixels /= 2; |
219 | } else { | ||
220 | if ((sibling->height + pixels) < min_sane_h) { | ||
221 | valid = false; | ||
222 | break; | ||
223 | } | ||
224 | } | ||
225 | } else if (sibling->y > parent->y) { | ||
226 | double pixels = -1 * amount; | ||
227 | pixels /= tnumber; | ||
228 | if (bnumber) { | ||
229 | if ((sibling->height + pixels/2) < min_sane_h) { | ||
230 | valid = false; | ||
231 | break; | ||
232 | } | ||
233 | } else { | ||
234 | if ((sibling->height + pixels) < min_sane_h) { | ||
235 | valid = false; | ||
236 | break; | ||
237 | } | ||
238 | } | ||
239 | } | 258 | } |
259 | sway_log(L_DEBUG, "%p: %s", sibling, is_before ? "before" : "after"); | ||
260 | recursive_resize(sibling, pixels, | ||
261 | use_width ? | ||
262 | (is_before ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_LEFT) : | ||
263 | (is_before ? WLC_RESIZE_EDGE_BOTTOM : WLC_RESIZE_EDGE_TOP)); | ||
240 | } else { | 264 | } else { |
241 | double pixels = amount; | 265 | sway_log(L_DEBUG, "%p: same pos", sibling); |
242 | if (parent->height + pixels < min_sane_h) { | 266 | recursive_resize(sibling, pixels, |
243 | valid = false; | 267 | use_width ? WLC_RESIZE_EDGE_LEFT : WLC_RESIZE_EDGE_TOP); |
244 | break; | 268 | recursive_resize(sibling, pixels, |
245 | } | 269 | use_width ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_BOTTOM); |
246 | } | ||
247 | } | ||
248 | if (valid) { | ||
249 | for (i = 0; i < parent->parent->children->length; i++) { | ||
250 | sibling = parent->parent->children->items[i]; | ||
251 | if (sibling->y != focused->y) { | ||
252 | if (sibling->y < parent->y) { | ||
253 | double pixels = -1 * amount; | ||
254 | pixels /= bnumber; | ||
255 | if (tnumber) { | ||
256 | recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_BOTTOM); | ||
257 | } else { | ||
258 | recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_BOTTOM); | ||
259 | } | ||
260 | } else if (sibling->x > parent->x) { | ||
261 | double pixels = -1 * amount; | ||
262 | pixels /= tnumber; | ||
263 | if (bnumber) { | ||
264 | recursive_resize(sibling, pixels/2, WLC_RESIZE_EDGE_TOP); | ||
265 | } else { | ||
266 | recursive_resize(sibling, pixels, WLC_RESIZE_EDGE_TOP); | ||
267 | } | ||
268 | } | ||
269 | } else { | ||
270 | if (bnumber != 0 && tnumber != 0) { | ||
271 | double pixels = amount/2; | ||
272 | recursive_resize(parent, pixels, WLC_RESIZE_EDGE_TOP); | ||
273 | recursive_resize(parent, pixels, WLC_RESIZE_EDGE_BOTTOM); | ||
274 | } else if (tnumber) { | ||
275 | recursive_resize(parent, amount, WLC_RESIZE_EDGE_TOP); | ||
276 | } else if (bnumber) { | ||
277 | recursive_resize(parent, amount, WLC_RESIZE_EDGE_BOTTOM); | ||
278 | } | ||
279 | } | ||
280 | } | 270 | } |
281 | arrange_windows(swayc_active_workspace(), -1, -1); | ||
282 | } | 271 | } |
283 | return true; | 272 | // Recursive resize does not handle positions, let arrange_windows |
273 | // take care of that. | ||
274 | arrange_windows(swayc_active_workspace(), -1, -1); | ||
284 | } | 275 | } |
285 | return true; | 276 | return true; |
286 | } | 277 | } |