1 #include <hikari/workspace.h>
2
3 #include <stdbool.h>
4 #include <stdlib.h>
5
6 #include <wlr/backend.h>
7 #include <wlr/render/wlr_renderer.h>
8 #include <wlr/render/wlr_texture.h>
9 #include <wlr/types/wlr_matrix.h>
10 #ifdef HAVE_XWAYLAND
11 #include <wlr/xwayland.h>
12 #endif
13
14 #include <hikari/color.h>
15 #include <hikari/configuration.h>
16 #include <hikari/group_assign_mode.h>
17 #include <hikari/indicator.h>
18 #include <hikari/indicator_frame.h>
19 #include <hikari/input_grab_mode.h>
20 #include <hikari/layout.h>
21 #include <hikari/mark_assign_mode.h>
22 #include <hikari/mark_select_mode.h>
23 #include <hikari/normal_mode.h>
24 #include <hikari/server.h>
25 #include <hikari/sheet.h>
26 #include <hikari/xdg_view.h>
27 #ifdef HAVE_XWAYLAND
28 #include <hikari/xwayland_unmanaged_view.h>
29 #include <hikari/xwayland_view.h>
30 #endif
31
32 #define FOCUS_GUARD(workspace, view) \
33 struct hikari_view *view = workspace->focus_view; \
34 \
35 if (focus_view == NULL) { \
36 return; \
37 }
38
39 void
hikari_workspace_init(struct hikari_workspace * workspace,struct hikari_output * output)40 hikari_workspace_init(
41 struct hikari_workspace *workspace, struct hikari_output *output)
42 {
43 wl_list_init(&workspace->views);
44 wl_list_init(&hikari_server.visible_groups);
45 workspace->output = output;
46 workspace->focus_view = NULL;
47 workspace->sheets =
48 hikari_calloc(HIKARI_NR_OF_SHEETS, sizeof(struct hikari_sheet));
49
50 for (int i = 0; i < HIKARI_NR_OF_SHEETS; i++) {
51 hikari_sheet_init(&workspace->sheets[i], i, workspace);
52 }
53
54 workspace->alternate_sheet = &workspace->sheets[0];
55 workspace->sheet = &workspace->sheets[1];
56
57 #ifdef HAVE_LAYERSHELL
58 workspace->focus_layer = NULL;
59 #endif
60 }
61
62 void
hikari_workspace_fini(struct hikari_workspace * workspace)63 hikari_workspace_fini(struct hikari_workspace *workspace)
64 {
65 hikari_free(workspace->sheets);
66 }
67
68 #define CYCLE_WORKSPACE(name) \
69 struct hikari_workspace *hikari_workspace_##name( \
70 struct hikari_workspace *workspace) \
71 { \
72 struct hikari_output *output = hikari_output_##name(workspace->output); \
73 \
74 return output->workspace; \
75 }
76
77 CYCLE_WORKSPACE(next)
CYCLE_WORKSPACE(prev)78 CYCLE_WORKSPACE(prev)
79 #undef CYCLE_WORKSPACE
80
81 void
82 hikari_workspace_merge(
83 struct hikari_workspace *workspace, struct hikari_workspace *into)
84 {
85 assert(workspace != NULL);
86 assert(into != NULL);
87
88 #ifndef NDEBUG
89 printf("WORKSPACE MERGE %p INTO %p\n", workspace, into);
90 #endif
91
92 for (int i = 0; i < HIKARI_NR_OF_SHEETS; i++) {
93 struct hikari_sheet *from = &workspace->sheets[i];
94 struct hikari_sheet *to = &into->sheets[i];
95 struct hikari_view *view, *view_temp;
96 wl_list_for_each_reverse_safe (view, view_temp, &from->views, sheet_views) {
97 hikari_view_evacuate(view, to);
98 }
99 }
100
101 #ifdef HAVE_XWAYLAND
102 struct hikari_xwayland_unmanaged_view *unmanaged_xwayland_view,
103 *unmanaged_xwayland_view_temp;
104 wl_list_for_each_reverse_safe (unmanaged_xwayland_view,
105 unmanaged_xwayland_view_temp,
106 &workspace->output->unmanaged_xwayland_views,
107 unmanaged_output_views) {
108 hikari_xwayland_unmanaged_evacuate(unmanaged_xwayland_view, into);
109 }
110 #endif
111 }
112
113 void
hikari_workspace_quit_view(struct hikari_workspace * workspace)114 hikari_workspace_quit_view(struct hikari_workspace *workspace)
115 {
116 struct hikari_view *focus_view = workspace->focus_view;
117
118 #ifdef HAVE_LAYERSHELL
119 struct hikari_layer *focus_layer = workspace->focus_layer;
120
121 if (focus_layer != NULL) {
122 assert(focus_view == NULL);
123 wlr_layer_surface_v1_close(focus_layer->surface);
124 return;
125 }
126 #endif
127
128 if (focus_view != NULL) {
129 #ifdef HAVE_LAYERSHELL
130 assert(focus_layer == NULL);
131 #endif
132
133 hikari_view_quit(focus_view);
134 hikari_server_cursor_focus();
135 }
136 }
137
138 void
hikari_workspace_clear(struct hikari_workspace * workspace)139 hikari_workspace_clear(struct hikari_workspace *workspace)
140 {
141 struct hikari_view *view = NULL, *view_tmp = NULL;
142
143 wl_list_for_each_reverse_safe (
144 view, view_tmp, &(workspace->views), workspace_views) {
145 hikari_view_hide(view);
146 }
147
148 hikari_server_cursor_focus();
149 }
150
151 static void
display_sheet(struct hikari_workspace * workspace,struct hikari_sheet * sheet)152 display_sheet(struct hikari_workspace *workspace, struct hikari_sheet *sheet)
153 {
154 hikari_workspace_clear(workspace);
155
156 if (sheet != workspace->sheet) {
157 workspace->alternate_sheet = workspace->sheet;
158 workspace->sheet = sheet;
159 }
160
161 hikari_sheet_show(&workspace->sheets[0]);
162
163 if (sheet->nr != 0) {
164 hikari_sheet_show(sheet);
165 }
166
167 hikari_server_cursor_focus();
168 }
169
170 #define DISPLAY_SHEET(name, sheet) \
171 void hikari_workspace_display_sheet_##name( \
172 struct hikari_workspace *workspace) \
173 { \
174 display_sheet(workspace, sheet); \
175 }
176
177 DISPLAY_SHEET(0, &workspace->sheets[0])
178 DISPLAY_SHEET(1, &workspace->sheets[1])
179 DISPLAY_SHEET(2, &workspace->sheets[2])
180 DISPLAY_SHEET(3, &workspace->sheets[3])
181 DISPLAY_SHEET(4, &workspace->sheets[4])
182 DISPLAY_SHEET(5, &workspace->sheets[5])
183 DISPLAY_SHEET(6, &workspace->sheets[6])
184 DISPLAY_SHEET(7, &workspace->sheets[7])
185 DISPLAY_SHEET(8, &workspace->sheets[8])
186 DISPLAY_SHEET(9, &workspace->sheets[9])
187 DISPLAY_SHEET(alternate, workspace->alternate_sheet)
188 DISPLAY_SHEET(current, workspace->sheet)
189 DISPLAY_SHEET(next, hikari_sheet_next(workspace->sheet))
190 DISPLAY_SHEET(prev, hikari_sheet_prev(workspace->sheet))
191 #undef DISPLAY_SHEET
192
193 void
hikari_workspace_switch_sheet(struct hikari_workspace * workspace,struct hikari_sheet * sheet)194 hikari_workspace_switch_sheet(
195 struct hikari_workspace *workspace, struct hikari_sheet *sheet)
196 {
197 assert(workspace == sheet->workspace);
198
199 display_sheet(workspace, sheet);
200 }
201
202 void
hikari_workspace_switch_to_next_sheet(struct hikari_workspace * workspace)203 hikari_workspace_switch_to_next_sheet(struct hikari_workspace *workspace)
204 {
205 if (workspace->sheet->nr == 0) {
206 return;
207 }
208
209 uint8_t nr = workspace->sheet->nr == 9 ? 1 : workspace->sheet->nr + 1;
210
211 display_sheet(workspace, &workspace->sheets[nr]);
212 }
213
214 void
hikari_workspace_switch_to_prev_sheet(struct hikari_workspace * workspace)215 hikari_workspace_switch_to_prev_sheet(struct hikari_workspace *workspace)
216 {
217 if (workspace->sheet->nr == 0) {
218 return;
219 }
220
221 uint8_t nr = workspace->sheet->nr == 1 ? 9 : workspace->sheet->nr - 1;
222
223 display_sheet(workspace, &workspace->sheets[nr]);
224 }
225
226 void
hikari_workspace_switch_to_next_inhabited_sheet(struct hikari_workspace * workspace)227 hikari_workspace_switch_to_next_inhabited_sheet(
228 struct hikari_workspace *workspace)
229 {
230 struct hikari_sheet *sheet = hikari_sheet_next_inhabited(workspace->sheet);
231
232 if (sheet == workspace->sheet) {
233 return;
234 }
235
236 display_sheet(workspace, sheet);
237 }
238
239 void
hikari_workspace_switch_to_prev_inhabited_sheet(struct hikari_workspace * workspace)240 hikari_workspace_switch_to_prev_inhabited_sheet(
241 struct hikari_workspace *workspace)
242 {
243 struct hikari_sheet *sheet = hikari_sheet_prev_inhabited(workspace->sheet);
244
245 if (sheet == workspace->sheet) {
246 return;
247 }
248
249 display_sheet(workspace, sheet);
250 }
251
252 #define CYCLE_LAYOUT_VIEW(fallback, link) \
253 \
254 struct hikari_view *hikari_workspace_##fallback##_layout_view( \
255 struct hikari_workspace *workspace) \
256 { \
257 struct hikari_layout *layout = workspace->sheet->layout; \
258 \
259 if (layout == NULL) { \
260 return NULL; \
261 } \
262 \
263 return hikari_layout_##fallback##_view(layout); \
264 } \
265 \
266 struct hikari_view *hikari_workspace_##link##_layout_view( \
267 struct hikari_workspace *workspace) \
268 { \
269 struct hikari_layout *layout = workspace->sheet->layout; \
270 \
271 if (layout == NULL) { \
272 return NULL; \
273 } \
274 \
275 struct hikari_view *focus_view = workspace->focus_view; \
276 \
277 if (focus_view == NULL || !hikari_view_is_tiled(focus_view) || \
278 focus_view->sheet->layout != layout) { \
279 return hikari_layout_##fallback##_view(layout); \
280 } else { \
281 return hikari_tile_##link##_view(focus_view->tile); \
282 } \
283 }
284
CYCLE_LAYOUT_VIEW(first,next)285 CYCLE_LAYOUT_VIEW(first, next)
286 CYCLE_LAYOUT_VIEW(last, prev)
287 #undef CYCLE_LAYOUT_VIEW
288
289 #define CYCLE_GROUP_VIEW(link) \
290 struct hikari_view *hikari_workspace_##link##_group_view( \
291 struct hikari_workspace *workspace) \
292 { \
293 struct hikari_view *focus_view = workspace->focus_view; \
294 if (focus_view == NULL) { \
295 return NULL; \
296 } \
297 \
298 return hikari_group_##link##_view(focus_view->group); \
299 }
300
301 CYCLE_GROUP_VIEW(first)
302 CYCLE_GROUP_VIEW(last)
303 #undef CYCLE_GROUP_VIEW
304
305 #define CYCLE_GROUP_VIEW(name, link) \
306 struct hikari_view *hikari_workspace_##name##_group_view( \
307 struct hikari_workspace *workspace) \
308 { \
309 struct hikari_view *focus_view = workspace->focus_view; \
310 if (focus_view == NULL) { \
311 return NULL; \
312 } \
313 \
314 struct hikari_view *view; \
315 struct hikari_group *group = focus_view->group; \
316 struct wl_list *link = focus_view->visible_group_views.link; \
317 \
318 if (link != &group->visible_views) { \
319 view = wl_container_of( \
320 focus_view->visible_group_views.link, view, visible_group_views); \
321 } else { \
322 view = wl_container_of( \
323 group->visible_views.link, view, visible_group_views); \
324 } \
325 \
326 return view; \
327 }
328
329 CYCLE_GROUP_VIEW(next, prev)
330 CYCLE_GROUP_VIEW(prev, next)
331 #undef CYCLE_GROUP_VIEW
332
333 #define CYCLE_GROUP(name, link) \
334 struct hikari_view *hikari_workspace_##name##_group( \
335 struct hikari_workspace *workspace) \
336 { \
337 if (wl_list_empty(&hikari_server.visible_groups)) { \
338 return NULL; \
339 } \
340 \
341 struct hikari_view *focus_view = workspace->focus_view; \
342 \
343 struct hikari_group *group; \
344 if (focus_view == NULL) { \
345 group = wl_container_of( \
346 hikari_server.visible_groups.link, group, visible_server_groups); \
347 } else { \
348 struct wl_list *link = focus_view->group->visible_server_groups.link; \
349 \
350 if (link != &hikari_server.visible_groups) { \
351 group = wl_container_of(link, group, visible_server_groups); \
352 } else { \
353 group = wl_container_of( \
354 hikari_server.visible_groups.link, group, visible_server_groups); \
355 } \
356 \
357 if (group == focus_view->group) { \
358 return focus_view; \
359 } \
360 } \
361 \
362 struct hikari_view *view = \
363 wl_container_of(group->visible_views.next, view, visible_group_views); \
364 \
365 return view; \
366 }
367
368 CYCLE_GROUP(next, prev)
369 CYCLE_GROUP(prev, next)
370 #undef CYCLE_GROUP
371
372 void
373 hikari_workspace_focus_view(
374 struct hikari_workspace *workspace, struct hikari_view *view)
375 {
376 assert(hikari_server_in_normal_mode());
377
378 struct wlr_seat *seat = hikari_server.seat;
379
380 struct hikari_workspace *current_workspace = hikari_server.workspace;
381 struct hikari_view *focus_view = current_workspace->focus_view;
382
383 if (focus_view != NULL) {
384 if (hikari_server_is_indicating()) {
385 hikari_group_damage(focus_view->group);
386 hikari_indicator_damage(&hikari_server.indicator, focus_view);
387 } else {
388 hikari_view_damage_border(focus_view);
389 }
390 hikari_view_activate(focus_view, false);
391 }
392
393 wlr_seat_keyboard_end_grab(seat);
394 wlr_seat_keyboard_clear_focus(seat);
395 wlr_seat_pointer_clear_focus(seat);
396
397 #ifdef HAVE_LAYERSHELL
398 workspace->focus_layer = NULL;
399 #endif
400
401 if (view != NULL) {
402 assert(!hikari_view_is_hidden(view));
403
404 struct wlr_keyboard *wlr_keyboard = wlr_seat_get_keyboard(seat);
405
406 hikari_view_activate(view, true);
407
408 if (wlr_keyboard != NULL) {
409 wlr_seat_keyboard_notify_enter(seat,
410 view->surface,
411 wlr_keyboard->keycodes,
412 wlr_keyboard->num_keycodes,
413 &wlr_keyboard->modifiers);
414 }
415
416 if (hikari_server_is_indicating()) {
417 if (focus_view == NULL || focus_view->group != view->group) {
418 hikari_group_damage(view->group);
419 }
420 } else {
421 hikari_view_damage_border(view);
422 }
423
424 hikari_indicator_update(&hikari_server.indicator, view);
425 } else {
426 hikari_cursor_reset_image(&hikari_server.cursor);
427 }
428
429 hikari_server.workspace = workspace;
430 workspace->focus_view = view;
431 }
432
433 void
hikari_workspace_raise_view(struct hikari_workspace * workspace)434 hikari_workspace_raise_view(struct hikari_workspace *workspace)
435 {
436 FOCUS_GUARD(workspace, focus_view);
437
438 struct hikari_group *group = focus_view->group;
439 struct hikari_view *first = hikari_group_first_view(group);
440
441 hikari_view_raise(focus_view);
442
443 hikari_view_damage_border(first);
444 hikari_indicator_damage(&hikari_server.indicator, focus_view);
445 }
446
447 void
hikari_workspace_raise_group(struct hikari_workspace * workspace)448 hikari_workspace_raise_group(struct hikari_workspace *workspace)
449 {
450 FOCUS_GUARD(workspace, focus_view);
451
452 hikari_group_raise(focus_view->group, focus_view);
453 hikari_indicator_damage(&hikari_server.indicator, focus_view);
454 }
455
456 void
hikari_workspace_lower_view(struct hikari_workspace * workspace)457 hikari_workspace_lower_view(struct hikari_workspace *workspace)
458 {
459 FOCUS_GUARD(workspace, focus_view);
460
461 hikari_server_unset_cycling();
462
463 hikari_view_lower(focus_view);
464
465 struct hikari_group *group = focus_view->group;
466 struct hikari_view *first = hikari_group_first_view(group);
467
468 hikari_view_damage_border(first);
469
470 hikari_server_cursor_focus();
471 }
472
473 void
hikari_workspace_lower_group(struct hikari_workspace * workspace)474 hikari_workspace_lower_group(struct hikari_workspace *workspace)
475 {
476 FOCUS_GUARD(workspace, focus_view);
477
478 hikari_group_lower(focus_view->group, focus_view);
479 hikari_indicator_damage(&hikari_server.indicator, focus_view);
480
481 hikari_server_cursor_focus();
482 }
483
484 void
hikari_workspace_hide_view(struct hikari_workspace * workspace)485 hikari_workspace_hide_view(struct hikari_workspace *workspace)
486 {
487 FOCUS_GUARD(workspace, focus_view);
488
489 hikari_view_hide(focus_view);
490
491 hikari_server_cursor_focus();
492 }
493
494 void
hikari_workspace_only_view(struct hikari_workspace * workspace)495 hikari_workspace_only_view(struct hikari_workspace *workspace)
496 {
497 FOCUS_GUARD(workspace, focus_view);
498
499 struct hikari_view *view = NULL;
500 struct hikari_view *view_tmp;
501 wl_list_for_each_safe (view, view_tmp, &workspace->views, workspace_views) {
502 if (view != focus_view) {
503 hikari_view_hide(view);
504 }
505 }
506
507 hikari_server_cursor_focus();
508 }
509
510 void
hikari_workspace_move_resize_view(struct hikari_workspace * workspace,int dx,int dy,int dwidth,int dheight)511 hikari_workspace_move_resize_view(
512 struct hikari_workspace *workspace, int dx, int dy, int dwidth, int dheight)
513 {
514 FOCUS_GUARD(workspace, focus_view);
515
516 hikari_server_set_cycling();
517
518 hikari_view_move_resize(focus_view, dx, dy, dwidth, dheight);
519 }
520
521 #define MOVE(pos) \
522 void hikari_workspace_move_view_##pos(struct hikari_workspace *workspace) \
523 { \
524 FOCUS_GUARD(workspace, focus_view); \
525 \
526 hikari_server_set_cycling(); \
527 \
528 hikari_view_move_##pos(focus_view); \
529 }
530
531 MOVE(bottom_left)
MOVE(bottom_middle)532 MOVE(bottom_middle)
533 MOVE(bottom_right)
534 MOVE(center_left)
535 MOVE(center)
536 MOVE(center_right)
537 MOVE(top_left)
538 MOVE(top_middle)
539 MOVE(top_right)
540 #undef MOVE
541
542 void
543 hikari_workspace_snap_view_up(struct hikari_workspace *workspace)
544 {
545 FOCUS_GUARD(workspace, focus_view);
546
547 hikari_server_set_cycling();
548
549 struct wlr_box *view_geometry = hikari_view_geometry(focus_view);
550
551 int border = hikari_configuration->border;
552 int gap = hikari_configuration->gap;
553 int lookahead = view_geometry->y - border - gap;
554 int view_right = view_geometry->x + view_geometry->width;
555 int y;
556
557 bool found = false;
558 struct hikari_view *view = NULL;
559 struct wlr_box *geometry = NULL;
560 wl_list_for_each (view, &workspace->views, workspace_views) {
561 if (view == focus_view) {
562 continue;
563 }
564
565 geometry = hikari_view_geometry(view);
566
567 int right = geometry->x + geometry->width;
568
569 if (geometry->y + geometry->height + border < lookahead &&
570 ((view_right >= geometry->x && geometry->x >= view_geometry->x) ||
571 (right >= view_geometry->x && view_geometry->x >= geometry->x))) {
572 found = true;
573 y = geometry->y + gap + geometry->height + border;
574 break;
575 }
576 }
577
578 if (!found) {
579 struct hikari_output *output = focus_view->output;
580 y = border + output->usable_area.y;
581 }
582
583 hikari_view_move_absolute(focus_view, view_geometry->x, y);
584 }
585
586 void
hikari_workspace_snap_view_down(struct hikari_workspace * workspace)587 hikari_workspace_snap_view_down(struct hikari_workspace *workspace)
588 {
589 FOCUS_GUARD(workspace, focus_view);
590
591 hikari_server_set_cycling();
592
593 struct wlr_box *view_geometry = hikari_view_geometry(focus_view);
594
595 int border = hikari_configuration->border;
596 int gap = hikari_configuration->gap;
597 int lookahead = view_geometry->y + view_geometry->height + border + gap;
598 int view_right = view_geometry->x + view_geometry->width;
599 int y;
600
601 bool found = false;
602 struct hikari_view *view = NULL;
603 struct wlr_box *geometry = NULL;
604 wl_list_for_each (view, &workspace->views, workspace_views) {
605 if (view == focus_view) {
606 continue;
607 }
608
609 geometry = hikari_view_geometry(view);
610
611 int right = geometry->x + geometry->width;
612
613 if (geometry->y > lookahead &&
614 ((view_right >= geometry->x && geometry->x >= view_geometry->x) ||
615 (right >= view_geometry->x && view_geometry->x >= geometry->x))) {
616 found = true;
617 y = geometry->y - gap - border - view_geometry->height;
618 break;
619 }
620 }
621
622 if (!found) {
623 struct hikari_output *output = focus_view->output;
624 y = output->usable_area.y + output->usable_area.height -
625 view_geometry->height - border;
626 }
627
628 hikari_view_move_absolute(focus_view, view_geometry->x, y);
629 }
630
631 void
hikari_workspace_snap_view_left(struct hikari_workspace * workspace)632 hikari_workspace_snap_view_left(struct hikari_workspace *workspace)
633 {
634 FOCUS_GUARD(workspace, focus_view);
635
636 hikari_server_set_cycling();
637
638 struct wlr_box *view_geometry = hikari_view_geometry(focus_view);
639
640 int border = hikari_configuration->border;
641 int gap = hikari_configuration->gap;
642 int lookahead = view_geometry->x - gap - border;
643 int view_bottom = view_geometry->y + view_geometry->height;
644 int x;
645
646 bool found = false;
647 struct hikari_view *view = NULL;
648 struct wlr_box *geometry = NULL;
649 wl_list_for_each (view, &workspace->views, workspace_views) {
650 if (view == focus_view) {
651 continue;
652 }
653
654 geometry = hikari_view_geometry(view);
655
656 int bottom = geometry->y + geometry->height;
657
658 if (geometry->x + geometry->width + border < lookahead &&
659 ((view_bottom >= geometry->y && geometry->y >= view_geometry->y) ||
660 (bottom >= view_geometry->y && view_geometry->y >= geometry->y))) {
661 found = true;
662 x = geometry->x + geometry->width + gap + border;
663 break;
664 }
665 }
666
667 if (!found) {
668 struct hikari_output *output = focus_view->output;
669 x = border + output->usable_area.x;
670 }
671
672 hikari_view_move_absolute(focus_view, x, view_geometry->y);
673 }
674
675 void
hikari_workspace_snap_view_right(struct hikari_workspace * workspace)676 hikari_workspace_snap_view_right(struct hikari_workspace *workspace)
677 {
678 FOCUS_GUARD(workspace, focus_view);
679
680 hikari_server_set_cycling();
681
682 struct wlr_box *view_geometry = hikari_view_geometry(focus_view);
683
684 int border = hikari_configuration->border;
685 int gap = hikari_configuration->gap;
686 int lookahead = view_geometry->x + view_geometry->width + gap + border;
687 int view_bottom = view_geometry->y + view_geometry->height;
688 int x;
689
690 bool found = false;
691 struct hikari_view *view = NULL;
692 struct wlr_box *geometry = NULL;
693 wl_list_for_each (view, &workspace->views, workspace_views) {
694 if (view == focus_view) {
695 continue;
696 }
697
698 geometry = hikari_view_geometry(view);
699
700 int bottom = geometry->y + geometry->height;
701
702 if (geometry->x > lookahead &&
703 ((view_bottom >= geometry->y && geometry->y >= view_geometry->y) ||
704 (bottom >= view_geometry->y && view_geometry->y >= geometry->y))) {
705 found = true;
706 x = geometry->x - gap - view_geometry->width - border;
707 break;
708 }
709 }
710
711 if (!found) {
712 struct hikari_output *output = focus_view->output;
713 x = output->usable_area.x + output->usable_area.width -
714 view_geometry->width - border;
715 }
716
717 hikari_view_move_absolute(focus_view, x, view_geometry->y);
718 }
719
720 static void
pin_to_sheet(struct hikari_workspace * workspace,struct hikari_sheet * sheet)721 pin_to_sheet(struct hikari_workspace *workspace, struct hikari_sheet *sheet)
722 {
723 FOCUS_GUARD(workspace, focus_view);
724
725 hikari_view_pin_to_sheet(focus_view, sheet);
726
727 if (!hikari_view_is_hidden(focus_view)) {
728 struct hikari_output *output = workspace->output;
729
730 hikari_indicator_update_sheet(
731 &hikari_server.indicator, output, focus_view->sheet, focus_view->flags);
732 }
733 }
734
735 #define PIN_TO_SHEET(name, sheet) \
736 void hikari_workspace_pin_view_to_sheet_##name( \
737 struct hikari_workspace *workspace) \
738 { \
739 pin_to_sheet(workspace, sheet); \
740 }
741
742 PIN_TO_SHEET(0, &workspace->sheets[0])
743 PIN_TO_SHEET(1, &workspace->sheets[1])
744 PIN_TO_SHEET(2, &workspace->sheets[2])
745 PIN_TO_SHEET(3, &workspace->sheets[3])
746 PIN_TO_SHEET(4, &workspace->sheets[4])
747 PIN_TO_SHEET(5, &workspace->sheets[5])
748 PIN_TO_SHEET(6, &workspace->sheets[6])
749 PIN_TO_SHEET(7, &workspace->sheets[7])
750 PIN_TO_SHEET(8, &workspace->sheets[8])
751 PIN_TO_SHEET(9, &workspace->sheets[9])
752 PIN_TO_SHEET(alternate, workspace->alternate_sheet)
753 PIN_TO_SHEET(current, workspace->sheet)
754 PIN_TO_SHEET(next, hikari_sheet_next(workspace->sheet))
755 PIN_TO_SHEET(prev, hikari_sheet_prev(workspace->sheet))
756 #undef PIN_TO_SHEET
757
758 #define MAXIMIZE(n) \
759 void hikari_workspace_toggle_view_##n##_maximize( \
760 struct hikari_workspace *workspace) \
761 { \
762 FOCUS_GUARD(workspace, focus_view); \
763 \
764 hikari_view_toggle_##n##_maximize(focus_view); \
765 }
766
MAXIMIZE(full)767 MAXIMIZE(full)
768 MAXIMIZE(vertical)
769 MAXIMIZE(horizontal)
770 #undef MAXIMIZE
771
772 void
773 hikari_workspace_toggle_view_invisible(struct hikari_workspace *workspace)
774 {
775 FOCUS_GUARD(workspace, focus_view);
776
777 hikari_view_toggle_invisible(focus_view);
778
779 struct hikari_output *output = workspace->output;
780 struct hikari_indicator *indicator = &hikari_server.indicator;
781 struct wlr_box *geometry = hikari_view_border_geometry(focus_view);
782
783 if (hikari_server_is_indicating()) {
784 hikari_indicator_damage_sheet(indicator, output, geometry);
785 }
786
787 hikari_indicator_update_sheet(
788 indicator, output, focus_view->sheet, focus_view->flags);
789
790 if (hikari_server_is_indicating()) {
791 hikari_indicator_damage_sheet(indicator, output, geometry);
792 }
793 }
794
795 void
hikari_workspace_toggle_view_public(struct hikari_workspace * workspace)796 hikari_workspace_toggle_view_public(struct hikari_workspace *workspace)
797 {
798 FOCUS_GUARD(workspace, focus_view);
799
800 hikari_view_toggle_public(focus_view);
801
802 struct hikari_output *output = workspace->output;
803 struct hikari_indicator *indicator = &hikari_server.indicator;
804 struct wlr_box *geometry = hikari_view_border_geometry(focus_view);
805
806 if (hikari_server_is_indicating()) {
807 hikari_indicator_damage_sheet(indicator, output, geometry);
808 }
809
810 hikari_indicator_update_sheet(
811 indicator, output, focus_view->sheet, focus_view->flags);
812
813 if (hikari_server_is_indicating()) {
814 hikari_indicator_damage_sheet(indicator, output, geometry);
815 }
816 }
817
818 void
hikari_workspace_toggle_view_floating(struct hikari_workspace * workspace)819 hikari_workspace_toggle_view_floating(struct hikari_workspace *workspace)
820 {
821 FOCUS_GUARD(workspace, focus_view);
822
823 hikari_view_toggle_floating(focus_view);
824
825 struct hikari_output *output = workspace->output;
826 struct hikari_indicator *indicator = &hikari_server.indicator;
827 struct wlr_box *geometry = hikari_view_border_geometry(focus_view);
828
829 if (hikari_server_is_indicating()) {
830 hikari_indicator_damage_sheet(indicator, output, geometry);
831 }
832
833 hikari_indicator_update_sheet(
834 indicator, output, focus_view->sheet, focus_view->flags);
835
836 if (hikari_server_is_indicating()) {
837 hikari_indicator_damage_sheet(indicator, output, geometry);
838 }
839 }
840
841 void
hikari_workspace_show_invisible_sheet_views(struct hikari_workspace * workspace)842 hikari_workspace_show_invisible_sheet_views(struct hikari_workspace *workspace)
843 {
844 hikari_workspace_clear(workspace);
845 hikari_sheet_show_invisible(workspace->sheet);
846 hikari_server_cursor_focus();
847 }
848
849 void
hikari_workspace_reset_view_geometry(struct hikari_workspace * workspace)850 hikari_workspace_reset_view_geometry(struct hikari_workspace *workspace)
851 {
852 FOCUS_GUARD(workspace, focus_view);
853
854 hikari_view_reset_geometry(focus_view);
855 }
856
857 #define VIEW_EXCHANGE(link) \
858 void hikari_workspace_exchange_##link##_view( \
859 struct hikari_workspace *workspace) \
860 { \
861 struct hikari_view *focus_view = workspace->focus_view; \
862 struct hikari_layout *layout = workspace->sheet->layout; \
863 \
864 if (focus_view == NULL || layout == NULL || \
865 !hikari_view_is_tiled(focus_view)) { \
866 return; \
867 } \
868 \
869 struct hikari_view *link = hikari_tile_##link##_view(focus_view->tile); \
870 \
871 assert(!hikari_view_is_hidden(link)); \
872 \
873 if (focus_view == link) { \
874 return; \
875 } \
876 \
877 hikari_view_exchange(focus_view, link); \
878 }
879
880 VIEW_EXCHANGE(prev)
VIEW_EXCHANGE(next)881 VIEW_EXCHANGE(next)
882 #undef VIEW_EXCHANGE
883
884 void
885 hikari_workspace_exchange_main_layout_view(struct hikari_workspace *workspace)
886 {
887 struct hikari_view *focus_view = workspace->focus_view;
888 struct hikari_layout *layout = workspace->sheet->layout;
889
890 if (focus_view == NULL || layout == NULL ||
891 !hikari_view_is_tiled(focus_view) || hikari_view_is_dirty(focus_view)) {
892 return;
893 }
894
895 struct hikari_view *first = hikari_layout_first_view(layout);
896
897 if (focus_view == first || hikari_view_is_hidden(first) ||
898 hikari_view_is_dirty(first)) {
899 return;
900 }
901
902 hikari_view_exchange(focus_view, first);
903 hikari_view_center_cursor(first);
904 }
905
906 void
hikari_workspace_only_group(struct hikari_workspace * workspace)907 hikari_workspace_only_group(struct hikari_workspace *workspace)
908 {
909 FOCUS_GUARD(workspace, focus_view);
910
911 struct hikari_group *group = focus_view->group;
912
913 struct hikari_view *view = NULL, *view_temp = NULL;
914 wl_list_for_each_safe (view, view_temp, &workspace->views, workspace_views) {
915 if (view->group != group) {
916 hikari_view_hide(view);
917 }
918 }
919 }
920
921 void
hikari_workspace_sheet_show_group(struct hikari_workspace * workspace)922 hikari_workspace_sheet_show_group(struct hikari_workspace *workspace)
923 {
924 FOCUS_GUARD(workspace, focus_view);
925
926 struct hikari_group *group = focus_view->group;
927 hikari_view_raise(focus_view);
928 hikari_workspace_clear(workspace);
929 hikari_sheet_show_group(workspace->sheet, group);
930 hikari_server_cursor_focus();
931 }
932
933 void
hikari_workspace_show_group(struct hikari_workspace * workspace)934 hikari_workspace_show_group(struct hikari_workspace *workspace)
935 {
936 FOCUS_GUARD(workspace, focus_view);
937
938 struct hikari_group *group = focus_view->group;
939 hikari_workspace_clear(workspace);
940 hikari_group_show(group);
941 hikari_server_cursor_focus();
942 }
943
944 #define SHOW_VIEWS(cond) \
945 { \
946 struct hikari_view *view, *view_temp, *top = NULL; \
947 wl_list_for_each_reverse_safe ( \
948 view, view_temp, &workspace->output->views, output_views) { \
949 if (cond) { \
950 if (top == view) { \
951 break; \
952 } \
953 \
954 if (top == NULL) { \
955 top = view; \
956 } \
957 \
958 hikari_view_show(view); \
959 } \
960 } \
961 }
962
963 void
hikari_workspace_show_all(struct hikari_workspace * workspace)964 hikari_workspace_show_all(struct hikari_workspace *workspace)
965 {
966 hikari_workspace_clear(workspace);
967 SHOW_VIEWS(true);
968 hikari_server_cursor_focus();
969 }
970
971 void
hikari_workspace_show_invisible(struct hikari_workspace * workspace)972 hikari_workspace_show_invisible(struct hikari_workspace *workspace)
973 {
974 hikari_workspace_clear(workspace);
975 SHOW_VIEWS(hikari_view_is_invisible(view));
976 hikari_server_cursor_focus();
977 }
978 #undef SHOW_VIEWS
979
980 void
hikari_workspace_hide_group(struct hikari_workspace * workspace)981 hikari_workspace_hide_group(struct hikari_workspace *workspace)
982 {
983 FOCUS_GUARD(workspace, focus_view);
984
985 struct hikari_group *group = focus_view->group;
986 hikari_group_hide(group);
987 hikari_server_cursor_focus();
988 }
989
990 void
hikari_workspace_show_all_sheet_views(struct hikari_workspace * workspace)991 hikari_workspace_show_all_sheet_views(struct hikari_workspace *workspace)
992 {
993 struct hikari_sheet *sheet = workspace->sheet;
994
995 hikari_workspace_clear(workspace);
996 hikari_sheet_show_all(sheet);
997 hikari_server_cursor_focus();
998 }
999
1000 void
hikari_workspace_apply_split(struct hikari_workspace * workspace,struct hikari_split * split)1001 hikari_workspace_apply_split(
1002 struct hikari_workspace *workspace, struct hikari_split *split)
1003 {
1004 assert(workspace != NULL);
1005 assert(split != NULL);
1006
1007 struct hikari_view *focus_view = workspace->focus_view;
1008 struct hikari_sheet *sheet = workspace->sheet;
1009
1010 if (focus_view != NULL && focus_view->sheet == sheet &&
1011 hikari_view_is_tileable(focus_view)) {
1012 hikari_view_raise(focus_view);
1013
1014 assert(focus_view == hikari_sheet_first_tileable_view(sheet));
1015 }
1016
1017 hikari_workspace_display_sheet_current(workspace);
1018 hikari_sheet_apply_split(sheet, split);
1019 }
1020
1021 void
hikari_workspace_center_cursor(struct hikari_workspace * workspace)1022 hikari_workspace_center_cursor(struct hikari_workspace *workspace)
1023 {
1024 struct hikari_output *output = workspace->output;
1025 hikari_cursor_center(&hikari_server.cursor, output, &output->usable_area);
1026 }
1027
1028 struct hikari_view *
hikari_workspace_first_view(struct hikari_workspace * workspace)1029 hikari_workspace_first_view(struct hikari_workspace *workspace)
1030 {
1031 assert(workspace != NULL);
1032
1033 struct hikari_view *view;
1034 if (workspace->focus_view != NULL) {
1035 view = workspace->focus_view;
1036 } else {
1037 view = hikari_sheet_first_view(workspace->sheet);
1038 }
1039
1040 return view;
1041 }
1042 #undef FOCUS_GUARD
1043