Commit1d8bb767Recorded29 Oct 2026Repositorysigil-wm
Merge native floating window movement and scene move lifecycle
Changed
Makefile | 5 ++++-
README.md | 13 +++++++++++++
scripts/check | 3 ++-
src/c/devices.h | 1 +
src/c/host.c | 31 +++++++++++++++++++++++++++----
src/c/lock.h | 1 +
src/c/scene-move.h | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/sigil/wm/runtime.sgl | 1 +
src/sigil/wm/scene.sgl | 14 +++++++++++++-
test/input-driver.c | 6 ++++++
test/scene-move.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 258 insertions(+), 7 deletions(-)Diff
A merge. Shown against its first parent, so this is the effect of merging rather than the work of the branch.
Makefilemodified
@@ -29,10 +29,13 @@ build/trace-records-test: test/trace-records.c src/c/trace-records.h
29
build/output-inventory-test: test/output-inventory.c src/c/output-inventory.h src/c/host.c 30
$(CC) $(CFLAGS) $(CPPFLAGS) $< $(LDFLAGS) $(LDLIBS) -o $@ 31
+32
build/scene-move-test: test/scene-move.c src/c/scene-move.h src/c/host.c+33
$(CC) $(CFLAGS) $(CPPFLAGS) $< $(LDFLAGS) $(LDLIBS) -o $@+34
35
build/deadlines-test: test/deadlines.c src/c/deadlines.h src/c/host.c 36
$(CC) $(CFLAGS) $(CPPFLAGS) $< $(LDFLAGS) $(LDLIBS) -o $@ 37
−35
build/libsigil-wm.so: src/c/trace-records.h src/c/output-inventory.h src/c/deadlines.h+38
build/libsigil-wm.so: src/c/scene-move.h src/c/trace-records.h src/c/output-inventory.h src/c/deadlines.h 39
40
build/environment-exec: src/c/environment-exec.c 41
mkdir -p buildREADME.mdmodified
@@ -4,6 +4,19 @@
4
5
A toolkit for writing Wayland window managers in Sigil, built on wlroots. 6
The native thread owns Wayland objects, input transport and scene presentation.+7
+8
Copied admissions that arrive after release, lock, or resource retirement complete+9
with a cancelled `scene-move-ended` event.+10
+11
Interactive scene translation uses `start-scene-move!` with a window, held+12
button, pointer anchor and an explicit set of window/pixel resources (at most+13
256). The native owner follows pointer motion without a manager round trip or+14
restacking. `scene-move-ended` reports `delta-x:`, `delta-y:`, `move-token:`+15
and `reason:` (0 release, 1 cancellation). The manager reconciles its geometry+16
in the next full plan; stale plans cannot rewind the move. Explicit fullscreen,+17
tiled or hidden placements cancel translation. `stop-scene-move!`, lock, unmap+18
and initiating-device removal also stop it.+19
20
Sigil chooses placement, visibility, stacking, focus and input handling. 21
22
The library namespaces are `(sigil wm host)`, `(sigil wm model)`,scripts/checkmodified
@@ -4,7 +4,8 @@ cd "$(dirname "$0")/.."
4
if [[ ${1:-} != --inside ]]; then 5
exec guix time-machine -C channels.scm -- shell -m draw-manifest.scm -- bash scripts/check --inside 6
fi−7
make -j2+7
make -j2 all build/scene-move-test+8
build/scene-move-test 9
bash scripts/test-environment-exec 10
bash scripts/run-sigil -L src -L examples -L .deps eval -f test/imports.sgl 11
src/c/devices.hmodified
@@ -9,6 +9,7 @@ static void device_destroy(struct wl_listener *listener,void *data) {
9
(void)data; 10
struct device *device=wl_container_of(listener,device,destroy); 11
struct server *s=device->server;+12
if(s->scene_move.device==device->id) scene_move_finish(s); 13
for(int index=0;index<QUEUE_SIZE;index++) { 14
if(s->buttons[index].held && s->buttons[index].device==device->id) { 15
wlr_seat_pointer_notify_button(s->seat,now_ms(),s->buttons[index].target,0);src/c/host.cmodified
@@ -260,6 +260,15 @@ struct input {
260
uint64_t output; 261
double x, y; 262
};+263
struct scene_move_item { int64_t id; int x,y; };+264
struct 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
}; 272
struct server { 273
struct wl_display *display; 274
struct wlr_security_context_manager_v1 *security_context;@@ -349,6 +358,7 @@ struct server {
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;@@ -360,6 +370,11 @@ struct server {
370
uint64_t plan_trace_causes[TRACE_CAUSES]; 371
}; 372
+373
static void scene_move_finish(struct server *s);+374
static void scene_move_button(struct server *s,const struct input *input);+375
static bool scene_move_motion(struct server *s,uint32_t time,double x,double y,uint64_t completion,int origin);+376
static void scene_move_position(struct server *s,int64_t resource,struct wlr_scene_node *node,int x,int y);+377
static void scene_move_plan(struct server *s,const int64_t *w); 378
#include "security-context.h" 379
#include "output-inventory.h" 380
@@ -867,6 +882,7 @@ static bool configure_input_intercepts(struct server *s,bool key,int64_t *words,
882
return true; 883
} 884
static 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;@@ -1046,6 +1062,7 @@ static void motion_input(struct server *s, uint32_t time, double x, double y, ui
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) {@@ -1437,11 +1454,12 @@ static void check_plan(struct server *s) {
1454
} 1455
if(!ready && now_ms()<s->plan_deadline) return; 1456
release_saved(s);+1457
scene_move_plan(s,w); 1458
for(int i=0;i<w[1];i++) { 1459
const int64_t *p=w+4+10*i; 1460
if(p[0]<0) { 1461
struct pixels *image=find_pixels(s,-p[0]);−1444
wlr_scene_node_set_position(&image->scene->node,p[1],p[2]);+1462
scene_move_position(s,p[0],&image->scene->node,p[1],p[2]); 1463
wlr_scene_buffer_set_dest_size(image->scene,p[3],p[4]); 1464
wlr_scene_node_set_enabled(&image->scene->node, 1465
p[5] && pixel_scope_valid(s,image->scope));@@ -1449,7 +1467,7 @@ static void check_plan(struct server *s) {
1467
continue; 1468
} 1469
struct view *v=find_view(s,p[0]);−1452
wlr_scene_node_set_position(&v->tree->node,p[1],p[2]);+1470
scene_move_position(s,p[0],&v->tree->node,p[1],p[2]); 1471
wlr_scene_node_set_enabled(&v->tree->node,p[5] && v->mapped); 1472
if (v->layer && p[5] && v->mapped && !v->layer_presented && !v->layer_present_armed) { 1473
v->layer_present_commit = v->layer->output->commit_seq + 1;@@ -1757,6 +1775,7 @@ static struct wlr_scene_node *scene_resource(struct server *s,int64_t resource)
1775
struct pixels *pixels=find_pixels(s,-resource); 1776
return pixels ? &pixels->scene->node : NULL; 1777
}+1778
#include "scene-move.h" 1779
/* Position only this resource. Copied retired neighbours are harmless; no 1780
* frame or input dispatch can observe creation before its final insertion. */ 1781
static void position_pixels(struct server *s,struct pixels *p,const int64_t *order,size_t count) {@@ -1801,7 +1820,7 @@ static bool apply_pixels(struct server *s,uint64_t id,int64_t *w,struct pixel_bu
1820
memcpy(p->scope,b->scope,sizeof(p->scope)); 1821
wlr_scene_node_set_enabled(&p->scene->node,true); 1822
wlr_scene_buffer_set_dest_size(p->scene,w[2],w[3]);−1804
wlr_scene_node_set_position(&p->scene->node,w[0],w[1]);+1823
scene_move_position(s,-(int64_t)id,&p->scene->node,w[0],w[1]); 1824
if(b->order_count) { 1825
size_t offset=(b->stride*(size_t)b->base.height+7)&~(size_t)7; 1826
position_pixels(s,p,(const int64_t *)(b->data+offset),b->order_count);@@ -2129,6 +2148,7 @@ static bool apply_command(struct server *s,struct wm_message m) {
2148
ok=output_set_gamma(s,w[2],data,w[4]); 2149
if(!ok && w[4]>=1) EVENT(131,data[0],w[2],false); 2150
break;+2151
case 17: ok=scene_move_start(s,w[2],data,w[4]); break; 2152
case 8: ok=restack_scene(s,data,w[4]); break; 2153
case 9: ok=configure_pointer(s,w[2],data,w[4]); break; 2154
case 10: output_batch(s,w[2],data,w[4]); free(data); return true;@@ -2159,6 +2179,9 @@ static bool apply_command(struct server *s,struct wm_message m) {
2179
if (w[1] < 1 || w[1] > 200) return false; 2180
s->scene_update_deadline = now_ms() + w[1]; 2181
return true;+2182
case 43:+2183
if(s->scene_move.token==(uint64_t)w[1]) scene_move_finish(s);+2184
return true; 2185
case 42: { 2186
struct output *o = find_output(s, w[1]); 2187
if (!o) return false;@@ -2519,7 +2542,7 @@ int wm_input_reply(const struct wm_message *m,int kind) {
2542
return result; 2543
} 2544
int wm_submit_traced(int64_t kind,int64_t token,const int64_t *words,int64_t count,const uint64_t *causes,int trace_count) {−2522
if(!words || count<1 || count>65536 || kind<1 || kind>16) return 0;+2545
if(!words || count<1 || count>65536 || kind<1 || kind>17) return 0; 2546
if(trace_count<0 || trace_count>TRACE_CAUSES || (trace_count && !causes)) return 0; 2547
int64_t *copy=malloc((count+trace_count)*sizeof(int64_t)); 2548
if(!copy) return 0;src/c/lock.hmodified
@@ -212,6 +212,7 @@ static void lock_new(struct wl_listener *listener,void *data) {
212
struct server *s=wl_container_of(listener,s,new_lock); 213
struct wlr_session_lock_v1 *owner=data; 214
if(s->lock_owner || s->stopping) { wlr_session_lock_v1_destroy(owner); return; }+215
scene_move_finish(s); 216
s->lock_owner=owner; s->lock_generation++; s->lock_state=1; 217
s->lock_deadline=now_ms()+bridge.request_deadline; 218
wlr_scene_node_set_enabled(&s->normal->node,false);src/c/scene-move.hadded
@@ -0,0 +1,123 @@
+1
/* SPDX-License-Identifier: BSD-3-Clause+2
* Pointer-following is a mechanism over an explicit manager-supplied resource+3
* set. It does not choose floating membership, decoration ownership or order. */+4
static void scene_move_finish_reason(struct server *s,int reason) {+5
struct scene_move *move=&s->scene_move;+6
if(!move->active) return;+7
move->active=false;+8
EVENT(38,move->window,move->dx,move->dy,move->token,reason);+9
}+10
static void scene_move_finish(struct server *s) { scene_move_finish_reason(s,1); }+11
static void scene_move_button(struct server *s,const struct input *input) {+12
if(input->kind==31 && !input->state && input->code==s->scene_move.button &&+13
input->device==s->scene_move.device) scene_move_finish_reason(s,0);+14
}+15
static void scene_move_position(struct server *s,int64_t resource,+16
struct wlr_scene_node *node,int x,int y) {+17
struct scene_move *move=&s->scene_move;+18
if(move->retained) {+19
for(unsigned i=0;i<move->count;i++) {+20
if(move->items[i].id!=resource) continue;+21
x=move->items[i].x+move->dx; y=move->items[i].y+move->dy;+22
break;+23
}+24
}+25
wlr_scene_node_set_position(node,x,y);+26
}+27
static void scene_move_update(struct server *s) {+28
struct scene_move *move=&s->scene_move;+29
move->dx=(int)round(s->cursor->x-move->pointer_x);+30
move->dy=(int)round(s->cursor->y-move->pointer_y);+31
for(unsigned i=0;i<move->count;i++) {+32
struct wlr_scene_node *node=scene_resource(s,move->items[i].id);+33
if(node) scene_move_position(s,move->items[i].id,node,0,0);+34
}+35
struct view *view=find_view(s,move->window);+36
if(view && view->x11)+37
wlr_xwayland_surface_configure(view->x11,view->tree->node.x,+38
view->tree->node.y,view->width,view->height);+39
}+40
static bool scene_move_motion(struct server *s,uint32_t time,double x,double y,+41
uint64_t completion,int origin) {+42
struct scene_move *move=&s->scene_move;+43
if(!move->active) return false;+44
struct view *view=find_view(s,move->window);+45
if(s->lock_state || !view || !visible(view)) {+46
scene_move_finish(s); return false;+47
}+48
uint64_t token=++s->next_token;+49
latency_trace(0,token,32,0);+50
s->motion_delivered_token=token;+51
constrained_warp(s,x,y);+52
s->motion_x=s->cursor->x; s->motion_y=s->cursor->y;+53
scene_move_update(s);+54
trace_damage(s,token,0);+55
route_motion(s,time,true);+56
if(completion) EVENT(35,completion,1,origin,token);+57
return true;+58
}+59
static bool scene_move_start(struct server *s,uint64_t token,const int64_t *w,size_t n) {+60
if(n<6 || w[0]<=0 || w[1]<272 || w[1]>=288 ||+61
w[2]<-32768000 || w[2]>32768000 || w[3]<-32768000 || w[3]>32768000 ||+62
w[4]<1 || w[4]>256 || n!=5+(size_t)w[4]) return false;+63
/* Validate copied shape before checking state that can retire in transit. */+64
bool owner=false;+65
for(unsigned i=0;i<(unsigned)w[4];i++) {+66
int64_t id=w[5+i];+67
if(!id || id==INT64_MIN) return false;+68
for(unsigned j=0;j<i;j++) if(w[5+j]==id) return false;+69
if(id==w[0]) owner=true;+70
}+71
if(!owner) return false;+72
struct view *view=find_view(s,w[0]);+73
bool held=false;+74
uint64_t device=0;+75
for(unsigned i=0;i<QUEUE_SIZE;i++) {+76
if((s->buttons[i].held && s->buttons[i].code==w[1]) ||+77
(s->intercepted_buttons[i].held && s->intercepted_buttons[i].code==w[1])) {+78
held=true;+79
device=s->intercepted_buttons[i].held && s->intercepted_buttons[i].code==w[1] ?+80
s->intercepted_buttons[i].device : s->buttons[i].device;+81
}+82
}+83
/* A quick release, unmap, lock or decoration retirement can precede this+84
* asynchronous admission. Complete the manager token without rejecting its+85
* command or resurrecting a gesture that has already ended. */+86
if(s->lock_state || !held || !view || !visible(view) || view->layer) {+87
EVENT(38,w[0],0,0,token,1); return true;+88
}+89
struct scene_move next={.retained=true,.active=true,.token=token,+90
.window=w[0],.device=device,.button=w[1],.pointer_x=w[2]/1000.0,.pointer_y=w[3]/1000.0,.count=w[4]};+91
for(unsigned i=0;i<next.count;i++) {+92
int64_t id=w[5+i];+93
struct wlr_scene_node *node=scene_resource(s,id);+94
if(!node || node->parent!=s->normal) {+95
EVENT(38,w[0],0,0,token,1); return true;+96
}+97
next.items[i]=(struct scene_move_item){id,node->x,node->y};+98
}+99
scene_move_finish(s);+100
s->scene_move=next;+101
scene_move_update(s);+102
return true;+103
}+104
/* Delayed plans/uploads cannot undo newer pointer motion. Keep the final+105
* position through release until the manager acknowledges it in a full plan. */+106
static void scene_move_plan(struct server *s,const int64_t *w) {+107
struct scene_move *move=&s->scene_move;+108
if(!move->retained) return;+109
struct view *view=find_view(s,move->window);+110
if(!view || !view->mapped) { scene_move_finish(s); move->retained=false; return; }+111
for(int i=0;i<w[1];i++) {+112
const int64_t *p=w+4+10*i;+113
if(p[0]!=(int64_t)move->window) continue;+114
if(!p[5] || p[7] || p[8]) {+115
scene_move_finish(s); move->retained=false; return;+116
}+117
if(!move->active) {+118
struct wlr_scene_node *node=scene_resource(s,move->window);+119
if(node && p[1]==node->x && p[2]==node->y) move->retained=false;+120
}+121
break;+122
}+123
}src/sigil/wm/runtime.sglmodified
@@ -104,6 +104,7 @@
104
((32) '(motion)) 105
((35) '(input-completed (success?: 2) (origin: 3) (input-token: 4))) 106
((36) '(motion-hook-applied (enabled?: 2)))+107
((38) '(scene-move-ended (delta-x: 2) (delta-y: 3) (move-token: 4) (reason: 5))) 108
((37) '(pointer-target-changed (output: 2) (x-milli: 3) (y-milli: 4) (moved?: 5) (generation: 6) (pointer-token: 7))) 109
((40) '(device-added (device-type: 2) (virtual?: 3) (libinput?: 4) (tap-fingers: 5) (nested?: 6))) 110
((41) '(keyboard-state (group: 2) (groups: 3)))src/sigil/wm/scene.sglmodified
@@ -4,7 +4,7 @@
4
(export placement placement? placement-window placement-kind placement-box placement-shown? 5
placement-activated? placement-suspended? placement-fullscreen? placement-tiled placement-clip? placement-resize? 6
scene-plan scene-plan? make-scene-plan scene-plan-placements scene-plan-focus−7
scene-plan-deadline scene-plan-limit validate-plan submit-plan! restack-scene! present-pixels! place-pixels! remove-pixels!)+7
scene-plan-deadline scene-plan-limit validate-plan submit-plan! restack-scene! start-scene-move! stop-scene-move! present-pixels! place-pixels! remove-pixels!) 8
(begin 9
(define-struct placement 10
(window) (kind default: 'window) (box) (shown? default: #t) (activated? default: #f) (suspended? default: #f)@@ -78,6 +78,18 @@
78
(and (<= (length words) 65535) 79
(host-submit! host 8 token (cons (length words) words)) token))) 80
+81
;; Follow the pointer natively until BUTTON is released. The manager supplies+82
;; all resources and the pointer anchor from the initiating press. No scene+83
;; order or window membership is inferred by the native host.+84
(define (start-scene-move! host window button x y resources)+85
(let ((words (scene-resource-words resources)) (token (host-next-token! host)))+86
(and (<= 1 (length words) 256)+87
(host-submit! host 17 token+88
(append (list window button (inexact->exact (round (* x 1000)))+89
(inexact->exact (round (* y 1000))) (length words)) words))+90
token)))+91
(define (stop-scene-move! host token) (host-send! host (list 43 token)))+92
93
;; Pixel descriptor: data, pixel width/height, stride. No draw-module import. 94
(define (stack-code stack) 95
(case stack ((top) 1) ((bottom) -1) ((keep) 0) (else (error "invalid pixel stacking" stack))))test/input-driver.cmodified
@@ -195,6 +195,12 @@ int main(void) {
195
if (wl_display_roundtrip(input.display) < 0) return 11; 196
printf("INPUT_SENT=%s", line); 197
printf("INPUT_ACK=%u\n", ++sequence);+198
if(getenv("SIGIL_WM_INPUT_TIMESTAMPS")) {+199
struct timespec now;+200
clock_gettime(CLOCK_MONOTONIC,&now);+201
printf("INPUT_ACK_TIME=%u %lld\n",sequence,+202
(long long)now.tv_sec*1000000000+now.tv_nsec);+203
} 204
fflush(stdout); 205
} 206
return 12;test/scene-move.cadded
@@ -0,0 +1,67 @@
+1
/* SPDX-License-Identifier: BSD-3-Clause */+2
#define listen socket_listen+3
#include <sys/socket.h>+4
#undef listen+5
#include "../src/c/host.c"+6
#include <assert.h>+7
+8
int main(void) {+9
struct server s={0};+10
wl_list_init(&s.views); wl_list_init(&s.pixels); wl_list_init(&s.outputs);+11
s.scene=wlr_scene_create(); assert(s.scene);+12
s.normal=wlr_scene_tree_create(&s.scene->tree); assert(s.normal);+13
s.cursor=wlr_cursor_create(); assert(s.cursor);+14
s.cursor->x=40; s.cursor->y=40;+15
bridge.event_fd=eventfd(0,EFD_NONBLOCK|EFD_CLOEXEC); assert(bridge.event_fd>=0);+16
struct view view={.id=1,.mapped=true,.tree=wlr_scene_tree_create(s.normal)};+17
struct pixels border={.id=2,.scene=wlr_scene_buffer_create(s.normal,NULL)};+18
assert(view.tree && border.scene);+19
wl_list_insert(&s.views,&view.link); wl_list_insert(&s.pixels,&border.link);+20
wlr_scene_node_set_position(&view.tree->node,100,100);+21
wlr_scene_node_set_position(&border.scene->node,99,99);+22
int64_t payload[]={1,272,40000,40000,2,1,-2};+23
struct wm_message event;+24
assert(scene_move_start(&s,10,payload,7)); /* release overtook copied admission */+25
assert(!s.scene_move.active && pop(&bridge.events,&event));+26
assert(event.word[0]==38 && event.word[4]==10 && event.word[5]==1);+27
assert(event.word[2]==0 && event.word[3]==0);+28
s.intercepted_buttons[0].held=true; s.intercepted_buttons[0].code=272;+29
s.intercepted_buttons[0].device=9;+30
assert(scene_move_start(&s,11,payload,7));+31
s.cursor->x=80; s.cursor->y=60; scene_move_update(&s);+32
assert(view.tree->node.x==140 && view.tree->node.y==120);+33
assert(border.scene->node.x==139 && border.scene->node.y==119);+34
assert(view.tree->node.link.next==&border.scene->node.link); /* no restack */+35
scene_move_position(&s,1,&view.tree->node,100,100);+36
scene_move_position(&s,-2,&border.scene->node,99,99);+37
assert(view.tree->node.x==140 && border.scene->node.x==139);+38
int64_t stale[]={1,1,0,200,1,100,100,64,64,1,0,0,0,0};+39
scene_move_plan(&s,stale); assert(s.scene_move.retained && s.scene_move.active);+40
struct input release={.kind=31,.code=272,.device=8};+41
scene_move_button(&s,&release); assert(s.scene_move.active);+42
release.device=9; scene_move_button(&s,&release); assert(!s.scene_move.active);+43
assert(pop(&bridge.events,&event));+44
assert(event.word[0]==38 && event.word[1]==1 && event.word[2]==40 && event.word[3]==20 && event.word[4]==11 && event.word[5]==0);+45
scene_move_plan(&s,stale); assert(s.scene_move.retained);+46
stale[5]=140; stale[6]=120; scene_move_plan(&s,stale); assert(!s.scene_move.retained);+47
int64_t duplicate[]={1,272,40000,40000,2,1,1};+48
assert(!scene_move_start(&s,12,duplicate,7));+49
int64_t missing_owner[]={1,272,40000,40000,1,-2};+50
assert(!scene_move_start(&s,12,missing_owner,6));+51
payload[2]=INT64_MAX; assert(!scene_move_start(&s,12,payload,7)); payload[2]=80000; payload[3]=60000;+52
int64_t retired[]={1,272,80000,60000,2,1,-999};+53
assert(scene_move_start(&s,99,retired,7));+54
assert(pop(&bridge.events,&event) && event.word[4]==99 && event.word[5]==1);+55
assert(!s.scene_move.active);+56
assert(scene_move_start(&s,12,payload,7));+57
stale[5]=0; stale[6]=0; stale[11]=1;+58
scene_move_plan(&s,stale); assert(!s.scene_move.active && !s.scene_move.retained);+59
scene_move_position(&s,1,&view.tree->node,0,0); assert(view.tree->node.x==0);+60
assert(scene_move_start(&s,13,payload,7));+61
s.lock_state=1; assert(!scene_move_motion(&s,0,90,60,0,0)); assert(!s.scene_move.active);+62
s.lock_state=0; assert(scene_move_start(&s,14,payload,7));+63
view.mapped=false; assert(!scene_move_motion(&s,0,90,60,0,0)); assert(!s.scene_move.active);+64
close(bridge.event_fd); wlr_cursor_destroy(s.cursor); wlr_scene_node_destroy(&s.scene->tree.node);+65
puts("SCENE_MOVE=PASS admission stale-start retired-resource grouped-geometry stable-order stale-plans release lock unmap");+66
return 0;+67
}