• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2010-2012 Intel Corporation
3  * Copyright © 2011-2012 Collabora, Ltd.
4  * Copyright © 2013 Raspberry Pi Foundation
5  * Copyright © 2016 Quentin "Sardem FF7" Glidic
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  */
26 
27 #include "config.h"
28 
29 #include <stdbool.h>
30 #include <assert.h>
31 
32 #include <wayland-server.h>
33 
34 #include <libweston/libweston.h>
35 #include <libweston/zalloc.h>
36 #include "xdg-shell-unstable-v6-server-protocol.h"
37 
38 #include <libweston-desktop/libweston-desktop.h>
39 #include "internal.h"
40 
41 #define WD_XDG_SHELL_PROTOCOL_VERSION 1
42 
43 static const char *weston_desktop_xdg_toplevel_role = "xdg_toplevel";
44 static const char *weston_desktop_xdg_popup_role = "xdg_popup";
45 
46 struct weston_desktop_xdg_positioner {
47 	struct weston_desktop *desktop;
48 	struct weston_desktop_client *client;
49 	struct wl_resource *resource;
50 
51 	struct weston_size size;
52 	struct weston_geometry anchor_rect;
53 	enum zxdg_positioner_v6_anchor anchor;
54 	enum zxdg_positioner_v6_gravity gravity;
55 	enum zxdg_positioner_v6_constraint_adjustment constraint_adjustment;
56 	struct weston_position offset;
57 };
58 
59 enum weston_desktop_xdg_surface_role {
60 	WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE,
61 	WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL,
62 	WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP,
63 };
64 
65 struct weston_desktop_xdg_surface {
66 	struct wl_resource *resource;
67 	struct weston_desktop *desktop;
68 	struct weston_surface *surface;
69 	struct weston_desktop_surface *desktop_surface;
70 	bool configured;
71 	struct wl_event_source *configure_idle;
72 	struct wl_list configure_list; /* weston_desktop_xdg_surface_configure::link */
73 
74 	bool has_next_geometry;
75 	struct weston_geometry next_geometry;
76 
77 	enum weston_desktop_xdg_surface_role role;
78 };
79 
80 struct weston_desktop_xdg_surface_configure {
81 	struct wl_list link; /* weston_desktop_xdg_surface::configure_list */
82 	uint32_t serial;
83 };
84 
85 struct weston_desktop_xdg_toplevel_state {
86 	bool maximized;
87 	bool fullscreen;
88 	bool resizing;
89 	bool activated;
90 };
91 
92 struct weston_desktop_xdg_toplevel_configure {
93 	struct weston_desktop_xdg_surface_configure base;
94 	struct weston_desktop_xdg_toplevel_state state;
95 	struct weston_size size;
96 };
97 
98 struct weston_desktop_xdg_toplevel {
99 	struct weston_desktop_xdg_surface base;
100 
101 	struct wl_resource *resource;
102 	bool added;
103 	struct {
104 		struct weston_desktop_xdg_toplevel_state state;
105 		struct weston_size size;
106 	} pending;
107 	struct {
108 		struct weston_desktop_xdg_toplevel_state state;
109 		struct weston_size size;
110 		struct weston_size min_size, max_size;
111 	} next;
112 	struct {
113 		struct weston_desktop_xdg_toplevel_state state;
114 		struct weston_size min_size, max_size;
115 	} current;
116 };
117 
118 struct weston_desktop_xdg_popup {
119 	struct weston_desktop_xdg_surface base;
120 
121 	struct wl_resource *resource;
122 	bool committed;
123 	struct weston_desktop_xdg_surface *parent;
124 	struct weston_desktop_seat *seat;
125 	struct weston_geometry geometry;
126 };
127 
128 #define weston_desktop_surface_role_biggest_size (sizeof(struct weston_desktop_xdg_toplevel))
129 #define weston_desktop_surface_configure_biggest_size (sizeof(struct weston_desktop_xdg_toplevel))
130 
131 
132 static struct weston_geometry
weston_desktop_xdg_positioner_get_geometry(struct weston_desktop_xdg_positioner * positioner,struct weston_desktop_surface * dsurface,struct weston_desktop_surface * parent)133 weston_desktop_xdg_positioner_get_geometry(struct weston_desktop_xdg_positioner *positioner,
134 					   struct weston_desktop_surface *dsurface,
135 					   struct weston_desktop_surface *parent)
136 {
137 	struct weston_geometry geometry = {
138 		.x = positioner->offset.x,
139 		.y = positioner->offset.y,
140 		.width = positioner->size.width,
141 		.height = positioner->size.height,
142 	};
143 
144 	if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP)
145 		geometry.y += positioner->anchor_rect.y;
146 	else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)
147 		geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height;
148 	else
149 		geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height / 2;
150 
151 	if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT)
152 		geometry.x += positioner->anchor_rect.x;
153 	else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT)
154 		geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width;
155 	else
156 		geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width / 2;
157 
158 	if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP)
159 		geometry.y -= geometry.height;
160 	else if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)
161 		geometry.y = geometry.y;
162 	else
163 		geometry.y -= geometry.height / 2;
164 
165 	if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT)
166 		geometry.x -= geometry.width;
167 	else if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT)
168 		geometry.x = geometry.x;
169 	else
170 		geometry.x -= geometry.width / 2;
171 
172 	if (positioner->constraint_adjustment == ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE)
173 		return geometry;
174 
175 	/* TODO: add compositor policy configuration and the code here */
176 
177 	return geometry;
178 }
179 
180 static void
weston_desktop_xdg_positioner_protocol_set_size(struct wl_client * wl_client,struct wl_resource * resource,int32_t width,int32_t height)181 weston_desktop_xdg_positioner_protocol_set_size(struct wl_client *wl_client,
182 						struct wl_resource *resource,
183 						int32_t width, int32_t height)
184 {
185 	struct weston_desktop_xdg_positioner *positioner =
186 		wl_resource_get_user_data(resource);
187 
188 	if (width < 1 || height < 1) {
189 		wl_resource_post_error(resource,
190 				       ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
191 				       "width and height must be positives and non-zero");
192 		return;
193 	}
194 
195 	positioner->size.width = width;
196 	positioner->size.height = height;
197 }
198 
199 static void
weston_desktop_xdg_positioner_protocol_set_anchor_rect(struct wl_client * wl_client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)200 weston_desktop_xdg_positioner_protocol_set_anchor_rect(struct wl_client *wl_client,
201 						       struct wl_resource *resource,
202 						       int32_t x, int32_t y,
203 						       int32_t width, int32_t height)
204 {
205 	struct weston_desktop_xdg_positioner *positioner =
206 		wl_resource_get_user_data(resource);
207 
208 	if (width < 1 || height < 1) {
209 		wl_resource_post_error(resource,
210 				       ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
211 				       "width and height must be positives and non-zero");
212 		return;
213 	}
214 
215 	positioner->anchor_rect.x = x;
216 	positioner->anchor_rect.y = y;
217 	positioner->anchor_rect.width = width;
218 	positioner->anchor_rect.height = height;
219 }
220 
221 static void
weston_desktop_xdg_positioner_protocol_set_anchor(struct wl_client * wl_client,struct wl_resource * resource,enum zxdg_positioner_v6_anchor anchor)222 weston_desktop_xdg_positioner_protocol_set_anchor(struct wl_client *wl_client,
223 						  struct wl_resource *resource,
224 						  enum zxdg_positioner_v6_anchor anchor)
225 {
226 	struct weston_desktop_xdg_positioner *positioner =
227 		wl_resource_get_user_data(resource);
228 
229 	if (((anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP ) &&
230 	      (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) ||
231 	    ((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) &&
232 	       (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT))) {
233 		wl_resource_post_error(resource,
234 				       ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
235 				       "same-axis values are not allowed");
236 		return;
237 	}
238 
239 	positioner->anchor = anchor;
240 }
241 
242 static void
weston_desktop_xdg_positioner_protocol_set_gravity(struct wl_client * wl_client,struct wl_resource * resource,enum zxdg_positioner_v6_gravity gravity)243 weston_desktop_xdg_positioner_protocol_set_gravity(struct wl_client *wl_client,
244 						   struct wl_resource *resource,
245 						   enum zxdg_positioner_v6_gravity gravity)
246 {
247 	struct weston_desktop_xdg_positioner *positioner =
248 		wl_resource_get_user_data(resource);
249 
250 	if (((gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) &&
251 	     (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) ||
252 	    ((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) &&
253 	     (gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT))) {
254 		wl_resource_post_error(resource,
255 				       ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
256 				       "same-axis values are not allowed");
257 		return;
258 	}
259 
260 	positioner->gravity = gravity;
261 }
262 
263 static void
weston_desktop_xdg_positioner_protocol_set_constraint_adjustment(struct wl_client * wl_client,struct wl_resource * resource,enum zxdg_positioner_v6_constraint_adjustment constraint_adjustment)264 weston_desktop_xdg_positioner_protocol_set_constraint_adjustment(struct wl_client *wl_client,
265 								 struct wl_resource *resource,
266 								 enum zxdg_positioner_v6_constraint_adjustment constraint_adjustment)
267 {
268 	struct weston_desktop_xdg_positioner *positioner =
269 		wl_resource_get_user_data(resource);
270 
271 	positioner->constraint_adjustment = constraint_adjustment;
272 }
273 
274 static void
weston_desktop_xdg_positioner_protocol_set_offset(struct wl_client * wl_client,struct wl_resource * resource,int32_t x,int32_t y)275 weston_desktop_xdg_positioner_protocol_set_offset(struct wl_client *wl_client,
276 						  struct wl_resource *resource,
277 						  int32_t x, int32_t y)
278 {
279 	struct weston_desktop_xdg_positioner *positioner =
280 		wl_resource_get_user_data(resource);
281 
282 	positioner->offset.x = x;
283 	positioner->offset.y = y;
284 }
285 
286 static void
weston_desktop_xdg_positioner_destroy(struct wl_resource * resource)287 weston_desktop_xdg_positioner_destroy(struct wl_resource *resource)
288 {
289 	struct weston_desktop_xdg_positioner *positioner =
290 		wl_resource_get_user_data(resource);
291 
292 	free(positioner);
293 }
294 
295 static const struct zxdg_positioner_v6_interface weston_desktop_xdg_positioner_implementation = {
296 	.destroy                   = weston_desktop_destroy_request,
297 	.set_size                  = weston_desktop_xdg_positioner_protocol_set_size,
298 	.set_anchor_rect           = weston_desktop_xdg_positioner_protocol_set_anchor_rect,
299 	.set_anchor                = weston_desktop_xdg_positioner_protocol_set_anchor,
300 	.set_gravity               = weston_desktop_xdg_positioner_protocol_set_gravity,
301 	.set_constraint_adjustment = weston_desktop_xdg_positioner_protocol_set_constraint_adjustment,
302 	.set_offset                = weston_desktop_xdg_positioner_protocol_set_offset,
303 };
304 
305 static void
306 weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *surface);
307 
308 static void
weston_desktop_xdg_toplevel_ensure_added(struct weston_desktop_xdg_toplevel * toplevel)309 weston_desktop_xdg_toplevel_ensure_added(struct weston_desktop_xdg_toplevel *toplevel)
310 {
311 	if (toplevel->added)
312 		return;
313 
314 	weston_desktop_api_surface_added(toplevel->base.desktop,
315 					 toplevel->base.desktop_surface);
316 	weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
317 	toplevel->added = true;
318 }
319 
320 static void
weston_desktop_xdg_toplevel_protocol_set_parent(struct wl_client * wl_client,struct wl_resource * resource,struct wl_resource * parent_resource)321 weston_desktop_xdg_toplevel_protocol_set_parent(struct wl_client *wl_client,
322 						struct wl_resource *resource,
323 						struct wl_resource *parent_resource)
324 {
325 	struct weston_desktop_surface *dsurface =
326 		wl_resource_get_user_data(resource);
327 	struct weston_desktop_xdg_toplevel *toplevel =
328 		weston_desktop_surface_get_implementation_data(dsurface);
329 	struct weston_desktop_surface *parent = NULL;
330 
331 	if (parent_resource != NULL)
332 		parent = wl_resource_get_user_data(parent_resource);
333 
334 	weston_desktop_xdg_toplevel_ensure_added(toplevel);
335 	weston_desktop_api_set_parent(toplevel->base.desktop, dsurface, parent);
336 }
337 
338 static void
weston_desktop_xdg_toplevel_protocol_set_title(struct wl_client * wl_client,struct wl_resource * resource,const char * title)339 weston_desktop_xdg_toplevel_protocol_set_title(struct wl_client *wl_client,
340 					       struct wl_resource *resource,
341 					       const char *title)
342 {
343 	struct weston_desktop_surface *toplevel =
344 		wl_resource_get_user_data(resource);
345 
346 	weston_desktop_surface_set_title(toplevel, title);
347 }
348 
349 static void
weston_desktop_xdg_toplevel_protocol_set_app_id(struct wl_client * wl_client,struct wl_resource * resource,const char * app_id)350 weston_desktop_xdg_toplevel_protocol_set_app_id(struct wl_client *wl_client,
351 						struct wl_resource *resource,
352 						const char *app_id)
353 {
354 	struct weston_desktop_surface *toplevel =
355 		wl_resource_get_user_data(resource);
356 
357 	weston_desktop_surface_set_app_id(toplevel, app_id);
358 }
359 
360 static void
weston_desktop_xdg_toplevel_protocol_show_window_menu(struct wl_client * wl_client,struct wl_resource * resource,struct wl_resource * seat_resource,uint32_t serial,int32_t x,int32_t y)361 weston_desktop_xdg_toplevel_protocol_show_window_menu(struct wl_client *wl_client,
362 						      struct wl_resource *resource,
363 						      struct wl_resource *seat_resource,
364 						      uint32_t serial,
365 						      int32_t x, int32_t y)
366 {
367 	struct weston_desktop_surface *dsurface =
368 		wl_resource_get_user_data(resource);
369 	struct weston_seat *seat =
370 		wl_resource_get_user_data(seat_resource);
371 	struct weston_desktop_xdg_toplevel *toplevel =
372 		weston_desktop_surface_get_implementation_data(dsurface);
373 
374 	if (!toplevel->base.configured) {
375 		wl_resource_post_error(toplevel->resource,
376 				       ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
377 				       "Surface has not been configured yet");
378 		return;
379 	}
380 
381 	if (seat == NULL)
382 		return;
383 
384 	weston_desktop_api_show_window_menu(toplevel->base.desktop,
385 					    dsurface, seat, x, y);
386 }
387 
388 static void
weston_desktop_xdg_toplevel_protocol_move(struct wl_client * wl_client,struct wl_resource * resource,struct wl_resource * seat_resource,uint32_t serial)389 weston_desktop_xdg_toplevel_protocol_move(struct wl_client *wl_client,
390 					  struct wl_resource *resource,
391 					  struct wl_resource *seat_resource,
392 					  uint32_t serial)
393 {
394 	struct weston_desktop_surface *dsurface =
395 		wl_resource_get_user_data(resource);
396 	struct weston_seat *seat =
397 		wl_resource_get_user_data(seat_resource);
398 	struct weston_desktop_xdg_toplevel *toplevel =
399 		weston_desktop_surface_get_implementation_data(dsurface);
400 
401 	if (!toplevel->base.configured) {
402 		wl_resource_post_error(toplevel->resource,
403 				       ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
404 				       "Surface has not been configured yet");
405 		return;
406 	}
407 
408 	if (seat == NULL)
409 		return;
410 
411 	weston_desktop_api_move(toplevel->base.desktop, dsurface, seat, serial);
412 }
413 
414 static void
weston_desktop_xdg_toplevel_protocol_resize(struct wl_client * wl_client,struct wl_resource * resource,struct wl_resource * seat_resource,uint32_t serial,enum zxdg_toplevel_v6_resize_edge edges)415 weston_desktop_xdg_toplevel_protocol_resize(struct wl_client *wl_client,
416 					    struct wl_resource *resource,
417 					    struct wl_resource *seat_resource,
418 					    uint32_t serial,
419 					    enum zxdg_toplevel_v6_resize_edge edges)
420 {
421 	struct weston_desktop_surface *dsurface =
422 		wl_resource_get_user_data(resource);
423 	struct weston_seat *seat =
424 		wl_resource_get_user_data(seat_resource);
425 	struct weston_desktop_xdg_toplevel *toplevel =
426 		weston_desktop_surface_get_implementation_data(dsurface);
427 	enum weston_desktop_surface_edge surf_edges =
428 		(enum weston_desktop_surface_edge) edges;
429 
430 	if (!toplevel->base.configured) {
431 		wl_resource_post_error(toplevel->resource,
432 				       ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
433 				       "Surface has not been configured yet");
434 		return;
435 	}
436 
437 	if (seat == NULL)
438 		return;
439 
440 	weston_desktop_api_resize(toplevel->base.desktop,
441 				  dsurface, seat, serial, surf_edges);
442 }
443 
444 static void
weston_desktop_xdg_toplevel_ack_configure(struct weston_desktop_xdg_toplevel * toplevel,struct weston_desktop_xdg_toplevel_configure * configure)445 weston_desktop_xdg_toplevel_ack_configure(struct weston_desktop_xdg_toplevel *toplevel,
446 					  struct weston_desktop_xdg_toplevel_configure *configure)
447 {
448 	toplevel->next.state = configure->state;
449 	toplevel->next.size = configure->size;
450 }
451 
452 static void
weston_desktop_xdg_toplevel_protocol_set_min_size(struct wl_client * wl_client,struct wl_resource * resource,int32_t width,int32_t height)453 weston_desktop_xdg_toplevel_protocol_set_min_size(struct wl_client *wl_client,
454 						  struct wl_resource *resource,
455 						  int32_t width, int32_t height)
456 {
457 	struct weston_desktop_surface *dsurface =
458 		wl_resource_get_user_data(resource);
459 	struct weston_desktop_xdg_toplevel *toplevel =
460 		weston_desktop_surface_get_implementation_data(dsurface);
461 
462 	toplevel->next.min_size.width = width;
463 	toplevel->next.min_size.height = height;
464 }
465 
466 static void
weston_desktop_xdg_toplevel_protocol_set_max_size(struct wl_client * wl_client,struct wl_resource * resource,int32_t width,int32_t height)467 weston_desktop_xdg_toplevel_protocol_set_max_size(struct wl_client *wl_client,
468 						  struct wl_resource *resource,
469 						  int32_t width, int32_t height)
470 {
471 	struct weston_desktop_surface *dsurface =
472 		wl_resource_get_user_data(resource);
473 	struct weston_desktop_xdg_toplevel *toplevel =
474 		weston_desktop_surface_get_implementation_data(dsurface);
475 
476 	toplevel->next.max_size.width = width;
477 	toplevel->next.max_size.height = height;
478 }
479 
480 static void
weston_desktop_xdg_toplevel_protocol_set_maximized(struct wl_client * wl_client,struct wl_resource * resource)481 weston_desktop_xdg_toplevel_protocol_set_maximized(struct wl_client *wl_client,
482 						   struct wl_resource *resource)
483 {
484 	struct weston_desktop_surface *dsurface =
485 		wl_resource_get_user_data(resource);
486 	struct weston_desktop_xdg_toplevel *toplevel =
487 		weston_desktop_surface_get_implementation_data(dsurface);
488 
489 	weston_desktop_xdg_toplevel_ensure_added(toplevel);
490 	weston_desktop_api_maximized_requested(toplevel->base.desktop, dsurface, true);
491 }
492 
493 static void
weston_desktop_xdg_toplevel_protocol_unset_maximized(struct wl_client * wl_client,struct wl_resource * resource)494 weston_desktop_xdg_toplevel_protocol_unset_maximized(struct wl_client *wl_client,
495 						     struct wl_resource *resource)
496 {
497 	struct weston_desktop_surface *dsurface =
498 		wl_resource_get_user_data(resource);
499 	struct weston_desktop_xdg_toplevel *toplevel =
500 		weston_desktop_surface_get_implementation_data(dsurface);
501 
502 	weston_desktop_xdg_toplevel_ensure_added(toplevel);
503 	weston_desktop_api_maximized_requested(toplevel->base.desktop, dsurface, false);
504 }
505 
506 static void
weston_desktop_xdg_toplevel_protocol_set_fullscreen(struct wl_client * wl_client,struct wl_resource * resource,struct wl_resource * output_resource)507 weston_desktop_xdg_toplevel_protocol_set_fullscreen(struct wl_client *wl_client,
508 						    struct wl_resource *resource,
509 						    struct wl_resource *output_resource)
510 {
511 	struct weston_desktop_surface *dsurface =
512 		wl_resource_get_user_data(resource);
513 	struct weston_desktop_xdg_toplevel *toplevel =
514 		weston_desktop_surface_get_implementation_data(dsurface);
515 	struct weston_output *output = NULL;
516 
517 	if (output_resource != NULL)
518 		output = weston_head_from_resource(output_resource)->output;
519 
520 	weston_desktop_xdg_toplevel_ensure_added(toplevel);
521 	weston_desktop_api_fullscreen_requested(toplevel->base.desktop, dsurface,
522 						true, output);
523 }
524 
525 static void
weston_desktop_xdg_toplevel_protocol_unset_fullscreen(struct wl_client * wl_client,struct wl_resource * resource)526 weston_desktop_xdg_toplevel_protocol_unset_fullscreen(struct wl_client *wl_client,
527 						      struct wl_resource *resource)
528 {
529 	struct weston_desktop_surface *dsurface =
530 		wl_resource_get_user_data(resource);
531 	struct weston_desktop_xdg_toplevel *toplevel =
532 		weston_desktop_surface_get_implementation_data(dsurface);
533 
534 	weston_desktop_xdg_toplevel_ensure_added(toplevel);
535 	weston_desktop_api_fullscreen_requested(toplevel->base.desktop, dsurface,
536 						false, NULL);
537 }
538 
539 static void
weston_desktop_xdg_toplevel_protocol_set_minimized(struct wl_client * wl_client,struct wl_resource * resource)540 weston_desktop_xdg_toplevel_protocol_set_minimized(struct wl_client *wl_client,
541 						   struct wl_resource *resource)
542 {
543 	struct weston_desktop_surface *dsurface =
544 		wl_resource_get_user_data(resource);
545 	struct weston_desktop_xdg_toplevel *toplevel =
546 		weston_desktop_surface_get_implementation_data(dsurface);
547 
548 	weston_desktop_xdg_toplevel_ensure_added(toplevel);
549 	weston_desktop_api_minimized_requested(toplevel->base.desktop, dsurface);
550 }
551 
552 static void
weston_desktop_xdg_toplevel_send_configure(struct weston_desktop_xdg_toplevel * toplevel,struct weston_desktop_xdg_toplevel_configure * configure)553 weston_desktop_xdg_toplevel_send_configure(struct weston_desktop_xdg_toplevel *toplevel,
554 					   struct weston_desktop_xdg_toplevel_configure *configure)
555 {
556 	uint32_t *s;
557 	struct wl_array states;
558 
559 	configure->state = toplevel->pending.state;
560 	configure->size = toplevel->pending.size;
561 
562 	wl_array_init(&states);
563 	if (toplevel->pending.state.maximized) {
564 		s = wl_array_add(&states, sizeof(uint32_t));
565 		*s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED;
566 	}
567 	if (toplevel->pending.state.fullscreen) {
568 		s = wl_array_add(&states, sizeof(uint32_t));
569 		*s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN;
570 	}
571 	if (toplevel->pending.state.resizing) {
572 		s = wl_array_add(&states, sizeof(uint32_t));
573 		*s = ZXDG_TOPLEVEL_V6_STATE_RESIZING;
574 	}
575 	if (toplevel->pending.state.activated) {
576 		s = wl_array_add(&states, sizeof(uint32_t));
577 		*s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED;
578 	}
579 
580 	zxdg_toplevel_v6_send_configure(toplevel->resource,
581 					toplevel->pending.size.width,
582 					toplevel->pending.size.height,
583 					&states);
584 
585 	wl_array_release(&states);
586 };
587 
588 static void
weston_desktop_xdg_toplevel_set_maximized(struct weston_desktop_surface * dsurface,void * user_data,bool maximized)589 weston_desktop_xdg_toplevel_set_maximized(struct weston_desktop_surface *dsurface,
590 					  void *user_data, bool maximized)
591 {
592 	struct weston_desktop_xdg_toplevel *toplevel = user_data;
593 
594 	toplevel->pending.state.maximized = maximized;
595 	weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
596 }
597 
598 static void
weston_desktop_xdg_toplevel_set_fullscreen(struct weston_desktop_surface * dsurface,void * user_data,bool fullscreen)599 weston_desktop_xdg_toplevel_set_fullscreen(struct weston_desktop_surface *dsurface,
600 					   void *user_data, bool fullscreen)
601 {
602 	struct weston_desktop_xdg_toplevel *toplevel = user_data;
603 
604 	toplevel->pending.state.fullscreen = fullscreen;
605 	weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
606 }
607 
608 static void
weston_desktop_xdg_toplevel_set_resizing(struct weston_desktop_surface * dsurface,void * user_data,bool resizing)609 weston_desktop_xdg_toplevel_set_resizing(struct weston_desktop_surface *dsurface,
610 					 void *user_data, bool resizing)
611 {
612 	struct weston_desktop_xdg_toplevel *toplevel = user_data;
613 
614 	toplevel->pending.state.resizing = resizing;
615 	weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
616 }
617 
618 static void
weston_desktop_xdg_toplevel_set_activated(struct weston_desktop_surface * dsurface,void * user_data,bool activated)619 weston_desktop_xdg_toplevel_set_activated(struct weston_desktop_surface *dsurface,
620 					  void *user_data, bool activated)
621 {
622 	struct weston_desktop_xdg_toplevel *toplevel = user_data;
623 
624 	toplevel->pending.state.activated = activated;
625 	weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
626 }
627 
628 static void
weston_desktop_xdg_toplevel_set_size(struct weston_desktop_surface * dsurface,void * user_data,int32_t width,int32_t height)629 weston_desktop_xdg_toplevel_set_size(struct weston_desktop_surface *dsurface,
630 				     void *user_data,
631 				     int32_t width, int32_t height)
632 {
633 	struct weston_desktop_xdg_toplevel *toplevel = user_data;
634 
635 	toplevel->pending.size.width = width;
636 	toplevel->pending.size.height = height;
637 
638 	weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
639 }
640 
641 static void
weston_desktop_xdg_toplevel_committed(struct weston_desktop_xdg_toplevel * toplevel,int32_t sx,int32_t sy)642 weston_desktop_xdg_toplevel_committed(struct weston_desktop_xdg_toplevel *toplevel,
643 				      int32_t sx, int32_t sy)
644 {
645 	struct weston_surface *wsurface =
646 		weston_desktop_surface_get_surface(toplevel->base.desktop_surface);
647 
648 	if (!wsurface->buffer_ref.buffer && !toplevel->added) {
649 		weston_desktop_xdg_toplevel_ensure_added(toplevel);
650 		return;
651 	}
652 	if (!wsurface->buffer_ref.buffer)
653 		return;
654 
655 	struct weston_geometry geometry =
656 		weston_desktop_surface_get_geometry(toplevel->base.desktop_surface);
657 
658 	if ((toplevel->next.state.maximized || toplevel->next.state.fullscreen) &&
659 	    (toplevel->next.size.width != geometry.width ||
660 	     toplevel->next.size.height != geometry.height)) {
661 		struct weston_desktop_client *client =
662 			weston_desktop_surface_get_client(toplevel->base.desktop_surface);
663 		struct wl_resource *client_resource =
664 			weston_desktop_client_get_resource(client);
665 
666 		wl_resource_post_error(client_resource,
667 				       ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
668 				       "xdg_surface buffer does not match the configured state");
669 		return;
670 	}
671 
672 	toplevel->current.state = toplevel->next.state;
673 	toplevel->current.min_size = toplevel->next.min_size;
674 	toplevel->current.max_size = toplevel->next.max_size;
675 
676 	weston_desktop_api_committed(toplevel->base.desktop,
677 				     toplevel->base.desktop_surface,
678 				     sx, sy);
679 }
680 
681 static void
weston_desktop_xdg_toplevel_close(struct weston_desktop_xdg_toplevel * toplevel)682 weston_desktop_xdg_toplevel_close(struct weston_desktop_xdg_toplevel *toplevel)
683 {
684 	zxdg_toplevel_v6_send_close(toplevel->resource);
685 }
686 
687 static bool
weston_desktop_xdg_toplevel_get_maximized(struct weston_desktop_surface * dsurface,void * user_data)688 weston_desktop_xdg_toplevel_get_maximized(struct weston_desktop_surface *dsurface,
689 					  void *user_data)
690 {
691 	struct weston_desktop_xdg_toplevel *toplevel = user_data;
692 
693 	return toplevel->current.state.maximized;
694 }
695 
696 static bool
weston_desktop_xdg_toplevel_get_fullscreen(struct weston_desktop_surface * dsurface,void * user_data)697 weston_desktop_xdg_toplevel_get_fullscreen(struct weston_desktop_surface *dsurface,
698 					   void *user_data)
699 {
700 	struct weston_desktop_xdg_toplevel *toplevel = user_data;
701 
702 	return toplevel->current.state.fullscreen;
703 }
704 
705 static bool
weston_desktop_xdg_toplevel_get_resizing(struct weston_desktop_surface * dsurface,void * user_data)706 weston_desktop_xdg_toplevel_get_resizing(struct weston_desktop_surface *dsurface,
707 					 void *user_data)
708 {
709 	struct weston_desktop_xdg_toplevel *toplevel = user_data;
710 
711 	return toplevel->current.state.resizing;
712 }
713 
714 static bool
weston_desktop_xdg_toplevel_get_activated(struct weston_desktop_surface * dsurface,void * user_data)715 weston_desktop_xdg_toplevel_get_activated(struct weston_desktop_surface *dsurface,
716 					  void *user_data)
717 {
718 	struct weston_desktop_xdg_toplevel *toplevel = user_data;
719 
720 	return toplevel->current.state.activated;
721 }
722 
723 static void
weston_desktop_xdg_toplevel_destroy(struct weston_desktop_xdg_toplevel * toplevel)724 weston_desktop_xdg_toplevel_destroy(struct weston_desktop_xdg_toplevel *toplevel)
725 {
726 	if (toplevel->added)
727 		weston_desktop_api_surface_removed(toplevel->base.desktop,
728 						   toplevel->base.desktop_surface);
729 }
730 
731 static void
weston_desktop_xdg_toplevel_resource_destroy(struct wl_resource * resource)732 weston_desktop_xdg_toplevel_resource_destroy(struct wl_resource *resource)
733 {
734 	struct weston_desktop_surface *dsurface =
735 		wl_resource_get_user_data(resource);
736 
737 	if (dsurface != NULL)
738 		weston_desktop_surface_resource_destroy(resource);
739 }
740 
741 static const struct zxdg_toplevel_v6_interface weston_desktop_xdg_toplevel_implementation = {
742 	.destroy             = weston_desktop_destroy_request,
743 	.set_parent          = weston_desktop_xdg_toplevel_protocol_set_parent,
744 	.set_title           = weston_desktop_xdg_toplevel_protocol_set_title,
745 	.set_app_id          = weston_desktop_xdg_toplevel_protocol_set_app_id,
746 	.show_window_menu    = weston_desktop_xdg_toplevel_protocol_show_window_menu,
747 	.move                = weston_desktop_xdg_toplevel_protocol_move,
748 	.resize              = weston_desktop_xdg_toplevel_protocol_resize,
749 	.set_min_size        = weston_desktop_xdg_toplevel_protocol_set_min_size,
750 	.set_max_size        = weston_desktop_xdg_toplevel_protocol_set_max_size,
751 	.set_maximized       = weston_desktop_xdg_toplevel_protocol_set_maximized,
752 	.unset_maximized     = weston_desktop_xdg_toplevel_protocol_unset_maximized,
753 	.set_fullscreen      = weston_desktop_xdg_toplevel_protocol_set_fullscreen,
754 	.unset_fullscreen    = weston_desktop_xdg_toplevel_protocol_unset_fullscreen,
755 	.set_minimized       = weston_desktop_xdg_toplevel_protocol_set_minimized,
756 };
757 
758 static void
weston_desktop_xdg_popup_protocol_grab(struct wl_client * wl_client,struct wl_resource * resource,struct wl_resource * seat_resource,uint32_t serial)759 weston_desktop_xdg_popup_protocol_grab(struct wl_client *wl_client,
760 				       struct wl_resource *resource,
761 				       struct wl_resource *seat_resource,
762 				       uint32_t serial)
763 {
764 	struct weston_desktop_surface *dsurface =
765 		wl_resource_get_user_data(resource);
766 	struct weston_desktop_xdg_popup *popup =
767 		weston_desktop_surface_get_implementation_data(dsurface);
768 	struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
769 	struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
770 	struct weston_desktop_surface *topmost;
771 	bool parent_is_toplevel =
772 		popup->parent->role == WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL;
773 
774 	/* Check that if we have a valid wseat we also got a valid desktop seat */
775 	if (wseat != NULL && seat == NULL) {
776 		wl_client_post_no_memory(wl_client);
777 		return;
778 	}
779 
780 	if (popup->committed) {
781 		wl_resource_post_error(popup->resource,
782 				       ZXDG_POPUP_V6_ERROR_INVALID_GRAB,
783 				       "xdg_popup already is mapped");
784 		return;
785 	}
786 
787 	/* If seat is NULL then get_topmost_surface will return NULL. In
788 	 * combination with setting parent_is_toplevel to TRUE here we will
789 	 * avoid posting an error, and we will instead gracefully fail the
790 	 * grab and dismiss the surface.
791 	 * FIXME: this is a hack because currently we cannot check the topmost
792 	 * parent with a destroyed weston_seat */
793 	if (seat == NULL)
794 		parent_is_toplevel = true;
795 
796 	topmost = weston_desktop_seat_popup_grab_get_topmost_surface(seat);
797 	if ((topmost == NULL && !parent_is_toplevel) ||
798 	    (topmost != NULL && topmost != popup->parent->desktop_surface)) {
799 		struct weston_desktop_client *client =
800 			weston_desktop_surface_get_client(dsurface);
801 		struct wl_resource *client_resource =
802 			weston_desktop_client_get_resource(client);
803 
804 		wl_resource_post_error(client_resource,
805 				       ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP,
806 				       "xdg_popup was not created on the topmost popup");
807 		return;
808 	}
809 
810 	popup->seat = seat;
811 	weston_desktop_surface_popup_grab(popup->base.desktop_surface,
812 					  popup->seat, serial);
813 }
814 
815 static void
weston_desktop_xdg_popup_send_configure(struct weston_desktop_xdg_popup * popup)816 weston_desktop_xdg_popup_send_configure(struct weston_desktop_xdg_popup *popup)
817 {
818 	zxdg_popup_v6_send_configure(popup->resource,
819 				     popup->geometry.x,
820 				     popup->geometry.y,
821 				     popup->geometry.width,
822 				     popup->geometry.height);
823 }
824 
825 static void
826 weston_desktop_xdg_popup_update_position(struct weston_desktop_surface *dsurface,
827 					 void *user_data);
828 
829 static void
weston_desktop_xdg_popup_committed(struct weston_desktop_xdg_popup * popup)830 weston_desktop_xdg_popup_committed(struct weston_desktop_xdg_popup *popup)
831 {
832 	struct weston_surface *wsurface =
833 		weston_desktop_surface_get_surface (popup->base.desktop_surface);
834 	struct weston_view *view;
835 
836 	wl_list_for_each(view, &wsurface->views, surface_link)
837 		weston_view_update_transform(view);
838 
839 	if (!popup->committed)
840 		weston_desktop_xdg_surface_schedule_configure(&popup->base);
841 	popup->committed = true;
842 	weston_desktop_xdg_popup_update_position(popup->base.desktop_surface,
843 						 popup);
844 }
845 
846 static void
weston_desktop_xdg_popup_update_position(struct weston_desktop_surface * dsurface,void * user_data)847 weston_desktop_xdg_popup_update_position(struct weston_desktop_surface *dsurface,
848 					 void *user_data)
849 {
850 }
851 
852 static void
weston_desktop_xdg_popup_close(struct weston_desktop_xdg_popup * popup)853 weston_desktop_xdg_popup_close(struct weston_desktop_xdg_popup *popup)
854 {
855 	zxdg_popup_v6_send_popup_done(popup->resource);
856 }
857 
858 static void
weston_desktop_xdg_popup_destroy(struct weston_desktop_xdg_popup * popup)859 weston_desktop_xdg_popup_destroy(struct weston_desktop_xdg_popup *popup)
860 {
861 	struct weston_desktop_surface *topmost;
862 	struct weston_desktop_client *client =
863 		weston_desktop_surface_get_client(popup->base.desktop_surface);
864 
865 	if (!weston_desktop_surface_get_grab(popup->base.desktop_surface))
866 		return;
867 
868 	topmost = weston_desktop_seat_popup_grab_get_topmost_surface(popup->seat);
869 	if (topmost != popup->base.desktop_surface) {
870 		struct wl_resource *client_resource =
871 			weston_desktop_client_get_resource(client);
872 
873 		wl_resource_post_error(client_resource,
874 				       ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP,
875 				       "xdg_popup was destroyed while it was not the topmost popup.");
876 	}
877 
878 	weston_desktop_surface_popup_ungrab(popup->base.desktop_surface,
879 					    popup->seat);
880 }
881 
882 static void
weston_desktop_xdg_popup_resource_destroy(struct wl_resource * resource)883 weston_desktop_xdg_popup_resource_destroy(struct wl_resource *resource)
884 {
885 	struct weston_desktop_surface *dsurface =
886 		wl_resource_get_user_data(resource);
887 
888 	if (dsurface != NULL)
889 		weston_desktop_surface_resource_destroy(resource);
890 }
891 
892 static const struct zxdg_popup_v6_interface weston_desktop_xdg_popup_implementation = {
893 	.destroy             = weston_desktop_destroy_request,
894 	.grab                = weston_desktop_xdg_popup_protocol_grab,
895 };
896 
897 static void
weston_desktop_xdg_surface_send_configure(void * user_data)898 weston_desktop_xdg_surface_send_configure(void *user_data)
899 {
900 	struct weston_desktop_xdg_surface *surface = user_data;
901 	struct weston_desktop_xdg_surface_configure *configure;
902 
903 	surface->configure_idle = NULL;
904 
905 	configure = zalloc(weston_desktop_surface_configure_biggest_size);
906 	if (configure == NULL) {
907 		struct weston_desktop_client *client =
908 			weston_desktop_surface_get_client(surface->desktop_surface);
909 		struct wl_client *wl_client =
910 			weston_desktop_client_get_client(client);
911 		wl_client_post_no_memory(wl_client);
912 		return;
913 	}
914 	wl_list_insert(surface->configure_list.prev, &configure->link);
915 	configure->serial =
916 		wl_display_next_serial(weston_desktop_get_display(surface->desktop));
917 
918 	switch (surface->role) {
919 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
920 		assert(0 && "not reached");
921 		break;
922 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
923 		weston_desktop_xdg_toplevel_send_configure((struct weston_desktop_xdg_toplevel *) surface,
924 							   (struct weston_desktop_xdg_toplevel_configure *) configure);
925 		break;
926 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
927 		weston_desktop_xdg_popup_send_configure((struct weston_desktop_xdg_popup *) surface);
928 		break;
929 	}
930 
931 	zxdg_surface_v6_send_configure(surface->resource, configure->serial);
932 }
933 
934 static bool
weston_desktop_xdg_toplevel_state_compare(struct weston_desktop_xdg_toplevel * toplevel)935 weston_desktop_xdg_toplevel_state_compare(struct weston_desktop_xdg_toplevel *toplevel)
936 {
937 	struct {
938 		struct weston_desktop_xdg_toplevel_state state;
939 		struct weston_size size;
940 	} configured;
941 
942 	if (!toplevel->base.configured)
943 		return false;
944 
945 	if (wl_list_empty(&toplevel->base.configure_list)) {
946 		/* Last configure is actually the current state, just use it */
947 		configured.state = toplevel->current.state;
948 		configured.size.width = toplevel->base.surface->width;
949 		configured.size.height = toplevel->base.surface->height;
950 	} else {
951 		struct weston_desktop_xdg_toplevel_configure *configure =
952 			wl_container_of(toplevel->base.configure_list.prev,
953 					configure, base.link);
954 
955 		configured.state = configure->state;
956 		configured.size = configure->size;
957 	}
958 
959 	if (toplevel->pending.state.activated != configured.state.activated)
960 		return false;
961 	if (toplevel->pending.state.fullscreen != configured.state.fullscreen)
962 		return false;
963 	if (toplevel->pending.state.maximized != configured.state.maximized)
964 		return false;
965 	if (toplevel->pending.state.resizing != configured.state.resizing)
966 		return false;
967 
968 	if (toplevel->pending.size.width == configured.size.width &&
969 	    toplevel->pending.size.height == configured.size.height)
970 		return true;
971 
972 	if (toplevel->pending.size.width == 0 &&
973 	    toplevel->pending.size.height == 0)
974 		return true;
975 
976 	return false;
977 }
978 
979 static void
weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface * surface)980 weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *surface)
981 {
982 	struct wl_display *display = weston_desktop_get_display(surface->desktop);
983 	struct wl_event_loop *loop = wl_display_get_event_loop(display);
984 	bool pending_same = false;
985 
986 	switch (surface->role) {
987 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
988 		assert(0 && "not reached");
989 		break;
990 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
991 		pending_same = weston_desktop_xdg_toplevel_state_compare((struct weston_desktop_xdg_toplevel *) surface);
992 		break;
993 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
994 		break;
995 	}
996 
997 	if (surface->configure_idle != NULL) {
998 		if (!pending_same)
999 			return;
1000 
1001 		wl_event_source_remove(surface->configure_idle);
1002 		surface->configure_idle = NULL;
1003 	} else {
1004 		if (pending_same)
1005 			return;
1006 
1007 		surface->configure_idle =
1008 			wl_event_loop_add_idle(loop,
1009 					       weston_desktop_xdg_surface_send_configure,
1010 					       surface);
1011 	}
1012 }
1013 
1014 static void
weston_desktop_xdg_surface_protocol_get_toplevel(struct wl_client * wl_client,struct wl_resource * resource,uint32_t id)1015 weston_desktop_xdg_surface_protocol_get_toplevel(struct wl_client *wl_client,
1016 						 struct wl_resource *resource,
1017 						 uint32_t id)
1018 {
1019 	struct weston_desktop_surface *dsurface =
1020 		wl_resource_get_user_data(resource);
1021 	struct weston_surface *wsurface =
1022 		weston_desktop_surface_get_surface(dsurface);
1023 	struct weston_desktop_xdg_toplevel *toplevel =
1024 		weston_desktop_surface_get_implementation_data(dsurface);
1025 
1026 	if (weston_surface_set_role(wsurface, weston_desktop_xdg_toplevel_role,
1027 				    resource, ZXDG_SHELL_V6_ERROR_ROLE) < 0)
1028 		return;
1029 
1030 	toplevel->resource =
1031 		weston_desktop_surface_add_resource(toplevel->base.desktop_surface,
1032 						    &zxdg_toplevel_v6_interface,
1033 						    &weston_desktop_xdg_toplevel_implementation,
1034 						    id, weston_desktop_xdg_toplevel_resource_destroy);
1035 	if (toplevel->resource == NULL)
1036 		return;
1037 
1038 	toplevel->base.role = WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL;
1039 }
1040 
1041 static void
weston_desktop_xdg_surface_protocol_get_popup(struct wl_client * wl_client,struct wl_resource * resource,uint32_t id,struct wl_resource * parent_resource,struct wl_resource * positioner_resource)1042 weston_desktop_xdg_surface_protocol_get_popup(struct wl_client *wl_client,
1043 					      struct wl_resource *resource,
1044 					      uint32_t id,
1045 					      struct wl_resource *parent_resource,
1046 					      struct wl_resource *positioner_resource)
1047 {
1048 	struct weston_desktop_surface *dsurface =
1049 		wl_resource_get_user_data(resource);
1050 	struct weston_surface *wsurface =
1051 		weston_desktop_surface_get_surface(dsurface);
1052 	struct weston_desktop_xdg_popup *popup =
1053 		weston_desktop_surface_get_implementation_data(dsurface);
1054 	struct weston_desktop_surface *parent_surface =
1055 		wl_resource_get_user_data(parent_resource);
1056 	struct weston_desktop_xdg_surface *parent =
1057 		weston_desktop_surface_get_implementation_data(parent_surface);
1058 	struct weston_desktop_xdg_positioner *positioner =
1059 		wl_resource_get_user_data(positioner_resource);
1060 
1061 	/* Checking whether the size and anchor rect both have a positive size
1062 	 * is enough to verify both have been correctly set */
1063 	if (positioner->size.width == 0 || positioner->anchor_rect.width == 0) {
1064 		wl_resource_post_error(resource,
1065 				       ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER,
1066 				       "positioner object is not complete");
1067 		return;
1068 	}
1069 
1070 	if (weston_surface_set_role(wsurface, weston_desktop_xdg_popup_role,
1071 				    resource, ZXDG_SHELL_V6_ERROR_ROLE) < 0)
1072 		return;
1073 
1074 	popup->resource =
1075 		weston_desktop_surface_add_resource(popup->base.desktop_surface,
1076 						    &zxdg_popup_v6_interface,
1077 						    &weston_desktop_xdg_popup_implementation,
1078 						    id, weston_desktop_xdg_popup_resource_destroy);
1079 	if (popup->resource == NULL)
1080 		return;
1081 
1082 	popup->base.role = WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP;
1083 	popup->parent = parent;
1084 
1085 	popup->geometry =
1086 		weston_desktop_xdg_positioner_get_geometry(positioner,
1087 							   dsurface,
1088 							   parent_surface);
1089 
1090 	weston_desktop_surface_set_relative_to(popup->base.desktop_surface,
1091 					       parent_surface,
1092 					       popup->geometry.x,
1093 					       popup->geometry.y,
1094 					       true);
1095 }
1096 
1097 static bool
weston_desktop_xdg_surface_check_role(struct weston_desktop_xdg_surface * surface)1098 weston_desktop_xdg_surface_check_role(struct weston_desktop_xdg_surface *surface)
1099 {
1100 	struct weston_surface *wsurface =
1101 		weston_desktop_surface_get_surface(surface->desktop_surface);
1102 	const char *role;
1103 
1104 	role = weston_surface_get_role(wsurface);
1105 	if (role != NULL &&
1106 	    (role == weston_desktop_xdg_toplevel_role ||
1107 	     role == weston_desktop_xdg_popup_role))
1108 	     return true;
1109 
1110 	wl_resource_post_error(surface->resource,
1111 			       ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
1112 			       "xdg_surface must have a role");
1113 	return false;
1114 }
1115 
1116 static void
weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client * wl_client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)1117 weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client,
1118 							struct wl_resource *resource,
1119 							int32_t x, int32_t y,
1120 							int32_t width, int32_t height)
1121 {
1122 	struct weston_desktop_surface *dsurface =
1123 		wl_resource_get_user_data(resource);
1124 	struct weston_desktop_xdg_surface *surface =
1125 		weston_desktop_surface_get_implementation_data(dsurface);
1126 
1127 	if (!weston_desktop_xdg_surface_check_role(surface))
1128 		return;
1129 
1130 	surface->has_next_geometry = true;
1131 	surface->next_geometry.x = x;
1132 	surface->next_geometry.y = y;
1133 	surface->next_geometry.width = width;
1134 	surface->next_geometry.height = height;
1135 }
1136 
1137 static void
weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client * wl_client,struct wl_resource * resource,uint32_t serial)1138 weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
1139 						  struct wl_resource *resource,
1140 						  uint32_t serial)
1141 {
1142 	struct weston_desktop_surface *dsurface =
1143 		wl_resource_get_user_data(resource);
1144 	struct weston_desktop_xdg_surface *surface =
1145 		weston_desktop_surface_get_implementation_data(dsurface);
1146 	struct weston_desktop_xdg_surface_configure *configure, *temp;
1147 	bool found = false;
1148 
1149 	if (!weston_desktop_xdg_surface_check_role(surface))
1150 		return;
1151 
1152 	wl_list_for_each_safe(configure, temp, &surface->configure_list, link) {
1153 		if (configure->serial < serial) {
1154 			wl_list_remove(&configure->link);
1155 			free(configure);
1156 		} else if (configure->serial == serial) {
1157 			wl_list_remove(&configure->link);
1158 			found = true;
1159 			break;
1160 		} else {
1161 			break;
1162 		}
1163 	}
1164 	if (!found) {
1165 		struct weston_desktop_client *client =
1166 			weston_desktop_surface_get_client(dsurface);
1167 		struct wl_resource *client_resource =
1168 			weston_desktop_client_get_resource(client);
1169 		wl_resource_post_error(client_resource,
1170 				       ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
1171 				       "Wrong configure serial: %u", serial);
1172 		return;
1173 	}
1174 
1175 	surface->configured = true;
1176 
1177 	switch (surface->role) {
1178 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
1179 		assert(0 && "not reached");
1180 		break;
1181 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
1182 		weston_desktop_xdg_toplevel_ack_configure((struct weston_desktop_xdg_toplevel *) surface,
1183 							  (struct weston_desktop_xdg_toplevel_configure *) configure);
1184 		break;
1185 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
1186 		break;
1187 	}
1188 
1189 	free(configure);
1190 }
1191 
1192 static void
weston_desktop_xdg_surface_ping(struct weston_desktop_surface * dsurface,uint32_t serial,void * user_data)1193 weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface,
1194 				uint32_t serial, void *user_data)
1195 {
1196 	struct weston_desktop_client *client =
1197 		weston_desktop_surface_get_client(dsurface);
1198 
1199 	zxdg_shell_v6_send_ping(weston_desktop_client_get_resource(client),
1200 				serial);
1201 }
1202 
1203 static void
weston_desktop_xdg_surface_committed(struct weston_desktop_surface * dsurface,void * user_data,int32_t sx,int32_t sy)1204 weston_desktop_xdg_surface_committed(struct weston_desktop_surface *dsurface,
1205 				     void *user_data,
1206 				     int32_t sx, int32_t sy)
1207 {
1208 	struct weston_desktop_xdg_surface *surface = user_data;
1209 	struct weston_surface *wsurface =
1210 		weston_desktop_surface_get_surface (dsurface);
1211 
1212 	if (wsurface->buffer_ref.buffer && !surface->configured) {
1213 		wl_resource_post_error(surface->resource,
1214 				       ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER,
1215 				       "xdg_surface has never been configured");
1216 		return;
1217 	}
1218 
1219 	if (surface->has_next_geometry) {
1220 		surface->has_next_geometry = false;
1221 		weston_desktop_surface_set_geometry(surface->desktop_surface,
1222 						    surface->next_geometry);
1223 	}
1224 
1225 	switch (surface->role) {
1226 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
1227 		wl_resource_post_error(surface->resource,
1228 				       ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
1229 				       "xdg_surface must have a role");
1230 		break;
1231 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
1232 		weston_desktop_xdg_toplevel_committed((struct weston_desktop_xdg_toplevel *) surface, sx, sy);
1233 		break;
1234 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
1235 		weston_desktop_xdg_popup_committed((struct weston_desktop_xdg_popup *) surface);
1236 		break;
1237 	}
1238 }
1239 
1240 static void
weston_desktop_xdg_surface_close(struct weston_desktop_surface * dsurface,void * user_data)1241 weston_desktop_xdg_surface_close(struct weston_desktop_surface *dsurface,
1242 				 void *user_data)
1243 {
1244 	struct weston_desktop_xdg_surface *surface = user_data;
1245 
1246 	switch (surface->role) {
1247 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
1248 		assert(0 && "not reached");
1249 		break;
1250 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
1251 		weston_desktop_xdg_toplevel_close((struct weston_desktop_xdg_toplevel *) surface);
1252 		break;
1253 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
1254 		weston_desktop_xdg_popup_close((struct weston_desktop_xdg_popup *) surface);
1255 		break;
1256 	}
1257 }
1258 
1259 static void
weston_desktop_xdg_surface_destroy(struct weston_desktop_surface * dsurface,void * user_data)1260 weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface,
1261 				   void *user_data)
1262 {
1263 	struct weston_desktop_xdg_surface *surface = user_data;
1264 	struct weston_desktop_xdg_surface_configure *configure, *temp;
1265 
1266 	switch (surface->role) {
1267 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
1268 		break;
1269 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
1270 		weston_desktop_xdg_toplevel_destroy((struct weston_desktop_xdg_toplevel *) surface);
1271 		break;
1272 	case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
1273 		weston_desktop_xdg_popup_destroy((struct weston_desktop_xdg_popup *) surface);
1274 		break;
1275 	}
1276 
1277 	if (surface->configure_idle != NULL)
1278 		wl_event_source_remove(surface->configure_idle);
1279 
1280 	wl_list_for_each_safe(configure, temp, &surface->configure_list, link)
1281 		free(configure);
1282 
1283 	free(surface);
1284 }
1285 
1286 static const struct zxdg_surface_v6_interface weston_desktop_xdg_surface_implementation = {
1287 	.destroy             = weston_desktop_destroy_request,
1288 	.get_toplevel        = weston_desktop_xdg_surface_protocol_get_toplevel,
1289 	.get_popup           = weston_desktop_xdg_surface_protocol_get_popup,
1290 	.set_window_geometry = weston_desktop_xdg_surface_protocol_set_window_geometry,
1291 	.ack_configure       = weston_desktop_xdg_surface_protocol_ack_configure,
1292 };
1293 
1294 static const struct weston_desktop_surface_implementation weston_desktop_xdg_surface_internal_implementation = {
1295 	/* These are used for toplevel only */
1296 	.set_maximized = weston_desktop_xdg_toplevel_set_maximized,
1297 	.set_fullscreen = weston_desktop_xdg_toplevel_set_fullscreen,
1298 	.set_resizing = weston_desktop_xdg_toplevel_set_resizing,
1299 	.set_activated = weston_desktop_xdg_toplevel_set_activated,
1300 	.set_size = weston_desktop_xdg_toplevel_set_size,
1301 
1302 	.get_maximized = weston_desktop_xdg_toplevel_get_maximized,
1303 	.get_fullscreen = weston_desktop_xdg_toplevel_get_fullscreen,
1304 	.get_resizing = weston_desktop_xdg_toplevel_get_resizing,
1305 	.get_activated = weston_desktop_xdg_toplevel_get_activated,
1306 
1307 	/* These are used for popup only */
1308 	.update_position = weston_desktop_xdg_popup_update_position,
1309 
1310 	/* Common API */
1311 	.committed = weston_desktop_xdg_surface_committed,
1312 	.ping = weston_desktop_xdg_surface_ping,
1313 	.close = weston_desktop_xdg_surface_close,
1314 
1315 	.destroy = weston_desktop_xdg_surface_destroy,
1316 };
1317 
1318 static void
weston_desktop_xdg_shell_protocol_create_positioner(struct wl_client * wl_client,struct wl_resource * resource,uint32_t id)1319 weston_desktop_xdg_shell_protocol_create_positioner(struct wl_client *wl_client,
1320 						    struct wl_resource *resource,
1321 						    uint32_t id)
1322 {
1323 	struct weston_desktop_client *client =
1324 		wl_resource_get_user_data(resource);
1325 	struct weston_desktop_xdg_positioner *positioner;
1326 
1327 	positioner = zalloc(sizeof(struct weston_desktop_xdg_positioner));
1328 	if (positioner == NULL) {
1329 		wl_client_post_no_memory(wl_client);
1330 		return;
1331 	}
1332 
1333 	positioner->client = client;
1334 	positioner->desktop = weston_desktop_client_get_desktop(positioner->client);
1335 
1336 	positioner->resource =
1337 		wl_resource_create(wl_client,
1338 				   &zxdg_positioner_v6_interface,
1339 				   wl_resource_get_version(resource), id);
1340 	if (positioner->resource == NULL) {
1341 		wl_client_post_no_memory(wl_client);
1342 		free(positioner);
1343 		return;
1344 	}
1345 	wl_resource_set_implementation(positioner->resource,
1346 				       &weston_desktop_xdg_positioner_implementation,
1347 				       positioner, weston_desktop_xdg_positioner_destroy);
1348 }
1349 
1350 static void
weston_desktop_xdg_surface_resource_destroy(struct wl_resource * resource)1351 weston_desktop_xdg_surface_resource_destroy(struct wl_resource *resource)
1352 {
1353 	struct weston_desktop_surface *dsurface =
1354 		wl_resource_get_user_data(resource);
1355 
1356 	if (dsurface != NULL)
1357 		weston_desktop_surface_resource_destroy(resource);
1358 }
1359 
1360 static void
weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client * wl_client,struct wl_resource * resource,uint32_t id,struct wl_resource * surface_resource)1361 weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
1362 						  struct wl_resource *resource,
1363 						  uint32_t id,
1364 						  struct wl_resource *surface_resource)
1365 {
1366 	struct weston_desktop_client *client =
1367 		wl_resource_get_user_data(resource);
1368 	struct weston_surface *wsurface =
1369 		wl_resource_get_user_data(surface_resource);
1370 	struct weston_desktop_xdg_surface *surface;
1371 
1372 	surface = zalloc(weston_desktop_surface_role_biggest_size);
1373 	if (surface == NULL) {
1374 		wl_client_post_no_memory(wl_client);
1375 		return;
1376 	}
1377 
1378 	surface->desktop = weston_desktop_client_get_desktop(client);
1379 	surface->surface = wsurface;
1380 	wl_list_init(&surface->configure_list);
1381 
1382 	surface->desktop_surface =
1383 		weston_desktop_surface_create(surface->desktop, client,
1384 					      surface->surface,
1385 					      &weston_desktop_xdg_surface_internal_implementation,
1386 					      surface);
1387 	if (surface->desktop_surface == NULL) {
1388 		free(surface);
1389 		return;
1390 	}
1391 
1392 	surface->resource =
1393 		weston_desktop_surface_add_resource(surface->desktop_surface,
1394 						    &zxdg_surface_v6_interface,
1395 						    &weston_desktop_xdg_surface_implementation,
1396 						    id, weston_desktop_xdg_surface_resource_destroy);
1397 	if (surface->resource == NULL)
1398 		return;
1399 
1400 	if (wsurface->buffer_ref.buffer != NULL) {
1401 		wl_resource_post_error(surface->resource,
1402 				       ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER,
1403 				       "xdg_surface must not have a buffer at creation");
1404 		return;
1405 	}
1406 }
1407 
1408 static void
weston_desktop_xdg_shell_protocol_pong(struct wl_client * wl_client,struct wl_resource * resource,uint32_t serial)1409 weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
1410 				       struct wl_resource *resource,
1411 				       uint32_t serial)
1412 {
1413 	struct weston_desktop_client *client =
1414 		wl_resource_get_user_data(resource);
1415 
1416 	weston_desktop_client_pong(client, serial);
1417 }
1418 
1419 static const struct zxdg_shell_v6_interface weston_desktop_xdg_shell_implementation = {
1420 	.destroy = weston_desktop_destroy_request,
1421 	.create_positioner = weston_desktop_xdg_shell_protocol_create_positioner,
1422 	.get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
1423 	.pong = weston_desktop_xdg_shell_protocol_pong,
1424 };
1425 
1426 static void
weston_desktop_xdg_shell_bind(struct wl_client * client,void * data,uint32_t version,uint32_t id)1427 weston_desktop_xdg_shell_bind(struct wl_client *client, void *data,
1428 			      uint32_t version, uint32_t id)
1429 {
1430 	struct weston_desktop *desktop = data;
1431 
1432 	weston_desktop_client_create(desktop, client, NULL,
1433 				     &zxdg_shell_v6_interface,
1434 				     &weston_desktop_xdg_shell_implementation,
1435 				     version, id);
1436 }
1437 
1438 struct wl_global *
weston_desktop_xdg_shell_v6_create(struct weston_desktop * desktop,struct wl_display * display)1439 weston_desktop_xdg_shell_v6_create(struct weston_desktop *desktop, struct wl_display *display)
1440 {
1441 	return wl_global_create(display, &zxdg_shell_v6_interface,
1442 				WD_XDG_SHELL_PROTOCOL_VERSION, desktop,
1443 				weston_desktop_xdg_shell_bind);
1444 }
1445