Commit76c870cfRecorded29 Oct 2026Repositorysigil-wm
Cover scene move completion and stale scene reconciliation
Changed
Makefile | 3 +++
src/c/devices.h | 1 +
src/c/host.c | 6 +++---
src/c/scene-move.h | 20 ++++++++++++++++----
src/sigil/wm/runtime.sgl | 2 +-
test/input-driver.c | 6 ++++++
test/scene-move.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 85 insertions(+), 8 deletions(-)Diff
Makefilemodified
@@ -29,6 +29,9 @@ 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
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
@@ -263,7 +263,7 @@ struct input {
263
struct scene_move_item { int64_t id; int x,y; }; 264
struct scene_move { 265
bool retained,active;−266
uint64_t token,window;+266
uint64_t token,window,device; 267
int button,dx,dy; 268
double pointer_x,pointer_y; 269
unsigned count;@@ -371,6 +371,7 @@ struct server {
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);@@ -881,8 +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) {−884
if(input.kind==31 && !input.state && input.code==s->scene_move.button)−885
scene_move_finish(s);+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;src/c/scene-move.hmodified
@@ -1,11 +1,16 @@
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(struct server *s) {+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);+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) {@@ -42,6 +47,7 @@ static bool scene_move_motion(struct server *s,uint32_t time,double x,double y,
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);@@ -52,17 +58,23 @@ static bool scene_move_motion(struct server *s,uint32_t time,double x,double y,
58
} 59
static bool scene_move_start(struct server *s,uint64_t token,const int64_t *w,size_t n) { 60
if(s->lock_state || 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
struct view *view=find_view(s,w[0]); 64
if(!view || !visible(view) || view->layer) return false; 65
bool held=false,owner=false;+66
uint64_t device=0; 67
for(unsigned i=0;i<QUEUE_SIZE;i++) { 68
if((s->buttons[i].held && s->buttons[i].code==w[1]) ||−61
(s->intercepted_buttons[i].held && s->intercepted_buttons[i].code==w[1])) held=true;+69
(s->intercepted_buttons[i].held && s->intercepted_buttons[i].code==w[1])) {+70
held=true;+71
device=s->intercepted_buttons[i].held && s->intercepted_buttons[i].code==w[1] ?+72
s->intercepted_buttons[i].device : s->buttons[i].device;+73
} 74
} 75
if(!held) return false; 76
struct scene_move next={.retained=true,.active=true,.token=token,−65
.window=w[0],.button=w[1],.pointer_x=w[2]/1000.0,.pointer_y=w[3]/1000.0,.count=w[4]};+77
.window=w[0],.device=device,.button=w[1],.pointer_x=w[2]/1000.0,.pointer_y=w[3]/1000.0,.count=w[4]}; 78
for(unsigned i=0;i<next.count;i++) { 79
int64_t id=w[5+i]; 80
if(!id || id==INT64_MIN) return false;src/sigil/wm/runtime.sglmodified
@@ -104,7 +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)))+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)))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,55 @@
+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
assert(!scene_move_start(&s,10,payload,7)); /* no held initiating button */+24
s.intercepted_buttons[0].held=true; s.intercepted_buttons[0].code=272;+25
s.intercepted_buttons[0].device=9;+26
assert(scene_move_start(&s,11,payload,7));+27
s.cursor->x=80; s.cursor->y=60; scene_move_update(&s);+28
assert(view.tree->node.x==140 && view.tree->node.y==120);+29
assert(border.scene->node.x==139 && border.scene->node.y==119);+30
assert(view.tree->node.link.next==&border.scene->node.link); /* no restack */+31
scene_move_position(&s,1,&view.tree->node,100,100);+32
scene_move_position(&s,-2,&border.scene->node,99,99);+33
assert(view.tree->node.x==140 && border.scene->node.x==139);+34
int64_t stale[]={1,1,0,200,1,100,100,64,64,1,0,0,0,0};+35
scene_move_plan(&s,stale); assert(s.scene_move.retained && s.scene_move.active);+36
struct input release={.kind=31,.code=272,.device=8};+37
scene_move_button(&s,&release); assert(s.scene_move.active);+38
release.device=9; scene_move_button(&s,&release); assert(!s.scene_move.active);+39
struct wm_message event; assert(pop(&bridge.events,&event));+40
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);+41
scene_move_plan(&s,stale); assert(s.scene_move.retained);+42
stale[5]=140; stale[6]=120; scene_move_plan(&s,stale); assert(!s.scene_move.retained);+43
int64_t duplicate[]={1,272,40000,40000,2,1,1};+44
assert(!scene_move_start(&s,12,duplicate,7));+45
int64_t missing_owner[]={1,272,40000,40000,1,-2};+46
assert(!scene_move_start(&s,12,missing_owner,6));+47
payload[2]=INT64_MAX; assert(!scene_move_start(&s,12,payload,7)); payload[2]=80000; payload[3]=60000;+48
assert(scene_move_start(&s,13,payload,7));+49
s.lock_state=1; assert(!scene_move_motion(&s,0,90,60,0,0)); assert(!s.scene_move.active);+50
s.lock_state=0; assert(scene_move_start(&s,14,payload,7));+51
view.mapped=false; assert(!scene_move_motion(&s,0,90,60,0,0)); assert(!s.scene_move.active);+52
close(bridge.event_fd); wlr_cursor_destroy(s.cursor); wlr_scene_node_destroy(&s.scene->tree.node);+53
puts("SCENE_MOVE=PASS admission grouped-geometry stable-order stale-plans release lock unmap");+54
return 0;+55
}