1 #include <hikari/view.h>
2
3 #include <assert.h>
4 #include <string.h>
5
6 #include <wlr/types/wlr_cursor.h>
7
8 #include <hikari/color.h>
9 #include <hikari/configuration.h>
10 #include <hikari/geometry.h>
11 #include <hikari/group.h>
12 #include <hikari/indicator.h>
13 #include <hikari/layout.h>
14 #include <hikari/mark.h>
15 #include <hikari/memory.h>
16 #include <hikari/operation.h>
17 #include <hikari/output.h>
18 #include <hikari/server.h>
19 #include <hikari/sheet.h>
20 #include <hikari/tile.h>
21 #include <hikari/view_config.h>
22 #include <hikari/workspace.h>
23 #include <hikari/xdg_view.h>
24 #include <hikari/xwayland_view.h>
25
26 #define VIEW(name, link) \
27 static struct hikari_view *name##_view(void) \
28 { \
29 struct wl_list *views = hikari_server.visible_views.link; \
30 \
31 if (!wl_list_empty(views)) { \
32 struct hikari_view *view; \
33 view = wl_container_of(views, view, visible_server_views); \
34 return view; \
35 } \
36 \
37 return NULL; \
38 } \
39 \
40 static bool is_##name##_view(struct hikari_view *view) \
41 { \
42 return view == name##_view(); \
43 }
44
VIEW(first,next)45 VIEW(first, next)
46 VIEW(last, prev)
47 #undef VIEW
48
49 static void
50 move_to_top(struct hikari_view *view)
51 {
52 assert(view != NULL);
53 assert(hikari_view_is_mapped(view));
54
55 wl_list_remove(&view->sheet_views);
56 wl_list_insert(&view->sheet->views, &view->sheet_views);
57
58 wl_list_remove(&view->group_views);
59 wl_list_insert(&view->group->views, &view->group_views);
60
61 wl_list_remove(&view->output_views);
62 wl_list_insert(&view->output->views, &view->output_views);
63 }
64
65 static void
place_visibly_above(struct hikari_view * view,struct hikari_workspace * workspace)66 place_visibly_above(
67 struct hikari_view *view, struct hikari_workspace *workspace)
68 {
69 assert(hikari_view_is_forced(view) ? hikari_view_is_hidden(view)
70 : !hikari_view_is_hidden(view));
71
72 wl_list_remove(&view->visible_server_views);
73 wl_list_insert(&hikari_server.visible_views, &view->visible_server_views);
74
75 wl_list_remove(&view->visible_group_views);
76 wl_list_insert(&view->group->visible_views, &view->visible_group_views);
77
78 wl_list_remove(&view->group->visible_server_groups);
79 wl_list_insert(
80 &hikari_server.visible_groups, &view->group->visible_server_groups);
81
82 wl_list_remove(&view->workspace_views);
83 wl_list_insert(&workspace->views, &view->workspace_views);
84 }
85
86 static void
raise_view(struct hikari_view * view)87 raise_view(struct hikari_view *view)
88 {
89 assert(view != NULL);
90
91 move_to_top(view);
92 place_visibly_above(view, view->sheet->workspace);
93 }
94
95 static void
refresh_border_geometry(struct hikari_view * view)96 refresh_border_geometry(struct hikari_view *view)
97 {
98 assert(view != NULL);
99 hikari_border_refresh_geometry(&view->border, view->current_geometry);
100 hikari_indicator_frame_refresh_geometry(&view->indicator_frame, view);
101 }
102
103 static inline void
move_view_constrained(struct hikari_view * view,struct wlr_box * geometry,int x,int y)104 move_view_constrained(
105 struct hikari_view *view, struct wlr_box *geometry, int x, int y)
106 {
107 if (!hikari_view_is_hidden(view)) {
108 hikari_view_damage_whole(view);
109 hikari_indicator_damage(&hikari_server.indicator, view);
110 }
111
112 hikari_geometry_constrain_relative(
113 geometry, &view->output->usable_area, x, y);
114 }
115
116 static void
move_view(struct hikari_view * view,struct wlr_box * geometry,int x,int y)117 move_view(struct hikari_view *view, struct wlr_box *geometry, int x, int y)
118 {
119 if (view->maximized_state != NULL) {
120 struct wlr_box *usable_area;
121
122 switch (view->maximized_state->maximization) {
123 case HIKARI_MAXIMIZATION_FULLY_MAXIMIZED:
124 return;
125
126 case HIKARI_MAXIMIZATION_VERTICALLY_MAXIMIZED:
127 usable_area = &view->output->usable_area;
128
129 if (y != usable_area->y) {
130 return;
131 }
132
133 move_view_constrained(view, geometry, x, y);
134 view->geometry.x = x;
135 break;
136
137 case HIKARI_MAXIMIZATION_HORIZONTALLY_MAXIMIZED:
138 usable_area = &view->output->usable_area;
139
140 if (x != usable_area->x) {
141 return;
142 }
143
144 move_view_constrained(view, geometry, x, y);
145 view->geometry.y = y;
146 break;
147 }
148 } else {
149 move_view_constrained(view, geometry, x, y);
150 }
151
152 #ifdef HAVE_XWAYLAND
153 if (view->move != NULL) {
154 view->move(view, geometry->x, geometry->y);
155 }
156 #endif
157
158 refresh_border_geometry(view);
159
160 if (!hikari_view_is_hidden(view)) {
161 hikari_view_damage_whole(view);
162 hikari_indicator_damage(&hikari_server.indicator, view);
163 }
164 }
165
166 static void
increase_group_visiblity(struct hikari_view * view)167 increase_group_visiblity(struct hikari_view *view)
168 {
169 assert(hikari_view_is_forced(view) ? hikari_view_is_hidden(view)
170 : !hikari_view_is_hidden(view));
171
172 struct hikari_group *group = view->group;
173
174 if (wl_list_empty(&group->visible_views)) {
175 wl_list_insert(
176 &hikari_server.visible_groups, &group->visible_server_groups);
177 }
178
179 wl_list_init(&view->visible_group_views);
180 }
181
182 static void
decrease_group_visibility(struct hikari_view * view)183 decrease_group_visibility(struct hikari_view *view)
184 {
185 struct hikari_group *group = view->group;
186
187 wl_list_remove(&view->visible_group_views);
188
189 if (wl_list_empty(&group->visible_views)) {
190 wl_list_remove(&group->visible_server_groups);
191 }
192 }
193
194 static void
hide(struct hikari_view * view)195 hide(struct hikari_view *view)
196 {
197 decrease_group_visibility(view);
198
199 wl_list_remove(&view->workspace_views);
200 wl_list_init(&view->workspace_views);
201
202 wl_list_remove(&view->visible_server_views);
203 wl_list_init(&view->visible_server_views);
204
205 hikari_view_set_hidden(view);
206 }
207
208 static void
detach_from_group(struct hikari_view * view)209 detach_from_group(struct hikari_view *view)
210 {
211 struct hikari_group *group = view->group;
212
213 wl_list_remove(&view->group_views);
214 wl_list_init(&view->group_views);
215
216 if (wl_list_empty(&group->views)) {
217 hikari_group_fini(group);
218 hikari_free(group);
219 }
220 }
221
222 static void
remove_from_group(struct hikari_view * view)223 remove_from_group(struct hikari_view *view)
224 {
225 assert(!hikari_view_is_hidden(view));
226
227 if (!hikari_view_is_hidden(view)) {
228 decrease_group_visibility(view);
229 }
230
231 detach_from_group(view);
232 }
233
234 static void
cancel_tile(struct hikari_view * view)235 cancel_tile(struct hikari_view *view)
236 {
237 if (hikari_view_is_tiling(view)) {
238 struct hikari_tile *tile = view->pending_operation.tile;
239
240 hikari_tile_detach(tile);
241 hikari_free(tile);
242 view->pending_operation.tile = NULL;
243 }
244 }
245
246 static inline void
guarded_resize(struct hikari_view * view,struct hikari_operation * op,void (* f)(struct hikari_view *,struct hikari_operation *))247 guarded_resize(struct hikari_view *view,
248 struct hikari_operation *op,
249 void (*f)(struct hikari_view *, struct hikari_operation *))
250 {
251 op->serial = view->resize(view, op->geometry.width, op->geometry.height);
252
253 if (op->serial == 0) {
254 f(view, op);
255 } else {
256 hikari_view_set_dirty(view);
257 }
258 }
259
260 static inline void
resize(struct hikari_view * view,struct hikari_operation * op,void (* f)(struct hikari_view *,struct hikari_operation *))261 resize(struct hikari_view *view,
262 struct hikari_operation *op,
263 void (*f)(struct hikari_view *, struct hikari_operation *))
264 {
265 #ifdef HAVE_XWAYLAND
266 if (view->move_resize != NULL) {
267 op->serial = 0;
268 view->move_resize(view,
269 op->geometry.x,
270 op->geometry.y,
271 op->geometry.width,
272 op->geometry.height);
273
274 hikari_view_set_dirty(view);
275 } else {
276 guarded_resize(view, op, f);
277 }
278 #else
279 guarded_resize(view, op, f);
280 #endif
281 }
282
283 static void
commit_pending_geometry(struct hikari_view * view,struct wlr_box * pending_geometry)284 commit_pending_geometry(
285 struct hikari_view *view, struct wlr_box *pending_geometry)
286 {
287 hikari_view_refresh_geometry(view, pending_geometry);
288
289 hikari_indicator_damage(&hikari_server.indicator, view);
290 hikari_view_damage_whole(view);
291 }
292
293 static void
commit_pending_operation(struct hikari_view * view,struct hikari_operation * operation)294 commit_pending_operation(
295 struct hikari_view *view, struct hikari_operation *operation)
296 {
297 if (!hikari_view_is_hidden(view)) {
298 if (!hikari_view_is_forced(view)) {
299 raise_view(view);
300 } else {
301 move_to_top(view);
302 }
303
304 commit_pending_geometry(view, &operation->geometry);
305
306 if (operation->center) {
307 hikari_view_center_cursor(view);
308 hikari_server_cursor_focus();
309 }
310 } else {
311 hikari_view_refresh_geometry(view, &operation->geometry);
312
313 if (hikari_sheet_is_visible(view->sheet)) {
314 if (!hikari_view_is_forced(view)) {
315 hikari_view_show(view);
316 } else {
317 raise_view(view);
318 }
319
320 if (operation->center) {
321 hikari_view_center_cursor(view);
322 hikari_server_cursor_focus();
323 }
324 } else {
325 if (!hikari_view_is_forced(view)) {
326 move_to_top(view);
327 } else {
328 raise_view(view);
329 }
330 }
331 }
332 }
333
334 static void
commit_reset(struct hikari_view * view,struct hikari_operation * operation)335 commit_reset(struct hikari_view *view, struct hikari_operation *operation)
336 {
337 hikari_indicator_damage(&hikari_server.indicator, view);
338
339 if (hikari_view_is_tiled(view)) {
340 assert(!hikari_tile_is_attached(view->tile));
341 hikari_free(view->tile);
342 view->tile = NULL;
343 }
344
345 if (hikari_view_is_maximized(view)) {
346 hikari_maximized_state_destroy(view->maximized_state);
347 view->maximized_state = NULL;
348
349 if (!view->use_csd) {
350 if (view == hikari_server.workspace->focus_view) {
351 view->border.state = HIKARI_BORDER_ACTIVE;
352 } else {
353 view->border.state = HIKARI_BORDER_INACTIVE;
354 }
355 }
356 }
357
358 commit_pending_operation(view, operation);
359 }
360
361 static void
queue_reset(struct hikari_view * view,bool center)362 queue_reset(struct hikari_view *view, bool center)
363 {
364 struct wlr_box *view_geometry = hikari_view_geometry(view);
365 struct hikari_operation *op = &view->pending_operation;
366 struct hikari_tile *tile = view->tile;
367 struct wlr_box *geometry = &view->geometry;
368
369 cancel_tile(view);
370
371 if (hikari_view_is_tiled(view) && hikari_tile_is_attached(tile)) {
372 hikari_tile_detach(tile);
373 }
374
375 op->type = HIKARI_OPERATION_TYPE_RESET;
376 op->center = center;
377 memcpy(&op->geometry, geometry, sizeof(struct wlr_box));
378
379 if (view_geometry->width == geometry->width &&
380 view_geometry->height == geometry->height) {
381 hikari_view_set_dirty(view);
382 hikari_view_commit_pending_operation(view, view_geometry);
383 } else {
384 resize(view, op, commit_reset);
385 }
386
387 assert(
388 hikari_view_is_tiled(view) ? !hikari_tile_is_attached(view->tile) : true);
389 }
390
391 static void
clear_focus(struct hikari_view * view)392 clear_focus(struct hikari_view *view)
393 {
394 if (hikari_view_is_focus_view(view)) {
395 if (hikari_view_has_focus(view)) {
396 assert(!hikari_server_in_lock_mode());
397
398 if (!hikari_server_in_normal_mode()) {
399 hikari_server_enter_normal_mode(NULL);
400 }
401
402 hikari_workspace_focus_view(hikari_server.workspace, NULL);
403 } else {
404 view->sheet->workspace->focus_view = NULL;
405 }
406 }
407 }
408
409 void
hikari_view_init(struct hikari_view * view,bool child,struct hikari_workspace * workspace)410 hikari_view_init(
411 struct hikari_view *view, bool child, struct hikari_workspace *workspace)
412 {
413 #if !defined(NDEBUG)
414 printf("VIEW INIT %p\n", view);
415 #endif
416 view->flags = hikari_view_hidden_flag;
417 view->border.state = HIKARI_BORDER_INACTIVE;
418 view->sheet = NULL;
419 view->mark = NULL;
420 view->surface = NULL;
421 view->maximized_state = NULL;
422 view->output = NULL;
423 view->group = NULL;
424 view->title = NULL;
425 view->tile = NULL;
426 view->id = NULL;
427 view->use_csd = false;
428 view->child = child;
429 view->current_geometry = &view->geometry;
430 view->current_unmaximized_geometry = &view->geometry;
431
432 hikari_view_unset_dirty(view);
433 view->pending_operation.tile = NULL;
434
435 wl_list_init(&view->children);
436 }
437
438 void
hikari_view_fini(struct hikari_view * view)439 hikari_view_fini(struct hikari_view *view)
440 {
441 assert(hikari_view_is_hidden(view));
442 assert(!hikari_view_is_mapped(view));
443 assert(!hikari_view_is_forced(view));
444
445 #if !defined(NDEBUG)
446 printf("DESTROY VIEW %p\n", view);
447 #endif
448
449 hikari_free(view->title);
450 hikari_free(view->id);
451
452 if (view->group != NULL) {
453 detach_from_group(view);
454 }
455
456 if (view->sheet != NULL) {
457 wl_list_remove(&view->sheet_views);
458 wl_list_remove(&view->output_views);
459 }
460
461 if (view->maximized_state != NULL) {
462 hikari_maximized_state_destroy(view->maximized_state);
463 }
464
465 if (view->mark != NULL) {
466 hikari_mark_clear(view->mark);
467 }
468
469 if (hikari_view_is_tiled(view)) {
470 struct hikari_tile *tile = view->tile;
471 hikari_tile_detach(tile);
472 hikari_free(tile);
473 view->tile = NULL;
474 }
475
476 cancel_tile(view);
477 }
478
479 void
hikari_view_set_title(struct hikari_view * view,const char * title)480 hikari_view_set_title(struct hikari_view *view, const char *title)
481 {
482 hikari_free(view->title);
483
484 if (title != NULL) {
485 view->title = hikari_malloc(strlen(title) + 1);
486 strcpy(view->title, title);
487
488 if (hikari_server.workspace->focus_view == view) {
489 assert(!hikari_view_is_hidden(view));
490 struct hikari_output *output = view->output;
491 hikari_indicator_update_title(&hikari_server.indicator, output, title);
492 }
493 } else {
494 view->title = NULL;
495 }
496 }
497
498 static void
set_app_id(struct hikari_view * view,const char * id)499 set_app_id(struct hikari_view *view, const char *id)
500 {
501 assert(view->id == NULL);
502 assert(id != NULL);
503
504 view->id = hikari_malloc(strlen(id) + 1);
505
506 strcpy(view->id, id);
507 }
508
509 struct hikari_damage_data {
510 struct wlr_box *geometry;
511 struct wlr_surface *surface;
512
513 struct hikari_view *view;
514 struct hikari_output *output;
515
516 bool whole;
517 };
518
519 static void
damage_whole_surface(struct wlr_surface * surface,int sx,int sy,void * data)520 damage_whole_surface(struct wlr_surface *surface, int sx, int sy, void *data)
521 {
522 struct hikari_damage_data *damage_data = data;
523 struct hikari_output *output = damage_data->output;
524 struct hikari_view *view = damage_data->view;
525
526 if (view->surface == surface) {
527 hikari_view_damage_border(view);
528 } else {
529 struct wlr_box geometry;
530 memcpy(&geometry, damage_data->geometry, sizeof(struct wlr_box));
531
532 geometry.x += sx;
533 geometry.y += sy;
534 geometry.width = surface->current.width;
535 geometry.height = surface->current.height;
536
537 hikari_output_add_damage(output, &geometry);
538 }
539 }
540
541 void
hikari_view_damage_whole(struct hikari_view * view)542 hikari_view_damage_whole(struct hikari_view *view)
543 {
544 assert(view != NULL);
545
546 struct hikari_output *output = view->output;
547
548 // TODO I know, this needs to be done A LOT better
549 if (view->use_csd) {
550 hikari_output_damage_whole(output);
551 return;
552 }
553
554 struct hikari_damage_data damage_data;
555
556 damage_data.geometry = hikari_view_geometry(view);
557 damage_data.output = output;
558 damage_data.view = view;
559
560 hikari_node_for_each_surface(
561 (struct hikari_node *)view, damage_whole_surface, &damage_data);
562 }
563
564 static struct wlr_box *
refresh_unmaximized_geometry(struct hikari_view * view)565 refresh_unmaximized_geometry(struct hikari_view *view)
566 {
567 assert(view != NULL);
568
569 if (hikari_view_is_tiled(view)) {
570 return &view->tile->view_geometry;
571 } else {
572 return &view->geometry;
573 }
574 }
575
576 static struct wlr_box *
refresh_geometry(struct hikari_view * view)577 refresh_geometry(struct hikari_view *view)
578 {
579 assert(view != NULL);
580
581 if (view->maximized_state != NULL) {
582 return &view->maximized_state->geometry;
583 } else {
584 return refresh_unmaximized_geometry(view);
585 }
586 }
587
588 static inline int
constrain_size(int min,int max,int value)589 constrain_size(int min, int max, int value)
590 {
591 if (value > max) {
592 return max;
593 } else if (value < min) {
594 return min;
595 } else {
596 return value;
597 }
598 }
599
600 static void
commit_resize(struct hikari_view * view,struct hikari_operation * operation)601 commit_resize(struct hikari_view *view, struct hikari_operation *operation)
602 {
603 commit_pending_operation(view, operation);
604 }
605
606 static void
queue_resize(struct hikari_view * view,struct wlr_box * geometry,int requested_x,int requested_y,int requested_width,int requested_height)607 queue_resize(struct hikari_view *view,
608 struct wlr_box *geometry,
609 int requested_x,
610 int requested_y,
611 int requested_width,
612 int requested_height)
613 {
614 struct hikari_operation *op = &view->pending_operation;
615
616 int min_width;
617 int min_height;
618 int max_width;
619 int max_height;
620
621 int new_width;
622 int new_height;
623
624 if (view->maximized_state != NULL) {
625 switch (view->maximized_state->maximization) {
626 case HIKARI_MAXIMIZATION_FULLY_MAXIMIZED:
627 return;
628
629 case HIKARI_MAXIMIZATION_VERTICALLY_MAXIMIZED:
630 view->constraints(
631 view, &min_width, &min_height, &max_width, &max_height);
632 new_width = constrain_size(min_width, max_width, requested_width);
633 new_height = geometry->height;
634 view->geometry.width = new_width;
635 break;
636
637 case HIKARI_MAXIMIZATION_HORIZONTALLY_MAXIMIZED:
638 view->constraints(
639 view, &min_width, &min_height, &max_width, &max_height);
640 new_width = geometry->width;
641 new_height = constrain_size(min_height, max_height, requested_height);
642 view->geometry.height = new_height;
643 break;
644 }
645 } else {
646 view->constraints(view, &min_width, &min_height, &max_width, &max_height);
647 new_width = constrain_size(min_width, max_width, requested_width);
648 new_height = constrain_size(min_height, max_height, requested_height);
649 }
650
651 struct hikari_output *output = view->output;
652
653 op->type = HIKARI_OPERATION_TYPE_RESIZE;
654 op->geometry.width = new_width;
655 op->geometry.height = new_height;
656 op->center = false;
657
658 hikari_geometry_constrain_relative(
659 &op->geometry, &output->usable_area, requested_x, requested_y);
660
661 resize(view, op, commit_resize);
662 }
663
664 void
hikari_view_resize(struct hikari_view * view,int dwidth,int dheight)665 hikari_view_resize(struct hikari_view *view, int dwidth, int dheight)
666 {
667 assert(view != NULL);
668 assert(view->resize != NULL);
669 assert(view->constraints != NULL);
670
671 if (hikari_view_is_dirty(view)) {
672 return;
673 }
674
675 struct wlr_box *geometry = hikari_view_geometry(view);
676
677 int requested_width = geometry->width + dwidth;
678 int requested_height = geometry->height + dheight;
679
680 queue_resize(view,
681 geometry,
682 geometry->x,
683 geometry->y,
684 requested_width,
685 requested_height);
686 }
687
688 void
hikari_view_resize_absolute(struct hikari_view * view,int width,int height)689 hikari_view_resize_absolute(struct hikari_view *view, int width, int height)
690 {
691 assert(view != NULL);
692 assert(view->resize != NULL);
693 assert(view->constraints != NULL);
694
695 if (hikari_view_is_dirty(view)) {
696 return;
697 }
698
699 struct wlr_box *geometry = hikari_view_geometry(view);
700 queue_resize(view, geometry, geometry->x, geometry->y, width, height);
701 }
702
703 void
hikari_view_move_resize(struct hikari_view * view,int x,int y,int width,int height)704 hikari_view_move_resize(
705 struct hikari_view *view, int x, int y, int width, int height)
706 {
707 assert(view != NULL);
708 assert(view->resize != NULL);
709 assert(view->constraints != NULL);
710
711 if (hikari_view_is_dirty(view)) {
712 return;
713 }
714
715 struct wlr_box *geometry = hikari_view_geometry(view);
716
717 int requested_x = geometry->x + x;
718 int requested_y = geometry->y + y;
719 int requested_width = geometry->width + width;
720 int requested_height = geometry->height + height;
721
722 queue_resize(view,
723 geometry,
724 requested_x,
725 requested_y,
726 requested_width,
727 requested_height);
728 }
729
730 void
hikari_view_move(struct hikari_view * view,int x,int y)731 hikari_view_move(struct hikari_view *view, int x, int y)
732 {
733 assert(view != NULL);
734
735 struct wlr_box *geometry = hikari_view_geometry(view);
736
737 move_view(view, geometry, geometry->x + x, geometry->y + y);
738 }
739
740 void
hikari_view_move_absolute(struct hikari_view * view,int x,int y)741 hikari_view_move_absolute(struct hikari_view *view, int x, int y)
742 {
743 assert(view != NULL);
744
745 struct wlr_box *geometry = hikari_view_geometry(view);
746
747 move_view(view, geometry, x, y);
748 }
749
750 #define MOVE(pos) \
751 void hikari_view_move_##pos(struct hikari_view *view) \
752 { \
753 assert(view != NULL); \
754 \
755 struct hikari_output *output = view->output; \
756 struct wlr_box *usable_area = &output->usable_area; \
757 struct wlr_box *border_geometry = hikari_view_border_geometry(view); \
758 struct wlr_box *geometry = hikari_view_geometry(view); \
759 \
760 int x; \
761 int y; \
762 hikari_geometry_position_##pos(border_geometry, usable_area, &x, &y); \
763 \
764 move_view(view, geometry, x, y); \
765 }
766
767 MOVE(bottom_left)
MOVE(bottom_middle)768 MOVE(bottom_middle)
769 MOVE(bottom_right)
770 MOVE(center_left)
771 MOVE(center)
772 MOVE(center_right)
773 MOVE(top_left)
774 MOVE(top_middle)
775 MOVE(top_right)
776 #undef MOVE
777
778 static void
779 new_subsurface_handler(struct wl_listener *listener, void *data)
780 {
781 struct hikari_view *view = wl_container_of(listener, view, new_subsurface);
782
783 struct wlr_subsurface *wlr_subsurface = data;
784
785 struct hikari_view_subsurface *view_subsurface =
786 hikari_malloc(sizeof(struct hikari_view_subsurface));
787
788 hikari_view_subsurface_init(view_subsurface, view, wlr_subsurface);
789 }
790
791 void
hikari_view_map(struct hikari_view * view,struct wlr_surface * surface)792 hikari_view_map(struct hikari_view *view, struct wlr_surface *surface)
793 {
794 assert(hikari_view_is_hidden(view));
795 assert(!hikari_view_is_unmanaged(view));
796 assert(!hikari_view_is_mapped(view));
797
798 struct hikari_sheet *sheet = view->sheet;
799 struct hikari_output *output = view->output;
800 struct hikari_group *group;
801 bool focus;
802
803 struct hikari_view_config *view_config =
804 hikari_configuration_resolve_view_config(hikari_configuration, view->id);
805
806 view->surface = surface;
807
808 view->new_subsurface.notify = new_subsurface_handler;
809 wl_signal_add(&surface->events.new_subsurface, &view->new_subsurface);
810
811 struct wlr_subsurface *wlr_subsurface;
812 wl_list_for_each (wlr_subsurface, &surface->subsurfaces, parent_link) {
813 struct hikari_view_subsurface *subsurface =
814 (struct hikari_view_subsurface *)malloc(
815 sizeof(struct hikari_view_subsurface));
816 hikari_view_subsurface_init(subsurface, view, wlr_subsurface);
817 }
818
819 if (view_config != NULL) {
820 struct hikari_mark *mark;
821 struct hikari_view_properties *properties =
822 hikari_view_config_resolve_properties(view_config, view->child);
823
824 assert(properties != NULL);
825
826 group = hikari_view_properties_resolve_group(properties, view->id);
827 mark = properties->mark;
828
829 if (mark != NULL && mark->view == NULL) {
830 hikari_mark_set(mark, view);
831 }
832
833 focus = properties->focus;
834 } else {
835 group = hikari_server_find_or_create_group(view->id);
836 focus = false;
837 }
838
839 view->group = group;
840
841 wl_list_insert(&sheet->views, &view->sheet_views);
842 wl_list_insert(&group->views, &view->group_views);
843 wl_list_insert(&output->views, &view->output_views);
844
845 if (!hikari_server_in_lock_mode() || hikari_view_is_public(view)) {
846 hikari_view_show(view);
847
848 if (focus) {
849 hikari_view_center_cursor(view);
850 }
851
852 hikari_server_cursor_focus();
853 } else {
854 hikari_view_set_forced(view);
855 increase_group_visiblity(view);
856 raise_view(view);
857 }
858 }
859
860 void
hikari_view_unmap(struct hikari_view * view)861 hikari_view_unmap(struct hikari_view *view)
862 {
863 assert(!hikari_view_is_unmanaged(view));
864 assert(hikari_view_is_mapped(view));
865
866 wl_list_remove(&view->new_subsurface.link);
867
868 struct hikari_view_child *child, *child_temp;
869 wl_list_for_each_safe (child, child_temp, &view->children, link) {
870 struct hikari_view_subsurface *subsurface =
871 (struct hikari_view_subsurface *)child;
872 hikari_view_subsurface_fini(subsurface);
873 hikari_free(subsurface);
874 }
875
876 if (hikari_view_is_forced(view)) {
877 if (hikari_view_is_hidden(view)) {
878 hide(view);
879 } else {
880 hikari_view_damage_whole(view);
881 hikari_view_set_hidden(view);
882 }
883
884 hikari_view_unset_forced(view);
885 }
886
887 if (!hikari_view_is_hidden(view)) {
888 hikari_view_hide(view);
889 hikari_server_cursor_focus();
890 }
891
892 assert(hikari_view_is_hidden(view));
893 assert(!hikari_view_is_forced(view));
894
895 view->surface = NULL;
896
897 struct hikari_mark *mark = view->mark;
898 if (mark != NULL) {
899 hikari_mark_clear(mark);
900 }
901
902 detach_from_group(view);
903 view->group = NULL;
904
905 cancel_tile(view);
906
907 if (hikari_view_is_tiled(view)) {
908 struct wlr_box geometry;
909 struct hikari_tile *tile = view->tile;
910
911 memcpy(&geometry, hikari_view_geometry(view), sizeof(struct wlr_box));
912
913 if (hikari_tile_is_attached(tile)) {
914 hikari_tile_detach(tile);
915 }
916
917 hikari_free(tile);
918 view->tile = NULL;
919
920 hikari_view_refresh_geometry(view, &geometry);
921 }
922
923 wl_list_remove(&view->sheet_views);
924 wl_list_init(&view->sheet_views);
925
926 wl_list_remove(&view->output_views);
927 wl_list_init(&view->output_views);
928
929 hikari_view_unset_dirty(view);
930
931 assert(!hikari_view_is_tiling(view));
932 assert(!hikari_view_is_tiled(view));
933 }
934
935 void
hikari_view_show(struct hikari_view * view)936 hikari_view_show(struct hikari_view *view)
937 {
938 assert(view != NULL);
939 assert(hikari_view_is_hidden(view));
940 assert(!hikari_view_is_forced(view));
941
942 #if !defined(NDEBUG)
943 printf("SHOW %p\n", view);
944 #endif
945 hikari_view_unset_hidden(view);
946
947 increase_group_visiblity(view);
948
949 raise_view(view);
950
951 hikari_view_damage_whole(view);
952
953 assert(is_first_view(view));
954 }
955
956 void
hikari_view_hide(struct hikari_view * view)957 hikari_view_hide(struct hikari_view *view)
958 {
959 assert(view != NULL);
960 assert(!hikari_view_is_hidden(view));
961 assert(!hikari_view_is_forced(view));
962
963 #if !defined(NDEBUG)
964 printf("HIDE %p\n", view);
965 #endif
966
967 clear_focus(view);
968 hide(view);
969
970 hikari_view_damage_whole(view);
971 }
972
973 void
hikari_view_raise(struct hikari_view * view)974 hikari_view_raise(struct hikari_view *view)
975 {
976 assert(view != NULL);
977 assert(!hikari_view_is_hidden(view));
978
979 if (is_first_view(view)) {
980 return;
981 }
982
983 raise_view(view);
984 hikari_view_damage_whole(view);
985 }
986
987 void
hikari_view_lower(struct hikari_view * view)988 hikari_view_lower(struct hikari_view *view)
989 {
990 assert(view != NULL);
991 assert(!hikari_view_is_hidden(view));
992
993 if (is_last_view(view)) {
994 return;
995 }
996
997 wl_list_remove(&view->sheet_views);
998 wl_list_insert(view->sheet->views.prev, &view->sheet_views);
999
1000 wl_list_remove(&view->group_views);
1001 wl_list_insert(view->group->views.prev, &view->group_views);
1002
1003 wl_list_remove(&view->output_views);
1004 wl_list_insert(view->output->views.prev, &view->output_views);
1005
1006 wl_list_remove(&view->visible_group_views);
1007 wl_list_insert(view->group->visible_views.prev, &view->visible_group_views);
1008
1009 wl_list_remove(&view->group->visible_server_groups);
1010 wl_list_insert(
1011 hikari_server.visible_groups.prev, &view->group->visible_server_groups);
1012
1013 wl_list_remove(&view->workspace_views);
1014 wl_list_insert(view->sheet->workspace->views.prev, &view->workspace_views);
1015
1016 wl_list_remove(&view->visible_server_views);
1017 wl_list_insert(hikari_server.visible_views.prev, &view->visible_server_views);
1018
1019 hikari_view_damage_whole(view);
1020 }
1021
1022 static void
commit_tile(struct hikari_view * view,struct hikari_operation * operation)1023 commit_tile(struct hikari_view *view, struct hikari_operation *operation)
1024 {
1025 if (view->maximized_state) {
1026 hikari_maximized_state_destroy(view->maximized_state);
1027 view->maximized_state = NULL;
1028 if (!view->use_csd) {
1029 view->border.state = HIKARI_BORDER_INACTIVE;
1030 }
1031 }
1032
1033 assert(hikari_tile_is_attached(operation->tile));
1034
1035 if (hikari_view_is_tiled(view)) {
1036 struct hikari_tile *tile = view->tile;
1037
1038 assert(hikari_tile_is_attached(tile));
1039
1040 wl_list_remove(&tile->layout_tiles);
1041 hikari_free(tile);
1042 view->tile = NULL;
1043 }
1044
1045 assert(!hikari_view_is_tiled(view));
1046 assert(operation->tile != NULL);
1047 view->tile = operation->tile;
1048 operation->tile = NULL;
1049
1050 if (!hikari_view_is_hidden(view)) {
1051 commit_pending_geometry(view, &operation->geometry);
1052 if (operation->center) {
1053 hikari_view_center_cursor(view);
1054 }
1055 hikari_server_cursor_focus();
1056 } else {
1057 hikari_view_refresh_geometry(view, &operation->geometry);
1058 }
1059 }
1060
1061 static void
queue_tile(struct hikari_view * view,struct hikari_layout * layout,struct hikari_tile * tile,bool center)1062 queue_tile(struct hikari_view *view,
1063 struct hikari_layout *layout,
1064 struct hikari_tile *tile,
1065 bool center)
1066 {
1067 assert(!hikari_view_is_dirty(view));
1068
1069 struct hikari_operation *op = &view->pending_operation;
1070
1071 struct wlr_box *current_geometry = hikari_view_geometry(view);
1072
1073 op->type = HIKARI_OPERATION_TYPE_TILE;
1074 op->tile = tile;
1075 op->geometry = tile->view_geometry;
1076 op->center = center;
1077
1078 if (current_geometry->width == op->geometry.width &&
1079 current_geometry->height == op->geometry.height) {
1080 hikari_view_set_dirty(view);
1081
1082 hikari_view_commit_pending_operation(view, current_geometry);
1083 } else {
1084 resize(view, op, commit_tile);
1085 }
1086 }
1087
1088 void
hikari_view_tile(struct hikari_view * view,struct wlr_box * geometry,bool center)1089 hikari_view_tile(
1090 struct hikari_view *view, struct wlr_box *geometry, bool center)
1091 {
1092 assert(!hikari_view_is_dirty(view));
1093 assert(hikari_view_is_tileable(view));
1094
1095 struct hikari_layout *layout = view->sheet->workspace->sheet->layout;
1096
1097 struct hikari_tile *tile = hikari_malloc(sizeof(struct hikari_tile));
1098 hikari_tile_init(tile, view, layout, geometry, geometry);
1099
1100 queue_tile(view, layout, tile, center);
1101
1102 wl_list_insert(layout->tiles.prev, &tile->layout_tiles);
1103 }
1104
1105 static void
commit_full_maximize(struct hikari_view * view,struct hikari_operation * operation)1106 commit_full_maximize(
1107 struct hikari_view *view, struct hikari_operation *operation)
1108 {
1109 if (!view->maximized_state) {
1110 view->maximized_state =
1111 hikari_malloc(sizeof(struct hikari_maximized_state));
1112 }
1113
1114 view->maximized_state->maximization = HIKARI_MAXIMIZATION_FULLY_MAXIMIZED;
1115 view->maximized_state->geometry = operation->geometry;
1116
1117 if (!view->use_csd) {
1118 view->border.state = HIKARI_BORDER_NONE;
1119 }
1120
1121 commit_pending_operation(view, operation);
1122 }
1123
1124 static void
queue_full_maximize(struct hikari_view * view)1125 queue_full_maximize(struct hikari_view *view)
1126 {
1127 assert(view != NULL);
1128 assert(!hikari_view_is_hidden(view));
1129
1130 struct hikari_operation *op = &view->pending_operation;
1131 struct hikari_output *output = view->output;
1132
1133 op->type = HIKARI_OPERATION_TYPE_FULL_MAXIMIZE;
1134 op->geometry = output->usable_area;
1135 op->center = true;
1136
1137 resize(view, op, commit_full_maximize);
1138 }
1139
1140 static void
commit_unmaximize(struct hikari_view * view,struct hikari_operation * operation)1141 commit_unmaximize(struct hikari_view *view, struct hikari_operation *operation)
1142 {
1143 hikari_view_damage_whole(view);
1144
1145 hikari_free(view->maximized_state);
1146 view->maximized_state = NULL;
1147
1148 if (!view->use_csd) {
1149 view->border.state = HIKARI_BORDER_ACTIVE;
1150 }
1151
1152 commit_pending_operation(view, operation);
1153 }
1154
1155 static void
queue_unmaximize(struct hikari_view * view)1156 queue_unmaximize(struct hikari_view *view)
1157 {
1158 assert(view != NULL);
1159 assert(!hikari_view_is_hidden(view));
1160
1161 struct hikari_operation *op = &view->pending_operation;
1162
1163 op->type = HIKARI_OPERATION_TYPE_UNMAXIMIZE;
1164 op->center = true;
1165
1166 if (view->tile != NULL) {
1167 op->geometry = view->tile->view_geometry;
1168 } else {
1169 op->geometry = view->geometry;
1170 }
1171
1172 resize(view, op, commit_unmaximize);
1173 }
1174
1175 void
hikari_view_toggle_full_maximize(struct hikari_view * view)1176 hikari_view_toggle_full_maximize(struct hikari_view *view)
1177 {
1178 assert(view != NULL);
1179 assert(!hikari_view_is_hidden(view));
1180
1181 if (hikari_view_is_dirty(view)) {
1182 return;
1183 }
1184
1185 if (hikari_view_is_fully_maximized(view)) {
1186 queue_unmaximize(view);
1187 } else {
1188 queue_full_maximize(view);
1189 }
1190 }
1191
1192 void
hikari_view_toggle_public(struct hikari_view * view)1193 hikari_view_toggle_public(struct hikari_view *view)
1194 {
1195 if (hikari_view_is_public(view)) {
1196 hikari_view_unset_public(view);
1197 } else {
1198 hikari_view_set_public(view);
1199 }
1200 }
1201
1202 static void
commit_horizontal_maximize(struct hikari_view * view,struct hikari_operation * operation)1203 commit_horizontal_maximize(
1204 struct hikari_view *view, struct hikari_operation *operation)
1205 {
1206 if (!view->maximized_state) {
1207 view->maximized_state =
1208 hikari_malloc(sizeof(struct hikari_maximized_state));
1209 } else {
1210 switch (view->maximized_state->maximization) {
1211 case HIKARI_MAXIMIZATION_HORIZONTALLY_MAXIMIZED:
1212 commit_full_maximize(view, operation);
1213 return;
1214
1215 case HIKARI_MAXIMIZATION_FULLY_MAXIMIZED:
1216 if (!view->use_csd) {
1217 view->border.state = HIKARI_BORDER_INACTIVE;
1218 }
1219 break;
1220
1221 case HIKARI_MAXIMIZATION_VERTICALLY_MAXIMIZED:
1222 assert(false);
1223 break;
1224 }
1225 }
1226
1227 view->maximized_state->maximization =
1228 HIKARI_MAXIMIZATION_HORIZONTALLY_MAXIMIZED;
1229 view->maximized_state->geometry = operation->geometry;
1230
1231 commit_pending_operation(view, operation);
1232 }
1233
1234 static void
queue_horizontal_maximize(struct hikari_view * view)1235 queue_horizontal_maximize(struct hikari_view *view)
1236 {
1237 assert(view != NULL);
1238 assert(!hikari_view_is_hidden(view));
1239
1240 struct hikari_operation *op = &view->pending_operation;
1241 struct hikari_output *output = view->output;
1242
1243 struct wlr_box *geometry = view->current_unmaximized_geometry;
1244
1245 op->type = HIKARI_OPERATION_TYPE_HORIZONTAL_MAXIMIZE;
1246 op->geometry.x = output->usable_area.x;
1247 op->geometry.y = geometry->y;
1248 op->geometry.height = geometry->height;
1249 op->geometry.width = output->usable_area.width;
1250 op->center = true;
1251
1252 resize(view, op, commit_horizontal_maximize);
1253 }
1254
1255 static void
commit_vertical_maximize(struct hikari_view * view,struct hikari_operation * operation)1256 commit_vertical_maximize(
1257 struct hikari_view *view, struct hikari_operation *operation)
1258 {
1259 if (!view->maximized_state) {
1260 view->maximized_state =
1261 hikari_malloc(sizeof(struct hikari_maximized_state));
1262 } else {
1263 switch (view->maximized_state->maximization) {
1264 case HIKARI_MAXIMIZATION_HORIZONTALLY_MAXIMIZED:
1265 commit_full_maximize(view, operation);
1266 return;
1267
1268 case HIKARI_MAXIMIZATION_FULLY_MAXIMIZED:
1269 if (!view->use_csd) {
1270 view->border.state = HIKARI_BORDER_INACTIVE;
1271 }
1272 break;
1273
1274 case HIKARI_MAXIMIZATION_VERTICALLY_MAXIMIZED:
1275 assert(false);
1276 break;
1277 }
1278 }
1279
1280 view->maximized_state->maximization =
1281 HIKARI_MAXIMIZATION_VERTICALLY_MAXIMIZED;
1282 view->maximized_state->geometry = operation->geometry;
1283
1284 commit_pending_operation(view, operation);
1285 }
1286
1287 static void
queue_vertical_maximize(struct hikari_view * view)1288 queue_vertical_maximize(struct hikari_view *view)
1289 {
1290 assert(view != NULL);
1291 assert(!hikari_view_is_hidden(view));
1292
1293 struct hikari_operation *op = &view->pending_operation;
1294 struct hikari_output *output = view->output;
1295
1296 struct wlr_box *geometry = view->current_unmaximized_geometry;
1297
1298 op->type = HIKARI_OPERATION_TYPE_VERTICAL_MAXIMIZE;
1299 op->geometry.x = geometry->x;
1300 op->geometry.y = output->usable_area.y;
1301 op->geometry.height = output->usable_area.height;
1302 op->geometry.width = geometry->width;
1303 op->center = true;
1304
1305 resize(view, op, commit_vertical_maximize);
1306 }
1307
1308 void
hikari_view_toggle_vertical_maximize(struct hikari_view * view)1309 hikari_view_toggle_vertical_maximize(struct hikari_view *view)
1310 {
1311 assert(view != NULL);
1312 assert(!hikari_view_is_hidden(view));
1313
1314 if (hikari_view_is_dirty(view)) {
1315 return;
1316 }
1317
1318 if (view->maximized_state != NULL) {
1319 switch (view->maximized_state->maximization) {
1320 case HIKARI_MAXIMIZATION_FULLY_MAXIMIZED:
1321 queue_horizontal_maximize(view);
1322 break;
1323
1324 case HIKARI_MAXIMIZATION_VERTICALLY_MAXIMIZED:
1325 queue_unmaximize(view);
1326 break;
1327
1328 case HIKARI_MAXIMIZATION_HORIZONTALLY_MAXIMIZED:
1329 queue_full_maximize(view);
1330 break;
1331 }
1332 } else {
1333 queue_vertical_maximize(view);
1334 }
1335 }
1336
1337 void
hikari_view_toggle_horizontal_maximize(struct hikari_view * view)1338 hikari_view_toggle_horizontal_maximize(struct hikari_view *view)
1339 {
1340 assert(view != NULL);
1341 assert(!hikari_view_is_hidden(view));
1342
1343 if (view->maximized_state != NULL) {
1344 switch (view->maximized_state->maximization) {
1345 case HIKARI_MAXIMIZATION_FULLY_MAXIMIZED:
1346 queue_vertical_maximize(view);
1347 break;
1348
1349 case HIKARI_MAXIMIZATION_VERTICALLY_MAXIMIZED:
1350 queue_full_maximize(view);
1351 break;
1352
1353 case HIKARI_MAXIMIZATION_HORIZONTALLY_MAXIMIZED:
1354 queue_unmaximize(view);
1355 break;
1356 }
1357 } else {
1358 queue_horizontal_maximize(view);
1359 }
1360 }
1361
1362 void
hikari_view_toggle_floating(struct hikari_view * view)1363 hikari_view_toggle_floating(struct hikari_view *view)
1364 {
1365 if (!hikari_view_is_floating(view)) {
1366 if (hikari_view_is_tiled(view)) {
1367 hikari_view_reset_geometry(view);
1368 }
1369 hikari_view_set_floating(view);
1370 } else {
1371 hikari_view_unset_floating(view);
1372 }
1373 }
1374
1375 void
hikari_view_reset_geometry(struct hikari_view * view)1376 hikari_view_reset_geometry(struct hikari_view *view)
1377 {
1378 queue_reset(view, true);
1379 }
1380
1381 void
hikari_view_evacuate(struct hikari_view * view,struct hikari_sheet * sheet)1382 hikari_view_evacuate(struct hikari_view *view, struct hikari_sheet *sheet)
1383 {
1384 #ifndef NDEBUG
1385 printf("EVACUATE VIEW %p\n", view);
1386 #endif
1387
1388 clear_focus(view);
1389
1390 view->output = sheet->workspace->output;
1391 view->sheet = sheet;
1392
1393 if (!hikari_view_is_hidden(view)) {
1394 if (hikari_view_is_forced(view)) {
1395 move_to_top(view);
1396 } else {
1397 raise_view(view);
1398 }
1399
1400 if (hikari_sheet_is_visible(sheet)) {
1401 hikari_view_damage_whole(view);
1402 hikari_indicator_damage(&hikari_server.indicator, view);
1403 } else {
1404 if (hikari_view_is_forced(view)) {
1405 move_to_top(view);
1406 } else {
1407 hikari_view_hide(view);
1408 }
1409 }
1410 } else {
1411 if (hikari_view_is_forced(view)) {
1412 raise_view(view);
1413 } else {
1414 move_to_top(view);
1415 }
1416 }
1417
1418 if (hikari_view_is_tiled(view) || hikari_view_is_maximized(view)) {
1419 queue_reset(view, false);
1420 }
1421 }
1422
1423 void
hikari_view_pin_to_sheet(struct hikari_view * view,struct hikari_sheet * sheet)1424 hikari_view_pin_to_sheet(struct hikari_view *view, struct hikari_sheet *sheet)
1425 {
1426 assert(view != NULL);
1427 assert(sheet != NULL);
1428 assert(sheet->workspace->output == view->output);
1429
1430 if (view->sheet == sheet) {
1431 assert(!hikari_view_is_hidden(view));
1432
1433 if (view->sheet->workspace->sheet != sheet && sheet->nr != 0) {
1434 hikari_view_hide(view);
1435 hikari_server_cursor_focus();
1436
1437 move_to_top(view);
1438 } else {
1439 hikari_view_raise(view);
1440 hikari_indicator_damage(&hikari_server.indicator, view);
1441 }
1442 } else {
1443 if (hikari_sheet_is_visible(sheet)) {
1444 place_visibly_above(view, sheet->workspace);
1445
1446 hikari_view_damage_whole(view);
1447 hikari_indicator_damage(&hikari_server.indicator, view);
1448 } else {
1449 hikari_view_hide(view);
1450 hikari_server_cursor_focus();
1451 }
1452
1453 view->sheet = sheet;
1454
1455 if (hikari_view_is_tiled(view)) {
1456 queue_reset(view, true);
1457 } else {
1458 move_to_top(view);
1459 }
1460 }
1461 }
1462
1463 void
hikari_view_center_cursor(struct hikari_view * view)1464 hikari_view_center_cursor(struct hikari_view *view)
1465 {
1466 assert(view != NULL);
1467
1468 struct hikari_output *output = view->output;
1469 struct wlr_box *view_geometry = hikari_view_geometry(view);
1470
1471 struct wlr_box geometry;
1472 hikari_geometry_constrain_size(
1473 view_geometry, &output->usable_area, &geometry);
1474
1475 hikari_cursor_center(&hikari_server.cursor, output, &geometry);
1476 }
1477
1478 void
hikari_view_top_left_cursor(struct hikari_view * view)1479 hikari_view_top_left_cursor(struct hikari_view *view)
1480 {
1481 assert(view != NULL);
1482
1483 struct wlr_box *geometry = hikari_view_geometry(view);
1484 struct hikari_output *output = view->output;
1485
1486 int x = output->geometry.x + geometry->x;
1487 int y = output->geometry.y + geometry->y;
1488
1489 hikari_cursor_warp(&hikari_server.cursor, x, y);
1490 }
1491
1492 void
hikari_view_bottom_right_cursor(struct hikari_view * view)1493 hikari_view_bottom_right_cursor(struct hikari_view *view)
1494 {
1495 assert(view != NULL);
1496
1497 struct wlr_box *geometry = hikari_view_geometry(view);
1498 struct hikari_output *output = view->output;
1499
1500 int x = output->geometry.x + geometry->x + geometry->width;
1501 int y = output->geometry.y + geometry->y + geometry->height;
1502
1503 hikari_cursor_warp(&hikari_server.cursor, x, y);
1504 }
1505
1506 void
hikari_view_toggle_invisible(struct hikari_view * view)1507 hikari_view_toggle_invisible(struct hikari_view *view)
1508 {
1509 if (hikari_view_is_invisible(view)) {
1510 hikari_view_unset_invisible(view);
1511 } else {
1512 if (hikari_view_is_tiled(view)) {
1513 hikari_view_reset_geometry(view);
1514 }
1515 hikari_view_set_invisible(view);
1516 }
1517 }
1518
1519 void
hikari_view_group(struct hikari_view * view,struct hikari_group * group)1520 hikari_view_group(struct hikari_view *view, struct hikari_group *group)
1521 {
1522 assert(view != NULL);
1523 assert(group != NULL);
1524 assert(view->group != NULL);
1525
1526 if (view->group == group) {
1527 return;
1528 }
1529
1530 remove_from_group(view);
1531 view->group = group;
1532
1533 increase_group_visiblity(view);
1534
1535 raise_view(view);
1536
1537 hikari_view_damage_whole(view);
1538 }
1539
1540 void
hikari_view_exchange(struct hikari_view * from,struct hikari_view * to)1541 hikari_view_exchange(struct hikari_view *from, struct hikari_view *to)
1542 {
1543 assert(from != NULL);
1544 assert(to != NULL);
1545
1546 if (hikari_view_is_dirty(from) || hikari_view_is_dirty(to)) {
1547 return;
1548 }
1549
1550 assert(from->tile != NULL);
1551 assert(to->tile != NULL);
1552 assert(to->tile->view->sheet == from->tile->view->sheet);
1553
1554 struct hikari_layout *layout = from->sheet->workspace->sheet->layout;
1555
1556 struct wlr_box *from_geometry = &from->tile->tile_geometry;
1557 struct wlr_box *to_geometry = &to->tile->tile_geometry;
1558
1559 struct hikari_tile *from_tile = hikari_malloc(sizeof(struct hikari_tile));
1560 struct hikari_tile *to_tile = hikari_malloc(sizeof(struct hikari_tile));
1561
1562 hikari_tile_init(from_tile, from, layout, to_geometry, to_geometry);
1563 hikari_tile_init(to_tile, to, layout, from_geometry, from_geometry);
1564
1565 wl_list_insert(&from->tile->layout_tiles, &to_tile->layout_tiles);
1566 wl_list_insert(&to->tile->layout_tiles, &from_tile->layout_tiles);
1567
1568 queue_tile(from, layout, from_tile, true);
1569 queue_tile(to, layout, to_tile, false);
1570 }
1571
1572 static void
destroy_subsurface_handler(struct wl_listener * listener,void * data)1573 destroy_subsurface_handler(struct wl_listener *listener, void *data)
1574 {
1575 struct hikari_view_subsurface *view_subsurface =
1576 wl_container_of(listener, view_subsurface, destroy);
1577
1578 hikari_view_subsurface_fini(view_subsurface);
1579
1580 hikari_free(view_subsurface);
1581 }
1582
1583 void
hikari_view_subsurface_init(struct hikari_view_subsurface * view_subsurface,struct hikari_view * parent,struct wlr_subsurface * subsurface)1584 hikari_view_subsurface_init(struct hikari_view_subsurface *view_subsurface,
1585 struct hikari_view *parent,
1586 struct wlr_subsurface *subsurface)
1587 {
1588 view_subsurface->subsurface = subsurface;
1589
1590 view_subsurface->destroy.notify = destroy_subsurface_handler;
1591 wl_signal_add(
1592 &subsurface->surface->events.destroy, &view_subsurface->destroy);
1593
1594 hikari_view_child_init(
1595 (struct hikari_view_child *)view_subsurface, parent, subsurface->surface);
1596 }
1597
1598 void
hikari_view_child_fini(struct hikari_view_child * view_child)1599 hikari_view_child_fini(struct hikari_view_child *view_child)
1600 {
1601 wl_list_remove(&view_child->link);
1602 wl_list_remove(&view_child->commit.link);
1603 wl_list_remove(&view_child->new_subsurface.link);
1604 }
1605
1606 void
hikari_view_subsurface_fini(struct hikari_view_subsurface * view_subsurface)1607 hikari_view_subsurface_fini(struct hikari_view_subsurface *view_subsurface)
1608 {
1609 hikari_view_child_fini(&view_subsurface->view_child);
1610 wl_list_remove(&view_subsurface->destroy.link);
1611 }
1612
1613 static void
damage_surface(struct wlr_surface * surface,int sx,int sy,void * data)1614 damage_surface(struct wlr_surface *surface, int sx, int sy, void *data)
1615 {
1616 struct hikari_damage_data *damage_data = data;
1617 struct hikari_output *output = damage_data->output;
1618
1619 if (damage_data->whole) {
1620 damage_whole_surface(surface, sx, sy, data);
1621 } else {
1622 struct wlr_box *geometry = damage_data->geometry;
1623
1624 hikari_output_add_effective_surface_damage(
1625 output, surface, geometry->x + sx, geometry->y + sy);
1626 }
1627 }
1628
1629 static void
damage_single_surface(struct wlr_surface * surface,int sx,int sy,void * data)1630 damage_single_surface(struct wlr_surface *surface, int sx, int sy, void *data)
1631 {
1632 struct hikari_damage_data *damage_data = data;
1633
1634 if (damage_data->surface == surface) {
1635 damage_surface(surface, sx, sy, data);
1636 }
1637 }
1638
1639 static void
commit_child_handler(struct wl_listener * listener,void * data)1640 commit_child_handler(struct wl_listener *listener, void *data)
1641 {
1642 struct hikari_view_child *view_child =
1643 wl_container_of(listener, view_child, commit);
1644
1645 struct hikari_view *parent = view_child->parent;
1646 assert(!hikari_view_is_hidden(parent));
1647
1648 struct wlr_surface *surface = view_child->surface;
1649
1650 hikari_view_damage_surface(parent, surface, false);
1651 }
1652
1653 static void
new_subsurface_child_handler(struct wl_listener * listener,void * data)1654 new_subsurface_child_handler(struct wl_listener *listener, void *data)
1655 {
1656 struct hikari_view_child *view_child =
1657 wl_container_of(listener, view_child, new_subsurface);
1658
1659 struct wlr_subsurface *wlr_subsurface = data;
1660
1661 struct hikari_view_subsurface *view_subsurface =
1662 hikari_malloc(sizeof(struct hikari_view_subsurface));
1663
1664 hikari_view_subsurface_init(
1665 view_subsurface, view_child->parent, wlr_subsurface);
1666 }
1667
1668 void
hikari_view_child_init(struct hikari_view_child * view_child,struct hikari_view * parent,struct wlr_surface * surface)1669 hikari_view_child_init(struct hikari_view_child *view_child,
1670 struct hikari_view *parent,
1671 struct wlr_surface *surface)
1672 {
1673 view_child->parent = parent;
1674 view_child->surface = surface;
1675
1676 view_child->new_subsurface.notify = new_subsurface_child_handler;
1677 wl_signal_add(&surface->events.new_subsurface, &view_child->new_subsurface);
1678
1679 view_child->commit.notify = commit_child_handler;
1680 wl_signal_add(&surface->events.commit, &view_child->commit);
1681
1682 wl_list_insert(&parent->children, &view_child->link);
1683 }
1684
1685 void
hikari_view_damage_surface(struct hikari_view * view,struct wlr_surface * surface,bool whole)1686 hikari_view_damage_surface(
1687 struct hikari_view *view, struct wlr_surface *surface, bool whole)
1688 {
1689 assert(view != NULL);
1690
1691 // TODO I know, this needs to be done A LOT better
1692 if (view->use_csd) {
1693 hikari_output_damage_whole(view->output);
1694 return;
1695 }
1696
1697 struct hikari_damage_data damage_data;
1698
1699 damage_data.geometry = hikari_view_geometry(view);
1700 damage_data.output = view->output;
1701 damage_data.surface = surface;
1702 damage_data.whole = whole;
1703 damage_data.view = view;
1704
1705 hikari_node_for_each_surface(
1706 (struct hikari_node *)view, damage_single_surface, &damage_data);
1707 }
1708
1709 void
hikari_view_refresh_geometry(struct hikari_view * view,struct wlr_box * geometry)1710 hikari_view_refresh_geometry(struct hikari_view *view, struct wlr_box *geometry)
1711 {
1712 struct wlr_box *new_geometry = refresh_geometry(view);
1713
1714 memcpy(new_geometry, geometry, sizeof(struct wlr_box));
1715
1716 view->current_geometry = new_geometry;
1717 view->current_unmaximized_geometry = refresh_unmaximized_geometry(view);
1718
1719 refresh_border_geometry(view);
1720 }
1721
1722 static void
commit_operation(struct hikari_operation * operation,struct hikari_view * view)1723 commit_operation(struct hikari_operation *operation, struct hikari_view *view)
1724 {
1725 switch (operation->type) {
1726 case HIKARI_OPERATION_TYPE_RESIZE:
1727 commit_resize(view, operation);
1728 break;
1729
1730 case HIKARI_OPERATION_TYPE_RESET:
1731 commit_reset(view, operation);
1732 break;
1733
1734 case HIKARI_OPERATION_TYPE_UNMAXIMIZE:
1735 commit_unmaximize(view, operation);
1736 break;
1737
1738 case HIKARI_OPERATION_TYPE_FULL_MAXIMIZE:
1739 commit_full_maximize(view, operation);
1740 break;
1741
1742 case HIKARI_OPERATION_TYPE_VERTICAL_MAXIMIZE:
1743 commit_vertical_maximize(view, operation);
1744 break;
1745
1746 case HIKARI_OPERATION_TYPE_HORIZONTAL_MAXIMIZE:
1747 commit_horizontal_maximize(view, operation);
1748 break;
1749
1750 case HIKARI_OPERATION_TYPE_TILE:
1751 commit_tile(view, operation);
1752 break;
1753 }
1754 }
1755
1756 void
hikari_view_commit_pending_operation(struct hikari_view * view,struct wlr_box * geometry)1757 hikari_view_commit_pending_operation(
1758 struct hikari_view *view, struct wlr_box *geometry)
1759 {
1760 assert(view != NULL);
1761 assert(hikari_view_is_dirty(view));
1762
1763 view->pending_operation.geometry.width = geometry->width;
1764 view->pending_operation.geometry.height = geometry->height;
1765
1766 hikari_indicator_damage(&hikari_server.indicator, view);
1767 hikari_view_damage_whole(view);
1768
1769 commit_operation(&view->pending_operation, view);
1770 hikari_view_unset_dirty(view);
1771 }
1772
1773 void
hikari_view_activate(struct hikari_view * view,bool active)1774 hikari_view_activate(struct hikari_view *view, bool active)
1775 {
1776 assert(view != NULL);
1777
1778 if (view->activate) {
1779 if (view->border.state != HIKARI_BORDER_NONE) {
1780 view->border.state =
1781 active ? HIKARI_BORDER_ACTIVE : HIKARI_BORDER_INACTIVE;
1782 }
1783 view->activate(view, active);
1784 }
1785 }
1786
1787 static void
migrate_view(struct hikari_view * view,struct hikari_sheet * sheet,bool center)1788 migrate_view(struct hikari_view *view, struct hikari_sheet *sheet, bool center)
1789 {
1790 assert(hikari_view_is_hidden(view));
1791
1792 view->output = sheet->workspace->output;
1793 view->sheet = sheet;
1794
1795 move_to_top(view);
1796
1797 queue_reset(view, center);
1798 }
1799
1800 void
hikari_view_migrate(struct hikari_view * view,struct hikari_sheet * sheet,int x,int y,bool center)1801 hikari_view_migrate(struct hikari_view *view,
1802 struct hikari_sheet *sheet,
1803 int x,
1804 int y,
1805 bool center)
1806 {
1807 struct hikari_output *output = sheet->workspace->output;
1808 struct wlr_box *view_geometry = hikari_view_geometry(view);
1809
1810 hikari_indicator_damage(&hikari_server.indicator, view);
1811 hikari_view_damage_whole(view);
1812
1813 // only remove view from lists and do not make it lose focus by calling
1814 // `hikari_view_hide`.
1815 hide(view);
1816
1817 hikari_geometry_constrain_relative(
1818 &view->geometry, &output->usable_area, x, y);
1819 hikari_geometry_constrain_relative(view_geometry, &output->usable_area, x, y);
1820
1821 migrate_view(view, sheet, center);
1822
1823 #ifdef HAVE_XWAYLAND
1824 if (view->move != NULL) {
1825 view->move(view, view_geometry->x, view_geometry->y);
1826 }
1827 #endif
1828
1829 if (hikari_view_is_hidden(view)) {
1830 hikari_view_show(view);
1831 }
1832 }
1833
1834 void
hikari_view_configure(struct hikari_view * view,const char * app_id,struct hikari_view_config * view_config)1835 hikari_view_configure(struct hikari_view *view,
1836 const char *app_id,
1837 struct hikari_view_config *view_config)
1838 {
1839 assert(view->id == NULL);
1840
1841 struct hikari_sheet *sheet;
1842 struct hikari_output *output;
1843 struct wlr_box *geometry = &view->geometry;
1844 int x, y;
1845 bool invisible, floating, publicview;
1846
1847 set_app_id(view, app_id);
1848
1849 if (view_config != NULL) {
1850 struct hikari_view_properties *properties =
1851 hikari_view_config_resolve_properties(view_config, view->child);
1852
1853 sheet = hikari_view_properties_resolve_sheet(properties);
1854 output = sheet->workspace->output;
1855
1856 invisible = properties->invisible;
1857 floating = properties->floating;
1858 publicview = properties->publicview;
1859
1860 hikari_view_properties_resolve_position(properties, view, &x, &y);
1861 } else {
1862 sheet = hikari_server.workspace->sheet;
1863 output = sheet->workspace->output;
1864
1865 invisible = false;
1866 floating = false;
1867 publicview = false;
1868
1869 x = hikari_server.cursor.wlr_cursor->x - output->geometry.x;
1870 y = hikari_server.cursor.wlr_cursor->y - output->geometry.y;
1871 }
1872
1873 view->sheet = sheet;
1874 view->output = output;
1875
1876 wl_list_init(&view->workspace_views);
1877 wl_list_init(&view->visible_server_views);
1878
1879 if (invisible) {
1880 hikari_view_set_invisible(view);
1881 }
1882
1883 if (floating) {
1884 hikari_view_set_floating(view);
1885 }
1886
1887 if (publicview) {
1888 hikari_view_set_public(view);
1889 }
1890
1891 hikari_geometry_constrain_absolute(geometry, &output->usable_area, x, y);
1892 hikari_view_refresh_geometry(view, geometry);
1893 }
1894