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 build
README.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
}