Commit20f6ad51Recorded29 Oct 2026Repositorysigil-wm
Complete stale pointer move admissions as cancelled
Changed
README.md | 3 +++
src/c/scene-move.h | 29 ++++++++++++++++++++---------
test/scene-move.c | 14 +++++++++++---
3 files changed, 34 insertions(+), 12 deletions(-)Diff
README.mdmodified
@@ -5,6 +5,9 @@
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 orsrc/c/scene-move.hmodified
@@ -57,12 +57,20 @@ static bool scene_move_motion(struct server *s,uint32_t time,double x,double y,
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(s->lock_state || n<6 || w[0]<=0 || w[1]<272 || w[1]>=288 ||+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]);−64
if(!view || !visible(view) || view->layer) return false;−65
bool held=false,owner=false;+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]) ||@@ -72,19 +80,22 @@ static bool scene_move_start(struct server *s,uint64_t token,const int64_t *w,si
80
s->intercepted_buttons[i].device : s->buttons[i].device; 81
} 82
}−75
if(!held) return false;+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];−80
if(!id || id==INT64_MIN) return false; 93
struct wlr_scene_node *node=scene_resource(s,id);−82
if(!node || node->parent!=s->normal) return false;−83
for(unsigned j=0;j<i;j++) if(next.items[j].id==id) return false;+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};−85
if(id==w[0]) owner=true; 98
}−87
if(!owner) return false; 99
scene_move_finish(s); 100
s->scene_move=next; 101
scene_move_update(s);test/scene-move.cmodified
@@ -20,7 +20,11 @@ int main(void) {
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 */+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));@@ -36,7 +40,7 @@ int main(void) {
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);−39
struct wm_message event; assert(pop(&bridge.events,&event));+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);@@ -45,6 +49,10 @@ int main(void) {
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);@@ -54,6 +62,6 @@ int main(void) {
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);−57
puts("SCENE_MOVE=PASS admission grouped-geometry stable-order stale-plans release lock unmap");+65
puts("SCENE_MOVE=PASS admission stale-start retired-resource grouped-geometry stable-order stale-plans release lock unmap"); 66
return 0; 67
}