AtlatestRepositorysigil-wm

sigil-wm / tree / src / cconstraints.h

1/* SPDX-License-Identifier: BSD-3-Clause
2 * Explicit constraint leases, changed protocol facts and native enforcement. */
3struct constraint {
4 struct wl_list link;
5 struct server *server;
6 struct wlr_pointer_constraint_v1 *native;
7 struct wl_listener destroy,region,unmap;
8 uint64_t id,scope;
9 double origin_x,origin_y;
10 int64_t facts[8];
11 bool sampled;
12};
13struct pointer_hint {
14 struct wl_list link;
15 struct server *server;
16 struct wlr_surface *surface;
17 struct wl_listener destroy;
18 uint64_t token,window,generation,deadline;
19 double x,y;
20};
21static pixman_region32_t *constraint_region(struct constraint *owner) {
22 return pixman_region32_empty(&owner->native->current.region) ?
23 &owner->native->surface->input_region : &owner->native->region;
25static bool constraint_contains(struct constraint *owner,double x,double y) {
26 return x>=0 && y>=0 && pixman_region32_contains_point(constraint_region(owner),(int)x,(int)y,NULL);
28static bool constraint_position(struct constraint *owner,double *x,double *y) {
29 struct server *s=owner->server;
30 struct wlr_pointer_constraint_v1 *native=owner->native;
31 struct view *view=find_view(s,window_for_surface(s,native->surface));
32 if(s->stopping || s->lock_state || native->seat!=s->seat || !native->surface->mapped ||
33 !visible(view) || wlr_seat_pointer_has_grab(s->seat) ||
34 s->seat->pointer_state.focused_surface!=native->surface) return false;
35 struct wlr_surface *under=surface_at(s,s->cursor->x,s->cursor->y,x,y);
36 if(under!=native->surface) return false;
37 owner->origin_x=s->cursor->x-*x; owner->origin_y=s->cursor->y-*y;
38 return true;
40static void constraints_end(struct server *s) {
41 struct constraint *owner=s->active_constraint;
42 if(!owner) return;
43 s->active_constraint=NULL;
44 EVENT(107,owner->id,0,s->generation);
45 wlr_pointer_constraint_v1_send_deactivated(owner->native);
47static void constraints_observe(struct server *s) {
48 if(!s->pointer_constraints || s->observing_constraints || s->stopping) return;
49 s->observing_constraints=true;
50 struct constraint *active=s->active_constraint;
51 double x=0,y=0;
52 if(active && (active->scope!=s->generation || !constraint_position(active,&x,&y) ||
53 !constraint_contains(active,x,y))) constraints_end(s);
54 uint64_t keyboard=window_for_surface(s,s->seat->keyboard_state.focused_surface);
55 struct constraint *owner;
56 wl_list_for_each(owner,&s->constraints,link) {
57 uint64_t window=window_for_surface(s,owner->native->surface);
58 bool over=constraint_position(owner,&x,&y);
59 struct view *view=find_view(s,window);
60 int64_t facts[8]={window,over,keyboard,over && constraint_contains(owner,x,y),
61 visible(view),(int64_t)(owner->origin_x*1000),(int64_t)(owner->origin_y*1000),s->generation};
62 if(!owner->sampled || memcmp(facts,owner->facts,sizeof(facts))) {
63 memcpy(owner->facts,facts,sizeof(facts)); owner->sampled=true;
64 EVENT(106,owner->id,facts[0],facts[1],facts[2],facts[3],facts[4],facts[5],facts[6],facts[7]);
65 }
66 }
67 s->observing_constraints=false;
69static void constrained_warp(struct server *s,double x,double y) {
70 constraints_observe(s);
71 struct constraint *owner=s->active_constraint;
72 if(!owner) { wlr_cursor_warp_closest(s->cursor,NULL,x,y); return; }
73 if(owner->native->type==WLR_POINTER_CONSTRAINT_V1_LOCKED) return;
74 double confined_x,confined_y;
75 if(wlr_region_confine(constraint_region(owner),s->cursor->x-owner->origin_x,
76 s->cursor->y-owner->origin_y,x-owner->origin_x,y-owner->origin_y,&confined_x,&confined_y))
77 wlr_cursor_warp(s->cursor,NULL,owner->origin_x+confined_x,owner->origin_y+confined_y);
79static void pointer_hint_remove(struct pointer_hint *hint) {
80 wl_list_remove(&hint->destroy.link); wl_list_remove(&hint->link);
81 hint->server->pointer_hint_count--;
82 atomic_fetch_sub(&bridge.objects,1);
83 free(hint);
85static void pointer_hint_destroyed(struct wl_listener *listener,void *data) {
86 (void)data;
87 struct pointer_hint *hint=wl_container_of(listener,hint,destroy);
88 EVENT(72,hint->token);
89 pointer_hint_remove(hint);
91static void pointer_hint_request(struct constraint *owner) {
92 struct server *s=owner->server;
93 struct wlr_pointer_constraint_v1 *native=owner->native;
94 double x,y;
95 if(s->pointer_hint_count>=64 || owner->scope!=s->generation ||
96 native->type!=WLR_POINTER_CONSTRAINT_V1_LOCKED || !native->current.cursor_hint.enabled ||
97 !constraint_position(owner,&x,&y)) return;
98 x=native->current.cursor_hint.x; y=native->current.cursor_hint.y;
99 if(x<0 || y<0 || !pixman_region32_contains_point(&native->surface->input_region,(int)x,(int)y,NULL)) return;
100 struct pointer_hint *hint=calloc(1,sizeof(*hint));
101 if(!hint) return;
102 hint->server=s; hint->surface=native->surface; hint->window=window_for_surface(s,native->surface);
103 hint->token=++s->next_token; hint->generation=s->generation; hint->deadline=now_ms()+bridge.request_deadline;
104 hint->x=owner->origin_x+x; hint->y=owner->origin_y+y;
105 listen(&native->surface->events.destroy,&hint->destroy,pointer_hint_destroyed);
106 wl_list_insert(&s->pointer_hints,&hint->link); s->pointer_hint_count++;
107 atomic_fetch_add(&bridge.objects,1);
108 EVENT(110,hint->token,hint->window,hint->generation,(int64_t)(hint->x*1000),(int64_t)(hint->y*1000));
110static bool pointer_hint_reply(struct server *s,uint64_t token,bool accept) {
111 struct pointer_hint *hint;
112 wl_list_for_each(hint,&s->pointer_hints,link) {
113 if(hint->token!=token) continue;
114 double sx,sy;
115 bool valid=accept && !s->lock_state && !s->active_constraint && hint->generation==s->generation &&
116 visible(find_view(s,hint->window)) &&
117 surface_at(s,s->cursor->x,s->cursor->y,&sx,&sy)==hint->surface;
118 double target_x=valid ? hint->x-(s->cursor->x-sx) : -1;
119 double target_y=valid ? hint->y-(s->cursor->y-sy) : -1;
120 valid=valid && target_x>=0 && target_y>=0 &&
121 pixman_region32_contains_point(&hint->surface->input_region,(int)target_x,(int)target_y,NULL);
122 bool applied=valid && wlr_cursor_warp(s->cursor,NULL,hint->x,hint->y);
123 pointer_hint_remove(hint);
124 if(applied) {
125 s->motion_x=s->cursor->x; s->motion_y=s->cursor->y;
126 route_motion(s,now_ms(),false);
127 }
128 EVENT(111,token,applied);
129 return true;
130 }
131 EVENT(111,token,0);
132 return true;
134static bool set_active_constraint(struct server *s,uint64_t id,uint64_t generation) {
135 if(!id) {
136 constraints_end(s);
137 EVENT(109,0,1);
138 return true;
139 }
140 struct constraint *owner;
141 wl_list_for_each(owner,&s->constraints,link) {
142 if(owner->id!=id) continue;
143 double x,y;
144 if(generation!=s->generation || !constraint_position(owner,&x,&y) ||
145 !constraint_contains(owner,x,y)) { EVENT(109,id,0); return true; }
146 if(s->active_constraint!=owner) {
147 constraints_end(s);
148 /* Releasing a one-shot lease can synchronously destroy its owner. */
149 owner->scope=s->generation;
150 s->active_constraint=owner;
151 wlr_pointer_constraint_v1_send_activated(owner->native);
152 EVENT(107,id,1,s->generation);
153 }
154 EVENT(109,id,1);
155 return true;
156 }
157 EVENT(109,id,0);
158 return true;
160static void constraint_destroyed(struct wl_listener *listener,void *data) {
161 (void)data;
162 struct constraint *owner=wl_container_of(listener,owner,destroy);
163 struct server *s=owner->server;
164 if(s->active_constraint==owner) {
165 s->active_constraint=NULL;
166 EVENT(107,owner->id,0,s->generation);
167 if(!s->stopping) pointer_hint_request(owner);
168 }
169 EVENT(108,owner->id);
170 wl_list_remove(&owner->destroy.link); wl_list_remove(&owner->region.link);
171 wl_list_remove(&owner->unmap.link); wl_list_remove(&owner->link);
172 s->constraint_count--;
173 atomic_fetch_sub(&bridge.objects,1);
174 free(owner);
175 constraints_observe(s);
177static void constraint_region_changed(struct wl_listener *listener,void *data) {
178 (void)data;
179 struct constraint *owner=wl_container_of(listener,owner,region);
180 constraints_observe(owner->server);
182static void constraint_unmapped(struct wl_listener *listener,void *data) {
183 (void)data;
184 struct constraint *owner=wl_container_of(listener,owner,unmap);
185 struct server *s=owner->server;
186 if(s->active_constraint==owner) constraints_end(s);
187 constraints_observe(s);
189static void new_constraint(struct wl_listener *listener,void *data) {
190 struct server *s=wl_container_of(listener,s,new_constraint);
191 struct wlr_pointer_constraint_v1 *native=data;
192 if(s->constraint_count>=128) { wl_resource_destroy(native->resource); return; }
193 struct constraint *owner=calloc(1,sizeof(*owner));
194 if(!owner) { wl_resource_destroy(native->resource); return; }
195 owner->server=s; owner->native=native; owner->id=++s->next_id;
196 wl_list_insert(&s->constraints,&owner->link); s->constraint_count++;
197 listen(&native->events.destroy,&owner->destroy,constraint_destroyed);
198 listen(&native->events.set_region,&owner->region,constraint_region_changed);
199 listen(&native->surface->events.unmap,&owner->unmap,constraint_unmapped);
200 atomic_fetch_add(&bridge.objects,1);
201 EVENT(105,owner->id,window_for_surface(s,native->surface),native->type,
202 native->lifetime==ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT,native->seat==s->seat);
203 constraints_observe(s);
205static void pointer_hints_expire(struct server *s) {
206 struct pointer_hint *hint,*next;
207 wl_list_for_each_safe(hint,next,&s->pointer_hints,link) {
208 if(now_ms()<hint->deadline && hint->generation==s->generation) continue;
209 EVENT(72,hint->token);
210 pointer_hint_remove(hint);
211 }
213static void constraint_pointer_focus(struct wl_listener *listener,void *data) {
214 (void)data;
215 struct server *s=wl_container_of(listener,s,constraint_pointer_focus);
216 constraints_observe(s);
218static void constraint_keyboard_focus(struct wl_listener *listener,void *data) {
219 (void)data;
220 struct server *s=wl_container_of(listener,s,constraint_keyboard_focus);
221 constraints_observe(s);
223static bool constraints_init(struct server *s) {
224 s->pointer_constraints=wlr_pointer_constraints_v1_create(s->display);
225 if(!s->pointer_constraints) return false;
226 listen(&s->pointer_constraints->events.new_constraint,&s->new_constraint,new_constraint);
227 listen(&s->seat->pointer_state.events.focus_change,&s->constraint_pointer_focus,constraint_pointer_focus);
228 listen(&s->seat->keyboard_state.events.focus_change,&s->constraint_keyboard_focus,constraint_keyboard_focus);
229 return true;
231static void constraints_finish(struct server *s) {
232 if(s->new_constraint.notify) {
233 wl_list_remove(&s->new_constraint.link);
234 wl_list_remove(&s->constraint_pointer_focus.link);
235 wl_list_remove(&s->constraint_keyboard_focus.link);
236 }
237 s->active_constraint=NULL;
238 struct constraint *owner,*next;
239 wl_list_for_each_safe(owner,next,&s->constraints,link) {
240 wl_list_remove(&owner->destroy.link); wl_list_remove(&owner->region.link);
241 wl_list_remove(&owner->unmap.link); wl_list_remove(&owner->link);
242 atomic_fetch_sub(&bridge.objects,1);
243 free(owner);
244 }
245 struct pointer_hint *hint,*next_hint;
246 wl_list_for_each_safe(hint,next_hint,&s->pointer_hints,link) pointer_hint_remove(hint);