AtlatestRepositorysigil-wm
1
/* SPDX-License-Identifier: BSD-3-Clause2
* Bounded request transport; acceptance and icon/cursor delegation are explicit. */3
struct 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
};13
struct 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
};19
static 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);26
}27
static 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);32
}33
static 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);38
}39
static 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;50
}51
static 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;68
}69
static 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);74
}75
static 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);80
}81
static 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);91
}92
static 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;96
}97
static 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);101
}102
static 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);113
}114
static bool drag_accepts_input(struct wlr_scene_buffer *buffer,double *x,double *y) {115
(void)buffer; (void)x; (void)y;116
return false;117
}118
static 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;121
}122
static 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);127
}128
static 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);144
}145
static 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;167
}168
static 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
}177
}178
static 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));185
}186
static 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;202
}203
static 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);209
}