1 #include <hikari/server.h>
2 
3 #include <errno.h>
4 #include <libinput.h>
5 #include <unistd.h>
6 
7 #include <wlr/backend.h>
8 #include <wlr/backend/libinput.h>
9 #include <wlr/backend/noop.h>
10 #include <wlr/backend/session.h>
11 #include <wlr/types/wlr_compositor.h>
12 #include <wlr/types/wlr_data_control_v1.h>
13 #include <wlr/types/wlr_data_device.h>
14 #include <wlr/types/wlr_gtk_primary_selection.h>
15 #include <wlr/types/wlr_input_device.h>
16 #include <wlr/types/wlr_keyboard.h>
17 #include <wlr/types/wlr_output_layout.h>
18 #include <wlr/types/wlr_primary_selection.h>
19 #include <wlr/types/wlr_primary_selection_v1.h>
20 #include <wlr/types/wlr_seat.h>
21 #include <wlr/types/wlr_server_decoration.h>
22 #include <wlr/types/wlr_xdg_output_v1.h>
23 #include <wlr/types/wlr_xdg_shell.h>
24 
25 #ifdef HAVE_LAYERSHELL
26 #include <wlr/types/wlr_layer_shell_v1.h>
27 #endif
28 
29 #ifdef HAVE_GAMMACONTROL
30 #include <wlr/types/wlr_gamma_control_v1.h>
31 #endif
32 
33 #ifdef HAVE_SCREENCOPY
34 #include <wlr/types/wlr_screencopy_v1.h>
35 #endif
36 
37 #ifdef HAVE_XWAYLAND
38 #include <wlr/xwayland.h>
39 #endif
40 
41 #include <hikari/border.h>
42 #include <hikari/command.h>
43 #include <hikari/configuration.h>
44 #include <hikari/decoration.h>
45 #include <hikari/exec.h>
46 #include <hikari/keyboard.h>
47 #include <hikari/layout.h>
48 #include <hikari/mark.h>
49 #include <hikari/memory.h>
50 #include <hikari/output.h>
51 #include <hikari/pointer.h>
52 #include <hikari/pointer_config.h>
53 #include <hikari/sheet.h>
54 #include <hikari/switch.h>
55 #include <hikari/workspace.h>
56 #include <hikari/xdg_view.h>
57 
58 #ifdef HAVE_XWAYLAND
59 #include <hikari/xwayland_unmanaged_view.h>
60 #include <hikari/xwayland_view.h>
61 #endif
62 
63 static void
add_pointer(struct hikari_server * server,struct wlr_input_device * device)64 add_pointer(struct hikari_server *server, struct wlr_input_device *device)
65 {
66   struct hikari_pointer *pointer = hikari_malloc(sizeof(struct hikari_pointer));
67   hikari_pointer_init(pointer, device);
68 
69   struct hikari_pointer_config *pointer_config =
70       hikari_configuration_resolve_pointer_config(
71           hikari_configuration, device->name);
72 
73   if (pointer_config != NULL) {
74     hikari_pointer_configure(pointer, pointer_config);
75   }
76 
77   wlr_cursor_attach_input_device(server->cursor.wlr_cursor, device);
78   wlr_cursor_map_input_to_output(server->cursor.wlr_cursor, device, NULL);
79 }
80 
81 static void
add_keyboard(struct hikari_server * server,struct wlr_input_device * device)82 add_keyboard(struct hikari_server *server, struct wlr_input_device *device)
83 {
84   struct hikari_keyboard *keyboard =
85       hikari_malloc(sizeof(struct hikari_keyboard));
86 
87   hikari_keyboard_init(keyboard, device);
88 
89   struct hikari_keyboard_config *keyboard_config =
90       hikari_configuration_resolve_keyboard_config(
91           hikari_configuration, device->name);
92 
93   assert(keyboard_config != NULL);
94   hikari_keyboard_configure(keyboard, keyboard_config);
95 
96   hikari_keyboard_configure_bindings(
97       keyboard, &hikari_configuration->keyboard_binding_configs);
98 }
99 
100 static void
add_switch(struct hikari_server * server,struct wlr_input_device * device)101 add_switch(struct hikari_server *server, struct wlr_input_device *device)
102 {
103   struct hikari_switch *swtch = hikari_malloc(sizeof(struct hikari_switch));
104 
105   hikari_switch_init(swtch, device);
106 
107   struct hikari_switch_config *switch_config =
108       hikari_configuration_resolve_switch_config(
109           hikari_configuration, device->name);
110 
111   if (switch_config != NULL) {
112     hikari_switch_configure(swtch, switch_config);
113   }
114 }
115 
116 static void
add_input(struct hikari_server * server,struct wlr_input_device * device)117 add_input(struct hikari_server *server, struct wlr_input_device *device)
118 {
119 
120   switch (device->type) {
121     case WLR_INPUT_DEVICE_KEYBOARD:
122       add_keyboard(server, device);
123       break;
124 
125     case WLR_INPUT_DEVICE_POINTER:
126       add_pointer(server, device);
127       break;
128 
129     case WLR_INPUT_DEVICE_SWITCH:
130       add_switch(server, device);
131       break;
132 
133     default:
134       break;
135   }
136 
137   uint32_t caps = WL_SEAT_CAPABILITY_POINTER;
138   if (!wl_list_empty(&server->keyboards)) {
139     caps |= WL_SEAT_CAPABILITY_KEYBOARD;
140   }
141   wlr_seat_set_capabilities(server->seat, caps);
142 
143   if ((caps & WL_SEAT_CAPABILITY_POINTER) != 0) {
144     hikari_cursor_reset_image(&server->cursor);
145   }
146 }
147 
148 static void
new_input_handler(struct wl_listener * listener,void * data)149 new_input_handler(struct wl_listener *listener, void *data)
150 {
151   struct hikari_server *server = wl_container_of(listener, server, new_input);
152   struct wlr_input_device *device = data;
153 
154   add_input(server, device);
155 }
156 
157 #ifdef HAVE_VIRTUAL_INPUT
158 static void
new_virtual_keyboard_handler(struct wl_listener * listener,void * data)159 new_virtual_keyboard_handler(struct wl_listener *listener, void *data)
160 {
161   struct hikari_server *server =
162       wl_container_of(listener, server, new_virtual_keyboard);
163   struct wlr_virtual_keyboard_v1 *keyboard = data;
164   struct wlr_input_device *device = &keyboard->input_device;
165 
166   add_input(server, device);
167 }
168 
169 static void
setup_virtual_keyboard(struct hikari_server * server)170 setup_virtual_keyboard(struct hikari_server *server)
171 {
172   server->virtual_keyboard =
173       wlr_virtual_keyboard_manager_v1_create(server->display);
174   wl_signal_add(&server->virtual_keyboard->events.new_virtual_keyboard,
175       &server->new_virtual_keyboard);
176   server->new_virtual_keyboard.notify = new_virtual_keyboard_handler;
177 }
178 
179 static void
new_virtual_pointer_handler(struct wl_listener * listener,void * data)180 new_virtual_pointer_handler(struct wl_listener *listener, void *data)
181 {
182   struct hikari_server *server =
183       wl_container_of(listener, server, new_virtual_pointer);
184   struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
185   struct wlr_virtual_pointer_v1 *pointer = event->new_pointer;
186   struct wlr_input_device *device = &pointer->input_device;
187 
188   add_input(server, device);
189 
190   if (event->suggested_output) {
191     wlr_cursor_map_to_output(
192         server->cursor.wlr_cursor, event->suggested_output);
193   }
194 }
195 
196 static void
setup_virtual_pointer(struct hikari_server * server)197 setup_virtual_pointer(struct hikari_server *server)
198 {
199   server->virtual_pointer =
200       wlr_virtual_pointer_manager_v1_create(server->display);
201   wl_signal_add(&server->virtual_pointer->events.new_virtual_pointer,
202       &server->new_virtual_pointer);
203   server->new_virtual_pointer.notify = new_virtual_pointer_handler;
204 }
205 #endif
206 
207 static void
new_output_handler(struct wl_listener * listener,void * data)208 new_output_handler(struct wl_listener *listener, void *data)
209 {
210   struct hikari_server *server = wl_container_of(listener, server, new_output);
211 
212   assert(server == &hikari_server);
213 
214   struct wlr_output *wlr_output = data;
215   struct hikari_output *output = hikari_malloc(sizeof(struct hikari_output));
216 
217   hikari_output_init(output, wlr_output);
218   if (hikari_server.workspace == NULL) {
219     hikari_server.workspace = output->workspace;
220     hikari_cursor_activate(&hikari_server.cursor);
221     hikari_server.mode = (struct hikari_mode *)&hikari_server.normal_mode;
222   } else {
223     hikari_cursor_reset_image(&server->cursor);
224   }
225 }
226 
227 static bool
surface_at(struct hikari_node * node,double ox,double oy,struct wlr_surface ** surface,double * sx,double * sy)228 surface_at(struct hikari_node *node,
229     double ox,
230     double oy,
231     struct wlr_surface **surface,
232     double *sx,
233     double *sy)
234 {
235   double out_sx, out_sy;
236 
237   struct wlr_surface *out_surface =
238       hikari_node_surface_at(node, ox, oy, &out_sx, &out_sy);
239 
240   if (out_surface != NULL) {
241     *sx = out_sx;
242     *sy = out_sy;
243     *surface = out_surface;
244     return true;
245   }
246 
247   return false;
248 }
249 
250 #ifdef HAVE_LAYERSHELL
251 static bool
layer_at(struct wl_list * layers,double ox,double oy,struct wlr_surface ** surface,double * sx,double * sy,struct hikari_node ** node)252 layer_at(struct wl_list *layers,
253     double ox,
254     double oy,
255     struct wlr_surface **surface,
256     double *sx,
257     double *sy,
258     struct hikari_node **node)
259 {
260   double out_sx, out_sy;
261 
262   struct hikari_layer *layer;
263   wl_list_for_each (layer, layers, layer_surfaces) {
264     struct hikari_node *out_node = (struct hikari_node *)layer;
265 
266     struct wlr_surface *out_surface =
267         hikari_node_surface_at(out_node, ox, oy, &out_sx, &out_sy);
268 
269     if (out_surface != NULL) {
270       *sx = out_sx;
271       *sy = out_sy;
272       *surface = out_surface;
273       *node = out_node;
274       return true;
275     }
276   }
277 
278   return false;
279 }
280 
281 static bool
topmost_of(struct wl_list * layers,double ox,double oy,struct wlr_surface ** surface,double * sx,double * sy,struct hikari_node ** node)282 topmost_of(struct wl_list *layers,
283     double ox,
284     double oy,
285     struct wlr_surface **surface,
286     double *sx,
287     double *sy,
288     struct hikari_node **node)
289 {
290   double out_sx, out_sy;
291 
292   struct hikari_layer *layer;
293   wl_list_for_each (layer, layers, layer_surfaces) {
294     struct hikari_node *out_node = (struct hikari_node *)layer;
295 
296     struct wlr_layer_surface_v1_state *state = &layer->surface->current;
297 
298     struct wlr_surface *out_surface =
299         hikari_node_surface_at(out_node, ox, oy, &out_sx, &out_sy);
300 
301     if (state->keyboard_interactive) {
302       if (out_surface != NULL) {
303         *surface = out_surface;
304       } else {
305         *surface = layer->surface->surface;
306       }
307 
308       *sx = out_sx;
309       *sy = out_sy;
310       *node = out_node;
311 
312       return true;
313     } else if (out_surface != NULL) {
314       *surface = out_surface;
315 
316       *sx = out_sx;
317       *sy = out_sy;
318       *node = out_node;
319 
320       return true;
321     }
322   }
323 
324   return false;
325 }
326 #endif
327 
328 static struct hikari_node *
node_at(double lx,double ly,struct wlr_surface ** surface,struct hikari_workspace ** workspace,double * sx,double * sy)329 node_at(double lx,
330     double ly,
331     struct wlr_surface **surface,
332     struct hikari_workspace **workspace,
333     double *sx,
334     double *sy)
335 {
336   assert(hikari_server.workspace != NULL);
337 
338   struct wlr_output *wlr_output =
339       wlr_output_layout_output_at(hikari_server.output_layout, lx, ly);
340 
341   if (wlr_output == NULL) {
342     *workspace = hikari_server.workspace;
343     return NULL;
344   }
345 
346   struct hikari_output *output = wlr_output->data;
347   struct hikari_workspace *output_workspace = output->workspace;
348 
349   *workspace = output_workspace;
350 
351   struct hikari_node *node;
352   double ox = lx - output->geometry.x;
353   double oy = ly - output->geometry.y;
354 
355 #ifdef HAVE_LAYERSHELL
356   if (topmost_of(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
357           ox,
358           oy,
359           surface,
360           sx,
361           sy,
362           &node)) {
363     return node;
364   }
365 #endif
366 
367 #ifdef HAVE_XWAYLAND
368   struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view = NULL;
369   wl_list_for_each (xwayland_unmanaged_view,
370       &output->unmanaged_xwayland_views,
371       unmanaged_output_views) {
372     node = (struct hikari_node *)xwayland_unmanaged_view;
373 
374     if (surface_at(node, ox, oy, surface, sx, sy)) {
375       return node;
376     }
377   }
378 #endif
379 
380 #ifdef HAVE_LAYERSHELL
381   if (topmost_of(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
382           ox,
383           oy,
384           surface,
385           sx,
386           sy,
387           &node)) {
388     return node;
389   }
390 #endif
391 
392   struct hikari_view *view = NULL;
393   wl_list_for_each (view, &output_workspace->views, workspace_views) {
394     node = (struct hikari_node *)view;
395 
396     if (surface_at(node, ox, oy, surface, sx, sy)) {
397       return node;
398     }
399   }
400 
401 #ifdef HAVE_LAYERSHELL
402   if (layer_at(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
403           ox,
404           oy,
405           surface,
406           sx,
407           sy,
408           &node)) {
409     return node;
410   }
411 #endif
412 
413   return NULL;
414 }
415 
416 struct hikari_node *
hikari_server_node_at(double x,double y,struct wlr_surface ** surface,struct hikari_workspace ** workspace,double * sx,double * sy)417 hikari_server_node_at(double x,
418     double y,
419     struct wlr_surface **surface,
420     struct hikari_workspace **workspace,
421     double *sx,
422     double *sy)
423 {
424   return node_at(x, y, surface, workspace, sx, sy);
425 }
426 
427 void
hikari_server_cursor_focus(void)428 hikari_server_cursor_focus(void)
429 {
430   struct timespec now;
431   uint32_t time_msec = (uint32_t)clock_gettime(CLOCK_MONOTONIC, &now);
432   hikari_server.mode->cursor_move(time_msec);
433 }
434 
435 static void
request_set_primary_selection_handler(struct wl_listener * listener,void * data)436 request_set_primary_selection_handler(struct wl_listener *listener, void *data)
437 {
438   struct hikari_server *server =
439       wl_container_of(listener, server, request_set_primary_selection);
440 
441   struct wlr_seat_request_set_primary_selection_event *event = data;
442 
443   // CAN FAIL WITH NULL POINTER. HOW?
444   wlr_seat_set_primary_selection(server->seat, event->source, event->serial);
445 }
446 
447 static void
request_set_selection_handler(struct wl_listener * listener,void * data)448 request_set_selection_handler(struct wl_listener *listener, void *data)
449 {
450   struct hikari_server *server =
451       wl_container_of(listener, server, request_set_selection);
452 
453   struct wlr_seat_request_set_selection_event *event = data;
454 
455   wlr_seat_set_selection(server->seat, event->source, event->serial);
456 }
457 
458 #ifdef HAVE_XWAYLAND
459 static void
new_xwayland_surface_handler(struct wl_listener * listener,void * data)460 new_xwayland_surface_handler(struct wl_listener *listener, void *data)
461 {
462   struct hikari_server *server =
463       wl_container_of(listener, server, new_xwayland_surface);
464 
465   struct wlr_xwayland_surface *wlr_xwayland_surface = data;
466 
467   struct hikari_workspace *workspace = server->workspace;
468 
469   if (wlr_xwayland_surface->override_redirect) {
470     struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view =
471         hikari_malloc(sizeof(struct hikari_xwayland_unmanaged_view));
472 
473     hikari_xwayland_unmanaged_view_init(
474         xwayland_unmanaged_view, wlr_xwayland_surface, workspace);
475   } else {
476     struct hikari_xwayland_view *xwayland_view =
477         hikari_malloc(sizeof(struct hikari_xwayland_view));
478 
479     hikari_xwayland_view_init(xwayland_view, wlr_xwayland_surface, workspace);
480   }
481 }
482 
483 static void
setup_xwayland(struct hikari_server * server)484 setup_xwayland(struct hikari_server *server)
485 {
486   server->xwayland =
487       wlr_xwayland_create(server->display, server->compositor, true);
488 
489   server->new_xwayland_surface.notify = new_xwayland_surface_handler;
490   wl_signal_add(
491       &server->xwayland->events.new_surface, &server->new_xwayland_surface);
492 
493   setenv("DISPLAY", server->xwayland->display_name, true);
494 }
495 #endif
496 
497 static void
setup_cursor(struct hikari_server * server)498 setup_cursor(struct hikari_server *server)
499 {
500   hikari_cursor_init(&hikari_server.cursor, server->output_layout);
501 
502   hikari_cursor_configure_bindings(
503       &hikari_server.cursor, &hikari_configuration->mouse_binding_configs);
504 }
505 
506 static void
server_decoration_mode_handler(struct wl_listener * listener,void * data)507 server_decoration_mode_handler(struct wl_listener *listener, void *data)
508 {
509   struct hikari_view_decoration *decoration =
510       wl_container_of(listener, decoration, mode);
511   struct hikari_view *view = decoration->view;
512 
513   view->use_csd = decoration->wlr_decoration->mode ==
514                   WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
515 
516   if (view->use_csd) {
517     view->border.state = HIKARI_BORDER_NONE;
518     hikari_output_damage_whole(hikari_server.workspace->output);
519   }
520 }
521 
522 static void
server_decoration_handler(struct wl_listener * listener,void * data)523 server_decoration_handler(struct wl_listener *listener, void *data)
524 {
525   struct wlr_server_decoration *wlr_decoration = data;
526   struct hikari_view *view =
527       wl_container_of(wlr_decoration->surface, view, surface);
528   struct wlr_xdg_surface *xdg_surface =
529       wlr_xdg_surface_from_wlr_surface(wlr_decoration->surface);
530   struct hikari_xdg_view *xdg_view = xdg_surface->data;
531 
532   if (xdg_view == NULL) {
533     return;
534   }
535 
536   wl_signal_add(&wlr_decoration->events.mode, &xdg_view->view.decoration.mode);
537   xdg_view->view.decoration.mode.notify = server_decoration_mode_handler;
538 
539   xdg_view->view.decoration.wlr_decoration = wlr_decoration;
540   xdg_view->view.decoration.view = &xdg_view->view;
541 }
542 
543 static void
new_toplevel_decoration_handler(struct wl_listener * listener,void * data)544 new_toplevel_decoration_handler(struct wl_listener *listener, void *data)
545 {
546   struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration = data;
547 
548   struct hikari_decoration *decoration =
549       hikari_malloc(sizeof(struct hikari_decoration));
550 
551   hikari_decoration_init(decoration, wlr_decoration);
552 }
553 
554 static void
setup_decorations(struct hikari_server * server)555 setup_decorations(struct hikari_server *server)
556 {
557   server->decoration_manager =
558       wlr_server_decoration_manager_create(server->display);
559 
560   wlr_server_decoration_manager_set_default_mode(
561       server->decoration_manager, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
562 
563   wl_signal_add(&server->decoration_manager->events.new_decoration,
564       &server->new_decoration);
565   server->new_decoration.notify = server_decoration_handler;
566 
567   server->xdg_decoration_manager =
568       wlr_xdg_decoration_manager_v1_create(server->display);
569   wl_signal_add(&server->xdg_decoration_manager->events.new_toplevel_decoration,
570       &server->new_toplevel_decoration);
571   server->new_toplevel_decoration.notify = new_toplevel_decoration_handler;
572 }
573 
574 static void
start_drag_handler(struct wl_listener * listener,void * data)575 start_drag_handler(struct wl_listener *listener, void *data)
576 {
577   struct wlr_surface *surface;
578   struct hikari_workspace *workspace;
579   double sx, sy;
580 
581   struct hikari_node *node = node_at(hikari_server.cursor.wlr_cursor->x,
582       hikari_server.cursor.wlr_cursor->y,
583       &surface,
584       &workspace,
585       &sx,
586       &sy);
587 
588   if (node != NULL) {
589     hikari_dnd_mode_enter();
590   }
591 }
592 
593 static void
request_start_drag_handler(struct wl_listener * listener,void * data)594 request_start_drag_handler(struct wl_listener *listener, void *data)
595 {
596   struct hikari_server *server =
597       wl_container_of(listener, server, request_start_drag);
598   struct wlr_seat_request_start_drag_event *event = data;
599 
600   if (wlr_seat_validate_pointer_grab_serial(
601           server->seat, event->origin, event->serial)) {
602     wlr_seat_start_pointer_drag(server->seat, event->drag, event->serial);
603   } else {
604     wlr_data_source_destroy(event->drag->source);
605   }
606 }
607 
608 static void
setup_selection(struct hikari_server * server)609 setup_selection(struct hikari_server *server)
610 {
611   wlr_data_control_manager_v1_create(server->display);
612 
613   wlr_gtk_primary_selection_device_manager_create(server->display);
614   wlr_primary_selection_v1_device_manager_create(server->display);
615 
616   server->seat = wlr_seat_create(server->display, "seat0");
617   assert(server->seat != NULL);
618 
619   server->request_set_primary_selection.notify =
620       request_set_primary_selection_handler;
621   wl_signal_add(&server->seat->events.request_set_primary_selection,
622       &server->request_set_primary_selection);
623 
624   server->request_set_selection.notify = request_set_selection_handler;
625   wl_signal_add(&server->seat->events.request_set_selection,
626       &server->request_set_selection);
627 
628   server->request_start_drag.notify = request_start_drag_handler;
629   wl_signal_add(
630       &server->seat->events.request_start_drag, &server->request_start_drag);
631 
632   server->start_drag.notify = start_drag_handler;
633   wl_signal_add(&server->seat->events.start_drag, &server->start_drag);
634 }
635 
636 static void
new_xdg_surface_handler(struct wl_listener * listener,void * data)637 new_xdg_surface_handler(struct wl_listener *listener, void *data)
638 {
639   struct hikari_server *server =
640       wl_container_of(listener, server, new_xdg_surface);
641 
642   struct wlr_xdg_surface *xdg_surface = data;
643 
644   if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
645     return;
646   }
647 
648   struct hikari_xdg_view *xdg_view =
649       hikari_malloc(sizeof(struct hikari_xdg_view));
650 
651   hikari_xdg_view_init(xdg_view, xdg_surface, server->workspace);
652 }
653 
654 static void
setup_xdg_shell(struct hikari_server * server)655 setup_xdg_shell(struct hikari_server *server)
656 {
657   server->xdg_shell = wlr_xdg_shell_create(server->display);
658 
659   server->new_xdg_surface.notify = new_xdg_surface_handler;
660   wl_signal_add(
661       &server->xdg_shell->events.new_surface, &server->new_xdg_surface);
662 }
663 
664 #ifdef HAVE_LAYERSHELL
665 static void
new_layer_shell_surface_handler(struct wl_listener * listener,void * data)666 new_layer_shell_surface_handler(struct wl_listener *listener, void *data)
667 {
668   struct wlr_layer_surface_v1 *wlr_layer_surface =
669       (struct wlr_layer_surface_v1 *)data;
670   struct hikari_layer *layer = hikari_malloc(sizeof(struct hikari_layer));
671 
672   hikari_layer_init(layer, wlr_layer_surface);
673 }
674 
675 static void
setup_layer_shell(struct hikari_server * server)676 setup_layer_shell(struct hikari_server *server)
677 {
678   server->layer_shell = wlr_layer_shell_v1_create(server->display);
679 
680   wl_signal_add(&server->layer_shell->events.new_surface,
681       &server->new_layer_shell_surface);
682   server->new_layer_shell_surface.notify = new_layer_shell_surface_handler;
683 }
684 #endif
685 
686 struct hikari_server hikari_server;
687 
688 static void
output_layout_change_handler(struct wl_listener * listener,void * data)689 output_layout_change_handler(struct wl_listener *listener, void *data)
690 {
691   struct hikari_server *server =
692       wl_container_of(listener, server, output_layout_change);
693 
694   struct hikari_output *output;
695   wl_list_for_each (output, &server->outputs, server_outputs) {
696     struct wlr_output *wlr_output = output->wlr_output;
697     struct wlr_box *output_box =
698         wlr_output_layout_get_box(hikari_server.output_layout, wlr_output);
699 
700     output->geometry.x = output_box->x;
701     output->geometry.y = output_box->y;
702     output->geometry.width = output_box->width;
703     output->geometry.height = output_box->height;
704 
705     struct hikari_output_config *output_config =
706         hikari_configuration_resolve_output_config(
707             hikari_configuration, wlr_output->name);
708 
709     if (output_config != NULL) {
710       hikari_output_load_background(output,
711           output_config->background.value,
712           output_config->background_fit.value);
713     }
714 
715 #ifdef HAVE_XWAYLAND
716     hikari_output_rearrange_xwayland_views(output);
717 #endif
718   }
719 }
720 
721 static bool
drop_privileges(struct hikari_server * server)722 drop_privileges(struct hikari_server *server)
723 {
724   if (getuid() != geteuid() || getgid() != getegid()) {
725     if (setuid(getuid()) != 0 || setgid(getgid()) != 0) {
726       return false;
727     }
728   }
729 
730   if (geteuid() == 0 || getegid() == 0) {
731     fprintf(stderr, "running as root is prohibited\n");
732     return false;
733   }
734 
735   return true;
736 }
737 
738 void
hikari_server_prepare_privileged(void)739 hikari_server_prepare_privileged(void)
740 {
741   bool success = false;
742   struct hikari_server *server = &hikari_server;
743 
744   server->display = wl_display_create();
745   if (server->display == NULL) {
746     fprintf(stderr, "error: could not create display\n");
747     goto done;
748   }
749 
750   server->event_loop = wl_display_get_event_loop(server->display);
751   if (server->event_loop == NULL) {
752     fprintf(stderr, "error: could not create event loop\n");
753     goto done;
754   }
755 
756   server->backend = wlr_backend_autocreate(server->display, NULL);
757   if (server->backend == NULL) {
758     fprintf(stderr, "error: could not create backend\n");
759     goto done;
760   }
761 
762   success = true;
763 
764 done:
765   if (!drop_privileges(server) || !success) {
766     if (server->display != NULL) {
767       wl_display_destroy(server->display);
768     }
769 
770     exit(EXIT_FAILURE);
771   }
772 }
773 
774 static void
init_noop_output(struct hikari_server * server)775 init_noop_output(struct hikari_server *server)
776 {
777   server->noop_backend = wlr_noop_backend_create(server->display);
778 
779   struct wlr_output *wlr_output = wlr_noop_add_output(server->noop_backend);
780 
781   server->noop_output = hikari_malloc(sizeof(struct hikari_output));
782   hikari_output_init(server->noop_output, wlr_output);
783 }
784 
785 static void
server_init(struct hikari_server * server,char * config_path)786 server_init(struct hikari_server *server, char *config_path)
787 {
788 #ifndef NDEBUG
789   server->track_damage = false;
790 #endif
791   server->shutdown_timer = NULL;
792   server->config_path = config_path;
793 
794   hikari_configuration = hikari_malloc(sizeof(struct hikari_configuration));
795 
796   hikari_configuration_init(hikari_configuration);
797 
798   if (!hikari_configuration_load(hikari_configuration, config_path)) {
799     hikari_configuration_fini(hikari_configuration);
800     hikari_free(hikari_configuration);
801 
802     wl_display_destroy(server->display);
803     exit(EXIT_FAILURE);
804   }
805 
806   server->keyboard_state.modifiers = 0;
807   server->keyboard_state.mod_released = false;
808   server->keyboard_state.mod_changed = false;
809   server->keyboard_state.mod_pressed = false;
810 
811   server->cycling = false;
812   server->workspace = NULL;
813 
814   hikari_indicator_init(
815       &server->indicator, hikari_configuration->indicator_selected);
816 
817   wl_list_init(&server->outputs);
818 
819   signal(SIGPIPE, SIG_IGN);
820 
821   server->renderer = wlr_backend_get_renderer(server->backend);
822 
823   if (server->renderer == NULL) {
824     wl_display_destroy(server->display);
825     exit(EXIT_FAILURE);
826   }
827 
828   wlr_renderer_init_wl_display(server->renderer, server->display);
829 
830   server->socket = wl_display_add_socket_auto(server->display);
831   if (server->socket == NULL) {
832     wl_display_destroy(server->display);
833     exit(EXIT_FAILURE);
834   }
835 
836   setenv("WAYLAND_DISPLAY", server->socket, true);
837 
838   server->compositor = wlr_compositor_create(server->display, server->renderer);
839 
840   server->data_device_manager = wlr_data_device_manager_create(server->display);
841 
842   server->new_input.notify = new_input_handler;
843   wl_signal_add(&server->backend->events.new_input, &server->new_input);
844 
845   server->output_layout = wlr_output_layout_create();
846   server->output_manager =
847       wlr_xdg_output_manager_v1_create(server->display, server->output_layout);
848 
849   server->output_layout_change.notify = output_layout_change_handler;
850   wl_signal_add(
851       &server->output_layout->events.change, &server->output_layout_change);
852 
853   server->new_output.notify = new_output_handler;
854   wl_signal_add(&server->backend->events.new_output, &server->new_output);
855 
856 #ifdef HAVE_GAMMACONTROL
857   wlr_gamma_control_manager_v1_create(server->display);
858 #endif
859 
860 #ifdef HAVE_SCREENCOPY
861   wlr_screencopy_manager_v1_create(server->display);
862 #endif
863 
864 #ifdef HAVE_XWAYLAND
865   setup_xwayland(server);
866 #endif
867   setup_cursor(server);
868 #ifdef HAVE_VIRTUAL_INPUT
869   setup_virtual_keyboard(server);
870   setup_virtual_pointer(server);
871 #endif
872   setup_decorations(server);
873   setup_selection(server);
874   setup_xdg_shell(server);
875 #ifdef HAVE_LAYERSHELL
876   setup_layer_shell(server);
877 #endif
878 
879   wl_list_init(&server->pointers);
880   wl_list_init(&server->keyboards);
881   wl_list_init(&server->switches);
882 
883   wl_list_init(&server->groups);
884   wl_list_init(&server->visible_groups);
885   wl_list_init(&server->visible_views);
886 
887   hikari_dnd_mode_init(&server->dnd_mode);
888   hikari_group_assign_mode_init(&server->group_assign_mode);
889   hikari_input_grab_mode_init(&server->input_grab_mode);
890   hikari_layout_select_mode_init(&server->layout_select_mode);
891   hikari_lock_mode_init(&server->lock_mode);
892   hikari_mark_assign_mode_init(&server->mark_assign_mode);
893   hikari_mark_select_mode_init(&server->mark_select_mode);
894   hikari_move_mode_init(&server->move_mode);
895   hikari_normal_mode_init(&server->normal_mode);
896   hikari_resize_mode_init(&server->resize_mode);
897   hikari_sheet_assign_mode_init(&server->sheet_assign_mode);
898 
899   hikari_marks_init();
900 
901   init_noop_output(server);
902 }
903 
904 static void
sig_handler(int signal)905 sig_handler(int signal)
906 {
907   hikari_server_terminate(NULL);
908 }
909 
910 static void
run_autostart(char * autostart)911 run_autostart(char *autostart)
912 {
913   hikari_command_execute(autostart);
914   free(autostart);
915 }
916 
917 void
hikari_server_start(char * config_path,char * autostart)918 hikari_server_start(char *config_path, char *autostart)
919 {
920   server_init(&hikari_server, config_path);
921   signal(SIGTERM, sig_handler);
922 
923   wlr_backend_start(hikari_server.backend);
924 
925   if (autostart != NULL) {
926     run_autostart(autostart);
927   }
928 
929   wl_display_run(hikari_server.display);
930 }
931 
932 static int
shutdown_handler(void * data)933 shutdown_handler(void *data)
934 {
935   struct hikari_server *server = &hikari_server;
936 
937   if (server->shutdown_timer == NULL) {
938     return 0;
939   }
940 
941   struct hikari_output *output;
942   wl_list_for_each (output, &server->outputs, server_outputs) {
943     if (!wl_list_empty(&output->views)) {
944       wl_event_source_timer_update(server->shutdown_timer, 1000);
945       return 0;
946     }
947   }
948 
949   wl_display_terminate(hikari_server.display);
950 
951   return 0;
952 }
953 
954 static void
destroy_shutdown_timer(struct hikari_server * server)955 destroy_shutdown_timer(struct hikari_server *server)
956 {
957   wl_event_source_timer_update(server->shutdown_timer, 0);
958   wl_event_source_remove(server->shutdown_timer);
959 
960   server->shutdown_timer = NULL;
961 }
962 
963 void
hikari_server_terminate(void * arg)964 hikari_server_terminate(void *arg)
965 {
966   struct hikari_server *server = &hikari_server;
967 
968   if (server->shutdown_timer != NULL) {
969     destroy_shutdown_timer(server);
970     wl_display_terminate(server->display);
971     return;
972   }
973 
974   struct hikari_output *output;
975   wl_list_for_each (output, &server->outputs, server_outputs) {
976     struct hikari_view *view, *view_temp;
977     wl_list_for_each_safe (view, view_temp, &output->views, output_views) {
978       hikari_view_quit(view);
979     }
980   }
981 
982   server->shutdown_timer =
983       wl_event_loop_add_timer(server->event_loop, shutdown_handler, NULL);
984 
985   wl_event_source_timer_update(server->shutdown_timer, 100);
986 }
987 
988 void
hikari_server_stop(void)989 hikari_server_stop(void)
990 {
991   struct hikari_server *server = &hikari_server;
992 
993   wl_list_remove(&server->new_output.link);
994   wl_list_remove(&server->new_input.link);
995   wl_list_remove(&server->new_xdg_surface.link);
996   wl_list_remove(&server->request_set_primary_selection.link);
997   wl_list_remove(&server->request_start_drag.link);
998   wl_list_remove(&server->start_drag.link);
999   wl_list_remove(&server->output_layout_change.link);
1000 #ifdef HAVE_XWAYLAND
1001   wl_list_remove(&server->new_xwayland_surface.link);
1002 #endif
1003 
1004   if (server->shutdown_timer != NULL) {
1005     destroy_shutdown_timer(server);
1006   }
1007 
1008   hikari_cursor_fini(&server->cursor);
1009   hikari_indicator_fini(&server->indicator);
1010 
1011   hikari_lock_mode_fini(&server->lock_mode);
1012   hikari_mark_assign_mode_fini(&server->mark_assign_mode);
1013 
1014 #if HAVE_XWAYLAND
1015   wlr_xwayland_destroy(server->xwayland);
1016 #endif
1017   wl_display_destroy_clients(server->display);
1018   wlr_seat_destroy(server->seat);
1019   wl_display_destroy(server->display);
1020 
1021   hikari_output_fini(server->noop_output);
1022   hikari_free(server->noop_output);
1023 
1024   wlr_output_layout_destroy(server->output_layout);
1025 
1026   hikari_configuration_fini(hikari_configuration);
1027   hikari_free(hikari_configuration);
1028   hikari_marks_fini();
1029 
1030   free(server->config_path);
1031 }
1032 
1033 struct hikari_group *
hikari_server_find_group(const char * group_name)1034 hikari_server_find_group(const char *group_name)
1035 {
1036   struct hikari_group *group;
1037   wl_list_for_each (group, &hikari_server.groups, server_groups) {
1038     if (!strcmp(group_name, group->name)) {
1039       return group;
1040     }
1041   }
1042 
1043   return NULL;
1044 }
1045 
1046 struct hikari_group *
hikari_server_find_or_create_group(const char * group_name)1047 hikari_server_find_or_create_group(const char *group_name)
1048 {
1049   struct hikari_group *group = hikari_server_find_group(group_name);
1050 
1051   if (group == NULL) {
1052     group = hikari_malloc(sizeof(struct hikari_group));
1053     hikari_group_init(group, group_name);
1054   }
1055 
1056   return group;
1057 }
1058 
1059 void
hikari_server_lock(void * arg)1060 hikari_server_lock(void *arg)
1061 {
1062   hikari_lock_mode_enter();
1063 }
1064 
1065 void
hikari_server_reload(void * arg)1066 hikari_server_reload(void *arg)
1067 {
1068   hikari_configuration_reload(hikari_server.config_path);
1069 }
1070 
1071 #define CYCLE_VIEW(name, link)                                                 \
1072   static struct hikari_view *cycle_##name##_view(void)                         \
1073   {                                                                            \
1074     struct hikari_server *server = &hikari_server;                             \
1075                                                                                \
1076     if (wl_list_empty(&server->visible_views)) {                               \
1077       return NULL;                                                             \
1078     }                                                                          \
1079                                                                                \
1080     struct hikari_view *focus_view = server->workspace->focus_view;            \
1081                                                                                \
1082     struct hikari_view *view;                                                  \
1083     if (focus_view == NULL) {                                                  \
1084       view = wl_container_of(                                                  \
1085           server->visible_views.link, view, visible_server_views);             \
1086     } else {                                                                   \
1087       struct wl_list *link = focus_view->visible_server_views.link;            \
1088       if (link != &server->visible_views) {                                    \
1089         view = wl_container_of(link, view, visible_server_views);              \
1090       } else {                                                                 \
1091         view = wl_container_of(                                                \
1092             server->visible_views.link, view, visible_server_views);           \
1093       }                                                                        \
1094     }                                                                          \
1095                                                                                \
1096     return view;                                                               \
1097   }                                                                            \
1098                                                                                \
1099   void hikari_server_cycle_##name##_view(void *arg)                            \
1100   {                                                                            \
1101     struct hikari_view *view;                                                  \
1102                                                                                \
1103     hikari_server_set_cycling();                                               \
1104     view = cycle_##name##_view();                                              \
1105                                                                                \
1106     if (view != NULL && view != hikari_server.workspace->focus_view) {         \
1107       hikari_workspace_focus_view(view->sheet->workspace, view);               \
1108     }                                                                          \
1109   }
1110 
CYCLE_VIEW(next,prev)1111 CYCLE_VIEW(next, prev)
1112 CYCLE_VIEW(prev, next)
1113 #undef CYCLE_VIEW
1114 
1115 #define CYCLE_ACTION(n)                                                        \
1116   void hikari_server_cycle_##n(void *arg)                                      \
1117   {                                                                            \
1118     struct hikari_view *view;                                                  \
1119                                                                                \
1120     hikari_server_set_cycling();                                               \
1121     view = hikari_workspace_##n(hikari_server.workspace);                      \
1122                                                                                \
1123     if (view != NULL && view != hikari_server.workspace->focus_view) {         \
1124       hikari_workspace_focus_view(view->sheet->workspace, view);               \
1125     }                                                                          \
1126   }
1127 
1128 CYCLE_ACTION(first_group_view)
1129 CYCLE_ACTION(last_group_view)
1130 CYCLE_ACTION(next_group_view)
1131 CYCLE_ACTION(prev_group_view)
1132 CYCLE_ACTION(next_layout_view)
1133 CYCLE_ACTION(prev_layout_view)
1134 CYCLE_ACTION(first_layout_view)
1135 CYCLE_ACTION(last_layout_view)
1136 CYCLE_ACTION(next_group)
1137 CYCLE_ACTION(prev_group)
1138 #undef CYCLE_ACTION
1139 
1140 #define CYCLE_WORKSPACE(link)                                                  \
1141   void hikari_server_cycle_##link##_workspace(void *arg)                       \
1142   {                                                                            \
1143     struct hikari_workspace *workspace = hikari_server.workspace;              \
1144     struct hikari_workspace *link = hikari_workspace_##link(workspace);        \
1145                                                                                \
1146     if (workspace != link) {                                                   \
1147       hikari_server_set_cycling();                                             \
1148                                                                                \
1149       struct hikari_view *view = hikari_workspace_first_view(link);            \
1150       if (view != NULL) {                                                      \
1151         hikari_workspace_focus_view(link, view);                               \
1152         hikari_view_center_cursor(view);                                       \
1153       } else {                                                                 \
1154         hikari_workspace_center_cursor(link);                                  \
1155         hikari_server_cursor_focus();                                          \
1156       }                                                                        \
1157     }                                                                          \
1158   }
1159 
1160 CYCLE_WORKSPACE(next)
1161 CYCLE_WORKSPACE(prev)
1162 #undef CYCLE_WORKSPACE
1163 
1164 static void
1165 update_indication(struct hikari_view *view)
1166 {
1167   assert(view != NULL);
1168   assert(view->group != NULL);
1169 
1170   hikari_group_damage(view->group);
1171   hikari_indicator_damage(&hikari_server.indicator, view);
1172 }
1173 
1174 void
hikari_server_enter_normal_mode(void * arg)1175 hikari_server_enter_normal_mode(void *arg)
1176 {
1177   struct hikari_server *server = &hikari_server;
1178 
1179   hikari_cursor_reset_image(&server->cursor);
1180 
1181   hikari_normal_mode_enter();
1182 
1183   hikari_server_cursor_focus();
1184 }
1185 
1186 void
hikari_server_enter_sheet_assign_mode(void * arg)1187 hikari_server_enter_sheet_assign_mode(void *arg)
1188 {
1189   assert(hikari_server.workspace != NULL);
1190 
1191   struct hikari_workspace *workspace = hikari_server.workspace;
1192   struct hikari_view *focus_view = workspace->focus_view;
1193 
1194   if (focus_view == NULL) {
1195     return;
1196   }
1197 
1198   update_indication(focus_view);
1199 
1200   hikari_sheet_assign_mode_enter(focus_view);
1201 }
1202 
1203 void
hikari_server_enter_move_mode(void * arg)1204 hikari_server_enter_move_mode(void *arg)
1205 {
1206   struct hikari_view *focus_view = hikari_server.workspace->focus_view;
1207 
1208   if (focus_view == NULL) {
1209     return;
1210   }
1211 
1212   update_indication(focus_view);
1213 
1214   hikari_move_mode_enter(focus_view);
1215 }
1216 
1217 void
hikari_server_enter_resize_mode(void * arg)1218 hikari_server_enter_resize_mode(void *arg)
1219 {
1220   struct hikari_view *focus_view = hikari_server.workspace->focus_view;
1221 
1222   if (focus_view == NULL) {
1223     return;
1224   }
1225 
1226   update_indication(focus_view);
1227 
1228   hikari_resize_mode_enter(focus_view);
1229 }
1230 
1231 void
hikari_server_enter_group_assign_mode(void * arg)1232 hikari_server_enter_group_assign_mode(void *arg)
1233 {
1234   struct hikari_view *focus_view = hikari_server.workspace->focus_view;
1235 
1236   if (focus_view == NULL) {
1237     return;
1238   }
1239 
1240   hikari_group_assign_mode_enter(focus_view);
1241 }
1242 
1243 void
hikari_server_enter_input_grab_mode(void * arg)1244 hikari_server_enter_input_grab_mode(void *arg)
1245 {
1246   struct hikari_workspace *workspace = hikari_server.workspace;
1247   struct hikari_view *focus_view = workspace->focus_view;
1248 
1249   if (focus_view == NULL) {
1250     return;
1251   }
1252 
1253   update_indication(focus_view);
1254 
1255   hikari_input_grab_mode_enter(focus_view);
1256 }
1257 
1258 void
hikari_server_enter_mark_select_mode(void * arg)1259 hikari_server_enter_mark_select_mode(void *arg)
1260 {
1261   hikari_mark_select_mode_enter(false);
1262 }
1263 
1264 void
hikari_server_enter_mark_select_switch_mode(void * arg)1265 hikari_server_enter_mark_select_switch_mode(void *arg)
1266 {
1267   hikari_mark_select_mode_enter(true);
1268 }
1269 
1270 void
hikari_server_enter_layout_select_mode(void * arg)1271 hikari_server_enter_layout_select_mode(void *arg)
1272 {
1273   struct hikari_workspace *workspace = hikari_server.workspace;
1274   struct hikari_view *focus_view = workspace->focus_view;
1275 
1276   if (focus_view != NULL) {
1277     update_indication(focus_view);
1278   }
1279 
1280   hikari_layout_select_mode_enter();
1281 }
1282 
1283 void
hikari_server_enter_mark_assign_mode(void * arg)1284 hikari_server_enter_mark_assign_mode(void *arg)
1285 {
1286   assert(hikari_server.workspace != NULL);
1287 
1288   struct hikari_workspace *workspace = hikari_server.workspace;
1289   struct hikari_view *focus_view = workspace->focus_view;
1290 
1291   if (focus_view == NULL) {
1292     return;
1293   }
1294 
1295   update_indication(focus_view);
1296 
1297   hikari_mark_assign_mode_enter(focus_view);
1298 }
1299 
1300 void
hikari_server_execute_command(void * arg)1301 hikari_server_execute_command(void *arg)
1302 {
1303   const char *command = arg;
1304   hikari_command_execute(command);
1305 }
1306 
1307 void
hikari_server_reset_sheet_layout(void * arg)1308 hikari_server_reset_sheet_layout(void *arg)
1309 {
1310   struct hikari_layout *layout = hikari_server.workspace->sheet->layout;
1311 
1312   if (layout == NULL) {
1313     return;
1314   }
1315 
1316   hikari_layout_reset(layout);
1317 }
1318 
1319 void
hikari_server_layout_restack_append(void * arg)1320 hikari_server_layout_restack_append(void *arg)
1321 {
1322   struct hikari_workspace *workspace = hikari_server.workspace;
1323   struct hikari_sheet *sheet = workspace->sheet;
1324   struct hikari_layout *layout = sheet->layout;
1325 
1326   if (layout == NULL) {
1327     struct hikari_split *split = hikari_sheet_default_split(sheet);
1328 
1329     if (split != NULL) {
1330       hikari_sheet_apply_split(sheet, split);
1331     }
1332   } else {
1333     hikari_workspace_display_sheet_current(workspace);
1334     hikari_layout_restack_append(layout);
1335   }
1336 }
1337 
1338 void
hikari_server_layout_restack_prepend(void * arg)1339 hikari_server_layout_restack_prepend(void *arg)
1340 {
1341   struct hikari_workspace *workspace = hikari_server.workspace;
1342   struct hikari_sheet *sheet = workspace->sheet;
1343   struct hikari_layout *layout = sheet->layout;
1344 
1345   if (layout == NULL) {
1346     struct hikari_split *split = hikari_sheet_default_split(sheet);
1347 
1348     if (split != NULL) {
1349       hikari_sheet_apply_split(sheet, split);
1350     }
1351   } else {
1352     hikari_workspace_display_sheet_current(workspace);
1353     hikari_layout_restack_prepend(layout);
1354   }
1355 }
1356 
1357 void
hikari_server_layout_sheet(void * arg)1358 hikari_server_layout_sheet(void *arg)
1359 {
1360   char layout_register = (intptr_t)arg;
1361 
1362   struct hikari_split *split =
1363       hikari_configuration_lookup_layout(hikari_configuration, layout_register);
1364 
1365   if (split != NULL) {
1366     hikari_workspace_apply_split(hikari_server.workspace, split);
1367   }
1368 }
1369 
1370 void
hikari_server_session_change_vt(void * arg)1371 hikari_server_session_change_vt(void *arg)
1372 {
1373   const intptr_t vt = (intptr_t)arg;
1374   assert(vt >= 1 && vt <= 12);
1375 
1376   struct wlr_session *session = wlr_backend_get_session(hikari_server.backend);
1377   if (session != NULL) {
1378     wlr_session_change_vt(session, vt);
1379   }
1380 }
1381 
1382 static void
show_marked_view(struct hikari_view * view,struct hikari_mark * mark)1383 show_marked_view(struct hikari_view *view, struct hikari_mark *mark)
1384 {
1385   if (view != NULL) {
1386     if (hikari_view_is_hidden(view)) {
1387       hikari_view_show(view);
1388     } else {
1389       hikari_view_raise(view);
1390     }
1391 
1392     hikari_view_center_cursor(view);
1393     hikari_server_cursor_focus();
1394   } else {
1395     char *command = hikari_configuration->execs[mark->nr].command;
1396 
1397     if (command != NULL) {
1398       hikari_command_execute(command);
1399     }
1400   }
1401 }
1402 
1403 void
hikari_server_show_mark(void * arg)1404 hikari_server_show_mark(void *arg)
1405 {
1406   assert(arg != NULL);
1407 
1408   struct hikari_mark *mark = (struct hikari_mark *)arg;
1409   struct hikari_view *view = mark->view;
1410 
1411   show_marked_view(view, mark);
1412 }
1413 
1414 void
hikari_server_switch_to_mark(void * arg)1415 hikari_server_switch_to_mark(void *arg)
1416 {
1417   assert(arg != NULL);
1418 
1419   struct hikari_mark *mark = (struct hikari_mark *)arg;
1420   struct hikari_view *view = mark->view;
1421 
1422   if (view != NULL && view->sheet->workspace->sheet != view->sheet) {
1423     hikari_workspace_switch_sheet(view->sheet->workspace, view->sheet);
1424   }
1425 
1426   show_marked_view(view, mark);
1427 }
1428 
1429 void
hikari_server_migrate_focus_view(struct hikari_output * output,double lx,double ly,bool center)1430 hikari_server_migrate_focus_view(
1431     struct hikari_output *output, double lx, double ly, bool center)
1432 {
1433   struct hikari_view *focus_view = hikari_server.workspace->focus_view;
1434 
1435   assert(focus_view != NULL);
1436 
1437   struct hikari_sheet *sheet = output->workspace->sheet;
1438 
1439   hikari_view_migrate(focus_view,
1440       sheet,
1441       lx - output->geometry.x,
1442       ly - output->geometry.y,
1443       center);
1444 
1445   hikari_indicator_update_sheet(
1446       &hikari_server.indicator, output, sheet, focus_view->flags);
1447 
1448   hikari_server.workspace->focus_view = NULL;
1449   hikari_server.workspace = output->workspace;
1450   hikari_server.workspace->focus_view = focus_view;
1451 }
1452 
1453 static void
move_view(int dx,int dy)1454 move_view(int dx, int dy)
1455 {
1456   struct hikari_view *focus_view = hikari_server.workspace->focus_view;
1457 
1458   if (focus_view == NULL) {
1459     return;
1460   }
1461 
1462   struct hikari_output *view_output = focus_view->output;
1463   struct wlr_box *geometry = hikari_view_geometry(focus_view);
1464 
1465   double lx = view_output->geometry.x + geometry->x + dx;
1466   double ly = view_output->geometry.y + geometry->y + dy;
1467 
1468   struct wlr_output *wlr_output =
1469       wlr_output_layout_output_at(hikari_server.output_layout, lx, ly);
1470 
1471   hikari_server_set_cycling();
1472 
1473   if (wlr_output == NULL || wlr_output->data == view_output) {
1474     hikari_view_move(focus_view, dx, dy);
1475   } else {
1476     hikari_server_migrate_focus_view(wlr_output->data, lx, ly, false);
1477   }
1478 }
1479 
1480 void
hikari_server_move_view_up(void * arg)1481 hikari_server_move_view_up(void *arg)
1482 {
1483   const int step = hikari_configuration->step;
1484   move_view(0, -step);
1485 }
1486 
1487 void
hikari_server_move_view_down(void * arg)1488 hikari_server_move_view_down(void *arg)
1489 {
1490   const int step = hikari_configuration->step;
1491   move_view(0, step);
1492 }
1493 
1494 void
hikari_server_move_view_left(void * arg)1495 hikari_server_move_view_left(void *arg)
1496 {
1497   const int step = hikari_configuration->step;
1498   move_view(-step, 0);
1499 }
1500 
1501 void
hikari_server_move_view_right(void * arg)1502 hikari_server_move_view_right(void *arg)
1503 {
1504   const int step = hikari_configuration->step;
1505   move_view(step, 0);
1506 }
1507 
1508 static void
move_resize_view(int dx,int dy,int dwidth,int dheight)1509 move_resize_view(int dx, int dy, int dwidth, int dheight)
1510 {
1511   struct hikari_view *focus_view = hikari_server.workspace->focus_view;
1512 
1513   if (focus_view == NULL) {
1514     return;
1515   }
1516 
1517   struct hikari_output *view_output = focus_view->output;
1518   struct wlr_box *geometry = hikari_view_geometry(focus_view);
1519 
1520   double lx = view_output->geometry.x + geometry->x + dy;
1521   double ly = view_output->geometry.y + geometry->y + dy;
1522 
1523   struct wlr_output *wlr_output =
1524       wlr_output_layout_output_at(hikari_server.output_layout, lx, ly);
1525 
1526   hikari_server_set_cycling();
1527 
1528   if (wlr_output == NULL || wlr_output->data == view_output) {
1529     hikari_view_move_resize(focus_view, dx, dy, dwidth, dheight);
1530   } else {
1531     hikari_server_migrate_focus_view(wlr_output->data, lx, ly, false);
1532     hikari_view_resize(focus_view, dheight, dwidth);
1533   }
1534 }
1535 
1536 void
hikari_server_decrease_view_size_down(void * arg)1537 hikari_server_decrease_view_size_down(void *arg)
1538 {
1539   const int step = hikari_configuration->step;
1540   move_resize_view(0, step, 0, -step);
1541 }
1542 
1543 void
hikari_server_decrease_view_size_right(void * arg)1544 hikari_server_decrease_view_size_right(void *arg)
1545 {
1546   const int step = hikari_configuration->step;
1547   move_resize_view(step, 0, -step, 0);
1548 }
1549 
1550 void
hikari_server_increase_view_size_up(void * arg)1551 hikari_server_increase_view_size_up(void *arg)
1552 {
1553   const int step = hikari_configuration->step;
1554   move_resize_view(0, -step, 0, step);
1555 }
1556 
1557 void
hikari_server_increase_view_size_left(void * arg)1558 hikari_server_increase_view_size_left(void *arg)
1559 {
1560   const int step = hikari_configuration->step;
1561   move_resize_view(-step, 0, step, 0);
1562 }
1563 
1564 #ifndef NDEBUG
1565 void
hikari_server_toggle_damage_tracking(void * arg)1566 hikari_server_toggle_damage_tracking(void *arg)
1567 {
1568   hikari_server.track_damage = !hikari_server.track_damage;
1569 
1570   struct hikari_output *output = NULL;
1571   wl_list_for_each (output, &hikari_server.outputs, server_outputs) {
1572     hikari_output_damage_whole(output);
1573   }
1574 }
1575 #endif
1576