parent
							
								
									c618a76540
								
							
						
					
					
						commit
						9e68ed2159
					
				| @ -0,0 +1,34 @@ | |||||||
|  | /*
 | ||||||
|  |  * This an unstable interface of wlroots. No guarantees are made regarding the | ||||||
|  |  * future consistency of this API. | ||||||
|  |  */ | ||||||
|  | #ifndef WLR_USE_UNSTABLE | ||||||
|  | #error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef WLR_TYPES_WLR_VIEWPORTER_H | ||||||
|  | #define WLR_TYPES_WLR_VIEWPORTER_H | ||||||
|  | 
 | ||||||
|  | #include <wayland-server-core.h> | ||||||
|  | 
 | ||||||
|  | struct wlr_viewporter { | ||||||
|  | 	struct wl_global *global; | ||||||
|  | 
 | ||||||
|  | 	struct { | ||||||
|  | 		struct wl_signal destroy; | ||||||
|  | 	} events; | ||||||
|  | 
 | ||||||
|  | 	struct wl_listener display_destroy; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_viewport { | ||||||
|  | 	struct wl_resource *resource; | ||||||
|  | 	struct wlr_surface *surface; | ||||||
|  | 
 | ||||||
|  | 	struct wl_listener surface_destroy; | ||||||
|  | 	struct wl_listener surface_commit; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct wlr_viewporter *wlr_viewporter_create(struct wl_display *display); | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
| @ -0,0 +1,224 @@ | |||||||
|  | #include <assert.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <wlr/types/wlr_surface.h> | ||||||
|  | #include <wlr/types/wlr_viewporter.h> | ||||||
|  | #include <wlr/util/log.h> | ||||||
|  | #include "util/signal.h" | ||||||
|  | #include "viewporter-protocol.h" | ||||||
|  | 
 | ||||||
|  | #define VIEWPORTER_VERSION 1 | ||||||
|  | 
 | ||||||
|  | static const struct wp_viewport_interface viewport_impl; | ||||||
|  | 
 | ||||||
|  | // Returns NULL if the viewport is inert
 | ||||||
|  | static struct wlr_viewport *viewport_from_resource( | ||||||
|  | 		struct wl_resource *resource) { | ||||||
|  | 	assert(wl_resource_instance_of(resource, &wp_viewport_interface, | ||||||
|  | 		&viewport_impl)); | ||||||
|  | 	return wl_resource_get_user_data(resource); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void viewport_handle_destroy(struct wl_client *client, | ||||||
|  | 		struct wl_resource *resource) { | ||||||
|  | 	wl_resource_destroy(resource); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void viewport_handle_set_source(struct wl_client *client, | ||||||
|  | 		struct wl_resource *resource, wl_fixed_t x_fixed, wl_fixed_t y_fixed, | ||||||
|  | 		wl_fixed_t width_fixed, wl_fixed_t height_fixed) { | ||||||
|  | 	struct wlr_viewport *viewport = viewport_from_resource(resource); | ||||||
|  | 	if (viewport == NULL) { | ||||||
|  | 		wl_resource_post_error(resource, WP_VIEWPORT_ERROR_NO_SURFACE, | ||||||
|  | 			"wp_viewport.set_source sent after wl_surface has been destroyed"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	struct wlr_surface_state *pending = &viewport->surface->pending; | ||||||
|  | 
 | ||||||
|  | 	double x = wl_fixed_to_double(x_fixed); | ||||||
|  | 	double y = wl_fixed_to_double(y_fixed); | ||||||
|  | 	double width = wl_fixed_to_double(width_fixed); | ||||||
|  | 	double height = wl_fixed_to_double(height_fixed); | ||||||
|  | 
 | ||||||
|  | 	if (x == -1.0 && y == -1.0 && width == -1.0 && height == -1.0) { | ||||||
|  | 		pending->viewport.has_src = false; | ||||||
|  | 	} else if (x < 0 || y < 0 || width <= 0 || height <= 0) { | ||||||
|  | 		wl_resource_post_error(resource, WP_VIEWPORT_ERROR_BAD_VALUE, | ||||||
|  | 			"wl_viewport.set_source sent with invalid values"); | ||||||
|  | 		return; | ||||||
|  | 	} else { | ||||||
|  | 		pending->viewport.has_src = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pending->viewport.src.x = x; | ||||||
|  | 	pending->viewport.src.y = y; | ||||||
|  | 	pending->viewport.src.width = width; | ||||||
|  | 	pending->viewport.src.height = height; | ||||||
|  | 
 | ||||||
|  | 	pending->committed |= WLR_SURFACE_STATE_VIEWPORT; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void viewport_handle_set_destination(struct wl_client *client, | ||||||
|  | 		struct wl_resource *resource, int32_t width, int32_t height) { | ||||||
|  | 	struct wlr_viewport *viewport = viewport_from_resource(resource); | ||||||
|  | 	if (viewport == NULL) { | ||||||
|  | 		wl_resource_post_error(resource, WP_VIEWPORT_ERROR_NO_SURFACE, | ||||||
|  | 			"wp_viewport.set_destination sent after wl_surface has been destroyed"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	struct wlr_surface_state *pending = &viewport->surface->pending; | ||||||
|  | 
 | ||||||
|  | 	if (width == -1 && height == -1) { | ||||||
|  | 		pending->viewport.has_dst = false; | ||||||
|  | 	} else if (width <= 0 || height <= 0) { | ||||||
|  | 		wl_resource_post_error(resource, WP_VIEWPORT_ERROR_BAD_VALUE, | ||||||
|  | 			"wl_viewport.set_destination sent with invalid values"); | ||||||
|  | 		return; | ||||||
|  | 	} else { | ||||||
|  | 		pending->viewport.has_dst = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pending->viewport.dst_width = width; | ||||||
|  | 	pending->viewport.dst_height = height; | ||||||
|  | 
 | ||||||
|  | 	pending->committed |= WLR_SURFACE_STATE_VIEWPORT; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct wp_viewport_interface viewport_impl = { | ||||||
|  | 	.destroy = viewport_handle_destroy, | ||||||
|  | 	.set_source = viewport_handle_set_source, | ||||||
|  | 	.set_destination = viewport_handle_set_destination, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void viewport_destroy(struct wlr_viewport *viewport) { | ||||||
|  | 	if (viewport == NULL) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	wl_resource_set_user_data(viewport->resource, NULL); | ||||||
|  | 	wl_list_remove(&viewport->surface_destroy.link); | ||||||
|  | 	wl_list_remove(&viewport->surface_commit.link); | ||||||
|  | 	free(viewport); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void viewport_handle_resource_destroy(struct wl_resource *resource) { | ||||||
|  | 	struct wlr_viewport *viewport = viewport_from_resource(resource); | ||||||
|  | 	viewport_destroy(viewport); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void viewport_handle_surface_destroy(struct wl_listener *listener, | ||||||
|  | 		void *data) { | ||||||
|  | 	struct wlr_viewport *viewport = | ||||||
|  | 		wl_container_of(listener, viewport, surface_destroy); | ||||||
|  | 	viewport_destroy(viewport); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void viewport_handle_surface_commit(struct wl_listener *listener, | ||||||
|  | 		void *data) { | ||||||
|  | 	struct wlr_viewport *viewport = | ||||||
|  | 		wl_container_of(listener, viewport, surface_commit); | ||||||
|  | 
 | ||||||
|  | 	struct wlr_surface_state *current = &viewport->surface->pending; | ||||||
|  | 
 | ||||||
|  | 	if (!current->viewport.has_dst && | ||||||
|  | 			(floor(current->viewport.src.width) != current->viewport.src.width || | ||||||
|  | 			floor(current->viewport.src.height) != current->viewport.src.height)) { | ||||||
|  | 		wl_resource_post_error(viewport->resource, WP_VIEWPORT_ERROR_BAD_SIZE, | ||||||
|  | 			"wl_viewport.set_source width and height must be integers " | ||||||
|  | 			"when the destination rectangle is unset"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (current->viewport.has_src && current->buffer_resource != NULL && | ||||||
|  | 			(current->viewport.src.x + current->viewport.src.width > | ||||||
|  | 				current->buffer_width || | ||||||
|  | 			current->viewport.src.y + current->viewport.src.height > | ||||||
|  | 				current->buffer_height)) { | ||||||
|  | 		wl_resource_post_error(viewport->resource, WP_VIEWPORT_ERROR_OUT_OF_BUFFER, | ||||||
|  | 			"source rectangle out of buffer bounds"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void viewporter_handle_destroy(struct wl_client *client, | ||||||
|  | 		struct wl_resource *resource) { | ||||||
|  | 	wl_resource_destroy(resource); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void viewporter_handle_get_viewport(struct wl_client *client, | ||||||
|  | 		struct wl_resource *resource, uint32_t id, | ||||||
|  | 		struct wl_resource *surface_resource) { | ||||||
|  | 	struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); | ||||||
|  | 
 | ||||||
|  | 	struct wlr_viewport *viewport = calloc(1, sizeof(*viewport)); | ||||||
|  | 	if (viewport == NULL) { | ||||||
|  | 		wl_client_post_no_memory(client); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	uint32_t version = wl_resource_get_version(resource); | ||||||
|  | 	viewport->resource = wl_resource_create(client, &wp_viewport_interface, | ||||||
|  | 		version, id); | ||||||
|  | 	if (viewport->resource == NULL) { | ||||||
|  | 		wl_client_post_no_memory(client); | ||||||
|  | 		free(viewport); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	wl_resource_set_implementation(viewport->resource, &viewport_impl, | ||||||
|  | 		viewport, viewport_handle_resource_destroy); | ||||||
|  | 
 | ||||||
|  | 	viewport->surface = surface; | ||||||
|  | 
 | ||||||
|  | 	viewport->surface_destroy.notify = viewport_handle_surface_destroy; | ||||||
|  | 	wl_signal_add(&surface->events.destroy, &viewport->surface_destroy); | ||||||
|  | 
 | ||||||
|  | 	viewport->surface_commit.notify = viewport_handle_surface_commit; | ||||||
|  | 	wl_signal_add(&surface->events.commit, &viewport->surface_commit); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct wp_viewporter_interface viewporter_impl = { | ||||||
|  | 	.destroy = viewporter_handle_destroy, | ||||||
|  | 	.get_viewport = viewporter_handle_get_viewport, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void viewporter_bind(struct wl_client *client, void *data, | ||||||
|  | 		uint32_t version, uint32_t id) { | ||||||
|  | 	struct wlr_viewporter *viewporter = data; | ||||||
|  | 
 | ||||||
|  | 	struct wl_resource *resource = wl_resource_create(client, | ||||||
|  | 		&wp_viewporter_interface, version, id); | ||||||
|  | 	if (resource == NULL) { | ||||||
|  | 		wl_client_post_no_memory(client); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	wl_resource_set_implementation(resource, &viewporter_impl, viewporter, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void handle_display_destroy(struct wl_listener *listener, void *data) { | ||||||
|  | 	struct wlr_viewporter *viewporter = | ||||||
|  | 		wl_container_of(listener, viewporter, display_destroy); | ||||||
|  | 	wlr_signal_emit_safe(&viewporter->events.destroy, NULL); | ||||||
|  | 	wl_global_destroy(viewporter->global); | ||||||
|  | 	free(viewporter); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct wlr_viewporter *wlr_viewporter_create(struct wl_display *display) { | ||||||
|  | 	struct wlr_viewporter *viewporter = calloc(1, sizeof(*viewporter)); | ||||||
|  | 	if (viewporter == NULL) { | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	viewporter->global = wl_global_create(display, &wp_viewporter_interface, | ||||||
|  | 		VIEWPORTER_VERSION, viewporter, viewporter_bind); | ||||||
|  | 	if (viewporter->global == NULL) { | ||||||
|  | 		free(viewporter); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	wl_signal_init(&viewporter->events.destroy); | ||||||
|  | 
 | ||||||
|  | 	viewporter->display_destroy.notify = handle_display_destroy; | ||||||
|  | 	wl_display_add_destroy_listener(display, &viewporter->display_destroy); | ||||||
|  | 
 | ||||||
|  | 	return viewporter; | ||||||
|  | } | ||||||
					Loading…
					
					
				
		Reference in new issue