1 #include <hikari/sheet.h>
2
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 #include <hikari/configuration.h>
7 #include <hikari/group.h>
8 #include <hikari/layout.h>
9 #include <hikari/memory.h>
10 #include <hikari/split.h>
11 #include <hikari/view.h>
12
13 void
hikari_sheet_init(struct hikari_sheet * sheet,int nr,struct hikari_workspace * workspace)14 hikari_sheet_init(
15 struct hikari_sheet *sheet, int nr, struct hikari_workspace *workspace)
16 {
17 assert(workspace->output != NULL);
18
19 wl_list_init(&sheet->views);
20
21 sheet->nr = nr;
22
23 sheet->workspace = workspace;
24 sheet->layout = NULL;
25 }
26
27 static struct hikari_view *
scan_next_tileable_view(struct hikari_view * view)28 scan_next_tileable_view(struct hikari_view *view)
29 {
30 assert(view != NULL);
31
32 struct wl_list *next = view->sheet_views.next;
33
34 while (next != &view->sheet->views) {
35 view = wl_container_of(next, view, sheet_views);
36 if (hikari_view_is_tileable(view)) {
37 assert(!hikari_view_is_hidden(view));
38 return view;
39 }
40 next = view->sheet_views.next;
41 }
42
43 return NULL;
44 }
45
46 struct hikari_view *
hikari_sheet_first_tileable_view(struct hikari_sheet * sheet)47 hikari_sheet_first_tileable_view(struct hikari_sheet *sheet)
48 {
49 assert(sheet != NULL);
50
51 struct wl_list *next = sheet->views.next;
52 struct hikari_view *view = NULL;
53
54 while (next != &sheet->views) {
55 view = wl_container_of(next, view, sheet_views);
56 if (hikari_view_is_tileable(view)) {
57 if (hikari_view_is_hidden(view)) {
58 hikari_view_show(view);
59 }
60 return view;
61 }
62 next = view->sheet_views.next;
63 }
64
65 return NULL;
66 }
67
68 static int
tileable_views(struct hikari_view * view)69 tileable_views(struct hikari_view *view)
70 {
71 int result;
72 if (hikari_view_is_tileable(view)) {
73 result = 1;
74 } else {
75 result = 0;
76 }
77
78 struct wl_list *next = view->sheet_views.next;
79
80 while (next != &view->sheet->views) {
81 view = wl_container_of(next, view, sheet_views);
82 if (hikari_view_is_tileable(view)) {
83 result++;
84 }
85 next = view->sheet_views.next;
86 }
87
88 return result;
89 }
90
91 static struct hikari_view *
single_layout(struct wlr_box * frame,struct hikari_view * first,int nr_of_views,bool * center)92 single_layout(struct wlr_box *frame,
93 struct hikari_view *first,
94 int nr_of_views,
95 bool *center)
96 {
97 hikari_view_tile(first, frame, *center);
98 *center = false;
99 return scan_next_tileable_view(first);
100 }
101
102 static struct hikari_view *
empty_layout(struct wlr_box * frame,struct hikari_view * first,int nr_of_views,bool * center)103 empty_layout(struct wlr_box *frame,
104 struct hikari_view *first,
105 int nr_of_views,
106 bool *center)
107 {
108 return first;
109 }
110
111 static struct hikari_view *
full_layout(struct wlr_box * frame,struct hikari_view * first,int nr_of_views,bool * center)112 full_layout(struct wlr_box *frame,
113 struct hikari_view *first,
114 int nr_of_views,
115 bool *center)
116 {
117 struct hikari_view *view = first;
118 for (int i = 0; i < nr_of_views && view != NULL; i++) {
119 if (hikari_view_is_tileable(view)) {
120 if (hikari_view_is_hidden(view)) {
121 hikari_view_show(view);
122 }
123 hikari_view_tile(view, frame, *center);
124 *center = false;
125 }
126 view = scan_next_tileable_view(view);
127 }
128
129 return view;
130 }
131
132 #define LAYOUT_VIEWS(nr_of_views, view, frame, center) \
133 if (nr_of_views == 0) { \
134 return NULL; \
135 } else if (nr_of_views == 1) { \
136 hikari_view_tile(view, frame, *center); \
137 *center = false; \
138 } else
139
140 static struct hikari_view *
grid_layout(struct wlr_box * frame,struct hikari_view * first,int nr_of_views,bool * center)141 grid_layout(struct wlr_box *frame,
142 struct hikari_view *first,
143 int nr_of_views,
144 bool *center)
145 {
146 int nr_of_rows = 1;
147 int nr_of_cols = 1;
148
149 for (int i = 1; i <= nr_of_views; i++) {
150 if (i > nr_of_rows * nr_of_cols) {
151 if (nr_of_cols > nr_of_rows) {
152 assert(nr_of_cols == nr_of_rows + 1);
153 nr_of_rows++;
154 } else {
155 nr_of_cols++;
156 }
157 }
158 }
159
160 struct hikari_view *view = first;
161 LAYOUT_VIEWS(nr_of_views, first, frame, center)
162 {
163 int border_width = hikari_configuration->border;
164 int gap = hikari_configuration->gap;
165 int border = 2 * border_width;
166 int row_gaps = nr_of_rows - 1;
167 int col_gaps = nr_of_cols - 1;
168 int gaps_height = gap * row_gaps;
169 int gaps_width = gap * col_gaps;
170 int views_height = frame->height - border * nr_of_rows - gaps_height;
171 int views_width = frame->width - border * nr_of_cols - gaps_width;
172
173 int width = views_width / nr_of_cols;
174 int height = views_height / nr_of_rows;
175
176 int rest_width =
177 frame->width - border * col_gaps - gaps_width - width * nr_of_cols;
178
179 int rest_height =
180 frame->height - border * row_gaps - gaps_height - height * nr_of_rows;
181
182 struct wlr_box geometry = { .y = frame->y, .x = frame->x };
183
184 geometry.height = height + rest_height;
185 for (int g_y = 0; g_y < nr_of_rows; g_y++) {
186 if (g_y == 1) {
187 geometry.height = height;
188 }
189 geometry.width = width + rest_width;
190 for (int g_x = 0; g_x < nr_of_cols; g_x++) {
191 if (g_x == 1) {
192 geometry.width = width;
193 }
194 hikari_view_tile(view, &geometry, *center);
195 *center = false;
196
197 view = scan_next_tileable_view(view);
198 if (view == NULL) {
199 return NULL;
200 }
201
202 geometry.x += gap + border + geometry.width;
203 }
204 geometry.x = frame->x;
205 geometry.y += gap + border + geometry.height;
206 }
207 }
208
209 return scan_next_tileable_view(view);
210 }
211
212 #define SPLIT_LAYOUT(name, x, y, width, height) \
213 static struct hikari_view *name##_layout(struct wlr_box *frame, \
214 struct hikari_view *first, \
215 int nr_of_views, \
216 bool *center) \
217 { \
218 struct hikari_view *view = first; \
219 int border_width = hikari_configuration->border; \
220 int gap = hikari_configuration->gap; \
221 int border = 2 * border_width; \
222 int gaps = nr_of_views - 1; \
223 int gaps_##width = gap * gaps; \
224 \
225 LAYOUT_VIEWS(nr_of_views, first, frame, center) \
226 { \
227 int views_width = frame->width - border * gaps - gaps_##width; \
228 int width = views_width / nr_of_views; \
229 int rest = views_width - width * nr_of_views; \
230 \
231 struct wlr_box geometry = { .x = frame->x, \
232 .y = frame->y, \
233 .width = width + rest, \
234 .height = frame->height }; \
235 \
236 hikari_view_tile(first, &geometry, *center); \
237 *center = false; \
238 \
239 geometry.x += gap + border + width + rest; \
240 geometry.width = width; \
241 for (int n = 1; n < nr_of_views; n++) { \
242 view = scan_next_tileable_view(view); \
243 hikari_view_tile(view, &geometry, *center); \
244 *center = false; \
245 geometry.x += gap + border + width; \
246 } \
247 } \
248 \
249 return scan_next_tileable_view(view); \
250 }
251
SPLIT_LAYOUT(queue,x,y,width,height)252 SPLIT_LAYOUT(queue, x, y, width, height)
253 SPLIT_LAYOUT(stack, y, x, height, width)
254 #undef SPLIT_LAYOUT
255
256 #define LAYOUT(name) \
257 struct hikari_view *hikari_sheet_##name##_layout(struct hikari_sheet *sheet, \
258 struct hikari_view *first, \
259 struct wlr_box *frame, \
260 int max, \
261 bool *center) \
262 { \
263 int nr_of_views = tileable_views(first); \
264 if (nr_of_views > max) { \
265 nr_of_views = max; \
266 } \
267 if (nr_of_views == 0 && max != 0) { \
268 return NULL; \
269 } \
270 \
271 return name##_layout(frame, first, nr_of_views, center); \
272 }
273
274 LAYOUT(queue)
275 LAYOUT(stack)
276 LAYOUT(grid)
277 LAYOUT(full)
278 LAYOUT(single)
279 LAYOUT(empty)
280 #undef LAYOUT
281
282 #undef LAYOUT_WINDOWS
283
284 #define SHEET_VIEW(name, link) \
285 struct hikari_view *hikari_sheet_##name##_view(struct hikari_sheet *sheet) \
286 { \
287 struct wl_list *link = sheet->views.link; \
288 struct hikari_view *view; \
289 \
290 while (link != &sheet->views) { \
291 view = wl_container_of(link, view, sheet_views); \
292 if (!hikari_view_is_hidden(view)) { \
293 return view; \
294 } \
295 link = view->sheet_views.link; \
296 } \
297 \
298 return NULL; \
299 }
300
301 SHEET_VIEW(first, next)
302 SHEET_VIEW(last, prev)
303 #undef SHEET_VIEW
304
305 #define SHEET_VIEW(link, fallback) \
306 struct hikari_view *hikari_sheet_##link##_view( \
307 struct hikari_sheet *sheet, struct hikari_view *view) \
308 { \
309 struct wl_list *link = view->sheet_views.link; \
310 \
311 while (link != &view->sheet->views) { \
312 view = wl_container_of(link, view, sheet_views); \
313 if (!hikari_view_is_hidden(view)) { \
314 return view; \
315 } \
316 link = view->sheet_views.link; \
317 } \
318 \
319 return hikari_sheet_##fallback##_view(sheet); \
320 }
321
322 SHEET_VIEW(next, first)
323 SHEET_VIEW(prev, last)
324 #undef SHEET_VIEW
325
326 int
327 hikari_sheet_tileable_views(struct hikari_sheet *sheet)
328 {
329 int nr_of_views = 0;
330
331 struct hikari_view *view;
332 wl_list_for_each (view, &sheet->views, sheet_views) {
333 if (hikari_view_is_tileable(view)) {
334 nr_of_views++;
335 }
336 }
337
338 return nr_of_views;
339 }
340
341 struct hikari_sheet *
hikari_sheet_next(struct hikari_sheet * sheet)342 hikari_sheet_next(struct hikari_sheet *sheet)
343 {
344 struct hikari_sheet *sheets = sheet->workspace->sheets;
345
346 if (sheet->nr == 9) {
347 return &sheets[1];
348 }
349
350 return &sheets[sheet->nr + 1];
351 }
352
353 struct hikari_sheet *
hikari_sheet_prev(struct hikari_sheet * sheet)354 hikari_sheet_prev(struct hikari_sheet *sheet)
355 {
356 struct hikari_sheet *sheets = sheet->workspace->sheets;
357
358 if (sheet->nr == 0 || sheet->nr == 1) {
359 return &sheets[9];
360 }
361
362 return &sheets[sheet->nr - 1];
363 }
364
365 #define CYCLE_INHABITED(name) \
366 struct hikari_sheet *hikari_sheet_##name##_inhabited( \
367 struct hikari_sheet *sheet) \
368 { \
369 struct hikari_sheet *name = sheet; \
370 \
371 do { \
372 name = hikari_sheet_##name(name); \
373 } while (wl_list_empty(&name->views) && name != sheet); \
374 \
375 return name; \
376 }
377
378 CYCLE_INHABITED(next)
CYCLE_INHABITED(prev)379 CYCLE_INHABITED(prev)
380 #undef CYCLE_INHABITED
381
382 static void
383 raise_floating(struct hikari_sheet *sheet)
384 {
385 struct hikari_view *view, *view_temp, *first = NULL;
386 wl_list_for_each_reverse_safe (view, view_temp, &sheet->views, sheet_views) {
387 if (!hikari_view_is_hidden(view) && hikari_view_is_floating(view)) {
388 if (first == view) {
389 break;
390 } else if (first == NULL) {
391 first = view;
392 }
393
394 hikari_view_raise(view);
395 }
396 }
397 }
398
399 void
hikari_sheet_apply_split(struct hikari_sheet * sheet,struct hikari_split * split)400 hikari_sheet_apply_split(struct hikari_sheet *sheet, struct hikari_split *split)
401 {
402 struct hikari_layout *layout;
403 if (sheet->layout != NULL) {
404 layout = sheet->layout;
405
406 struct hikari_tile *tile;
407 wl_list_for_each (tile, &layout->tiles, layout_tiles) {
408 if (hikari_view_is_dirty(tile->view)) {
409 return;
410 }
411 }
412
413 if (layout->split != split) {
414 hikari_split_free(layout->split);
415 layout->split = hikari_split_copy(split);
416 }
417 } else {
418 layout = hikari_malloc(sizeof(struct hikari_layout));
419 hikari_layout_init(layout, split, sheet);
420
421 sheet->layout = layout;
422 }
423
424 struct hikari_output *output = sheet->workspace->output;
425 struct wlr_box geometry = output->usable_area;
426 struct hikari_view *first = hikari_sheet_first_tileable_view(sheet);
427
428 hikari_split_apply(layout->split, &geometry, first);
429
430 raise_floating(sheet);
431 }
432
433 bool
hikari_sheet_is_visible(struct hikari_sheet * sheet)434 hikari_sheet_is_visible(struct hikari_sheet *sheet)
435 {
436 struct hikari_sheet *sheets = sheet->workspace->sheets;
437
438 return sheet == sheet->workspace->sheet || sheet == &sheets[0];
439 }
440
441 #define SHOW_VIEWS(cond) \
442 { \
443 struct hikari_view *view, *view_temp, *top = NULL; \
444 wl_list_for_each_reverse_safe ( \
445 view, view_temp, &sheet->views, sheet_views) { \
446 if (cond) { \
447 if (top == view) { \
448 break; \
449 } \
450 \
451 if (top == NULL) { \
452 top = view; \
453 } \
454 \
455 hikari_view_show(view); \
456 } \
457 } \
458 }
459
460 void
hikari_sheet_show_all(struct hikari_sheet * sheet)461 hikari_sheet_show_all(struct hikari_sheet *sheet)
462 {
463 SHOW_VIEWS(true);
464 }
465
466 void
hikari_sheet_show(struct hikari_sheet * sheet)467 hikari_sheet_show(struct hikari_sheet *sheet)
468 {
469 SHOW_VIEWS(!hikari_view_is_invisible(view));
470 }
471
472 void
hikari_sheet_show_group(struct hikari_sheet * sheet,struct hikari_group * group)473 hikari_sheet_show_group(struct hikari_sheet *sheet, struct hikari_group *group)
474 {
475 SHOW_VIEWS(view->group == group);
476 }
477
478 void
hikari_sheet_show_invisible(struct hikari_sheet * sheet)479 hikari_sheet_show_invisible(struct hikari_sheet *sheet)
480 {
481 SHOW_VIEWS(hikari_view_is_invisible(view));
482 }
483 #undef SHOW_VIEWS
484