diff options
| author | Drew DeVault <sir@cmpwn.com> | 2017-09-17 09:45:21 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-09-17 09:45:21 -0400 | 
| commit | 29539645ccaa6ff0d4eb304e1a5d5ac8f65447a2 (patch) | |
| tree | 3b22d6f061e635a2fa1ef8189a4087097577fe69 | |
| parent | 94da69a0647eb00cdb2862a88c777b78d2934874 (diff) | |
| parent | f46befec7c9c1561d2325df2325008a8a4e36328 (diff) | |
| download | wlroots-29539645ccaa6ff0d4eb304e1a5d5ac8f65447a2.tar.xz | |
Merge pull request #145 from acrisci/feature/xdg-shell-toplevel
xdg shell toplevel
| -rw-r--r-- | examples/compositor.c | 127 | ||||
| -rw-r--r-- | include/wlr/types/wlr_surface.h | 9 | ||||
| -rw-r--r-- | include/wlr/types/wlr_xdg_shell_v6.h | 158 | ||||
| -rw-r--r-- | types/wlr_surface.c | 23 | ||||
| -rw-r--r-- | types/wlr_xdg_shell_v6.c | 724 | 
5 files changed, 955 insertions, 86 deletions
| diff --git a/examples/compositor.c b/examples/compositor.c index 995c1b7d..fb5d8dfd 100644 --- a/examples/compositor.c +++ b/examples/compositor.c @@ -56,6 +56,19 @@ struct sample_state {  	struct wl_listener cursor_motion_absolute;  	struct wl_listener cursor_button;  	struct wl_listener cursor_axis; + +	struct wl_listener new_xdg_surface_v6; +}; + +struct example_xdg_surface_v6 { +	struct wlr_xdg_surface_v6 *surface; + +	struct wl_listener destroy_listener; +	struct wl_listener ping_timeout_listener; +	struct wl_listener request_minimize_listener; +	struct wl_listener request_move_listener; +	struct wl_listener request_resize_listener; +	struct wl_listener request_show_window_menu_listener;  };  /* @@ -85,6 +98,103 @@ static void output_frame_handle_surface(struct sample_state *sample,  		}  	}  } + +static void handle_xdg_surface_v6_ping_timeout(struct wl_listener *listener, +		void *data) { +	struct wlr_xdg_surface_v6 *surface = data; +	wlr_log(L_DEBUG, "got ping timeout for surface: %s", surface->title); +} + +static void handle_xdg_surface_v6_destroy(struct wl_listener *listener, +		void *data) { +	struct example_xdg_surface_v6 *example_surface = +		wl_container_of(listener, example_surface, destroy_listener); +	wl_list_remove(&example_surface->destroy_listener.link); +	wl_list_remove(&example_surface->ping_timeout_listener.link); +	wl_list_remove(&example_surface->request_move_listener.link); +	wl_list_remove(&example_surface->request_resize_listener.link); +	wl_list_remove(&example_surface->request_show_window_menu_listener.link); +	wl_list_remove(&example_surface->request_minimize_listener.link); +	free(example_surface); +} + +static void handle_xdg_surface_v6_request_move(struct wl_listener *listener, +		void *data) { +	struct example_xdg_surface_v6 *example_surface = +		wl_container_of(listener, example_surface, request_move_listener); +	struct wlr_xdg_toplevel_v6_move_event *e = data; +	wlr_log(L_DEBUG, "TODO: surface requested move: %s", e->surface->title); +} + +static void handle_xdg_surface_v6_request_resize(struct wl_listener *listener, +		void *data) { +	struct example_xdg_surface_v6 *example_surface = +		wl_container_of(listener, example_surface, request_resize_listener); +	struct wlr_xdg_toplevel_v6_resize_event *e = data; +	wlr_log(L_DEBUG, "TODO: surface requested resize: %s", e->surface->title); +} + +static void handle_xdg_surface_v6_request_show_window_menu( +		struct wl_listener *listener, void *data) { +	struct example_xdg_surface_v6 *example_surface = +		wl_container_of(listener, example_surface, +			request_show_window_menu_listener); +	struct wlr_xdg_toplevel_v6_show_window_menu_event *e = data; +	wlr_log(L_DEBUG, "TODO: surface requested to show window menu: %s", +		e->surface->title); +} + +static void handle_xdg_surface_v6_request_minimize( +		struct wl_listener *listener, void *data) { +	struct example_xdg_surface_v6 *example_surface = +		wl_container_of(listener, example_surface, request_minimize_listener); +	wlr_log(L_DEBUG, "TODO: surface requested to be minimized: %s", +		example_surface->surface->title); +} + +static void handle_new_xdg_surface_v6(struct wl_listener *listener, +		void *data) { +	struct wlr_xdg_surface_v6 *surface = data; +	wlr_log(L_DEBUG, "new xdg surface: title=%s, app_id=%s", +		surface->title, surface->app_id); + +	wlr_xdg_surface_v6_ping(surface); + +	struct example_xdg_surface_v6 *esurface = +		calloc(1, sizeof(struct example_xdg_surface_v6)); +	if (esurface == NULL) { +		return; +	} + +	esurface->surface = surface; + +	wl_signal_add(&surface->events.destroy, &esurface->destroy_listener); +	esurface->destroy_listener.notify = handle_xdg_surface_v6_destroy; + +	wl_signal_add(&surface->events.ping_timeout, +		&esurface->ping_timeout_listener); +	esurface->ping_timeout_listener.notify = handle_xdg_surface_v6_ping_timeout; + +	wl_signal_add(&surface->events.request_move, +		&esurface->request_move_listener); +	esurface->request_move_listener.notify = handle_xdg_surface_v6_request_move; + +	wl_signal_add(&surface->events.request_resize, +		&esurface->request_resize_listener); +	esurface->request_resize_listener.notify = +		handle_xdg_surface_v6_request_resize; + +	wl_signal_add(&surface->events.request_show_window_menu, +		&esurface->request_show_window_menu_listener); +	esurface->request_show_window_menu_listener.notify = +		handle_xdg_surface_v6_request_show_window_menu; + +	wl_signal_add(&surface->events.request_minimize, +		&esurface->request_minimize_listener); +	esurface->request_minimize_listener.notify = +		handle_xdg_surface_v6_request_minimize; +} +  static void handle_output_frame(struct output_state *output,  		struct timespec *ts) {  	struct compositor_state *state = output->compositor; @@ -100,9 +210,12 @@ static void handle_output_frame(struct output_state *output,  			wl_shell_surface->surface);  	}  	struct wlr_xdg_surface_v6 *xdg_surface; -	wl_list_for_each(xdg_surface, &sample->xdg_shell->surfaces, link) { -		output_frame_handle_surface(sample, wlr_output, ts, -			xdg_surface->surface); +	struct wlr_xdg_client_v6 *xdg_client; +	wl_list_for_each(xdg_client, &sample->xdg_shell->clients, link) { +		wl_list_for_each(xdg_surface, &xdg_client->surfaces, link) { +			output_frame_handle_surface(sample, wlr_output, ts, +					xdg_surface->surface->resource); +		}  	}  	struct wlr_x11_window *x11_window;  	wl_list_for_each(x11_window, &sample->xwayland->displayable_windows, link) { @@ -309,6 +422,12 @@ int main(int argc, char *argv[]) {  	state.wl_shell = wlr_wl_shell_create(compositor.display);  	state.xdg_shell = wlr_xdg_shell_v6_create(compositor.display); +	// shell events +	wl_signal_add(&state.xdg_shell->events.new_surface, +		&state.new_xdg_surface_v6); +	state.new_xdg_surface_v6.notify = handle_new_xdg_surface_v6; + +  	state.data_device_manager =  		wlr_data_device_manager_create(compositor.display); @@ -341,6 +460,8 @@ int main(int argc, char *argv[]) {  	wl_display_run(compositor.display); +	wl_list_remove(&state.new_xdg_surface_v6.link); +  	wlr_xwayland_destroy(state.xwayland);  	close(state.keymap_fd);  	wlr_seat_destroy(state.wl_seat); diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index f0765160..d76fff16 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -42,6 +42,7 @@ struct wlr_surface {  	struct {  		struct wl_signal commit; +		struct wl_signal destroy;  	} signals;  	struct wl_list frame_callback_list; // wl_surface.frame @@ -69,4 +70,12 @@ void wlr_surface_get_matrix(struct wlr_surface *surface,  		const float (*projection)[16],  		const float (*transform)[16]); + +/** + * Set the lifetime role for this surface. Returns 0 on success or -1 if the + * role cannot be set. + */ +int wlr_surface_set_role(struct wlr_surface *surface, const char *role, +		struct wl_resource *error_resource, uint32_t error_code); +  #endif diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 41cf483a..786bf4e6 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -1,24 +1,174 @@  #ifndef _WLR_XDG_SHELL_V6_H  #define _WLR_XDG_SHELL_V6_H +#include <wlr/types/wlr_box.h>  #include <wayland-server.h>  struct wlr_xdg_shell_v6 {  	struct wl_global *wl_global; -	struct wl_list wl_resources; -	struct wl_list surfaces; +	struct wl_list clients; +	uint32_t ping_timeout; + +	struct { +		struct wl_signal new_surface; +	} events;  	void *data;  }; +struct wlr_xdg_client_v6 { +	struct wlr_xdg_shell_v6 *shell; +	struct wl_resource *resource; +	struct wl_client *client; +	struct wl_list surfaces; + +	struct wl_list link; // wlr_xdg_shell_v6::clients + +	uint32_t ping_serial; +	struct wl_event_source *ping_timer; +}; + + +enum wlr_xdg_surface_v6_role { +	WLR_XDG_SURFACE_V6_ROLE_NONE, +	WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL, +	WLR_XDG_SURFACE_V6_ROLE_POPUP, +}; + +struct wlr_xdg_toplevel_v6_state { +	bool maximized; +	bool fullscreen; +	bool resizing; +	bool activated; + +	uint32_t width; +	uint32_t height; + +	uint32_t max_width; +	uint32_t max_height; + +	uint32_t min_width; +	uint32_t min_height; +}; + +struct wlr_xdg_toplevel_v6 { +	struct wl_resource *resource; +	struct wlr_xdg_surface_v6 *base; +	struct wlr_xdg_surface_v6 *parent; +	bool added; +	struct wlr_xdg_toplevel_v6_state next; // client protocol requests +	struct wlr_xdg_toplevel_v6_state pending; // user configure requests +	struct wlr_xdg_toplevel_v6_state current; +}; + +// TODO split up into toplevel and popup configure +struct wlr_xdg_surface_v6_configure { +	struct wl_list link; // wlr_xdg_surface_v6::configure_list +	uint32_t serial; +	struct wlr_xdg_toplevel_v6_state state; +}; +  struct wlr_xdg_surface_v6 { +	struct wlr_xdg_client_v6 *client;  	struct wl_resource *resource; -	struct wl_resource *surface; -	struct wl_list link; +	struct wlr_surface *surface; +	struct wl_list link; // wlr_xdg_client_v6::surfaces +	enum wlr_xdg_surface_v6_role role; +	struct wlr_xdg_toplevel_v6 *toplevel_state; + +	bool configured; +	struct wl_event_source *configure_idle; +	struct wl_list configure_list; + +	char *title; +	char *app_id; + +	bool has_next_geometry; +	struct wlr_box *next_geometry; +	struct wlr_box *geometry; + +	struct wl_listener surface_destroy_listener; +	struct wl_listener surface_commit_listener; + +	struct { +		struct wl_signal commit; +		struct wl_signal destroy; +		struct wl_signal ack_configure; +		struct wl_signal ping_timeout; + +		struct wl_signal request_minimize; +		struct wl_signal request_move; +		struct wl_signal request_resize; +		struct wl_signal request_show_window_menu; +	} events;  	void *data;  }; +struct wlr_xdg_toplevel_v6_move_event { +	struct wl_client *client; +	struct wlr_xdg_surface_v6 *surface; +	struct wlr_seat_handle *seat_handle; +	uint32_t serial; +}; + +struct wlr_xdg_toplevel_v6_resize_event { +	struct wl_client *client; +	struct wlr_xdg_surface_v6 *surface; +	struct wlr_seat_handle *seat_handle; +	uint32_t serial; +	uint32_t edges; +}; + +struct wlr_xdg_toplevel_v6_show_window_menu_event { +	struct wl_client *client; +	struct wlr_xdg_surface_v6 *surface; +	struct wlr_seat_handle *seat_handle; +	uint32_t serial; +	uint32_t x; +	uint32_t y; +}; +  struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display);  void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell); +/** + * Send a ping to the surface. If the surface does not respond in a reasonable + * amount of time, the ping_timeout event will be emitted. + */ +void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface); + +/** + * Request that this toplevel surface be the given size. + */ +void wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, +		uint32_t width, uint32_t height); + +/** + * Request that this toplevel surface show itself in an activated or deactivated + * state. + */ +void wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, +		bool activated); + +/** + * Request that this toplevel surface consider itself maximized or not + * maximized. + */ +void wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, +		bool maximized); + +/** + * Request that this toplevel surface consider itself fullscreen or not + * fullscreen. + */ +void wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, +		bool fullscreen); + +/** + * Request that this toplevel surface consider itself to be resizing or not + * resizing. + */ +void wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, +		bool resizing); +  #endif diff --git a/types/wlr_surface.c b/types/wlr_surface.c index e733c544..a9a54abe 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -365,6 +365,7 @@ const struct wl_surface_interface surface_interface = {  static void destroy_surface(struct wl_resource *resource) {  	struct wlr_surface *surface = wl_resource_get_user_data(resource); +	wl_signal_emit(&surface->signals.destroy, surface);  	wlr_texture_destroy(surface->texture);  	struct wlr_frame_callback *cb, *next; @@ -399,6 +400,7 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res,  	pixman_region32_init(&surface->pending.opaque);  	pixman_region32_init(&surface->pending.input);  	wl_signal_init(&surface->signals.commit); +	wl_signal_init(&surface->signals.destroy);  	wl_list_init(&surface->frame_callback_list);  	wl_resource_set_implementation(res, &surface_interface,  		surface, destroy_surface); @@ -420,3 +422,24 @@ void wlr_surface_get_matrix(struct wlr_surface *surface,  	wlr_matrix_mul(matrix, &scale, matrix);  	wlr_matrix_mul(projection, matrix, matrix);  } + +int wlr_surface_set_role(struct wlr_surface *surface, const char *role, +		struct wl_resource *error_resource, uint32_t error_code) { +	assert(role); + +	if (surface->role == NULL || +			surface->role == role || +			strcmp(surface->role, role) == 0) { +		surface->role = role; + +		return 0; +	} + +	wl_resource_post_error(error_resource, error_code, +		"Cannot assign role %s to wl_surface@%d, already has role %s\n", +		role, +		wl_resource_get_id(surface->resource), +		surface->role); + +	return -1; +} diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index b5df9bd8..a7450add 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -1,111 +1,266 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif  #include <assert.h>  #include <stdlib.h> +#include <string.h>  #include <wayland-server.h>  #include <wlr/types/wlr_xdg_shell_v6.h> +#include <wlr/types/wlr_surface.h> +#include <wlr/types/wlr_seat.h>  #include <wlr/util/log.h>  #include "xdg-shell-unstable-v6-protocol.h" -static void resource_destroy(struct wl_client *client, struct wl_resource *resource) { -	// TODO: we probably need to do more than this +static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel"; + +static void resource_destroy(struct wl_client *client, +		struct wl_resource *resource) {  	wl_resource_destroy(resource);  } -static void xdg_toplevel_set_parent(struct wl_client *client, +static void xdg_toplevel_protocol_set_parent(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *parent_resource) { -	wlr_log(L_DEBUG, "TODO: toplevel set parent"); +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	struct wlr_xdg_surface_v6 *parent = NULL; + +	if (parent_resource != NULL) { +		parent = wl_resource_get_user_data(parent_resource); +	} + +	surface->toplevel_state->parent = parent;  } -static void xdg_toplevel_set_title(struct wl_client *client, +static void xdg_toplevel_protocol_set_title(struct wl_client *client,  		struct wl_resource *resource, const char *title) { -	wlr_log(L_DEBUG, "TODO: toplevel set title"); +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	char *tmp; + +	tmp = strdup(title); +	if (tmp == NULL) { +		return; +	} + +	free(surface->title); +	surface->title = tmp;  } -static void xdg_toplevel_set_app_id(struct wl_client *client, +static void xdg_toplevel_protocol_set_app_id(struct wl_client *client,  		struct wl_resource *resource, const char *app_id) { -	wlr_log(L_DEBUG, "TODO: toplevel set app id"); +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	char *tmp; + +	tmp = strdup(app_id); +	if (tmp == NULL) { +		return; +	} + +	free(surface->app_id); +	surface->app_id = tmp;  } -static void xdg_toplevel_show_window_menu(struct wl_client *client, -		struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, -		int32_t x, int32_t y) { -	wlr_log(L_DEBUG, "TODO: toplevel show window menu"); +static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, +		struct wl_resource *resource, struct wl_resource *seat_resource, +		uint32_t serial, int32_t x, int32_t y) { +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	struct wlr_seat_handle *seat_handle = +		wl_resource_get_user_data(seat_resource); + +	if (!surface->configured) { +		wl_resource_post_error(surface->toplevel_state->resource, +			ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, +			"surface has not been configured yet"); +		return; +	} + +	struct wlr_xdg_toplevel_v6_show_window_menu_event *event = +		calloc(1, sizeof(struct wlr_xdg_toplevel_v6_show_window_menu_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->x = x; +	event->y = y; + +	wl_signal_emit(&surface->events.request_show_window_menu, event); + +	free(event);  } -static void xdg_toplevel_move(struct wl_client *client, +static void xdg_toplevel_protocol_move(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *seat_resource,  		uint32_t serial) { -	wlr_log(L_DEBUG, "TODO: toplevel move"); +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	struct wlr_seat_handle *seat_handle = +		wl_resource_get_user_data(seat_resource); + +	if (!surface->configured) { +		wl_resource_post_error(surface->toplevel_state->resource, +			ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, +			"surface has not been configured yet"); +		return; +	} + +	struct wlr_xdg_toplevel_v6_move_event *event = +		calloc(1, sizeof(struct wlr_xdg_toplevel_v6_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 xdg_toplevel_resize(struct wl_client *client, +static void xdg_toplevel_protocol_resize(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *seat_resource,  		uint32_t serial, uint32_t edges) { -	wlr_log(L_DEBUG, "TODO: toplevel resize"); +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	struct wlr_seat_handle *seat_handle = +		wl_resource_get_user_data(seat_resource); + +	if (!surface->configured) { +		wl_resource_post_error(surface->toplevel_state->resource, +			ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, +			"surface has not been configured yet"); +		return; +	} + +	struct wlr_xdg_toplevel_v6_resize_event *event = +		calloc(1, sizeof(struct wlr_xdg_toplevel_v6_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 xdg_toplevel_set_max_size(struct wl_client *client, +static void xdg_toplevel_protocol_set_max_size(struct wl_client *client,  		struct wl_resource *resource, int32_t width, int32_t height) { -	wlr_log(L_DEBUG, "TODO: toplevel set max size"); +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	surface->toplevel_state->next.max_width = width; +	surface->toplevel_state->next.max_height = height;  } -static void xdg_toplevel_set_min_size(struct wl_client *client, +static void xdg_toplevel_protocol_set_min_size(struct wl_client *client,  		struct wl_resource *resource, int32_t width, int32_t height) { -	wlr_log(L_DEBUG, "TODO: toplevel set min size"); +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	surface->toplevel_state->next.min_width = width; +	surface->toplevel_state->next.min_height = height;  } -static void xdg_toplevel_set_maximized(struct wl_client *client, +static void xdg_toplevel_protocol_set_maximized(struct wl_client *client,  		struct wl_resource *resource) { -	wlr_log(L_DEBUG, "TODO: toplevel set maximized"); +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	surface->toplevel_state->next.maximized = true;  } -static void xdg_toplevel_unset_maximized(struct wl_client *client, struct wl_resource *resource) { -	wlr_log(L_DEBUG, "TODO: toplevel unset maximized"); +static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, +		struct wl_resource *resource) { +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	surface->toplevel_state->next.maximized = false;  } -static void xdg_toplevel_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { -	wlr_log(L_DEBUG, "TODO: toplevel set fullscreen"); +static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, +		struct wl_resource *resource, struct wl_resource *output_resource) { +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	surface->toplevel_state->next.fullscreen = true;  } -static void xdg_toplevel_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { -	wlr_log(L_DEBUG, "TODO: toplevel unset fullscreen"); +static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, +		struct wl_resource *resource) { +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	surface->toplevel_state->next.fullscreen = false;  } -static void xdg_toplevel_set_minimized(struct wl_client *client, struct wl_resource *resource) { -	wlr_log(L_DEBUG, "TODO: toplevel set minimized"); +static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, +		struct wl_resource *resource) { +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	wl_signal_emit(&surface->events.request_minimize, surface);  } -static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = { +static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = +{  	.destroy = resource_destroy, -	.set_parent = xdg_toplevel_set_parent, -	.set_title = xdg_toplevel_set_title, -	.set_app_id = xdg_toplevel_set_app_id, -	.show_window_menu = xdg_toplevel_show_window_menu, -	.move = xdg_toplevel_move, -	.resize = xdg_toplevel_resize, -	.set_max_size = xdg_toplevel_set_max_size, -	.set_min_size = xdg_toplevel_set_min_size, -	.set_maximized = xdg_toplevel_set_maximized, -	.unset_maximized = xdg_toplevel_unset_maximized, -	.set_fullscreen = xdg_toplevel_set_fullscreen, -	.unset_fullscreen = xdg_toplevel_unset_fullscreen, -	.set_minimized = xdg_toplevel_set_minimized +	.set_parent = xdg_toplevel_protocol_set_parent, +	.set_title = xdg_toplevel_protocol_set_title, +	.set_app_id = xdg_toplevel_protocol_set_app_id, +	.show_window_menu = xdg_toplevel_protocol_show_window_menu, +	.move = xdg_toplevel_protocol_move, +	.resize = xdg_toplevel_protocol_resize, +	.set_max_size = xdg_toplevel_protocol_set_max_size, +	.set_min_size = xdg_toplevel_protocol_set_min_size, +	.set_maximized = xdg_toplevel_protocol_set_maximized, +	.unset_maximized = xdg_toplevel_protocol_unset_maximized, +	.set_fullscreen = xdg_toplevel_protocol_set_fullscreen, +	.unset_fullscreen = xdg_toplevel_protocol_unset_fullscreen, +	.set_minimized = xdg_toplevel_protocol_set_minimized  }; -static void xdg_surface_destroy(struct wl_resource *resource) { -	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *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); +	wl_list_remove(&surface->surface_commit_listener.link); +	free(surface->geometry); +	free(surface->next_geometry); +	free(surface->title); +	free(surface->app_id);  	free(surface);  } +static void xdg_surface_resource_destroy(struct wl_resource *resource) { +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +	if (surface != NULL) { +		xdg_surface_destroy(surface); +	} +} +  static void xdg_surface_get_toplevel(struct wl_client *client,  		struct wl_resource *resource, uint32_t id) { -	// TODO: Flesh out +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + +	if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role, +			resource, ZXDG_SHELL_V6_ERROR_ROLE)) { +		return; +	} + +	surface->toplevel_state = calloc(1, sizeof(struct wlr_xdg_toplevel_v6)); +	if (surface->toplevel_state == NULL) { +		wl_client_post_no_memory(client); +		return; +	} + +	surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; +	surface->toplevel_state->base = surface; +  	struct wl_resource *toplevel_resource = wl_resource_create(client,  		&zxdg_toplevel_v6_interface, wl_resource_get_version(resource), id); + +	surface->toplevel_state->resource = toplevel_resource; +  	wl_resource_set_implementation(toplevel_resource, -		&zxdg_toplevel_v6_implementation, NULL, NULL); -	struct wl_display *display = wl_client_get_display(client); -	zxdg_surface_v6_send_configure(resource, wl_display_next_serial(display)); +		&zxdg_toplevel_v6_implementation, surface, NULL);  }  static void xdg_surface_get_popup(struct wl_client *client, @@ -114,15 +269,80 @@ static void xdg_surface_get_popup(struct wl_client *client,  	wlr_log(L_DEBUG, "TODO xdg surface get popup");  } +static void wlr_xdg_toplevel_v6_ack_configure( +		struct wlr_xdg_surface_v6 *surface, +		struct wlr_xdg_surface_v6_configure *configure) { +	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); +	surface->toplevel_state->next = configure->state; +	surface->toplevel_state->pending.width = 0; +	surface->toplevel_state->pending.height = 0; +} +  static void xdg_surface_ack_configure(struct wl_client *client,  		struct wl_resource *resource, uint32_t serial) { -	wlr_log(L_DEBUG, "TODO xdg surface ack configure"); +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + +	if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { +		wl_resource_post_error(surface->resource, +			ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, +			"xdg_surface must have a role"); +		return; +	} + +	bool found = false; +	struct wlr_xdg_surface_v6_configure *configure, *tmp; +	wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { +		if (configure->serial < serial) { +			wl_list_remove(&configure->link); +			free(configure); +		} else if (configure->serial == serial) { +			wl_list_remove(&configure->link); +			found = true; +			break; +		} else { +			break; +		} +	} +	if (!found) { +		wl_resource_post_error(surface->client->resource, +			ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, +			"wrong configure serial: %u", serial); +		return; +	} + +	// TODO handle popups +	if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { +		wlr_xdg_toplevel_v6_ack_configure(surface, configure); +	} + +	if (!surface->configured) { +		surface->configured = true; +		wl_signal_emit(&surface->client->shell->events.new_surface, surface); +	} + +	wl_signal_emit(&surface->events.ack_configure, surface); + +	free(configure);  } -  +  static void xdg_surface_set_window_geometry(struct wl_client *client,  		struct wl_resource *resource, int32_t x, int32_t y, int32_t width,  		int32_t height) { -	wlr_log(L_DEBUG, "TODO xdg surface set window geometry"); +	struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + +	if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { +		wl_resource_post_error(surface->resource, +			ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, +			"xdg_surface must have a role"); +		return; +	} + +	surface->has_next_geometry = true; +	surface->next_geometry->height = height; +	surface->next_geometry->width = width; +	surface->next_geometry->x = x; +	surface->next_geometry->y = y; +  }  static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation = { @@ -138,26 +358,270 @@ static void xdg_shell_create_positioner(struct wl_client *client,  	wlr_log(L_DEBUG, "TODO: xdg shell create positioner");  } -static void xdg_shell_get_xdg_surface(struct wl_client *client, -		struct wl_resource *_xdg_shell, uint32_t id, -		struct wl_resource *_surface) { -	struct wlr_xdg_shell_v6 *xdg_shell = wl_resource_get_user_data(_xdg_shell); +static bool wlr_xdg_surface_v6_toplevel_state_compare( +		struct wlr_xdg_toplevel_v6 *state) { +	// is pending state different from current state? +	if (state->pending.activated != state->current.activated) { +		return false; +	} +	if (state->pending.fullscreen != state->current.fullscreen) { +		return false; +	} +	if (state->pending.maximized != state->current.maximized) { +		return false; +	} +	if (state->pending.resizing != state->current.resizing) { +		return false; +	} + +	if ((uint32_t)state->base->geometry->width == state->pending.width && +			(uint32_t)state->base->geometry->height == state->pending.height) { +		return true; +	} + +	if (state->pending.width == 0 && state->pending.height == 0) { +		return true; +	} + +	return false; +} + +static void wlr_xdg_toplevel_v6_send_configure( +		struct wlr_xdg_surface_v6 *surface, +		struct wlr_xdg_surface_v6_configure *configure) { +	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); +	uint32_t *s; +	struct wl_array states; + +	configure->state = surface->toplevel_state->pending; + +	wl_array_init(&states); +	if (surface->toplevel_state->pending.maximized) { +		s = wl_array_add(&states, sizeof(uint32_t)); +		*s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; +	} +	if (surface->toplevel_state->pending.fullscreen) { +		s = wl_array_add(&states, sizeof(uint32_t)); +		*s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; +	} +	if (surface->toplevel_state->pending.resizing) { +		s = wl_array_add(&states, sizeof(uint32_t)); +		*s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; +	} +	if (surface->toplevel_state->pending.activated) { +		s = wl_array_add(&states, sizeof(uint32_t)); +		*s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; +	} + +	uint32_t width = surface->toplevel_state->pending.width; +	uint32_t height = surface->toplevel_state->pending.height; + +	if (width == 0 || height == 0) { +		width = surface->geometry->width; +		height = surface->geometry->height; +	} + +	zxdg_toplevel_v6_send_configure(surface->toplevel_state->resource, width, +		height, &states); + +	wl_array_release(&states); +} + +static void wlr_xdg_surface_send_configure(void *user_data) { +	struct wlr_xdg_surface_v6 *surface = user_data; +	struct wl_display *display = wl_client_get_display(surface->client->client); + +	// TODO handle popups +	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + +	surface->configure_idle = NULL; + +	struct wlr_xdg_surface_v6_configure *configure = +		calloc(1, sizeof(struct wlr_xdg_surface_v6_configure)); +	if (configure == NULL) { +		wl_client_post_no_memory(surface->client->client); +		return; +	} + +	wl_list_insert(surface->configure_list.prev, &configure->link); +	configure->serial = wl_display_next_serial(display); + +	wlr_xdg_toplevel_v6_send_configure(surface, configure); + +	zxdg_surface_v6_send_configure(surface->resource, configure->serial); +} + +static void wlr_xdg_surface_v6_schedule_configure( +		struct wlr_xdg_surface_v6 *surface, bool force) { +	// TODO handle popups +	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + +	struct wl_display *display = wl_client_get_display(surface->client->client); +	struct wl_event_loop *loop = wl_display_get_event_loop(display); + +	bool pending_same = !force && +		wlr_xdg_surface_v6_toplevel_state_compare(surface->toplevel_state); + +	if (surface->configure_idle != NULL) { +		if (!pending_same) { +			// configure request already scheduled +			return; +		} + +		// configure request not necessary anymore +		wl_event_source_remove(surface->configure_idle); +		surface->configure_idle = NULL; +	} else { +		if (pending_same) { +			// configure request not necessary +			return; +		} + +		surface->configure_idle = +			wl_event_loop_add_idle( +				loop, +				wlr_xdg_surface_send_configure, +				surface); +	} +} + +static void handle_wlr_surface_destroyed(struct wl_listener *listener, +		void *data) { +	struct wlr_xdg_surface_v6 *xdg_surface = +		wl_container_of(listener, xdg_surface, surface_destroy_listener); +	xdg_surface_destroy(xdg_surface); +} + +static void wlr_xdg_surface_v6_toplevel_committed( +		struct wlr_xdg_surface_v6 *surface) { +	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + +	if (!surface->surface->current.buffer && !surface->toplevel_state->added) { +		// on the first commit, send a configure request to tell the client it +		// is added +		wlr_xdg_surface_v6_schedule_configure(surface, true); +		surface->toplevel_state->added = true; +		return; +	} + +	if (!surface->surface->current.buffer) { +		return; +	} + +	surface->toplevel_state->current = surface->toplevel_state->next; +} + +static void handle_wlr_surface_committed(struct wl_listener *listener, +		void *data) { +	struct wlr_xdg_surface_v6 *surface = +		wl_container_of(listener, surface, surface_commit_listener); + +	if (surface->surface->current.buffer && !surface->configured) { +		wl_resource_post_error(surface->resource, +			ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, +			"xdg_surface has never been configured"); +		return; +	} + +	if (surface->has_next_geometry) { +		surface->has_next_geometry = false; +		surface->geometry->x = surface->next_geometry->x; +		surface->geometry->y = surface->next_geometry->y; +		surface->geometry->width = surface->next_geometry->width; +		surface->geometry->height = surface->next_geometry->height; +	} + +	switch (surface->role) { +	case WLR_XDG_SURFACE_V6_ROLE_NONE: +		wl_resource_post_error(surface->resource, +			ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, +			"xdg_surface must have a role"); +		break; +	case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: +		wlr_xdg_surface_v6_toplevel_committed(surface); +		break; +	case WLR_XDG_SURFACE_V6_ROLE_POPUP: +		wlr_log(L_DEBUG, "TODO: popup surface committed"); +		break; +	} + +	wl_signal_emit(&surface->events.commit, surface); +} + +static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, +		struct wl_resource *client_resource, uint32_t id, +		struct wl_resource *surface_resource) { +	struct wlr_xdg_client_v6 *client = +		wl_resource_get_user_data(client_resource); +  	struct wlr_xdg_surface_v6 *surface;  	if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface_v6)))) { +		wl_client_post_no_memory(wl_client); +		return; +	} + +	if (!(surface->geometry = calloc(1, sizeof(struct wlr_box)))) { +		free(surface); +		wl_client_post_no_memory(wl_client);  		return;  	} -	surface->surface = _surface; -	surface->resource = wl_resource_create(client, -		&zxdg_surface_v6_interface, wl_resource_get_version(_xdg_shell), id); + +	if (!(surface->next_geometry = calloc(1, sizeof(struct wlr_box)))) { +		free(surface->geometry); +		free(surface); +		wl_client_post_no_memory(wl_client); +		return; +	} + +	surface->client = client; +	surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; +	surface->surface = wl_resource_get_user_data(surface_resource); +	surface->resource = wl_resource_create(wl_client, +		&zxdg_surface_v6_interface, wl_resource_get_version(client_resource), +		id); + +	if (surface->surface->current.buffer != NULL) { +		wl_resource_post_error(surface->resource, +			ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, +			"xdg_surface must not have a buffer at creation"); +		return; +	} + +	wl_list_init(&surface->configure_list); + +	wl_signal_init(&surface->events.request_minimize); +	wl_signal_init(&surface->events.request_move); +	wl_signal_init(&surface->events.request_resize); +	wl_signal_init(&surface->events.request_show_window_menu); +	wl_signal_init(&surface->events.commit); +	wl_signal_init(&surface->events.destroy); +	wl_signal_init(&surface->events.ack_configure); +	wl_signal_init(&surface->events.ping_timeout); + +	wl_signal_add(&surface->surface->signals.destroy, +		&surface->surface_destroy_listener); +	surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed; + +	wl_signal_add(&surface->surface->signals.commit, +		&surface->surface_commit_listener); +	surface->surface_commit_listener.notify = handle_wlr_surface_committed; +  	wlr_log(L_DEBUG, "new xdg_surface %p (res %p)", surface, surface->resource);  	wl_resource_set_implementation(surface->resource, -		&zxdg_surface_v6_implementation, surface, xdg_surface_destroy); -	wl_list_insert(&xdg_shell->surfaces, &surface->link); +		&zxdg_surface_v6_implementation, surface, xdg_surface_resource_destroy); +	wl_list_insert(&client->surfaces, &surface->link);  } -static void xdg_shell_pong(struct wl_client *client, +static void xdg_shell_pong(struct wl_client *wl_client,  		struct wl_resource *resource, uint32_t serial) { -	wlr_log(L_DEBUG, "TODO xdg shell pong"); +	struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); + +	if (client->ping_serial != serial) { +		return; +	} + +	wl_event_source_timer_update(client->ping_timer, 0); +	client->ping_serial = 0;  }  static struct zxdg_shell_v6_interface xdg_shell_impl = { @@ -166,8 +630,33 @@ static struct zxdg_shell_v6_interface xdg_shell_impl = {  	.pong = xdg_shell_pong,  }; -static void xdg_shell_destroy(struct wl_resource *resource) { -	wl_list_remove(wl_resource_get_link(resource)); +static void wlr_xdg_client_v6_destroy(struct wl_resource *resource) { +	struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); + +	struct wlr_xdg_surface_v6 *surface, *tmp = NULL; +	wl_list_for_each_safe(surface, tmp, &client->surfaces, link) { +		wl_list_remove(&surface->link); +		wl_list_init(&surface->link); +	} + +	if (client->ping_timer != NULL) { +		wl_event_source_remove(client->ping_timer); +	} + +	wl_list_remove(&client->link); +	free(client); +} + +static int wlr_xdg_client_v6_ping_timeout(void *user_data) { +	struct wlr_xdg_client_v6 *client = user_data; + +	struct wlr_xdg_surface_v6 *surface; +	wl_list_for_each(surface, &client->surfaces, link) { +		wl_signal_emit(&surface->events.ping_timeout, surface); +	} + +	client->ping_serial = 0; +	return 1;  }  static void xdg_shell_bind(struct wl_client *wl_client, void *_xdg_shell, @@ -175,14 +664,36 @@ static void xdg_shell_bind(struct wl_client *wl_client, void *_xdg_shell,  	struct wlr_xdg_shell_v6 *xdg_shell = _xdg_shell;  	assert(wl_client && xdg_shell);  	if (version > 1) { -		wlr_log(L_ERROR, "Client requested unsupported xdg_shell_v6 version, disconnecting"); +		wlr_log(L_ERROR, +			"Client requested unsupported xdg_shell_v6 version, disconnecting");  		wl_client_destroy(wl_client);  		return;  	} -	struct wl_resource *wl_resource = wl_resource_create( -		wl_client, &zxdg_shell_v6_interface, version, id); -	wl_resource_set_implementation(wl_resource, &xdg_shell_impl, xdg_shell, xdg_shell_destroy); -	wl_list_insert(&xdg_shell->wl_resources, wl_resource_get_link(wl_resource)); +	struct wlr_xdg_client_v6 *client = +		calloc(1, sizeof(struct wlr_xdg_client_v6)); +	if (client == NULL) { +		wl_client_post_no_memory(wl_client); +		return; +	} + +	wl_list_init(&client->surfaces); + +	client->resource = +		wl_resource_create(wl_client, &zxdg_shell_v6_interface, version, id); +	client->client = wl_client; +	client->shell = xdg_shell; + +	wl_resource_set_implementation(client->resource, &xdg_shell_impl, client, +		wlr_xdg_client_v6_destroy); +	wl_list_insert(&xdg_shell->clients, &client->link); + +	struct wl_display *display = wl_client_get_display(client->client); +	struct wl_event_loop *loop = wl_display_get_event_loop(display); +	client->ping_timer = wl_event_loop_add_timer(loop, +		wlr_xdg_client_v6_ping_timeout, client); +	if (client->ping_timer == NULL) { +		wl_client_post_no_memory(client->client); +	}  }  struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { @@ -191,6 +702,11 @@ struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) {  	if (!xdg_shell) {  		return NULL;  	} + +	xdg_shell->ping_timeout = 10000; + +	wl_list_init(&xdg_shell->clients); +  	struct wl_global *wl_global = wl_global_create(display,  		&zxdg_shell_v6_interface, 1, xdg_shell, xdg_shell_bind);  	if (!wl_global) { @@ -198,8 +714,9 @@ struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) {  		return NULL;  	}  	xdg_shell->wl_global = wl_global; -	wl_list_init(&xdg_shell->wl_resources); -	wl_list_init(&xdg_shell->surfaces); + +	wl_signal_init(&xdg_shell->events.new_surface); +  	return xdg_shell;  } @@ -207,13 +724,62 @@ void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell) {  	if (!xdg_shell) {  		return;  	} -	struct wl_resource *resource = NULL, *temp = NULL; -	wl_resource_for_each_safe(resource, temp, &xdg_shell->wl_resources) { -		struct wl_list *link = wl_resource_get_link(resource); -		wl_list_remove(link); -	} -	// TODO: destroy surfaces  	// TODO: this segfault (wl_display->registry_resource_list is not init)  	// wl_global_destroy(xdg_shell->wl_global);  	free(xdg_shell);  } + +void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface) { +	if (surface->client->ping_serial != 0) { +		// already pinged +		return; +	} + +	surface->client->ping_serial = +		wl_display_next_serial(wl_client_get_display(surface->client->client)); +	wl_event_source_timer_update(surface->client->ping_timer, +		surface->client->shell->ping_timeout); +	zxdg_shell_v6_send_ping(surface->client->resource, +		surface->client->ping_serial); +} + +void wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, +		uint32_t width, uint32_t height) { +	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); +	surface->toplevel_state->pending.width = width; +	surface->toplevel_state->pending.height = height; + +	wlr_xdg_surface_v6_schedule_configure(surface, false); +} + +void wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, +		bool activated) { +	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); +	surface->toplevel_state->pending.activated = activated; + +	wlr_xdg_surface_v6_schedule_configure(surface, false); +} + +void wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, +		bool maximized) { +	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); +	surface->toplevel_state->pending.maximized = maximized; + +	wlr_xdg_surface_v6_schedule_configure(surface, false); +} + +void wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, +		bool fullscreen) { +	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); +	surface->toplevel_state->pending.fullscreen = fullscreen; + +	wlr_xdg_surface_v6_schedule_configure(surface, false); +} + +void wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, +		bool resizing) { +	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); +	surface->toplevel_state->pending.fullscreen = resizing; + +	wlr_xdg_surface_v6_schedule_configure(surface, false); +} | 
