8 static const struct xdg_surface_interface xdg_surface_impl;
10 static void xdg_surface_handle_surface_destroy(struct wl_listener *listener,
12 static void xdg_surface_handle_surface_commit(struct wl_listener *listener,
14 static void xdg_surface_handle_resource_destroy(struct wl_resource *resource);
15 static void xdg_surface_configure_destroy(struct ds_xdg_surface_configure *configure);
16 static void surface_send_configure(void *user_data);
19 ds_xdg_surface_add_destroy_listener(struct ds_xdg_surface *surface,
20 struct wl_listener *listener)
22 wl_signal_add(&surface->events.destroy, listener);
26 ds_xdg_surface_add_map_listener(struct ds_xdg_surface *surface,
27 struct wl_listener *listener)
29 wl_signal_add(&surface->events.map, listener);
33 ds_xdg_surface_add_unmap_listener(struct ds_xdg_surface *surface,
34 struct wl_listener *listener)
36 wl_signal_add(&surface->events.unmap, listener);
40 ds_xdg_surface_get_surface(struct ds_xdg_surface *surface)
42 return surface->ds_surface;
45 struct ds_xdg_surface *
46 create_xdg_surface(struct ds_xdg_client *client, struct ds_surface *ds_surface,
49 struct ds_xdg_surface *surface;
51 surface = calloc(1, sizeof *surface);
53 wl_client_post_no_memory(client->wl_client);
57 surface->client = client;
58 surface->role = DS_XDG_SURFACE_ROLE_NONE;
59 surface->ds_surface = ds_surface;
60 surface->resource = wl_resource_create(client->wl_client,
61 &xdg_surface_interface, wl_resource_get_version(client->resource),
63 if (!surface->resource) {
65 wl_client_post_no_memory(client->wl_client);
69 if (ds_surface_has_buffer(surface->ds_surface)) {
70 wl_resource_destroy(surface->resource);
72 wl_resource_post_error(client->resource,
73 XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER,
74 "xdg_surface must not have a buffer at creation");
78 wl_list_init(&surface->configure_list);
80 wl_signal_init(&surface->events.destroy);
81 wl_signal_init(&surface->events.ping_timeout);
82 wl_signal_init(&surface->events.new_popup);
83 wl_signal_init(&surface->events.map);
84 wl_signal_init(&surface->events.unmap);
85 wl_signal_init(&surface->events.configure);
86 wl_signal_init(&surface->events.ack_configure);
88 surface->listener.surface_destroy.notify =
89 xdg_surface_handle_surface_destroy;
90 ds_surface_add_destroy_listener(ds_surface,
91 &surface->listener.surface_destroy);
93 surface->listener.surface_commit.notify =
94 xdg_surface_handle_surface_commit;
95 ds_surface_add_commit_listener(ds_surface,
96 &surface->listener.surface_commit);
98 wl_resource_set_implementation(surface->resource, &xdg_surface_impl,
99 surface, xdg_surface_handle_resource_destroy);
101 wl_list_insert(&client->surfaces, &surface->link);
103 ds_inf("New xdg_surface %p (res %p)", surface, surface->resource);
109 unmap_xdg_surface(struct ds_xdg_surface *surface)
111 struct ds_xdg_surface_configure *configure, *tmp;
116 wl_signal_emit(&surface->events.unmap, surface);
118 switch (surface->role) {
119 case DS_XDG_SURFACE_ROLE_TOPLEVEL:
120 if (surface->toplevel->parent) {
121 wl_list_remove(&surface->toplevel->parent_unmap.link);
122 surface->toplevel->parent = NULL;
124 free(surface->toplevel->title);
125 surface->toplevel->title = NULL;
126 free(surface->toplevel->app_id);
127 surface->toplevel->app_id = NULL;
129 case DS_XDG_SURFACE_ROLE_POPUP:
132 case DS_XDG_SURFACE_ROLE_NONE:
133 assert(false && "not reached");
136 wl_list_for_each_safe(configure, tmp, &surface->configure_list, link)
137 xdg_surface_configure_destroy(configure);
139 if (surface->configure_idle) {
140 wl_event_source_remove(surface->configure_idle);
141 surface->configure_idle = NULL;
144 surface->configured = false;
145 surface->mapped = false;
149 reset_xdg_surface(struct ds_xdg_surface *surface)
151 struct ds_xdg_toplevel_requested *req;
153 if (surface->role != DS_XDG_SURFACE_ROLE_NONE)
154 unmap_xdg_surface(surface);
156 if (surface->added) {
157 wl_signal_emit(&surface->events.destroy, surface);
158 surface->added = false;
161 switch (surface->role) {
162 case DS_XDG_SURFACE_ROLE_TOPLEVEL:
163 wl_resource_set_user_data(surface->toplevel->resource, NULL);
164 surface->toplevel->resource = NULL;
165 req = &surface->toplevel->requested;
166 if (req->fullscreen_output)
167 wl_list_remove(&req->fullscreen_output_destroy.link);
168 free(surface->toplevel);
169 surface->toplevel = NULL;
171 case DS_XDG_SURFACE_ROLE_POPUP:
174 case DS_XDG_SURFACE_ROLE_NONE:
175 // This space is intentionally left blank
179 surface->role = DS_XDG_SURFACE_ROLE_NONE;
183 destroy_xdg_surface(struct ds_xdg_surface *surface)
185 reset_xdg_surface(surface);
187 wl_resource_set_user_data(surface->resource, NULL);
189 ds_surface_reset_role_data(surface->ds_surface);
191 wl_list_remove(&surface->link);
192 wl_list_remove(&surface->listener.surface_destroy.link);
193 wl_list_remove(&surface->listener.surface_commit.link);
199 handle_xdg_surface_commit(struct ds_surface *ds_surface)
201 struct ds_xdg_surface *surface;
203 surface = ds_surface_get_role_data(ds_surface);
204 surface->current = surface->pending;
206 switch (surface->role) {
207 case DS_XDG_SURFACE_ROLE_NONE:
208 // inert toplevel or popup
210 case DS_XDG_SURFACE_ROLE_TOPLEVEL:
211 handle_xdg_surface_toplevel_committed(surface);
214 case DS_XDG_SURFACE_ROLE_POPUP:
219 if (!surface->added) {
220 surface->added = true;
221 wl_signal_emit(&surface->client->shell->events.new_surface, surface);
224 if (surface->configured &&
225 ds_surface_has_buffer(surface->ds_surface) &&
227 surface->mapped = true;
228 wl_signal_emit(&surface->events.map, surface);
232 void handle_xdg_surface_precommit(struct ds_surface *ds_surface)
234 struct ds_xdg_surface *surface;
236 surface = ds_surface_get_role_data(ds_surface);
243 ds_xdg_surface_schedule_configure(struct ds_xdg_surface *surface)
245 struct wl_display *display;
246 struct wl_event_loop *loop;
248 display = wl_client_get_display(surface->client->wl_client);
249 loop = wl_display_get_event_loop(display);
251 if (!surface->configure_idle) {
252 surface->scheduled_serial = wl_display_next_serial(display);
253 surface->configure_idle = wl_event_loop_add_idle(loop,
254 surface_send_configure, surface);
255 if (!surface->configure_idle)
256 wl_client_post_no_memory(surface->client->wl_client);
259 return surface->scheduled_serial;
263 ds_xdg_surface_ping(struct ds_xdg_surface *surface)
268 xdg_surface_handle_surface_destroy(struct wl_listener *listener, void *data)
270 struct ds_xdg_surface *surface;
272 surface = wl_container_of(listener, surface, listener.surface_destroy);
273 destroy_xdg_surface(surface);
277 xdg_surface_handle_surface_commit(struct wl_listener *listener, void *data)
279 struct ds_xdg_surface *surface;
281 surface = wl_container_of(listener, surface, listener.surface_commit);
283 if (ds_surface_has_buffer(surface->ds_surface) &&
284 !surface->configured) {
285 wl_resource_post_error(surface->resource,
286 XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER,
287 "xdg_surface has never been configured");
291 if (!ds_surface_get_role(surface->ds_surface)) {
292 wl_resource_post_error(surface->resource,
293 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
294 "xdg_surface must have a role");
300 xdg_surface_handle_resource_destroy(struct wl_resource *resource)
302 struct ds_xdg_surface *surface;
304 surface = wl_resource_get_user_data(resource);
308 destroy_xdg_surface(surface);
312 xdg_surface_configure_destroy(struct ds_xdg_surface_configure *configure)
314 wl_list_remove(&configure->link);
315 free(configure->toplevel_configure);
320 xdg_surface_handle_destroy(struct wl_client *client,
321 struct wl_resource *resource)
323 struct ds_xdg_surface *surface;
325 surface = wl_resource_get_user_data(resource);
327 if (surface->role != DS_XDG_SURFACE_ROLE_NONE) {
328 ds_err("Tried to destroy an xdg_surface before its role object");
332 wl_resource_destroy(resource);
336 xdg_surface_handle_get_toplevel(struct wl_client *client,
337 struct wl_resource *resource, uint32_t id)
339 struct ds_xdg_surface *surface;
341 surface = wl_resource_get_user_data(resource);
342 create_xdg_toplevel(surface, id);
346 xdg_surface_handle_get_popup(struct wl_client *client,
347 struct wl_resource *resource, uint32_t id,
348 struct wl_resource *parent_resource,
349 struct wl_resource *positioner_resource)
351 struct ds_xdg_surface *surface;
353 surface = wl_resource_get_user_data(resource);
360 xdg_surface_handle_ack_configure(struct wl_client *client,
361 struct wl_resource *resource, uint32_t serial)
363 struct ds_xdg_surface *surface;
365 surface = wl_resource_get_user_data(resource);
367 if (surface->role == DS_XDG_SURFACE_ROLE_NONE) {
368 wl_resource_post_error(surface->resource,
369 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
370 "xdg_surface must have a role");
375 struct ds_xdg_surface_configure *configure, *tmp;
376 wl_list_for_each(configure, &surface->configure_list, link) {
377 if (configure->serial == serial) {
384 wl_resource_post_error(surface->client->resource,
385 XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
386 "wrong configure serial: %u", serial);
390 wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) {
391 if (configure->serial == serial)
394 wl_signal_emit(&surface->events.ack_configure, configure);
395 xdg_surface_configure_destroy(configure);
398 switch (surface->role) {
399 case DS_XDG_SURFACE_ROLE_NONE:
400 assert(0 && "not reached");
402 case DS_XDG_SURFACE_ROLE_TOPLEVEL:
405 case DS_XDG_SURFACE_ROLE_POPUP:
409 surface->configured = true;
410 surface->pending.configure_serial = serial;
412 wl_signal_emit(&surface->events.ack_configure, configure);
413 xdg_surface_configure_destroy(configure);
417 xdg_surface_handle_set_window_geometry(struct wl_client *client,
418 struct wl_resource *resource,
419 int32_t x, int32_t y, int32_t width, int32_t height)
421 struct ds_xdg_surface *surface;
423 surface = wl_resource_get_user_data(resource);
425 if (surface->role == DS_XDG_SURFACE_ROLE_NONE) {
426 wl_resource_post_error(surface->resource,
427 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
428 "xdg_surface must have a role");
432 if (width <= 0 || height <= 0) {
433 ds_err("Client tried to set invalid geometry");
434 wl_resource_post_error(resource, -1,
435 "Tried to set invalid xdg_surface geometry");
439 surface->pending.geometry.x = x;
440 surface->pending.geometry.y = y;
441 surface->pending.geometry.width = width;
442 surface->pending.geometry.height = height;
445 static const struct xdg_surface_interface xdg_surface_impl =
447 .destroy = xdg_surface_handle_destroy,
448 .get_toplevel = xdg_surface_handle_get_toplevel,
449 .get_popup = xdg_surface_handle_get_popup,
450 .ack_configure = xdg_surface_handle_ack_configure,
451 .set_window_geometry = xdg_surface_handle_set_window_geometry,
455 surface_send_configure(void *user_data)
457 struct ds_xdg_surface *surface;
458 struct ds_xdg_surface_configure *configure;
461 surface->configure_idle = NULL;
463 configure = calloc(1, sizeof *configure);
465 wl_client_post_no_memory(surface->client->wl_client);
469 wl_list_insert(surface->configure_list.prev, &configure->link);
470 configure->serial = surface->scheduled_serial;
471 configure->surface = surface;
473 switch (surface->role) {
474 case DS_XDG_SURFACE_ROLE_NONE:
475 assert(0 && "not reached");
477 case DS_XDG_SURFACE_ROLE_TOPLEVEL:
478 send_xdg_toplevel_configure(surface, configure);
480 case DS_XDG_SURFACE_ROLE_POPUP:
484 wl_signal_emit(&surface->events.configure, configure);
486 xdg_surface_send_configure(surface->resource, configure->serial);