xdgtoplevel_shmifev_handler(struct comp_surf * surf,struct arcan_event * ev)1 static bool xdgtoplevel_shmifev_handler(
2 	struct comp_surf* surf, struct arcan_event* ev)
3 {
4 	if (!surf->shell_res)
5 		return true;
6 
7 	if (ev->category == EVENT_TARGET)
8 		switch (ev->tgt.kind){
9 
10 		case TARGET_COMMAND_DISPLAYHINT:{
11 		/* update state tracking first */
12 			trace(TRACE_SHELL, "xdg-toplevel(%"PRIxPTR"):hint=%d,%d,%d,%d:size=%d,%d",
13 				(uintptr_t) surf,
14 				ev->tgt.ioevs[0].iv, ev->tgt.ioevs[1].iv,
15 				ev->tgt.ioevs[2].iv, ev->tgt.ioevs[3].iv, surf->acon.w, surf->acon.h);
16 
17 			bool changed = displayhint_handler(surf, &ev->tgt);
18 
19 /* and then, if something has changed, send the configure event */
20 			int w = ev->tgt.ioevs[0].iv;
21 			int h = ev->tgt.ioevs[1].iv;
22 			if (!w)
23 				w = surf->acon.w;
24 			if (!h)
25 				h = surf->acon.h;
26 
27 			bool resized = (w && h && (w != surf->acon.w || h != surf->acon.h));
28 			if (!resized){
29 				if (surf->geom_w)
30 					w = surf->geom_w;
31 				if (surf->geom_h)
32 					h = surf->geom_h;
33 			}
34 
35 			if (changed || resized){
36 				struct wl_array states;
37 
38 				if (resized){
39 					trace(TRACE_SHELL,
40 						"resizereq:last=%d,%d:req:=%d,%d",
41 						(int) surf->acon.w, (int) surf->acon.h, w, h);
42 				}
43 
44 				wl_array_init(&states);
45 				uint32_t* sv;
46 				if (surf->states.maximized){
47 					sv = wl_array_add(&states, sizeof(uint32_t));
48 					*sv = XDG_TOPLEVEL_STATE_MAXIMIZED;
49 					trace(TRACE_SHELL, "maximized");
50 				}
51 
52 				if (surf->states.fullscreen){
53 					sv = wl_array_add(&states, sizeof(uint32_t));
54 					*sv = XDG_TOPLEVEL_STATE_FULLSCREEN;
55 					trace(TRACE_SHELL, "fullscreen");
56 				}
57 
58 				if (surf->states.drag_resize){
59 					sv = wl_array_add(&states, sizeof(uint32_t));
60 					*sv = XDG_TOPLEVEL_STATE_RESIZING;
61 					trace(TRACE_SHELL, "resizing");
62 				}
63 
64 				if (!surf->states.unfocused){
65 					sv = wl_array_add(&states, sizeof(uint32_t));
66 					*sv = XDG_TOPLEVEL_STATE_ACTIVATED;
67 					trace(TRACE_SHELL, "focused");
68 				}
69 				else {
70 					release_all_keys(surf->client);
71 				}
72 
73 				if (wl.force_sz){
74 					w = wl.init.display_width_px;
75 					h = wl.init.display_height_px;
76 				}
77 
78 				w *= (1.0 / surf->scale);
79 				h *= (1.0 / surf->scale);
80 
81 				xdg_toplevel_send_configure(surf->shell_res, w, h, &states);
82 				xdg_surface_send_configure(surf->surf_res, STEP_SERIAL());
83 
84 	/* from zxdg_toplevel_decoration_v1_configure */
85 				if (surf->pending_decoration && surf->decor_mgmt){
86 					trace(TRACE_SHELL, "decor=%d", surf->pending_decoration);
87 					zxdg_toplevel_decoration_v1_send_configure(
88 						surf->decor_mgmt, surf->pending_decoration);
89 					surf->pending_decoration = 0;
90 				}
91 
92 				wl_array_release(&states);
93 				changed = true;
94 			}
95 
96 			if (changed)
97 				try_frame_callback(surf);
98 		}
99 		return true;
100 		break;
101 
102 /* Previously we flushed callbacks and released buffers here, but afaict
103  * the proper procedure is to let the client do the closing as a response to
104  * send_close. After this all arcan- related calls will fail on the surface, so
105  * chances are that a window could go with something like 'do you really want
106  * to close' and we can't actually draw that anywhere, this is not really
107  * solvable, can only warn the appl- side about the perils of force closing a
108  * wayland surface - unless there is some error we can send to fake it */
109 		case TARGET_COMMAND_EXIT:
110 			xdg_toplevel_send_close(surf->shell_res);
111 			return true;
112 		break;
113 		default:
114 		break;
115 		}
116 
117 	return false;
118 }
119 
xdgtop_setparent(struct wl_client * cl,struct wl_resource * res,struct wl_resource * parent)120 static void xdgtop_setparent(
121 	struct wl_client* cl, struct wl_resource* res, struct wl_resource* parent)
122 {
123 	trace(TRACE_SHELL, "parent: %"PRIxPTR, (uintptr_t) parent);
124 	struct comp_surf* surf = wl_resource_get_user_data(res);
125 	uint32_t par_token = 0;
126 	int8_t order = 0;
127 
128 	if (parent){
129 		struct comp_surf* par = wl_resource_get_user_data(parent);
130 		par_token = par->acon.segment_token;
131 		order = par->viewport.ext.viewport.order + 1;
132 	}
133 	surf->viewport.ext.viewport.order = order;
134 	surf->viewport.ext.viewport.parent = par_token;
135 
136 /* Likely that we need more order tracking for subsurfaces, or shift
137  * the relative assignment to the scripting layer again */
138 	arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
139 		.ext.kind = ARCAN_EVENT(VIEWPORT),
140 		.ext.viewport.parent = par_token,
141 		.ext.viewport.order = order
142 	});
143 }
144 
xdgtop_title(struct wl_client * cl,struct wl_resource * res,const char * title)145 static void xdgtop_title(
146 	struct wl_client* cl, struct wl_resource* res, const char* title)
147 {
148 	trace(TRACE_SHELL, "%s", title ? title : "(null)");
149 	struct comp_surf* surf = wl_resource_get_user_data(res);
150 
151 	arcan_event ev = {
152 		.ext.kind = ARCAN_EVENT(IDENT)
153 	};
154 	size_t lim = sizeof(ev.ext.message.data)/sizeof(ev.ext.message.data[1]);
155 	snprintf((char*)ev.ext.message.data, lim, "%s", title);
156 	arcan_shmif_enqueue(&surf->acon, &ev);
157 }
158 
xdgtop_appid(struct wl_client * cl,struct wl_resource * res,const char * app_id)159 static void xdgtop_appid(
160 	struct wl_client* cl, struct wl_resource* res, const char* app_id)
161 {
162 	trace(TRACE_SHELL, "xdgtop_app_id");
163 	/* I wondered how long it would take for D-Bus to rear its ugly
164 	 * face along with the .desktop clusterfuck. I wonder no more.
165 	 * we can wrap this around some _message call and leave it to
166 	 * the appl to determine if the crap should be bridged or not. */
167 }
168 
xdgtop_wndmenu(struct wl_client * cl,struct wl_resource * res,struct wl_resource * seat,uint32_t serial,int32_t x,int32_t y)169 static void xdgtop_wndmenu(struct wl_client* cl, struct wl_resource* res,
170 	struct wl_resource* seat, uint32_t serial, int32_t x, int32_t y)
171 {
172 	trace(TRACE_SHELL, "@x,y: %"PRId32", %"PRId32"", x, y);
173 }
174 
175 /*
176  * "The server may ignore move requests depending on the state of
177  * the surface (e.g. fullscreen or maximized), or if the passed
178  * serial is no longer valid."
179  *
180  *  i.e. the state can be such that it never needs to drag-move..
181  *
182  * "If triggered, the surface will lose the focus of the device
183  * (wl_pointer, wl_touch, etc) used for the move. It is up to the
184  * compositor to visually indicate that the move is taking place,
185  * such as updating a pointer cursor, during the move. There is no
186  * guarantee that the device focus will return when the move is
187  * completed."
188  *
189  * so this implies that the compositor actually needs to have
190  * state cursors.
191  *  => _CURSORHINT
192  */
xdgtop_move(struct wl_client * cl,struct wl_resource * res,struct wl_resource * seat,uint32_t serial)193 static void xdgtop_move(struct wl_client* cl,
194 	struct wl_resource* res, struct wl_resource* seat, uint32_t serial)
195 {
196 	trace(TRACE_SHELL, "%"PRIxPTR", serial: %"PRIu32, (uintptr_t) seat, serial);
197 	struct comp_surf* surf = wl_resource_get_user_data(res);
198 	arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
199 		.ext.kind = ARCAN_EVENT(MESSAGE),
200 		.ext.message.data = {"shell:xdg_top:move"}
201 	});
202 }
203 
xdg_edge_to_mask(uint32_t edges,int * dx,int * dy)204 static void xdg_edge_to_mask(uint32_t edges, int* dx, int* dy)
205 {
206 	switch (edges){
207 	case XDG_TOPLEVEL_RESIZE_EDGE_TOP:
208 		*dx = 0; *dy = -1;
209 	break;
210 	case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM:
211 		*dx = 0; *dy = 1;
212 	break;
213 	case XDG_TOPLEVEL_RESIZE_EDGE_LEFT:
214 		*dx = -1; *dy = 0;
215 	break;
216 	case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT:
217 		*dx = -1; *dy = -1;
218 	break;
219 	case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT:
220 		*dx = -1; *dy = 1;
221 	break;
222 	case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT:
223 		*dx = 1; *dy = 0;
224 	break;
225 	case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT:
226 		*dx = 1; *dy = -1;
227 	break;
228 	case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT:
229 		*dx = 1; *dy = 1;
230 	break;
231 	default:
232 		*dx = *dy = 0;
233 	}
234 }
235 
xdgtop_resize(struct wl_client * cl,struct wl_resource * res,struct wl_resource * seat,uint32_t serial,uint32_t edges)236 static void xdgtop_resize(struct wl_client* cl, struct wl_resource* res,
237 	struct wl_resource* seat, uint32_t serial, uint32_t edges)
238 {
239 	trace(TRACE_SHELL, "serial: %"PRIu32", edges: %"PRIu32, serial, edges);
240 	struct comp_surf* surf = wl_resource_get_user_data(res);
241 	struct arcan_event ev = {
242 		.ext.kind = ARCAN_EVENT(MESSAGE)
243 	};
244 
245 	int dx, dy;
246 	xdg_edge_to_mask(edges, &dx, &dy);
247 	size_t lim = sizeof(ev.ext.message.data)/sizeof(ev.ext.message.data[1]);
248 	snprintf((char*)ev.ext.message.data, lim, "shell:xdg_top:resize:%d:%d", dx, dy);
249 	arcan_shmif_enqueue(&surf->acon, &ev);
250 }
251 
252 /*
253  * => We need to track this in the client structure so that the
254  * reconfigure done in reaction to DISPLAYHINT constrain this.
255  *
256  * All these comes for the reason that the titlebar lives in the
257  * client as part of the toplevel surface.
258  */
xdgtop_set_max(struct wl_client * cl,struct wl_resource * res,int32_t width,int32_t height)259 static void xdgtop_set_max(struct wl_client* cl,
260 	struct wl_resource* res, int32_t width, int32_t height)
261 {
262 	trace(TRACE_SHELL, "xdgtop_set_max (%"PRId32", %"PRId32")");
263 	struct comp_surf* surf = wl_resource_get_user_data(res);
264 	surf->max_w = width * (1.0 / surf->scale);
265 	surf->max_h = height * (1.0 / surf->scale);
266 }
267 
268 /*
269  * Same as with _max
270  */
xdgtop_set_min(struct wl_client * cl,struct wl_resource * res,int32_t width,int32_t height)271 static void xdgtop_set_min(struct wl_client* cl,
272 	struct wl_resource* res, int32_t width, int32_t height)
273 {
274 	trace(TRACE_SHELL, "xdgtop_set_min (%"PRId32", %"PRId32")", width, height);
275 	struct comp_surf* surf = wl_resource_get_user_data(res);
276 	surf->min_w = width * (1.0 / surf->scale);
277 	surf->min_h = height * (1.0 / surf->scale);
278 }
279 
280 /*
281  * Hmm, this actually has implications for the presence of shadow
282  */
xdgtop_maximize(struct wl_client * cl,struct wl_resource * res)283 static void xdgtop_maximize(
284 	struct wl_client* cl, struct wl_resource* res)
285 {
286 	trace(TRACE_SHELL, "xdgtop_maximize");
287 	struct comp_surf* surf = wl_resource_get_user_data(res);
288 	arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
289 		.ext.kind = ARCAN_EVENT(MESSAGE),
290 		.ext.message.data = {"shell:xdg_top:maximize"}
291 	});
292 }
293 
xdgtop_demaximize(struct wl_client * cl,struct wl_resource * res)294 static void xdgtop_demaximize(
295 	struct wl_client* cl, struct wl_resource* res)
296 {
297 	trace(TRACE_SHELL, "xdgtop_demaximize");
298 	struct comp_surf* surf = wl_resource_get_user_data(res);
299 	arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
300 		.ext.kind = ARCAN_EVENT(MESSAGE),
301 		.ext.message.data = {"shell:xdg_top:demaximize"}
302 	});
303 }
304 
xdgtop_fullscreen(struct wl_client * cl,struct wl_resource * res,struct wl_resource * output)305 static void xdgtop_fullscreen(
306 	struct wl_client* cl, struct wl_resource* res, struct wl_resource* output)
307 {
308 	trace(TRACE_SHELL, "xdgtop_fullscreen");
309 	struct comp_surf* surf = wl_resource_get_user_data(res);
310 	arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
311 		.ext.kind = ARCAN_EVENT(MESSAGE),
312 		.ext.message.data = {"shell:xdg_top:fullscreen"}
313 	});
314 }
315 
xdgtop_unset_fullscreen(struct wl_client * cl,struct wl_resource * res)316 static void xdgtop_unset_fullscreen(
317 	struct wl_client* cl, struct wl_resource* res)
318 {
319 	trace(TRACE_SHELL, "xdgtop_unset_fullscreen");
320 	struct comp_surf* surf = wl_resource_get_user_data(res);
321 	arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
322 		.ext.kind = ARCAN_EVENT(MESSAGE),
323 		.ext.message.data = {"shell:xdg_top:defullscreen"}
324 	});
325 }
326 
xdgtop_minimize(struct wl_client * cl,struct wl_resource * res)327 static void xdgtop_minimize(
328 	struct wl_client* cl, struct wl_resource* res)
329 {
330 	trace(TRACE_SHELL, "xdgtop_minimize");
331 	struct comp_surf* surf = wl_resource_get_user_data(res);
332 	arcan_shmif_enqueue(&surf->acon, &(struct arcan_event){
333 		.ext.kind = ARCAN_EVENT(MESSAGE),
334 		.ext.message.data = {"shell:xdg_top:minimize"}
335 	});
336 }
337 
xdgtop_destroy(struct wl_client * cl,struct wl_resource * res)338 static void xdgtop_destroy(
339 	struct wl_client* cl, struct wl_resource* res)
340 {
341 	trace(TRACE_ALLOC, "%"PRIxPTR, (uintptr_t)res);
342 	struct comp_surf* surf = wl_resource_get_user_data(res);
343 
344 /* so we don't send a _leave to a dangling surface */
345 	if (surf && surf->client){
346 		if (surf->client->last_cursor == res)
347 			surf->client->last_cursor = NULL;
348 	}
349 }
350 
xdgtop_internal(struct comp_surf * surf,int cmd)351 static void xdgtop_internal(struct comp_surf* surf, int cmd)
352 {
353 	try_frame_callback(surf);
354 }
355