xdgpop_defer_handler(struct surface_request * req,struct arcan_shmif_cont * con)1 static bool xdgpop_defer_handler(
2 	struct surface_request* req, struct arcan_shmif_cont* con)
3 {
4 	if (!con){
5 		trace(TRACE_SHELL, "reqfail");
6 		wl_resource_post_no_memory(req->target);
7 		return false;
8 	}
9 
10 /*
11  * PROTOCOL NOTE:
12  * positioner needs to be validated: non-zero size, non-zero anchor is needed,
13  * else send: ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER
14  *
15  * parent needs to be validated,
16  * else send ZXDG_SHELL_V6_ERROR_POPUP_PARENT
17  *
18  * + destroy- rules that are a bit clunky
19  */
20 	struct wl_resource* popup = wl_resource_create(req->client->client,
21 		&xdg_popup_interface, wl_resource_get_version(req->target), req->id);
22 
23 	if (!popup){
24 		wl_resource_post_no_memory(req->target);
25 		return false;
26 	}
27 
28 	struct comp_surf* surf = wl_resource_get_user_data(req->target);
29 	wl_resource_set_implementation(popup, &xdgpop_if, surf, NULL);
30 	surf->acon = *con;
31 	surf->cookie = 0xfeedface;
32 	surf->shell_res = popup;
33 	surf->dispatch = xdgpopup_shmifev_handler;
34 
35 	snprintf(surf->tracetag, SURF_TAGLEN, "xdg_popup");
36 	arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
37 		.ext.kind = ARCAN_EVENT(MESSAGE),
38 		.ext.message.data = {"shell:xdg_popup"}
39 	});
40 
41 /* update the viewport hint and send that event */
42 	bool upd_view = false;
43 	if (req->positioner){
44 		struct positioner* pos = wl_resource_get_user_data(req->positioner);
45 		apply_positioner(pos, &surf->viewport);
46 		upd_view = true;
47 	}
48 
49 	if (req->parent){
50 		struct comp_surf* psurf = wl_resource_get_user_data(req->parent);
51 		if (!psurf->acon.addr){
52 			trace(TRACE_ALLOC, "bad popup, broken parent");
53 			return false;
54 		}
55 		surf->viewport.ext.viewport.parent = psurf->acon.segment_token;
56 		upd_view = true;
57 	}
58 
59 /* likely that if this is not true, we have a protocol error */
60 	if (upd_view){
61 		arcan_shmif_enqueue(&surf->acon, &surf->viewport);
62 		xdg_popup_send_configure(popup,
63 			surf->viewport.ext.viewport.x, surf->viewport.ext.viewport.y,
64 			surf->viewport.ext.viewport.w, surf->viewport.ext.viewport.h);
65 		xdg_surface_send_configure(surf->surf_res, STEP_SERIAL());
66 	}
67 
68 	surf->internal = xdgpop_internal;
69 	return true;
70 }
71 
xdgtop_defer_handler(struct surface_request * req,struct arcan_shmif_cont * con)72 static bool xdgtop_defer_handler(
73 	struct surface_request* req, struct arcan_shmif_cont* con)
74 {
75 	if (!con){
76 		trace(TRACE_SHELL, "xdgsurf:reqfail");
77 		wl_resource_post_no_memory(req->target);
78 		return false;
79 	}
80 
81 	struct wl_resource* toplevel = wl_resource_create(req->client->client,
82 		&xdg_toplevel_interface, wl_resource_get_version(req->target), req->id);
83 
84 	if (!toplevel){
85 		wl_resource_post_no_memory(req->target);
86 		return false;
87 	}
88 
89 	struct comp_surf* surf = wl_resource_get_user_data(req->target);
90 	wl_resource_set_implementation(toplevel, &xdgtop_if, surf, NULL);
91 	surf->acon = *con;
92 	surf->cookie = 0xfeedface;
93 	surf->shell_res = toplevel;
94 	surf->dispatch = xdgtoplevel_shmifev_handler;
95 	snprintf(surf->tracetag, SURF_TAGLEN, "xdg_toplevel");
96 
97 /* propagate this so the scripts have a chance of following the restrictions
98  * indicated by the protocol */
99 	arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
100 		.ext.kind = ARCAN_EVENT(MESSAGE),
101 		.ext.message.data = {"shell:xdg_top"}
102 	});
103 
104 	struct wl_array states;
105 	wl_array_init(&states);
106 
107 	size_t w = surf->acon.w;
108 	size_t h = surf->acon.h;
109 	if (wl.force_sz){
110 		w = wl.init.display_width_px * (1.0 / surf->scale);
111 		h = wl.init.display_height_px * (1.0 / surf->scale);
112 	}
113 
114 	xdg_toplevel_send_configure(toplevel, w, h, &states);
115 	xdg_surface_send_configure(surf->surf_res, STEP_SERIAL());
116 	surf->internal = xdgtop_internal;
117 	wl_array_release(&states);
118 	return true;
119 }
120 
xdgsurf_toplevel(struct wl_client * cl,struct wl_resource * res,uint32_t id)121 static void xdgsurf_toplevel(
122 	struct wl_client* cl, struct wl_resource* res, uint32_t id)
123 {
124 	trace(TRACE_SHELL, "%"PRIu32, id);
125 	struct comp_surf* surf = wl_resource_get_user_data(res);
126 
127 /* though it is marked as 'defered' here, chances are that the request
128  * function will just return with the surface immediately */
129 	request_surface(surf->client, &(struct surface_request){
130 		.segid = SEGID_APPLICATION,
131 		.target = res,
132 		.id = id,
133 		.trace = "xdg toplevel",
134 		.dispatch = xdgtop_defer_handler,
135 		.client = surf->client,
136 		.source = surf
137 	}, 't');
138 }
139 
xdgsurf_getpopup(struct wl_client * cl,struct wl_resource * res,uint32_t id,struct wl_resource * parent,struct wl_resource * positioner)140 static void xdgsurf_getpopup(struct wl_client* cl, struct wl_resource* res,
141 	uint32_t id, struct wl_resource* parent, struct wl_resource* positioner)
142 {
143 	trace(TRACE_SHELL, "xdgsurf_getpopup");
144 	struct comp_surf* surf = wl_resource_get_user_data(res);
145 	request_surface(surf->client, &(struct surface_request ){
146 		.segid = SEGID_POPUP,
147 		.target = res,
148 		.id = id,
149 		.trace = "xdg popup",
150 		.dispatch = xdgpop_defer_handler,
151 		.client = surf->client,
152 		.source = surf,
153 		.parent = parent,
154 		.positioner = positioner
155 	}, 'p');
156 }
157 
158 /* Hints about the window visible size sans dropshadows and things like that,
159  * but since it doesn't carry information about decorations (titlebar, ...)
160  * we can't actually use this for a full viewport hint. Still better than
161  * nothing and since we WM script need to take 'special ed' considerations
162  * for xdg- clients anyhow, go with that. */
xdgsurf_set_geometry(struct wl_client * cl,struct wl_resource * res,int32_t x,int32_t y,int32_t width,int32_t height)163 static void xdgsurf_set_geometry(struct wl_client* cl,
164 	struct wl_resource* res, int32_t x, int32_t y, int32_t width, int32_t height)
165 {
166 	struct comp_surf* surf = wl_resource_get_user_data(res);
167 	if (!surf)
168 		return;
169 
170 	trace(TRACE_SHELL, "xdgsurf_setgeom("
171 		"%"PRIu32"+%"PRIu32", %"PRIu32"+%"PRIu32")", x, y, width, height);
172 
173 /* the better way is to use the tldr[] from the VIEWPORT hint,
174  * we just need a 'dirty- viewport' and a cache of the properties first */
175 	struct arcan_event ev = {
176 		.ext.kind = ARCAN_EVENT(MESSAGE)
177 	};
178 	snprintf((char*)ev.ext.message.data,
179 		COUNT_OF(ev.ext.message.data),
180 		"geom:%"PRIu32":%"PRIu32":%"PRIu32":%"PRIu32,	x, y, width, height
181 	);
182 
183 	surf->geom_x = x;
184 	surf->geom_y = y;
185 	surf->geom_w = width;
186 	surf->geom_h = height;
187 	arcan_shmif_enqueue(&surf->acon, &ev);
188 }
189 
xdgsurf_ackcfg(struct wl_client * cl,struct wl_resource * res,uint32_t serial)190 static void xdgsurf_ackcfg(
191 	struct wl_client* cl, struct wl_resource* res, uint32_t serial)
192 {
193 	trace(TRACE_SHELL, "%"PRIu32, serial);
194 /* reading the spec for this makes it seem like there can be many
195  * 'in flight' cfgs and you need to send ack individually and thus
196  * track pending cfgs that lacks an acq */
197 }
198 
xdgsurf_destroy(struct wl_client * cl,struct wl_resource * res)199 static void xdgsurf_destroy(
200 	struct wl_client* cl, struct wl_resource* res)
201 {
202 	trace(TRACE_ALLOC, "%"PRIxPTR, res);
203 	struct comp_surf* surf = wl_resource_get_user_data(res);
204 	if (surf){
205 		surf->shell_res = NULL;
206 		surf->internal = NULL;
207 	}
208 	wl_resource_destroy(res);
209 }
210