main neuswc / libswc / xdg_shell.c
  1/* swc: libswc/xdg_shell.c
  2 *
  3 * Copyright (c) 2014, 2018 Michael Forney
  4 *
  5 * Permission is hereby granted, free of charge, to any person obtaining a copy
  6 * of this software and associated documentation files (the "Software"), to deal
  7 * in the Software without restriction, including without limitation the rights
  8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9 * copies of the Software, and to permit persons to whom the Software is
 10 * furnished to do so, subject to the following conditions:
 11 *
 12 * The above copyright notice and this permission notice shall be included in
 13 * all copies or substantial portions of the Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21 * SOFTWARE.
 22 */
 23
 24#include "xdg_shell.h"
 25#include "compositor.h"
 26#include "internal.h"
 27#include "seat.h"
 28#include "surface.h"
 29#include "util.h"
 30#include "window.h"
 31
 32#include "xdg-shell-server-protocol.h"
 33#include <assert.h>
 34#include <stdlib.h>
 35#include <wayland-server.h>
 36
 37struct xdg_surface {
 38	struct wl_resource *resource, *role;
 39	struct surface *surface;
 40	struct wl_listener surface_destroy_listener, role_destroy_listener;
 41	uint32_t configure_serial;
 42};
 43
 44struct xdg_positioner {
 45	int32_t width, height;
 46	int32_t anchor_x, anchor_y;
 47	int32_t anchor_width, anchor_height;
 48	enum xdg_positioner_anchor anchor;
 49	enum xdg_positioner_gravity gravity;
 50	enum xdg_positioner_constraint_adjustment constraint;
 51	int32_t offset_x, offset_y;
 52};
 53
 54struct xdg_toplevel {
 55	struct window window;
 56	struct wl_resource *resource;
 57	struct wl_array states;
 58	struct xdg_surface *xdg_surface;
 59};
 60
 61struct xdg_popup {
 62	struct wl_resource *resource;
 63	struct xdg_surface *xdg_surface;
 64	struct xdg_positioner positioner;
 65	struct compositor_view *view;
 66};
 67
 68/* xdg_positioner */
 69static void
 70destroy_positioner(struct wl_resource *resource)
 71{
 72	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
 73
 74	free(positioner);
 75}
 76
 77static void
 78set_size(struct wl_client *client, struct wl_resource *resource, int32_t width,
 79         int32_t height)
 80{
 81	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
 82
 83	if (width <= 0 || height <= 0) {
 84		wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT,
 85		                       "invalid size");
 86		return;
 87	}
 88	positioner->width = width;
 89	positioner->height = height;
 90}
 91
 92static void
 93set_anchor_rect(struct wl_client *client, struct wl_resource *resource,
 94                int32_t x, int32_t y, int32_t width, int32_t height)
 95{
 96	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
 97
 98	if (width <= 0 || height <= 0) {
 99		wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT,
100		                       "invalid anchor size");
101		return;
102	}
103	positioner->anchor_x = x;
104	positioner->anchor_y = y;
105	positioner->anchor_width = width;
106	positioner->anchor_height = height;
107}
108
109static void
110set_anchor(struct wl_client *client, struct wl_resource *resource,
111           uint32_t anchor)
112{
113	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
114
115	positioner->anchor = anchor;
116}
117
118static void
119set_gravity(struct wl_client *client, struct wl_resource *resource,
120            uint32_t gravity)
121{
122	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
123
124	positioner->gravity = gravity;
125}
126
127static void
128set_constraint_adjustment(struct wl_client *client,
129                          struct wl_resource *resource, uint32_t constraint)
130{
131	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
132
133	positioner->constraint = constraint;
134}
135
136static void
137set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x,
138           int32_t y)
139{
140	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
141
142	positioner->offset_x = x;
143	positioner->offset_y = y;
144}
145
146static const struct xdg_positioner_interface positioner_impl = {
147    .destroy = destroy_resource,
148    .set_size = set_size,
149    .set_anchor_rect = set_anchor_rect,
150    .set_anchor = set_anchor,
151    .set_gravity = set_gravity,
152    .set_constraint_adjustment = set_constraint_adjustment,
153    .set_offset = set_offset,
154};
155
156static struct swc_rectangle
157calculate_position(struct xdg_positioner *positioner)
158{
159	struct swc_rectangle r = {
160	    .x = positioner->offset_x,
161	    .y = positioner->offset_y,
162	    .width = positioner->width,
163	    .height = positioner->height,
164	};
165
166	switch (positioner->anchor) {
167	case XDG_POSITIONER_ANCHOR_TOP:
168	case XDG_POSITIONER_ANCHOR_TOP_LEFT:
169	case XDG_POSITIONER_ANCHOR_TOP_RIGHT:
170		r.y += positioner->anchor_y;
171		break;
172	case XDG_POSITIONER_ANCHOR_BOTTOM:
173	case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
174	case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
175		r.y += positioner->anchor_y + positioner->anchor_height;
176		break;
177	default:
178		r.y += positioner->anchor_y + positioner->anchor_height / 2;
179	}
180	switch (positioner->anchor) {
181	case XDG_POSITIONER_ANCHOR_LEFT:
182	case XDG_POSITIONER_ANCHOR_TOP_LEFT:
183	case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
184		r.x += positioner->anchor_x;
185		break;
186	case XDG_POSITIONER_ANCHOR_RIGHT:
187	case XDG_POSITIONER_ANCHOR_TOP_RIGHT:
188	case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
189		r.x += positioner->anchor_x + positioner->anchor_width;
190		break;
191	default:
192		r.x += positioner->anchor_x + positioner->anchor_width / 2;
193	}
194
195	switch (positioner->gravity) {
196	case XDG_POSITIONER_GRAVITY_TOP:
197	case XDG_POSITIONER_GRAVITY_TOP_LEFT:
198	case XDG_POSITIONER_GRAVITY_TOP_RIGHT:
199		r.y -= r.height;
200		break;
201	case XDG_POSITIONER_GRAVITY_BOTTOM:
202	case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT:
203	case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT:
204		break;
205	default:
206		r.y -= r.height / 2;
207	}
208	switch (positioner->gravity) {
209	case XDG_POSITIONER_GRAVITY_LEFT:
210	case XDG_POSITIONER_GRAVITY_TOP_LEFT:
211	case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT:
212		r.x -= r.width;
213		break;
214	case XDG_POSITIONER_GRAVITY_RIGHT:
215	case XDG_POSITIONER_GRAVITY_TOP_RIGHT:
216	case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT:
217		break;
218	default:
219		r.x -= r.width / 2;
220	}
221
222	return r;
223}
224
225/* xdg_toplevel */
226static void
227destroy_toplevel(struct wl_resource *resource)
228{
229	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource);
230
231	window_finalize(&toplevel->window);
232	free(toplevel);
233}
234
235static bool
236add_state(struct xdg_toplevel *toplevel, uint32_t state)
237{
238	uint32_t *current_state;
239
240	wl_array_for_each(current_state, &toplevel->states)
241	{
242		if (*current_state == state) {
243			return false;
244		}
245	}
246
247	if (!(current_state = wl_array_add(&toplevel->states, sizeof(state)))) {
248		WARNING("xdg_toplevel: Failed to allocate new state\n");
249		return false;
250	}
251
252	*current_state = state;
253	return true;
254}
255
256static bool
257remove_state(struct xdg_toplevel *toplevel, uint32_t state)
258{
259	uint32_t *current_state;
260
261	wl_array_for_each(current_state, &toplevel->states)
262	{
263		if (*current_state == state) {
264			array_remove(&toplevel->states, current_state, sizeof(state));
265			return true;
266		}
267	}
268
269	return false;
270}
271
272static uint32_t
273send_configure(struct xdg_toplevel *toplevel, int32_t width, int32_t height)
274{
275	uint32_t serial = wl_display_next_serial(swc.display);
276
277	if (width < 0) {
278		width = toplevel->window.configure.width;
279	}
280	if (height < 0) {
281		height = toplevel->window.configure.height;
282	}
283
284	xdg_toplevel_send_configure(toplevel->resource, width, height,
285	                            &toplevel->states);
286	xdg_surface_send_configure(toplevel->xdg_surface->resource, serial);
287
288	return serial;
289}
290
291static void
292configure(struct window *window, uint32_t width, uint32_t height)
293{
294	struct xdg_toplevel *toplevel = wl_container_of(window, toplevel, window);
295
296	window->configure.acknowledged = false;
297	toplevel->xdg_surface->configure_serial =
298	    send_configure(toplevel, width, height);
299}
300
301static void
302focus(struct window *window)
303{
304	struct xdg_toplevel *toplevel = wl_container_of(window, toplevel, window);
305	uint32_t width = window->view->base.geometry.width;
306	uint32_t height = window->view->base.geometry.height;
307
308	add_state(toplevel, XDG_TOPLEVEL_STATE_ACTIVATED);
309	/* dont send  0x0 on focus change */
310	send_configure(toplevel, width ? (int32_t)width : -1,
311	               height ? (int32_t)height : -1);
312}
313
314static void
315unfocus(struct window *window)
316{
317	struct xdg_toplevel *toplevel = wl_container_of(window, toplevel, window);
318	uint32_t width = window->view->base.geometry.width;
319	uint32_t height = window->view->base.geometry.height;
320
321	remove_state(toplevel, XDG_TOPLEVEL_STATE_ACTIVATED);
322	send_configure(toplevel, width ? (int32_t)width : -1,
323	               height ? (int32_t)height : -1);
324}
325
326static void
327close_(struct window *window)
328{
329	struct xdg_toplevel *toplevel = wl_container_of(window, toplevel, window);
330
331	xdg_toplevel_send_close(toplevel->resource);
332}
333
334static void
335set_mode(struct window *window, unsigned mode)
336{
337	struct xdg_toplevel *toplevel = wl_container_of(window, toplevel, window);
338
339	switch (window->mode) {
340	case WINDOW_MODE_TILED:
341		remove_state(toplevel, XDG_TOPLEVEL_STATE_MAXIMIZED);
342		break;
343	case WINDOW_MODE_FULLSCREEN:
344		remove_state(toplevel, XDG_TOPLEVEL_STATE_FULLSCREEN);
345		break;
346	}
347
348	switch (mode) {
349	case WINDOW_MODE_TILED:
350		add_state(toplevel, XDG_TOPLEVEL_STATE_MAXIMIZED);
351		break;
352	case WINDOW_MODE_FULLSCREEN:
353		add_state(toplevel, XDG_TOPLEVEL_STATE_FULLSCREEN);
354		break;
355	}
356
357	send_configure(toplevel, -1, -1);
358}
359
360static const struct window_impl toplevel_window_impl = {
361    .configure = configure,
362    .focus = focus,
363    .unfocus = unfocus,
364    .close = close_,
365    .set_mode = set_mode,
366};
367
368static void
369set_parent(struct wl_client *client, struct wl_resource *resource,
370           struct wl_resource *parent_resource)
371{
372	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource),
373	                    *parent = NULL;
374
375	if (parent_resource) {
376		parent = wl_resource_get_user_data(parent_resource);
377	}
378	window_set_parent(&toplevel->window, parent ? &parent->window : NULL);
379}
380
381static void
382set_title(struct wl_client *client, struct wl_resource *resource,
383          const char *title)
384{
385	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource);
386	window_set_title(&toplevel->window, title, -1);
387}
388
389static void
390set_app_id(struct wl_client *client, struct wl_resource *resource,
391           const char *app_id)
392{
393	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource);
394	window_set_app_id(&toplevel->window, app_id);
395}
396
397static void
398show_window_menu(struct wl_client *client, struct wl_resource *resource,
399                 struct wl_resource *seat, uint32_t serial, int32_t x,
400                 int32_t y)
401{
402}
403
404static void
405move(struct wl_client *client, struct wl_resource *resource,
406     struct wl_resource *seat, uint32_t serial)
407{
408	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource);
409	struct button *button;
410
411	button = pointer_get_button(swc.seat->pointer, serial);
412	if (button) {
413		window_begin_move(&toplevel->window, button);
414	}
415}
416
417static void
418resize(struct wl_client *client, struct wl_resource *resource,
419       struct wl_resource *seat, uint32_t serial, uint32_t edges)
420{
421	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource);
422	struct button *button;
423
424	button = pointer_get_button(swc.seat->pointer, serial);
425	if (button) {
426		window_begin_resize(&toplevel->window, edges, button);
427	}
428}
429
430static void
431set_max_size(struct wl_client *client, struct wl_resource *resource,
432             int32_t width, int32_t height)
433{
434}
435
436static void
437set_min_size(struct wl_client *client, struct wl_resource *resource,
438             int32_t width, int32_t height)
439{
440}
441
442static void
443set_maximized(struct wl_client *client, struct wl_resource *resource)
444{
445}
446
447static void
448unset_maximized(struct wl_client *client, struct wl_resource *resource)
449{
450}
451
452static void
453set_fullscreen(struct wl_client *client, struct wl_resource *resource,
454               struct wl_resource *output)
455{
456}
457
458static void
459unset_fullscreen(struct wl_client *client, struct wl_resource *resource)
460{
461}
462
463static void
464set_minimized(struct wl_client *client, struct wl_resource *resource)
465{
466}
467
468static const struct xdg_toplevel_interface toplevel_impl = {
469    .destroy = destroy_resource,
470    .set_parent = set_parent,
471    .set_title = set_title,
472    .set_app_id = set_app_id,
473    .show_window_menu = show_window_menu,
474    .move = move,
475    .resize = resize,
476    .set_max_size = set_max_size,
477    .set_min_size = set_min_size,
478    .set_maximized = set_maximized,
479    .unset_maximized = unset_maximized,
480    .set_fullscreen = set_fullscreen,
481    .unset_fullscreen = unset_fullscreen,
482    .set_minimized = set_minimized,
483};
484
485static struct xdg_toplevel *
486xdg_toplevel_new(struct wl_client *client, uint32_t version, uint32_t id,
487                 struct xdg_surface *xdg_surface)
488{
489	struct xdg_toplevel *toplevel;
490
491	toplevel = malloc(sizeof(*toplevel));
492	if (!toplevel) {
493		goto error0;
494	}
495	toplevel->xdg_surface = xdg_surface;
496	toplevel->resource =
497	    wl_resource_create(client, &xdg_toplevel_interface, version, id);
498	if (!toplevel->resource) {
499		goto error1;
500	}
501	if (!surface_set_role(xdg_surface->surface, toplevel->resource)) {
502		goto error2;
503	}
504	if (!window_initialize(&toplevel->window, &toplevel_window_impl,
505	                       xdg_surface->surface)) {
506		goto error2;
507	}
508	wl_array_init(&toplevel->states);
509	wl_resource_set_implementation(toplevel->resource, &toplevel_impl, toplevel,
510	                               &destroy_toplevel);
511	window_manage(&toplevel->window);
512
513	return toplevel;
514
515error2:
516	wl_resource_destroy(toplevel->resource);
517	free(toplevel);
518error1:
519error0:
520	return NULL;
521}
522
523/* xdg_popup */
524static void
525destroy_popup(struct wl_resource *resource)
526{
527	struct xdg_popup *popup = wl_resource_get_user_data(resource);
528
529	compositor_view_destroy(popup->view);
530	free(popup);
531}
532
533static void
534grab(struct wl_client *client, struct wl_resource *resource,
535     struct wl_resource *seat, uint32_t serial)
536{
537}
538
539static const struct xdg_popup_interface popup_impl = {
540    .destroy = destroy_resource,
541    .grab = grab,
542};
543
544static struct xdg_popup *
545xdg_popup_new(struct wl_client *client, uint32_t version, uint32_t id,
546              struct xdg_surface *xdg_surface, struct xdg_surface *parent,
547              struct xdg_positioner *positioner)
548{
549	struct xdg_popup *popup;
550	struct compositor_view *parent_view =
551	    compositor_view(parent->surface->view);
552	uint32_t serial = wl_display_next_serial(swc.display);
553	struct swc_rectangle rect;
554
555	if (!parent_view) {
556		goto error0;
557	}
558	popup = malloc(sizeof(*popup));
559	if (!popup) {
560		goto error0;
561	}
562	popup->xdg_surface = xdg_surface;
563	popup->positioner = *positioner;
564	popup->resource =
565	    wl_resource_create(client, &xdg_popup_interface, version, id);
566	if (!popup->resource) {
567		goto error1;
568	}
569	if (!surface_set_role(xdg_surface->surface, popup->resource)) {
570		goto error2;
571	}
572	popup->view = compositor_create_view(xdg_surface->surface);
573	if (!popup->view) {
574		goto error3;
575	}
576	wl_resource_set_implementation(popup->resource, &popup_impl, popup,
577	                               &destroy_popup);
578
579	rect = calculate_position(positioner);
580	compositor_view_set_parent(popup->view, parent_view);
581	view_move(&popup->view->base, parent_view->base.geometry.x + rect.x,
582	          parent_view->base.geometry.y + rect.y);
583	xdg_popup_send_configure(popup->resource, rect.x, rect.y, rect.width,
584	                         rect.height);
585	xdg_surface_send_configure(xdg_surface->resource, serial);
586
587	return popup;
588
589error3:
590	wl_resource_destroy(popup->resource);
591error2:
592	free(popup);
593error1:
594error0:
595	return NULL;
596}
597
598/* xdg_surface */
599static void
600get_toplevel(struct wl_client *client, struct wl_resource *resource,
601             uint32_t id)
602{
603	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
604	struct xdg_toplevel *toplevel;
605
606	if (xdg_surface->role) {
607		wl_resource_post_error(resource, XDG_WM_BASE_ERROR_ROLE,
608		                       "surface already has a role");
609		return;
610	}
611	if (xdg_surface->surface->role) {
612		wl_resource_post_error(resource, XDG_WM_BASE_ERROR_ROLE,
613		                       "surface already has a role");
614		return;
615	}
616	toplevel = xdg_toplevel_new(client, wl_resource_get_version(resource), id,
617	                            xdg_surface);
618	if (!toplevel) {
619		wl_client_post_no_memory(client);
620		return;
621	}
622	xdg_surface->role = toplevel->resource;
623	wl_resource_add_destroy_listener(xdg_surface->role,
624	                                 &xdg_surface->role_destroy_listener);
625}
626
627static void
628get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id,
629          struct wl_resource *parent_resource,
630          struct wl_resource *positioner_resource)
631{
632	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
633	struct xdg_surface *parent = wl_resource_get_user_data(parent_resource);
634	struct xdg_positioner *positioner =
635	    wl_resource_get_user_data(positioner_resource);
636	struct xdg_popup *popup;
637
638	if (xdg_surface->role) {
639		wl_resource_post_error(resource, XDG_WM_BASE_ERROR_ROLE,
640		                       "surface already has a role");
641		return;
642	}
643	if (xdg_surface->surface->role) {
644		wl_resource_post_error(resource, XDG_WM_BASE_ERROR_ROLE,
645		                       "surface already has a role");
646		return;
647	}
648	popup = xdg_popup_new(client, wl_resource_get_version(resource), id,
649	                      xdg_surface, parent, positioner);
650	if (!popup) {
651		wl_client_post_no_memory(client);
652		return;
653	}
654	xdg_surface->role = popup->resource;
655	wl_resource_add_destroy_listener(xdg_surface->role,
656	                                 &xdg_surface->role_destroy_listener);
657}
658
659static void
660ack_configure(struct wl_client *client, struct wl_resource *resource,
661              uint32_t serial)
662{
663	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
664	struct window *window;
665
666	if (!xdg_surface->role) {
667		return;
668	}
669	window = wl_resource_get_user_data(xdg_surface->role);
670	if (window && serial == xdg_surface->configure_serial) {
671		window->configure.acknowledged = true;
672	}
673}
674
675static void
676set_window_geometry(struct wl_client *client, struct wl_resource *resource,
677                    int32_t x, int32_t y, int32_t width, int32_t height)
678{
679	(void)client;
680	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
681	struct surface *surface = xdg_surface->surface;
682
683	if (width <= 0 || height <= 0) {
684		surface->has_window_geometry = false;
685		return;
686	}
687
688	surface->has_window_geometry = true;
689	surface->window_x = x;
690	surface->window_y = y;
691	surface->window_width = width;
692	surface->window_height = height;
693	if (!surface->window_geometry_applied && surface->view &&
694	    (x != 0 || y != 0)) {
695		struct swc_rectangle *geom = &surface->view->geometry;
696		view_move(surface->view, geom->x - x, geom->y - y);
697		surface->window_geometry_applied = true;
698	}
699}
700
701static const struct xdg_surface_interface xdg_surface_impl = {
702    .destroy = destroy_resource,
703    .get_toplevel = get_toplevel,
704    .get_popup = get_popup,
705    .ack_configure = ack_configure,
706    .set_window_geometry = set_window_geometry,
707};
708
709static void
710handle_surface_destroy(struct wl_listener *listener, void *data)
711{
712	struct xdg_surface *xdg_surface =
713	    wl_container_of(listener, xdg_surface, surface_destroy_listener);
714
715	wl_resource_destroy(xdg_surface->resource);
716}
717
718static void
719handle_role_destroy(struct wl_listener *listener, void *data)
720{
721	struct xdg_surface *xdg_surface =
722	    wl_container_of(listener, xdg_surface, role_destroy_listener);
723
724	xdg_surface->role = NULL;
725}
726
727static void
728destroy_xdg_surface(struct wl_resource *resource)
729{
730	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
731
732	wl_list_remove(&xdg_surface->surface_destroy_listener.link);
733	if (xdg_surface->role) {
734		wl_resource_destroy(xdg_surface->role);
735	}
736	free(xdg_surface);
737}
738
739static struct xdg_surface *
740xdg_surface_new(struct wl_client *client, uint32_t version, uint32_t id,
741                struct surface *surface)
742{
743	struct xdg_surface *xdg_surface;
744
745	xdg_surface = malloc(sizeof(*xdg_surface));
746	if (!xdg_surface) {
747		goto error0;
748	}
749	xdg_surface->resource =
750	    wl_resource_create(client, &xdg_surface_interface, version, id);
751	if (!xdg_surface->resource) {
752		goto error1;
753	}
754	xdg_surface->surface = surface;
755	xdg_surface->surface_destroy_listener.notify = &handle_surface_destroy;
756	xdg_surface->role = NULL;
757	xdg_surface->role_destroy_listener.notify = &handle_role_destroy;
758	wl_resource_add_destroy_listener(surface->resource,
759	                                 &xdg_surface->surface_destroy_listener);
760	wl_resource_set_implementation(xdg_surface->resource, &xdg_surface_impl,
761	                               xdg_surface, destroy_xdg_surface);
762
763	return xdg_surface;
764
765error1:
766	free(xdg_surface);
767error0:
768	return NULL;
769}
770
771/* xdg_shell */
772static void
773create_positioner(struct wl_client *client, struct wl_resource *resource,
774                  uint32_t id)
775{
776	struct xdg_positioner *positioner;
777	struct wl_resource *positioner_resource;
778	uint32_t version;
779
780	positioner = calloc(1, sizeof(*positioner));
781	if (!positioner) {
782		goto error0;
783	}
784
785	version = wl_resource_get_version(resource);
786	positioner_resource =
787	    wl_resource_create(client, &xdg_positioner_interface, version, id);
788	if (!positioner_resource) {
789		goto error1;
790	}
791	wl_resource_set_implementation(positioner_resource, &positioner_impl,
792	                               positioner, &destroy_positioner);
793	return;
794
795error1:
796	free(positioner);
797error0:
798	wl_resource_post_no_memory(resource);
799}
800
801static void
802get_xdg_surface(struct wl_client *client, struct wl_resource *resource,
803                uint32_t id, struct wl_resource *surface_resource)
804{
805	struct xdg_surface *xdg_surface;
806	struct surface *surface = wl_resource_get_user_data(surface_resource);
807
808	xdg_surface =
809	    xdg_surface_new(client, wl_resource_get_version(resource), id, surface);
810	if (!xdg_surface) {
811		wl_client_post_no_memory(client);
812	}
813}
814
815static void
816pong(struct wl_client *client, struct wl_resource *resource, uint32_t serial)
817{
818}
819
820static const struct xdg_wm_base_interface wm_base_impl = {
821    .destroy = destroy_resource,
822    .create_positioner = create_positioner,
823    .get_xdg_surface = get_xdg_surface,
824    .pong = pong,
825};
826
827static void
828bind_wm_base(struct wl_client *client, void *data, uint32_t version,
829             uint32_t id)
830{
831	struct wl_resource *resource;
832
833	resource = wl_resource_create(client, &xdg_wm_base_interface, version, id);
834	if (!resource) {
835		wl_client_post_no_memory(client);
836		return;
837	}
838	wl_resource_set_implementation(resource, &wm_base_impl, NULL, NULL);
839}
840
841struct wl_global *
842xdg_shell_create(struct wl_display *display)
843{
844	return wl_global_create(display, &xdg_wm_base_interface, 1, NULL,
845	                        &bind_wm_base);
846}