AtlatestRepositorysigil-wm

sigil-wm / tree / src / cdesktop.h

1/* SPDX-License-Identifier: BSD-3-Clause
2 * Bounded request transport; acceptance and icon/cursor delegation are explicit. */
3struct data_request {
4 struct wl_list link;
5 struct server *server;
6 uint64_t token,deadline,generation;
7 int kind;
8 void *source;
9 struct wlr_surface *origin;
10 uint32_t serial;
11 struct wl_listener destroy,origin_destroy;
12};
13struct active_drag {
14 struct server *server;
15 uint64_t id;
16 struct wlr_scene_tree *icon;
17 struct wl_listener destroy,drop,icon_destroy;
18};
19static void data_remove(struct data_request *request) {
20 if(request->destroy.notify) wl_list_remove(&request->destroy.link);
21 if(request->origin_destroy.notify) wl_list_remove(&request->origin_destroy.link);
22 wl_list_remove(&request->link);
23 request->server->data_request_count--;
24 atomic_fetch_sub(&bridge.objects,1);
25 free(request);
27static void data_destroyed(struct wl_listener *listener,void *data) {
28 (void)data;
29 struct data_request *request=wl_container_of(listener,request,destroy);
30 EVENT(72,request->token);
31 data_remove(request);
33static void data_origin_destroyed(struct wl_listener *listener,void *data) {
34 (void)data;
35 struct data_request *request=wl_container_of(listener,request,origin_destroy);
36 EVENT(72,request->token);
37 data_remove(request);
39static uint64_t window_for_surface(struct server *s,struct wlr_surface *surface) {
40 if(!surface) return 0;
41 struct view *view;
42 struct wlr_surface *root=wlr_surface_get_root_surface(surface);
43 for(int depth=0;root && depth<64;depth++) {
44 wl_list_for_each(view,&s->views,link) if(view_surface(view)==root) return view->id;
45 struct wlr_xdg_surface *xdg=wlr_xdg_surface_try_from_wlr_surface(root);
46 if(!xdg || xdg->role!=WLR_XDG_SURFACE_ROLE_POPUP || !xdg->popup->parent) break;
47 root=wlr_surface_get_root_surface(xdg->popup->parent);
48 }
49 return 0;
51static struct data_request *data_request_new(struct server *s,int kind,void *source,uint32_t serial) {
52 if(s->data_request_count>=256) return NULL;
53 struct data_request *request=calloc(1,sizeof(*request));
54 if(!request) return NULL;
55 request->server=s; request->kind=kind; request->source=source; request->serial=serial;
56 request->token=++s->next_token; request->deadline=now_ms()+bridge.request_deadline;
57 request->generation=s->generation;
58 wl_list_insert(&s->data_requests,&request->link);
59 s->data_request_count++;
60 atomic_fetch_add(&bridge.objects,1);
61 if(source) {
62 struct wl_signal *signal=kind==0 ? &((struct wlr_data_source *)source)->events.destroy :
63 kind==1 ? &((struct wlr_primary_selection_source *)source)->events.destroy :
64 &((struct wlr_drag *)source)->events.destroy;
65 listen(signal,&request->destroy,data_destroyed);
66 }
67 return request;
69static void selection_request(struct wl_listener *listener,void *data) {
70 struct server *s=wl_container_of(listener,s,selection_request);
71 struct wlr_seat_request_set_selection_event *event=data;
72 struct data_request *request=data_request_new(s,0,event->source,event->serial);
73 if(request) EVENT(84,request->token,0,event->serial,s->focus,event->source!=NULL,s->generation);
75static void primary_request(struct wl_listener *listener,void *data) {
76 struct server *s=wl_container_of(listener,s,primary_request);
77 struct wlr_seat_request_set_primary_selection_event *event=data;
78 struct data_request *request=data_request_new(s,1,event->source,event->serial);
79 if(request) EVENT(84,request->token,1,event->serial,s->focus,event->source!=NULL,s->generation);
81static void drag_request(struct wl_listener *listener,void *data) {
82 struct server *s=wl_container_of(listener,s,drag_request);
83 struct wlr_seat_request_start_drag_event *event=data;
84 struct data_request *request=data_request_new(s,2,event->drag,event->serial);
85 if(!request) { if(event->drag->source) wlr_data_source_destroy(event->drag->source); return; }
86 request->origin=event->origin;
87 listen(&event->origin->events.destroy,&request->origin_destroy,data_origin_destroyed);
88 EVENT(85,request->token,window_for_surface(s,event->origin),event->serial,
89 wlr_seat_validate_pointer_grab_serial(s->seat,event->origin,event->serial),
90 event->drag->source!=NULL,s->generation);
92static void drag_icon_destroyed(struct wl_listener *listener,void *data) {
93 (void)data;
94 struct active_drag *drag=wl_container_of(listener,drag,icon_destroy);
95 wl_list_remove(&drag->icon_destroy.link); drag->icon=NULL;
97static void drag_dropped(struct wl_listener *listener,void *data) {
98 (void)data;
99 struct active_drag *drag=wl_container_of(listener,drag,drop);
100 EVENT(88,drag->id);
102static void drag_ended(struct wl_listener *listener,void *data) {
103 (void)data;
104 struct active_drag *drag=wl_container_of(listener,drag,destroy);
105 struct server *s=drag->server;
106 wl_list_remove(&drag->destroy.link); wl_list_remove(&drag->drop.link);
107 if(drag->icon) wlr_scene_node_destroy(&drag->icon->node);
108 s->drag=NULL;
109 EVENT(89,drag->id);
110 atomic_fetch_sub(&bridge.objects,1);
111 free(drag);
112 if(!s->stopping) route_motion(s,0,false);
114static bool drag_accepts_input(struct wlr_scene_buffer *buffer,double *x,double *y) {
115 (void)buffer; (void)x; (void)y;
116 return false;
118static void drag_ignore_input(struct wlr_scene_buffer *buffer,int x,int y,void *data) {
119 (void)x; (void)y; (void)data;
120 buffer->point_accepts_input=drag_accepts_input;
122static void update_drag_icon(struct server *s) {
123 if(s->drag && s->drag->icon)
124 wlr_scene_node_for_each_buffer(&s->drag->icon->node,drag_ignore_input,NULL);
125 if(s->drag && s->drag->icon)
126 wlr_scene_node_set_position(&s->drag->icon->node,s->cursor->x,s->cursor->y);
128static void drag_started(struct wl_listener *listener,void *data) {
129 struct server *s=wl_container_of(listener,s,drag_started);
130 struct wlr_drag *native=data;
131 struct active_drag *drag=calloc(1,sizeof(*drag));
132 if(!drag) return;
133 drag->server=s; drag->id=++s->next_id; s->drag=drag;
134 atomic_fetch_add(&bridge.objects,1);
135 listen(&native->events.destroy,&drag->destroy,drag_ended);
136 listen(&native->events.drop,&drag->drop,drag_dropped);
137 if(s->follow_drag_icon && native->icon) {
138 wlr_scene_node_raise_to_top(&s->drag_scene->node);
139 drag->icon=wlr_scene_drag_icon_create(s->drag_scene,native->icon);
140 if(drag->icon) listen(&drag->icon->node.events.destroy,&drag->icon_destroy,drag_icon_destroyed);
141 update_drag_icon(s);
142 }
143 EVENT(87,drag->id,drag->icon!=NULL);
145static bool data_reply(struct server *s,uint64_t token,bool accept,bool follow_icon) {
146 struct data_request *request;
147 wl_list_for_each(request,&s->data_requests,link) {
148 if(request->token!=token) continue;
149 int kind=request->kind;
150 void *source=request->source;
151 uint32_t serial=request->serial;
152 bool valid=request->generation==s->generation && !s->lock_state;
153 if(kind==2) valid=valid && wlr_seat_validate_pointer_grab_serial(s->seat,request->origin,serial);
154 data_remove(request);
155 bool allowed=accept && valid;
156 if(kind==0 && allowed) wlr_seat_set_selection(s->seat,source,serial);
157 else if(kind==1 && allowed) wlr_seat_set_primary_selection(s->seat,source,serial);
158 else if(kind==2) {
159 struct wlr_drag *drag=source;
160 if(allowed) { s->follow_drag_icon=follow_icon; wlr_seat_start_pointer_drag(s->seat,drag,serial); }
161 else if(drag->source) wlr_data_source_destroy(drag->source);
162 }
163 EVENT(86,token,kind,allowed);
164 return true;
165 }
166 return false;
168static void data_expire(struct server *s) {
169 for(;;) {
170 struct data_request *request;
171 uint64_t token=0;
172 wl_list_for_each(request,&s->data_requests,link)
173 if(now_ms()>=request->deadline) { token=request->token; break; }
174 if(!token) break;
175 data_reply(s,token,false,false);
176 }
178static void cursor_shape_request(struct wl_listener *listener,void *data) {
179 struct server *s=wl_container_of(listener,s,cursor_shape);
180 struct wlr_cursor_shape_manager_v1_request_set_shape_event *event=data;
181 if(s->allow_client_cursor && s->cursor_manager &&
182 event->device_type==WLR_CURSOR_SHAPE_MANAGER_V1_DEVICE_TYPE_POINTER &&
183 event->seat_client==s->seat->pointer_state.focused_client)
184 wlr_cursor_set_xcursor(s->cursor,s->cursor_manager,wlr_cursor_shape_v1_name(event->shape));
186static bool desktop_init(struct server *s) {
187 if(!wlr_single_pixel_buffer_manager_v1_create(s->display) ||
188 !wlr_data_control_manager_v1_create(s->display) ||
189 !wlr_primary_selection_v1_device_manager_create(s->display) ||
190 !wlr_xdg_output_manager_v1_create(s->display,s->layout) ||
191 !wlr_screencopy_manager_v1_create(s->display) ||
192 !wlr_ext_image_copy_capture_manager_v1_create(s->display,1) ||
193 !wlr_ext_output_image_capture_source_manager_v1_create(s->display,1)) return false;
194 struct wlr_cursor_shape_manager_v1 *shapes=wlr_cursor_shape_manager_v1_create(s->display,1);
195 if(!shapes) return false;
196 listen(&shapes->events.request_set_shape,&s->cursor_shape,cursor_shape_request);
197 listen(&s->seat->events.request_set_selection,&s->selection_request,selection_request);
198 listen(&s->seat->events.request_set_primary_selection,&s->primary_request,primary_request);
199 listen(&s->seat->events.request_start_drag,&s->drag_request,drag_request);
200 listen(&s->seat->events.start_drag,&s->drag_started,drag_started);
201 return true;
203static void desktop_finish(struct server *s) {
204 struct wl_listener *listeners[]={&s->cursor_shape,&s->selection_request,&s->primary_request,&s->drag_request,&s->drag_started};
205 for(unsigned i=0;i<sizeof(listeners)/sizeof(listeners[0]);i++)
206 if(listeners[i]->notify) wl_list_remove(&listeners[i]->link);
207 struct data_request *request,*next;
208 wl_list_for_each_safe(request,next,&s->data_requests,link) data_remove(request);