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
}