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