| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "frame.h" | ||
| 2 | #include "editor.h" | ||
| 3 | #include "util/xmalloc.h" | ||
| 4 | #include "window.h" | ||
| 5 | |||
| 6 | enum { | ||
| 7 | WINDOW_MIN_WIDTH = 8, | ||
| 8 | WINDOW_MIN_HEIGHT = 3, | ||
| 9 | }; | ||
| 10 | |||
| 11 | // Recursion is bounded by the number of descendant frames, which is | ||
| 12 | // typically not more than 5 or so | ||
| 13 | // NOLINTBEGIN(misc-no-recursion) | ||
| 14 | |||
| 15 | 11 | static void sanity_check_frame(const Frame *frame) | |
| 16 | { | ||
| 17 | 11 | bool has_window = !!frame->window; | |
| 18 | 11 | bool has_frames = frame->frames.count > 0; | |
| 19 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 11 times.
|
11 | if (has_window == has_frames) { |
| 20 | − | BUG("frames must contain a window or subframe(s), but never both"); | |
| 21 | } | ||
| 22 | 11 | BUG_ON(has_window && frame != frame->window->frame); | |
| 23 | 11 | } | |
| 24 | |||
| 25 | 46 | static int get_min_w(const Frame *frame) | |
| 26 | { | ||
| 27 |
2/2✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 11 taken 43 times.
|
46 | if (frame->window) { |
| 28 | return WINDOW_MIN_WIDTH; | ||
| 29 | } | ||
| 30 | |||
| 31 | 3 | void **subframes = frame->frames.ptrs; | |
| 32 | 3 | size_t count = frame->frames.count; | |
| 33 |
1/2✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 10 not taken.
|
3 | if (!frame->vertical) { |
| 34 | 3 | int w = count - 1; // Separators | |
| 35 |
2/2✓ Branch 7 → 5 taken 6 times.
✓ Branch 7 → 11 taken 3 times.
|
9 | for (size_t i = 0; i < count; i++) { |
| 36 | 6 | w += get_min_w(subframes[i]); | |
| 37 | } | ||
| 38 | return w; | ||
| 39 | } | ||
| 40 | |||
| 41 | int max = 0; | ||
| 42 | ✗ | for (size_t i = 0; i < count; i++) { | |
| 43 | ✗ | int w = get_min_w(subframes[i]); | |
| 44 | ✗ | max = MAX(w, max); | |
| 45 | } | ||
| 46 | return max; | ||
| 47 | } | ||
| 48 | |||
| 49 | 30 | static int get_min_h(const Frame *frame) | |
| 50 | { | ||
| 51 |
2/2✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 10 taken 27 times.
|
30 | if (frame->window) { |
| 52 | return WINDOW_MIN_HEIGHT; | ||
| 53 | } | ||
| 54 | |||
| 55 | 3 | void **subframes = frame->frames.ptrs; | |
| 56 | 3 | size_t count = frame->frames.count; | |
| 57 |
1/2✗ Branch 3 → 6 not taken.
✓ Branch 3 → 9 taken 3 times.
|
3 | if (frame->vertical) { |
| 58 | int h = 0; | ||
| 59 | ✗ | for (size_t i = 0; i < count; i++) { | |
| 60 | ✗ | h += get_min_h(subframes[i]); | |
| 61 | } | ||
| 62 | return h; | ||
| 63 | } | ||
| 64 | |||
| 65 | int max = 0; | ||
| 66 |
2/2✓ Branch 9 → 7 taken 6 times.
✓ Branch 9 → 10 taken 3 times.
|
9 | for (size_t i = 0; i < count; i++) { |
| 67 | 6 | int h = get_min_h(subframes[i]); | |
| 68 | 6 | max = MAX(h, max); | |
| 69 | } | ||
| 70 | return max; | ||
| 71 | } | ||
| 72 | |||
| 73 | // Get parent frame and assert non-NULL, for use in contexts where | ||
| 74 | // `frame` may not be the root frame | ||
| 75 | 62 | static Frame *frame_must_get_parent(const Frame *frame) | |
| 76 | { | ||
| 77 | 62 | Frame *parent = frame->parent; | |
| 78 | 62 | BUG_ON(!parent); | |
| 79 | 62 | return parent; | |
| 80 | } | ||
| 81 | |||
| 82 | 16 | static int get_min(const Frame *frame) | |
| 83 | { | ||
| 84 | 16 | const Frame *parent = frame_must_get_parent(frame); | |
| 85 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 16 times.
|
16 | return parent->vertical ? get_min_h(frame) : get_min_w(frame); |
| 86 | } | ||
| 87 | |||
| 88 | 13 | static int get_size(const Frame *frame) | |
| 89 | { | ||
| 90 | 13 | const Frame *parent = frame_must_get_parent(frame); | |
| 91 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 13 times.
|
13 | return parent->vertical ? frame->h : frame->w; |
| 92 | } | ||
| 93 | |||
| 94 | 4 | static int get_container_size(const Frame *frame) | |
| 95 | { | ||
| 96 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 4 times.
|
4 | return frame->vertical ? frame->h : frame->w; |
| 97 | } | ||
| 98 | |||
| 99 | 18 | static void set_size(Frame *frame, int size) | |
| 100 | { | ||
| 101 | 18 | const Frame *parent = frame_must_get_parent(frame); | |
| 102 | 18 | bool vertical = parent->vertical; | |
| 103 |
1/2✓ Branch 3 → 4 taken 18 times.
✗ Branch 3 → 5 not taken.
|
18 | int w = vertical ? parent->w : size; |
| 104 | 18 | int h = vertical ? size : parent->h; | |
| 105 | 18 | frame_set_size(frame, w, h); | |
| 106 | 18 | } | |
| 107 | |||
| 108 | 4 | static void divide_equally(const Frame *frame) | |
| 109 | { | ||
| 110 | 4 | void **ptrs = frame->frames.ptrs; | |
| 111 | 4 | size_t count = frame->frames.count; | |
| 112 | 4 | BUG_ON(count == 0); | |
| 113 | 4 | BUG_ON(!ptrs); | |
| 114 | |||
| 115 | 4 | int *min = xmallocarray(count, sizeof(int)); | |
| 116 |
2/2✓ Branch 10 → 8 taken 8 times.
✓ Branch 10 → 11 taken 4 times.
|
12 | for (size_t i = 0; i < count; i++) { |
| 117 | 8 | min[i] = get_min(ptrs[i]); | |
| 118 | } | ||
| 119 | |||
| 120 | 4 | int *size = xcalloc(count, sizeof(int)); | |
| 121 | 4 | int s = get_container_size(frame); | |
| 122 | 4 | int q, r, used; | |
| 123 | 4 | size_t n = count; | |
| 124 | |||
| 125 | // Consume q and r as equally as possible | ||
| 126 | 4 | do { | |
| 127 | 4 | used = 0; | |
| 128 | 4 | q = s / n; | |
| 129 | 4 | r = s % n; | |
| 130 |
2/2✓ Branch 18 → 14 taken 8 times.
✓ Branch 18 → 19 taken 4 times.
|
12 | for (size_t i = 0; i < count; i++) { |
| 131 |
2/4✓ Branch 14 → 15 taken 8 times.
✗ Branch 14 → 17 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 8 times.
|
8 | if (size[i] == 0 && min[i] > q) { |
| 132 | ✗ | size[i] = min[i]; | |
| 133 | ✗ | used += min[i]; | |
| 134 | ✗ | n--; | |
| 135 | } | ||
| 136 | } | ||
| 137 | 4 | s -= used; | |
| 138 |
1/2✗ Branch 19 → 13 not taken.
✓ Branch 19 → 24 taken 4 times.
|
4 | } while (used && n > 0); |
| 139 | |||
| 140 |
2/2✓ Branch 24 → 20 taken 8 times.
✓ Branch 24 → 25 taken 4 times.
|
12 | for (size_t i = 0; i < count; i++) { |
| 141 | 8 | Frame *c = ptrs[i]; | |
| 142 |
1/2✓ Branch 20 → 21 taken 8 times.
✗ Branch 20 → 22 not taken.
|
8 | if (size[i] == 0) { |
| 143 | 8 | size[i] = q + (r-- > 0); | |
| 144 | } | ||
| 145 | 8 | set_size(c, size[i]); | |
| 146 | } | ||
| 147 | |||
| 148 | 4 | free(size); | |
| 149 | 4 | free(min); | |
| 150 | 4 | } | |
| 151 | |||
| 152 | ✗ | static void fix_size(const Frame *frame) | |
| 153 | { | ||
| 154 | ✗ | void **ptrs = frame->frames.ptrs; | |
| 155 | ✗ | size_t count = frame->frames.count; | |
| 156 | ✗ | int *size = xmallocarray(count, sizeof(int)); | |
| 157 | ✗ | int *min = xmallocarray(count, sizeof(int)); | |
| 158 | ✗ | int total = 0; | |
| 159 | |||
| 160 | ✗ | for (size_t i = 0; i < count; i++) { | |
| 161 | ✗ | const Frame *c = ptrs[i]; | |
| 162 | ✗ | min[i] = get_min(c); | |
| 163 | ✗ | size[i] = MAX(get_size(c), min[i]); | |
| 164 | ✗ | total += size[i]; | |
| 165 | } | ||
| 166 | |||
| 167 | ✗ | int s = get_container_size(frame); | |
| 168 | ✗ | if (total > s) { | |
| 169 | ✗ | int n = total - s; | |
| 170 | ✗ | for (ssize_t i = count - 1; n > 0 && i >= 0; i--) { | |
| 171 | ✗ | int new_size = MAX(size[i] - n, min[i]); | |
| 172 | ✗ | n -= size[i] - new_size; | |
| 173 | ✗ | size[i] = new_size; | |
| 174 | } | ||
| 175 | } else { | ||
| 176 | ✗ | size[count - 1] += s - total; | |
| 177 | } | ||
| 178 | |||
| 179 | ✗ | for (size_t i = 0; i < count; i++) { | |
| 180 | ✗ | set_size(ptrs[i], size[i]); | |
| 181 | } | ||
| 182 | |||
| 183 | ✗ | free(size); | |
| 184 | ✗ | free(min); | |
| 185 | ✗ | } | |
| 186 | |||
| 187 | 2 | static void add_to_sibling_size(Frame *frame, int count) | |
| 188 | { | ||
| 189 | 2 | const Frame *parent = frame_must_get_parent(frame); | |
| 190 | 2 | const PointerArray *pframes = &parent->frames; | |
| 191 | 2 | size_t idx = ptr_array_xindex(pframes, frame); | |
| 192 | 2 | bool last = (idx == pframes->count - 1); | |
| 193 |
1/2✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 6 not taken.
|
2 | frame = pframes->ptrs[last ? idx - 1 : idx + 1]; |
| 194 | 2 | set_size(frame, get_size(frame) + count); | |
| 195 | 2 | } | |
| 196 | |||
| 197 | 3 | static int sub(Frame *frame, int count) | |
| 198 | { | ||
| 199 | 3 | int min = get_min(frame); | |
| 200 | 3 | int old = get_size(frame); | |
| 201 | 3 | int new = MAX(min, old - count); | |
| 202 |
1/2✓ Branch 4 → 5 taken 3 times.
✗ Branch 4 → 6 not taken.
|
3 | if (new != old) { |
| 203 | 3 | set_size(frame, new); | |
| 204 | } | ||
| 205 | 3 | return count - (old - new); | |
| 206 | } | ||
| 207 | |||
| 208 | 3 | static void subtract_from_sibling_size(const Frame *frame, int count) | |
| 209 | { | ||
| 210 | 3 | const Frame *parent = frame_must_get_parent(frame); | |
| 211 | 3 | const PointerArray *pframes = &parent->frames; | |
| 212 | 3 | size_t idx = ptr_array_xindex(pframes, frame); | |
| 213 | 3 | void **ptrs = pframes->ptrs; | |
| 214 | |||
| 215 |
1/2✗ Branch 8 → 5 not taken.
✓ Branch 8 → 11 taken 3 times.
|
3 | for (size_t i = idx + 1, n = pframes->count; i < n; i++) { |
| 216 | ✗ | count = sub(ptrs[i], count); | |
| 217 | ✗ | if (count == 0) { | |
| 218 | return; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 |
1/2✓ Branch 11 → 9 taken 3 times.
✗ Branch 11 → 12 not taken.
|
3 | for (size_t i = idx; i > 0; i--) { |
| 223 | 3 | count = sub(ptrs[i - 1], count); | |
| 224 |
1/2✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 3 times.
|
3 | if (count == 0) { |
| 225 | return; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | 5 | static void resize_to(Frame *frame, int size) | |
| 231 | { | ||
| 232 | 5 | const Frame *parent = frame_must_get_parent(frame); | |
| 233 | 5 | size_t count = parent->frames.count; | |
| 234 | 5 | BUG_ON(count == 0); | |
| 235 | |||
| 236 |
1/2✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 5 times.
|
5 | int total = parent->vertical ? parent->h : parent->w; |
| 237 | 5 | int min = get_min(frame); | |
| 238 | 5 | int max = total - ((count - 1) * min); | |
| 239 | 5 | max = MAX(min, max); | |
| 240 | 5 | size = CLAMP(size, min, max); | |
| 241 | |||
| 242 | 5 | int change = size - get_size(frame); | |
| 243 |
1/2✓ Branch 10 → 11 taken 5 times.
✗ Branch 10 → 15 not taken.
|
5 | if (change == 0) { |
| 244 | return; | ||
| 245 | } | ||
| 246 | |||
| 247 | 5 | set_size(frame, size); | |
| 248 |
2/2✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 14 taken 3 times.
|
5 | if (change < 0) { |
| 249 | 2 | add_to_sibling_size(frame, -change); | |
| 250 | } else { | ||
| 251 | 3 | subtract_from_sibling_size(frame, change); | |
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | 30 | static bool rightmost_frame(const Frame *frame) | |
| 256 | { | ||
| 257 | 30 | const Frame *parent = frame->parent; | |
| 258 |
2/2✓ Branch 2 → 3 taken 18 times.
✓ Branch 2 → 6 taken 12 times.
|
30 | if (!parent) { |
| 259 | return true; | ||
| 260 | } | ||
| 261 |
1/2✓ Branch 3 → 4 taken 18 times.
✗ Branch 3 → 5 not taken.
|
18 | if (!parent->vertical) { |
| 262 |
2/2✓ Branch 4 → 5 taken 9 times.
✓ Branch 4 → 6 taken 9 times.
|
18 | if (frame != parent->frames.ptrs[parent->frames.count - 1]) { |
| 263 | return false; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | 9 | return rightmost_frame(parent); | |
| 267 | } | ||
| 268 | |||
| 269 | 16 | static Frame *new_frame(void) | |
| 270 | { | ||
| 271 | 16 | Frame *frame = xcalloc1(sizeof(*frame)); | |
| 272 | 16 | frame->equal_size = true; | |
| 273 | 16 | return frame; | |
| 274 | } | ||
| 275 | |||
| 276 | 15 | static Frame *add_frame(Frame *parent, Window *window, size_t idx) | |
| 277 | { | ||
| 278 | 15 | Frame *frame = new_frame(); | |
| 279 | 15 | frame->parent = parent; | |
| 280 | 15 | frame->window = window; | |
| 281 | 15 | window->frame = frame; | |
| 282 |
2/2✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 8 taken 10 times.
|
15 | if (parent) { |
| 283 | 5 | BUG_ON(idx > parent->frames.count); | |
| 284 | 5 | ptr_array_insert(&parent->frames, frame, idx); | |
| 285 | 5 | parent->window = NULL; | |
| 286 | } | ||
| 287 | 15 | return frame; | |
| 288 | } | ||
| 289 | |||
| 290 | 10 | Frame *new_root_frame(Window *window) | |
| 291 | { | ||
| 292 | 10 | return add_frame(NULL, window, 0); | |
| 293 | } | ||
| 294 | |||
| 295 | 6 | static Frame *find_resizable(Frame *frame, ResizeDirection dir) | |
| 296 | { | ||
| 297 |
2/2✓ Branch 2 → 8 taken 2 times.
✓ Branch 2 → 9 taken 4 times.
|
6 | if (dir == RESIZE_DIRECTION_AUTO) { |
| 298 | return frame; | ||
| 299 | } | ||
| 300 | |||
| 301 |
2/2✓ Branch 8 → 3 taken 2 times.
✓ Branch 8 → 9 taken 1 time.
|
3 | while (frame->parent) { |
| 302 |
3/4✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1 time.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 9 not taken.
|
2 | if (dir == RESIZE_DIRECTION_VERTICAL && frame->parent->vertical) { |
| 303 | return frame; | ||
| 304 | } | ||
| 305 |
3/4✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 1 time.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 9 taken 1 time.
|
2 | if (dir == RESIZE_DIRECTION_HORIZONTAL && !frame->parent->vertical) { |
| 306 | return frame; | ||
| 307 | } | ||
| 308 | frame = frame->parent; | ||
| 309 | } | ||
| 310 | return NULL; | ||
| 311 | } | ||
| 312 | |||
| 313 | 24 | void frame_set_size(Frame *frame, int w, int h) | |
| 314 | { | ||
| 315 | 24 | int min_w = get_min_w(frame); | |
| 316 | 24 | int min_h = get_min_h(frame); | |
| 317 | 24 | w = MAX(w, min_w); | |
| 318 | 24 | h = MAX(h, min_h); | |
| 319 | 24 | frame->w = w; | |
| 320 | 24 | frame->h = h; | |
| 321 | |||
| 322 |
2/2✓ Branch 4 → 5 taken 21 times.
✓ Branch 4 → 8 taken 3 times.
|
24 | if (frame->window) { |
| 323 | 21 | w -= rightmost_frame(frame) ? 0 : 1; // Separator | |
| 324 | 21 | window_set_size(frame->window, w, h); | |
| 325 | 21 | return; | |
| 326 | } | ||
| 327 | |||
| 328 |
1/2✓ Branch 8 → 9 taken 3 times.
✗ Branch 8 → 10 not taken.
|
3 | if (frame->equal_size) { |
| 329 | 3 | divide_equally(frame); | |
| 330 | } else { | ||
| 331 | ✗ | fix_size(frame); | |
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | 1 | void frame_equalize_sizes(Frame *parent) | |
| 336 | { | ||
| 337 | 1 | parent->equal_size = true; | |
| 338 | 1 | divide_equally(parent); | |
| 339 | 1 | update_window_coordinates(parent); | |
| 340 | 1 | } | |
| 341 | |||
| 342 | 6 | void frame_resize(Frame *frame, ResizeDirection dir, int size) | |
| 343 | { | ||
| 344 | 6 | frame = find_resizable(frame, dir); | |
| 345 |
2/2✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 7 taken 1 time.
|
6 | if (!frame) { |
| 346 | return; | ||
| 347 | } | ||
| 348 | |||
| 349 | 5 | Frame *parent = frame_must_get_parent(frame); | |
| 350 | 5 | parent->equal_size = false; | |
| 351 | 5 | resize_to(frame, size); | |
| 352 | 5 | update_window_coordinates(parent); | |
| 353 | } | ||
| 354 | |||
| 355 | 3 | void frame_add_to_size(Frame *frame, ResizeDirection dir, int amount) | |
| 356 | { | ||
| 357 | 3 | frame_resize(frame, dir, get_size(frame) + amount); | |
| 358 | 3 | } | |
| 359 | |||
| 360 | 29 | static void update_frame_coordinates(const Frame *frame, int x, int y) | |
| 361 | { | ||
| 362 |
2/2✓ Branch 2 → 3 taken 20 times.
✓ Branch 2 → 5 taken 9 times.
|
29 | if (frame->window) { |
| 363 | 20 | window_set_coordinates(frame->window, x, y); | |
| 364 | 20 | return; | |
| 365 | } | ||
| 366 | |||
| 367 | 9 | void **ptrs = frame->frames.ptrs; | |
| 368 |
2/2✓ Branch 11 → 6 taken 18 times.
✓ Branch 11 → 12 taken 9 times.
|
27 | for (size_t i = 0, n = frame->frames.count; i < n; i++) { |
| 369 | 18 | const Frame *c = ptrs[i]; | |
| 370 | 18 | update_frame_coordinates(c, x, y); | |
| 371 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 18 times.
|
18 | if (frame->vertical) { |
| 372 | ✗ | y += c->h; | |
| 373 | } else { | ||
| 374 | 18 | x += c->w; | |
| 375 | } | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | 11 | static Frame *get_root_frame(Frame *frame) | |
| 380 | { | ||
| 381 | 11 | BUG_ON(!frame); | |
| 382 |
1/2✗ Branch 4 → 4 not taken.
✓ Branch 4 → 5 taken 11 times.
|
11 | while (frame->parent) { |
| 383 | frame = frame->parent; | ||
| 384 | } | ||
| 385 | 11 | return frame; | |
| 386 | } | ||
| 387 | |||
| 388 | 11 | void update_window_coordinates(Frame *frame) | |
| 389 | { | ||
| 390 | 11 | update_frame_coordinates(get_root_frame(frame), 0, 0); | |
| 391 | 11 | } | |
| 392 | |||
| 393 | 2 | Frame *frame_split(Window *window, bool vertical, bool before) | |
| 394 | { | ||
| 395 | 2 | Frame *frame = window->frame; | |
| 396 | 2 | Frame *parent = frame->parent; | |
| 397 |
1/4✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
|
2 | if (!parent || parent->vertical != vertical) { |
| 398 | // Reparent window | ||
| 399 | 2 | frame->vertical = vertical; | |
| 400 | 2 | add_frame(frame, window, 0); | |
| 401 | 2 | parent = frame; | |
| 402 | } | ||
| 403 | |||
| 404 | 2 | size_t idx = ptr_array_xindex(&parent->frames, window->frame); | |
| 405 | 2 | idx += before ? 0 : 1; | |
| 406 | 2 | frame = add_frame(parent, new_window(window->editor), idx); | |
| 407 | 2 | parent->equal_size = true; | |
| 408 | |||
| 409 | // Recalculate | ||
| 410 | 2 | frame_set_size(parent, parent->w, parent->h); | |
| 411 | 2 | update_window_coordinates(parent); | |
| 412 | 2 | return frame; | |
| 413 | } | ||
| 414 | |||
| 415 | // Doesn't really split root but adds new frame between root and its contents | ||
| 416 | 1 | Frame *frame_split_root(EditorState *e, bool vertical, bool before) | |
| 417 | { | ||
| 418 | 1 | Frame *old_root = e->root_frame; | |
| 419 | 1 | Frame *new_root = new_frame(); | |
| 420 | 1 | ptr_array_append(&new_root->frames, old_root); | |
| 421 | 1 | old_root->parent = new_root; | |
| 422 | 1 | new_root->vertical = vertical; | |
| 423 | 1 | e->root_frame = new_root; | |
| 424 | |||
| 425 | 1 | Frame *frame = add_frame(new_root, new_window(e), before ? 0 : 1); | |
| 426 | 1 | frame_set_size(new_root, old_root->w, old_root->h); | |
| 427 | 1 | update_window_coordinates(new_root); | |
| 428 | 1 | return frame; | |
| 429 | } | ||
| 430 | |||
| 431 | // NOTE: does not remove frame from frame->parent->frames | ||
| 432 | 14 | static void free_frame(Frame *frame) | |
| 433 | { | ||
| 434 | 14 | frame->parent = NULL; | |
| 435 | 14 | ptr_array_free_cb(&frame->frames, FREE_FUNC(free_frame)); | |
| 436 | |||
| 437 |
2/2✓ Branch 3 → 4 taken 13 times.
✓ Branch 3 → 6 taken 1 time.
|
14 | if (frame->window) { |
| 438 | 13 | window_free(frame->window); | |
| 439 | 13 | frame->window = NULL; | |
| 440 | } | ||
| 441 | |||
| 442 | 14 | free(frame); | |
| 443 | 14 | } | |
| 444 | |||
| 445 | 12 | void frame_remove(EditorState *e, Frame *frame) | |
| 446 | { | ||
| 447 | 12 | Frame *parent = frame->parent; | |
| 448 |
2/2✓ Branch 2 → 3 taken 10 times.
✓ Branch 2 → 5 taken 2 times.
|
12 | if (!parent) { |
| 449 | 10 | free_frame(frame); | |
| 450 | 10 | return; | |
| 451 | } | ||
| 452 | |||
| 453 | 2 | ptr_array_remove(&parent->frames, frame); | |
| 454 | 2 | free_frame(frame); | |
| 455 | |||
| 456 |
1/2✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 14 not taken.
|
2 | if (parent->frames.count == 1) { |
| 457 | // Replace parent with the only child frame | ||
| 458 | 2 | Frame *gp = parent->parent; | |
| 459 | 2 | Frame *c = parent->frames.ptrs[0]; | |
| 460 | 2 | c->parent = gp; | |
| 461 | 2 | c->w = parent->w; | |
| 462 | 2 | c->h = parent->h; | |
| 463 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 11 taken 2 times.
|
2 | if (gp) { |
| 464 | ✗ | size_t idx = ptr_array_xindex(&gp->frames, parent); | |
| 465 | ✗ | gp->frames.ptrs[idx] = c; | |
| 466 | } else { | ||
| 467 | 2 | e->root_frame = c; | |
| 468 | } | ||
| 469 | 2 | ptr_array_free_array(&parent->frames); | |
| 470 | 2 | free(parent); | |
| 471 | 2 | parent = c; | |
| 472 | } | ||
| 473 | |||
| 474 | // Recalculate | ||
| 475 | 2 | frame_set_size(parent, parent->w, parent->h); | |
| 476 | 2 | update_window_coordinates(parent); | |
| 477 | } | ||
| 478 | |||
| 479 | 1 | void dump_frame(const Frame *frame, size_t level, String *str) | |
| 480 | { | ||
| 481 | 1 | sanity_check_frame(frame); | |
| 482 | 1 | string_append_memset(str, ' ', level * 4); | |
| 483 | 1 | string_sprintf(str, "%dx%d", frame->w, frame->h); | |
| 484 | |||
| 485 | 1 | const Window *w = frame->window; | |
| 486 |
1/2✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 11 not taken.
|
1 | if (w) { |
| 487 | 1 | const char *name = buffer_filename(w->view->buffer); | |
| 488 | 1 | string_append_byte(str, '\n'); | |
| 489 | 1 | string_append_memset(str, ' ', (level + 1) * 4); | |
| 490 | 1 | string_sprintf(str, "%d,%d %dx%d %s\n", w->x, w->y, w->w, w->h, name); | |
| 491 | 1 | return; | |
| 492 | } | ||
| 493 | |||
| 494 | ✗ | string_append_cstring(str, frame->vertical ? " V" : " H"); | |
| 495 | ✗ | string_append_cstring(str, frame->equal_size ? "\n" : " !\n"); | |
| 496 | |||
| 497 | ✗ | for (size_t i = 0, n = frame->frames.count; i < n; i++) { | |
| 498 | ✗ | const Frame *c = frame->frames.ptrs[i]; | |
| 499 | ✗ | dump_frame(c, level + 1, str); | |
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | #if DEBUG_ASSERTIONS_ENABLED | ||
| 504 | 10 | void frame_debug(const Frame *frame) | |
| 505 | { | ||
| 506 | 10 | sanity_check_frame(frame); | |
| 507 |
2/2✓ Branch 8 → 4 taken 4 times.
✓ Branch 8 → 9 taken 10 times.
|
14 | for (size_t i = 0, n = frame->frames.count; i < n; i++) { |
| 508 | 4 | const Frame *c = frame->frames.ptrs[i]; | |
| 509 | 4 | BUG_ON(c->parent != frame); | |
| 510 | 4 | frame_debug(c); | |
| 511 | } | ||
| 512 | 10 | } | |
| 513 | #endif | ||
| 514 | |||
| 515 | // NOLINTEND(misc-no-recursion) | ||
| 516 |