Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
src/server/wlroots_log_wrapper.c (40.2K)
1 // SPDX-FileCopyrightText: © 2021 The River Developers
2 // SPDX-License-Identifier: GPL-3.0-only
3
4 #define _POSIX_C_SOURCE 199309L
5 #include <assert.h>
6 #include <math.h>
7 #include <stdarg.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10
11 #include <wlr/util/log.h>
12 #include <wlr/backend/session.h>
13
14 #define BUFFER_SIZE 1024
15
16 void river_wlroots_log_callback(enum wlr_log_importance importance, const char *ptr, size_t len);
17
18 static void callback(enum wlr_log_importance importance, const char *fmt, va_list args) {
19 char buffer[BUFFER_SIZE];
20
21 // Need to make a copy of the args in case our buffer isn't big
22 // enough and we need to use them again.
23 va_list args_copy;
24 va_copy(args_copy, args);
25
26 const int length = vsnprintf(buffer, BUFFER_SIZE, fmt, args);
27 // Need to add one for the terminating 0 byte
28 if (length + 1 <= BUFFER_SIZE) {
29 // The formatted string fit within our buffer, pass it on to river
30 river_wlroots_log_callback(importance, buffer, length);
31 } else {
32 // The formatted string did not fit in our buffer, we need
33 // to allocate enough memory to hold it.
34 char *allocated_buffer = malloc(length + 1);
35 if (allocated_buffer != NULL) {
36 const int length2 = vsnprintf(allocated_buffer, length + 1, fmt, args_copy);
37 assert(length2 == length);
38 river_wlroots_log_callback(importance, allocated_buffer, length);
39 free(allocated_buffer);
40 }
41 }
42
43 va_end(args_copy);
44 }
45
46 void river_init_wlroots_log(enum wlr_log_importance importance) {
47 wlr_log_init(importance, callback);
48 }
49
50 #include <time.h>
51 #include <scenefx/types/wlr_scene.h>
52 #include <wlr/types/wlr_buffer.h>
53 #include <wlr/interfaces/wlr_buffer.h>
54 #include <drm_fourcc.h>
55 #include <wlr/types/wlr_output.h>
56 #include <wlr/util/region.h>
57 #include <wlr/types/wlr_compositor.h>
58 #include <wlr/types/wlr_input_device.h>
59 #include <wlr/types/wlr_keyboard.h>
60 #include <wlr/interfaces/wlr_keyboard.h>
61 #include <wlr/types/wlr_cursor.h>
62 #include <wlr/types/wlr_seat.h>
63 #include <wlr/types/wlr_pointer.h>
64 #include <wlr/types/wlr_tablet_v2.h>
65 #include <wlr/backend.h>
66 #include <wlr/types/wlr_xdg_shell.h>
67 #include <wlr/types/wlr_input_method_v2.h>
68 #include <wlr/types/wlr_data_device.h>
69
70 struct wlr_surface *river_scene_node_get_surface(struct wlr_scene_node *node) {
71 if (node->type == WLR_SCENE_NODE_BUFFER) {
72 struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
73 struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer);
74 if (scene_surface) {
75 return scene_surface->surface;
76 }
77 }
78 return NULL;
79 }
80
81 enum wlr_scene_node_type river_scene_node_get_type(struct wlr_scene_node *node) {
82 return node->type;
83 }
84
85 struct wlr_scene_tree *river_scene_node_get_parent(struct wlr_scene_node *node) {
86 return node->parent;
87 }
88
89 int river_scene_node_get_x(struct wlr_scene_node *node) {
90 return node->x;
91 }
92
93 int river_scene_node_get_y(struct wlr_scene_node *node) {
94 return node->y;
95 }
96
97 void *river_scene_node_get_data(struct wlr_scene_node *node) {
98 return node->data;
99 }
100
101 void river_scene_node_set_data(struct wlr_scene_node *node, void *data) {
102 node->data = data;
103 }
104
105 struct wl_signal *river_scene_node_get_destroy_signal(struct wlr_scene_node *node) {
106 return &node->events.destroy;
107 }
108
109 static void save_surface_tree_iter(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
110 struct wlr_scene_tree *saved_tree = user_data;
111 struct wlr_scene_tree *buffer_tree = wlr_scene_tree_create(saved_tree);
112 if (!buffer_tree) {
113 return;
114 }
115 wlr_scene_node_set_position(&buffer_tree->node, sx, sy);
116 struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create(buffer_tree, buffer->buffer);
117 if (!scene_buffer) {
118 wlr_scene_node_destroy(&buffer_tree->node);
119 return;
120 }
121 wlr_scene_node_set_position(&scene_buffer->node, 0, 0);
122 wlr_scene_buffer_set_dest_size(scene_buffer, buffer->dst_width, buffer->dst_height);
123 wlr_scene_buffer_set_source_box(scene_buffer, &buffer->src_box);
124 wlr_scene_buffer_set_transform(scene_buffer, buffer->transform);
125 }
126
127 void river_scene_tree_save_buffers(struct wlr_scene_tree *tree, struct wlr_scene_tree *saved_tree) {
128 wlr_scene_node_for_each_buffer(&tree->node, save_surface_tree_iter, saved_tree);
129 }
130
131 void river_scene_tree_clear_children(struct wlr_scene_tree *tree) {
132 struct wlr_scene_node *child, *tmp;
133 wl_list_for_each_safe(child, tmp, &tree->children, link) {
134 wlr_scene_node_destroy(child);
135 }
136 }
137
138 struct wlr_scene_node *river_scene_node_from_children_link(struct wl_list *link) {
139 return wl_container_of(link, (struct wlr_scene_node *)NULL, link);
140 }
141
142 struct wl_signal *river_wlr_output_get_destroy_signal(struct wlr_output *output) {
143 return &output->events.destroy;
144 }
145
146 struct wl_signal *river_wlr_output_get_request_state_signal(struct wlr_output *output) {
147 return &output->events.request_state;
148 }
149
150 struct wl_signal *river_wlr_output_get_frame_signal(struct wlr_output *output) {
151 return &output->events.frame;
152 }
153
154 struct wl_signal *river_wlr_output_get_present_signal(struct wlr_output *output) {
155 return &output->events.present;
156 }
157
158 void *river_wlr_output_get_data(struct wlr_output *output) {
159 return output->data;
160 }
161
162 void river_wlr_output_set_data(struct wlr_output *output, void *data) {
163 output->data = data;
164 }
165
166 const char *river_wlr_output_get_name(struct wlr_output *output) {
167 return output->name;
168 }
169
170 enum wlr_output_adaptive_sync_status river_wlr_output_get_adaptive_sync_status(struct wlr_output *output) {
171 return output->adaptive_sync_status;
172 }
173
174 bool river_wlr_output_get_enabled(struct wlr_output *output) {
175 return output->enabled;
176 }
177
178 struct wlr_output_mode *river_wlr_output_get_current_mode(struct wlr_output *output) {
179 return output->current_mode;
180 }
181
182 void river_wlr_output_get_phys_size(struct wlr_output *output, int32_t *width_mm, int32_t *height_mm) {
183 *width_mm = output->phys_width;
184 *height_mm = output->phys_height;
185 }
186
187 void river_wlr_output_set_phys_size(struct wlr_output *output, int32_t width_mm, int32_t height_mm) {
188 output->phys_width = width_mm;
189 output->phys_height = height_mm;
190 }
191
192 int32_t river_wlr_output_get_width(struct wlr_output *output) {
193 return output->width;
194 }
195
196 int32_t river_wlr_output_get_height(struct wlr_output *output) {
197 return output->height;
198 }
199
200 int32_t river_wlr_output_get_refresh(struct wlr_output *output) {
201 return output->refresh;
202 }
203
204 struct wl_global *river_wlr_output_get_global(struct wlr_output *output) {
205 return output->global;
206 }
207
208 void *river_wlr_surface_get_data(struct wlr_surface *surface) {
209 return surface->data;
210 }
211
212 void river_wlr_surface_set_data(struct wlr_surface *surface, void *data) {
213 surface->data = data;
214 }
215
216 struct wl_signal *river_wlr_surface_get_commit_signal(struct wlr_surface *surface) {
217 return &surface->events.commit;
218 }
219
220 struct wl_signal *river_wlr_surface_get_destroy_signal(struct wlr_surface *surface) {
221 return &surface->events.destroy;
222 }
223
224 // Show a surface at 1/scale of the size it committed itself at.
225 //
226 // For the cursor surface of an X11 client. Xwayland always commits its cursor
227 // at buffer scale 1, and wlr_cursor sizes the pointer from `current.width` --
228 // the surface's LOGICAL size -- so an N-pixel X cursor comes out N logical
229 // pixels, twice as big as everything else on a scale-2 panel. Under
230 // `xwayland_hidpi` X11 is a physical-pixel world and an X11 window's own
231 // buffer is already drawn at 1/scale (Window::x11_buffer_scale); this puts its
232 // cursor in the same world. Derived from the buffer, so applying it twice to
233 // one committed state is a no-op.
234 void river_wlr_surface_scale_logical_size(struct wlr_surface *surface, float scale) {
235 if (surface == NULL || scale <= 0.0f || scale == 1.0f) {
236 return;
237 }
238 float total = (float)surface->current.scale * scale;
239 surface->current.width = (int)roundf((float)surface->current.buffer_width / total);
240 surface->current.height = (int)roundf((float)surface->current.buffer_height / total);
241 }
242
243 enum wlr_input_device_type river_wlr_input_device_get_type(struct wlr_input_device *dev) {
244 return dev->type;
245 }
246
247 const char *river_wlr_input_device_get_name(struct wlr_input_device *dev) {
248 return dev->name;
249 }
250
251 struct wl_signal *river_wlr_input_device_get_destroy_signal(struct wlr_input_device *dev) {
252 return &dev->events.destroy;
253 }
254
255 void *river_wlr_input_device_get_data(struct wlr_input_device *dev) {
256 return dev->data;
257 }
258
259 void river_wlr_input_device_set_data(struct wlr_input_device *dev, void *data) {
260 dev->data = data;
261 }
262
263 struct wl_signal *river_wlr_keyboard_get_key_signal(struct wlr_keyboard *kbd) {
264 return &kbd->events.key;
265 }
266
267 struct wl_signal *river_wlr_keyboard_get_modifiers_signal(struct wlr_keyboard *kbd) {
268 return &kbd->events.modifiers;
269 }
270
271 struct wl_signal *river_wlr_keyboard_get_keymap_signal(struct wlr_keyboard *kbd) {
272 return &kbd->events.keymap;
273 }
274
275 struct xkb_keymap *river_wlr_keyboard_get_keymap(struct wlr_keyboard *kbd) {
276 return kbd->keymap;
277 }
278
279 struct wlr_keyboard_modifiers *river_wlr_keyboard_get_modifiers(struct wlr_keyboard *kbd) {
280 return &kbd->modifiers;
281 }
282
283 void *river_wlr_keyboard_get_data(struct wlr_keyboard *kbd) {
284 return kbd->data;
285 }
286
287 void river_wlr_keyboard_set_data(struct wlr_keyboard *kbd, void *data) {
288 kbd->data = data;
289 }
290
291 double river_wlr_cursor_get_x(struct wlr_cursor *cursor) {
292 return cursor->x;
293 }
294
295 double river_wlr_cursor_get_y(struct wlr_cursor *cursor) {
296 return cursor->y;
297 }
298
299 struct wl_signal *river_wlr_cursor_get_motion_signal(struct wlr_cursor *cursor) {
300 return &cursor->events.motion;
301 }
302
303 struct wl_signal *river_wlr_cursor_get_motion_absolute_signal(struct wlr_cursor *cursor) {
304 return &cursor->events.motion_absolute;
305 }
306
307 struct wl_signal *river_wlr_cursor_get_button_signal(struct wlr_cursor *cursor) {
308 return &cursor->events.button;
309 }
310
311 struct wl_signal *river_wlr_cursor_get_axis_signal(struct wlr_cursor *cursor) {
312 return &cursor->events.axis;
313 }
314
315 struct wl_signal *river_wlr_cursor_get_frame_signal(struct wlr_cursor *cursor) {
316 return &cursor->events.frame;
317 }
318
319 struct wl_signal *river_wlr_cursor_get_swipe_begin_signal(struct wlr_cursor *cursor) {
320 return &cursor->events.swipe_begin;
321 }
322
323 struct wl_signal *river_wlr_cursor_get_swipe_update_signal(struct wlr_cursor *cursor) {
324 return &cursor->events.swipe_update;
325 }
326
327 struct wl_signal *river_wlr_cursor_get_swipe_end_signal(struct wlr_cursor *cursor) {
328 return &cursor->events.swipe_end;
329 }
330
331 struct wl_signal *river_wlr_cursor_get_pinch_begin_signal(struct wlr_cursor *cursor) {
332 return &cursor->events.pinch_begin;
333 }
334
335 struct wl_signal *river_wlr_cursor_get_pinch_update_signal(struct wlr_cursor *cursor) {
336 return &cursor->events.pinch_update;
337 }
338
339 struct wl_signal *river_wlr_cursor_get_pinch_end_signal(struct wlr_cursor *cursor) {
340 return &cursor->events.pinch_end;
341 }
342
343 struct wl_signal *river_wlr_cursor_get_hold_begin_signal(struct wlr_cursor *cursor) {
344 return &cursor->events.hold_begin;
345 }
346
347 struct wl_signal *river_wlr_cursor_get_hold_end_signal(struct wlr_cursor *cursor) {
348 return &cursor->events.hold_end;
349 }
350
351 struct wl_signal *river_wlr_cursor_get_touch_down_signal(struct wlr_cursor *cursor) {
352 return &cursor->events.touch_down;
353 }
354
355 struct wl_signal *river_wlr_cursor_get_touch_motion_signal(struct wlr_cursor *cursor) {
356 return &cursor->events.touch_motion;
357 }
358
359 struct wl_signal *river_wlr_cursor_get_touch_up_signal(struct wlr_cursor *cursor) {
360 return &cursor->events.touch_up;
361 }
362
363 struct wl_signal *river_wlr_cursor_get_touch_cancel_signal(struct wlr_cursor *cursor) {
364 return &cursor->events.touch_cancel;
365 }
366
367 struct wl_signal *river_wlr_cursor_get_touch_frame_signal(struct wlr_cursor *cursor) {
368 return &cursor->events.touch_frame;
369 }
370
371 struct wl_signal *river_wlr_cursor_get_tablet_tool_axis_signal(struct wlr_cursor *cursor) {
372 return &cursor->events.tablet_tool_axis;
373 }
374
375 struct wl_signal *river_wlr_cursor_get_tablet_tool_proximity_signal(struct wlr_cursor *cursor) {
376 return &cursor->events.tablet_tool_proximity;
377 }
378
379 struct wl_signal *river_wlr_cursor_get_tablet_tool_tip_signal(struct wlr_cursor *cursor) {
380 return &cursor->events.tablet_tool_tip;
381 }
382
383 struct wl_signal *river_wlr_cursor_get_tablet_tool_button_signal(struct wlr_cursor *cursor) {
384 return &cursor->events.tablet_tool_button;
385 }
386
387 const char *river_wlr_seat_get_name(struct wlr_seat *seat) {
388 return seat->name;
389 }
390
391 void *river_wlr_seat_get_data(struct wlr_seat *seat) {
392 return seat->data;
393 }
394
395 void river_wlr_seat_set_data(struct wlr_seat *seat, void *data) {
396 seat->data = data;
397 }
398
399 struct wl_signal *river_wlr_seat_get_request_set_cursor_signal(struct wlr_seat *seat) {
400 return &seat->events.request_set_cursor;
401 }
402
403 struct wl_signal *river_wlr_seat_get_request_set_selection_signal(struct wlr_seat *seat) {
404 return &seat->events.request_set_selection;
405 }
406
407 struct wl_signal *river_wlr_seat_get_request_start_drag_signal(struct wlr_seat *seat) {
408 return &seat->events.request_start_drag;
409 }
410
411 struct wl_signal *river_wlr_seat_get_start_drag_signal(struct wlr_seat *seat) {
412 return &seat->events.start_drag;
413 }
414
415 struct wl_signal *river_wlr_seat_get_request_set_primary_selection_signal(struct wlr_seat *seat) {
416 return &seat->events.request_set_primary_selection;
417 }
418
419 struct wlr_seat_client *river_wlr_seat_get_pointer_focused_client(struct wlr_seat *seat) {
420 return seat->pointer_state.focused_client;
421 }
422
423 struct wlr_surface *river_wlr_seat_get_pointer_focused_surface(struct wlr_seat *seat) {
424 return seat->pointer_state.focused_surface;
425 }
426
427 /* Damage the whole output and schedule a frame — the public-field replica of
428 * scenefx's internal scene_output_damage_whole(). Viewport zoom re-lays-out
429 * the entire screen, but per-node damage under-reports at the seams (stale
430 * slivers of the previous zoom level survive), so camera motion forces a
431 * full repaint. */
432 void river_scene_output_damage_whole(struct wlr_scene_output *scene_output) {
433 struct wlr_output *output = scene_output->output;
434 pixman_region32_t damage;
435 pixman_region32_init_rect(&damage, 0, 0, output->width, output->height);
436 wlr_output_schedule_frame(output);
437 wlr_damage_ring_add(&scene_output->damage_ring, &damage);
438 /* pending_commit_damage lives in the WLR_PRIVATE member — reaching in is
439 * the same deal as the pointer_state accesses elsewhere in this file. */
440 pixman_region32_union(&scene_output->WLR_PRIVATE.pending_commit_damage,
441 &scene_output->WLR_PRIVATE.pending_commit_damage, &damage);
442 pixman_region32_fini(&damage);
443 }
444
445 struct wl_client *river_wlr_seat_client_get_client(struct wlr_seat_client *client) {
446 return client->client;
447 }
448
449 struct wlr_keyboard *river_wlr_seat_get_keyboard(struct wlr_seat *seat) {
450 return seat->keyboard_state.keyboard;
451 }
452
453 struct wl_global *river_wlr_seat_get_global(struct wlr_seat *seat) {
454 return seat->global;
455 }
456
457 struct wl_signal *river_wlr_backend_get_new_input_signal(struct wlr_backend *backend) {
458 return &backend->events.new_input;
459 }
460
461 const struct wlr_surface_role *river_wlr_surface_get_role(struct wlr_surface *surface) {
462 return surface->role;
463 }
464
465 struct wl_resource *river_wlr_surface_get_role_resource(struct wlr_surface *surface) {
466 return surface->role_resource;
467 }
468
469 void river_wlr_surface_set_role_object(struct wlr_surface *surface, struct wl_resource *role_resource) {
470 surface->role_resource = role_resource;
471 }
472
473 struct wlr_surface *river_wlr_xdg_surface_get_surface(struct wlr_xdg_surface *xdg_surface) {
474 return xdg_surface->surface;
475 }
476
477 struct wl_signal *river_wlr_xdg_surface_get_ack_configure_signal(struct wlr_xdg_surface *xdg_surface) {
478 return &xdg_surface->events.ack_configure;
479 }
480
481 struct wl_signal *river_wlr_xdg_surface_get_new_popup_signal(struct wlr_xdg_surface *xdg_surface) {
482 return &xdg_surface->events.new_popup;
483 }
484
485 void river_wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *xdg_surface, struct wlr_box *box) {
486 *box = xdg_surface->geometry;
487 }
488
489 bool river_wlr_xdg_surface_get_initial_commit(struct wlr_xdg_surface *xdg_surface) {
490 return xdg_surface->initial_commit;
491 }
492
493 bool river_wlr_xdg_surface_get_initialized(struct wlr_xdg_surface *xdg_surface) {
494 return xdg_surface->initialized;
495 }
496
497 struct wlr_xdg_surface *river_wlr_xdg_toplevel_get_base(struct wlr_xdg_toplevel *toplevel) {
498 return toplevel->base;
499 }
500
501 struct wl_signal *river_wlr_xdg_toplevel_get_destroy_signal(struct wlr_xdg_toplevel *toplevel) {
502 return &toplevel->events.destroy;
503 }
504
505 struct wl_signal *river_wlr_xdg_toplevel_get_request_show_window_menu_signal(struct wlr_xdg_toplevel *toplevel) {
506 return &toplevel->events.request_show_window_menu;
507 }
508
509 struct wl_signal *river_wlr_xdg_toplevel_get_request_fullscreen_signal(struct wlr_xdg_toplevel *toplevel) {
510 return &toplevel->events.request_fullscreen;
511 }
512
513 struct wl_signal *river_wlr_xdg_toplevel_get_request_maximize_signal(struct wlr_xdg_toplevel *toplevel) {
514 return &toplevel->events.request_maximize;
515 }
516
517 struct wl_signal *river_wlr_xdg_toplevel_get_request_minimize_signal(struct wlr_xdg_toplevel *toplevel) {
518 return &toplevel->events.request_minimize;
519 }
520
521 struct wl_signal *river_wlr_xdg_toplevel_get_request_move_signal(struct wlr_xdg_toplevel *toplevel) {
522 return &toplevel->events.request_move;
523 }
524
525 struct wl_signal *river_wlr_xdg_toplevel_get_request_resize_signal(struct wlr_xdg_toplevel *toplevel) {
526 return &toplevel->events.request_resize;
527 }
528
529 struct wl_signal *river_wlr_xdg_toplevel_get_set_parent_signal(struct wlr_xdg_toplevel *toplevel) {
530 return &toplevel->events.set_parent;
531 }
532
533 struct wl_signal *river_wlr_xdg_toplevel_get_set_title_signal(struct wlr_xdg_toplevel *toplevel) {
534 return &toplevel->events.set_title;
535 }
536
537 struct wl_signal *river_wlr_xdg_toplevel_get_set_app_id_signal(struct wlr_xdg_toplevel *toplevel) {
538 return &toplevel->events.set_app_id;
539 }
540
541 const char *river_wlr_xdg_toplevel_get_title(struct wlr_xdg_toplevel *toplevel) {
542 return toplevel->title;
543 }
544
545 const char *river_wlr_xdg_toplevel_get_app_id(struct wlr_xdg_toplevel *toplevel) {
546 return toplevel->app_id;
547 }
548
549 struct wlr_xdg_toplevel *river_wlr_xdg_toplevel_get_parent(struct wlr_xdg_toplevel *toplevel) {
550 return toplevel->parent;
551 }
552
553 bool river_wlr_xdg_toplevel_get_requested_fullscreen(struct wlr_xdg_toplevel *toplevel) {
554 return toplevel->requested.fullscreen;
555 }
556
557 struct wlr_output *river_wlr_xdg_toplevel_get_requested_fullscreen_output(struct wlr_xdg_toplevel *toplevel) {
558 return toplevel->requested.fullscreen_output;
559 }
560
561 bool river_wlr_xdg_toplevel_get_requested_maximized(struct wlr_xdg_toplevel *toplevel) {
562 return toplevel->requested.maximized;
563 }
564
565 void river_wlr_xdg_toplevel_get_requested_min_max_size(struct wlr_xdg_toplevel *toplevel, int *min_w, int *min_h, int *max_w, int *max_h) {
566 *min_w = toplevel->current.min_width;
567 *min_h = toplevel->current.min_height;
568 *max_w = toplevel->current.max_width;
569 *max_h = toplevel->current.max_height;
570 }
571
572 struct wlr_xdg_surface *river_wlr_xdg_popup_get_base(struct wlr_xdg_popup *popup) {
573 return popup->base;
574 }
575
576 struct wl_signal *river_wlr_xdg_popup_get_destroy_signal(struct wlr_xdg_popup *popup) {
577 return &popup->events.destroy;
578 }
579
580 struct wl_signal *river_wlr_xdg_popup_get_reposition_signal(struct wlr_xdg_popup *popup) {
581 return &popup->events.reposition;
582 }
583
584 void river_wlr_xdg_popup_get_anchor_rect(struct wlr_xdg_popup *popup, struct wlr_box *box) {
585 *box = popup->scheduled.rules.anchor_rect;
586 }
587
588 void *river_wlr_xdg_surface_get_data(struct wlr_xdg_surface *xdg_surface) {
589 return xdg_surface->data;
590 }
591
592 void river_wlr_xdg_surface_set_data(struct wlr_xdg_surface *xdg_surface, void *data) {
593 xdg_surface->data = data;
594 }
595
596 struct wl_list *river_wlr_xdg_surface_get_popups(struct wlr_xdg_surface *xdg_surface) {
597 return &xdg_surface->popups;
598 }
599
600 struct wlr_scene_tree *river_wlr_scene_tree_get_parent(struct wlr_scene_tree *tree) {
601 return tree->node.parent;
602 }
603
604 struct wl_list *river_scene_tree_get_children(struct wlr_scene_tree *tree) {
605 return &tree->children;
606 }
607
608 struct wl_signal *river_wlr_surface_get_map_signal(struct wlr_surface *surface) {
609 return &surface->events.map;
610 }
611
612 struct wl_signal *river_wlr_surface_get_unmap_signal(struct wlr_surface *surface) {
613 return &surface->events.unmap;
614 }
615
616 struct wl_resource *river_wlr_surface_get_resource(struct wlr_surface *surface) {
617 return surface->resource;
618 }
619
620 bool river_wlr_surface_is_mapped(struct wlr_surface *surface) {
621 return surface->mapped;
622 }
623
624 struct wl_signal *river_wlr_tablet_v2_tablet_tool_get_set_cursor_signal(struct wlr_tablet_v2_tablet_tool *tool) {
625 return &tool->events.set_cursor;
626 }
627
628 struct wlr_surface *river_wlr_tablet_v2_tablet_tool_get_focused_surface(struct wlr_tablet_v2_tablet_tool *tool) {
629 return tool->focused_surface;
630 }
631
632 uint32_t river_wlr_tablet_v2_tablet_tool_get_proximity_serial(struct wlr_tablet_v2_tablet_tool *tool) {
633 return tool->proximity_serial;
634 }
635
636 bool river_wlr_tablet_v2_tablet_tool_get_is_down(struct wlr_tablet_v2_tablet_tool *tool) {
637 return tool->is_down;
638 }
639
640 size_t river_wlr_tablet_v2_tablet_tool_get_num_buttons(struct wlr_tablet_v2_tablet_tool *tool) {
641 return tool->num_buttons;
642 }
643
644 struct wlr_tablet_tool *river_wlr_tablet_v2_tablet_tool_get_wlr_tool(struct wlr_tablet_v2_tablet_tool *tool) {
645 return tool->wlr_tool;
646 }
647
648 void river_wlr_seat_touch_cancel_all(struct wlr_seat *wlr_seat) {
649 struct wlr_touch_point *point, *tmp;
650 wl_list_for_each_safe(point, tmp, &wlr_seat->touch_state.touch_points, link) {
651 wlr_seat_touch_notify_cancel(wlr_seat, point->client);
652 }
653 }
654
655 struct wlr_surface *river_wlr_seat_get_keyboard_focused_surface(struct wlr_seat *seat) {
656 return seat->keyboard_state.focused_surface;
657 }
658
659 int river_wlr_surface_get_width(struct wlr_surface *surface) {
660 return surface->current.width;
661 }
662
663 int river_wlr_surface_get_height(struct wlr_surface *surface) {
664 return surface->current.height;
665 }
666
667 // Commit sequence of a surface's current state. Cheap "has this drawn
668 // anything new?" key for the status-bar backdrop sampler, which is trying
669 // hard NOT to read back a texture it has already read.
670 uint32_t river_wlr_surface_current_seq(struct wlr_surface *surface) {
671 return surface->current.seq;
672 }
673
674 void river_wlr_surface_get_buffer_size(struct wlr_surface *surface, int *width, int *height) {
675 *width = surface->current.buffer_width;
676 *height = surface->current.buffer_height;
677 }
678
679 struct wlr_keyboard *river_wlr_input_method_keyboard_grab_v2_get_keyboard(struct wlr_input_method_keyboard_grab_v2 *grab) {
680 return grab->keyboard;
681 }
682
683 struct wl_signal *river_wlr_input_method_keyboard_grab_v2_get_destroy_signal(struct wlr_input_method_keyboard_grab_v2 *grab) {
684 return &grab->events.destroy;
685 }
686
687 struct wlr_drag_icon *river_wlr_drag_get_icon(struct wlr_drag *drag) {
688 return drag->icon;
689 }
690
691 struct wlr_seat *river_wlr_drag_get_seat(struct wlr_drag *drag) {
692 return drag->seat;
693 }
694
695 enum wlr_drag_grab_type river_wlr_drag_get_grab_type(struct wlr_drag *drag) {
696 return drag->grab_type;
697 }
698
699 int32_t river_wlr_drag_get_touch_id(struct wlr_drag *drag) {
700 return drag->touch_id;
701 }
702
703 struct wlr_data_source *river_wlr_drag_get_source(struct wlr_drag *drag) {
704 return drag->source;
705 }
706
707 struct wl_signal *river_wlr_drag_get_destroy_signal(struct wlr_drag *drag) {
708 return &drag->events.destroy;
709 }
710
711 struct wlr_seat_client *river_wlr_drag_get_seat_client(struct wlr_drag *drag) {
712 return drag->seat_client;
713 }
714
715 void river_wlr_keyboard_init(struct wlr_keyboard *keyboard,
716 void (*led_update)(struct wlr_keyboard *keyboard, uint32_t leds),
717 const char *name) {
718 static struct wlr_keyboard_impl impl;
719 static bool impl_initialized = false;
720 if (!impl_initialized) {
721 impl.name = name;
722 impl.led_update = led_update;
723 impl_initialized = true;
724 }
725 wlr_keyboard_init(keyboard, &impl, name);
726 }
727
728 static struct wlr_scene_node *find_blur_node(struct wlr_scene_tree *tree) {
729 struct wlr_scene_node *child;
730 wl_list_for_each(child, &tree->children, link) {
731 if (child->type == WLR_SCENE_NODE_BLUR) {
732 return child;
733 }
734 }
735 return NULL;
736 }
737
738 static struct wlr_scene_node *find_optimized_blur_node(struct wlr_scene_tree *tree) {
739 struct wlr_scene_node *child;
740 wl_list_for_each(child, &tree->children, link) {
741 if (child->type == WLR_SCENE_NODE_OPTIMIZED_BLUR) {
742 return child;
743 }
744 }
745 return NULL;
746 }
747
748 static void get_size_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
749 (void)sx;
750 (void)sy;
751 int *size = (int *)user_data;
752 if (buffer->dst_width > size[0]) size[0] = buffer->dst_width;
753 if (buffer->dst_height > size[1]) size[1] = buffer->dst_height;
754 }
755
756 static void find_buffer_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
757 (void)sx;
758 (void)sy;
759 struct wlr_scene_buffer **result = (struct wlr_scene_buffer **)user_data;
760 if (*result == NULL) {
761 *result = buffer;
762 }
763 }
764
765 // `corner_radius` is in the same (scaled, device) pixels as width/height. It is applied
766 // here rather than through river_scene_node_set_corner_radius so that a blur node can
767 // never exist without it: that helper looks the blur up by scanning a tree's direct
768 // children, so aiming it at the wrong tree silently no-ops, and it was never called at
769 // all on the viewport-update path. Note the optimized blur node cannot be rounded --
770 // wlr_scene_optimized_blur has no radius field -- so callers that need rounded corners
771 // must pass optimized = false.
772 void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled, bool optimized, bool ignore_transparent, int x, int y, int width, int height, int corner_radius) {
773 if (node->type != WLR_SCENE_NODE_TREE) {
774 return;
775 }
776 struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
777 struct wlr_scene_node *opt_blur_node = find_optimized_blur_node(tree);
778 struct wlr_scene_node *std_blur_node = find_blur_node(tree);
779
780 if (!enabled) {
781 if (opt_blur_node) {
782 wlr_scene_node_destroy(opt_blur_node);
783 }
784 if (std_blur_node) {
785 wlr_scene_node_destroy(std_blur_node);
786 }
787 return;
788 }
789
790 if (width <= 0 || height <= 0) {
791 int size[2] = {0, 0};
792 wlr_scene_node_for_each_buffer(node, get_size_iterator, size);
793 width = size[0];
794 height = size[1];
795 x = 0;
796 y = 0;
797 }
798
799 if (width <= 0 || height <= 0) {
800 if (opt_blur_node) {
801 wlr_scene_node_destroy(opt_blur_node);
802 }
803 if (std_blur_node) {
804 wlr_scene_node_destroy(std_blur_node);
805 }
806 return;
807 }
808
809 if (optimized) {
810 if (!opt_blur_node) {
811 struct wlr_scene_optimized_blur *opt_blur = wlr_scene_optimized_blur_create(tree, width, height);
812 if (opt_blur) {
813 opt_blur_node = &opt_blur->node;
814 }
815 } else {
816 wlr_scene_optimized_blur_set_size((struct wlr_scene_optimized_blur *)opt_blur_node, width, height);
817 }
818 if (opt_blur_node) {
819 wlr_scene_node_set_position(opt_blur_node, x, y);
820 }
821 } else {
822 if (opt_blur_node) {
823 wlr_scene_node_destroy(opt_blur_node);
824 opt_blur_node = NULL;
825 }
826 }
827
828 if (!std_blur_node) {
829 struct wlr_scene_blur *std_blur = wlr_scene_blur_create(tree, width, height);
830 if (std_blur) {
831 std_blur_node = &std_blur->node;
832 wlr_scene_blur_set_should_only_blur_bottom_layer(std_blur, optimized);
833 }
834 } else {
835 wlr_scene_blur_set_should_only_blur_bottom_layer((struct wlr_scene_blur *)std_blur_node, optimized);
836 wlr_scene_blur_set_size((struct wlr_scene_blur *)std_blur_node, width, height);
837 }
838
839 // Set on both the create and the reuse path: a node reused across a resize keeps its
840 // radius, but one recreated after a blur toggle would otherwise come back square.
841 if (std_blur_node) {
842 wlr_scene_blur_set_corner_radius((struct wlr_scene_blur *)std_blur_node, corner_radius);
843 }
844
845 if (std_blur_node) {
846 wlr_scene_node_set_position(std_blur_node, x, y);
847 struct wlr_scene_buffer *source_buffer = NULL;
848 if (ignore_transparent) {
849 wlr_scene_node_for_each_buffer(node, find_buffer_iterator, &source_buffer);
850 }
851 wlr_scene_blur_set_transparency_mask_source((struct wlr_scene_blur *)std_blur_node, source_buffer);
852 }
853
854 // Ensure correct stack order (from back to front): opt_blur_node -> std_blur_node -> window content.
855 // Only reorder when out of order: the lower_to_bottom pair is not idempotent
856 // (on an already-ordered tree each call swaps the two nodes, and every swap
857 // damages the node's whole window-sized region — this runs per commit and
858 // per render_finish, so the no-op path must not touch the scene graph).
859 struct wlr_scene_node *want_bottom = opt_blur_node ? opt_blur_node : std_blur_node;
860 struct wlr_scene_node *want_second = opt_blur_node ? std_blur_node : NULL;
861 bool ordered = want_bottom != NULL
862 && tree->children.next == &want_bottom->link
863 && (want_second == NULL || want_bottom->link.next == &want_second->link);
864 if (!ordered) {
865 if (std_blur_node) {
866 wlr_scene_node_lower_to_bottom(std_blur_node);
867 }
868 if (opt_blur_node) {
869 wlr_scene_node_lower_to_bottom(opt_blur_node);
870 }
871 }
872 }
873
874 static void set_opacity_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
875 (void)sx;
876 (void)sy;
877 float opacity = *(float *)user_data;
878 if (buffer->opacity != opacity) {
879 wlr_scene_buffer_set_opacity(buffer, opacity);
880 }
881 }
882
883 void river_scene_node_set_opacity(struct wlr_scene_node *node, float opacity) {
884 wlr_scene_node_for_each_buffer(node, set_opacity_iterator, &opacity);
885 if (node->type == WLR_SCENE_NODE_TREE) {
886 struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
887 struct wlr_scene_node *blur_node = find_blur_node(tree);
888 if (blur_node && blur_node->type == WLR_SCENE_NODE_BLUR) {
889 wlr_scene_blur_set_alpha((struct wlr_scene_blur *)blur_node, opacity);
890 }
891 }
892 }
893
894 static void set_corner_radius_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
895 (void)sx;
896 (void)sy;
897 int radius = *(int *)user_data;
898 wlr_scene_buffer_set_corner_radius(buffer, radius);
899 }
900
901 void river_scene_node_set_corner_radius(struct wlr_scene_node *node, int radius) {
902 wlr_scene_node_for_each_buffer(node, set_corner_radius_iterator, &radius);
903 if (node->type == WLR_SCENE_NODE_TREE) {
904 struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
905 struct wlr_scene_node *blur_node = find_blur_node(tree);
906 if (blur_node && blur_node->type == WLR_SCENE_NODE_BLUR) {
907 wlr_scene_blur_set_corner_radius((struct wlr_scene_blur *)blur_node, radius);
908 }
909 }
910 }
911
912 void river_scene_buffer_set_dest_size_if_changed(struct wlr_scene_buffer *scene_buffer, int width, int height) {
913 if (scene_buffer->dst_width != width || scene_buffer->dst_height != height) {
914 wlr_scene_buffer_set_dest_size(scene_buffer, width, height);
915 }
916 }
917
918 void river_scene_node_set_position_if_changed(struct wlr_scene_node *node, int x, int y) {
919 if (node->x != x || node->y != y) {
920 wlr_scene_node_set_position(node, x, y);
921 }
922 }
923
924 void river_scene_rect_set_size_if_changed(struct wlr_scene_rect *rect, int width, int height) {
925 if (rect->width != width || rect->height != height) {
926 wlr_scene_rect_set_size(rect, width, height);
927 }
928 }
929
930 void river_scene_rect_set_corner_radius(struct wlr_scene_rect *rect, int radius) {
931 wlr_scene_rect_set_corner_radius(rect, radius);
932 }
933
934 int river_scene_buffer_get_width(struct wlr_scene_buffer *scene_buffer) {
935 if (scene_buffer->buffer) {
936 return scene_buffer->buffer->width;
937 }
938 return scene_buffer->dst_width;
939 }
940
941 int river_scene_buffer_get_height(struct wlr_scene_buffer *scene_buffer) {
942 if (scene_buffer->buffer) {
943 return scene_buffer->buffer->height;
944 }
945 return scene_buffer->dst_height;
946 }
947
948 /* Scale a surface's opaque region to match a custom buffer dest size and
949 * apply it to the scene buffer. The scene keeps opaque regions in SURFACE
950 * coordinates and scenefx's occlusion culling only intersects them with the
951 * node box — so a zoomed-down window's unscaled opaque rect still covered
952 * (almost) the whole scaled node, INCLUDING its translucent CSD shadow
953 * margins. Culling then skipped repainting behind the shadow ring: stale
954 * pixels showed through the translucent shadow around focused windows when
955 * zoomed (worst at the bottom, where Chromium's ring is tallest). */
956 /* The subsurface clip on a surface buffer (wlr_scene_subsurface_tree_set_clip,
957 * applied by the window's apply_surface_clip as the xdg geometry): the part of
958 * the surface this buffer shows, in surface coordinates. wlroots crops the
959 * buffer's source box to it and sizes/positions the node from it on every
960 * commit, so every pass that rewrites a buffer's dest size or position must
961 * work from this extent rather than the surface's full size — or it stretches
962 * the cropped source back out to the whole surface. False (and an empty box)
963 * when the buffer is not a surface's or nothing is clipped. */
964 bool river_scene_buffer_get_surface_clip(struct wlr_scene_buffer *scene_buffer,
965 struct wlr_box *out) {
966 *out = (struct wlr_box){0};
967 struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer);
968 if (!scene_surface) {
969 return false;
970 }
971 *out = scene_surface->WLR_PRIVATE.clip;
972 return !wlr_box_empty(out);
973 }
974
975 void river_scene_buffer_set_scaled_opaque_region(struct wlr_scene_buffer *scene_buffer,
976 struct wlr_surface *surface, double scale) {
977 pixman_region32_t scaled;
978 pixman_region32_init(&scaled);
979 pixman_region32_copy(&scaled, &surface->opaque_region);
980 /* A clipped buffer shows only `clip` of the surface, at its own origin:
981 * bring the region into buffer space before scaling, or the part of it
982 * that lies in the cropped-away margin claims pixels the node never
983 * paints. */
984 struct wlr_box clip;
985 if (river_scene_buffer_get_surface_clip(scene_buffer, &clip)) {
986 pixman_region32_translate(&scaled, -clip.x, -clip.y);
987 pixman_region32_intersect_rect(&scaled, &scaled, 0, 0, clip.width, clip.height);
988 }
989 wlr_region_scale(&scaled, &scaled, (float)scale);
990 wlr_scene_buffer_set_opaque_region(scene_buffer, &scaled);
991 pixman_region32_fini(&scaled);
992 }
993
994 int river_scene_buffer_get_dest_width(struct wlr_scene_buffer *scene_buffer) {
995 return scene_buffer->dst_width;
996 }
997
998 int river_scene_buffer_get_dest_height(struct wlr_scene_buffer *scene_buffer) {
999 return scene_buffer->dst_height;
1000 }
1001
1002 bool river_scene_node_get_enabled(struct wlr_scene_node *node) {
1003 return node->enabled;
1004 }
1005
1006 /* Overview-delay debugging: dump the true scene-side state of every buffer
1007 * under a node — enabled flags, absolute position, dest size, whether a
1008 * wlr_buffer/texture is attached, the primary output, and the computed
1009 * visibility region. The visibility extents are the ground truth for "will
1010 * this buffer be drawn": an empty region means the scene considers it
1011 * invisible regardless of what the window-manager state says. */
1012 static void river_ovdbg_buffer_iter(struct wlr_scene_buffer *buffer,
1013 int sx, int sy, void *data) {
1014 const char *tag = data;
1015 struct wlr_scene_node *node = &buffer->node;
1016 int lx = 0, ly = 0;
1017 bool coords_en = wlr_scene_node_coords(node, &lx, &ly);
1018 pixman_box32_t *ext = pixman_region32_extents(&node->WLR_PRIVATE.visible);
1019 struct timespec ts;
1020 clock_gettime(CLOCK_REALTIME, &ts);
1021 fprintf(stderr,
1022 "[ovdbg] t=%ld.%03ld %s buf=%p en=%d coords_en=%d abs=(%d,%d) "
1023 "dst=%dx%d bufwh=%dx%d wlrbuf=%p tex=%p primary=%p vis=(%d,%d %dx%d)\n",
1024 (long)ts.tv_sec, ts.tv_nsec / 1000000, tag, (void *)buffer,
1025 node->enabled, coords_en, lx, ly,
1026 buffer->dst_width, buffer->dst_height,
1027 buffer->WLR_PRIVATE.buffer_width, buffer->WLR_PRIVATE.buffer_height,
1028 (void *)buffer->buffer, (void *)buffer->WLR_PRIVATE.texture,
1029 (void *)buffer->primary_output,
1030 ext->x1, ext->y1, ext->x2 - ext->x1, ext->y2 - ext->y1);
1031 }
1032
1033 void river_scene_ovdbg_dump(struct wlr_scene_node *node, const char *tag) {
1034 wlr_scene_node_for_each_buffer(node, river_ovdbg_buffer_iter, (void *)tag);
1035 }
1036
1037 /* Overview-delay/shadow debugging: report a window's drop-shadow node state so
1038 * it can be compared against the window's current zoom scale. Everything here
1039 * is device px, as update_shadow writes it. */
1040 void river_scene_shadow_dbg(struct wlr_scene_shadow *shadow, const char *tag) {
1041 if (!shadow) {
1042 fprintf(stderr, "[ovdbg] %s shadow=NULL\n", tag);
1043 return;
1044 }
1045 struct wlr_scene_node *node = &shadow->node;
1046 fprintf(stderr,
1047 "[ovdbg] %s shadow en=%d pos=(%d,%d) size=%dx%d sigma=%.1f radius=%d "
1048 "clip=(%d,%d %dx%d)\n",
1049 tag, node->enabled, node->x, node->y, shadow->width, shadow->height,
1050 shadow->blur_sigma, shadow->corner_radius,
1051 shadow->clipped_region.area.x, shadow->clipped_region.area.y,
1052 shadow->clipped_region.area.width, shadow->clipped_region.area.height);
1053 }
1054
1055 /* ------------------------------------------------------------------
1056 * CPU-backed buffer: lets the compositor hand the renderer pixels it
1057 * rasterized itself (the desktop-grid square labels). wlroots has no public
1058 * constructor for this, so implement the minimal wlr_buffer: the renderer
1059 * reaches the pixels through data-ptr access and uploads them like any shm
1060 * buffer. The data is copied in, so the caller's Rust Vec can be dropped.
1061 * ------------------------------------------------------------------ */
1062 struct cce_data_buffer {
1063 struct wlr_buffer base;
1064 void *data;
1065 uint32_t format;
1066 size_t stride;
1067 };
1068
1069 static void cce_data_buffer_destroy(struct wlr_buffer *wlr_buffer) {
1070 struct cce_data_buffer *buf = (struct cce_data_buffer *)wlr_buffer;
1071 free(buf->data);
1072 free(buf);
1073 }
1074
1075 static bool cce_data_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer,
1076 uint32_t flags, void **data, uint32_t *format, size_t *stride) {
1077 struct cce_data_buffer *buf = (struct cce_data_buffer *)wlr_buffer;
1078 if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) {
1079 return false; /* immutable once built */
1080 }
1081 *data = buf->data;
1082 *format = buf->format;
1083 *stride = buf->stride;
1084 return true;
1085 }
1086
1087 static void cce_data_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {
1088 /* nothing to unmap */
1089 }
1090
1091 static const struct wlr_buffer_impl cce_data_buffer_impl = {
1092 .destroy = cce_data_buffer_destroy,
1093 .begin_data_ptr_access = cce_data_buffer_begin_data_ptr_access,
1094 .end_data_ptr_access = cce_data_buffer_end_data_ptr_access,
1095 };
1096
1097 /* Copy `data` (ARGB8888, premultiplied, `stride` bytes per row) into a new
1098 * buffer. Returns NULL on allocation failure. The buffer starts with one
1099 * reference, as wlr_buffer_init leaves it: pass it to a scene buffer and then
1100 * drop this reference with wlr_buffer_drop(). */
1101 struct wlr_buffer *river_data_buffer_create(int width, int height,
1102 size_t stride, const void *data) {
1103 if (width <= 0 || height <= 0 || stride == 0) {
1104 return NULL;
1105 }
1106 struct cce_data_buffer *buf = calloc(1, sizeof(*buf));
1107 if (!buf) {
1108 return NULL;
1109 }
1110 size_t size = stride * (size_t)height;
1111 buf->data = malloc(size);
1112 if (!buf->data) {
1113 free(buf);
1114 return NULL;
1115 }
1116 memcpy(buf->data, data, size);
1117 buf->format = DRM_FORMAT_ARGB8888;
1118 buf->stride = stride;
1119 wlr_buffer_init(&buf->base, &cce_data_buffer_impl, width, height);
1120 return &buf->base;
1121 }
1122
1123 /* Mark every optimized-blur node in the scene dirty, forcing a re-bake of the
1124 * shared blurred-backdrop cache on the next frame. The cache is otherwise
1125 * invalidated only by blur-parameter setters and window blur RESIZES
1126 * (optimized_blur_set_size marks dirty; a same-size re-enable does not), so
1127 * backdrop CONTENT that changes without either — the grid client latching a
1128 * new patch after the viewport has settled, or the client<->fallback grid
1129 * swap — leaves every translucent window showing a stale bake. */
1130 static void mark_optimized_blur_dirty_rec(struct wlr_scene_node *node) {
1131 if (node->type == WLR_SCENE_NODE_OPTIMIZED_BLUR) {
1132 wlr_scene_optimized_blur_mark_dirty(wlr_scene_optimized_blur_from_node(node));
1133 return;
1134 }
1135 if (node->type == WLR_SCENE_NODE_TREE) {
1136 struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
1137 struct wlr_scene_node *child;
1138 wl_list_for_each(child, &tree->children, link) {
1139 mark_optimized_blur_dirty_rec(child);
1140 }
1141 }
1142 }
1143
1144 void river_scene_mark_optimized_blur_dirty(struct wlr_scene *scene) {
1145 mark_optimized_blur_dirty_rec(&scene->tree.node);
1146 }
1147
1148 /* See wlr_scene.blur_frozen: suspend the moved-node-below blur
1149 * invalidation for the duration of a camera pan. Thawing marks every
1150 * optimized blur dirty once so the settled frame re-bakes against the
1151 * final backdrop. */
1152 /* See wlr_scene.blur_frozen. Blurs sample the shared cache where their own
1153 * bake lives, frozen or not, and bake the strips they newly expose as they
1154 * travel, so a pan needs no re-bake at either end: the thaw is just the
1155 * flag. */
1156 void river_scene_set_blur_frozen(struct wlr_scene *scene, bool frozen) {
1157 scene->blur_frozen = frozen;
1158 }
1159
1160 /* See wlr_scene.desk_trees: this subtree renders with the desk's
1161 * sub-pixel offset. Idempotent; silently ignores a ninth tree. */
1162 struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
1163
1164 void river_scene_tree_set_desk_offset(struct wlr_scene_tree *tree, bool on) {
1165 struct wlr_scene *scene = scene_node_get_root(&tree->node);
1166 if (scene == NULL) {
1167 return;
1168 }
1169 int free_slot = -1;
1170 for (int i = 0; i < WLR_SCENE_DESK_TREES; i++) {
1171 if (scene->desk_trees[i] == tree) {
1172 if (!on) {
1173 scene->desk_trees[i] = NULL;
1174 }
1175 return;
1176 }
1177 if (scene->desk_trees[i] == NULL && free_slot < 0) {
1178 free_slot = i;
1179 }
1180 }
1181 if (on && free_slot >= 0) {
1182 scene->desk_trees[free_slot] = tree;
1183 }
1184 }
1185
1186 /* See wlr_scene.desk_sub_x/y: the camera pan's remainder below one
1187 * layout pixel, each in (-1, 0]. Changing it moves every desk node on
1188 * screen, which the caller damages (it is a camera move). */
1189 void river_scene_set_desk_subpixel(struct wlr_scene *scene, double sub_x, double sub_y) {
1190 scene->desk_sub_x = sub_x;
1191 scene->desk_sub_y = sub_y;
1192 }
1193
1194 struct wl_signal *river_wlr_session_get_active_signal(struct wlr_session *session) {
1195 return &session->events.active;
1196 }
1197
1198 bool river_wlr_session_get_active(struct wlr_session *session) {
1199 return session->active;
1200 }