parent
							
								
									71cba94e73
								
							
						
					
					
						commit
						7d26a6debd
					
				| @ -0,0 +1,232 @@ | |||||||
|  | #ifndef WLR_TYPES_WLR_XDG_SHELL_H | ||||||
|  | #define WLR_TYPES_WLR_XDG_SHELL_H | ||||||
|  | 
 | ||||||
|  | #include <wlr/types/wlr_box.h> | ||||||
|  | #include <wlr/types/wlr_seat.h> | ||||||
|  | #include <wayland-server.h> | ||||||
|  | 
 | ||||||
|  | struct wlr_xdg_shell { | ||||||
|  | 	struct wl_global *wl_global; | ||||||
|  | 	struct wl_list clients; | ||||||
|  | 	struct wl_list popup_grabs; | ||||||
|  | 	uint32_t ping_timeout; | ||||||
|  | 
 | ||||||
|  | 	struct wl_listener display_destroy; | ||||||
|  | 
 | ||||||
|  | 	struct { | ||||||
|  | 		struct wl_signal new_surface; | ||||||
|  | 	} events; | ||||||
|  | 
 | ||||||
|  | 	void *data; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_xdg_client { | ||||||
|  | 	struct wlr_xdg_shell *shell; | ||||||
|  | 	struct wl_resource *resource; | ||||||
|  | 	struct wl_client *client; | ||||||
|  | 	struct wl_list surfaces; | ||||||
|  | 
 | ||||||
|  | 	struct wl_list link; // wlr_xdg_shell::clients
 | ||||||
|  | 
 | ||||||
|  | 	uint32_t ping_serial; | ||||||
|  | 	struct wl_event_source *ping_timer; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_xdg_popup { | ||||||
|  | 	struct wlr_xdg_surface *base; | ||||||
|  | 	struct wl_list link; | ||||||
|  | 
 | ||||||
|  | 	struct wl_resource *resource; | ||||||
|  | 	bool committed; | ||||||
|  | 	struct wlr_xdg_surface *parent; | ||||||
|  | 	struct wlr_seat *seat; | ||||||
|  | 	struct wlr_box geometry; | ||||||
|  | 
 | ||||||
|  | 	struct wl_list grab_link; // wlr_xdg_popup_grab::popups
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // each seat gets a popup grab
 | ||||||
|  | struct wlr_xdg_popup_grab { | ||||||
|  | 	struct wl_client *client; | ||||||
|  | 	struct wlr_seat_pointer_grab pointer_grab; | ||||||
|  | 	struct wlr_seat_keyboard_grab keyboard_grab; | ||||||
|  | 	struct wlr_seat *seat; | ||||||
|  | 	struct wl_list popups; | ||||||
|  | 	struct wl_list link; // wlr_xdg_shell::popup_grabs
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | enum wlr_xdg_surface_role { | ||||||
|  | 	WLR_XDG_SURFACE_ROLE_NONE, | ||||||
|  | 	WLR_XDG_SURFACE_ROLE_TOPLEVEL, | ||||||
|  | 	WLR_XDG_SURFACE_ROLE_POPUP, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_xdg_toplevel_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 { | ||||||
|  | 	struct wl_resource *resource; | ||||||
|  | 	struct wlr_xdg_surface *base; | ||||||
|  | 	struct wlr_xdg_surface *parent; | ||||||
|  | 	bool added; | ||||||
|  | 	struct wlr_xdg_toplevel_state next; // client protocol requests
 | ||||||
|  | 	struct wlr_xdg_toplevel_state pending; // user configure requests
 | ||||||
|  | 	struct wlr_xdg_toplevel_state current; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_xdg_surface_configure { | ||||||
|  | 	struct wl_list link; // wlr_xdg_surface::configure_list
 | ||||||
|  | 	uint32_t serial; | ||||||
|  | 	struct wlr_xdg_toplevel_state state; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_xdg_surface { | ||||||
|  | 	struct wlr_xdg_client *client; | ||||||
|  | 	struct wl_resource *resource; | ||||||
|  | 	struct wlr_surface *surface; | ||||||
|  | 	struct wl_list link; // wlr_xdg_client::surfaces
 | ||||||
|  | 	enum wlr_xdg_surface_role role; | ||||||
|  | 
 | ||||||
|  | 	union { | ||||||
|  | 		struct wlr_xdg_toplevel *toplevel_state; | ||||||
|  | 		struct wlr_xdg_popup *popup_state; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	struct wl_list popups; // wlr_xdg_popup::link
 | ||||||
|  | 
 | ||||||
|  | 	bool configured; | ||||||
|  | 	bool added; | ||||||
|  | 	uint32_t configure_serial; | ||||||
|  | 	struct wl_event_source *configure_idle; | ||||||
|  | 	uint32_t configure_next_serial; | ||||||
|  | 	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 { | ||||||
|  | 		struct wl_signal destroy; | ||||||
|  | 		struct wl_signal ping_timeout; | ||||||
|  | 		struct wl_signal new_popup; | ||||||
|  | 
 | ||||||
|  | 		struct wl_signal request_maximize; | ||||||
|  | 		struct wl_signal request_fullscreen; | ||||||
|  | 		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_move_event { | ||||||
|  | 	struct wlr_xdg_surface *surface; | ||||||
|  | 	struct wlr_seat_client *seat; | ||||||
|  | 	uint32_t serial; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_xdg_toplevel_resize_event { | ||||||
|  | 	struct wlr_xdg_surface *surface; | ||||||
|  | 	struct wlr_seat_client *seat; | ||||||
|  | 	uint32_t serial; | ||||||
|  | 	uint32_t edges; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_xdg_toplevel_set_fullscreen_event { | ||||||
|  | 	struct wlr_xdg_surface *surface; | ||||||
|  | 	bool fullscreen; | ||||||
|  | 	struct wlr_output *output; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_xdg_toplevel_show_window_menu_event { | ||||||
|  | 	struct wlr_xdg_surface *surface; | ||||||
|  | 	struct wlr_seat_client *seat; | ||||||
|  | 	uint32_t serial; | ||||||
|  | 	uint32_t x, y; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display); | ||||||
|  | void wlr_xdg_shell_destroy(struct wlr_xdg_shell *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_ping(struct wlr_xdg_surface *surface); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Request that this toplevel surface be the given size. Returns the associated | ||||||
|  |  * configure serial. | ||||||
|  |  */ | ||||||
|  | uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface, | ||||||
|  | 		uint32_t width, uint32_t height); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Request that this toplevel surface show itself in an activated or deactivated | ||||||
|  |  * state. Returns the associated configure serial. | ||||||
|  |  */ | ||||||
|  | uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface, | ||||||
|  | 		bool activated); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Request that this toplevel surface consider itself maximized or not | ||||||
|  |  * maximized. Returns the associated configure serial. | ||||||
|  |  */ | ||||||
|  | uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface, | ||||||
|  | 		bool maximized); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Request that this toplevel surface consider itself fullscreen or not | ||||||
|  |  * fullscreen. Returns the associated configure serial. | ||||||
|  |  */ | ||||||
|  | uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface, | ||||||
|  | 		bool fullscreen); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Request that this toplevel surface consider itself to be resizing or not | ||||||
|  |  * resizing. Returns the associated configure serial. | ||||||
|  |  */ | ||||||
|  | uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface, | ||||||
|  | 		bool resizing); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Request that this toplevel surface closes. | ||||||
|  |  */ | ||||||
|  | void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Compute the popup position in surface-local coordinates. | ||||||
|  |  */ | ||||||
|  | void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface, | ||||||
|  | 		double *popup_sx, double *popup_sy); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Find a popup within this surface at the surface-local coordinates. Returns | ||||||
|  |  * the popup and coordinates in the topmost surface coordinate system or NULL if | ||||||
|  |  * no popup is found at that location. | ||||||
|  |  */ | ||||||
|  | struct wlr_xdg_surface *wlr_xdg_surface_popup_at( | ||||||
|  | 		struct wlr_xdg_surface *surface, double sx, double sy, | ||||||
|  | 		double *popup_sx, double *popup_sy); | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
| @ -0,0 +1,363 @@ | |||||||
|  | #include <assert.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <wayland-server.h> | ||||||
|  | #include <wlr/types/wlr_box.h> | ||||||
|  | #include <wlr/types/wlr_surface.h> | ||||||
|  | #include <wlr/types/wlr_xdg_shell.h> | ||||||
|  | #include <wlr/util/log.h> | ||||||
|  | #include "rootston/desktop.h" | ||||||
|  | #include "rootston/input.h" | ||||||
|  | #include "rootston/server.h" | ||||||
|  | 
 | ||||||
|  | static void popup_destroy(struct roots_view_child *child) { | ||||||
|  | 	assert(child->destroy == popup_destroy); | ||||||
|  | 	struct roots_xdg_popup *popup = (struct roots_xdg_popup *)child; | ||||||
|  | 	if (popup == NULL) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	wl_list_remove(&popup->destroy.link); | ||||||
|  | 	wl_list_remove(&popup->new_popup.link); | ||||||
|  | 	view_child_finish(&popup->view_child); | ||||||
|  | 	free(popup); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void popup_handle_destroy(struct wl_listener *listener, void *data) { | ||||||
|  | 	struct roots_xdg_popup *popup = | ||||||
|  | 		wl_container_of(listener, popup, destroy); | ||||||
|  | 	popup_destroy((struct roots_view_child *)popup); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct roots_xdg_popup *popup_create(struct roots_view *view, | ||||||
|  | 	struct wlr_xdg_popup *wlr_popup); | ||||||
|  | 
 | ||||||
|  | static void popup_handle_new_popup(struct wl_listener *listener, void *data) { | ||||||
|  | 	struct roots_xdg_popup *popup = | ||||||
|  | 		wl_container_of(listener, popup, new_popup); | ||||||
|  | 	struct wlr_xdg_popup *wlr_popup = data; | ||||||
|  | 	popup_create(popup->view_child.view, wlr_popup); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct roots_xdg_popup *popup_create(struct roots_view *view, | ||||||
|  | 		struct wlr_xdg_popup *wlr_popup) { | ||||||
|  | 	struct roots_xdg_popup *popup = | ||||||
|  | 		calloc(1, sizeof(struct roots_xdg_popup)); | ||||||
|  | 	if (popup == NULL) { | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	popup->wlr_popup = wlr_popup; | ||||||
|  | 	popup->view_child.destroy = popup_destroy; | ||||||
|  | 	view_child_init(&popup->view_child, view, wlr_popup->base->surface); | ||||||
|  | 	popup->destroy.notify = popup_handle_destroy; | ||||||
|  | 	wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); | ||||||
|  | 	popup->new_popup.notify = popup_handle_new_popup; | ||||||
|  | 	wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); | ||||||
|  | 	return popup; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static void get_size(const struct roots_view *view, struct wlr_box *box) { | ||||||
|  | 	assert(view->type == ROOTS_XDG_SHELL_VIEW); | ||||||
|  | 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||||
|  | 
 | ||||||
|  | 	if (surface->geometry->width > 0 && surface->geometry->height > 0) { | ||||||
|  | 		box->width = surface->geometry->width; | ||||||
|  | 		box->height = surface->geometry->height; | ||||||
|  | 	} else { | ||||||
|  | 		box->width = view->wlr_surface->current->width; | ||||||
|  | 		box->height = view->wlr_surface->current->height; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void activate(struct roots_view *view, bool active) { | ||||||
|  | 	assert(view->type == ROOTS_XDG_SHELL_VIEW); | ||||||
|  | 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||||
|  | 	if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { | ||||||
|  | 		wlr_xdg_toplevel_set_activated(surface, active); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void apply_size_constraints(struct wlr_xdg_surface *surface, | ||||||
|  | 		uint32_t width, uint32_t height, uint32_t *dest_width, | ||||||
|  | 		uint32_t *dest_height) { | ||||||
|  | 	*dest_width = width; | ||||||
|  | 	*dest_height = height; | ||||||
|  | 
 | ||||||
|  | 	struct wlr_xdg_toplevel_state *state = &surface->toplevel_state->current; | ||||||
|  | 	if (width < state->min_width) { | ||||||
|  | 		*dest_width = state->min_width; | ||||||
|  | 	} else if (state->max_width > 0 && | ||||||
|  | 			width > state->max_width) { | ||||||
|  | 		*dest_width = state->max_width; | ||||||
|  | 	} | ||||||
|  | 	if (height < state->min_height) { | ||||||
|  | 		*dest_height = state->min_height; | ||||||
|  | 	} else if (state->max_height > 0 && | ||||||
|  | 			height > state->max_height) { | ||||||
|  | 		*dest_height = state->max_height; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void resize(struct roots_view *view, uint32_t width, uint32_t height) { | ||||||
|  | 	assert(view->type == ROOTS_XDG_SHELL_VIEW); | ||||||
|  | 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||||
|  | 	if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	uint32_t constrained_width, constrained_height; | ||||||
|  | 	apply_size_constraints(surface, width, height, &constrained_width, | ||||||
|  | 		&constrained_height); | ||||||
|  | 
 | ||||||
|  | 	wlr_xdg_toplevel_set_size(surface, constrained_width, | ||||||
|  | 		constrained_height); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void move_resize(struct roots_view *view, double x, double y, | ||||||
|  | 		uint32_t width, uint32_t height) { | ||||||
|  | 	assert(view->type == ROOTS_XDG_SHELL_VIEW); | ||||||
|  | 	struct roots_xdg_surface *roots_surface = view->roots_xdg_surface; | ||||||
|  | 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||||
|  | 	if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool update_x = x != view->x; | ||||||
|  | 	bool update_y = y != view->y; | ||||||
|  | 
 | ||||||
|  | 	uint32_t constrained_width, constrained_height; | ||||||
|  | 	apply_size_constraints(surface, width, height, &constrained_width, | ||||||
|  | 		&constrained_height); | ||||||
|  | 
 | ||||||
|  | 	if (update_x) { | ||||||
|  | 		x = x + width - constrained_width; | ||||||
|  | 	} | ||||||
|  | 	if (update_y) { | ||||||
|  | 		y = y + height - constrained_height; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	view->pending_move_resize.update_x = update_x; | ||||||
|  | 	view->pending_move_resize.update_y = update_y; | ||||||
|  | 	view->pending_move_resize.x = x; | ||||||
|  | 	view->pending_move_resize.y = y; | ||||||
|  | 	view->pending_move_resize.width = constrained_width; | ||||||
|  | 	view->pending_move_resize.height = constrained_height; | ||||||
|  | 
 | ||||||
|  | 	uint32_t serial = wlr_xdg_toplevel_set_size(surface, constrained_width, | ||||||
|  | 		constrained_height); | ||||||
|  | 	if (serial > 0) { | ||||||
|  | 		roots_surface->pending_move_resize_configure_serial = serial; | ||||||
|  | 	} else if (roots_surface->pending_move_resize_configure_serial == 0) { | ||||||
|  | 		view_update_position(view, x, y); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void maximize(struct roots_view *view, bool maximized) { | ||||||
|  | 	assert(view->type == ROOTS_XDG_SHELL_VIEW); | ||||||
|  | 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||||
|  | 	if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	wlr_xdg_toplevel_set_maximized(surface, maximized); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void set_fullscreen(struct roots_view *view, bool fullscreen) { | ||||||
|  | 	assert(view->type == ROOTS_XDG_SHELL_VIEW); | ||||||
|  | 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||||
|  | 	if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	wlr_xdg_toplevel_set_fullscreen(surface, fullscreen); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void close(struct roots_view *view) { | ||||||
|  | 	assert(view->type == ROOTS_XDG_SHELL_VIEW); | ||||||
|  | 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||||
|  | 	if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { | ||||||
|  | 		wlr_xdg_toplevel_send_close(surface); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void handle_request_move(struct wl_listener *listener, void *data) { | ||||||
|  | 	struct roots_xdg_surface *roots_xdg_surface = | ||||||
|  | 		wl_container_of(listener, roots_xdg_surface, request_move); | ||||||
|  | 	struct roots_view *view = roots_xdg_surface->view; | ||||||
|  | 	struct roots_input *input = view->desktop->server->input; | ||||||
|  | 	struct wlr_xdg_toplevel_move_event *e = data; | ||||||
|  | 	struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); | ||||||
|  | 	// TODO verify event serial
 | ||||||
|  | 	if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	roots_seat_begin_move(seat, view); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void handle_request_resize(struct wl_listener *listener, void *data) { | ||||||
|  | 	struct roots_xdg_surface *roots_xdg_surface = | ||||||
|  | 		wl_container_of(listener, roots_xdg_surface, request_resize); | ||||||
|  | 	struct roots_view *view = roots_xdg_surface->view; | ||||||
|  | 	struct roots_input *input = view->desktop->server->input; | ||||||
|  | 	struct wlr_xdg_toplevel_resize_event *e = data; | ||||||
|  | 	// TODO verify event serial
 | ||||||
|  | 	struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); | ||||||
|  | 	assert(seat); | ||||||
|  | 	if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	roots_seat_begin_resize(seat, view, e->edges); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void handle_request_maximize(struct wl_listener *listener, void *data) { | ||||||
|  | 	struct roots_xdg_surface *roots_xdg_surface = | ||||||
|  | 		wl_container_of(listener, roots_xdg_surface, request_maximize); | ||||||
|  | 	struct roots_view *view = roots_xdg_surface->view; | ||||||
|  | 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||||
|  | 
 | ||||||
|  | 	if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	view_maximize(view, surface->toplevel_state->next.maximized); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void handle_request_fullscreen(struct wl_listener *listener, | ||||||
|  | 		void *data) { | ||||||
|  | 	struct roots_xdg_surface *roots_xdg_surface = | ||||||
|  | 		wl_container_of(listener, roots_xdg_surface, request_fullscreen); | ||||||
|  | 	struct roots_view *view = roots_xdg_surface->view; | ||||||
|  | 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||||
|  | 	struct wlr_xdg_toplevel_set_fullscreen_event *e = data; | ||||||
|  | 
 | ||||||
|  | 	if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	view_set_fullscreen(view, e->fullscreen, e->output); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void handle_surface_commit(struct wl_listener *listener, void *data) { | ||||||
|  | 	struct roots_xdg_surface *roots_surface = | ||||||
|  | 		wl_container_of(listener, roots_surface, surface_commit); | ||||||
|  | 	struct roots_view *view = roots_surface->view; | ||||||
|  | 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||||
|  | 
 | ||||||
|  | 	view_apply_damage(view); | ||||||
|  | 
 | ||||||
|  | 	struct wlr_box size; | ||||||
|  | 	get_size(view, &size); | ||||||
|  | 	view_update_size(view, size.width, size.height); | ||||||
|  | 
 | ||||||
|  | 	uint32_t pending_serial = | ||||||
|  | 		roots_surface->pending_move_resize_configure_serial; | ||||||
|  | 	if (pending_serial > 0 && pending_serial >= surface->configure_serial) { | ||||||
|  | 		double x = view->x; | ||||||
|  | 		double y = view->y; | ||||||
|  | 		if (view->pending_move_resize.update_x) { | ||||||
|  | 			x = view->pending_move_resize.x + view->pending_move_resize.width - | ||||||
|  | 				size.width; | ||||||
|  | 		} | ||||||
|  | 		if (view->pending_move_resize.update_y) { | ||||||
|  | 			y = view->pending_move_resize.y + view->pending_move_resize.height - | ||||||
|  | 				size.height; | ||||||
|  | 		} | ||||||
|  | 		view_update_position(view, x, y); | ||||||
|  | 
 | ||||||
|  | 		if (pending_serial == surface->configure_serial) { | ||||||
|  | 			roots_surface->pending_move_resize_configure_serial = 0; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void handle_new_popup(struct wl_listener *listener, void *data) { | ||||||
|  | 	struct roots_xdg_surface *roots_xdg_surface = | ||||||
|  | 		wl_container_of(listener, roots_xdg_surface, new_popup); | ||||||
|  | 	struct wlr_xdg_popup *wlr_popup = data; | ||||||
|  | 	popup_create(roots_xdg_surface->view, wlr_popup); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void handle_destroy(struct wl_listener *listener, void *data) { | ||||||
|  | 	struct roots_xdg_surface *roots_xdg_surface = | ||||||
|  | 		wl_container_of(listener, roots_xdg_surface, destroy); | ||||||
|  | 	wl_list_remove(&roots_xdg_surface->surface_commit.link); | ||||||
|  | 	wl_list_remove(&roots_xdg_surface->destroy.link); | ||||||
|  | 	wl_list_remove(&roots_xdg_surface->new_popup.link); | ||||||
|  | 	wl_list_remove(&roots_xdg_surface->request_move.link); | ||||||
|  | 	wl_list_remove(&roots_xdg_surface->request_resize.link); | ||||||
|  | 	wl_list_remove(&roots_xdg_surface->request_maximize.link); | ||||||
|  | 	wl_list_remove(&roots_xdg_surface->request_fullscreen.link); | ||||||
|  | 	wl_list_remove(&roots_xdg_surface->view->link); | ||||||
|  | 	view_finish(roots_xdg_surface->view); | ||||||
|  | 	free(roots_xdg_surface->view); | ||||||
|  | 	free(roots_xdg_surface); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { | ||||||
|  | 	struct wlr_xdg_surface *surface = data; | ||||||
|  | 	assert(surface->role != WLR_XDG_SURFACE_ROLE_NONE); | ||||||
|  | 
 | ||||||
|  | 	if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { | ||||||
|  | 		wlr_log(L_DEBUG, "new xdg popup"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	struct roots_desktop *desktop = | ||||||
|  | 		wl_container_of(listener, desktop, xdg_shell_surface); | ||||||
|  | 
 | ||||||
|  | 	wlr_log(L_DEBUG, "new xdg toplevel: title=%s, app_id=%s", | ||||||
|  | 		surface->title, surface->app_id); | ||||||
|  | 	wlr_xdg_surface_ping(surface); | ||||||
|  | 
 | ||||||
|  | 	struct roots_xdg_surface *roots_surface = | ||||||
|  | 		calloc(1, sizeof(struct roots_xdg_surface)); | ||||||
|  | 	if (!roots_surface) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	roots_surface->surface_commit.notify = handle_surface_commit; | ||||||
|  | 	wl_signal_add(&surface->surface->events.commit, | ||||||
|  | 		&roots_surface->surface_commit); | ||||||
|  | 	roots_surface->destroy.notify = handle_destroy; | ||||||
|  | 	wl_signal_add(&surface->events.destroy, &roots_surface->destroy); | ||||||
|  | 	roots_surface->request_move.notify = handle_request_move; | ||||||
|  | 	wl_signal_add(&surface->events.request_move, &roots_surface->request_move); | ||||||
|  | 	roots_surface->request_resize.notify = handle_request_resize; | ||||||
|  | 	wl_signal_add(&surface->events.request_resize, | ||||||
|  | 		&roots_surface->request_resize); | ||||||
|  | 	roots_surface->request_maximize.notify = handle_request_maximize; | ||||||
|  | 	wl_signal_add(&surface->events.request_maximize, | ||||||
|  | 		&roots_surface->request_maximize); | ||||||
|  | 	roots_surface->request_fullscreen.notify = handle_request_fullscreen; | ||||||
|  | 	wl_signal_add(&surface->events.request_fullscreen, | ||||||
|  | 		&roots_surface->request_fullscreen); | ||||||
|  | 	roots_surface->new_popup.notify = handle_new_popup; | ||||||
|  | 	wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); | ||||||
|  | 
 | ||||||
|  | 	struct roots_view *view = calloc(1, sizeof(struct roots_view)); | ||||||
|  | 	if (!view) { | ||||||
|  | 		free(roots_surface); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	view->type = ROOTS_XDG_SHELL_VIEW; | ||||||
|  | 
 | ||||||
|  | 	view->xdg_surface = surface; | ||||||
|  | 	view->roots_xdg_surface = roots_surface; | ||||||
|  | 	view->wlr_surface = surface->surface; | ||||||
|  | 	view->activate = activate; | ||||||
|  | 	view->resize = resize; | ||||||
|  | 	view->move_resize = move_resize; | ||||||
|  | 	view->maximize = maximize; | ||||||
|  | 	view->set_fullscreen = set_fullscreen; | ||||||
|  | 	view->close = close; | ||||||
|  | 	roots_surface->view = view; | ||||||
|  | 
 | ||||||
|  | 	struct wlr_box box; | ||||||
|  | 	get_size(view, &box); | ||||||
|  | 	view->width = box.width; | ||||||
|  | 	view->height = box.height; | ||||||
|  | 
 | ||||||
|  | 	view_init(view, desktop); | ||||||
|  | 	wl_list_insert(&desktop->views, &view->link); | ||||||
|  | 
 | ||||||
|  | 	view_setup(view); | ||||||
|  | } | ||||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								
					Loading…
					
					
				
		Reference in new issue