9 static const struct wl_shell_surface_interface shell_surface_impl;
11 static void reset_shell_surface(struct ds_shell_surface *shell_surface);
12 static void shell_surface_handle_surface_destroy(struct wl_listener *listener,
14 static void shell_surface_handle_surface_commit(struct wl_listener *listener,
16 static void shell_surface_handle_resource_destroy(struct wl_resource *resource);
17 static void shell_surface_configure_destroy(struct ds_shell_surface_configure *configure);
18 static void surface_send_configure(void *user_data);
19 static void handle_shell_surface_commit(struct ds_surface *surface);
22 ds_shell_surface_add_destroy_listener(struct ds_shell_surface *shell_surface,
23 struct wl_listener *listener)
25 wl_signal_add(&shell_surface->events.destroy, listener);
29 ds_shell_surface_add_map_listener(struct ds_shell_surface *shell_surface,
30 struct wl_listener *listener)
32 wl_signal_add(&shell_surface->events.map, listener);
36 ds_shell_surface_add_unmap_listener(struct ds_shell_surface *shell_surface,
37 struct wl_listener *listener)
39 wl_signal_add(&shell_surface->events.unmap, listener);
42 WL_EXPORT struct ds_surface *
43 ds_shell_surface_get_surface(struct ds_shell_surface *shell_surface)
45 return shell_surface->surface;
48 static const struct ds_surface_role shell_surface_role =
50 .name = "shell_surface",
51 .commit = handle_shell_surface_commit,
54 struct ds_shell_surface *
55 create_shell_surface(struct ds_shell_client *client, struct ds_surface *surface,
58 struct ds_shell_surface *shell_surface;
60 shell_surface = calloc(1, sizeof *shell_surface);
62 wl_client_post_no_memory(client->wl_client);
66 shell_surface->client = client;
67 shell_surface->role = DS_SHELL_SURFACE_ROLE_NONE;
68 shell_surface->surface = surface;
69 shell_surface->resource = wl_resource_create(client->wl_client,
70 &wl_shell_surface_interface, wl_resource_get_version(client->resource),
72 if (!shell_surface->resource) {
74 wl_client_post_no_memory(client->wl_client);
78 if (!ds_surface_set_role(shell_surface->surface, &shell_surface_role,
79 shell_surface, shell_surface->resource, -1)) {
84 wl_list_init(&shell_surface->configure_list);
86 wl_signal_init(&shell_surface->events.destroy);
87 wl_signal_init(&shell_surface->events.ping_timeout);
88 wl_signal_init(&shell_surface->events.new_popup);
89 wl_signal_init(&shell_surface->events.map);
90 wl_signal_init(&shell_surface->events.unmap);
91 wl_signal_init(&shell_surface->events.configure);
93 shell_surface->listener.surface_destroy.notify =
94 shell_surface_handle_surface_destroy;
95 ds_surface_add_destroy_listener(surface,
96 &shell_surface->listener.surface_destroy);
98 shell_surface->listener.surface_commit.notify =
99 shell_surface_handle_surface_commit;
100 ds_surface_add_commit_listener(surface,
101 &shell_surface->listener.surface_commit);
103 wl_resource_set_implementation(shell_surface->resource, &shell_surface_impl,
104 shell_surface, shell_surface_handle_resource_destroy);
106 wl_list_insert(&client->shell_surfaces, &shell_surface->link);
108 ds_inf("New shell_surface %p (res %p)", shell_surface, shell_surface->resource);
110 return shell_surface;
114 destroy_shell_surface(struct ds_shell_surface *shell_surface)
116 reset_shell_surface(shell_surface);
118 wl_resource_set_user_data(shell_surface->resource, NULL);
120 ds_surface_reset_role_data(shell_surface->surface);
122 wl_list_remove(&shell_surface->link);
123 wl_list_remove(&shell_surface->listener.surface_destroy.link);
124 wl_list_remove(&shell_surface->listener.surface_commit.link);
130 unmap_shell_surface(struct ds_shell_surface *shell_surface)
132 struct ds_shell_surface_configure *configure, *tmp;
136 if (shell_surface->mapped)
137 wl_signal_emit(&shell_surface->events.unmap, shell_surface);
139 switch (shell_surface->role) {
140 case DS_SHELL_SURFACE_ROLE_TOPLEVEL:
141 if (shell_surface->toplevel->parent) {
142 wl_list_remove(&shell_surface->toplevel->parent_unmap.link);
143 shell_surface->toplevel->parent = NULL;
145 free(shell_surface->toplevel->title);
146 shell_surface->toplevel->title = NULL;
147 free(shell_surface->toplevel->app_id);
148 shell_surface->toplevel->app_id = NULL;
150 case DS_SHELL_SURFACE_ROLE_POPUP:
153 case DS_SHELL_SURFACE_ROLE_NONE:
154 assert(false && "not reached");
157 wl_list_for_each_safe(configure, tmp, &shell_surface->configure_list, link)
158 shell_surface_configure_destroy(configure);
160 if (shell_surface->configure_idle) {
161 wl_event_source_remove(shell_surface->configure_idle);
162 shell_surface->configure_idle = NULL;
165 shell_surface->configured = false;
166 shell_surface->mapped = false;
170 reset_shell_surface(struct ds_shell_surface *shell_surface)
172 struct ds_shell_toplevel_requested *req;
174 if (shell_surface->role != DS_SHELL_SURFACE_ROLE_NONE)
175 unmap_shell_surface(shell_surface);
177 if (shell_surface->added) {
178 wl_signal_emit(&shell_surface->events.destroy, shell_surface);
179 shell_surface->added = false;
182 switch (shell_surface->role) {
183 case DS_SHELL_SURFACE_ROLE_TOPLEVEL:
184 req = &shell_surface->toplevel->requested;
185 if (req->fullscreen_output)
186 wl_list_remove(&req->fullscreen_output_destroy.link);
187 free(shell_surface->toplevel);
188 shell_surface->toplevel = NULL;
190 case DS_SHELL_SURFACE_ROLE_POPUP:
193 case DS_SHELL_SURFACE_ROLE_NONE:
194 // This space is intentionally left blank
198 shell_surface->role = DS_SHELL_SURFACE_ROLE_NONE;
202 ds_shell_surface_schedule_configure(struct ds_shell_surface *shell_surface)
204 struct wl_display *display;
205 struct wl_event_loop *loop;
207 display = wl_client_get_display(shell_surface->client->wl_client);
208 loop = wl_display_get_event_loop(display);
210 if (!shell_surface->configure_idle) {
211 shell_surface->scheduled_serial = wl_display_next_serial(display);
212 shell_surface->configure_idle = wl_event_loop_add_idle(loop,
213 surface_send_configure, shell_surface);
214 if (!shell_surface->configure_idle)
215 wl_client_post_no_memory(shell_surface->client->wl_client);
218 return shell_surface->scheduled_serial;
222 handle_shell_surface_commit(struct ds_surface *surface)
224 struct ds_shell_surface *shell_surface;
226 shell_surface = ds_surface_get_role_data(surface);
227 shell_surface->current = shell_surface->pending;
229 switch (shell_surface->role) {
230 case DS_SHELL_SURFACE_ROLE_NONE:
231 // inert toplevel or popup
233 case DS_SHELL_SURFACE_ROLE_TOPLEVEL:
234 if (!shell_surface->toplevel->added) {
235 ds_shell_surface_schedule_configure(shell_surface);
236 shell_surface->toplevel->added = true;
240 case DS_SHELL_SURFACE_ROLE_POPUP:
245 if (!shell_surface->added) {
246 shell_surface->added = true;
247 wl_signal_emit(&shell_surface->client->shell->events.new_surface, shell_surface);
250 if (shell_surface->configured &&
251 ds_surface_has_buffer(shell_surface->surface) &&
252 !shell_surface->mapped) {
253 shell_surface->mapped = true;
254 wl_signal_emit(&shell_surface->events.map, shell_surface);
258 void handle_shell_surface_precommit(struct ds_surface *surface)
260 struct ds_shell_surface *shell_surface;
262 shell_surface = ds_surface_get_role_data(surface);
269 ds_shell_surface_ping(struct ds_shell_surface *shell_surface)
274 shell_surface_handle_surface_destroy(struct wl_listener *listener, void *data)
276 struct ds_shell_surface *shell_surface;
278 shell_surface = wl_container_of(listener, shell_surface, listener.surface_destroy);
279 destroy_shell_surface(shell_surface);
283 shell_surface_handle_surface_commit(struct wl_listener *listener, void *data)
285 struct ds_shell_surface *shell_surface;
287 shell_surface = wl_container_of(listener, shell_surface, listener.surface_commit);
289 if (ds_surface_has_buffer(shell_surface->surface) &&
290 !shell_surface->configured) {
291 wl_resource_post_error(shell_surface->resource,
293 "shell_surface has never been configured");
297 if (!ds_surface_get_role(shell_surface->surface)) {
298 wl_resource_post_error(shell_surface->resource,
300 "shell_surface must have a role");
306 shell_surface_handle_resource_destroy(struct wl_resource *resource)
308 struct ds_shell_surface *shell_surface;
310 shell_surface = wl_resource_get_user_data(resource);
314 destroy_shell_surface(shell_surface);
318 shell_surface_configure_destroy(struct ds_shell_surface_configure *configure)
320 wl_list_remove(&configure->link);
325 create_shell_surface_toplevel(struct ds_shell_surface *shell_surface)
327 assert(shell_surface->toplevel == NULL);
329 shell_surface->toplevel = calloc(1, sizeof *shell_surface->toplevel);
330 if (!shell_surface->toplevel) {
331 wl_resource_post_no_memory(shell_surface->resource);
335 shell_surface->toplevel->base = shell_surface;
337 wl_signal_init(&shell_surface->toplevel->events.request_maximize);
338 wl_signal_init(&shell_surface->toplevel->events.request_fullscreen);
339 wl_signal_init(&shell_surface->toplevel->events.request_minimize);
340 wl_signal_init(&shell_surface->toplevel->events.request_move);
341 wl_signal_init(&shell_surface->toplevel->events.request_resize);
342 wl_signal_init(&shell_surface->toplevel->events.request_show_window_menu);
343 wl_signal_init(&shell_surface->toplevel->events.set_parent);
344 wl_signal_init(&shell_surface->toplevel->events.set_title);
345 wl_signal_init(&shell_surface->toplevel->events.set_app_id);
347 shell_surface->role = DS_SHELL_SURFACE_ROLE_TOPLEVEL;
351 shell_surface_handle_pong(struct wl_client *wl_client,
352 struct wl_resource *resource, uint32_t serial)
354 struct ds_shell_surface *shell_surface;
355 struct ds_shell_client *client;
357 shell_surface = wl_resource_get_user_data(resource);
359 client = shell_surface->client;
360 if (client->ping_serial != serial)
363 wl_event_source_timer_update(client->ping_timer, 0);
364 client->ping_serial = 0;
368 shell_surface_handle_move(struct wl_client *client,
369 struct wl_resource *resource, struct wl_resource *seat_resource,
372 struct ds_shell_surface *shell_surface;
374 shell_surface = wl_resource_get_user_data(resource);
381 shell_surface_handle_resize(struct wl_client *client,
382 struct wl_resource *resource, struct wl_resource *seat_resource,
383 uint32_t serial, uint32_t edges)
385 struct ds_shell_surface *shell_surface;
387 shell_surface = wl_resource_get_user_data(resource);
394 shell_surface_handle_set_toplevel(struct wl_client *client, struct wl_resource *resource)
396 struct ds_shell_surface *shell_surface;
398 shell_surface = wl_resource_get_user_data(resource);
399 create_shell_surface_toplevel(shell_surface);
403 shell_surface_handle_set_transient(struct wl_client *client,
404 struct wl_resource *resource, struct wl_resource *parent_resource,
405 int32_t x, int32_t y, uint32_t flags)
407 struct ds_shell_surface *shell_surface;
409 shell_surface = wl_resource_get_user_data(resource);
413 ds_err("Not implemented yet.");
417 shell_surface_handle_set_fullscreen(struct wl_client *client,
418 struct wl_resource *resource, uint32_t method, uint32_t framerate,
419 struct wl_resource *output_resource)
421 struct ds_shell_surface *shell_surface;
423 shell_surface = wl_resource_get_user_data(resource);
427 ds_err("Not implemented yet.");
431 shell_surface_handle_set_popup(struct wl_client *client,
432 struct wl_resource *resource, struct wl_resource *seat_resource,
433 uint32_t serial, struct wl_resource *parent_resource,
434 int32_t x, int32_t y, uint32_t flags)
436 struct ds_shell_surface *shell_surface;
438 shell_surface = wl_resource_get_user_data(resource);
442 ds_err("Not implemented yet.");
446 shell_surface_handle_set_maximized(struct wl_client *client,
447 struct wl_resource *resource, struct wl_resource *output_resource)
449 struct ds_shell_surface *shell_surface;
451 shell_surface = wl_resource_get_user_data(resource);
453 shell_surface->toplevel->requested.maximized = true;
454 wl_signal_emit(&shell_surface->toplevel->events.request_maximize, shell_surface);
455 ds_shell_surface_schedule_configure(shell_surface);
459 shell_surface_handle_set_title(struct wl_client *client,
460 struct wl_resource *resource, const char *title)
462 struct ds_shell_surface *shell_surface;
465 shell_surface = wl_resource_get_user_data(resource);
468 wl_resource_post_no_memory(resource);
472 if (shell_surface->toplevel->title)
473 free(shell_surface->toplevel->title);
475 shell_surface->toplevel->title = tmp;
476 wl_signal_emit(&shell_surface->toplevel->events.set_title, shell_surface);
480 shell_surface_handle_set_class(struct wl_client *client,
481 struct wl_resource *resource, const char *clas)
483 struct ds_shell_surface *shell_surface;
485 shell_surface = wl_resource_get_user_data(resource);
489 ds_err("Not implemented yet.");
492 static const struct wl_shell_surface_interface shell_surface_impl =
494 .pong = shell_surface_handle_pong,
495 .move = shell_surface_handle_move,
496 .resize = shell_surface_handle_resize,
497 .set_toplevel = shell_surface_handle_set_toplevel,
498 .set_transient = shell_surface_handle_set_transient,
499 .set_fullscreen = shell_surface_handle_set_fullscreen,
500 .set_popup = shell_surface_handle_set_popup,
501 .set_maximized = shell_surface_handle_set_maximized,
502 .set_title = shell_surface_handle_set_title,
503 .set_class = shell_surface_handle_set_class,
507 surface_send_configure(void *user_data)
509 struct ds_shell_surface *shell_surface;
510 struct ds_shell_surface_configure *configure;
511 uint32_t width, height;
514 shell_surface = user_data;
515 shell_surface->configure_idle = NULL;
517 // TDOO: Not sure if shell needs the struct ds_shell_surface_configure.
518 configure = calloc(1, sizeof *configure);
520 wl_client_post_no_memory(shell_surface->client->wl_client);
524 wl_list_insert(shell_surface->configure_list.prev, &configure->link);
525 configure->serial = shell_surface->scheduled_serial;
526 configure->shell_surface = shell_surface;
528 wl_signal_emit(&shell_surface->events.configure, configure);
530 edges = (WL_SHELL_SURFACE_RESIZE_TOP | WL_SHELL_SURFACE_RESIZE_LEFT); // fixed default value
531 width = shell_surface->current.geometry.width;
532 height = shell_surface->current.geometry.height;
534 wl_shell_surface_send_configure(shell_surface->resource, edges, width, height);
536 shell_surface->configured = true;
538 // TDOO: Not sure if shell needs the struct ds_shell_surface_configure.
539 shell_surface_configure_destroy(configure);