diff --git a/examples/compositor.c b/examples/compositor.c index 6f28b193..ae21697a 100644 --- a/examples/compositor.c +++ b/examples/compositor.c @@ -290,7 +290,7 @@ static void handle_output_frame(struct output_state *output, struct wlr_wl_shell_surface *wl_shell_surface; wl_list_for_each(wl_shell_surface, &sample->wl_shell->surfaces, link) { output_frame_handle_surface(sample, wlr_output, ts, - wl_shell_surface->surface, 200, 200); + wl_shell_surface->surface->resource, 200, 200); } struct wlr_xdg_surface_v6 *xdg_surface; struct wlr_xdg_client_v6 *xdg_client; diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 62050972..ef361d87 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -39,6 +39,7 @@ struct roots_desktop { struct wl_listener output_add; struct wl_listener output_remove; struct wl_listener xdg_shell_v6_surface; + struct wl_listener wl_shell_surface; }; struct roots_server; @@ -55,5 +56,6 @@ void output_add_notify(struct wl_listener *listener, void *data); void output_remove_notify(struct wl_listener *listener, void *data); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); +void handle_wl_shell_surface(struct wl_listener *listener, void *data); #endif diff --git a/include/rootston/view.h b/include/rootston/view.h index b74d1075..1010566a 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -6,8 +6,14 @@ #include struct roots_wl_shell_surface { - // TODO - void *_placeholder; + struct roots_view *view; + // TODO: Maybe destroy listener should go in roots_view + struct wl_listener destroy; + struct wl_listener ping_timeout; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_set_fullscreen; + struct wl_listener request_set_maximized; }; struct roots_xdg_surface_v6 { @@ -34,7 +40,7 @@ struct roots_view { // TODO: Something for roots-enforced width/height enum roots_view_type type; union { - struct wlr_shell_surface *wl_shell_surface; + struct wlr_wl_shell_surface *wl_shell_surface; struct wlr_xdg_surface_v6 *xdg_surface_v6; }; union { diff --git a/include/wlr/types/wlr_wl_shell.h b/include/wlr/types/wlr_wl_shell.h index 1443bbf0..11d30d95 100644 --- a/include/wlr/types/wlr_wl_shell.h +++ b/include/wlr/types/wlr_wl_shell.h @@ -1,26 +1,112 @@ #ifndef WLR_TYPES_WLR_WL_SHELL_H #define WLR_TYPES_WLR_WL_SHELL_H +#include #include struct wlr_wl_shell { struct wl_global *wl_global; struct wl_list wl_resources; struct wl_list surfaces; + uint32_t ping_timeout; + + struct { + struct wl_signal new_surface; + } events; void *data; }; +struct wlr_wl_shell_surface_transient_state { + struct wlr_wl_shell_surface *parent; + int32_t x; + int32_t y; + uint32_t flags; +}; + +struct wlr_wl_shell_surface_popup_state { + struct wlr_seat_handle *seat_handle; + uint32_t serial; +}; + +enum wlr_wl_shell_surface_role { + WLR_WL_SHELL_SURFACE_ROLE_NONE, + WLR_WL_SHELL_SURFACE_ROLE_TOPLEVEL, + WLR_WL_SHELL_SURFACE_ROLE_TRANSCIENT, + WLR_WL_SHELL_SURFACE_ROLE_POPUP, +}; + struct wlr_wl_shell_surface { - struct wl_resource *surface; - struct wlr_texture *wlr_texture; + struct wlr_wl_shell *shell; + struct wl_client *client; + struct wl_resource *resource; + struct wlr_surface *surface; struct wl_list link; + uint32_t ping_serial; + struct wl_event_source *ping_timer; + + enum wlr_wl_shell_surface_role role; + struct wlr_wl_shell_surface_transient_state *transient_state; + struct wlr_wl_shell_surface_popup_state *popup_state; + + char *title; + char *class; + + struct wl_listener surface_destroy_listener; + + struct { + struct wl_signal destroy; + struct wl_signal ping_timeout; + + struct wl_signal request_move; + struct wl_signal request_resize; + struct wl_signal request_set_fullscreen; + struct wl_signal request_set_maximized; + + struct wl_signal set_role; + struct wl_signal set_title; + struct wl_signal set_class; + } events; + void *data; }; +struct wlr_wl_shell_surface_move_event { + struct wl_client *client; + struct wlr_wl_shell_surface *surface; + struct wlr_seat_handle *seat_handle; + uint32_t serial; +}; + +struct wlr_wl_shell_surface_resize_event { + struct wl_client *client; + struct wlr_wl_shell_surface *surface; + struct wlr_seat_handle *seat_handle; + uint32_t serial; + uint32_t edges; +}; + +struct wlr_wl_shell_surface_set_fullscreen_event { + struct wl_client *client; + struct wlr_wl_shell_surface *surface; + uint32_t method; + uint32_t framerate; + struct wlr_output *output; +}; + +struct wlr_wl_shell_surface_set_maximized_event { + struct wl_client *client; + struct wlr_wl_shell_surface *surface; + struct wlr_output *output; +}; struct wlr_wl_shell *wlr_wl_shell_create(struct wl_display *display); void wlr_wl_shell_destroy(struct wlr_wl_shell *wlr_wl_shell); +void wlr_wl_shell_surface_ping(struct wlr_wl_shell_surface *surface); +void wlr_wl_shell_surface_configure(struct wlr_wl_shell_surface *surface, + uint32_t edges, int32_t width, int32_t height); +void wlr_wl_shell_surface_popup_done(struct wlr_wl_shell_surface *surface); + #endif diff --git a/rootston/desktop.c b/rootston/desktop.c index f0495fa1..f9af3b8e 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -67,7 +67,6 @@ struct roots_desktop *desktop_create(struct roots_server *server, desktop->layout = wlr_output_layout_create(); desktop->compositor = wlr_compositor_create( server->wl_display, server->renderer); - desktop->wl_shell = wlr_wl_shell_create(server->wl_display); wlr_cursor_attach_output_layout(server->input->cursor, desktop->layout); wlr_cursor_map_to_region(server->input->cursor, config->cursor.mapped_box); @@ -79,6 +78,11 @@ struct roots_desktop *desktop_create(struct roots_server *server, &desktop->xdg_shell_v6_surface); desktop->xdg_shell_v6_surface.notify = handle_xdg_shell_v6_surface; + desktop->wl_shell = wlr_wl_shell_create(server->wl_display); + wl_signal_add(&desktop->wl_shell->events.new_surface, + &desktop->wl_shell_surface); + desktop->wl_shell_surface.notify = handle_wl_shell_surface; + desktop->gamma_control_manager = wlr_gamma_control_manager_create( server->wl_display); diff --git a/rootston/meson.build b/rootston/meson.build index 30ae1548..6e9e0041 100644 --- a/rootston/meson.build +++ b/rootston/meson.build @@ -9,6 +9,7 @@ executable( 'main.c', 'output.c', 'pointer.c', - 'xdg_shell_v6.c' + 'xdg_shell_v6.c', + 'wl_shell.c', ], dependencies: wlroots ) diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c new file mode 100644 index 00000000..2b850d09 --- /dev/null +++ b/rootston/wl_shell.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "rootston/desktop.h" +#include "rootston/server.h" +#include "rootston/input.h" + +static void handle_move(struct wl_listener *listener, void *data) { + struct roots_wl_shell_surface *roots_surface = + wl_container_of(listener, roots_surface, request_move); + struct roots_view *view = roots_surface->view; + struct roots_input *input = view->desktop->server->input; + struct wlr_wl_shell_surface_move_event *e = data; + + // TODO: Some of this might want to live in cursor.c I guess + struct roots_input_event *event = NULL; + size_t len = sizeof(input->input_events) / sizeof(*input->input_events); + for (size_t i = 0; i < len; ++i) { + if (input->input_events[i].cursor + && input->input_events[i].serial == e->serial) { + event = &input->input_events[i]; + break; + } + } + if (!event || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + return; + } + input->mode = ROOTS_CURSOR_MOVE; + input->offs_x = input->cursor->x - view->x; + input->offs_y = input->cursor->y - view->y; + wlr_seat_pointer_clear_focus(input->wl_seat); +} + +static void handle_destroy(struct wl_listener *listener, void *data) { + struct roots_wl_shell_surface *roots_surface = + wl_container_of(listener, roots_surface, destroy); + wl_list_remove(&roots_surface->destroy.link); + wl_list_remove(&roots_surface->ping_timeout.link); + wl_list_remove(&roots_surface->request_move.link); + wl_list_remove(&roots_surface->request_resize.link); + wl_list_remove(&roots_surface->request_set_fullscreen.link); + wl_list_remove(&roots_surface->request_set_maximized.link); + view_destroy(roots_surface->view); + free(roots_surface); +} + +void handle_wl_shell_surface(struct wl_listener *listener, void *data) { + struct roots_desktop *desktop = + wl_container_of(listener, desktop, wl_shell_surface); + + struct wlr_wl_shell_surface *surface = data; + wlr_log(L_DEBUG, "new shell surface: title=%s, class=%s", + surface->title, surface->class); + wlr_wl_shell_surface_ping(surface); // TODO: segfaults + + struct roots_wl_shell_surface *roots_surface = + calloc(1, sizeof(struct roots_wl_shell_surface)); + // TODO: all of the trimmings + wl_list_init(&roots_surface->destroy.link); + roots_surface->destroy.notify = handle_destroy; + wl_signal_add(&surface->events.destroy, &roots_surface->destroy); + wl_list_init(&roots_surface->ping_timeout.link); + wl_list_init(&roots_surface->request_move.link); + roots_surface->request_move.notify = handle_move; + wl_signal_add(&surface->events.request_move, &roots_surface->request_move); + wl_list_init(&roots_surface->request_resize.link); + wl_list_init(&roots_surface->request_set_fullscreen.link); + wl_list_init(&roots_surface->request_set_maximized.link); + + struct roots_view *view = calloc(1, sizeof(struct roots_view)); + view->type = ROOTS_WL_SHELL_VIEW; + view->x = view->y = 200; + view->wl_shell_surface = surface; + view->roots_wl_shell_surface = roots_surface; + view->wlr_surface = surface->surface; + view->desktop = desktop; + roots_surface->view = view; + wl_list_insert(&desktop->views, &view->link); +} diff --git a/types/wlr_wl_shell.c b/types/wlr_wl_shell.c index 84b40fc3..99371fb4 100644 --- a/types/wlr_wl_shell.c +++ b/types/wlr_wl_shell.c @@ -1,61 +1,264 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif #include #include #include +#include #include #include +#include -static void shell_surface_pong(struct wl_client *client, struct wl_resource - *resource, uint32_t serial) { - wlr_log(L_DEBUG, "TODO: implement shell surface pong"); +static void shell_surface_pong(struct wl_client *client, + struct wl_resource *resource, uint32_t serial) { + wlr_log(L_DEBUG, "got shell surface pong"); + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + if (surface->ping_serial != serial) { + return; + } + + wl_event_source_timer_update(surface->ping_timer, 0); + surface->ping_serial = 0; } -static void shell_surface_move(struct wl_client *client, struct wl_resource - *resource, struct wl_resource *seat, uint32_t serial) { - wlr_log(L_DEBUG, "TODO: implement shell surface move"); +static void shell_surface_move(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial) { + wlr_log(L_DEBUG, "got shell surface move"); + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_seat_handle *seat_handle = + wl_resource_get_user_data(seat_resource); + + struct wlr_wl_shell_surface_move_event *event = + calloc(1, sizeof(struct wlr_wl_shell_surface_move_event)); + if (event == NULL) { + wl_client_post_no_memory(client); + return; + } + + event->client = client; + event->surface = surface; + event->seat_handle = seat_handle; + event->serial = serial; + + wl_signal_emit(&surface->events.request_move, event); + + free(event); } static void shell_surface_resize(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, - uint32_t edges) { - wlr_log(L_DEBUG, "TODO: implement shell surface resize"); + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial, uint32_t edges) { + wlr_log(L_DEBUG, "got shell surface resize"); + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_seat_handle *seat_handle = + wl_resource_get_user_data(seat_resource); + + struct wlr_wl_shell_surface_resize_event *event = + calloc(1, sizeof(struct wlr_wl_shell_surface_resize_event)); + if (event == NULL) { + wl_client_post_no_memory(client); + return; + } + + event->client = client; + event->surface = surface; + event->seat_handle = seat_handle; + event->serial = serial; + event->edges = edges; + + wl_signal_emit(&surface->events.request_resize, event); + + free(event); } static void shell_surface_set_toplevel(struct wl_client *client, struct wl_resource *resource) { - wlr_log(L_DEBUG, "TODO: implement shell surface set_toplevel"); + wlr_log(L_DEBUG, "got shell surface toplevel"); + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + + if (surface->role != WLR_WL_SHELL_SURFACE_ROLE_NONE) { + return; + } + + surface->role = WLR_WL_SHELL_SURFACE_ROLE_TOPLEVEL; + + wl_signal_emit(&surface->events.set_role, surface); } static void shell_surface_set_transient(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *parent, int32_t x, - int32_t y, uint32_t flags) { - wlr_log(L_DEBUG, "TODO: implement shell surface set_transient"); + struct wl_resource *resource, struct wl_resource *parent_resource, + int32_t x, int32_t y, uint32_t flags) { + wlr_log(L_DEBUG, "got shell surface transient"); + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *parent = + wl_resource_get_user_data(parent_resource); + // TODO: check if parent_resource == NULL? + + if (surface->role != WLR_WL_SHELL_SURFACE_ROLE_NONE) { + return; + } + + struct wlr_wl_shell_surface_transient_state *state = + calloc(1, sizeof(struct wlr_wl_shell_surface_transient_state)); + if (state == NULL) { + wl_client_post_no_memory(client); + return; + } + + state->parent = parent; + state->x = x; + state->y = y; + state->flags = flags; + + free(surface->transient_state); + surface->transient_state = state; + + surface->role = WLR_WL_SHELL_SURFACE_ROLE_TRANSCIENT; + + wl_signal_emit(&surface->events.set_role, surface); } static void shell_surface_set_fullscreen(struct wl_client *client, struct wl_resource *resource, uint32_t method, uint32_t framerate, - struct wl_resource *output) { - wlr_log(L_DEBUG, "TODO: implement shell surface set_fullscreen"); + struct wl_resource *output_resource) { + wlr_log(L_DEBUG, "got shell surface fullscreen"); + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_output *output = NULL; + if (output_resource != NULL) { + output = wl_resource_get_user_data(output_resource); + } + + if (surface->role == WLR_WL_SHELL_SURFACE_ROLE_TOPLEVEL) { + return; + } + + struct wlr_wl_shell_surface_set_fullscreen_event *event = + calloc(1, sizeof(struct wlr_wl_shell_surface_set_fullscreen_event)); + if (event == NULL) { + wl_client_post_no_memory(client); + return; + } + + event->client = client; + event->surface = surface; + event->method = method; + event->framerate = framerate; + event->output = output; + + wl_signal_emit(&surface->events.request_set_fullscreen, event); + + free(event); } static void shell_surface_set_popup(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, - struct wl_resource *parent, int32_t x, int32_t y, uint32_t flags) { - wlr_log(L_DEBUG, "TODO: implement shell surface set_popup"); + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial, struct wl_resource *parent_resource, int32_t x, int32_t y, + uint32_t flags) { + wlr_log(L_DEBUG, "got shell surface popup"); + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_seat_handle *seat_handle = + wl_resource_get_user_data(seat_resource); + struct wlr_wl_shell_surface *parent = + wl_resource_get_user_data(parent_resource); + // TODO: check if parent_resource == NULL? + + if (surface->role != WLR_WL_SHELL_SURFACE_ROLE_NONE) { + return; + } + + struct wlr_wl_shell_surface_transient_state *transcient_state = + calloc(1, sizeof(struct wlr_wl_shell_surface_transient_state)); + if (transcient_state == NULL) { + wl_client_post_no_memory(client); + return; + } + + transcient_state->parent = parent; + transcient_state->x = x; + transcient_state->y = y; + transcient_state->flags = flags; + + struct wlr_wl_shell_surface_popup_state *popup_state = + calloc(1, sizeof(struct wlr_wl_shell_surface_transient_state)); + if (popup_state == NULL) { + wl_client_post_no_memory(client); + return; + } + + popup_state->seat_handle = seat_handle; + popup_state->serial = serial; + + free(surface->transient_state); + surface->transient_state = transcient_state; + + free(surface->popup_state); + surface->popup_state = popup_state; + + surface->role = WLR_WL_SHELL_SURFACE_ROLE_POPUP; + + wl_signal_emit(&surface->events.set_role, surface); } static void shell_surface_set_maximized(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *output) { - wlr_log(L_DEBUG, "TODO: implement shell surface set_maximized"); + struct wl_resource *resource, struct wl_resource *output_resource) { + wlr_log(L_DEBUG, "got shell surface maximized"); + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_output *output = NULL; + if (output_resource != NULL) { + output = wl_resource_get_user_data(output_resource); + } + + if (surface->role == WLR_WL_SHELL_SURFACE_ROLE_TOPLEVEL) { + return; + } + + struct wlr_wl_shell_surface_set_maximized_event *event = + calloc(1, sizeof(struct wlr_wl_shell_surface_set_maximized_event)); + if (event == NULL) { + wl_client_post_no_memory(client); + return; + } + + event->client = client; + event->surface = surface; + event->output = output; + + wl_signal_emit(&surface->events.request_set_maximized, event); + + free(event); } static void shell_surface_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { - wlr_log(L_DEBUG, "TODO: implement shell surface set_title"); + wlr_log(L_DEBUG, "new shell surface title: %s", title); + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + + char *tmp = strdup(title); + if (tmp == NULL) { + return; + } + + free(surface->title); + surface->title = tmp; + + wl_signal_emit(&surface->events.set_title, surface); } static void shell_surface_set_class(struct wl_client *client, - struct wl_resource *resource, const char *class_) { - wlr_log(L_DEBUG, "TODO: implement shell surface set_class"); + struct wl_resource *resource, const char *class) { + wlr_log(L_DEBUG, "new shell surface class: %s", class); + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + + char *tmp = strdup(class); + if (tmp == NULL) { + return; + } + + free(surface->class); + surface->class = tmp; + + wl_signal_emit(&surface->events.set_class, surface); } struct wl_shell_surface_interface shell_surface_interface = { @@ -71,27 +274,86 @@ struct wl_shell_surface_interface shell_surface_interface = { .set_class = shell_surface_set_class, }; -static void destroy_shell_surface(struct wl_resource *resource) { - struct wlr_wl_shell_surface *state = wl_resource_get_user_data(resource); - wl_list_remove(&state->link); - free(state); +static void wl_shell_surface_destroy(struct wlr_wl_shell_surface *surface) { + wl_signal_emit(&surface->events.destroy, surface); + wl_resource_set_user_data(surface->resource, NULL); + wl_list_remove(&surface->link); + wl_list_remove(&surface->surface_destroy_listener.link); + free(surface->transient_state); + free(surface->popup_state); + free(surface->title); + free(surface->class); + free(surface); +} + +static void wl_shell_surface_resource_destroy(struct wl_resource *resource) { + struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + if (surface != NULL) { + wl_shell_surface_destroy(surface); + } +} + +static void handle_wlr_surface_destroyed(struct wl_listener *listener, + void *data) { + struct wlr_wl_shell_surface *surface = + wl_container_of(listener, surface, surface_destroy_listener); + wl_shell_surface_destroy(surface); +} + +static int wlr_wl_shell_surface_ping_timeout(void *user_data) { + struct wlr_wl_shell_surface *surface = user_data; + wl_signal_emit(&surface->events.ping_timeout, surface); + + surface->ping_serial = 0; + return 1; } static void wl_shell_get_shell_surface(struct wl_client *client, struct wl_resource *resource, uint32_t id, - struct wl_resource *surface) { - struct wlr_texture *wlr_texture = wl_resource_get_user_data(surface); - struct wlr_wl_shell *wlr_wl_shell = wl_resource_get_user_data(resource); - struct wlr_wl_shell_surface *state = + struct wl_resource *surface_resource) { + struct wlr_surface *surface = wl_resource_get_user_data(surface_resource); + struct wlr_wl_shell *wl_shell = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *wl_surface = calloc(1, sizeof(struct wlr_wl_shell_surface)); - state->wlr_texture = wlr_texture; - state->surface = surface; - struct wl_resource *shell_surface_resource = wl_resource_create(client, - &wl_shell_surface_interface, wl_resource_get_version(resource), id); - wlr_log(L_DEBUG, "New wl_shell %p (res %p)", state, shell_surface_resource); - wl_resource_set_implementation(shell_surface_resource, - &shell_surface_interface, state, destroy_shell_surface); - wl_list_insert(&wlr_wl_shell->surfaces, &state->link); + if (wl_surface == NULL) { + wl_client_post_no_memory(client); + return; + } + + wl_surface->shell = wl_shell; + wl_surface->client = client; + wl_surface->surface = surface; + + wl_surface->resource = wl_resource_create(client, &wl_shell_surface_interface, + wl_resource_get_version(resource), id); + wlr_log(L_DEBUG, "new wl_shell %p (res %p)", wl_surface, wl_surface->resource); + wl_resource_set_implementation(wl_surface->resource, + &shell_surface_interface, wl_surface, wl_shell_surface_resource_destroy); + + wl_signal_init(&wl_surface->events.destroy); + wl_signal_init(&wl_surface->events.ping_timeout); + wl_signal_init(&wl_surface->events.request_move); + wl_signal_init(&wl_surface->events.request_resize); + wl_signal_init(&wl_surface->events.request_set_fullscreen); + wl_signal_init(&wl_surface->events.request_set_maximized); + wl_signal_init(&wl_surface->events.set_role); + wl_signal_init(&wl_surface->events.set_title); + wl_signal_init(&wl_surface->events.set_class); + + wl_signal_add(&wl_surface->surface->signals.destroy, + &wl_surface->surface_destroy_listener); + wl_surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed; + + struct wl_display *display = wl_client_get_display(client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + wl_surface->ping_timer = wl_event_loop_add_timer(loop, + wlr_wl_shell_surface_ping_timeout, wl_surface); + if (wl_surface->ping_timer == NULL) { + wl_client_post_no_memory(client); + } + + wl_list_insert(&wl_shell->surfaces, &wl_surface->link); + wl_signal_emit(&wl_shell->events.new_surface, wl_surface); } static struct wl_shell_interface wl_shell_impl = { @@ -119,21 +381,22 @@ static void wl_shell_bind(struct wl_client *wl_client, void *_wl_shell, } struct wlr_wl_shell *wlr_wl_shell_create(struct wl_display *display) { - struct wlr_wl_shell *wlr_wl_shell = - calloc(1, sizeof(struct wlr_wl_shell)); - if (!wlr_wl_shell) { + struct wlr_wl_shell *wl_shell = calloc(1, sizeof(struct wlr_wl_shell)); + if (!wl_shell) { return NULL; } + wl_shell->ping_timeout = 10000; struct wl_global *wl_global = wl_global_create(display, - &wl_shell_interface, 1, wlr_wl_shell, wl_shell_bind); + &wl_shell_interface, 1, wl_shell, wl_shell_bind); if (!wl_global) { - free(wlr_wl_shell); + free(wl_shell); return NULL; } - wlr_wl_shell->wl_global = wl_global; - wl_list_init(&wlr_wl_shell->wl_resources); - wl_list_init(&wlr_wl_shell->surfaces); - return wlr_wl_shell; + wl_shell->wl_global = wl_global; + wl_list_init(&wl_shell->wl_resources); + wl_list_init(&wl_shell->surfaces); + wl_signal_init(&wl_shell->events.new_surface); + return wl_shell; } void wlr_wl_shell_destroy(struct wlr_wl_shell *wlr_wl_shell) { @@ -150,3 +413,25 @@ void wlr_wl_shell_destroy(struct wlr_wl_shell *wlr_wl_shell) { // wl_global_destroy(wlr_wl_shell->wl_global); free(wlr_wl_shell); } + +void wlr_wl_shell_surface_ping(struct wlr_wl_shell_surface *surface) { + if (surface->ping_serial != 0) { + // already pinged + return; + } + + surface->ping_serial = + wl_display_next_serial(wl_client_get_display(surface->client)); + wl_event_source_timer_update(surface->ping_timer, + surface->shell->ping_timeout); + wl_shell_surface_send_ping(surface->resource, surface->ping_serial); +} + +void wlr_wl_shell_surface_configure(struct wlr_wl_shell_surface *surface, + uint32_t edges, int32_t width, int32_t height) { + wl_shell_surface_send_configure(surface->resource, edges, width, height); +} + +void wlr_wl_shell_surface_popup_done(struct wlr_wl_shell_surface *surface) { + wl_shell_surface_send_popup_done(surface->resource); +}