AtlatestRepositorysigil-wm

sigil-wm / tree / src / chost.c

1/*
2 * SPDX-License-Identifier: MIT AND BSD-3-Clause
3 *
4 * This file started from wlroots' compositor example (see UPSTREAM.md). The
5 * original portions remain under the MIT license below. sigil-wm changes are
6 * Copyright (C) 2026 David Wilson and licensed under the BSD 3-Clause
7 * License (see LICENSE).
8 *
9 * Copyright (c) 2017, 2018 Drew DeVault
10 * Copyright (c) 2014 Jari Vetoniemi
11 * Copyright (c) 2023 The wlroots contributors
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a copy of
14 * this software and associated documentation files (the "Software"), to deal in
15 * the Software without restriction, including without limitation the rights to
16 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
17 * of the Software, and to permit persons to whom the Software is furnished to do
18 * so, subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included in all
21 * copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 * SOFTWARE.
30 */
32#define _GNU_SOURCE
33#include <stdbool.h>
34#include <errno.h>
35#include <limits.h>
36#include <math.h>
37#include <pthread.h>
38#include <stdatomic.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <sys/eventfd.h>
43#include <time.h>
44#include <unistd.h>
45#include <sys/stat.h>
46#include <xf86drmMode.h>
47#include <drm_fourcc.h>
48#include <wayland-server-core.h>
49#include <wlr/backend.h>
50#include <wlr/backend/session.h>
51#include <wlr/types/wlr_xdg_activation_v1.h>
52#include <wlr/types/wlr_server_decoration.h>
53#include <wlr/backend/headless.h>
54#include <wlr/backend/drm.h>
55#include <wlr/backend/multi.h>
56#include <wlr/backend/wayland.h>
57#include <wlr/interfaces/wlr_buffer.h>
58#include <wlr/interfaces/wlr_keyboard.h>
59#include <wlr/render/allocator.h>
60#include <wlr/render/wlr_renderer.h>
61#include <wlr/types/wlr_compositor.h>
62#include <wlr/types/wlr_subcompositor.h>
63#include <wlr/types/wlr_cursor.h>
64#include <wlr/types/wlr_data_device.h>
65#include <wlr/types/wlr_fractional_scale_v1.h>
66#include <wlr/types/wlr_input_device.h>
67#include <wlr/types/wlr_pointer_constraints_v1.h>
68#include <wlr/util/region.h>
69#include <wlr/types/wlr_output_power_management_v1.h>
70#include <wlr/types/wlr_output_management_v1.h>
71#include <wlr/types/wlr_output_swapchain_manager.h>
72#include <wlr/types/wlr_gamma_control_v1.h>
73#include <wlr/backend/libinput.h>
74#include <wlr/types/wlr_keyboard.h>
75#include <wlr/types/wlr_layer_shell_v1.h>
76#include <wlr/types/wlr_output.h>
77#include <wlr/types/wlr_output_layout.h>
78#include <wlr/types/wlr_pointer.h>
79#include <wlr/types/wlr_relative_pointer_v1.h>
80#include <wlr/types/wlr_scene.h>
81#include <wlr/types/wlr_seat.h>
82#include <wlr/types/wlr_session_lock_v1.h>
83#include <wlr/types/wlr_security_context_v1.h>
84#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
85#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
86#include <wlr/types/wlr_virtual_keyboard_v1.h>
87#include <wlr/types/wlr_virtual_pointer_v1.h>
88#include <wlr/types/wlr_xcursor_manager.h>
89#include <wlr/types/wlr_xdg_decoration_v1.h>
90#include <wlr/types/wlr_idle_notify_v1.h>
91#include <wlr/types/wlr_idle_inhibit_v1.h>
92#include <wlr/types/wlr_data_control_v1.h>
93#include <wlr/types/wlr_primary_selection.h>
94#include <wlr/types/wlr_primary_selection_v1.h>
95#include <wlr/types/wlr_presentation_time.h>
96#include <wlr/types/wlr_single_pixel_buffer_v1.h>
97#include <wlr/types/wlr_xdg_output_v1.h>
98#include <wlr/types/wlr_screencopy_v1.h>
99#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
100#include <wlr/types/wlr_ext_image_capture_source_v1.h>
101#include <wlr/types/wlr_cursor_shape_v1.h>
102#include <wlr/types/wlr_viewporter.h>
103#include <wlr/types/wlr_xdg_shell.h>
104#include <wlr/util/log.h>
105#include <xkbcommon/xkbcommon.h>
106#include <wlr/xwayland.h>
107#include "api.h"
108#include "trace-records.h"
110#define QUEUE_SIZE 1024
111#define INPUT_DECISION_DEADLINE_MS 32
112#define MAX_PLAN_VIEWS 256
113/* Four header words plus ten per placement fit the 65536-word bridge. */
114#define MAX_PLAN 6553
115#define MAX_KEYS 768
116#define MAX_PIXELS (32u * 1024 * 1024)
117/* All of these objects are confined to the native owner except the bridge. */
118struct queue { struct wm_message entries[QUEUE_SIZE]; atomic_uint read, write; };
119static struct {
120 pthread_t thread;
121 struct queue events, commands;
122 int event_fd, command_fd;
123 bool created, joined;
124 bool terminal_delivered;
125 atomic_int state;
126 atomic_uint_fast64_t frames, objects, overflow, rejected, bytes, pixel_nodes, pixel_drops, saved_trees, snapshots;
127 atomic_uint_fast64_t input_expired,motion_coalesced,timer_wakes,first_present_ms;
128 atomic_bool input_resync;
129 char socket[64],requested_socket[64];
130 int64_t protocols,request_deadline;
131 uint32_t legacy_decoration_default;
132} bridge;
133struct server;
134struct lock_surface;
135struct permission;
136struct active_drag;
137struct constraint;
138struct pending_output_batch;
139struct output {
140 struct trace_output trace;
141 struct wl_list link;
142 struct server *server;
143 uint64_t id;
144 struct wlr_output *native;
145 struct wl_listener frame, destroy, request, readback;
146 struct wlr_scene_output *scene;
147 char capture[PATH_MAX];
148 unsigned sample_frames, sample_index, sample_count;
149 int sample_points[128];
150 struct wl_listener lock_present,wake_present,gamma_present;
151 uint64_t wake_requested,wake_commit_time;
152 uint32_t wake_commit;
153 bool wake_armed;
154 bool pending_power,pending_on;
155 struct lock_surface *lock_surface;
156 struct wlr_scene_rect *lock_fill;
157 uint64_t lock_generation;
158 uint32_t lock_commit;
159 bool lock_presented, lock_armed;
160 bool configured_enabled,gamma_pending,gamma_external,nearest_filter;
161 uint16_t *gamma_table;
162 size_t gamma_size;
163 uint64_t gamma_token,gamma_retry_at,scene_retry_at;
164 int x,y;
165 uint64_t configuration_generation;
166};
167struct view {
168 struct wl_list link;
169 struct server *server;
170 uint64_t id;
171 struct wlr_xdg_toplevel *native;
172 struct wlr_layer_surface_v1 *layer;
173 struct wlr_xwayland_surface *x11;
174 struct wlr_scene_tree *tree, *live, *saved;
175 struct wl_listener map, unmap, commit, destroy, title, app_id;
176 struct wl_listener move, resize, maximize, fullscreen;
177 struct wl_listener role_popup, role_output_destroy;
178 struct wl_listener associate, dissociate, request_configure, set_geometry, request_activate;
179 int width, height;
180 struct wlr_box committed;
181 uint32_t committed_serial;
182 uint32_t serial, layer_present_commit;
183 bool layer_presented, layer_present_armed;
184 bool initialized, mapped, clip_enabled;
185 int clip_width,clip_height;
186 int hints_min_width,hints_min_height,hints_max_width,hints_max_height;
187 uint64_t hints_parent;
188 struct wlr_ext_foreign_toplevel_handle_v1 *foreign_list;
189 struct wlr_foreign_toplevel_handle_v1 *foreign;
190 struct wl_listener foreign_activate,foreign_close,foreign_fullscreen;
191 struct wl_listener foreign_maximize,foreign_minimize;
192 struct wlr_box foreign_box;
193 bool foreign_placed,foreign_fullscreen_state;
194};
195static struct wlr_scene_node *view_surface_tree(struct view *view) {
196 if(!view->live) return NULL;
197 if(!view->native) return &view->live->node;
198 if(wl_list_empty(&view->live->children)) return NULL;
199 struct wlr_scene_node *surface_tree=wl_container_of(view->live->children.next,surface_tree,link);
200 return surface_tree;
202static void apply_view_clip(struct view *view) {
203 struct wlr_scene_node *surface_tree=view_surface_tree(view);
204 if(!surface_tree) return;
205 struct wlr_box clip={view->native ? view->committed.x : 0,
206 view->native ? view->committed.y : 0,view->clip_width,view->clip_height};
207 wlr_scene_subsurface_tree_set_clip(surface_tree,view->clip_enabled ? &clip : NULL);
209static void discard_saved(struct view *view) {
210 if(!view->saved) return;
211 wlr_scene_node_destroy(&view->saved->node);
212 view->saved=NULL;
213 atomic_fetch_sub(&bridge.saved_trees,1);
215struct device {
216 struct wl_list link;
217 struct server *server;
218 struct wlr_input_device *native;
219 uint64_t id;
220 bool is_virtual;
221 struct wl_listener destroy;
222};
223struct keyboard {
224 struct wl_list link;
225 struct server *server;
226 uint64_t id;
227 struct wlr_keyboard *native;
228 struct wl_listener key, modifiers, destroy;
229 int forwarded[MAX_KEYS];
230 int forwarded_modifiers[MAX_KEYS];
231 bool is_virtual,session_consumed[MAX_KEYS],intercepted[MAX_KEYS],fixed_group;
232 uint32_t group;
233};
234struct pixels {
235 struct wl_list link;
236 uint64_t id;
237 struct wlr_scene_buffer *scene;
238 bool input;
239 struct server *server;
240 int64_t scope[5];
241};
242struct pixel_buffer {
243 unsigned trace_count;
244 uint64_t trace_causes[TRACE_CAUSES];
245 struct wlr_buffer base;
246 size_t length, stride, order_count;
247 bool input;
248 int64_t scope[5];
249 unsigned char data[];
250};
251struct input_intercept { uint32_t code, modifiers, mask; int scope; int64_t target; };
252struct input {
253 uint64_t token, device, generation, completion, deadline,press_token,order_deadline;
254 int kind, code, state, origin;
255 uint32_t time, modifiers, keysym, base_keysym, first_keysym;
256 int result, replacement;
257 int replacement_modifiers;
258 bool ready,notified,native,completed;
259 int64_t target;
260 uint64_t output;
261 double x, y;
262};
263struct scene_move_item { int64_t id; int x,y; };
264struct scene_move {
265 bool retained,active;
266 uint64_t token,window,device;
267 int button,dx,dy;
268 double pointer_x,pointer_y;
269 unsigned count;
270 struct scene_move_item items[256];
271};
272struct server {
273 struct wl_display *display;
274 struct wlr_security_context_manager_v1 *security_context;
275 struct wlr_ext_foreign_toplevel_list_v1 *foreign_list;
276 struct wlr_foreign_toplevel_manager_v1 *foreign_manager;
277 struct wlr_backend *backend;
278 struct wlr_session *session;
279 struct wlr_xdg_activation_v1 *activation;
280 struct wl_listener activation_request;
281 struct { uint32_t symbol; unsigned vt; } session_switches[12];
282 unsigned session_switch_count;
283 struct wlr_renderer *renderer;
284 struct wlr_allocator *allocator;
285 struct wlr_scene *scene;
286 struct wlr_scene_tree *normal;
287 struct wlr_scene_tree *lock_scene;
288 struct wlr_session_lock_v1 *lock_owner;
289 struct wl_listener new_lock, lock_new_surface, lock_unlock, lock_destroy;
290 int lock_state;
291 uint32_t lock_colour;
292 uint64_t lock_generation, lock_deadline;
293 struct wlr_output_layout *layout;
294 struct wlr_scene_output_layout *scene_layout;
295 struct wlr_xdg_shell *shell;
296 struct wlr_compositor *compositor;
297 struct wlr_xwayland *xwayland;
298 struct wl_listener new_x11, x11_destroy, x11_ready;
299 struct wlr_seat *seat;
300 struct wlr_cursor *cursor;
301 struct wlr_relative_pointer_manager_v1 *relative;
302 struct wlr_xcursor_manager *cursor_manager;
303 struct wl_list data_requests;
304 unsigned data_request_count;
305 struct wl_listener selection_request,primary_request,drag_request,drag_started,cursor_shape;
306 struct active_drag *drag;
307 struct wlr_scene_tree *drag_scene;
308 bool follow_drag_icon,allow_client_cursor;
309 struct wlr_idle_notifier_v1 *idle;
310 int activity_classes,activity_origins;
311 struct wl_list outputs, views, keyboards, devices, pixels, permissions,decorations,popups,inhibitors;
312 struct wl_list constraints,pointer_hints;
313 struct wlr_pointer_constraints_v1 *pointer_constraints;
314 struct constraint *active_constraint;
315 struct wl_listener new_constraint,constraint_pointer_focus,constraint_keyboard_focus;
316 unsigned constraint_count,pointer_hint_count;
317 bool observing_constraints,relative_route;
318 struct wl_list output_controls,output_requests;
319 struct wlr_output_manager_v1 *output_manager;
320 struct wl_listener output_apply,output_test;
321 unsigned output_request_count;
322 uint64_t output_revision;
323 unsigned output_control_count;
324 struct wl_list pending_outputs;
325 unsigned pending_output_count;
326 struct wl_event_source *output_idle;
327 bool output_commit_attempted;
328 struct wlr_output_power_manager_v1 *power_manager;
329 struct wlr_gamma_control_manager_v1 *gamma_manager;
330 struct wl_listener power_request,gamma_request;
331 struct wl_listener new_virtual_keyboard,new_virtual_pointer;
332 struct wl_listener new_decoration,new_inhibitor,new_legacy_decoration;
333 struct wl_list legacy_decorations;
334 unsigned decoration_count;
335 struct wl_listener new_output, new_view, new_popup, new_input, new_layer;
336 uint64_t default_layer_output;
337 char pending_output_name[129];
338 struct wl_listener motion, absolute, button, axis, cursor_frame, cursor_request;
339 struct wl_event_source *commands, *timer, *inventory_idle;
340 struct wlr_keyboard synthetic;
341 struct xkb_state *emulation_state;
342 struct keyboard synthetic_owner;
343 uint64_t next_id, next_token, generation, focus;
344 struct input inputs[QUEUE_SIZE];
345 unsigned input_read, input_write;
346 struct { uint64_t device,press_token; int code,target; bool held; } buttons[QUEUE_SIZE];
347 unsigned key_refs[MAX_KEYS];
348 struct input_intercept key_intercepts[QUEUE_SIZE],button_intercepts[QUEUE_SIZE];
349 unsigned key_intercept_count,button_intercept_count;
350 bool key_intercept_all,button_intercept_all;
351 struct { uint64_t device,press_token; int code; bool held; } intercepted_buttons[QUEUE_SIZE];
352 bool motion_hook, route_hit_test, stopping;
353 bool observe_pointer, pointer_sampled, pointer_motion_only;
354 uint32_t keyboard_modifiers;
355 int64_t pointer_target;
356 uint64_t pointer_output, pointer_sample_token, pointer_sample_generation;
357 uint64_t motion_generation;
358 uint64_t motion_delivered_token;
359 int64_t motion_device, motion_period, motion_last;
360 double motion_x,motion_y;
361 struct scene_move scene_move;
362 struct input pending_motion;
363 bool has_pending_motion;
364 struct wlr_box motion_region;
365 int64_t *plan;
366 size_t plan_count;
367 int64_t plan_token;
368 uint64_t plan_deadline, scene_update_deadline, trace_correlation, timer_deadline;
369 unsigned plan_trace_count;
370 uint64_t plan_trace_causes[TRACE_CAUSES];
371};
373static void scene_move_finish(struct server *s);
374static void scene_move_button(struct server *s,const struct input *input);
375static bool scene_move_motion(struct server *s,uint32_t time,double x,double y,uint64_t completion,int origin);
376static void scene_move_position(struct server *s,int64_t resource,struct wlr_scene_node *node,int x,int y);
377static void scene_move_plan(struct server *s,const int64_t *w);
378#include "security-context.h"
379#include "output-inventory.h"
381static uint64_t now_ms(void) {
382 struct timespec ts;
383 clock_gettime(CLOCK_MONOTONIC, &ts);
384 return (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
386static void wake(int fd);
387static void latency_trace_at(int stage, uint64_t token, uint64_t object, uint64_t detail,
388 const struct timespec *timestamp) {
389 if(trace_record_at(stage,token,object,detail,timestamp) && bridge.created && !bridge.joined)
390 wake(bridge.event_fd);
392static void latency_trace(int stage, uint64_t token, uint64_t object, uint64_t detail) {
393 latency_trace_at(stage, token, object, detail, NULL);
395void wm_latency_mark(int stage, uint64_t token) {
396 if (stage < 0 || stage > 31) return;
397 latency_trace(stage,token,0,0);
399void wm_trace_enable(int enabled) { atomic_store(&trace.enabled,enabled!=0); }
400uint64_t wm_trace_dropped(void) { return atomic_load(&trace.dropped); }
401static void trace_damage(struct server *s,uint64_t correlation,uint64_t output) {
402 if(!atomic_load_explicit(&trace.enabled,memory_order_relaxed)) return;
403 struct output *o;
404 wl_list_for_each(o,&s->outputs,link)
405 if(!output || o->id==output) trace_output_damage(&o->trace,correlation);
407static bool push(struct queue *q, struct wm_message m) {
408 unsigned w = atomic_load_explicit(&q->write, memory_order_relaxed);
409 unsigned r = atomic_load_explicit(&q->read, memory_order_acquire);
410 if (w - r == QUEUE_SIZE) return false;
411 q->entries[w % QUEUE_SIZE] = m;
412 atomic_store_explicit(&q->write, w + 1, memory_order_release);
413 return true;
415static bool pop(struct queue *q, struct wm_message *m) {
416 unsigned r = atomic_load_explicit(&q->read, memory_order_relaxed);
417 unsigned w = atomic_load_explicit(&q->write, memory_order_acquire);
418 if (r == w) return false;
419 *m = q->entries[r % QUEUE_SIZE];
420 atomic_store_explicit(&q->read, r + 1, memory_order_release);
421 return true;
423static void wake(int fd) {
424 uint64_t one = 1;
425 ssize_t result;
426 do { result = write(fd, &one, sizeof(one)); } while (result < 0 && errno == EINTR);
427 if (result < 0 && errno != EAGAIN) atomic_fetch_add(&bridge.overflow, 1);
429static void drain(int fd) {
430 uint64_t value;
431 while (read(fd, &value, sizeof(value)) < 0 && errno == EINTR) {}
433#include "event-stream.h"
434#define EVENT(...) emit((struct wm_message){ .word = {__VA_ARGS__} })
435static void listen(struct wl_signal *signal, struct wl_listener *listener,
436 void (*notify)(struct wl_listener *, void *)) {
437 listener->notify = notify;
438 wl_signal_add(signal, listener);
440static void activity(struct server *s,int kind,int origin) {
441 if(s->lock_state && origin!=0) return;
442 if(s->idle && (s->activity_classes&kind) && (s->activity_origins&(1<<origin)))
443 wlr_idle_notifier_v1_notify_activity(s->idle,s->seat);
445static struct view *find_view(struct server *s, uint64_t id) {
446 struct view *v;
447 wl_list_for_each(v, &s->views, link) if (v->id == id) return v;
448 return NULL;
450static struct output *find_output(struct server *s, uint64_t id) {
451 struct output *o;
452 wl_list_for_each(o, &s->outputs, link) if (o->id == id) return o;
453 return NULL;
455static struct pixels *find_pixels(struct server *s,uint64_t id) {
456 struct pixels *p;
457 wl_list_for_each(p,&s->pixels,link) if(p->id==id) return p;
458 return NULL;
460static struct keyboard *find_keyboard(struct server *s, uint64_t id) {
461 if (id == s->synthetic_owner.id) return &s->synthetic_owner;
462 struct keyboard *k;
463 wl_list_for_each(k, &s->keyboards, link) if (k->id == id) return k;
464 return NULL;
466#include "roles.h"
467#include "foreign-toplevel.h"
469static bool visible(struct view *v) {
470 int x, y;
471 return v && v->tree && v->mapped && wlr_scene_node_coords(&v->tree->node, &x, &y);
473static void deliver_key(struct server *s, uint32_t time, int code, bool pressed, int override) {
474 struct wlr_keyboard *key = &s->synthetic;
475 if (!key->xkb_state) return;
476 if(pressed) { if(s->key_refs[code]++>0) return; }
477 else { if(!s->key_refs[code] || --s->key_refs[code]>0) return; }
478 /* Publish an explicitly changed group before the next key uses it.
479 * Modifier transitions caused by this key still follow the key event. */
480 if(override<0) wlr_seat_keyboard_notify_modifiers(s->seat,&key->modifiers);
481 xkb_state_update_key(key->xkb_state, code + 8, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
482 struct wlr_keyboard_modifiers mods = {
483 .depressed = xkb_state_serialize_mods(key->xkb_state, XKB_STATE_MODS_DEPRESSED),
484 .latched = xkb_state_serialize_mods(key->xkb_state, XKB_STATE_MODS_LATCHED),
485 .locked = xkb_state_serialize_mods(key->xkb_state, XKB_STATE_MODS_LOCKED),
486 .group = xkb_state_serialize_layout(key->xkb_state, XKB_STATE_LAYOUT_EFFECTIVE),
487 };
488 key->modifiers = mods;
489 if(override>=0) {
490 struct wlr_keyboard_modifiers replaced=mods;
491 replaced.depressed=0;
492 const char *names[8]={XKB_MOD_NAME_SHIFT,XKB_MOD_NAME_CAPS,XKB_MOD_NAME_CTRL,
493 XKB_MOD_NAME_ALT,"Mod2","Mod3",XKB_MOD_NAME_LOGO,"Mod5"};
494 for(int bit=0;bit<8;bit++) {
495 xkb_mod_index_t index=xkb_keymap_mod_get_index(key->keymap,names[bit]);
496 if((override&(1<<bit)) && index<32) replaced.depressed|=1u<<index;
497 }
498 wlr_seat_keyboard_notify_modifiers(s->seat,&replaced);
499 }
500 wlr_seat_keyboard_notify_key(s->seat, time, code, pressed);
501 wlr_seat_keyboard_notify_modifiers(s->seat, &mods);
503static void constraints_end(struct server *s);
504static void constraints_observe(struct server *s);
505static void constrained_warp(struct server *s,double x,double y);
506static void clear_held(struct server *s) {
507 struct keyboard *k = &s->synthetic_owner;
508 for (int pass = 0; ; pass++) {
509 for (int i = 0; i < MAX_KEYS; i++) {
510 k->intercepted[i]=false;
511 if (k->forwarded[i] >= 0) {
512 deliver_key(s, now_ms(), k->forwarded[i], false,k->forwarded_modifiers[i]);
513 k->forwarded[i] = -1;
514 }
515 }
516 if (!pass) {
517 if (wl_list_empty(&s->keyboards)) break;
518 k = wl_container_of(s->keyboards.next, k, link);
519 } else {
520 if (k->link.next == &s->keyboards) break;
521 k = wl_container_of(k->link.next, k, link);
522 }
523 }
524 for (int i = 0; i < QUEUE_SIZE; i++) {
525 if (s->buttons[i].held) {
526 wlr_seat_pointer_notify_button(s->seat, now_ms(), s->buttons[i].target, WL_POINTER_BUTTON_STATE_RELEASED);
527 s->buttons[i].held = false;
528 }
529 }
531static void route_motion(struct server *s, uint32_t time, bool moved);
532static void set_focus(struct server *s, uint64_t id) {
533 if (s->lock_state) return;
534 struct view *v = id ? find_view(s, id) : NULL;
535 if (id && (!visible(v) || (v->layer && v->layer->current.keyboard_interactive ==
536 ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE))) return;
537 if (s->focus == id) return;
538 clear_held(s);
539 route_motion(s,now_ms(),false);
540 /* XWM selection authorization follows its active X surface, not the
541 * Wayland seat alone. Focus can change without a configure transaction. */
542 struct view *previous = find_view(s, s->focus);
543 if (previous && previous->x11)
544 wlr_xwayland_surface_activate(previous->x11, false);
545 if (v && v->x11)
546 wlr_xwayland_surface_activate(v->x11, true);
547 s->focus = id;
548 s->generation++;
549 if (!v) wlr_seat_keyboard_notify_clear_focus(s->seat);
550 else {
551 struct wlr_keyboard *k = &s->synthetic;
552 wlr_seat_set_keyboard(s->seat, k);
553 wlr_seat_keyboard_notify_enter(s->seat, view_surface(v), NULL, 0, &k->modifiers);
554 }
555 latency_trace(11, s->trace_correlation, id, s->generation);
556 EVENT(25, id, s->generation, s->trace_correlation);
557 foreign_refresh(s);
558 constraints_observe(s);
560static struct wlr_surface *surface_at(struct server *s, double x, double y, double *sx, double *sy) {
561 struct wlr_scene_node *node = wlr_scene_node_at(
562 s->lock_state ? &s->lock_scene->node : &s->normal->node, x, y, sx, sy);
563 if (!node || node->type != WLR_SCENE_NODE_BUFFER) return NULL;
564 struct wlr_scene_surface *surface = wlr_scene_surface_try_from_buffer(wlr_scene_buffer_from_node(node));
565 if(surface) return surface->surface;
566 while(node && node->parent!=s->normal)
567 node=node->parent ? &node->parent->node : NULL;
568 if(!node || node->type!=WLR_SCENE_NODE_TREE || !node->data) return NULL;
569 struct view *view=node->data;
570 if(!view->saved || !view->mapped) return NULL;
571 int vx,vy;
572 if(!wlr_scene_node_coords(&view->tree->node,&vx,&vy)) return NULL;
573 double local_x=x-vx+view->committed.x, local_y=y-vy+view->committed.y;
574 if(view->native) return wlr_xdg_surface_surface_at(view->native->base,local_x,local_y,sx,sy);
575 if(view->layer) return wlr_layer_surface_v1_surface_at(view->layer,local_x,local_y,sx,sy);
576 return wlr_surface_surface_at(view_surface(view),local_x,local_y,sx,sy);
578static int64_t target_at(struct server *s, double x, double y);
579static void update_drag_icon(struct server *s);
580struct pointer_surface_position {
581 struct wlr_surface *surface;
582 int x,y;
583 bool found;
584};
585static void pointer_surface_position(struct wlr_scene_buffer *buffer,int x,int y,void *data) {
586 struct pointer_surface_position *position=data;
587 struct wlr_scene_surface *scene=wlr_scene_surface_try_from_buffer(buffer);
588 if(scene && scene->surface==position->surface) {
589 /* Subsurface trees move the buffer to its clip origin. Implicit
590 * grabs need the unclipped surface origin retained by its parent. */
591 position->x=x-buffer->node.x;
592 position->y=y-buffer->node.y;
593 position->found=true;
594 }
596static void pointer_native_position(struct wlr_surface *surface,int x,int y,void *data) {
597 struct pointer_surface_position *position=data;
598 if(surface==position->surface) {
599 position->x+=x; position->y+=y; position->found=true;
600 }
602static void route_motion(struct server *s, uint32_t time, bool moved) {
603 update_drag_icon(s);
604 if(s->route_hit_test) {
605 double sx,sy;
606 struct wlr_surface *surface=surface_at(s,s->cursor->x,s->cursor->y,&sx,&sy);
607 if(s->seat->pointer_state.button_count && !wlr_seat_pointer_has_grab(s->seat)) {
608 struct pointer_surface_position position={.surface=s->seat->pointer_state.focused_surface};
609 wlr_scene_node_for_each_buffer(s->lock_state ? &s->lock_scene->node : &s->normal->node,
610 pointer_surface_position,&position);
611 if(!position.found) {
612 struct view *view;
613 wl_list_for_each(view,&s->views,link) {
614 if(!view->saved || !visible(view)) continue;
615 int vx,vy;
616 wlr_scene_node_coords(&view->tree->node,&vx,&vy);
617 position.x=vx-view->committed.x; position.y=vy-view->committed.y;
618 view_each_surface(view,pointer_native_position,&position);
619 if(position.found) break;
620 }
621 }
622 surface=position.found ? position.surface : NULL;
623 sx=s->cursor->x-position.x; sy=s->cursor->y-position.y;
624 }
625 if(surface) {
626 wlr_seat_pointer_notify_enter(s->seat,surface,sx,sy);
627 wlr_seat_pointer_notify_motion(s->seat,time,sx,sy);
628 } else wlr_seat_pointer_notify_clear_focus(s->seat);
629 wlr_seat_pointer_notify_frame(s->seat);
630 }
631 if(s->observe_pointer && !(s->pointer_motion_only && !s->pointer_sampled && !moved)) {
632 int64_t target=target_at(s,s->cursor->x,s->cursor->y);
633 struct wlr_output *native=wlr_output_layout_output_at(s->layout,s->cursor->x,s->cursor->y);
634 struct output *output=native ? native->data : NULL;
635 uint64_t id=output ? output->id : 0;
636 if(!s->pointer_sampled || target!=s->pointer_target || id!=s->pointer_output) {
637 s->pointer_sampled=true;
638 s->pointer_target=target; s->pointer_output=id;
639 s->pointer_sample_token=++s->next_token;
640 s->pointer_sample_generation=s->generation;
641 EVENT(37,target,id,(int64_t)(s->cursor->x*1000),(int64_t)(s->cursor->y*1000),moved,s->generation,s->pointer_sample_token);
642 }
643 }
644 constraints_observe(s);
646static bool motion_matches(struct server *s,const struct input *in) {
647 return s->motion_hook && (!s->motion_device || in->device==(uint64_t)s->motion_device) &&
648 (!s->motion_region.width || wlr_box_contains_point(&s->motion_region,in->x,in->y));
650static struct device *find_device(struct server *s,uint64_t id);
651static void notify_input(struct server *s,struct input *in);
652static void deliver_ready_input(struct server *s,struct input *in) {
653 bool valid = (in->generation == s->generation || (in->native && in->kind==30)) &&
654 !(s->lock_state && in->origin != 0) &&
655 (in->origin==1 || find_device(s,in->device));
656 if(in->kind==31 && in->state)
657 valid=valid && target_at(s,in->x,in->y)==in->target;
658 if (in->kind == 30) {
659 struct keyboard *k = find_keyboard(s, in->device);
660 if (k && in->code >= 0 && in->code < MAX_KEYS) {
661 int code = k->forwarded[in->code];
662 if (!in->state) {
663 if (code >= 0) {
664 deliver_key(s, in->time, code, false,
665 k->forwarded_modifiers[in->code]<0 ? (int)in->modifiers : k->forwarded_modifiers[in->code]);
666 k->forwarded[in->code] = -1;
667 }
668 } else if (valid && in->result && code<0 && in->replacement >= 0 && in->replacement < MAX_KEYS) {
669 code = in->result == 2 ? in->replacement : in->code;
670 k->forwarded[in->code] = code;
671 k->forwarded_modifiers[in->code]=in->result==2 ? in->replacement_modifiers : -1;
672 deliver_key(s, in->time, code, true,
673 k->forwarded_modifiers[in->code]<0 ? (int)in->modifiers : k->forwarded_modifiers[in->code]);
674 }
675 }
676 } else if (in->kind == 31 && in->code >= 0 && in->code < MAX_KEYS) {
677 int found=-1,empty=-1;
678 for(int i=0;i<QUEUE_SIZE;i++) {
679 if(s->buttons[i].held && s->buttons[i].device==in->device && s->buttons[i].code==in->code) found=i;
680 if(!s->buttons[i].held && empty<0) empty=i;
681 }
682 if(!in->state) {
683 uint64_t press_token=in->press_token;
684 if(found>=0) {
685 press_token=s->buttons[found].press_token;
686 wlr_seat_pointer_notify_button(s->seat,in->time,s->buttons[found].target,0);
687 s->buttons[found].held=false;
688 }
689 /* Motion can precede the eventual focus decision. Publish a fresh
690 * observation at release in the current epoch, so managers can
691 * reconcile hover after their button/grab state clears. */
692 bool moved=press_token && s->motion_delivered_token>press_token;
693 if(moved) s->pointer_sampled=false;
694 route_motion(s,in->time,moved);
695 } else if(in->state && valid && in->result && found<0 && empty>=0) {
696 int target=in->result==2 ? in->replacement : in->code;
697 /* Cursor transport may have advanced while this press waited.
698 * Revalidate its copied scene hit and deliver to that surface,
699 * without moving the cursor back or stealing an existing grab. */
700 if(!s->seat->pointer_state.button_count && !wlr_seat_pointer_has_grab(s->seat)) {
701 double sx,sy;
702 struct wlr_surface *surface=surface_at(s,in->x,in->y,&sx,&sy);
703 if(surface) wlr_seat_pointer_notify_enter(s->seat,surface,sx,sy);
704 else wlr_seat_pointer_notify_clear_focus(s->seat);
705 }
706 s->buttons[empty].device=in->device; s->buttons[empty].code=in->code;
707 s->buttons[empty].press_token=in->token;
708 s->buttons[empty].target=target; s->buttons[empty].held=true;
709 wlr_seat_pointer_notify_button(s->seat,in->time,target,1);
710 route_motion(s,in->time,false);
711 }
712 wlr_seat_pointer_notify_frame(s->seat);
713 } else if (in->kind == 32 && valid && in->result && in->token>s->motion_delivered_token &&
714 (in->native || (uint64_t)in->code == s->motion_generation)) {
715 s->motion_delivered_token=in->token;
716 constrained_warp(s,in->x,in->y);
717 route_motion(s, in->time,true);
718 }
719 else if(in->kind==33 && valid && in->result &&
720 target_at(s,s->cursor->x,s->cursor->y)==in->target) {
721 wlr_seat_pointer_notify_axis(s->seat,in->time,in->state,in->x,(int32_t)in->y,in->code,in->modifiers);
722 wlr_seat_pointer_notify_frame(s->seat);
723 }
724 if(!in->native || in->completion)
725 EVENT(35, in->completion ? in->completion : in->token, valid, in->origin, in->token);
727static void cancel_intercepted_input(struct server *s) {
728 /* Cancel queued interception, leaving ordinary native streams untouched. */
729 while(s->input_read!=s->input_write) {
730 struct input *input=&s->inputs[s->input_read++%QUEUE_SIZE];
731 if(input->completed) continue;
732 input->ready=true;
733 input->result=input->native || input->kind==32;
734 if(input->kind==32) input->native=true;
735 deliver_ready_input(s,input);
736 }
738static void deliver_input(struct server *s) {
739 if(atomic_exchange(&bridge.input_resync,false)) {
740 /* Transport resync invalidates discarded decision tokens. */
741 cancel_intercepted_input(s);
742 EVENT(99,0,3);
743 }
744 /* A waiting bound chord cannot hold cursor transport behind it. Expire
745 * hooked motion independently, then retire its queue slot in seat order.
746 * The transport token prevents an older delayed sample undoing new motion. */
747 uint64_t now=now_ms();
748 /* Ordinary keys preserve seat order behind a chord only for its original
749 * budget. Release them in order even while the bound decision still waits.
750 * They remain native and never need a policy disposition. */
751 for(unsigned index=s->input_read;index!=s->input_write;index++) {
752 struct input *key=&s->inputs[index%QUEUE_SIZE];
753 if(key->kind!=30 || !key->native || key->completed) continue;
754 if(now<key->order_deadline) break;
755 deliver_ready_input(s,key);
756 key->completed=true;
757 }
758 for(unsigned index=s->input_read;index!=s->input_write;index++) {
759 struct input *motion=&s->inputs[index%QUEUE_SIZE];
760 if(motion->kind!=32 || motion->completed || motion->ready || now<motion->deadline) continue;
761 motion->ready=true; motion->native=true; motion->result=1;
762 atomic_fetch_add(&bridge.input_expired,1);
763 deliver_ready_input(s,motion);
764 motion->completed=true;
765 }
766 while (s->input_read != s->input_write) {
767 struct input *in = &s->inputs[s->input_read % QUEUE_SIZE];
768 if(in->completed) { s->input_read++; continue; }
769 if(in->native && in->kind==32 && in->generation==s->generation && motion_matches(s,in)) {
770 if(now_ms()-(uint64_t)s->motion_last < (uint64_t)s->motion_period) {
771 if(s->input_read+1!=s->input_write) {
772 struct input *next=&s->inputs[(s->input_read+1)%QUEUE_SIZE];
773 if(next->native && next->kind==32 && next->device==in->device &&
774 next->origin==in->origin && next->generation==in->generation && motion_matches(s,next)) {
775 if(in->completion) EVENT(35,in->completion,0,in->origin,in->token);
776 s->input_read++;
777 continue;
778 }
779 }
780 break;
781 }
782 in->native=false; in->ready=false; in->code=s->motion_generation;
783 s->motion_last=now_ms();
784 }
785 if(!in->ready && now_ms()>=in->deadline) {
786 atomic_fetch_add(&bridge.input_expired,1);
787 /* Bound decisions stay intercepted across scheduler stalls.
788 * Ordinary keys leave independently after their ordering budget. */
789 if(in->kind==30 || in->kind==31) {
790 wlr_log(WLR_INFO,"INPUT_BOUND_TIMEOUT kind=%d device=%llu code=%d token=%llu outcome=wait",
791 in->kind,(unsigned long long)in->device,in->code,(unsigned long long)in->token);
792 in->deadline=UINT64_MAX;
793 } else {
794 in->ready=true;
795 in->result=in->kind==32;
796 if(in->kind==32) in->native=true;
797 }
798 }
799 if(!in->ready && !in->notified) {
800 bool stale=in->generation!=s->generation;
801 bool semantic_key=in->kind==30 && !s->lock_state;
802 if((stale && !semantic_key) || (s->lock_state && in->origin!=0) ||
803 (in->origin!=1 && !find_device(s,in->device))) {
804 in->ready=true; in->result=0;
805 } else {
806 in->notified=true;
807 notify_input(s,in);
808 }
809 }
810 if (!in->ready) break;
811 deliver_ready_input(s,in);
812 s->input_read++;
813 }
814 if(s->input_read==s->input_write && !s->has_pending_motion) {
815 s->motion_x=s->cursor->x; s->motion_y=s->cursor->y;
816 }
818static int64_t target_at(struct server *s, double x, double y) {
819 update_drag_icon(s);
820 if(s->lock_state) return 0;
821 double sx,sy;
822 struct wlr_scene_node *node=wlr_scene_node_at(&s->normal->node,x,y,&sx,&sy);
823 while(node && node->parent!=s->normal)
824 node=node->parent ? &node->parent->node : NULL;
825 if(node && node->type==WLR_SCENE_NODE_BUFFER) {
826 struct pixels *p;
827 wl_list_for_each(p,&s->pixels,link)
828 if(&p->scene->node==node) return -(int64_t)p->id;
829 return 0;
830 }
831 if(!node || node->type!=WLR_SCENE_NODE_TREE || !node->data) return 0;
832 return ((struct view *)node->data)->id;
834static void notify_input(struct server *s,struct input *in) {
835 struct input input=*in;
836 int64_t detail=input.kind==30 ? input.base_keysym : input.target;
837 int64_t extra=input.kind==30 ? input.first_keysym : (int64_t)input.output;
838 EVENT(input.kind,input.token,input.device,input.time,input.code,input.state,
839 input.modifiers,s->focus,input.generation,input.origin,
840 (int64_t)(input.x*1000),(int64_t)(input.y*1000),
841 input.kind==32 ? (uint64_t)input.code : s->motion_generation,input.keysym,detail,extra);
843static uint64_t window_for_surface(struct server *s,struct wlr_surface *surface);
844static bool intercept_matches(struct server *s,const struct input *input) {
845 bool key=input->kind==30;
846 if(key ? (s->key_intercept_all && !s->lock_state) : s->button_intercept_all) return true;
847 struct input_intercept *rules=key ? s->key_intercepts : s->button_intercepts;
848 unsigned count=key ? s->key_intercept_count : s->button_intercept_count;
849 for(unsigned i=0;i<count;i++) {
850 struct input_intercept *rule=&rules[i];
851 if((input->modifiers & rule->mask)!=rule->modifiers) continue;
852 if(key) {
853 if((rule->scope==1 && s->lock_state) || (rule->scope==2 && !s->lock_state)) continue;
854 if(rule->code==input->keysym || rule->code==input->base_keysym || rule->code==input->first_keysym)
855 return true;
856 } else if((!rule->code || rule->code==(uint32_t)input->code) &&
857 (rule->scope==0 || (rule->scope==1 && input->target>0) ||
858 (rule->scope==2 && input->target<0) ||
859 (rule->scope==3 && rule->target==input->target) ||
860 (rule->scope==4 && input->target>0 &&
861 (uint64_t)input->target!=window_for_surface(s,s->seat->keyboard_state.focused_surface))))
862 return true;
863 }
864 return false;
866static bool configure_input_intercepts(struct server *s,bool key,int64_t *words,int64_t count) {
867 if(count<2 || words[0]<0 || words[0]>1 || words[1]<0 || words[1]>QUEUE_SIZE ||
868 count!=2+words[1]*5) return false;
869 for(int i=0;i<words[1];i++) {
870 int64_t *rule=words+2+i*5;
871 if(rule[0]<0 || rule[0]>UINT32_MAX || rule[1]<0 || rule[1]>255 ||
872 rule[2]<0 || rule[2]>255 || (rule[1] & ~rule[2]) ||
873 rule[3]<0 || rule[3]>(key ? 2 : 4)) return false;
874 }
875 struct input_intercept *rules=key ? s->key_intercepts : s->button_intercepts;
876 for(int i=0;i<words[1];i++) {
877 int64_t *rule=words+2+i*5;
878 rules[i]=(struct input_intercept){rule[0],rule[1],rule[2],rule[3],rule[4]};
879 }
880 if(key) { s->key_intercept_all=words[0]; s->key_intercept_count=words[1]; }
881 else { s->button_intercept_all=words[0]; s->button_intercept_count=words[1]; }
882 return true;
884static void queue_input(struct server *s,struct input input) {
885 scene_move_button(s,&input);
886 if(input.kind!=32 && s->has_pending_motion) {
887 struct input pending=s->pending_motion;
888 s->has_pending_motion=false;
889 queue_input(s,pending);
890 }
891 if(input.kind==30 || input.kind==31) activity(s,input.kind==30 ? 1 : 4,input.origin);
892 input.token=++s->next_token;
893 if(!input.generation) input.generation=s->generation;
894 input.deadline=now_ms()+INPUT_DECISION_DEADLINE_MS;
895 input.order_deadline=input.deadline;
896 if(input.kind==31 || input.kind==32) {
897 input.target=target_at(s,input.x,input.y);
898 struct wlr_output *native=wlr_output_layout_output_at(s->layout,input.x,input.y);
899 struct output *output=native ? native->data : NULL;
900 input.output=output ? output->id : 0;
901 }
902 bool intercepted=true;
903 if(input.kind==30) {
904 struct keyboard *keyboard=find_keyboard(s,input.device);
905 if(!keyboard || input.code<0 || input.code>=MAX_KEYS) return;
906 intercepted=input.state ? intercept_matches(s,&input) : keyboard->intercepted[input.code];
907 if(getenv("SIGIL_WM_DEBUG_INPUT") && input.state)
908 wlr_log(WLR_ERROR,"INPUT_ELIGIBILITY device=%llu code=%d modifiers=%u symbol=%u base=%u first=%u rules=%u all=%d intercept=%d",
909 (unsigned long long)input.device,input.code,input.modifiers,input.keysym,input.base_keysym,
910 input.first_keysym,s->key_intercept_count,s->key_intercept_all,intercepted);
911 keyboard->intercepted[input.code]=input.state && intercepted;
912 } else if(input.kind==31) {
913 int found=-1,empty=-1;
914 for(int i=0;i<QUEUE_SIZE;i++) {
915 if(s->intercepted_buttons[i].held && s->intercepted_buttons[i].device==input.device &&
916 s->intercepted_buttons[i].code==input.code) found=i;
917 if(!s->intercepted_buttons[i].held && empty<0) empty=i;
918 }
919 intercepted=input.state ? intercept_matches(s,&input) : found>=0;
920 if(input.state && intercepted && found<0 && empty>=0) {
921 s->intercepted_buttons[empty].device=input.device;
922 s->intercepted_buttons[empty].press_token=input.token;
923 s->intercepted_buttons[empty].code=input.code;
924 s->intercepted_buttons[empty].held=true;
925 } else if(!input.state && found>=0) {
926 input.press_token=s->intercepted_buttons[found].press_token;
927 s->intercepted_buttons[found].held=false;
928 }
929 }
930 if ((input.kind == 30 || input.kind == 31) && input.state)
931 latency_trace(0, input.token, input.code, 0);
932 if(!intercepted) {
933 input.native=true; input.ready=true; input.result=1; input.replacement=input.code;
934 if(input.kind==31) {
935 /* Observation precedes client delivery, so a subsequent client
936 * move/resize request sees the press without blocking that press. */
937 struct input observed=input;
938 observed.kind=126;
939 notify_input(s,&observed);
940 }
941 uint64_t order_deadline=0;
942 if(input.kind==30) {
943 for(unsigned index=s->input_read;index!=s->input_write;index++) {
944 struct input *pending=&s->inputs[index%QUEUE_SIZE];
945 if(pending->kind==30 && !pending->completed) {
946 order_deadline=pending->order_deadline;
947 break;
948 }
949 }
950 }
951 if(!order_deadline || now_ms()>=order_deadline) {
952 deliver_input(s);
953 deliver_ready_input(s,&input);
954 return;
955 }
956 input.order_deadline=order_deadline;
957 }
958 if(input.kind==32 && s->input_read!=s->input_write) {
959 struct input *last=&s->inputs[(s->input_write-1)%QUEUE_SIZE];
960 if(last->kind==32 && !last->notified && !last->completed && last->device==input.device &&
961 last->origin==input.origin && last->generation==input.generation) {
962 if(last->completion) EVENT(35,last->completion,0,last->origin,last->token);
963 input.deadline=last->deadline;
964 atomic_fetch_add(&bridge.motion_coalesced,1);
965 *last=input;
966 deliver_input(s);
967 return;
968 }
969 }
970 if(s->input_write-s->input_read==QUEUE_SIZE) {
971 cancel_intercepted_input(s);
972 input.ready=true; input.result=input.native || input.kind==32;
973 if(input.kind==32) input.native=true;
974 deliver_ready_input(s,&input);
975 EVENT(99,0,2); return;
976 }
977 s->inputs[s->input_write++%QUEUE_SIZE]=input;
978 deliver_input(s);
980#include "keyboard-settings.h"
981static uint64_t window_for_surface(struct server *s,struct wlr_surface *surface);
982static void lock_keyboard_input(struct keyboard *keyboard,struct wlr_keyboard_key_event *event);
983#include "session-control.h"
985static void key_event(struct wl_listener *listener, void *data) {
986 struct keyboard *k = wl_container_of(listener, k, key);
987 struct wlr_keyboard_key_event *e = data;
988 if(session_key(k,e)) return;
989 struct input input={.kind=30, .device=k->id, .time=e->time_msec,
990 .code=e->keycode, .state=e->state, .origin=k->is_virtual ? 2 : 0,
991 .keysym=k->native->xkb_state ? xkb_state_key_get_one_sym(k->native->xkb_state,e->keycode+8) : 0,
992 .modifiers=wlr_keyboard_get_modifiers(k->native),
993 .base_keysym=base_keysym(k->native,e->keycode,false),
994 .first_keysym=base_keysym(k->native,e->keycode,true)};
995 if(k->server->lock_state) {
996 if(k->is_virtual) return;
997 bool intercepted=e->state ? intercept_matches(k->server,&input) :
998 (e->keycode<MAX_KEYS && k->intercepted[e->keycode]);
999 if(!intercepted) { lock_keyboard_input(k,e); return; }
1001 queue_input(k->server,input);
1003static void modifier_event(struct wl_listener *listener, void *data) {
1004 (void)data;
1005 struct keyboard *keyboard=wl_container_of(listener,keyboard,modifiers);
1006 if(keyboard->fixed_group && keyboard->native->modifiers.group!=keyboard->group) {
1007 struct wlr_keyboard_modifiers *mods=&keyboard->native->modifiers;
1008 wlr_keyboard_notify_modifiers(keyboard->native,mods->depressed,mods->latched,mods->locked,keyboard->group);
1009 return;
1011 keyboard->server->keyboard_modifiers=wlr_keyboard_get_modifiers(keyboard->native);
1012 if(keyboard->server->lock_state && !keyboard->is_virtual)
1013 wlr_seat_keyboard_notify_modifiers(keyboard->server->seat,&keyboard->native->modifiers);
1014 EVENT(43,keyboard->id,keyboard->server->keyboard_modifiers,keyboard->native->modifiers.group);
1016static void keyboard_destroy(struct wl_listener *listener, void *data) {
1017 (void)data;
1018 struct keyboard *k = wl_container_of(listener, k, destroy);
1019 for(int code=0;code<MAX_KEYS;code++) {
1020 if(k->forwarded[code]>=0)
1021 deliver_key(k->server,now_ms(),k->forwarded[code],false,k->forwarded_modifiers[code]);
1023 wl_list_remove(&k->key.link);
1024 wl_list_remove(&k->modifiers.link);
1025 wl_list_remove(&k->destroy.link);
1026 wl_list_remove(&k->link);
1027 free(k);
1029#include "devices.h"
1030static void attach_input(struct server *s,struct wlr_input_device *native,bool is_virtual) {
1031 struct device *device=calloc(1,sizeof(*device));
1032 if(!device) { atomic_fetch_add(&bridge.overflow,1); return; }
1033 device->server=s; device->native=native; device->id=++s->next_id;
1034 device->is_virtual=is_virtual;
1035 native->data=(void *)(uintptr_t)((device->id<<1)|(is_virtual ? 1 : 0));
1036 wl_list_insert(&s->devices,&device->link);
1037 listen(&native->events.destroy,&device->destroy,device_destroy);
1038 atomic_fetch_add(&bridge.objects,1);
1039 bool libinput=wlr_input_device_is_libinput(native);
1040 struct libinput_device *handle=libinput ? wlr_libinput_get_device_handle(native) : NULL;
1041 EVENT(40,device->id,native->type,is_virtual,libinput,
1042 handle ? libinput_device_config_tap_get_finger_count(handle) : 0,wlr_input_device_is_wl(native));
1043 object_text(device->id,28,native->name);
1044 if(native->type==WLR_INPUT_DEVICE_KEYBOARD) {
1045 struct keyboard *keyboard=calloc(1,sizeof(*keyboard));
1046 if(!keyboard) { atomic_fetch_add(&bridge.overflow,1); return; }
1047 keyboard->id=device->id; keyboard->server=s; keyboard->is_virtual=is_virtual;
1048 keyboard->native=wlr_keyboard_from_input_device(native);
1049 for(int code=0;code<MAX_KEYS;code++) keyboard->forwarded[code]=-1;
1050 listen(&keyboard->native->events.key,&keyboard->key,key_event);
1051 listen(&keyboard->native->events.modifiers,&keyboard->modifiers,modifier_event);
1052 listen(&native->events.destroy,&keyboard->destroy,keyboard_destroy);
1053 wl_list_insert(&s->keyboards,&keyboard->link);
1054 } else if(native->type==WLR_INPUT_DEVICE_POINTER)
1055 wlr_cursor_attach_input_device(s->cursor,native);
1057static void new_input(struct wl_listener *listener,void *data) {
1058 struct server *s=wl_container_of(listener,s,new_input);
1059 attach_input(s,data,false);
1061static void motion_input(struct server *s, uint32_t time, double x, double y, uint64_t device, int origin, uint64_t completion) {
1062 if(s->lock_state && origin!=0) return;
1063 activity(s,2,origin);
1064 s->motion_x=x; s->motion_y=y;
1065 if(scene_move_motion(s,time,x,y,completion,origin)) return;
1066 bool matches = s->motion_hook && (!s->motion_device || device == (uint64_t)s->motion_device) &&
1067 (!s->motion_region.width || wlr_box_contains_point(&s->motion_region, x, y));
1068 if (matches) {
1069 struct input in={.kind=32, .device=device, .code=s->motion_generation,
1070 .time=time, .x=x, .y=y, .origin=origin, .completion=completion,
1071 .generation=s->generation, .modifiers=s->keyboard_modifiers};
1072 if (now_ms()-(uint64_t)s->motion_last < (uint64_t)s->motion_period) {
1073 if(s->has_pending_motion && s->pending_motion.completion)
1074 EVENT(35,s->pending_motion.completion,0,s->pending_motion.origin);
1075 s->pending_motion=in; s->has_pending_motion=true;
1076 return;
1078 s->motion_last=now_ms();
1079 queue_input(s,in);
1080 } else {
1081 s->motion_delivered_token=++s->next_token;
1082 constrained_warp(s,x,y);
1083 s->motion_x=s->cursor->x; s->motion_y=s->cursor->y;
1084 route_motion(s, time,true);
1085 if (completion) EVENT(35, completion, 1, origin);
1088static void cursor_motion(struct wl_listener *listener, void *data) {
1089 struct server *s = wl_container_of(listener, s, motion);
1090 struct wlr_pointer_motion_event *e = data;
1091 uintptr_t tag=(uintptr_t)e->pointer->base.data;
1092 if(s->lock_state && (tag&1)) return;
1093 if(s->relative_route && !s->lock_state)
1094 wlr_relative_pointer_manager_v1_send_relative_motion(s->relative,s->seat,
1095 (uint64_t)e->time_msec*1000,e->delta_x,e->delta_y,e->unaccel_dx,e->unaccel_dy);
1096 s->motion_x+=e->delta_x; s->motion_y+=e->delta_y;
1097 motion_input(s, e->time_msec, s->motion_x, s->motion_y, tag>>1, tag&1 ? 2 : 0, 0);
1099static void cursor_absolute(struct wl_listener *listener, void *data) {
1100 struct server *s = wl_container_of(listener, s, absolute);
1101 struct wlr_pointer_motion_absolute_event *e = data;
1102 double x, y;
1103 wlr_cursor_absolute_to_layout_coords(s->cursor, &e->pointer->base, e->x, e->y, &x, &y);
1104 s->motion_x=x; s->motion_y=y;
1105 uintptr_t tag=(uintptr_t)e->pointer->base.data;
1106 motion_input(s, e->time_msec, x, y, tag>>1, tag&1 ? 2 : 0, 0);
1108static double pointer_x(struct server *s) {
1109 return s->input_read!=s->input_write || s->has_pending_motion ? s->motion_x : s->cursor->x;
1111static double pointer_y(struct server *s) {
1112 return s->input_read!=s->input_write || s->has_pending_motion ? s->motion_y : s->cursor->y;
1114static void axis_input(struct server *s,uint64_t device,int origin,uint32_t time,
1115 int orientation,double delta,int32_t discrete,int source,int direction,uint64_t completion) {
1116 activity(s,8,origin);
1117 (void)device;
1118 if(s->lock_state && origin!=0) return;
1120 wlr_seat_pointer_notify_axis(s->seat,time,orientation,delta,discrete,source,direction);
1121 wlr_seat_pointer_notify_frame(s->seat);
1122 if(completion) EVENT(35,completion,1,origin);
1125static void cursor_button(struct wl_listener *listener, void *data) {
1126 struct server *s = wl_container_of(listener, s, button);
1127 struct wlr_pointer_button_event *e = data;
1128 uintptr_t tag=(uintptr_t)e->pointer->base.data;
1129 queue_input(s, (struct input){.kind=31, .device=tag>>1, .origin=tag&1 ? 2 : 0, .time=e->time_msec, .code=e->button,
1130 .state=e->state, .x=pointer_x(s), .y=pointer_y(s), .modifiers=s->keyboard_modifiers});
1132static void cursor_axis(struct wl_listener *listener, void *data) {
1133 struct server *s = wl_container_of(listener, s, axis);
1134 struct wlr_pointer_axis_event *e = data;
1135 if(s->lock_state && ((uintptr_t)e->pointer->base.data&1)) return;
1136 uintptr_t tag=(uintptr_t)e->pointer->base.data;
1137 axis_input(s,tag>>1,tag&1 ? 2 : 0,e->time_msec,e->orientation,e->delta,
1138 e->delta_discrete,e->source,e->relative_direction,0);
1140static void cursor_frame(struct wl_listener *listener, void *data) {
1141 (void)data;
1142 struct server *s = wl_container_of(listener, s, cursor_frame);
1143 wlr_seat_pointer_notify_frame(s->seat);
1145static void cursor_request(struct wl_listener *listener, void *data) {
1146 struct server *s = wl_container_of(listener, s, cursor_request);
1147 struct wlr_seat_pointer_request_set_cursor_event *e = data;
1148 if (s->allow_client_cursor && e->seat_client == s->seat->pointer_state.focused_client)
1149 wlr_cursor_set_surface(s->cursor, e->surface, e->hotspot_x, e->hotspot_y);
1152static void layer_presentation(struct view *view, bool presented, uint32_t sequence);
1153static void layer_output_present(struct output *output, struct wlr_output_event_present *event);
1154#include "lock.h"
1155#include "permissions.h"
1156static uint64_t window_for_surface(struct server *s,struct wlr_surface *surface);
1157#include "extensions.h"
1158#include "legacy-decorations.h"
1159#include "desktop.h"
1160#include "constraints.h"
1162static void check_plan(struct server *s);
1163static void view_map(struct wl_listener *listener, void *data) {
1164 (void)data;
1165 struct view *v=wl_container_of(listener,v,map);
1166 v->mapped=true;
1167 foreign_map(v);
1168 wlr_scene_node_set_enabled(&v->tree->node, false);
1169 struct wlr_box box=v->native->base->geometry;
1170 if(box.width<=0 || box.height<=0) {
1171 box.width=v->native->base->surface->current.width;
1172 box.height=v->native->base->surface->current.height;
1174 v->committed=box;
1175 v->committed_serial=v->native->base->current.configure_serial;
1176 EVENT(18,v->id,box.x,box.y,box.width,box.height,v->committed_serial);
1177 EVENT(11,v->id);
1178 object_text(v->id,15,v->native->title);
1179 object_text(v->id,16,v->native->app_id);
1181static void view_unmap(struct wl_listener *listener, void *data) {
1182 (void)data;
1183 struct view *v=wl_container_of(listener,v,unmap);
1184 v->mapped=false;
1185 if (v->layer) {
1186 v->layer_present_commit = 0;
1187 v->layer_present_armed = false;
1188 layer_presentation(v, false, 0);
1190 foreign_unmap(v);
1191 if(v->tree) wlr_scene_node_set_enabled(&v->tree->node,false);
1192 if(v->server->focus==v->id) set_focus(v->server,0);
1193 EVENT(12,v->id);
1194 check_plan(v->server);
1196static void view_commit(struct wl_listener *listener, void *data) {
1197 (void)data;
1198 struct view *v=wl_container_of(listener,v,commit);
1199 struct wlr_xdg_toplevel_state *h=&v->native->current;
1200 uint64_t parent=v->native->parent ? ((struct view *)v->native->parent->base->data)->id : 0;
1201 if(v->native->base->initial_commit || v->hints_min_width!=h->min_width ||
1202 v->hints_min_height!=h->min_height || v->hints_max_width!=h->max_width ||
1203 v->hints_max_height!=h->max_height || v->hints_parent!=parent) {
1204 int kind=v->native->base->initial_commit ? 14 : 123;
1205 EVENT(kind,v->id,h->min_width,h->min_height,h->max_width,h->max_height,parent);
1206 v->hints_min_width=h->min_width;
1207 v->hints_min_height=h->min_height;
1208 v->hints_max_width=h->max_width;
1209 v->hints_max_height=h->max_height;
1210 v->hints_parent=parent;
1212 struct wlr_box box=v->native->base->geometry;
1213 if(box.x!=v->committed.x || box.y!=v->committed.y || box.width!=v->committed.width || box.height!=v->committed.height ||
1214 v->committed_serial!=v->native->base->current.configure_serial) {
1215 v->committed=box;
1216 v->committed_serial=v->native->base->current.configure_serial;
1217 EVENT(18,v->id,box.x,box.y,box.width,box.height,v->native->base->current.configure_serial);
1219 apply_view_clip(v);
1220 check_plan(v->server);
1222static void view_destroy(struct wl_listener *listener, void *data) {
1223 (void)data;
1224 struct view *v=wl_container_of(listener,v,destroy);
1225 struct server *s=v->server;
1226 foreign_unmap(v);
1227 if(s->focus==v->id) set_focus(s,0);
1228 wl_list_remove(&v->map.link); wl_list_remove(&v->unmap.link);
1229 wl_list_remove(&v->commit.link); wl_list_remove(&v->destroy.link);
1230 wl_list_remove(&v->title.link); wl_list_remove(&v->app_id.link);
1231 wl_list_remove(&v->move.link); wl_list_remove(&v->resize.link);
1232 wl_list_remove(&v->maximize.link); wl_list_remove(&v->fullscreen.link);
1233 wl_list_remove(&v->link);
1234 v->native->base->data=NULL;
1235 discard_saved(v); wlr_scene_node_destroy(&v->tree->node);
1236 EVENT(13,v->id);
1237 atomic_fetch_sub(&bridge.objects,1);
1238 free(v);
1239 check_plan(s);
1241static void view_title(struct wl_listener *listener, void *data) {
1242 (void)data;
1243 struct view *v=wl_container_of(listener,v,title);
1244 object_text(v->id,15,v->native->title);
1245 foreign_metadata(v);
1247static void view_app_id(struct wl_listener *listener, void *data) {
1248 (void)data;
1249 struct view *v=wl_container_of(listener,v,app_id);
1250 object_text(v->id,16,v->native->app_id);
1251 foreign_metadata(v);
1253static void view_move(struct wl_listener *listener, void *data) {
1254 struct view *v=wl_container_of(listener,v,move);
1255 struct wlr_xdg_toplevel_move_event *e=data;
1256 if(wlr_seat_validate_pointer_grab_serial(v->server->seat,v->native->base->surface,e->serial))
1257 EVENT(17,v->id,1,e->serial);
1259static void view_resize(struct wl_listener *listener, void *data) {
1260 struct view *v=wl_container_of(listener,v,resize);
1261 struct wlr_xdg_toplevel_resize_event *e=data;
1262 if(wlr_seat_validate_pointer_grab_serial(v->server->seat,v->native->base->surface,e->serial))
1263 EVENT(17,v->id,2,e->serial,e->edges);
1265static void view_maximize(struct wl_listener *listener, void *data) {
1266 (void)data;
1267 struct view *v=wl_container_of(listener,v,maximize);
1268 EVENT(17,v->id,3,v->native->requested.maximized);
1270static void view_fullscreen(struct wl_listener *listener, void *data) {
1271 (void)data;
1272 struct view *v=wl_container_of(listener,v,fullscreen);
1273 EVENT(17,v->id,4,v->native->requested.fullscreen);
1275static void new_view(struct wl_listener *listener, void *data) {
1276 struct server *s=wl_container_of(listener,s,new_view);
1277 struct wlr_xdg_toplevel *native=data;
1278 struct view *v=calloc(1,sizeof(*v));
1279 if(!v) { wl_client_post_no_memory(wl_resource_get_client(native->resource)); return; }
1280 v->server=s; v->native=native; v->id=++s->next_id;
1281 v->tree=wlr_scene_tree_create(s->normal);
1282 if(!v->tree) { free(v); return; }
1283 v->live=wlr_scene_xdg_surface_create(v->tree,native->base);
1284 if(!v->live) { discard_saved(v); wlr_scene_node_destroy(&v->tree->node); free(v); return; }
1285 native->base->data=v;
1286 v->tree->node.data=v;
1287 wlr_scene_node_set_enabled(&v->tree->node,false);
1288 wl_list_insert(&s->views,&v->link);
1289 listen(&native->base->surface->events.map,&v->map,view_map);
1290 listen(&native->base->surface->events.unmap,&v->unmap,view_unmap);
1291 listen(&native->base->surface->events.commit,&v->commit,view_commit);
1292 listen(&native->events.destroy,&v->destroy,view_destroy);
1293 listen(&native->events.set_title,&v->title,view_title);
1294 listen(&native->events.set_app_id,&v->app_id,view_app_id);
1295 listen(&native->events.request_move,&v->move,view_move);
1296 listen(&native->events.request_resize,&v->resize,view_resize);
1297 listen(&native->events.request_maximize,&v->maximize,view_maximize);
1298 listen(&native->events.request_fullscreen,&v->fullscreen,view_fullscreen);
1299 atomic_fetch_add(&bridge.objects,1);
1300 pid_t pid=0;
1301 uid_t uid=0;
1302 gid_t gid=0;
1303 wl_client_get_credentials(wl_resource_get_client(native->resource),&pid,&uid,&gid);
1304 EVENT(10,v->id,0,pid,uid,gid);
1305 refresh_inhibitors(s);
1306 refresh_decorations(s);
1308struct popup {
1309 struct wl_list link;
1310 struct server *server;
1311 uint64_t id,parent,deadline;
1312 struct wlr_xdg_popup *native;
1313 struct wlr_scene_tree *tree;
1314 struct wl_listener commit,destroy,reposition;
1316static void constrain_popup(struct popup *p) {
1317 struct server *s=p->server;
1318 struct view *root=find_view(s,window_for_surface(s,p->native->parent));
1319 if(!root) return;
1320 int x,y;
1321 wlr_scene_node_coords(&root->tree->node,&x,&y);
1322 struct wlr_output *output=root->layer ? root->layer->output :
1323 wlr_output_layout_output_at(s->layout,x+root->committed.width/2.0,y+root->committed.height/2.0);
1324 if(!output) return;
1325 struct wlr_box box;
1326 wlr_output_layout_get_box(s->layout,output,&box);
1327 /* wlroots resolves nested popup offsets from the root surface origin. */
1328 box.x-=x-root->committed.x;
1329 box.y-=y-root->committed.y;
1330 wlr_xdg_popup_unconstrain_from_box(p->native,&box);
1332static void popup_request(struct popup *p) {
1333 constrain_popup(p);
1334 struct wlr_box box=p->native->scheduled.geometry;
1335 p->deadline=now_ms()+bridge.request_deadline;
1336 EVENT(80,p->id,p->parent,box.x,box.y,box.width,box.height);
1338static void popup_commit(struct wl_listener *listener,void *data) {
1339 (void)data;
1340 struct popup *p=wl_container_of(listener,p,commit);
1341 if(p->native->base->initial_commit) popup_request(p);
1343static void popup_reposition(struct wl_listener *listener,void *data) {
1344 (void)data;
1345 struct popup *p=wl_container_of(listener,p,reposition);
1346 popup_request(p);
1348static void popup_destroy(struct wl_listener *listener,void *data) {
1349 (void)data;
1350 struct popup *p=wl_container_of(listener,p,destroy);
1351 p->native->base->data=NULL;
1352 EVENT(81,p->id);
1353 wl_list_remove(&p->commit.link); wl_list_remove(&p->destroy.link);
1354 wl_list_remove(&p->reposition.link); wl_list_remove(&p->link); free(p);
1356static void new_popup(struct wl_listener *listener,void *data) {
1357 struct server *s=wl_container_of(listener,s,new_popup);
1358 struct wlr_xdg_popup *native=data;
1359 if(!native->parent || native->base->data) return;
1360 struct wlr_xdg_surface *parent=wlr_xdg_surface_try_from_wlr_surface(native->parent);
1361 struct wlr_scene_tree *parent_tree=NULL;
1362 uint64_t parent_id=0;
1363 struct wlr_layer_surface_v1 *layer=wlr_layer_surface_v1_try_from_wlr_surface(native->parent);
1364 if(layer && layer->data) {
1365 struct view *v=layer->data; parent_tree=v->tree; parent_id=v->id;
1366 } else if(!parent || !parent->data) return;
1367 else if(parent->role==WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
1368 struct view *v=parent->data; parent_tree=v->tree; parent_id=v->id;
1369 } else if(parent->role==WLR_XDG_SURFACE_ROLE_POPUP) {
1370 struct popup *p=parent->data; parent_tree=p->tree; parent_id=p->id;
1372 if(!parent_tree) return;
1373 struct popup *p=calloc(1,sizeof(*p));
1374 if(!p) return;
1375 p->native=native; p->server=s; p->parent=parent_id; p->id=++s->next_id;
1376 p->tree=wlr_scene_xdg_surface_create(parent_tree,native->base);
1377 if(!p->tree) { free(p); return; }
1378 native->base->data=p;
1379 wl_list_insert(&s->popups,&p->link);
1380 listen(&native->base->surface->events.commit,&p->commit,popup_commit);
1381 listen(&native->events.destroy,&p->destroy,popup_destroy);
1382 listen(&native->events.reposition,&p->reposition,popup_reposition);
1384static bool configure_popup(struct server *s,int64_t *w) {
1385 if(w[2]<-32768 || w[2]>32768 || w[3]<-32768 || w[3]>32768 ||
1386 w[4]<1 || w[4]>16384 || w[5]<1 || w[5]>16384) return false;
1387 struct popup *p;
1388 wl_list_for_each(p,&s->popups,link) {
1389 if(p->id!=(uint64_t)w[1] || !p->native->base->initialized) continue;
1390 p->native->scheduled.geometry=(struct wlr_box){w[2],w[3],w[4],w[5]};
1391 constrain_popup(p);
1392 wlr_xdg_surface_schedule_configure(p->native->base);
1393 p->deadline=0;
1394 return true;
1396 return false;
1399#include "layers.h"
1400#include "x11.h"
1402/* Plan header: version, count, keyboard focus, deadline-ms; records (10):
1403 * view, x,y,w,h, shown, activated, fullscreen, tiled-edges, clip.
1404 * Record order is explicit bottom-to-top stacking. */
1405static bool valid_plan(struct server *s,const int64_t *w,size_t n) {
1406 if(n<4 || w[0]!=1 || w[1]<0 || w[1]>MAX_PLAN || n!=4+(size_t)w[1]*10 ||
1407 w[3]<0 || w[3]>10000) return false;
1408 bool focus_valid=w[2]==0;
1409 unsigned views=0;
1410 for(int i=0;i<w[1];i++) {
1411 const int64_t *p=w+4+10*i;
1412 if(p[0]==INT64_MIN) return false;
1413 struct view *v=p[0]>0 ? find_view(s,p[0]) : NULL;
1414 if(p[0]>0 && ++views>MAX_PLAN_VIEWS) return false;
1415 struct pixels *image=p[0]<0 ? find_pixels(s,-p[0]) : NULL;
1416 if((!v && !image) || (v && !view_ready(v)) || p[1]<-32768 || p[1]>32768 ||
1417 p[2]<-32768 || p[2]>32768 || p[3]<1 || p[3]>16384 || p[4]<1 ||
1418 p[4]>16384 || p[5]<0 || p[5]>1 || p[6]<0 || p[6]>3 ||
1419 p[7]<0 || p[7]>1 || p[8]<0 || p[8]>15 || p[9]<0 || p[9]>3) return false;
1420 if(image && (p[6] || p[7] || p[8])) return false;
1421 for(int j=0;j<i;j++) if(w[4+10*j]==p[0]) return false;
1422 if(v && p[0]==w[2] && p[5] && v->mapped) focus_valid=true;
1424 return focus_valid;
1426static void save_buffer(struct wlr_scene_buffer *buffer, int x, int y, void *data) {
1427 struct view *v=data;
1428 if(!buffer->buffer) return;
1429 struct wlr_scene_buffer *copy=wlr_scene_buffer_create(v->saved,buffer->buffer);
1430 if(!copy) return;
1431 wlr_scene_buffer_set_dest_size(copy,buffer->dst_width,buffer->dst_height);
1432 wlr_scene_buffer_set_source_box(copy,&buffer->src_box);
1433 wlr_scene_buffer_set_transform(copy,buffer->transform);
1434 wlr_scene_buffer_set_opaque_region(copy,&buffer->opaque_region);
1435 wlr_scene_node_set_position(&copy->node,x,y);
1437static void release_saved(struct server *s) {
1438 struct view *v;
1439 wl_list_for_each(v,&s->views,link) {
1440 if(!v->saved) continue;
1441 discard_saved(v);
1442 wlr_scene_node_set_enabled(&v->live->node,true);
1445static void reject_plan_object(struct server *s,int reason,int64_t object) {
1446 if(s->plan) {
1447 EVENT(23,s->plan_token,reason,object,0);
1448 free(s->plan); s->plan=NULL;
1449 release_saved(s);
1452static void reject_plan(struct server *s,int reason) { reject_plan_object(s,reason,0); }
1453static bool plan_waits_for_view(struct server *s,struct view *view) {
1454 if(!s->plan || !view->mapped || view_configured(view)) return false;
1455 for(int i=0;i<s->plan[1];i++) {
1456 const int64_t *placement=s->plan+4+10*i;
1457 if(placement[0]==(int64_t)view->id) return placement[5]!=0;
1459 return false;
1461static bool pixel_scope_valid(struct server *s,const int64_t *scope);
1462static void check_plan(struct server *s) {
1463 if(!s->plan) return;
1464 const int64_t *w=s->plan;
1465 bool ready=true;
1466 for(int i=0;i<w[1];i++) {
1467 int64_t id=w[4+10*i];
1468 if(id<0) { if(!find_pixels(s,-id)) { reject_plan_object(s,2,id); return; } continue; }
1469 struct view *v=find_view(s,id);
1470 if(!v) { reject_plan_object(s,2,id); return; }
1471 if(plan_waits_for_view(s,v)) ready=false;
1473 if(!ready && now_ms()<s->plan_deadline) return;
1474 release_saved(s);
1475 scene_move_plan(s,w);
1476 for(int i=0;i<w[1];i++) {
1477 const int64_t *p=w+4+10*i;
1478 if(p[0]<0) {
1479 struct pixels *image=find_pixels(s,-p[0]);
1480 scene_move_position(s,p[0],&image->scene->node,p[1],p[2]);
1481 wlr_scene_buffer_set_dest_size(image->scene,p[3],p[4]);
1482 wlr_scene_node_set_enabled(&image->scene->node,
1483 p[5] && pixel_scope_valid(s,image->scope));
1484 wlr_scene_node_raise_to_top(&image->scene->node);
1485 continue;
1487 struct view *v=find_view(s,p[0]);
1488 scene_move_position(s,p[0],&v->tree->node,p[1],p[2]);
1489 wlr_scene_node_set_enabled(&v->tree->node,p[5] && v->mapped);
1490 if (v->layer && p[5] && v->mapped && !v->layer_presented && !v->layer_present_armed) {
1491 v->layer_present_commit = v->layer->output->commit_seq + 1;
1492 v->layer_present_armed = true;
1494 wlr_scene_node_raise_to_top(&v->tree->node);
1495 v->clip_enabled=(p[9]&1)!=0;
1496 v->clip_width=p[3]; v->clip_height=p[4];
1497 apply_view_clip(v);
1498 foreign_placement(v,p);
1500 uint64_t previous_correlation=s->trace_correlation;
1501 s->trace_correlation=s->plan_trace_count ? s->plan_trace_causes[0] : 0;
1502 set_focus(s,w[2]);
1503 s->trace_correlation=previous_correlation;
1504 foreign_refresh(s);
1505 route_motion(s,now_ms(),false);
1506 if (s->scene_update_deadline) {
1507 s->scene_update_deadline = 0;
1508 struct output *output;
1509 wl_list_for_each(output, &s->outputs, link) {
1510 wlr_damage_ring_add_whole(&output->scene->damage_ring);
1511 wlr_output_schedule_frame(output->native);
1514 for(unsigned i=0;i<s->plan_trace_count;i++) {
1515 trace_damage(s,s->plan_trace_causes[i],0);
1516 latency_trace(10,s->plan_trace_causes[i],s->plan_token,0);
1518 EVENT(22,s->plan_token,ready ? 0 : 1);
1519 free(s->plan); s->plan=NULL;
1521static int64_t missing_plan_object(struct server *s,const int64_t *w,size_t n) {
1522 if(n<4 || w[0]!=1 || w[1]<0 || w[1]>MAX_PLAN || n!=4+(size_t)w[1]*10) return 0;
1523 for(int i=0;i<w[1];i++) {
1524 int64_t id=w[4+10*i];
1525 if(id==INT64_MIN) return 0;
1526 if((id>0 && !find_view(s,id)) || (id<0 && !find_pixels(s,-id))) return id;
1528 return 0;
1530static bool submit_plan(struct server *s,int64_t token,int64_t *w,size_t n,unsigned trace_count) {
1531 int64_t missing=missing_plan_object(s,w,n);
1532 if(missing) { EVENT(23,token,2,missing,1); free(w); return false; }
1533 if(!valid_plan(s,w,n)) { EVENT(23,token,1); free(w); return false; }
1534 reject_plan(s,3);
1535 s->plan=w; s->plan_count=n; s->plan_token=token;
1536 s->plan_trace_count=trace_count;
1537 if(trace_count) memcpy(s->plan_trace_causes,w+n,trace_count*sizeof(uint64_t));
1538 s->plan_deadline=now_ms()+w[3];
1539 for(int i=0;i<w[1];i++) {
1540 const int64_t *p=w+4+10*i;
1541 if(p[0]<0) continue;
1542 struct view *v=find_view(s,p[0]);
1543 if(v->mapped && visible(v) && !v->saved) {
1544 v->saved=wlr_scene_tree_create(v->tree);
1545 if(v->saved) {
1546 atomic_fetch_add(&bridge.saved_trees,1);
1547 atomic_fetch_add(&bridge.snapshots,1);
1548 wlr_scene_node_for_each_buffer(&v->live->node,save_buffer,v);
1549 wlr_scene_node_set_enabled(&v->live->node,false);
1552 bool resize=(p[9]&2)==0;
1553 int width=resize || v->width<=0 ? p[3] : v->width;
1554 int height=resize || v->height<=0 ? p[4] : v->height;
1555 v->serial=configure_view(v,p[1],p[2],width,height,p[6]&1,p[7],p[8],(p[6]&2)!=0);
1556 v->width=width; v->height=height;
1558 EVENT(21,token);
1559 struct output *output;
1560 wl_list_for_each(output,&s->outputs,link)
1561 if(output->native->enabled) wlr_output_schedule_frame(output->native);
1562 check_plan(s);
1563 return true;
1565static void frame_done(struct wlr_surface *surface,int x,int y,void *data) {
1566 (void)x; (void)y;
1567 wlr_surface_send_frame_done(surface,data);
1569static void publish_output_management(struct server *s);
1570static void queue_output_flush(struct server *s);
1571#include "output-atomic.h"
1572#include "output-controls.h"
1573#include "output-gamma.h"
1574static void output_buffer_filter(struct wlr_scene_buffer *buffer,int x,int y,void *data) {
1575 (void)x; (void)y;
1576 struct output *output=data;
1577 buffer->filter_mode=output->nearest_filter ? WLR_SCALE_FILTER_NEAREST : WLR_SCALE_FILTER_BILINEAR;
1579static void output_frame_done(struct output *output,struct timespec *now) {
1580 wlr_scene_output_send_frame_done(output->scene,now);
1581 struct view *view;
1582 wl_list_for_each(view,&output->server->views,link)
1583 if(view->saved || plan_waits_for_view(output->server,view))
1584 view_each_surface(view,frame_done,now);
1586static void output_frame(struct wl_listener *listener,void *data) {
1587 (void)data;
1588 struct output *o=wl_container_of(listener,o,frame);
1589 if(!o->native->enabled) return;
1590 if (!o->server->lock_state && o->server->scene_update_deadline &&
1591 now_ms() < o->server->scene_update_deadline) {
1592 /* Keep configure/animation clients making progress while copied
1593 * decorations and their complete scene are being prepared. */
1594 struct timespec now;
1595 clock_gettime(CLOCK_MONOTONIC, &now);
1596 output_frame_done(o,&now);
1597 return;
1599 wlr_scene_output_for_each_buffer(o->scene,output_buffer_filter,o);
1600 lock_arm(o);
1601 bool committed=o->gamma_pending ? output_commit_gamma(o) : wlr_scene_output_commit(o->scene,NULL);
1602 if(!committed) {
1603 /* Retain damage and callbacks until a replacement frame is accepted. */
1604 wlr_damage_ring_add_whole(&o->scene->damage_ring);
1605 if(!o->gamma_pending) o->scene_retry_at=now_ms()+16;
1606 return;
1608 o->scene_retry_at=0;
1609 struct timespec now;
1610 clock_gettime(CLOCK_MONOTONIC,&now);
1611 output_frame_done(o,&now);
1612 atomic_fetch_add(&bridge.frames,1);
1614static void output_readback(struct wl_listener *listener,void *data) {
1615 struct output *o=wl_container_of(listener,o,readback);
1616 struct wlr_output_event_commit *e=data;
1617 if(e->state->committed & (WLR_OUTPUT_STATE_ENABLED|WLR_OUTPUT_STATE_MODE|
1618 WLR_OUTPUT_STATE_SCALE|WLR_OUTPUT_STATE_TRANSFORM)) inventory_schedule(o->server);
1619 if((e->state->committed&WLR_OUTPUT_STATE_ENABLED) && o->native->enabled) {
1620 o->gamma_pending=true;
1621 wlr_output_schedule_frame(o->native);
1623 if(e->state->committed&(WLR_OUTPUT_STATE_ENABLED|WLR_OUTPUT_STATE_MODE))
1624 EVENT(130,o->id,wlr_output_get_gamma_size(o->native),output_gamma_control(o)!=NULL);
1625 if (e->state->committed & WLR_OUTPUT_STATE_BUFFER) {
1626 if(trace_output_commit(&o->trace,o->native->commit_seq,o->id,e->when)) wake(bridge.event_fd);
1628 if(!o->capture[0] || !(e->state->committed&WLR_OUTPUT_STATE_BUFFER) || !e->state->buffer) return;
1629 void *data_ptr;
1630 uint32_t format;
1631 size_t stride;
1632 struct wlr_buffer *b=e->state->buffer;
1633 if(!wlr_buffer_begin_data_ptr_access(b,WLR_BUFFER_DATA_PTR_ACCESS_READ,&data_ptr,&format,&stride)) {
1634 if (o->sample_frames) {
1635 FILE *file = fopen(o->capture, "a");
1636 if (file) { fprintf(file, "FAIL buffer is not CPU-readable\n"); fclose(file); }
1637 o->sample_frames = 0;
1638 o->capture[0] = 0;
1639 wlr_output_lock_attach_render(o->native, false);
1640 EVENT(51, o->id, false, b->width, b->height);
1642 return;
1644 bool ok=false;
1645 if (o->sample_frames) {
1646 FILE *file = fopen(o->capture, "a");
1647 ok = file && (format == DRM_FORMAT_ARGB8888 || format == DRM_FORMAT_XRGB8888);
1648 if (file) {
1649 fprintf(file, "FRAME %u %u %d %d", ++o->sample_index,
1650 o->native->commit_seq, b->width, b->height);
1651 for (unsigned index = 0; index < o->sample_count; index++) {
1652 int x = o->sample_points[index * 2], y = o->sample_points[index * 2 + 1];
1653 uint32_t colour = 0;
1654 if (ok && x < b->width && y < b->height)
1655 colour = *(uint32_t *)((char *)data_ptr + y * stride + x * 4) & 0xffffff;
1656 else ok = false;
1657 fprintf(file, " %06x", colour);
1659 fprintf(file, " %s\n", ok ? "PASS" : "FAIL");
1660 if (fclose(file)) ok = false;
1662 o->sample_frames--;
1663 } else if(format==DRM_FORMAT_ARGB8888 || format==DRM_FORMAT_XRGB8888) {
1664 FILE *file=fopen(o->capture,"wb");
1665 if(file) {
1666 fprintf(file,"P6\n%d %d\n255\n",b->width,b->height);
1667 ok=true;
1668 for(int y=0;y<b->height;y++) {
1669 uint32_t *row=(uint32_t *)((char *)data_ptr+y*stride);
1670 for(int x=0;x<b->width;x++) {
1671 unsigned char rgb[3]={row[x]>>16,row[x]>>8,row[x]};
1672 if(fwrite(rgb,1,3,file)!=3) ok=false;
1675 if(fclose(file)) ok=false;
1678 wlr_buffer_end_data_ptr_access(b);
1679 if (!o->sample_frames) {
1680 o->capture[0]=0;
1681 wlr_output_lock_attach_render(o->native,false);
1683 EVENT(51,o->id,ok,b->width,b->height);
1685static bool pixel_scope_valid(struct server *s,const int64_t *scope) {
1686 if(!scope[0]) return true;
1687 struct output *o=find_output(s,scope[0]);
1688 if(!o || !o->configured_enabled) return false;
1689 struct wlr_box box;
1690 wlr_output_layout_get_box(s->layout,o->native,&box);
1691 return box.x==scope[1] && box.y==scope[2] && box.width==scope[3] && box.height==scope[4];
1693static void destroy_pixels(struct pixels *p) {
1694 wlr_scene_node_destroy(&p->scene->node);
1695 wl_list_remove(&p->link);
1696 free(p);
1697 atomic_fetch_sub(&bridge.pixel_nodes,1);
1699static void invalidate_scoped_pixels(struct server *s,uint64_t removed) {
1700 struct pixels *p,*next;
1701 wl_list_for_each_safe(p,next,&s->pixels,link)
1702 if(removed && p->scope[0]==(int64_t)removed)
1703 destroy_pixels(p);
1704 else if(p->scope[0] && !pixel_scope_valid(s,p->scope))
1705 wlr_scene_node_set_enabled(&p->scene->node,false);
1706 route_motion(s,0,false);
1708static void output_destroy(struct wl_listener *listener,void *data) {
1709 (void)data;
1710 struct output *o=wl_container_of(listener,o,destroy);
1711 if(!o->server->stopping) invalidate_scoped_pixels(o->server,o->id);
1712 EVENT(3,o->id);
1713 o->server->output_revision++;
1714 if(o->capture[0]) wlr_output_lock_attach_render(o->native,false);
1715 wl_list_remove(&o->frame.link); wl_list_remove(&o->destroy.link);
1716 wl_list_remove(&o->request.link); wl_list_remove(&o->readback.link);
1717 wl_list_remove(&o->lock_present.link);
1718 wl_list_remove(&o->wake_present.link);
1719 wl_list_remove(&o->gamma_present.link);
1720 if(o->lock_surface) o->lock_surface->output=NULL;
1721 if(o->lock_fill && !o->server->stopping) wlr_scene_node_destroy(&o->lock_fill->node);
1722 wl_list_remove(&o->link);
1723 inventory_schedule(o->server);
1724 publish_output_management(o->server);
1725 o->native->data=NULL;
1726 free(o->gamma_table);
1727 free(o);
1729static void output_request(struct wl_listener *listener,void *data) {
1730 struct output *o=wl_container_of(listener,o,request);
1731 struct wlr_output_event_request_state *e=data;
1732 EVENT(4,o->id,e->state->custom_mode.width,e->state->custom_mode.height);
1734static void new_output(struct wl_listener *listener,void *data) {
1735 struct server *s=wl_container_of(listener,s,new_output);
1736 struct wlr_output *native=data;
1737 if(s->pending_output_name[0]) wlr_output_set_name(native,s->pending_output_name);
1738 if(!wlr_output_init_render(native,s->allocator,s->renderer)) return;
1739 struct output *o=calloc(1,sizeof(*o));
1740 if(!o) return;
1741 o->server=s; o->native=native; o->id=++s->next_id;
1742 o->wake_requested=now_ms();
1743 o->gamma_pending=true;
1744 native->data=o;
1745 o->scene=wlr_scene_output_create(s->scene,native);
1746 if(!o->scene) { free(o); return; }
1747 wl_list_insert(&s->outputs,&o->link);
1748 listen(&native->events.frame,&o->frame,output_frame);
1749 listen(&native->events.destroy,&o->destroy,output_destroy);
1750 listen(&native->events.request_state,&o->request,output_request);
1751 listen(&native->events.commit,&o->readback,output_readback);
1752 listen(&native->events.present,&o->lock_present,lock_present);
1753 listen(&native->events.present,&o->wake_present,output_wake_present);
1754 listen(&native->events.present,&o->gamma_present,output_gamma_present);
1755 if(s->lock_state) lock_configure(o);
1756 struct wlr_output_mode *mode;
1757 int index=0,preferred=-1;
1758 wl_list_for_each(mode,&native->modes,link) {
1759 if(mode->preferred) preferred=index;
1760 EVENT(5,o->id,index++,mode->width,mode->height,mode->refresh,mode->preferred);
1762 EVENT(2,o->id,native->width,native->height,preferred,wlr_output_is_wl(native));
1763 object_text(o->id,8,native->name);
1764 EVENT(130,o->id,wlr_output_get_gamma_size(native),false);
1765 s->output_revision++;
1766 inventory_schedule(s);
1767 publish_output_management(s);
1769#include "output-batch.h"
1770#include "output-pending.h"
1771#include "output-management.h"
1772static void pixel_destroy(struct wlr_buffer *base) {
1773 struct pixel_buffer *b=wl_container_of(base,b,base);
1774 atomic_fetch_sub(&bridge.bytes,b->length+sizeof(*b));
1775 free(b);
1777static bool pixel_access(struct wlr_buffer *base,uint32_t flags,void **data,uint32_t *format,size_t *stride) {
1778 struct pixel_buffer *b=wl_container_of(base,b,base);
1779 if(flags&WLR_BUFFER_DATA_PTR_ACCESS_WRITE) return false;
1780 *data=b->data; *format=DRM_FORMAT_ARGB8888; *stride=b->stride; return true;
1782static void pixel_end(struct wlr_buffer *base) { (void)base; }
1783static const struct wlr_buffer_impl pixel_impl={.destroy=pixel_destroy,.begin_data_ptr_access=pixel_access,.end_data_ptr_access=pixel_end};
1784static bool pixels_accept_input(struct wlr_scene_buffer *buffer,double *sx,double *sy) {
1785 (void)sx; (void)sy;
1786 struct pixels *p=buffer->node.data;
1787 return p && p->input && pixel_scope_valid(p->server,p->scope);
1789static bool scene_order_valid(const int64_t *words,size_t count) {
1790 if(count<1 || words[0]<0 || words[0]>65535 || count!=(size_t)words[0]+1) return false;
1791 for(size_t i=1;i<count;i++) {
1792 if(words[i]==INT64_MIN) return false;
1793 for(size_t j=1;j<i;j++) if(words[i]==words[j]) return false;
1795 return true;
1797static struct wlr_scene_node *scene_resource(struct server *s,int64_t resource) {
1798 if(!resource) return &s->drag_scene->node;
1799 if(resource>0) {
1800 struct view *view=find_view(s,resource);
1801 return view ? &view->tree->node : NULL;
1803 struct pixels *pixels=find_pixels(s,-resource);
1804 return pixels ? &pixels->scene->node : NULL;
1806#include "scene-move.h"
1807/* Position only this resource. Copied retired neighbours are harmless; no
1808 * frame or input dispatch can observe creation before its final insertion. */
1809static void position_pixels(struct server *s,struct pixels *p,const int64_t *order,size_t count) {
1810 struct wlr_scene_node *lower=NULL,*upper=NULL;
1811 bool passed=false;
1812 for(size_t i=1;i<count;i++) {
1813 if(order[i]==-(int64_t)p->id) { passed=true; continue; }
1814 struct wlr_scene_node *node=scene_resource(s,order[i]);
1815 if(!node || node->parent!=p->scene->node.parent) continue;
1816 if(passed) { upper=node; break; }
1817 lower=node;
1819 if(upper) wlr_scene_node_place_below(&p->scene->node,upper);
1820 else if(lower) wlr_scene_node_place_above(&p->scene->node,lower);
1821 else wlr_scene_node_lower_to_bottom(&p->scene->node);
1823static bool apply_pixels(struct server *s,uint64_t id,int64_t *w,struct pixel_buffer *b) {
1824 struct pixels *p=NULL,*it;
1825 wl_list_for_each(it,&s->pixels,link) if(it->id==id) { p=it; break; }
1826 if(!b) {
1827 if(p) destroy_pixels(p);
1828 route_motion(s,0,false);
1829 return true;
1831 if(!pixel_scope_valid(s,b->scope)) {
1832 wlr_buffer_drop(&b->base);
1833 atomic_fetch_add(&bridge.pixel_drops,1);
1834 return true;
1836 if(!p) {
1837 p=calloc(1,sizeof(*p));
1838 if(!p) { wlr_buffer_drop(&b->base); return false; }
1839 p->id=id; p->scene=wlr_scene_buffer_create(s->normal,&b->base);
1840 if(!p->scene) { free(p); wlr_buffer_drop(&b->base); return false; }
1841 p->scene->node.data=p;
1842 p->scene->point_accepts_input=pixels_accept_input;
1843 wl_list_insert(&s->pixels,&p->link);
1844 atomic_fetch_add(&bridge.pixel_nodes,1);
1845 } else wlr_scene_buffer_set_buffer(p->scene,&b->base);
1846 p->input=b->input;
1847 p->server=s;
1848 memcpy(p->scope,b->scope,sizeof(p->scope));
1849 wlr_scene_node_set_enabled(&p->scene->node,true);
1850 wlr_scene_buffer_set_dest_size(p->scene,w[2],w[3]);
1851 scene_move_position(s,-(int64_t)id,&p->scene->node,w[0],w[1]);
1852 if(b->order_count) {
1853 size_t offset=(b->stride*(size_t)b->base.height+7)&~(size_t)7;
1854 position_pixels(s,p,(const int64_t *)(b->data+offset),b->order_count);
1855 } else {
1856 if(w[7]>0) wlr_scene_node_raise_to_top(&p->scene->node);
1857 if(w[7]<0) wlr_scene_node_lower_to_bottom(&p->scene->node);
1859 for(unsigned i=0;i<b->trace_count;i++) {
1860 trace_damage(s,b->trace_causes[i],p->scope[0]);
1861 latency_trace(12,b->trace_causes[i],id,0);
1863 wlr_buffer_drop(&b->base);
1864 route_motion(s,0,false);
1865 return true;
1868#include "headless.h"
1870static bool configure_device(struct server *s,const int64_t *w,size_t n) {
1871 if(n<5 || w[1]<0 || w[1]>200 || w[2]<0 || w[2]>5000 || w[3]<1 || w[3]>128 || n!=4+(size_t)w[3]) return false;
1872 struct keyboard *k=find_keyboard(s,w[0]);
1873 if(!k) return false;
1874 char layout[129]={0};
1875 for(int i=0;i<w[3];i++) {
1876 if(w[4+i]<32 || w[4+i]>126) return false;
1877 layout[i]=w[4+i];
1879 struct xkb_context *context=xkb_context_new(XKB_CONTEXT_NO_FLAGS);
1880 if(!context) return false;
1881 struct xkb_rule_names names={.layout=layout};
1882 struct xkb_keymap *map=xkb_keymap_new_from_names(context,&names,XKB_KEYMAP_COMPILE_NO_FLAGS);
1883 xkb_context_unref(context);
1884 if(!map) return false;
1885 bool ok=wlr_keyboard_set_keymap(k->native,map);
1886 if(ok && k==&s->synthetic_owner) {
1887 if(s->emulation_state) xkb_state_unref(s->emulation_state);
1888 s->emulation_state=xkb_state_new(map);
1889 if(!s->emulation_state) ok=false;
1891 xkb_keymap_unref(map);
1892 if(ok) wlr_keyboard_set_repeat_info(k->native,w[1],w[2]);
1893 return ok;
1895/* Ordering is explicit. Retired resources are harmless omissions, since a
1896 * copied order can cross an independently delivered destruction fact. */
1897static bool restack_scene(struct server *s,const int64_t *words,size_t count) {
1898 if(!scene_order_valid(words,count)) return false;
1899 for(size_t i=1;i<count;i++) {
1900 struct wlr_scene_node *node=NULL;
1901 if(words[i]==0) node=&s->drag_scene->node;
1902 else if(words[i]>0) {
1903 struct view *view=find_view(s,words[i]);
1904 if(view) node=&view->tree->node;
1905 } else {
1906 struct pixels *pixels=find_pixels(s,-words[i]);
1907 if(pixels) node=&pixels->scene->node;
1909 if(node) wlr_scene_node_raise_to_top(node);
1911 route_motion(s,now_ms(),false);
1912 return true;
1914static bool apply_command(struct server *s,struct wm_message m) {
1915 int64_t *w=m.word;
1916 switch(w[0]) {
1917 case 1: s->stopping=true; wl_display_terminate(s->display); return true;
1918 case 2: {
1919 struct view *v=find_view(s,w[1]);
1920 if(!v || !view_ready(v) || w[2]<0 || w[2]>16384 || w[3]<0 || w[3]>16384) return false;
1921 v->width=w[2]; v->height=w[3];
1922 if(v->x11) {
1923 if(!w[2] || !w[3]) return false;
1924 wlr_xwayland_surface_configure(v->x11,v->x11->x,v->x11->y,w[2],w[3]);
1925 } else if(v->layer) {
1926 if(!w[2] || !w[3]) return false;
1927 v->serial=wlr_layer_surface_v1_configure(v->layer,w[2],w[3]);
1928 } else wlr_xdg_toplevel_set_size(v->native,w[2],w[3]);
1929 return true;
1931 case 3:
1932 s->route_hit_test=w[1]!=0;
1933 if(s->route_hit_test) route_motion(s,now_ms(),false);
1934 return true;
1935 case 4:
1936 if(w[2]<1 || w[3]<0 || w[4]<0 || w[4]>1000 || w[7]<0 || w[8]<0) return false;
1937 if(s->has_pending_motion && s->pending_motion.completion)
1938 EVENT(35,s->pending_motion.completion,0,s->pending_motion.origin);
1939 s->has_pending_motion=false;
1940 if(s->input_read==s->input_write) {
1941 s->motion_x=s->cursor->x; s->motion_y=s->cursor->y;
1943 s->motion_hook=w[1]!=0; s->motion_generation=w[2]; s->motion_device=w[3];
1944 s->motion_period=w[4]; s->motion_region=(struct wlr_box){w[5],w[6],w[7],w[8]};
1945 EVENT(36,w[2],w[1]); return true;
1946 case 5: {
1947 struct view *v=find_view(s,w[1]);
1948 if(w[1]<0 || w[2]<0 || w[3]<0 || w[4]<0 || w[5]<0 || (w[2] && w[3])) return false;
1949 uint64_t generation=s->generation, authorization=w[2] ? w[2] : w[3];
1950 uint64_t operation=w[5] ? (uint64_t)w[5] : authorization;
1951 int64_t target=w[4] ? w[4] : w[1];
1952 bool valid=(!w[1] || visible(v));
1953 if(w[2]) {
1954 valid=valid && !s->lock_state && s->input_read!=s->input_write;
1955 if(valid) {
1956 struct input *in=&s->inputs[s->input_read%QUEUE_SIZE];
1957 valid=in->token==(uint64_t)w[2] && in->notified && !in->ready && in->kind==31 &&
1958 in->state && in->generation==generation && in->target==target &&
1959 target_at(s,in->x,in->y)==target;
1961 } else if(w[3]) {
1962 valid=valid && !s->lock_state && s->observe_pointer && s->pointer_sampled &&
1963 s->pointer_sample_token==(uint64_t)w[3] && s->pointer_sample_generation==generation &&
1964 s->pointer_target==target && target_at(s,s->cursor->x,s->cursor->y)==target;
1966 if(!valid) {
1967 if(operation) { EVENT(113,operation,w[1],0,authorization); return true; }
1968 return false;
1970 set_focus(s,w[1]);
1971 bool accepted=s->focus==(uint64_t)w[1];
1972 if(authorization && accepted) {
1973 for(unsigned index=s->input_read;index!=s->input_write;index++) {
1974 struct input *in=&s->inputs[index%QUEUE_SIZE];
1975 if(in->generation==generation) in->generation=s->generation;
1977 if(s->has_pending_motion && s->pending_motion.generation==generation)
1978 s->pending_motion.generation=s->generation;
1980 if(operation) { EVENT(113,operation,w[1],accepted,authorization); return true; }
1981 return accepted;
1983 case 6: {
1984 if(s->lock_state || w[1]!=1 || w[2]<0 || w[2]>=MAX_KEYS || (w[3]!=0 && w[3]!=1) || !s->synthetic.keymap) return false;
1985 if(!s->emulation_state) return false;
1986 uint32_t symbol=xkb_state_key_get_one_sym(s->emulation_state,w[2]+8),modifiers=0;
1987 const char *names[8]={XKB_MOD_NAME_SHIFT,XKB_MOD_NAME_CAPS,XKB_MOD_NAME_CTRL,
1988 XKB_MOD_NAME_ALT,"Mod2","Mod3",XKB_MOD_NAME_LOGO,"Mod5"};
1989 for(int bit=0;bit<8;bit++)
1990 if(xkb_state_mod_name_is_active(s->emulation_state,names[bit],XKB_STATE_MODS_EFFECTIVE)>0) modifiers|=1u<<bit;
1991 xkb_state_update_key(s->emulation_state,w[2]+8,w[3] ? XKB_KEY_DOWN : XKB_KEY_UP);
1992 queue_input(s,(struct input){.kind=30,.device=s->synthetic_owner.id,.time=now_ms(),.code=w[2],.state=w[3],.origin=1,.completion=w[4],
1993 .keysym=symbol,.modifiers=modifiers,
1994 .base_keysym=base_keysym(&s->synthetic,w[2],false),
1995 .first_keysym=base_keysym(&s->synthetic,w[2],true)});
1996 uint32_t current=0;
1997 for(int bit=0;bit<8;bit++)
1998 if(xkb_state_mod_name_is_active(s->emulation_state,names[bit],XKB_STATE_MODS_EFFECTIVE)>0) current|=1u<<bit;
1999 s->keyboard_modifiers=current;
2000 EVENT(43,s->synthetic_owner.id,current,xkb_state_serialize_layout(s->emulation_state,XKB_STATE_LAYOUT_EFFECTIVE));
2001 return true;
2003 case 7:
2004 if(s->lock_state || w[1]!=1 || w[2]<0 || w[2]>=MAX_KEYS || (w[3]!=0 && w[3]!=1)) return false;
2005 queue_input(s,(struct input){.kind=31,.device=s->synthetic_owner.id,.time=now_ms(),.code=w[2],.state=w[3],.origin=1,.completion=w[4],.x=pointer_x(s),.y=pointer_y(s),.modifiers=s->keyboard_modifiers});
2006 return true;
2007 case 8:
2008 if(s->lock_state || w[1]!=1) return false;
2009 motion_input(s,now_ms(),w[2]/1000.0,w[3]/1000.0,1,1,w[4]); return true;
2010 case 9:
2011 if(s->lock_state || w[1]!=1 || w[2]<0 || w[2]>1 || w[4]<-32767 || w[4]>32767) return false;
2012 axis_input(s,1,1,now_ms(),w[2],w[3]/1000.0,w[4]*WLR_POINTER_AXIS_DISCRETE_STEP,
2013 WL_POINTER_AXIS_SOURCE_WHEEL,WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL,w[5]);
2014 return true;
2015 case 11:
2016 if(w[2]<0 || w[2]>2 || w[3]<0 || w[3]>=MAX_KEYS || w[6]<0 || w[6]>255) return false;
2017 for(unsigned i=s->input_read;i!=s->input_write;i++) {
2018 struct input *in=&s->inputs[i%QUEUE_SIZE];
2019 if(in->token!=(uint64_t)w[1]) continue;
2020 if(in->completed) return true;
2021 if(in->ready || !in->notified) return false;
2022 in->ready=true; in->result=w[2]; in->replacement=w[3];
2023 in->replacement_modifiers=w[6];
2024 if(in->kind==32 && w[2]==2) { in->x=w[4]/1000.0; in->y=w[5]/1000.0; }
2025 deliver_input(s); return true;
2027 /* The native decision deadline may already have retired this token. */
2028 return true;
2029 case 13: {
2030 struct view *v=find_view(s,w[1]);
2031 if(!v) return false;
2032 close_view(v); return true;
2034 case 14:
2035 if(w[1]<0 || w[1]>7) return false;
2036 wlr_seat_set_capabilities(s->seat,w[1]); return true;
2037 case 40: {
2038 if(w[1]<1 || w[2]<1) return false;
2039 struct view *view=find_view(s,w[1]);
2040 if(!view || !view_ready(view)) {
2041 EVENT(120,w[2],w[1],0);
2042 return true;
2044 struct wlr_xdg_toplevel_state *state=view->native ? &view->native->current : NULL;
2045 uint32_t version=view->native ? wl_resource_get_version(view->native->resource) : 0;
2046 EVENT(120,w[2],w[1],1,view->tree->node.x,view->tree->node.y,
2047 view->committed.width,view->committed.height,view->mapped,visible(view),s->focus==view->id,
2048 state ? state->activated : 0,state ? state->suspended : 0,
2049 state ? state->fullscreen : 0,state ? state->tiled : 0,state!=NULL);
2050 struct wlr_scene_node *surface_tree=view_surface_tree(view);
2051 EVENT(121,w[2],w[1],view->committed.x,view->committed.y,
2052 surface_tree ? surface_tree->x : 0,surface_tree ? surface_tree->y : 0,
2053 version,view_serial(view),
2054 view->native ? view->native->scheduled.suspended : 0,
2055 view->native ? view->native->base->pending.configure_serial : 0,
2056 view->native ? view->native->base->scheduled_serial : 0);
2057 return true;
2059 case 39: {
2060 struct view *view=find_view(s,w[1]);
2061 if(!view || !view->native) return false;
2062 if(view->native->base->initialized) wlr_xdg_surface_schedule_configure(view->native->base);
2063 return true;
2065 case 35:
2066 if(w[1]<0 || w[2]<0) return false;
2067 return set_active_constraint(s,w[1],w[2]);
2068 case 36: return pointer_hint_reply(s,w[1],w[2]!=0);
2069 case 37: {
2070 struct wlr_output *native=wlr_output_layout_output_at(s->layout,s->cursor->x,s->cursor->y);
2071 struct output *output=native ? native->data : NULL;
2072 EVENT(112,w[1],(int64_t)(s->cursor->x*1000),(int64_t)(s->cursor->y*1000),
2073 target_at(s,s->cursor->x,s->cursor->y),output ? output->id : 0,s->generation);
2074 return true;
2076 case 38:
2077 if(w[1]!=0 && w[1]!=1) return false;
2078 s->relative_route=w[1]!=0; return true;
2079 case 34: {
2080 struct output *output=find_output(s,w[1]);
2081 if(!output || (w[2]!=0 && w[2]!=1)) return false;
2082 output->nearest_filter=w[2]!=0;
2083 wlr_damage_ring_add_whole(&output->scene->damage_ring);
2084 wlr_output_schedule_frame(output->native);
2085 EVENT(46,output->id,w[2]);
2086 return true;
2088 case 32: return output_control_reply(s,w[1],w[2]!=0);
2089 case 33:
2090 if(w[2]!=0 && w[2]!=1) return false;
2091 return output_set_power(s,w[1],w[2]!=0);
2092 case 31:
2093 if(w[2]<0 || w[2]>UINT32_MAX || (w[2]&255)!=255) return false;
2094 if(!s->lock_state || w[1]!=(int64_t)s->lock_generation) return true;
2095 s->lock_colour=w[2];
2097 float colour[4]={(s->lock_colour>>24)/255.0f,
2098 ((s->lock_colour>>16)&255)/255.0f,((s->lock_colour>>8)&255)/255.0f,1};
2099 struct output *output;
2100 wl_list_for_each(output,&s->outputs,link) {
2101 if(output->lock_fill) wlr_scene_rect_set_color(output->lock_fill,colour);
2102 lock_damage(output);
2105 return true;
2106 case 15: return lock_focus(s,w[1],w[2]);
2107 case 16: return permission_reply(s,w[1],w[2]!=0);
2108 case 18: return set_decoration_mode(s,w[1],w[2]);
2109 case 19:
2110 if(!s->idle || w[2]<0 || w[2]>15 || w[3]<0 || w[3]>7) return false;
2111 s->activity_classes=w[2]; s->activity_origins=w[3];
2112 wlr_idle_notifier_v1_set_inhibited(s->idle,w[1]!=0);
2113 EVENT(45,w[1]!=0,w[2],w[3]); return true;
2114 case 20: return configure_popup(s,w);
2115 case 21: {
2116 struct pixels *p=find_pixels(s,w[1]);
2117 if(!p || w[2]<-32768 || w[2]>32768 || w[3]<-32768 || w[3]>32768 ||
2118 w[4]<1 || w[4]>16384 || w[5]<1 || w[5]>16384 || w[6]<-1 || w[6]>1) return false;
2119 wlr_scene_node_set_position(&p->scene->node,w[2],w[3]);
2120 wlr_scene_buffer_set_dest_size(p->scene,w[4],w[5]);
2121 if(w[6]>0) wlr_scene_node_raise_to_top(&p->scene->node);
2122 if(w[6]<0) wlr_scene_node_lower_to_bottom(&p->scene->node);
2123 return true;
2125 case 29: return data_reply(s,w[1],w[2]!=0,w[3]!=0);
2126 case 30: s->allow_client_cursor=w[1]!=0; return true;
2127 case 28: {
2128 struct output *output=find_output(s,w[1]);
2129 if(!output || !wlr_output_is_headless(output->native)) return false;
2130 wlr_output_destroy(output->native); return true;
2132 case 27:
2133 if((w[1]!=0 && w[1]!=1) || (w[2]!=0 && w[2]!=1)) return false;
2134 s->observe_pointer=w[1]!=0; s->pointer_sampled=false; s->pointer_motion_only=w[2]!=0;
2135 if(!s->pointer_motion_only) route_motion(s,now_ms(),false);
2136 return true;
2137 case 26: {
2138 struct view *v=find_view(s,w[1]);
2139 if(!v || !v->x11 || w[2]<-32768 || w[2]>32767 || w[3]<-32768 || w[3]>32767 ||
2140 w[4]<1 || w[4]>16384 || w[5]<1 || w[5]>16384) return false;
2141 wlr_xwayland_surface_configure(v->x11,w[2],w[3],w[4],w[5]); return true;
2143 case 24: return configure_layer(s,w);
2144 case 25: {
2145 if(w[1]<0 || w[2]<0) return false;
2146 bool accepted=!w[1] || find_output(s,w[1]);
2147 if(accepted) s->default_layer_output=w[1];
2148 if(w[2]) { EVENT(122,w[2],w[1],accepted); return true; }
2149 return accepted;
2151 case 22:
2152 if(w[3]!=0 && w[3]!=1) return false;
2153 return set_keyboard_group(s,w[1],w[2],w[3]!=0);
2154 case 23:
2155 if(s->lock_state || w[1]<-32768000 || w[1]>32768000 || w[2]<-32768000 || w[2]>32768000) return false;
2156 constrained_warp(s,w[1]/1000.0,w[2]/1000.0);
2157 s->motion_x=s->cursor->x; s->motion_y=s->cursor->y;
2158 route_motion(s,now_ms(),false);
2159 return true;
2160 case 90: {
2161 int64_t *data=(void *)(intptr_t)w[3];
2162 bool ok=false;
2163 switch(w[1]) {
2164 case 1: return submit_plan(s,w[2],data,w[4],w[5]);
2165 case 2:
2166 ok=queue_output_batch(s,2,w[2],data,w[4]);
2167 free(data);
2168 if(!ok) EVENT(24,w[2],2,0);
2169 return true;
2170 case 3: ok=configure_device(s,data,w[4]); break;
2171 case 4: ok=configure_cursor(s,data,w[4]); break;
2172 case 6: ok=configure_keyboard(s,data,w[4]); break;
2173 case 7: ok=add_headless_output(s,data,w[4]); break;
2174 case 15: ok=record_output_samples(s,w[2],data,w[4]); break;
2175 case 16:
2176 ok=output_set_gamma(s,w[2],data,w[4]);
2177 if(!ok && w[4]>=1) EVENT(131,data[0],w[2],false);
2178 break;
2179 case 17: ok=scene_move_start(s,w[2],data,w[4]); break;
2180 case 8: ok=restack_scene(s,data,w[4]); break;
2181 case 9: ok=configure_pointer(s,w[2],data,w[4]); break;
2182 case 10: output_batch(s,w[2],data,w[4]); free(data); return true;
2183 case 12: ok=configure_session_switches(s,data,w[4]); break;
2184 case 13: ok=configure_input_intercepts(s,true,data,w[4]); break;
2185 case 14: ok=configure_input_intercepts(s,false,data,w[4]); break;
2186 case 11: output_configuration_reply(s,w[2],data,w[4]); free(data); return true;
2187 case 5: {
2188 struct output *o=find_output(s,w[2]);
2189 if(o && !o->capture[0] && w[4]>0 && w[4]<PATH_MAX) {
2190 ok=true;
2191 for(int i=0;i<w[4];i++) {
2192 if(data[i]<1 || data[i]>127) { ok=false; break; }
2193 o->capture[i]=data[i];
2195 o->capture[w[4]]=0;
2196 if(ok) wlr_output_lock_attach_render(o->native,true);
2197 else o->capture[0]=0;
2198 wlr_damage_ring_add_whole(&o->scene->damage_ring);
2199 wlr_output_schedule_frame(o->native);
2201 break;
2204 free(data); EVENT(24,w[2],w[1],ok); return ok || w[1]==6;
2206 case 41:
2207 if (w[1] < 1 || w[1] > 200) return false;
2208 s->scene_update_deadline = now_ms() + w[1];
2209 return true;
2210 case 43:
2211 if(s->scene_move.token==(uint64_t)w[1]) scene_move_finish(s);
2212 return true;
2213 case 42: {
2214 struct output *o = find_output(s, w[1]);
2215 if (!o) return false;
2216 if (o->sample_frames) {
2217 o->sample_frames = 0;
2218 o->capture[0] = 0;
2219 wlr_output_lock_attach_render(o->native, false);
2221 return true;
2223 case 91: {
2224 struct pixel_buffer *b=(void *)(intptr_t)w[12];
2225 return apply_pixels(s,w[1],w+2,b);
2227 default: return false;
2230static int commands_ready(int fd,uint32_t mask,void *data) {
2231 (void)mask;
2232 struct server *s=data;
2233 drain(fd);
2234 struct wm_message command;
2235 unsigned count=0;
2236 while(count++<64 && pop(&bridge.commands,&command)) {
2237 s->trace_correlation=command.word[15];
2238 if(!apply_command(s,command)) {
2239 atomic_fetch_add(&bridge.rejected,1);
2240 EVENT(98,command.word[0],command.word[1]);
2242 s->trace_correlation=0;
2244 if(atomic_load(&bridge.commands.read)!=atomic_load(&bridge.commands.write)) wake(fd);
2245 return 0;
2247static int timer_tick(void *data) {
2248 struct server *s=data;
2249 s->timer_deadline=0;
2250 atomic_fetch_add(&bridge.timer_wakes,1);
2251 check_plan(s);
2252 if (s->scene_update_deadline && now_ms() >= s->scene_update_deadline) {
2253 s->scene_update_deadline = 0;
2254 struct output *output;
2255 wl_list_for_each(output, &s->outputs, link) {
2256 wlr_damage_ring_add_whole(&output->scene->damage_ring);
2257 wlr_output_schedule_frame(output->native);
2260 if(s->lock_state) {
2261 lock_ack(s);
2262 if(s->lock_deadline && now_ms()>=s->lock_deadline) s->lock_deadline=0;
2264 permissions_expire(s);
2265 data_expire(s);
2266 output_controls_expire(s);
2267 output_gamma_expire(s);
2268 struct output *output;
2269 wl_list_for_each(output,&s->outputs,link) {
2270 if(!output->scene_retry_at || now_ms()<output->scene_retry_at) continue;
2271 output->scene_retry_at=0;
2272 if(output->native->enabled) wlr_output_schedule_frame(output->native);
2274 output_requests_expire(s);
2275 pointer_hints_expire(s);
2276 struct popup *p,*next;
2277 wl_list_for_each_safe(p,next,&s->popups,link)
2278 if(p->deadline && now_ms()>=p->deadline) wlr_xdg_popup_destroy(p->native);
2279 if(s->has_pending_motion && now_ms()-(uint64_t)s->motion_last >= (uint64_t)s->motion_period) {
2280 s->has_pending_motion=false; s->motion_last=now_ms();
2281 queue_input(s,s->pending_motion);
2283 deliver_input(s);
2284 return 0;
2286#include "deadlines.h"
2287static const struct wlr_keyboard_impl synthetic_impl={0};
2288static int run_host(void) {
2289 struct server s={0};
2290 wl_list_init(&s.outputs); wl_list_init(&s.views);
2291 wl_list_init(&s.keyboards); wl_list_init(&s.devices); wl_list_init(&s.pixels);
2292 wl_list_init(&s.permissions);
2293 wl_list_init(&s.data_requests);
2294 wl_list_init(&s.output_controls);
2295 wl_list_init(&s.pending_outputs);
2296 wl_list_init(&s.output_requests);
2297 wl_list_init(&s.constraints); wl_list_init(&s.pointer_hints);
2298 wl_list_init(&s.decorations);
2299 wl_list_init(&s.legacy_decorations);
2300 wl_list_init(&s.inhibitors);
2301 wl_list_init(&s.popups);
2302 s.next_id=1; s.generation=1; s.lock_colour=255; s.relative_route=true;
2303 s.display=wl_display_create();
2304 if(!s.display) return 1;
2305 int result=1;
2306 s.security_context=wlr_security_context_manager_v1_create(s.display);
2307 if(!s.security_context) goto cleanup;
2308 wl_display_set_global_filter(s.display,client_global_filter,&s);
2309 struct wl_event_loop *loop=wl_display_get_event_loop(s.display);
2310 s.backend=wlr_backend_autocreate(loop,&s.session);
2311 if(!s.backend) goto cleanup;
2312 s.renderer=wlr_renderer_autocreate(s.backend);
2313 if(!s.renderer || !wlr_renderer_init_wl_display(s.renderer,s.display)) goto cleanup;
2314 s.allocator=wlr_allocator_autocreate(s.backend,s.renderer);
2315 if(!s.allocator) goto cleanup;
2316 s.compositor=wlr_compositor_create(s.display,6,s.renderer);
2317 if(!s.compositor || !wlr_subcompositor_create(s.display) ||
2318 !wlr_viewporter_create(s.display) || !wlr_fractional_scale_manager_v1_create(s.display,1)) goto cleanup;
2319 wlr_data_device_manager_create(s.display);
2320 if(!wlr_presentation_create(s.display,s.backend,1)) goto cleanup;
2321 s.layout=wlr_output_layout_create(s.display);
2322 s.scene=wlr_scene_create();
2323 if(!s.layout || !s.scene) goto cleanup;
2324 s.scene_layout=wlr_scene_attach_output_layout(s.scene,s.layout);
2325 s.normal=wlr_scene_tree_create(&s.scene->tree);
2326 s.drag_scene=wlr_scene_tree_create(s.normal);
2327 s.lock_scene=wlr_scene_tree_create(&s.scene->tree);
2328 if(!s.scene_layout || !s.normal || !s.drag_scene || !s.lock_scene) goto cleanup;
2329 wlr_scene_node_set_enabled(&s.lock_scene->node,false);
2330 s.seat=wlr_seat_create(s.display,"seat0");
2331 s.cursor=wlr_cursor_create();
2332 if(!s.seat || !s.cursor) goto cleanup;
2333 wlr_cursor_attach_output_layout(s.cursor,s.layout);
2334 s.relative=wlr_relative_pointer_manager_v1_create(s.display);
2335 wlr_keyboard_init(&s.synthetic,&synthetic_impl,"sigil-wm-emulation");
2336 s.synthetic_owner=(struct keyboard){.server=&s,.id=1,.native=&s.synthetic};
2337 for(int i=0;i<MAX_KEYS;i++) s.synthetic_owner.forwarded[i]=-1;
2338 wlr_seat_set_keyboard(s.seat,&s.synthetic);
2339 s.shell=wlr_xdg_shell_create(s.display,6);
2340 if(!s.shell || !s.relative) goto cleanup;
2341 if(bridge.protocols&1024) {
2342 s.foreign_list=wlr_ext_foreign_toplevel_list_v1_create(s.display,1);
2343 if(!s.foreign_list) goto cleanup;
2345 if(bridge.protocols&2048) {
2346 s.foreign_manager=wlr_foreign_toplevel_manager_v1_create(s.display);
2347 if(!s.foreign_manager) goto cleanup;
2349 if(bridge.protocols&1) {
2350 struct wlr_session_lock_manager_v1 *manager=wlr_session_lock_manager_v1_create(s.display);
2351 if(!manager) goto cleanup;
2352 listen(&manager->events.new_lock,&s.new_lock,lock_new);
2354 if(bridge.protocols&2) {
2355 struct wlr_virtual_keyboard_manager_v1 *keys=wlr_virtual_keyboard_manager_v1_create(s.display);
2356 struct wlr_virtual_pointer_manager_v1 *pointers=wlr_virtual_pointer_manager_v1_create(s.display);
2357 if(!keys || !pointers) goto cleanup;
2358 listen(&keys->events.new_virtual_keyboard,&s.new_virtual_keyboard,virtual_keyboard);
2359 listen(&pointers->events.new_virtual_pointer,&s.new_virtual_pointer,virtual_pointer);
2361 if(bridge.protocols&8) {
2362 struct wlr_xdg_decoration_manager_v1 *decor=wlr_xdg_decoration_manager_v1_create(s.display);
2363 struct wlr_server_decoration_manager *legacy=wlr_server_decoration_manager_create(s.display);
2364 if(!decor || !legacy) goto cleanup;
2365 wlr_server_decoration_manager_set_default_mode(legacy,bridge.legacy_decoration_default);
2366 listen(&legacy->events.new_decoration,&s.new_legacy_decoration,new_legacy_decoration);
2367 listen(&decor->events.new_toplevel_decoration,&s.new_decoration,new_decoration);
2369 if(bridge.protocols&16) {
2370 s.idle=wlr_idle_notifier_v1_create(s.display);
2371 struct wlr_idle_inhibit_manager_v1 *inhibit=wlr_idle_inhibit_v1_create(s.display);
2372 if(!s.idle || !inhibit) goto cleanup;
2373 listen(&inhibit->events.new_inhibitor,&s.new_inhibitor,new_inhibitor);
2375 if(bridge.protocols&4) {
2376 s.xwayland=wlr_xwayland_create(s.display,s.compositor,true);
2377 if(!s.xwayland) goto cleanup;
2378 wlr_xwayland_set_seat(s.xwayland,s.seat);
2379 listen(&s.xwayland->events.new_surface,&s.new_x11,new_x11);
2380 listen(&s.xwayland->events.destroy,&s.x11_destroy,x11_manager_destroy);
2381 listen(&s.xwayland->events.ready,&s.x11_ready,x11_manager_ready);
2382 object_text(0,9,s.xwayland->display_name);
2384 if((bridge.protocols&64) && !desktop_init(&s)) goto cleanup;
2385 if((bridge.protocols&128) && (!output_controls_init(&s) || !output_management_init(&s))) goto cleanup;
2386 if(bridge.protocols&256) {
2387 s.activation=wlr_xdg_activation_v1_create(s.display);
2388 if(!s.activation) goto cleanup;
2389 listen(&s.activation->events.request_activate,&s.activation_request,activation_requested);
2391 if((bridge.protocols&512) && !constraints_init(&s)) goto cleanup;
2392 if(bridge.protocols&32) {
2393 struct wlr_layer_shell_v1 *layers=wlr_layer_shell_v1_create(s.display,4);
2394 if(!layers) goto cleanup;
2395 listen(&layers->events.new_surface,&s.new_layer,new_layer);
2397 listen(&s.backend->events.new_output,&s.new_output,new_output);
2398 listen(&s.backend->events.new_input,&s.new_input,new_input);
2399 listen(&s.shell->events.new_toplevel,&s.new_view,new_view);
2400 listen(&s.shell->events.new_popup,&s.new_popup,new_popup);
2401 listen(&s.cursor->events.motion,&s.motion,cursor_motion);
2402 listen(&s.cursor->events.motion_absolute,&s.absolute,cursor_absolute);
2403 listen(&s.cursor->events.button,&s.button,cursor_button);
2404 listen(&s.cursor->events.axis,&s.axis,cursor_axis);
2405 listen(&s.cursor->events.frame,&s.cursor_frame,cursor_frame);
2406 listen(&s.seat->events.request_set_cursor,&s.cursor_request,cursor_request);
2407 s.commands=wl_event_loop_add_fd(loop,bridge.command_fd,WL_EVENT_READABLE,commands_ready,&s);
2408 s.timer=wl_event_loop_add_timer(loop,timer_tick,&s);
2409 if(!s.commands || !s.timer) goto cleanup;
2410 const char *socket=bridge.requested_socket[0] ? bridge.requested_socket : wl_display_add_socket_auto(s.display);
2411 if(bridge.requested_socket[0] && wl_display_add_socket(s.display,socket)!=0) goto cleanup;
2412 if(!socket) goto cleanup;
2413 snprintf(bridge.socket,sizeof(bridge.socket),"%s",socket);
2414 atomic_store(&bridge.state,2);
2415 if(!wlr_backend_start(s.backend)) goto cleanup;
2416 inventory_schedule(&s);
2417 EVENT(1,1,s.session!=NULL);
2418 while(!s.stopping)
2419 if(dispatch_native_once(&s,-1)<0 && errno!=EINTR) goto cleanup;
2420 result=0;
2421cleanup:
2422 atomic_store(&bridge.state,4);
2423 s.stopping=true;
2424 if(s.plan) free(s.plan);
2425 s.plan=NULL;
2426 if(s.commands) wl_event_source_remove(s.commands);
2427 if(s.timer) wl_event_source_remove(s.timer);
2428 if(s.inventory_idle) wl_event_source_remove(s.inventory_idle);
2429 if(s.motion.notify) {
2430 wl_list_remove(&s.motion.link); wl_list_remove(&s.absolute.link);
2431 wl_list_remove(&s.button.link); wl_list_remove(&s.axis.link);
2432 wl_list_remove(&s.cursor_frame.link); wl_list_remove(&s.cursor_request.link);
2433 wl_list_remove(&s.new_input.link); wl_list_remove(&s.new_output.link);
2434 wl_list_remove(&s.new_view.link); wl_list_remove(&s.new_popup.link);
2436 if(s.activation_request.notify) wl_list_remove(&s.activation_request.link);
2437 constraints_finish(&s);
2438 output_pending_finish(&s);
2439 output_management_finish(&s);
2440 output_gamma_finish(&s);
2441 output_controls_finish(&s);
2442 desktop_finish(&s);
2443 if(s.new_layer.notify) wl_list_remove(&s.new_layer.link);
2444 if(s.new_lock.notify) wl_list_remove(&s.new_lock.link);
2445 if(s.new_virtual_keyboard.notify) {
2446 wl_list_remove(&s.new_virtual_keyboard.link); wl_list_remove(&s.new_virtual_pointer.link);
2448 if(s.new_decoration.notify) wl_list_remove(&s.new_decoration.link);
2449 if(s.new_legacy_decoration.notify) wl_list_remove(&s.new_legacy_decoration.link);
2450 if(s.new_inhibitor.notify) wl_list_remove(&s.new_inhibitor.link);
2451 if(s.xwayland) wlr_xwayland_destroy(s.xwayland);
2452 wl_display_destroy_clients(s.display);
2453 struct pixels *p,*next;
2454 wl_list_for_each_safe(p,next,&s.pixels,link) {
2455 wl_list_remove(&p->link); free(p);
2456 atomic_fetch_sub(&bridge.pixel_nodes,1);
2458 if(s.scene) wlr_scene_node_destroy(&s.scene->tree.node);
2459 if(s.cursor) wlr_cursor_destroy(s.cursor);
2460 if(s.cursor_manager) wlr_xcursor_manager_destroy(s.cursor_manager);
2461 if(s.allocator) wlr_allocator_destroy(s.allocator);
2462 if(s.renderer) wlr_renderer_destroy(s.renderer);
2463 if(s.backend) wlr_backend_destroy(s.backend);
2464 if(s.emulation_state) xkb_state_unref(s.emulation_state);
2465 if(s.synthetic_owner.id) wlr_keyboard_finish(&s.synthetic);
2466 wl_display_destroy(s.display);
2467 return result;
2469static void free_command(struct wm_message m) {
2470 if(m.word[0]==90) free((void *)(intptr_t)m.word[3]);
2471 if(m.word[0]==91 && m.word[12]) wlr_buffer_drop((void *)(intptr_t)m.word[12]);
2473static void *host_thread(void *unused) {
2474 (void)unused;
2475 wlr_log_init(WLR_ERROR,NULL);
2476 int result=run_host();
2477 struct wm_message m;
2478 while(pop(&bridge.commands,&m)) free_command(m);
2479 atomic_store(&bridge.state,result ? -1 : 3);
2480 EVENT(7,0,result);
2481 return NULL;
2483int wm_start(void) {
2484 if(bridge.created || bridge.request_deadline<1) return 0;
2485 bridge.created=true;
2486 if(getenv("SIGIL_WM_TRACE_LATENCY") && !strcmp(getenv("SIGIL_WM_TRACE_LATENCY"),"1"))
2487 wm_trace_enable(1);
2488 bridge.event_fd=eventfd(0,EFD_NONBLOCK|EFD_CLOEXEC);
2489 bridge.command_fd=eventfd(0,EFD_NONBLOCK|EFD_CLOEXEC);
2490 if(bridge.event_fd<0 || bridge.command_fd<0) goto fail;
2491 atomic_store(&bridge.state,1);
2492 if(!pthread_create(&bridge.thread,NULL,host_thread,NULL)) return 1;
2493fail:
2494 if(bridge.event_fd>=0) close(bridge.event_fd);
2495 if(bridge.command_fd>=0) close(bridge.command_fd);
2496 bridge.joined=true;
2497 atomic_store(&bridge.state,-1);
2498 return 0;
2500int wm_options(int64_t protocols,int64_t request_deadline) {
2501 if(bridge.created || protocols<0 || (protocols&~4095) || request_deadline<1 || request_deadline>60000) return 0;
2502 bridge.protocols=protocols; bridge.request_deadline=request_deadline;
2503 return 1;
2505int wm_decoration_default(int mode) {
2506 if(bridge.created || mode<0 || mode>2) return 0;
2507 bridge.legacy_decoration_default=mode;
2508 return 1;
2510int wm_socket_name(const char *name) {
2511 if(bridge.created || !name || strlen(name)>=sizeof(bridge.requested_socket)) return 0;
2512 if(!strcmp(name,".") || !strcmp(name,"..")) return 0;
2513 for(const unsigned char *character=(const unsigned char *)name;*character;character++)
2514 if(*character<33 || *character>126 || *character=='/') return 0;
2515 snprintf(bridge.requested_socket,sizeof(bridge.requested_socket),"%s",name);
2516 return 1;
2518int wm_state(void) { return atomic_load(&bridge.state); }
2519int wm_event_fd(void) { return bridge.created && !bridge.joined ? bridge.event_fd : -1; }
2520int wm_next(struct wm_message *event) {
2521 if(!event || !bridge.created || bridge.joined) return 0;
2522 drain(bridge.event_fd);
2523 if(next_copied_event(event)) {
2524 if(event->word[0]==7) bridge.terminal_delivered=true;
2525 return 1;
2527 struct trace_record record;
2528 if(trace_next(&record)) {
2529 *event=(struct wm_message){.word={129,record.correlation,record.stage,record.ns,
2530 record.object,record.sequence,record.ns/1000000000ULL,record.ns%1000000000ULL}};
2531 return 1;
2533 int state=wm_state();
2534 if(!bridge.terminal_delivered && (state==3 || state==-1)) {
2535 *event=(struct wm_message){.word={7,0,state==-1}};
2536 bridge.terminal_delivered=true;
2537 return 1;
2539 return 0;
2541static int send_owned_result(struct wm_message m,unsigned *depth,int *state) {
2542 *state=wm_state();
2543 if(*state!=2 || bridge.joined) {
2544 *depth=atomic_load(&bridge.commands.write)-atomic_load(&bridge.commands.read);
2545 return *state==1 && !bridge.joined ? WM_SEND_STARTING : WM_SEND_STOPPED;
2547 if(!push(&bridge.commands,m)) { *depth=QUEUE_SIZE; return WM_SEND_FULL; }
2548 wake(bridge.command_fd); return WM_SEND_ACCEPTED;
2550static int send_owned(struct wm_message m) {
2551 unsigned depth;
2552 int state;
2553 return send_owned_result(m,&depth,&state)==WM_SEND_ACCEPTED;
2555int wm_send(const struct wm_message *m) {
2556 if(!m || m->word[0]>=90 || m->word[0]<=0) return 0;
2557 return send_owned(*m);
2559int wm_input_reply(const struct wm_message *m,int kind) {
2560 /* Repeated retries must not turn backpressure into logging pressure. */
2561 static struct { uint64_t next,suppressed; } reports[3][3];
2562 if(!m || m->word[0]!=11 || kind<30 || kind>32) return WM_SEND_INVALID;
2563 unsigned depth;
2564 int state,result=send_owned_result(*m,&depth,&state);
2565 if(result==WM_SEND_ACCEPTED) return result;
2566 unsigned reason=result==WM_SEND_FULL ? 0 : result==WM_SEND_STARTING ? 1 : 2;
2567 uint64_t now=now_ms();
2568 if(now>=reports[kind-30][reason].next) {
2569 fprintf(stderr,"INPUT_REPLY case=%s action=%s depth=%u kind=%d state=%d suppressed=%llu\n",
2570 result==WM_SEND_FULL ? "queue-full" : result==WM_SEND_STARTING ? "receiver-starting" : "receiver-stopped",
2571 result==WM_SEND_STOPPED ? "drop" : "wait",depth,kind,state,
2572 (unsigned long long)reports[kind-30][reason].suppressed);
2573 reports[kind-30][reason].next=now+1000;
2574 reports[kind-30][reason].suppressed=0;
2575 } else reports[kind-30][reason].suppressed++;
2576 return result;
2578int wm_submit_traced(int64_t kind,int64_t token,const int64_t *words,int64_t count,const uint64_t *causes,int trace_count) {
2579 if(!words || count<1 || count>65536 || kind<1 || kind>17) return 0;
2580 if(trace_count<0 || trace_count>TRACE_CAUSES || (trace_count && !causes)) return 0;
2581 int64_t *copy=malloc((count+trace_count)*sizeof(int64_t));
2582 if(!copy) return 0;
2583 memcpy(copy,words,count*sizeof(int64_t));
2584 if(trace_count) memcpy(copy+count,causes,trace_count*sizeof(uint64_t));
2585 struct wm_message m={.word={90,kind,token,(int64_t)(intptr_t)copy,count}};
2586 m.word[5]=trace_count;
2587 m.word[15]=trace_count ? causes[0] : 0;
2588 if(send_owned(m)) return 1;
2589 free(copy); return 0;
2591int wm_submit(int64_t kind,int64_t token,const int64_t *words,int64_t count) {
2592 return wm_submit_traced(kind,token,words,count,NULL,0);
2594int wm_pixels_traced(int64_t id,const int64_t *w,const void *data,const int64_t *options,const uint64_t *causes,int trace_count) {
2595 if(trace_count<0 || trace_count>TRACE_CAUSES || (trace_count && !causes)) return 0;
2596 if(options && (options[0]<0 || options[0]>1 || options[1]<0)) return 0;
2597 if(!w || id<=0 || w[0]<-32768 || w[0]>32768 || w[1]<-32768 || w[1]>32768 || w[7]<-1 || w[7]>2) return 0;
2598 size_t order_count=0;
2599 if(w[7]==2) {
2600 if(!data || !options || options[6]<1 || options[6]>65535) return 0;
2601 order_count=(size_t)options[6]+1;
2602 if(!scene_order_valid(options+6,order_count)) return 0;
2603 bool included=false;
2604 for(size_t i=7;i<6+order_count;i++) if(options[i]==-id) included=true;
2605 if(!included) return 0;
2607 struct pixel_buffer *b=NULL;
2608 if(data) {
2609 if(w[2]<1 || w[2]>16384 || w[3]<1 || w[3]>16384 || w[4]<1 || w[4]>16384 ||
2610 w[5]<1 || w[5]>16384 || w[6]<w[4]*4 || w[6]>65536 || w[6]%4 ||
2611 w[5]*w[6]>8*1024*1024) return 0;
2612 if(options && options[1]>0 &&
2613 (options[2]<-32768 || options[2]>32768 || options[3]<-32768 || options[3]>32768 ||
2614 options[4]<1 || options[4]>32768 || options[5]<1 || options[5]>32768 ||
2615 w[0]<options[2] || w[1]<options[3] ||
2616 w[0]+w[2]>options[2]+options[4] || w[1]+w[3]>options[3]+options[5])) return 0;
2617 size_t pixels_length=w[5]*w[6];
2618 size_t offset=order_count ? (pixels_length+7)&~(size_t)7 : pixels_length;
2619 size_t length=offset+order_count*sizeof(int64_t),size=sizeof(*b)+length;
2620 uint_fast64_t retained=atomic_load(&bridge.bytes);
2621 do { if(retained+size>MAX_PIXELS) return 0; }
2622 while(!atomic_compare_exchange_weak(&bridge.bytes,&retained,retained+size));
2623 b=calloc(1,size);
2624 if(!b) { atomic_fetch_sub(&bridge.bytes,size); return 0; }
2625 b->length=length; b->stride=w[6]; b->input=options && options[0];
2626 b->trace_count=trace_count;
2627 if(trace_count) memcpy(b->trace_causes,causes,trace_count*sizeof(uint64_t));
2628 b->order_count=order_count;
2629 if(options) memcpy(b->scope,options+1,sizeof(b->scope));
2630 memcpy(b->data,data,pixels_length);
2631 if(order_count) memcpy(b->data+offset,options+6,order_count*sizeof(int64_t));
2632 wlr_buffer_init(&b->base,&pixel_impl,w[4],w[5]);
2634 struct wm_message m={.word={91,id}};
2635 memcpy(m.word+2,w,8*sizeof(int64_t));
2636 m.word[12]=(int64_t)(intptr_t)b;
2637 m.word[15]=trace_count ? causes[0] : 0;
2638 if(send_owned(m)) return 1;
2639 if(b) wlr_buffer_drop(&b->base);
2640 return 0;
2642int wm_pixels_with_options(int64_t id,const int64_t *w,const void *data,const int64_t *options) {
2643 return wm_pixels_traced(id,w,data,options,NULL,0);
2645int wm_pixels(int64_t id,const int64_t *w,const void *data) {
2646 return wm_pixels_with_options(id,w,data,NULL);
2648const char *wm_socket(void) { return wm_state()==2 ? bridge.socket : ""; }
2649uint64_t wm_stat(int which) {
2650 switch(which) {
2651 case 0: return atomic_load(&bridge.frames);
2652 case 1: return atomic_load(&bridge.objects);
2653 case 2: return atomic_load(&bridge.overflow);
2654 case 3: return atomic_load(&bridge.rejected);
2655 case 4: return atomic_load(&bridge.bytes);
2656 case 5: return atomic_load(&bridge.pixel_nodes);
2657 case 6: return atomic_load(&bridge.pixel_drops);
2658 case 7: return atomic_load(&bridge.saved_trees);
2659 case 8: return atomic_load(&bridge.snapshots);
2660 case 9: return event_resync_count;
2661 case 10: return atomic_load(&bridge.input_expired);
2662 case 11: return atomic_load(&bridge.motion_coalesced);
2663 case 12: return atomic_load(&bridge.timer_wakes);
2664 case 13: return atomic_load(&bridge.first_present_ms);
2665 default: return UINT64_MAX;
2668int wm_join(void) {
2669 if(!bridge.created || bridge.joined || (wm_state()!=3 && wm_state()!=-1)) return 0;
2670 if(pthread_join(bridge.thread,NULL)) return 0;
2671 struct wm_message command;
2672 while(pop(&bridge.commands,&command)) free_command(command);
2673 free_event_stream();
2674 close(bridge.event_fd); close(bridge.command_fd); bridge.joined=true; return 1;