git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

src/server/wlroots_log_wrapper.c (41.4K)

   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 // wl_touch.cancel is per client: it voids every point that client holds,
 649 // and wlr_seat_touch_notify_cancel destroys them all. So cancelling one
 650 // finger cancels its client's whole sequence — the protocol's unit.
 651 void river_wlr_seat_touch_cancel_point(struct wlr_seat *wlr_seat, int32_t touch_id) {
 652 	struct wlr_touch_point *point = wlr_seat_touch_get_point(wlr_seat, touch_id);
 653 	if (point != NULL && point->client != NULL) {
 654 		wlr_seat_touch_notify_cancel(wlr_seat, point->client);
 655 	}
 656 }
 657 
 658 struct wlr_surface *river_wlr_seat_get_keyboard_focused_surface(struct wlr_seat *seat) {
 659 	return seat->keyboard_state.focused_surface;
 660 }
 661 
 662 int river_wlr_surface_get_width(struct wlr_surface *surface) {
 663 	return surface->current.width;
 664 }
 665 
 666 int river_wlr_surface_get_height(struct wlr_surface *surface) {
 667 	return surface->current.height;
 668 }
 669 
 670 // Commit sequence of a surface's current state. Cheap "has this drawn
 671 // anything new?" key for the status-bar backdrop sampler, which is trying
 672 // hard NOT to read back a texture it has already read.
 673 uint32_t river_wlr_surface_current_seq(struct wlr_surface *surface) {
 674 	return surface->current.seq;
 675 }
 676 
 677 void river_wlr_surface_get_buffer_size(struct wlr_surface *surface, int *width, int *height) {
 678 	*width = surface->current.buffer_width;
 679 	*height = surface->current.buffer_height;
 680 }
 681 
 682 struct wlr_keyboard *river_wlr_input_method_keyboard_grab_v2_get_keyboard(struct wlr_input_method_keyboard_grab_v2 *grab) {
 683 	return grab->keyboard;
 684 }
 685 
 686 struct wl_signal *river_wlr_input_method_keyboard_grab_v2_get_destroy_signal(struct wlr_input_method_keyboard_grab_v2 *grab) {
 687 	return &grab->events.destroy;
 688 }
 689 
 690 struct wlr_drag_icon *river_wlr_drag_get_icon(struct wlr_drag *drag) {
 691 	return drag->icon;
 692 }
 693 
 694 struct wlr_seat *river_wlr_drag_get_seat(struct wlr_drag *drag) {
 695 	return drag->seat;
 696 }
 697 
 698 enum wlr_drag_grab_type river_wlr_drag_get_grab_type(struct wlr_drag *drag) {
 699 	return drag->grab_type;
 700 }
 701 
 702 int32_t river_wlr_drag_get_touch_id(struct wlr_drag *drag) {
 703 	return drag->touch_id;
 704 }
 705 
 706 struct wlr_data_source *river_wlr_drag_get_source(struct wlr_drag *drag) {
 707 	return drag->source;
 708 }
 709 
 710 struct wl_signal *river_wlr_drag_get_destroy_signal(struct wlr_drag *drag) {
 711 	return &drag->events.destroy;
 712 }
 713 
 714 struct wlr_seat_client *river_wlr_drag_get_seat_client(struct wlr_drag *drag) {
 715 	return drag->seat_client;
 716 }
 717 
 718 void river_wlr_keyboard_init(struct wlr_keyboard *keyboard,
 719 		void (*led_update)(struct wlr_keyboard *keyboard, uint32_t leds),
 720 		const char *name) {
 721 	static struct wlr_keyboard_impl impl;
 722 	static bool impl_initialized = false;
 723 	if (!impl_initialized) {
 724 		impl.name = name;
 725 		impl.led_update = led_update;
 726 		impl_initialized = true;
 727 	}
 728 	wlr_keyboard_init(keyboard, &impl, name);
 729 }
 730 
 731 static struct wlr_scene_node *find_blur_node(struct wlr_scene_tree *tree) {
 732 	struct wlr_scene_node *child;
 733 	wl_list_for_each(child, &tree->children, link) {
 734 		if (child->type == WLR_SCENE_NODE_BLUR) {
 735 			return child;
 736 		}
 737 	}
 738 	return NULL;
 739 }
 740 
 741 static struct wlr_scene_node *find_optimized_blur_node(struct wlr_scene_tree *tree) {
 742 	struct wlr_scene_node *child;
 743 	wl_list_for_each(child, &tree->children, link) {
 744 		if (child->type == WLR_SCENE_NODE_OPTIMIZED_BLUR) {
 745 			return child;
 746 		}
 747 	}
 748 	return NULL;
 749 }
 750 
 751 static void get_size_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
 752 	(void)sx;
 753 	(void)sy;
 754 	int *size = (int *)user_data;
 755 	if (buffer->dst_width > size[0]) size[0] = buffer->dst_width;
 756 	if (buffer->dst_height > size[1]) size[1] = buffer->dst_height;
 757 }
 758 
 759 static void find_buffer_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
 760 	(void)sx;
 761 	(void)sy;
 762 	struct wlr_scene_buffer **result = (struct wlr_scene_buffer **)user_data;
 763 	if (*result == NULL) {
 764 		*result = buffer;
 765 	}
 766 }
 767 
 768 // `corner_radius` is in the same (scaled, device) pixels as width/height. It is applied
 769 // here rather than through river_scene_node_set_corner_radius so that a blur node can
 770 // never exist without it: that helper looks the blur up by scanning a tree's direct
 771 // children, so aiming it at the wrong tree silently no-ops, and it was never called at
 772 // all on the viewport-update path. Note the optimized blur node cannot be rounded --
 773 // wlr_scene_optimized_blur has no radius field -- so callers that need rounded corners
 774 // must pass optimized = false.
 775 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) {
 776 	if (node->type != WLR_SCENE_NODE_TREE) {
 777 		return;
 778 	}
 779 	struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
 780 	struct wlr_scene_node *opt_blur_node = find_optimized_blur_node(tree);
 781 	struct wlr_scene_node *std_blur_node = find_blur_node(tree);
 782 
 783 	if (!enabled) {
 784 		if (opt_blur_node) {
 785 			wlr_scene_node_destroy(opt_blur_node);
 786 		}
 787 		if (std_blur_node) {
 788 			wlr_scene_node_destroy(std_blur_node);
 789 		}
 790 		return;
 791 	}
 792 
 793 	if (width <= 0 || height <= 0) {
 794 		int size[2] = {0, 0};
 795 		wlr_scene_node_for_each_buffer(node, get_size_iterator, size);
 796 		width = size[0];
 797 		height = size[1];
 798 		x = 0;
 799 		y = 0;
 800 	}
 801 
 802 	if (width <= 0 || height <= 0) {
 803 		if (opt_blur_node) {
 804 			wlr_scene_node_destroy(opt_blur_node);
 805 		}
 806 		if (std_blur_node) {
 807 			wlr_scene_node_destroy(std_blur_node);
 808 		}
 809 		return;
 810 	}
 811 
 812 	if (optimized) {
 813 		if (!opt_blur_node) {
 814 			struct wlr_scene_optimized_blur *opt_blur = wlr_scene_optimized_blur_create(tree, width, height);
 815 			if (opt_blur) {
 816 				opt_blur_node = &opt_blur->node;
 817 			}
 818 		} else {
 819 			wlr_scene_optimized_blur_set_size((struct wlr_scene_optimized_blur *)opt_blur_node, width, height);
 820 		}
 821 		if (opt_blur_node) {
 822 			wlr_scene_node_set_position(opt_blur_node, x, y);
 823 		}
 824 	} else {
 825 		if (opt_blur_node) {
 826 			wlr_scene_node_destroy(opt_blur_node);
 827 			opt_blur_node = NULL;
 828 		}
 829 	}
 830 
 831 	if (!std_blur_node) {
 832 		struct wlr_scene_blur *std_blur = wlr_scene_blur_create(tree, width, height);
 833 		if (std_blur) {
 834 			std_blur_node = &std_blur->node;
 835 			wlr_scene_blur_set_should_only_blur_bottom_layer(std_blur, optimized);
 836 		}
 837 	} else {
 838 		wlr_scene_blur_set_should_only_blur_bottom_layer((struct wlr_scene_blur *)std_blur_node, optimized);
 839 		wlr_scene_blur_set_size((struct wlr_scene_blur *)std_blur_node, width, height);
 840 	}
 841 
 842 	// Set on both the create and the reuse path: a node reused across a resize keeps its
 843 	// radius, but one recreated after a blur toggle would otherwise come back square.
 844 	if (std_blur_node) {
 845 		wlr_scene_blur_set_corner_radius((struct wlr_scene_blur *)std_blur_node, corner_radius);
 846 	}
 847 
 848 	if (std_blur_node) {
 849 		wlr_scene_node_set_position(std_blur_node, x, y);
 850 		struct wlr_scene_buffer *source_buffer = NULL;
 851 		if (ignore_transparent) {
 852 			wlr_scene_node_for_each_buffer(node, find_buffer_iterator, &source_buffer);
 853 		}
 854 		wlr_scene_blur_set_transparency_mask_source((struct wlr_scene_blur *)std_blur_node, source_buffer);
 855 	}
 856 
 857 	// Ensure correct stack order (from back to front): opt_blur_node -> std_blur_node -> window content.
 858 	// Only reorder when out of order: the lower_to_bottom pair is not idempotent
 859 	// (on an already-ordered tree each call swaps the two nodes, and every swap
 860 	// damages the node's whole window-sized region — this runs per commit and
 861 	// per render_finish, so the no-op path must not touch the scene graph).
 862 	struct wlr_scene_node *want_bottom = opt_blur_node ? opt_blur_node : std_blur_node;
 863 	struct wlr_scene_node *want_second = opt_blur_node ? std_blur_node : NULL;
 864 	bool ordered = want_bottom != NULL
 865 		&& tree->children.next == &want_bottom->link
 866 		&& (want_second == NULL || want_bottom->link.next == &want_second->link);
 867 	if (!ordered) {
 868 		if (std_blur_node) {
 869 			wlr_scene_node_lower_to_bottom(std_blur_node);
 870 		}
 871 		if (opt_blur_node) {
 872 			wlr_scene_node_lower_to_bottom(opt_blur_node);
 873 		}
 874 	}
 875 }
 876 
 877 // Backdrop compression on the tree's standard blur node (see
 878 // wlr_scene_blur_set_compress). Separate from river_scene_node_enable_blur so
 879 // its many callers need not all carry it: call it after enable_blur, which may
 880 // have just recreated the node with compression off.
 881 void river_scene_node_set_blur_compress(struct wlr_scene_node *node, float ceil, float knee, bool invert) {
 882 	if (node->type != WLR_SCENE_NODE_TREE) {
 883 		return;
 884 	}
 885 	struct wlr_scene_node *std_blur_node = find_blur_node(wlr_scene_tree_from_node(node));
 886 	if (std_blur_node) {
 887 		wlr_scene_blur_set_compress((struct wlr_scene_blur *)std_blur_node, ceil, knee, invert);
 888 	}
 889 }
 890 
 891 static void set_opacity_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
 892 	(void)sx;
 893 	(void)sy;
 894 	float opacity = *(float *)user_data;
 895 	if (buffer->opacity != opacity) {
 896 		wlr_scene_buffer_set_opacity(buffer, opacity);
 897 	}
 898 }
 899 
 900 void river_scene_node_set_opacity(struct wlr_scene_node *node, float opacity) {
 901 	wlr_scene_node_for_each_buffer(node, set_opacity_iterator, &opacity);
 902 	if (node->type == WLR_SCENE_NODE_TREE) {
 903 		struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
 904 		struct wlr_scene_node *blur_node = find_blur_node(tree);
 905 		if (blur_node && blur_node->type == WLR_SCENE_NODE_BLUR) {
 906 			wlr_scene_blur_set_alpha((struct wlr_scene_blur *)blur_node, opacity);
 907 		}
 908 	}
 909 }
 910 
 911 static void set_corner_radius_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
 912 	(void)sx;
 913 	(void)sy;
 914 	int radius = *(int *)user_data;
 915 	wlr_scene_buffer_set_corner_radius(buffer, radius);
 916 }
 917 
 918 void river_scene_node_set_corner_radius(struct wlr_scene_node *node, int radius) {
 919 	wlr_scene_node_for_each_buffer(node, set_corner_radius_iterator, &radius);
 920 	if (node->type == WLR_SCENE_NODE_TREE) {
 921 		struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
 922 		struct wlr_scene_node *blur_node = find_blur_node(tree);
 923 		if (blur_node && blur_node->type == WLR_SCENE_NODE_BLUR) {
 924 			wlr_scene_blur_set_corner_radius((struct wlr_scene_blur *)blur_node, radius);
 925 		}
 926 	}
 927 }
 928 
 929 /* See wlr_scene_buffer_set_geometry_pinned(). The two setters below write
 930  * through the pin, so every caller of theirs keeps working on a pinned
 931  * buffer. */
 932 void river_scene_buffer_set_geometry_pinned(struct wlr_scene_buffer *scene_buffer, bool pinned) {
 933 	wlr_scene_buffer_set_geometry_pinned(scene_buffer, pinned);
 934 }
 935 
 936 void river_scene_buffer_set_dest_size_if_changed(struct wlr_scene_buffer *scene_buffer, int width, int height) {
 937 	if (scene_buffer->dst_width != width || scene_buffer->dst_height != height) {
 938 		wlr_scene_buffer_set_dest_size_pinned(scene_buffer, width, height);
 939 	}
 940 }
 941 
 942 void river_scene_node_set_position_if_changed(struct wlr_scene_node *node, int x, int y) {
 943 	if (node->x != x || node->y != y) {
 944 		wlr_scene_node_set_position(node, x, y);
 945 	}
 946 }
 947 
 948 void river_scene_rect_set_size_if_changed(struct wlr_scene_rect *rect, int width, int height) {
 949 	if (rect->width != width || rect->height != height) {
 950 		wlr_scene_rect_set_size(rect, width, height);
 951 	}
 952 }
 953 
 954 void river_scene_rect_set_corner_radius(struct wlr_scene_rect *rect, int radius) {
 955 	wlr_scene_rect_set_corner_radius(rect, radius);
 956 }
 957 
 958 int river_scene_buffer_get_width(struct wlr_scene_buffer *scene_buffer) {
 959 	if (scene_buffer->buffer) {
 960 		return scene_buffer->buffer->width;
 961 	}
 962 	return scene_buffer->dst_width;
 963 }
 964 
 965 int river_scene_buffer_get_height(struct wlr_scene_buffer *scene_buffer) {
 966 	if (scene_buffer->buffer) {
 967 		return scene_buffer->buffer->height;
 968 	}
 969 	return scene_buffer->dst_height;
 970 }
 971 
 972 /* Scale a surface's opaque region to match a custom buffer dest size and
 973  * apply it to the scene buffer. The scene keeps opaque regions in SURFACE
 974  * coordinates and scenefx's occlusion culling only intersects them with the
 975  * node box — so a zoomed-down window's unscaled opaque rect still covered
 976  * (almost) the whole scaled node, INCLUDING its translucent CSD shadow
 977  * margins. Culling then skipped repainting behind the shadow ring: stale
 978  * pixels showed through the translucent shadow around focused windows when
 979  * zoomed (worst at the bottom, where Chromium's ring is tallest). */
 980 /* The subsurface clip on a surface buffer (wlr_scene_subsurface_tree_set_clip,
 981  * applied by the window's apply_surface_clip as the xdg geometry): the part of
 982  * the surface this buffer shows, in surface coordinates. wlroots crops the
 983  * buffer's source box to it and sizes/positions the node from it on every
 984  * commit, so every pass that rewrites a buffer's dest size or position must
 985  * work from this extent rather than the surface's full size — or it stretches
 986  * the cropped source back out to the whole surface. False (and an empty box)
 987  * when the buffer is not a surface's or nothing is clipped. */
 988 bool river_scene_buffer_get_surface_clip(struct wlr_scene_buffer *scene_buffer,
 989 		struct wlr_box *out) {
 990 	*out = (struct wlr_box){0};
 991 	struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer);
 992 	if (!scene_surface) {
 993 		return false;
 994 	}
 995 	*out = scene_surface->WLR_PRIVATE.clip;
 996 	return !wlr_box_empty(out);
 997 }
 998 
 999 void river_scene_buffer_set_scaled_opaque_region(struct wlr_scene_buffer *scene_buffer,
1000 		struct wlr_surface *surface, double scale) {
1001 	pixman_region32_t scaled;
1002 	pixman_region32_init(&scaled);
1003 	pixman_region32_copy(&scaled, &surface->opaque_region);
1004 	/* A clipped buffer shows only `clip` of the surface, at its own origin:
1005 	 * bring the region into buffer space before scaling, or the part of it
1006 	 * that lies in the cropped-away margin claims pixels the node never
1007 	 * paints. */
1008 	struct wlr_box clip;
1009 	if (river_scene_buffer_get_surface_clip(scene_buffer, &clip)) {
1010 		pixman_region32_translate(&scaled, -clip.x, -clip.y);
1011 		pixman_region32_intersect_rect(&scaled, &scaled, 0, 0, clip.width, clip.height);
1012 	}
1013 	wlr_region_scale(&scaled, &scaled, (float)scale);
1014 	wlr_scene_buffer_set_opaque_region_pinned(scene_buffer, &scaled);
1015 	pixman_region32_fini(&scaled);
1016 }
1017 
1018 int river_scene_buffer_get_dest_width(struct wlr_scene_buffer *scene_buffer) {
1019 	return scene_buffer->dst_width;
1020 }
1021 
1022 int river_scene_buffer_get_dest_height(struct wlr_scene_buffer *scene_buffer) {
1023 	return scene_buffer->dst_height;
1024 }
1025 
1026 bool river_scene_node_get_enabled(struct wlr_scene_node *node) {
1027 	return node->enabled;
1028 }
1029 
1030 /* Overview-delay debugging: dump the true scene-side state of every buffer
1031  * under a node — enabled flags, absolute position, dest size, whether a
1032  * wlr_buffer/texture is attached, the primary output, and the computed
1033  * visibility region. The visibility extents are the ground truth for "will
1034  * this buffer be drawn": an empty region means the scene considers it
1035  * invisible regardless of what the window-manager state says. */
1036 static void river_ovdbg_buffer_iter(struct wlr_scene_buffer *buffer,
1037 		int sx, int sy, void *data) {
1038 	const char *tag = data;
1039 	struct wlr_scene_node *node = &buffer->node;
1040 	int lx = 0, ly = 0;
1041 	bool coords_en = wlr_scene_node_coords(node, &lx, &ly);
1042 	pixman_box32_t *ext = pixman_region32_extents(&node->WLR_PRIVATE.visible);
1043 	struct timespec ts;
1044 	clock_gettime(CLOCK_REALTIME, &ts);
1045 	fprintf(stderr,
1046 		"[ovdbg] t=%ld.%03ld %s buf=%p en=%d coords_en=%d abs=(%d,%d) "
1047 		"dst=%dx%d bufwh=%dx%d wlrbuf=%p tex=%p primary=%p vis=(%d,%d %dx%d)\n",
1048 		(long)ts.tv_sec, ts.tv_nsec / 1000000, tag, (void *)buffer,
1049 		node->enabled, coords_en, lx, ly,
1050 		buffer->dst_width, buffer->dst_height,
1051 		buffer->WLR_PRIVATE.buffer_width, buffer->WLR_PRIVATE.buffer_height,
1052 		(void *)buffer->buffer, (void *)buffer->WLR_PRIVATE.texture,
1053 		(void *)buffer->primary_output,
1054 		ext->x1, ext->y1, ext->x2 - ext->x1, ext->y2 - ext->y1);
1055 }
1056 
1057 void river_scene_ovdbg_dump(struct wlr_scene_node *node, const char *tag) {
1058 	wlr_scene_node_for_each_buffer(node, river_ovdbg_buffer_iter, (void *)tag);
1059 }
1060 
1061 /* Overview-delay/shadow debugging: report a window's drop-shadow node state so
1062  * it can be compared against the window's current zoom scale. Everything here
1063  * is device px, as update_shadow writes it. */
1064 void river_scene_shadow_dbg(struct wlr_scene_shadow *shadow, const char *tag) {
1065 	if (!shadow) {
1066 		fprintf(stderr, "[ovdbg] %s shadow=NULL\n", tag);
1067 		return;
1068 	}
1069 	struct wlr_scene_node *node = &shadow->node;
1070 	fprintf(stderr,
1071 		"[ovdbg] %s shadow en=%d pos=(%d,%d) size=%dx%d sigma=%.1f radius=%d "
1072 		"clip=(%d,%d %dx%d)\n",
1073 		tag, node->enabled, node->x, node->y, shadow->width, shadow->height,
1074 		shadow->blur_sigma, shadow->corner_radius,
1075 		shadow->clipped_region.area.x, shadow->clipped_region.area.y,
1076 		shadow->clipped_region.area.width, shadow->clipped_region.area.height);
1077 }
1078 
1079 /* ------------------------------------------------------------------
1080  * CPU-backed buffer: lets the compositor hand the renderer pixels it
1081  * rasterized itself (the desktop-grid square labels). wlroots has no public
1082  * constructor for this, so implement the minimal wlr_buffer: the renderer
1083  * reaches the pixels through data-ptr access and uploads them like any shm
1084  * buffer. The data is copied in, so the caller's Rust Vec can be dropped.
1085  * ------------------------------------------------------------------ */
1086 struct cce_data_buffer {
1087 	struct wlr_buffer base;
1088 	void *data;
1089 	uint32_t format;
1090 	size_t stride;
1091 };
1092 
1093 static void cce_data_buffer_destroy(struct wlr_buffer *wlr_buffer) {
1094 	struct cce_data_buffer *buf = (struct cce_data_buffer *)wlr_buffer;
1095 	free(buf->data);
1096 	free(buf);
1097 }
1098 
1099 static bool cce_data_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer,
1100 		uint32_t flags, void **data, uint32_t *format, size_t *stride) {
1101 	struct cce_data_buffer *buf = (struct cce_data_buffer *)wlr_buffer;
1102 	if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) {
1103 		return false; /* immutable once built */
1104 	}
1105 	*data = buf->data;
1106 	*format = buf->format;
1107 	*stride = buf->stride;
1108 	return true;
1109 }
1110 
1111 static void cce_data_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {
1112 	/* nothing to unmap */
1113 }
1114 
1115 static const struct wlr_buffer_impl cce_data_buffer_impl = {
1116 	.destroy = cce_data_buffer_destroy,
1117 	.begin_data_ptr_access = cce_data_buffer_begin_data_ptr_access,
1118 	.end_data_ptr_access = cce_data_buffer_end_data_ptr_access,
1119 };
1120 
1121 /* Copy `data` (ARGB8888, premultiplied, `stride` bytes per row) into a new
1122  * buffer. Returns NULL on allocation failure. The buffer starts with one
1123  * reference, as wlr_buffer_init leaves it: pass it to a scene buffer and then
1124  * drop this reference with wlr_buffer_drop(). */
1125 struct wlr_buffer *river_data_buffer_create(int width, int height,
1126 		size_t stride, const void *data) {
1127 	if (width <= 0 || height <= 0 || stride == 0) {
1128 		return NULL;
1129 	}
1130 	struct cce_data_buffer *buf = calloc(1, sizeof(*buf));
1131 	if (!buf) {
1132 		return NULL;
1133 	}
1134 	size_t size = stride * (size_t)height;
1135 	buf->data = malloc(size);
1136 	if (!buf->data) {
1137 		free(buf);
1138 		return NULL;
1139 	}
1140 	memcpy(buf->data, data, size);
1141 	buf->format = DRM_FORMAT_ARGB8888;
1142 	buf->stride = stride;
1143 	wlr_buffer_init(&buf->base, &cce_data_buffer_impl, width, height);
1144 	return &buf->base;
1145 }
1146 
1147 /* Mark every optimized-blur node in the scene dirty, forcing a re-bake of the
1148  * shared blurred-backdrop cache on the next frame. The cache is otherwise
1149  * invalidated only by blur-parameter setters and window blur RESIZES
1150  * (optimized_blur_set_size marks dirty; a same-size re-enable does not), so
1151  * backdrop CONTENT that changes without either — the grid client latching a
1152  * new patch after the viewport has settled, or the client<->fallback grid
1153  * swap — leaves every translucent window showing a stale bake. */
1154 static void mark_optimized_blur_dirty_rec(struct wlr_scene_node *node) {
1155 	if (node->type == WLR_SCENE_NODE_OPTIMIZED_BLUR) {
1156 		wlr_scene_optimized_blur_mark_dirty(wlr_scene_optimized_blur_from_node(node));
1157 		return;
1158 	}
1159 	if (node->type == WLR_SCENE_NODE_TREE) {
1160 		struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
1161 		struct wlr_scene_node *child;
1162 		wl_list_for_each(child, &tree->children, link) {
1163 			mark_optimized_blur_dirty_rec(child);
1164 		}
1165 	}
1166 }
1167 
1168 void river_scene_mark_optimized_blur_dirty(struct wlr_scene *scene) {
1169 	mark_optimized_blur_dirty_rec(&scene->tree.node);
1170 }
1171 
1172 /* See wlr_scene.blur_frozen: suspend the moved-node-below blur
1173  * invalidation for the duration of a camera pan. Thawing marks every
1174  * optimized blur dirty once so the settled frame re-bakes against the
1175  * final backdrop. */
1176 /* See wlr_scene.blur_frozen. Blurs sample the shared cache where their own
1177  * bake lives, frozen or not, and bake the strips they newly expose as they
1178  * travel, so a pan needs no re-bake at either end: the thaw is just the
1179  * flag. */
1180 void river_scene_set_blur_frozen(struct wlr_scene *scene, bool frozen) {
1181 	scene->blur_frozen = frozen;
1182 }
1183 
1184 /* See wlr_scene.desk_trees: this subtree renders with the desk's
1185  * sub-pixel offset. Idempotent; silently ignores a ninth tree. */
1186 struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
1187 
1188 void river_scene_tree_set_desk_offset(struct wlr_scene_tree *tree, bool on) {
1189 	struct wlr_scene *scene = scene_node_get_root(&tree->node);
1190 	if (scene == NULL) {
1191 		return;
1192 	}
1193 	int free_slot = -1;
1194 	for (int i = 0; i < WLR_SCENE_DESK_TREES; i++) {
1195 		if (scene->desk_trees[i] == tree) {
1196 			if (!on) {
1197 				scene->desk_trees[i] = NULL;
1198 			}
1199 			return;
1200 		}
1201 		if (scene->desk_trees[i] == NULL && free_slot < 0) {
1202 			free_slot = i;
1203 		}
1204 	}
1205 	if (on && free_slot >= 0) {
1206 		scene->desk_trees[free_slot] = tree;
1207 	}
1208 }
1209 
1210 /* See wlr_scene.desk_sub_x/y: the camera pan's remainder below one
1211  * layout pixel, each in (-1, 0]. Changing it moves every desk node on
1212  * screen, which the caller damages (it is a camera move). */
1213 void river_scene_set_desk_subpixel(struct wlr_scene *scene, double sub_x, double sub_y) {
1214 	scene->desk_sub_x = sub_x;
1215 	scene->desk_sub_y = sub_y;
1216 }
1217 
1218 struct wl_signal *river_wlr_session_get_active_signal(struct wlr_session *session) {
1219 	return &session->events.active;
1220 }
1221 
1222 bool river_wlr_session_get_active(struct wlr_session *session) {
1223 	return session->active;
1224 }