diff options
82 files changed, 3293 insertions, 1999 deletions
diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 75b44210..43a8d017 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -173,7 +173,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,  	}  	if (!wlr_egl_bind_display(&drm->renderer.egl, display)) { -		wlr_log(L_INFO, "Failed to bind egl/wl display: %s", egl_error()); +		wlr_log(L_INFO, "Failed to bind egl/wl display");  	}  	drm->display_destroy.notify = handle_display_destroy; diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 3b714300..524e80bb 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -15,9 +15,9 @@  #include <wayland-util.h>  #include <wlr/backend/interface.h>  #include <wlr/interfaces/wlr_output.h> -#include <wlr/render.h>  #include <wlr/render/gles2.h> -#include <wlr/render/matrix.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/util/log.h>  #include <xf86drm.h>  #include <xf86drmMode.h> @@ -544,10 +544,10 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,  	if (!crtc) {  		return false;  	} -	struct wlr_drm_plane *plane = crtc->cursor; -	// We don't have a real cursor plane, so we make a fake one +	struct wlr_drm_plane *plane = crtc->cursor;  	if (!plane) { +		// We don't have a real cursor plane, so we make a fake one  		plane = calloc(1, sizeof(*plane));  		if (!plane) {  			wlr_log_errno(L_ERROR, "Allocation failed"); @@ -556,16 +556,6 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,  		crtc->cursor = plane;  	} -	if (!buf && update_pixels) { -		// Hide the cursor -		plane->cursor_enabled = false; -		if (!drm->session->active) { -			return true; -		} -		return drm->iface->crtc_set_cursor(drm, crtc, NULL); -	} -	plane->cursor_enabled = true; -  	if (!plane->surf.gbm) {  		int ret;  		uint64_t w, h; @@ -592,13 +582,10 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,  			return false;  		} -		// OpenGL will read the pixels out upside down, -		// so we need to flip the image vertically -		enum wl_output_transform transform = wlr_output_transform_compose( -			wlr_output_transform_invert(output->transform), -			WL_OUTPUT_TRANSFORM_FLIPPED_180); -		wlr_matrix_texture(plane->matrix, plane->surf.width, plane->surf.height, -			transform); +		enum wl_output_transform transform = +			wlr_output_transform_invert(output->transform); +		wlr_matrix_projection(plane->matrix, plane->surf.width, +			plane->surf.height, transform);  		plane->wlr_tex =  			wlr_render_texture_create(plane->surf.renderer->wlr_rend); @@ -607,62 +594,71 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,  		}  	} -	struct wlr_box hotspot = { -		.x = hotspot_x, -		.y = hotspot_y, -	}; +	struct wlr_box hotspot = { .x = hotspot_x, .y = hotspot_y };  	enum wl_output_transform transform =  		wlr_output_transform_invert(output->transform);  	wlr_box_transform(&hotspot, transform,  		plane->surf.width, plane->surf.height, &hotspot); -	plane->cursor_hotspot_x = hotspot.x; -	plane->cursor_hotspot_y = hotspot.y; + +	if (plane->cursor_hotspot_x != hotspot.x || +			plane->cursor_hotspot_y != hotspot.y) { +		// Update cursor hotspot +		conn->cursor_x -= hotspot.x - plane->cursor_hotspot_x; +		conn->cursor_y -= hotspot.y - plane->cursor_hotspot_y; +		plane->cursor_hotspot_x = hotspot.x; +		plane->cursor_hotspot_y = hotspot.y; + +		if (!drm->iface->crtc_move_cursor(drm, conn->crtc, conn->cursor_x, +				conn->cursor_y)) { +			return false; +		} + +		wlr_output_update_needs_swap(output); +	}  	if (!update_pixels) { -		// Only update the cursor hotspot +		// Don't update cursor image  		return true;  	} -	struct gbm_bo *bo = plane->cursor_bo; -	uint32_t bo_width = gbm_bo_get_width(bo); -	uint32_t bo_height = gbm_bo_get_height(bo); -	uint32_t bo_stride; -	void *bo_data; +	plane->cursor_enabled = buf != NULL; -	if (!gbm_bo_map(bo, 0, 0, bo_width, bo_height, -			GBM_BO_TRANSFER_WRITE, &bo_stride, &bo_data)) { -		wlr_log_errno(L_ERROR, "Unable to map buffer"); -		return false; -	} +	if (buf != NULL) { +		uint32_t bo_width = gbm_bo_get_width(plane->cursor_bo); +		uint32_t bo_height = gbm_bo_get_height(plane->cursor_bo); -	wlr_drm_surface_make_current(&plane->surf, NULL); +		uint32_t bo_stride; +		void *bo_data; +		if (!gbm_bo_map(plane->cursor_bo, 0, 0, bo_width, bo_height, +				GBM_BO_TRANSFER_WRITE, &bo_stride, &bo_data)) { +			wlr_log_errno(L_ERROR, "Unable to map buffer"); +			return false; +		} -	wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888, -		stride, width, height, buf); +		wlr_drm_surface_make_current(&plane->surf, NULL); -	glViewport(0, 0, plane->surf.width, plane->surf.height); -	glClearColor(0.0, 0.0, 0.0, 0.0); -	glClear(GL_COLOR_BUFFER_BIT); +		wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888, +			stride, width, height, buf); -	float matrix[16]; -	wlr_texture_get_matrix(plane->wlr_tex, &matrix, &plane->matrix, 0, 0); -	wlr_render_with_matrix(plane->surf.renderer->wlr_rend, plane->wlr_tex, -		&matrix, 1.0f); +		struct wlr_renderer *rend = plane->surf.renderer->wlr_rend; +		wlr_renderer_begin(rend, plane->surf.width, plane->surf.height); +		wlr_renderer_clear(rend, (float[]){ 0.0, 0.0, 0.0, 0.0 }); +		wlr_render_texture(rend, plane->wlr_tex, plane->matrix, 0, 0, 1.0f); +		wlr_renderer_end(rend); -	glFinish(); -	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, bo_stride); -	glReadPixels(0, 0, plane->surf.width, plane->surf.height, GL_BGRA_EXT, -		GL_UNSIGNED_BYTE, bo_data); -	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); +		wlr_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, bo_stride, +			plane->surf.width, plane->surf.height, 0, 0, 0, 0, bo_data); -	wlr_drm_surface_swap_buffers(&plane->surf, NULL); +		wlr_drm_surface_swap_buffers(&plane->surf, NULL); -	gbm_bo_unmap(bo, bo_data); +		gbm_bo_unmap(plane->cursor_bo, bo_data); +	}  	if (!drm->session->active) { -		return true; +		return true; // will be committed when session is resumed  	} +	struct gbm_bo *bo = plane->cursor_enabled ? plane->cursor_bo : NULL;  	bool ok = drm->iface->crtc_set_cursor(drm, crtc, bo);  	if (ok) {  		wlr_output_update_needs_swap(output); @@ -697,7 +693,7 @@ static bool wlr_drm_connector_move_cursor(struct wlr_output *output,  	conn->cursor_y = box.y;  	if (!drm->session->active) { -		return true; +		return true; // will be committed when session is resumed  	}  	bool ok = drm->iface->crtc_move_cursor(drm, conn->crtc, box.x, box.y); diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 7ee13843..b2998b5f 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -1,15 +1,15 @@ +#include <assert.h>  #include <EGL/egl.h>  #include <EGL/eglext.h>  #include <gbm.h> -#include <GLES2/gl2.h>  #include <stdbool.h>  #include <stdlib.h>  #include <unistd.h>  #include <wayland-util.h> -#include <wlr/render.h>  #include <wlr/render/egl.h>  #include <wlr/render/gles2.h> -#include <wlr/render/matrix.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/util/log.h>  #include "backend/drm/drm.h"  #include "glapi.h" @@ -106,9 +106,6 @@ void wlr_drm_surface_finish(struct wlr_drm_surface *surf) {  		return;  	} -	eglMakeCurrent(surf->renderer->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, -		EGL_NO_CONTEXT); -  	if (surf->front) {  		gbm_surface_release_buffer(surf->gbm, surf->front);  	} @@ -150,9 +147,10 @@ struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_surface *surf) {  	}  	wlr_drm_surface_make_current(surf, NULL); -	glViewport(0, 0, surf->width, surf->height); -	glClearColor(0.0, 0.0, 0.0, 1.0); -	glClear(GL_COLOR_BUFFER_BIT); +	struct wlr_renderer *renderer = surf->renderer->wlr_rend; +	wlr_renderer_begin(renderer, surf->width, surf->height); +	wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 }); +	wlr_renderer_end(renderer);  	return wlr_drm_surface_swap_buffers(surf, NULL);  } @@ -177,12 +175,15 @@ static void free_eglimage(struct gbm_bo *bo, void *data) {  	free(tex);  } -static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, struct gbm_bo *bo) { +static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, +		struct gbm_bo *bo) {  	struct tex *tex = gbm_bo_get_user_data(bo);  	if (tex) {  		return tex->tex;  	} +	// TODO: use wlr_texture_upload_dmabuf instead +  	tex = malloc(sizeof(*tex));  	if (!tex) {  		wlr_log_errno(L_ERROR, "Allocation failed"); @@ -209,7 +210,7 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, str  	tex->img = eglCreateImageKHR(renderer->egl.display, EGL_NO_CONTEXT,  		EGL_LINUX_DMA_BUF_EXT, NULL, attribs);  	if (!tex->img) { -		wlr_log(L_ERROR, "Failed to create EGL image: %s", egl_error()); +		wlr_log(L_ERROR, "Failed to create EGL image");  		abort();  	} @@ -226,26 +227,23 @@ struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest,  	wlr_drm_surface_make_current(dest, NULL);  	struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src); +	assert(tex); -	static const float matrix[16] = { -		[0] = 2.0f, -		[3] = -1.0f, -		[5] = 2.0f, -		[7] = -1.0f, -		[10] = 1.0f, -		[15] = 1.0f, -	}; +	float mat[9]; +	wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_FLIPPED_180); -	glViewport(0, 0, dest->width, dest->height); -	glClearColor(0.0, 0.0, 0.0, 1.0); -	glClear(GL_COLOR_BUFFER_BIT); -	wlr_render_with_matrix(dest->renderer->wlr_rend, tex, &matrix, 1.0f); +	struct wlr_renderer *renderer = dest->renderer->wlr_rend; +	wlr_renderer_begin(renderer, dest->width, dest->height); +	wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 }); +	wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f); +	wlr_renderer_end(renderer);  	return wlr_drm_surface_swap_buffers(dest, NULL);  } -bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane, struct wlr_drm_backend *drm, -		int32_t width, uint32_t height, uint32_t format) { +bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane, +		struct wlr_drm_backend *drm, int32_t width, uint32_t height, +		uint32_t format) {  	if (!drm->parent) {  		return wlr_drm_surface_init(&plane->surf, &drm->renderer, width, height,  			format, GBM_BO_USE_SCANOUT); diff --git a/backend/headless/output.c b/backend/headless/output.c index 6ce8fc35..a13ed22c 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -1,8 +1,8 @@  #include <EGL/egl.h>  #include <EGL/eglext.h> -#include <GLES2/gl2.h>  #include <stdlib.h>  #include <wlr/interfaces/wlr_output.h> +#include <wlr/render/wlr_renderer.h>  #include <wlr/util/log.h>  #include "backend/headless.h"  #include "util/signal.h" @@ -13,7 +13,7 @@ static EGLSurface egl_create_surface(struct wlr_egl *egl, unsigned int width,  	EGLSurface surf = eglCreatePbufferSurface(egl->display, egl->config, attribs);  	if (surf == EGL_NO_SURFACE) { -		wlr_log(L_ERROR, "Failed to create EGL surface: %s", egl_error()); +		wlr_log(L_ERROR, "Failed to create EGL surface");  		return EGL_NO_SURFACE;  	}  	return surf; @@ -120,16 +120,14 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend,  	snprintf(wlr_output->name, sizeof(wlr_output->name), "HEADLESS-%d",  		wl_list_length(&backend->outputs) + 1); -	if (!eglMakeCurrent(output->backend->egl.display, -			output->egl_surface, output->egl_surface, -			output->backend->egl.context)) { -		wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); +	if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface, +			NULL)) {  		goto error;  	} -	glViewport(0, 0, wlr_output->width, wlr_output->height); -	glClearColor(1.0, 1.0, 1.0, 1.0); -	glClear(GL_COLOR_BUFFER_BIT); +	wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height); +	wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 }); +	wlr_renderer_end(backend->renderer);  	struct wl_event_loop *ev = wl_display_get_event_loop(backend->display);  	output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output); diff --git a/backend/wayland/output.c b/backend/wayland/output.c index fc40dea0..d528c888 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -1,5 +1,4 @@  #include <assert.h> -#include <GLES2/gl2.h>  #include <stdint.h>  #include <stdio.h>  #include <stdlib.h> @@ -9,6 +8,7 @@  #include <unistd.h>  #include <wayland-client.h>  #include <wlr/interfaces/wlr_output.h> +#include <wlr/render/wlr_renderer.h>  #include <wlr/util/log.h>  #include "backend/wayland.h"  #include "util/signal.h" @@ -313,27 +313,26 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) {  	output->egl_window = wl_egl_window_create(output->surface,  			wlr_output->width, wlr_output->height); -	output->egl_surface = wlr_egl_create_surface(&backend->egl, output->egl_window); +	output->egl_surface = wlr_egl_create_surface(&backend->egl, +		output->egl_window);  	wl_display_roundtrip(output->backend->remote_display);  	// start rendering loop per callbacks by rendering first frame -	if (!eglMakeCurrent(output->backend->egl.display, -		output->egl_surface, output->egl_surface, -		output->backend->egl.context)) { -		wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); +	if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface, +			NULL)) {  		goto error;  	} -	glViewport(0, 0, wlr_output->width, wlr_output->height); -	glClearColor(1.0, 1.0, 1.0, 1.0); -	glClear(GL_COLOR_BUFFER_BIT); +	wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height); +	wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 }); +	wlr_renderer_end(backend->renderer);  	output->frame_callback = wl_surface_frame(output->surface);  	wl_callback_add_listener(output->frame_callback, &frame_listener, output); -	if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) { -		wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); +	if (!wlr_egl_swap_buffers(&output->backend->egl, output->egl_surface, +			NULL)) {  		goto error;  	} diff --git a/backend/wayland/wl_seat.c b/backend/wayland/wl_seat.c index 841e693d..6ca59130 100644 --- a/backend/wayland/wl_seat.c +++ b/backend/wayland/wl_seat.c @@ -26,6 +26,11 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,  		// GNOME sends a pointer enter when the surface is being destroyed  		return;  	} +	if (wlr_wl_pointer->current_output) { +		wl_list_remove(&wlr_wl_pointer->output_destroy_listener.link); +	} +	wl_signal_add(&output->wlr_output.events.destroy, +		&wlr_wl_pointer->output_destroy_listener);  	wlr_wl_pointer->current_output = output;  	output->enter_serial = serial;  	wlr_wl_output_update_cursor(output); @@ -49,7 +54,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,  	struct wlr_wl_pointer *wlr_wl_pointer =  		(struct wlr_wl_pointer *)dev->pointer;  	if (!wlr_wl_pointer->current_output) { -		wlr_log(L_ERROR, "pointer motion event without current output"); +		wlr_log(L_DEBUG, "pointer motion event without current output");  		return;  	} @@ -231,6 +236,14 @@ static struct wlr_input_device *allocate_device(struct wlr_wl_backend *backend,  	return wlr_device;  } +static void wlr_wl_pointer_handle_output_destroy(struct wl_listener *listener, +		void *data) { +	struct wlr_wl_pointer *wlr_wl_pointer = +		wl_container_of(listener, wlr_wl_pointer, output_destroy_listener); +	wlr_wl_pointer->current_output = NULL; +	wl_list_remove(&wlr_wl_pointer->output_destroy_listener.link); +} +  static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,  		enum wl_seat_capability caps) {  	struct wlr_wl_backend *backend = data; @@ -243,6 +256,8 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,  			wlr_log(L_ERROR, "Unable to allocate wlr_wl_pointer");  			return;  		} +		wlr_wl_pointer->output_destroy_listener.notify = +			wlr_wl_pointer_handle_output_destroy;  		struct wlr_input_device *wlr_device;  		if (!(wlr_device = allocate_device(backend, WLR_INPUT_DEVICE_POINTER))) { diff --git a/backend/x11/backend.c b/backend/x11/backend.c index cb29e518..36d72d9e 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -143,6 +143,7 @@ static bool handle_x11_event(struct wlr_x11_backend *x11, xcb_generic_event_t *e  		};  		wlr_signal_emit_safe(&x11->pointer.events.motion_absolute, &abs); +		free(pointer);  		break;  	}  	case XCB_CLIENT_MESSAGE: { @@ -317,12 +318,17 @@ static void wlr_x11_backend_destroy(struct wlr_backend *backend) {  	wlr_signal_emit_safe(&backend->events.destroy, backend); +	if (x11->event_source) { +		wl_event_source_remove(x11->event_source); +	}  	wl_list_remove(&x11->display_destroy.link);  	wl_event_source_remove(x11->frame_timer);  	wlr_egl_finish(&x11->egl); -	xcb_disconnect(x11->xcb_conn); +	if (x11->xlib_conn) { +		XCloseDisplay(x11->xlib_conn); +	}  	free(x11);  } @@ -419,7 +425,6 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,  error_event:  	wl_event_source_remove(x11->event_source);  error_x11: -	xcb_disconnect(x11->xcb_conn);  	XCloseDisplay(x11->xlib_conn);  	free(x11);  	return NULL; diff --git a/examples/idle-inhibit.c b/examples/idle-inhibit.c index b7b9c21c..c09e6507 100644 --- a/examples/idle-inhibit.c +++ b/examples/idle-inhibit.c @@ -5,8 +5,8 @@  #include <wayland-client.h>  #include <wayland-egl.h>  #include <wlr/render/egl.h> -#include "xdg-shell-client-protocol.h"  #include "idle-inhibit-unstable-v1-client-protocol.h" +#include "xdg-shell-client-protocol.h"  #include <linux/input-event-codes.h> diff --git a/examples/idle.c b/examples/idle.c index 2b155c68..b65a81cf 100644 --- a/examples/idle.c +++ b/examples/idle.c @@ -1,11 +1,11 @@ +#include <getopt.h> +#include <pthread.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h>  #include <unistd.h> -#include <getopt.h> -#include <pthread.h> -#include <wayland-client.h>  #include <wayland-client-protocol.h> +#include <wayland-client.h>  #include <wlr/util/log.h>  #include "idle-client-protocol.h" diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index d3d425f2..43ccdb66 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -1,30 +1,30 @@  #define _POSIX_C_SOURCE 199309L  #define _XOPEN_SOURCE 500 +#include <assert.h> +#include <GLES2/gl2.h> +#include <math.h>  #include <stdio.h>  #include <stdlib.h> -#include <time.h>  #include <string.h> +#include <time.h>  #include <unistd.h> -#include <math.h> -#include <assert.h> -#include <wayland-server.h>  #include <wayland-server-protocol.h> -#include <xkbcommon/xkbcommon.h> -#include <GLES2/gl2.h> -#include <wlr/render/matrix.h> -#include <wlr/render/gles2.h> -#include <wlr/render.h> +#include <wayland-server.h>  #include <wlr/backend.h>  #include <wlr/backend/session.h> +#include <wlr/render/gles2.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_cursor.h>  #include <wlr/types/wlr_keyboard.h> +#include <wlr/types/wlr_list.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/types/wlr_output_layout.h> -#include <wlr/xcursor.h> -#include <wlr/types/wlr_cursor.h>  #include <wlr/util/log.h> -#include <wlr/types/wlr_list.h> -#include "support/shared.h" -#include "support/config.h" +#include <wlr/xcursor.h> +#include <xkbcommon/xkbcommon.h>  #include "support/cat.h" +#include "support/config.h" +#include "support/shared.h"  struct sample_state; diff --git a/examples/output-layout.c b/examples/output-layout.c index 45257be9..45d896b0 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -1,29 +1,29 @@  #define _POSIX_C_SOURCE 199309L  #define _XOPEN_SOURCE 700 +#include <GLES2/gl2.h> +#include <limits.h> +#include <math.h>  #include <stdio.h>  #include <stdlib.h> -#include <time.h>  #include <string.h>  #include <strings.h> +#include <time.h>  #include <unistd.h> -#include <limits.h> -#include <wayland-server.h>  #include <wayland-server-protocol.h> -#include <xkbcommon/xkbcommon.h> -#include <GLES2/gl2.h> -#include <wlr/render/matrix.h> -#include <wlr/render/gles2.h> -#include <wlr/render.h> -#include <wlr/util/log.h> +#include <wayland-server.h>  #include <wlr/backend.h>  #include <wlr/backend/session.h> +#include <wlr/render/gles2.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_keyboard.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/types/wlr_output_layout.h>  #include <wlr/types/wlr_output.h> -#include <wlr/types/wlr_keyboard.h> -#include <math.h> -#include "support/shared.h" -#include "support/config.h" +#include <wlr/util/log.h> +#include <xkbcommon/xkbcommon.h>  #include "support/cat.h" +#include "support/config.h" +#include "support/shared.h"  struct sample_state {  	struct example_config *config; @@ -101,8 +101,8 @@ static void handle_output_frame(struct output_state *output,  	struct wlr_output *wlr_output = output->output;  	wlr_output_make_current(wlr_output, NULL); -	wlr_renderer_begin(sample->renderer, wlr_output); -	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); +	wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); +	wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1});  	animate_cat(sample, output->output); @@ -111,18 +111,14 @@ static void handle_output_frame(struct output_state *output,  		.width = 128, .height = 128,  	};  	if (wlr_output_layout_intersects(sample->layout, output->output, &box)) { -		float matrix[16]; -  		// transform global coordinates to local coordinates  		double local_x = sample->x_offs;  		double local_y = sample->y_offs;  		wlr_output_layout_output_coords(sample->layout, output->output,  			&local_x, &local_y); -		wlr_texture_get_matrix(sample->cat_texture, &matrix, -			&wlr_output->transform_matrix, local_x, local_y); -		wlr_render_with_matrix(sample->renderer, -			sample->cat_texture, &matrix, 1.0f); +		wlr_render_texture(sample->renderer, sample->cat_texture, +			wlr_output->transform_matrix, local_x, local_y, 1.0f);  	}  	wlr_renderer_end(sample->renderer); diff --git a/examples/pointer.c b/examples/pointer.c index 0dbd02d2..e8a0e892 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -1,30 +1,30 @@  #define _POSIX_C_SOURCE 199309L  #define _XOPEN_SOURCE 500 +#include <assert.h> +#include <GLES2/gl2.h> +#include <math.h>  #include <stdio.h>  #include <stdlib.h> -#include <time.h>  #include <string.h> +#include <time.h>  #include <unistd.h> -#include <math.h> -#include <assert.h> -#include <wayland-server.h>  #include <wayland-server-protocol.h> -#include <xkbcommon/xkbcommon.h> -#include <GLES2/gl2.h> -#include <wlr/render/matrix.h> -#include <wlr/render/gles2.h> -#include <wlr/render.h> +#include <wayland-server.h>  #include <wlr/backend.h>  #include <wlr/backend/session.h> +#include <wlr/render/gles2.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_cursor.h>  #include <wlr/types/wlr_keyboard.h> +#include <wlr/types/wlr_list.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/types/wlr_output_layout.h> -#include <wlr/xcursor.h> -#include <wlr/types/wlr_cursor.h>  #include <wlr/util/log.h> -#include <wlr/types/wlr_list.h> -#include "support/shared.h" -#include "support/config.h" +#include <wlr/xcursor.h> +#include <xkbcommon/xkbcommon.h>  #include "support/cat.h" +#include "support/config.h" +#include "support/shared.h"  struct sample_state {  	struct compositor_state *compositor; diff --git a/examples/rotation.c b/examples/rotation.c index 1158ccc4..cbff09a1 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -1,23 +1,23 @@  #define _POSIX_C_SOURCE 199309L  #define _XOPEN_SOURCE 500 +#include <GLES2/gl2.h> +#include <math.h>  #include <stdio.h>  #include <stdlib.h> -#include <time.h>  #include <string.h>  #include <strings.h> +#include <time.h>  #include <unistd.h> -#include <wayland-server.h>  #include <wayland-server-protocol.h> -#include <xkbcommon/xkbcommon.h> -#include <GLES2/gl2.h> -#include <wlr/render/matrix.h> -#include <wlr/render/gles2.h> -#include <wlr/render.h> +#include <wayland-server.h>  #include <wlr/backend.h>  #include <wlr/backend/session.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/render/gles2.h>  #include <wlr/types/wlr_keyboard.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/util/log.h> -#include <math.h> +#include <xkbcommon/xkbcommon.h>  #include "support/shared.h"  #include "support/config.h"  #include "support/cat.h" @@ -43,16 +43,13 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts  	wlr_output_effective_resolution(wlr_output, &width, &height);  	wlr_output_make_current(wlr_output, NULL); -	wlr_renderer_begin(sample->renderer, wlr_output); -	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); +	wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); +	wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); -	float matrix[16];  	for (int y = -128 + (int)odata->y_offs; y < height; y += 128) {  		for (int x = -128 + (int)odata->x_offs; x < width; x += 128) { -			wlr_texture_get_matrix(sample->cat_texture, &matrix, -				&wlr_output->transform_matrix, x, y); -			wlr_render_with_matrix(sample->renderer, -					sample->cat_texture, &matrix, 1.0f); +			wlr_render_texture(sample->renderer, sample->cat_texture, +				wlr_output->transform_matrix, x, y, 1.0f);  		}  	} diff --git a/examples/screenshot.c b/examples/screenshot.c index e73989c6..fb37f32c 100644 --- a/examples/screenshot.c +++ b/examples/screenshot.c @@ -26,6 +26,7 @@  #include <errno.h>  #include <fcntl.h>  #include <limits.h> +#include <stdbool.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h> @@ -36,33 +37,22 @@  #include <wayland-client.h>  #include <wlr/util/log.h>  #include "screenshooter-client-protocol.h" -#include "util/os-compatibility.h"  static struct wl_shm *shm = NULL;  static struct orbital_screenshooter *screenshooter = NULL;  static struct wl_list output_list; -int min_x, min_y, max_x, max_y; -int buffer_copy_done; +static bool buffer_copy_done;  struct screenshooter_output {  	struct wl_output *output; -	struct wl_buffer *buffer; -	int width, height, offset_x, offset_y; -	enum wl_output_transform transform; -	void *data; +	int width, height;  	struct wl_list link;  };  static void output_handle_geometry(void *data, struct wl_output *wl_output,  		int x, int y, int physical_width, int physical_height, int subpixel,  		const char *make, const char *model, int transform) { -	struct screenshooter_output *output = wl_output_get_user_data(wl_output); - -	if (wl_output == output->output) { -		output->offset_x = x; -		output->offset_y = y; -		output->transform = transform; -	} +	// No-op  }  static void output_handle_mode(void *data, struct wl_output *wl_output, @@ -86,7 +76,7 @@ static const struct wl_output_listener output_listener = {  };  static void screenshot_done(void *data, struct orbital_screenshot *screenshot) { -	buffer_copy_done = 1; +	buffer_copy_done = true;  }  static const struct orbital_screenshot_listener screenshot_listener = { @@ -113,7 +103,7 @@ static void handle_global(void *data, struct wl_registry *registry,  static void handle_global_remove(void *data, struct wl_registry *registry,  		uint32_t name) { -	// Unimplemented +	// Who cares?  }  static const struct wl_registry_listener registry_listener = { @@ -123,14 +113,15 @@ static const struct wl_registry_listener registry_listener = {  static int backingfile(off_t size) {  	char template[] = "/tmp/wlroots-shared-XXXXXX"; -	int fd, ret; - -	fd = mkstemp(template); +	int fd = mkstemp(template);  	if (fd < 0) {  		return -1;  	} -	while ((ret = ftruncate(fd, size)) == EINTR) {} +	int ret; +	while ((ret = ftruncate(fd, size)) == EINTR) { +		// No-op +	}  	if (ret < 0) {  		close(fd);  		return -1; @@ -140,7 +131,6 @@ static int backingfile(off_t size) {  	return fd;  } -  static struct wl_buffer *create_shm_buffer(int width, int height,  		void **data_out) {  	int stride = width * 4; @@ -170,91 +160,8 @@ static struct wl_buffer *create_shm_buffer(int width, int height,  	return buffer;  } -static void write_image(const char *filename, int width, int height) { -	int buffer_stride = width * 4; - -	void *data = calloc(1, buffer_stride * height); -	if (!data) { -		return; -	} - -	struct screenshooter_output *output, *next; -	wl_list_for_each_safe(output, next, &output_list, link) { -		int output_stride = output->width * 4; -		uint32_t *src = (uint32_t *)output->data; -		uint32_t *dst = (uint32_t *)(data + -			(output->offset_y - min_y) * buffer_stride + -			(output->offset_x - min_x) * 4); - -		switch (output->transform) { -		case WL_OUTPUT_TRANSFORM_NORMAL: -			for (int i = 0; i < output->height; i++) { -				memcpy(dst, src, output_stride); -				dst += width; -				src += output->width; -			} -			break; -		case WL_OUTPUT_TRANSFORM_FLIPPED: -			for (int i = 0; i < output->height; ++i) { -				for (int j = 0; j < output->width; ++j) { -					dst[i * width + j] = -						src[i * output->width + output->width - 1 - j]; -				} -			} -			break; -		case WL_OUTPUT_TRANSFORM_90: -			for (int i = 0; i < output->width; ++i) { -				for (int j = 0; j < output->height; ++j) { -					dst[i * width + j] = -						src[j * output->width + output->width - 1 - i]; -				} -			} -			break; -		case WL_OUTPUT_TRANSFORM_FLIPPED_90: -			for (int i = 0; i < output->width; ++i) { -				for (int j = 0; j < output->height; ++j) { -					dst[i * width + j] = -						src[(output->height - 1 - j) * output->width + output->width - 1 - i]; -				} -			} -			break; -		case WL_OUTPUT_TRANSFORM_180: -			for (int i = 0; i < output->height; ++i) { -				for (int j = 0; j < output->width; ++j) { -					dst[i * width + j] = -						src[(output->height - 1 - i) * output->width + output->width - 1 - j]; -				} -			} -			break; -		case WL_OUTPUT_TRANSFORM_FLIPPED_180: -			for (int i = 0; i < output->height; ++i) { -				for (int j = 0; j < output->width; ++j) { -					dst[i * width + j] = -						src[(output->height - 1 - i) * output->width + j]; -				} -			} -			break; -		case WL_OUTPUT_TRANSFORM_270: -			for (int i = 0; i < output->width; ++i) { -				for (int j = 0; j < output->height; ++j) { -					dst[i * width + j] = -						src[(output->height - 1 - j) * output->width + i]; -				} -			} -			break; -		case WL_OUTPUT_TRANSFORM_FLIPPED_270: -			for (int i = 0; i < output->width; ++i) { -				for (int j = 0; j < output->height; ++j) { -					dst[i * width + j] = -						src[j * output->width + i]; -				} -			} -			break; -		} - -		free(output); -	} - +static void write_image(const char *filename, int width, int height, +		void *data) {  	char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits  	sprintf(size, "%dx%d+0", width, height); @@ -270,12 +177,11 @@ static void write_image(const char *filename, int width, int height) {  		exit(EXIT_FAILURE);  	} else if (child != 0) {  		close(fd[0]); -		if (write(fd[1], data, buffer_stride * height) < 0) { +		if (write(fd[1], data, 4 * width * height) < 0) {  			fprintf(stderr, "write() failed: %s\n", strerror(errno));  			exit(EXIT_FAILURE);  		}  		close(fd[1]); -		free(data);  		waitpid(child, NULL, 0);  	} else {  		close(fd[1]); @@ -293,38 +199,9 @@ static void write_image(const char *filename, int width, int height) {  	}  } -static int set_buffer_size(int *width, int *height) { -	int owidth, oheight; -	min_x = min_y = INT_MAX; -	max_x = max_y = INT_MIN; - -	struct screenshooter_output *output; -	wl_list_for_each(output, &output_list, link) { -		if (output->transform & 0x1) { -			owidth = output->height; -			oheight = output->width; -		} else { -			owidth = output->width; -			oheight = output->height; -		} -		min_x = MIN(min_x, output->offset_x); -		min_y = MIN(min_y, output->offset_y); -		max_x = MAX(max_x, output->offset_x + owidth); -		max_y = MAX(max_y, output->offset_y + oheight); -	} - -	if (max_x <= min_x || max_y <= min_y) { -		return -1; -	} - -	*width = max_x - min_x; -	*height = max_y - min_y; - -	return 0; -} -  int main(int argc, char *argv[]) {  	wlr_log_init(L_DEBUG, NULL); +  	struct wl_display * display = wl_display_connect(NULL);  	if (display == NULL) {  		fprintf(stderr, "failed to create display: %m\n"); @@ -342,27 +219,31 @@ int main(int argc, char *argv[]) {  		return -1;  	} -	int width, height; -	if (set_buffer_size(&width, &height)) { -		fprintf(stderr, "cannot set buffer size\n"); -		return -1; -	} - +	int i = 0;  	struct screenshooter_output *output;  	wl_list_for_each(output, &output_list, link) { -		output->buffer = create_shm_buffer(output->width, output->height, &output->data); -		if (output->buffer == NULL) { +		void *data = NULL; +		struct wl_buffer *buffer = +			create_shm_buffer(output->width, output->height, &data); +		if (buffer == NULL) {  			return -1;  		}  		struct orbital_screenshot *screenshot = orbital_screenshooter_shoot( -			screenshooter, output->output, output->buffer); -		orbital_screenshot_add_listener(screenshot, &screenshot_listener, screenshot); -		buffer_copy_done = 0; +			screenshooter, output->output, buffer); +		orbital_screenshot_add_listener(screenshot, &screenshot_listener, +			screenshot); +		buffer_copy_done = false;  		while (!buffer_copy_done) {  			wl_display_roundtrip(display);  		} + +		char filename[24 + 10]; // int32_t are max 10 digits +		snprintf(filename, sizeof(filename), "wayland-screenshot-%d.png", i); + +		write_image(filename, output->width, output->height, data); +		wl_buffer_destroy(buffer); +		++i;  	} -	write_image("wayland-screenshot.png", width, height);  	return EXIT_SUCCESS;  } diff --git a/examples/simple.c b/examples/simple.c index 90808b0f..79db4a0c 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -1,11 +1,11 @@  #define _POSIX_C_SOURCE 199309L -#include <string.h> +#include <GLES2/gl2.h> +#include <inttypes.h>  #include <stdio.h>  #include <stdlib.h> +#include <string.h>  #include <time.h> -#include <inttypes.h>  #include <wayland-server.h> -#include <GLES2/gl2.h>  #include <wlr/backend.h>  #include <wlr/backend/session.h>  #include <wlr/types/wlr_output.h> diff --git a/examples/tablet.c b/examples/tablet.c index 5bfa1271..9379fac3 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -1,27 +1,27 @@  #define _POSIX_C_SOURCE 199309L  #define _XOPEN_SOURCE 500 +#include <GLES2/gl2.h> +#include <math.h>  #include <stdio.h>  #include <stdlib.h> -#include <time.h>  #include <string.h> +#include <time.h>  #include <unistd.h> -#include <wayland-server.h>  #include <wayland-server-protocol.h> -#include <xkbcommon/xkbcommon.h> -#include <GLES2/gl2.h> -#include <wlr/render/matrix.h> -#include <wlr/render/gles2.h> -#include <wlr/render.h> +#include <wayland-server.h>  #include <wlr/backend.h>  #include <wlr/backend/session.h> +#include <wlr/render/gles2.h> +#include <wlr/render/wlr_renderer.h>  #include <wlr/types/wlr_box.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/types/wlr_output.h> -#include <wlr/types/wlr_tablet_tool.h>  #include <wlr/types/wlr_tablet_pad.h> +#include <wlr/types/wlr_tablet_tool.h>  #include <wlr/util/log.h> -#include <math.h> -#include "support/shared.h" +#include <xkbcommon/xkbcommon.h>  #include "support/cat.h" +#include "support/shared.h"  struct sample_state {  	struct wlr_renderer *renderer; @@ -46,10 +46,9 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts  	wlr_output_effective_resolution(wlr_output, &width, &height);  	wlr_output_make_current(wlr_output, NULL); -	wlr_renderer_begin(sample->renderer, wlr_output); -	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); +	wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); +	wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); -	float matrix[16];  	float distance = 0.8f * (1 - sample->distance);  	float tool_color[4] = { distance, distance, distance, 1 };  	for (size_t i = 0; sample->button && i < 4; ++i) { @@ -61,13 +60,12 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts  	float pad_height = sample->height_mm * scale;  	float left = width / 2.0f - pad_width / 2.0f;  	float top = height / 2.0f - pad_height / 2.0f; -	struct wlr_box box = { +	const struct wlr_box box = {  		.x = left, .y = top,  		.width = pad_width, .height = pad_height,  	}; -	wlr_matrix_project_box(&matrix, &box, 0, 0, -			&wlr_output->transform_matrix); -	wlr_render_colored_quad(sample->renderer, &sample->pad_color, &matrix); +	wlr_render_rect(sample->renderer, &box, sample->pad_color, +		wlr_output->transform_matrix);  	if (sample->proximity) {  		struct wlr_box box = { @@ -76,16 +74,17 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts  			.width = 16 * (sample->pressure + 1),  			.height = 16 * (sample->pressure + 1),  		}; -		wlr_matrix_project_box(&matrix, &box, 0, sample->ring, -				&wlr_output->transform_matrix); -		wlr_render_colored_quad(sample->renderer, &tool_color, &matrix); +		float matrix[9]; +		wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, +			sample->ring, wlr_output->transform_matrix); +		wlr_render_quad_with_matrix(sample->renderer, tool_color, matrix); +  		box.x += sample->x_tilt;  		box.y += sample->y_tilt;  		box.width /= 2;  		box.height /= 2; -		wlr_matrix_project_box(&matrix, &box, 0, 0, -				&wlr_output->transform_matrix); -		wlr_render_colored_quad(sample->renderer, &tool_color, &matrix); +		wlr_render_rect(sample->renderer, &box, tool_color, +			wlr_output->transform_matrix);  	}  	wlr_renderer_end(sample->renderer); diff --git a/examples/touch.c b/examples/touch.c index 278252cc..f9c496cf 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -1,25 +1,25 @@  #define _POSIX_C_SOURCE 199309L  #define _XOPEN_SOURCE 500 +#include <GLES2/gl2.h> +#include <math.h> +#include <stdint.h>  #include <stdio.h>  #include <stdlib.h> -#include <time.h>  #include <string.h> +#include <time.h>  #include <unistd.h> -#include <stdint.h> -#include <math.h> -#include <wayland-server.h>  #include <wayland-server-protocol.h> -#include <xkbcommon/xkbcommon.h> -#include <GLES2/gl2.h> -#include <wlr/render/matrix.h> -#include <wlr/render/gles2.h> -#include <wlr/render.h> +#include <wayland-server.h>  #include <wlr/backend.h>  #include <wlr/backend/session.h> +#include <wlr/render/gles2.h> +#include <wlr/render/wlr_renderer.h>  #include <wlr/types/wlr_list.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/util/log.h> -#include "support/shared.h" +#include <xkbcommon/xkbcommon.h>  #include "support/cat.h" +#include "support/shared.h"  struct sample_state {  	struct wlr_renderer *renderer; @@ -42,18 +42,15 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts  	wlr_output_effective_resolution(wlr_output, &width, &height);  	wlr_output_make_current(wlr_output, NULL); -	wlr_renderer_begin(sample->renderer, wlr_output); -	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); +	wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); +	wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); -	float matrix[16];  	struct touch_point *p;  	wl_list_for_each(p, &sample->touch_points, link) { -		wlr_texture_get_matrix(sample->cat_texture, &matrix, -			&wlr_output->transform_matrix, -			(int)(p->x * width) - sample->cat_texture->width / 2, -			(int)(p->y * height) - sample->cat_texture->height / 2); -		wlr_render_with_matrix(sample->renderer, -			sample->cat_texture, &matrix, 1.0f); +		int x = (int)(p->x * width) - sample->cat_texture->width / 2; +		int y = (int)(p->y * height) - sample->cat_texture->height / 2; +		wlr_render_texture(sample->renderer, sample->cat_texture, +			wlr_output->transform_matrix, x, y, 1.0f);  	}  	wlr_renderer_end(sample->renderer); diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index ee3fd38e..26189340 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -26,7 +26,7 @@ struct wlr_drm_plane {  	struct wlr_drm_surface mgpu_surf;  	// Only used by cursor -	float matrix[16]; +	float matrix[9];  	struct wlr_texture *wlr_tex;  	struct gbm_bo *cursor_bo;  	bool cursor_enabled; diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index a56a8673..73adfc27 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -5,7 +5,7 @@  #include <gbm.h>  #include <stdbool.h>  #include <stdint.h> -#include <wlr/render.h> +#include <wlr/render/wlr_renderer.h>  struct wlr_drm_backend;  struct wlr_drm_plane; diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 16c8e13b..00b6ae89 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -7,8 +7,8 @@  #include <wayland-server.h>  #include <wayland-util.h>  #include <wlr/backend/wayland.h> -#include <wlr/render.h>  #include <wlr/render/egl.h> +#include <wlr/render/wlr_renderer.h>  #include <wlr/types/wlr_box.h>  struct wlr_wl_backend { @@ -71,6 +71,7 @@ struct wlr_wl_pointer {  	struct wlr_pointer wlr_pointer;  	enum wlr_axis_source axis_source;  	struct wlr_wl_backend_output *current_output; +	struct wl_listener output_destroy_listener;  };  void wlr_wl_registry_poll(struct wlr_wl_backend *backend); diff --git a/include/render/gles2.h b/include/render/gles2.h index e015160d..43a8d648 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -9,24 +9,33 @@  #include <stdint.h>  #include <string.h>  #include <wlr/backend.h> -#include <wlr/render.h>  #include <wlr/render/egl.h>  #include <wlr/render/interface.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/render/wlr_texture.h>  #include <wlr/util/log.h>  extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; -struct pixel_format { +struct gles2_pixel_format {  	uint32_t wl_format;  	GLint gl_format, gl_type;  	int depth, bpp; -	GLuint *shader; +	bool has_alpha;  };  struct wlr_gles2_renderer {  	struct wlr_renderer wlr_renderer;  	struct wlr_egl *egl; + +	struct { +		GLuint quad; +		GLuint ellipse; +		GLuint tex_rgba; +		GLuint tex_rgbx; +		GLuint tex_ext; +	} shaders;  };  struct wlr_gles2_texture { @@ -34,36 +43,20 @@ struct wlr_gles2_texture {  	struct wlr_egl *egl;  	GLuint tex_id; -	const struct pixel_format *pixel_format; +	const struct gles2_pixel_format *pixel_format;  	EGLImageKHR image; +	GLenum target;  }; -struct shaders { -	bool initialized; -	GLuint rgba, rgbx; -	GLuint quad; -	GLuint ellipse; -	GLuint external; -}; - -extern struct shaders shaders; - -const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt); +const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt); +const enum wl_shm_format *gles2_formats(size_t *len);  struct wlr_texture *gles2_texture_create(); +struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture); -extern const GLchar quad_vertex_src[]; -extern const GLchar quad_fragment_src[]; -extern const GLchar ellipse_fragment_src[]; -extern const GLchar vertex_src[]; -extern const GLchar fragment_src_rgba[]; -extern const GLchar fragment_src_rgbx[]; -extern const GLchar fragment_src_external[]; - -bool _gles2_flush_errors(const char *file, int line); -#define gles2_flush_errors(...) \ -	_gles2_flush_errors(wlr_strip_path(__FILE__), __LINE__) - -#define GL_CALL(func) func; gles2_flush_errors() +void gles2_push_marker(const char *file, const char *func); +void gles2_pop_marker(void); +#define GLES2_DEBUG_PUSH gles2_push_marker(wlr_strip_path(__FILE__), __func__) +#define GLES2_DEBUG_POP gles2_pop_marker()  #endif diff --git a/include/rootston/config.h b/include/rootston/config.h index 9926d9c2..0a67ac1e 100644 --- a/include/rootston/config.h +++ b/include/rootston/config.h @@ -66,8 +66,10 @@ struct roots_config {  	struct wl_list bindings;  	struct wl_list keyboards;  	struct wl_list cursors; +  	char *config_path;  	char *startup_cmd; +	bool debug_damage_tracking;  };  /** diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 467de8ab..5986c96f 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -7,6 +7,7 @@  #include <wlr/types/wlr_compositor.h>  #include <wlr/types/wlr_gamma_control.h>  #include <wlr/types/wlr_idle.h> +#include <wlr/types/wlr_linux_dmabuf.h>  #include <wlr/types/wlr_list.h>  #include <wlr/types/wlr_output_layout.h>  #include <wlr/types/wlr_output.h> @@ -46,6 +47,7 @@ struct roots_desktop {  	struct wlr_primary_selection_device_manager *primary_selection_device_manager;  	struct wlr_idle *idle;  	struct wlr_idle_inhibit_manager_v1 *idle_inhibit; +	struct wlr_linux_dmabuf *linux_dmabuf;  	struct wl_listener new_output;  	struct wl_listener layout_change; @@ -71,14 +73,16 @@ struct roots_output *desktop_output_from_wlr_output(  struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx,  	double ly, struct wlr_surface **surface, double *sx, double *sy); -void view_init(struct roots_view *view, struct roots_desktop *desktop); -void view_finish(struct roots_view *view); +struct roots_view *view_create(struct roots_desktop *desktop); +void view_destroy(struct roots_view *view);  void view_activate(struct roots_view *view, bool activate);  void view_apply_damage(struct roots_view *view);  void view_damage_whole(struct roots_view *view);  void view_update_position(struct roots_view *view, double x, double y);  void view_update_size(struct roots_view *view, uint32_t width, uint32_t height);  void view_initial_focus(struct roots_view *view); +void view_map(struct roots_view *view, struct wlr_surface *surface); +void view_unmap(struct roots_view *view);  void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data);  void handle_xdg_shell_surface(struct wl_listener *listener, void *data); diff --git a/include/rootston/seat.h b/include/rootston/seat.h index cc0293b5..0b1dbe2d 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -39,6 +39,7 @@ struct roots_seat_view {  	struct wl_list link; // roots_seat::views +	struct wl_listener view_unmap;  	struct wl_listener view_destroy;  }; diff --git a/include/rootston/server.h b/include/rootston/server.h index 5f35dd90..7ab15682 100644 --- a/include/rootston/server.h +++ b/include/rootston/server.h @@ -5,7 +5,7 @@  #include <wlr/backend.h>  #include <wlr/backend/session.h>  #include <wlr/config.h> -#include <wlr/render.h> +#include <wlr/render/wlr_renderer.h>  #include <wlr/types/wlr_data_device.h>  #ifdef WLR_HAS_XWAYLAND  #include <wlr/xwayland.h> diff --git a/include/rootston/view.h b/include/rootston/view.h index ff5ef44a..775f3d11 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -27,6 +27,8 @@ struct roots_xdg_surface_v6 {  	struct wl_listener destroy;  	struct wl_listener new_popup; +	struct wl_listener map; +	struct wl_listener unmap;  	struct wl_listener request_move;  	struct wl_listener request_resize;  	struct wl_listener request_maximize; @@ -42,6 +44,8 @@ struct roots_xdg_surface {  	struct wl_listener destroy;  	struct wl_listener new_popup; +	struct wl_listener map; +	struct wl_listener unmap;  	struct wl_listener request_move;  	struct wl_listener request_resize;  	struct wl_listener request_maximize; @@ -128,6 +132,7 @@ struct roots_view {  	struct wl_listener new_subsurface;  	struct { +		struct wl_signal unmap;  		struct wl_signal destroy;  	} events; @@ -140,6 +145,7 @@ struct roots_view {  	void (*maximize)(struct roots_view *view, bool maximized);  	void (*set_fullscreen)(struct roots_view *view, bool fullscreen);  	void (*close)(struct roots_view *view); +	void (*destroy)(struct roots_view *view);  };  struct roots_view_child { @@ -181,7 +187,6 @@ struct roots_xdg_popup {  	struct wl_listener new_popup;  }; -struct roots_view *view_create();  void view_get_box(const struct roots_view *view, struct wlr_box *box);  void view_activate(struct roots_view *view, bool active);  void view_move(struct roots_view *view, double x, double y); diff --git a/include/wlr/backend.h b/include/wlr/backend.h index 00dc9fdc..e3b14add 100644 --- a/include/wlr/backend.h +++ b/include/wlr/backend.h @@ -11,16 +11,39 @@ struct wlr_backend {  	const struct wlr_backend_impl *impl;  	struct { +		/** Raised when destroyed, passed the wlr_backend reference */  		struct wl_signal destroy; +		/** Raised when new inputs are added, passed the wlr_input_device */  		struct wl_signal new_input; +		/** Raised when new outputs are added, passed the wlr_output */  		struct wl_signal new_output;  	} events;  }; +/** + * Automatically initializes the most suitable backend given the environment. + * Will always return a multibackend. The backend is created but not started. + * Returns NULL on failure. + */  struct wlr_backend *wlr_backend_autocreate(struct wl_display *display); +/** + * Start the backend. This may signal new_input or new_output immediately, but + * may also wait until the display's event loop begins. Returns false on + * failure. + */  bool wlr_backend_start(struct wlr_backend *backend); +/** + * Destroy the backend and clean up all of its resources. Normally called + * automatically when the wl_display is destroyed. + */  void wlr_backend_destroy(struct wlr_backend *backend); +/** + * Obtains the wlr_egl reference this backend is using. + */  struct wlr_egl *wlr_backend_get_egl(struct wlr_backend *backend); +/** + * Obtains the wlr_renderer reference this backend is using. + */  struct wlr_renderer *wlr_backend_get_renderer(struct wlr_backend *backend);  uint32_t usec_to_msec(uint64_t usec); diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h index 90460647..0c9e5c8b 100644 --- a/include/wlr/backend/drm.h +++ b/include/wlr/backend/drm.h @@ -6,6 +6,13 @@  #include <wlr/backend/session.h>  #include <wlr/types/wlr_output.h> +/** + * Creates a DRM backend using the specified GPU file descriptor (typically from + * a device node in /dev/dri). + * + * To slave this to another DRM backend, pass it as the parent (which _must_ be + * a DRM backend, other kinds of backends raise SIGABRT). + */  struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,  	struct wlr_session *session, int gpu_fd, struct wlr_backend *parent); diff --git a/include/wlr/backend/headless.h b/include/wlr/backend/headless.h index 8995f7cb..ee784a0d 100644 --- a/include/wlr/backend/headless.h +++ b/include/wlr/backend/headless.h @@ -5,9 +5,23 @@  #include <wlr/types/wlr_input_device.h>  #include <wlr/types/wlr_output.h> +/** + * Creates a headless backend. A headless backend has no outputs or inputs by + * default. + */  struct wlr_backend *wlr_headless_backend_create(struct wl_display *display); +/** + * Create a new headless output backed by an in-memory EGL framebuffer. You can + * read pixels from this framebuffer via wlr_renderer_read_pixels but it is + * otherwise not displayed. + */  struct wlr_output *wlr_headless_add_output(struct wlr_backend *backend,  	unsigned int width, unsigned int height); +/** + * Creates a new input device. The caller is responsible for manually raising + * any event signals on the new input device if it wants to simulate input + * events. + */  struct wlr_input_device *wlr_headless_add_input_device(  	struct wlr_backend *backend, enum wlr_input_device_type type);  bool wlr_backend_is_headless(struct wlr_backend *backend); diff --git a/include/wlr/backend/interface.h b/include/wlr/backend/interface.h index d9212795..f03e95d9 100644 --- a/include/wlr/backend/interface.h +++ b/include/wlr/backend/interface.h @@ -12,6 +12,10 @@ struct wlr_backend_impl {  	struct wlr_renderer *(*get_renderer)(struct wlr_backend *backend);  }; +/** + * Initializes common state on a wlr_backend and sets the implementation to the + * provided wlr_backend_impl reference. + */  void wlr_backend_init(struct wlr_backend *backend,  		const struct wlr_backend_impl *impl); diff --git a/include/wlr/backend/libinput.h b/include/wlr/backend/libinput.h index c7cfe894..92d31415 100644 --- a/include/wlr/backend/libinput.h +++ b/include/wlr/backend/libinput.h @@ -9,7 +9,9 @@  struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display,  		struct wlr_session *session); -struct libinput_device *wlr_libinput_get_device_handle(struct wlr_input_device *dev); +/** Gets the underlying libinput_device handle for the given wlr_input_device */ +struct libinput_device *wlr_libinput_get_device_handle( +		struct wlr_input_device *dev);  bool wlr_backend_is_libinput(struct wlr_backend *backend);  bool wlr_input_device_is_libinput(struct wlr_input_device *device); diff --git a/include/wlr/backend/multi.h b/include/wlr/backend/multi.h index 2dee7403..842eed67 100644 --- a/include/wlr/backend/multi.h +++ b/include/wlr/backend/multi.h @@ -4,11 +4,21 @@  #include <wlr/backend.h>  #include <wlr/backend/session.h> +/** + * Creates a multi-backend. Multi-backends wrap an arbitrary number of backends + * and aggregate their new_output/new_input signals. + */  struct wlr_backend *wlr_multi_backend_create(struct wl_display *display); +/** + * Adds the given backend to the multi backend. This should be done before the + * new backend is started. + */  void wlr_multi_backend_add(struct wlr_backend *multi,  	struct wlr_backend *backend); +  void wlr_multi_backend_remove(struct wlr_backend *multi,  	struct wlr_backend *backend); +  bool wlr_backend_is_multi(struct wlr_backend *backend);  struct wlr_session *wlr_multi_get_session(struct wlr_backend *base);  bool wlr_multi_is_empty(struct wlr_backend *backend); diff --git a/include/wlr/render.h b/include/wlr/render.h deleted file mode 100644 index 747603da..00000000 --- a/include/wlr/render.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef WLR_RENDER_H -#define WLR_RENDER_H - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <stdint.h> -#include <wayland-server-protocol.h> -#include <wlr/types/wlr_box.h> -#include <wlr/types/wlr_output.h> - -struct wlr_texture; -struct wlr_renderer; - -void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *output); -void wlr_renderer_end(struct wlr_renderer *r); -void wlr_renderer_clear(struct wlr_renderer *r, const float (*color)[4]); -/** - * Defines a scissor box. Only pixels that lie within the scissor box can be - * modified by drawing functions. Providing a NULL `box` disables the scissor - * box. - */ -void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box); -/** - * Requests a texture handle from this renderer. - */ -struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r); -/** - * Renders the requested texture using the provided matrix. A typical texture - * rendering goes like so: - * - * 	struct wlr_renderer *renderer; - * 	struct wlr_texture *texture; - * 	float projection[16]; - * 	float matrix[16]; - * 	wlr_texture_get_matrix(texture, &matrix, &projection, 123, 321); - * 	wlr_render_with_matrix(renderer, texture, &matrix, 0.5f); - * - * This will render the texture at <123, 321> with an alpha channel of 0.5. - */ -bool wlr_render_with_matrix(struct wlr_renderer *r, -	struct wlr_texture *texture, const float (*matrix)[16], float alpha); - -/** - * Renders a solid quad in the specified color. - */ -void wlr_render_colored_quad(struct wlr_renderer *r, -	const float (*color)[4], const float (*matrix)[16]); -/** - * Renders a solid ellipse in the specified color. - */ -void wlr_render_colored_ellipse(struct wlr_renderer *r, -	const float (*color)[4], const float (*matrix)[16]); -/** - * Returns a list of pixel formats supported by this renderer. - */ -const enum wl_shm_format *wlr_renderer_get_formats( -	struct wlr_renderer *r, size_t *len); -/** - * Returns true if this wl_buffer is a DRM buffer. - */ -bool wlr_renderer_buffer_is_drm(struct wlr_renderer *renderer, -	struct wl_resource *buffer); -/** - * Reads out of pixels of the currently bound surface into data. `stride` is in - * bytes. - */ -bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt, -	uint32_t stride, uint32_t width, uint32_t height, -	uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, void *data); -/** - * Checks if a format is supported. - */ -bool wlr_renderer_format_supported(struct wlr_renderer *r, -	enum wl_shm_format fmt); -/** - * Destroys this wlr_renderer. Textures must be destroyed separately. - */ -void wlr_renderer_destroy(struct wlr_renderer *renderer); - -struct wlr_texture_impl; - -struct wlr_texture { -	struct wlr_texture_impl *impl; - -	bool valid; -	uint32_t format; -	int width, height; -	struct wl_signal destroy_signal; -	struct wl_resource *resource; -}; - -/** - * Copies pixels to this texture. The buffer is not accessed after this function - * returns. - */ -bool wlr_texture_upload_pixels(struct wlr_texture *tex, -		enum wl_shm_format format, int stride, int width, int height, -		const unsigned char *pixels); -/** - * Copies pixels to this texture. The buffer is not accessed after this function - * returns. Under some circumstances, this function may re-upload the entire - * buffer - therefore, the entire buffer must be valid. - */ -bool wlr_texture_update_pixels(struct wlr_texture *surf, -		enum wl_shm_format format, int stride, int x, int y, -		int width, int height, const unsigned char *pixels); -/** - * Copies pixels from a wl_shm_buffer into this texture. The buffer is not - * accessed after this function returns. - */ -bool wlr_texture_upload_shm(struct wlr_texture *tex, uint32_t format, -		struct wl_shm_buffer *shm); - -/** - * Attaches the contents from the given wl_drm wl_buffer resource onto the - * texture. The wl_resource is not used after this call. - * Will fail (return false) if the given resource is no drm buffer. - */ -bool wlr_texture_upload_drm(struct wlr_texture *tex, -	struct wl_resource *drm_buffer); - -bool wlr_texture_upload_eglimage(struct wlr_texture *tex, -	EGLImageKHR image, uint32_t width, uint32_t height); - -/** - * Copies a rectangle of pixels from a wl_shm_buffer onto the texture. The - * buffer is not accessed after this function returns. Under some circumstances, - * this function may re-upload the entire buffer - therefore, the entire buffer - * must be valid. - */ -bool wlr_texture_update_shm(struct wlr_texture *surf, uint32_t format, -		int x, int y, int width, int height, struct wl_shm_buffer *shm); -/** - * Prepares a matrix with the appropriate scale for the given texture and - * multiplies it with the projection, producing a matrix that the shader can - * muptlipy vertex coordinates with to get final screen coordinates. - * - * The projection matrix is assumed to be an orthographic projection of [0, - * width) and [0, height], and the x and y coordinates provided are used as - * such. - */ -void wlr_texture_get_matrix(struct wlr_texture *texture, -		float (*matrix)[16], const float (*projection)[16], int x, int y); -/** - * Destroys this wlr_texture. - */ -void wlr_texture_destroy(struct wlr_texture *texture); - -#endif diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 97a28016..aa429e8e 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -6,6 +6,7 @@  #include <pixman.h>  #include <stdbool.h>  #include <wayland-server.h> +#include <wlr/types/wlr_linux_dmabuf.h>  struct wlr_egl {  	EGLDisplay display; @@ -18,6 +19,8 @@ struct wlr_egl {  	struct {  		bool buffer_age;  		bool swap_buffers_with_damage; +		bool dmabuf_import; +		bool dmabuf_import_modifiers;  	} egl_exts;  	struct wl_display *wl_display; @@ -62,14 +65,34 @@ EGLImageKHR wlr_egl_create_image(struct wlr_egl *egl,  		EGLenum target, EGLClientBuffer buffer, const EGLint *attribs);  /** - * Destroys an egl image created with the given wlr_egl. + * Creates an egl image from the given dmabuf attributes. Check usability + * of the dmabuf with wlr_egl_check_import_dmabuf once first.   */ -bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImageKHR image); +EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, +		struct wlr_dmabuf_buffer_attribs *attributes);  /** - * Returns a string for the last error ocurred with egl. + * Try to import the given dmabuf. On success return true false otherwise. + * If this succeeds the dmabuf can be used for rendering on a texture   */ -const char *egl_error(void); +bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, +		struct wlr_dmabuf_buffer *dmabuf); + +/** + * Get the available dmabuf formats + */ +int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats); + +/** + * Get the available dmabuf modifiers for a given format + */ +int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format, +		uint64_t **modifiers); + +/** + * Destroys an egl image created with the given wlr_egl. + */ +bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImageKHR image);  bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface,  	int *buffer_age); diff --git a/include/wlr/render/gles2.h b/include/wlr/render/gles2.h index a924a065..b3b43ab2 100644 --- a/include/wlr/render/gles2.h +++ b/include/wlr/render/gles2.h @@ -2,7 +2,7 @@  #define WLR_RENDER_GLES2_H  #include <wlr/backend.h> -#include <wlr/render.h> +#include <wlr/render/wlr_renderer.h>  struct wlr_egl;  struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend); diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index eda5af1c..d4cd35f8 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -5,28 +5,32 @@  #include <EGL/eglext.h>  #include <stdbool.h>  #include <wayland-server-protocol.h> -#include <wlr/render.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/render/wlr_texture.h>  #include <wlr/types/wlr_box.h> +#include <wlr/types/wlr_linux_dmabuf.h>  #include <wlr/types/wlr_output.h>  struct wlr_renderer_impl;  struct wlr_renderer { -	struct wlr_renderer_impl *impl; +	const struct wlr_renderer_impl *impl;  };  struct wlr_renderer_impl { -	void (*begin)(struct wlr_renderer *renderer, struct wlr_output *output); +	void (*begin)(struct wlr_renderer *renderer, uint32_t width, +		uint32_t height);  	void (*end)(struct wlr_renderer *renderer); -	void (*clear)(struct wlr_renderer *renderer, const float (*color)[4]); +	void (*clear)(struct wlr_renderer *renderer, const float color[static 4]);  	void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box);  	struct wlr_texture *(*texture_create)(struct wlr_renderer *renderer); -	bool (*render_with_matrix)(struct wlr_renderer *renderer, -		struct wlr_texture *texture, const float (*matrix)[16], float alpha); -	void (*render_quad)(struct wlr_renderer *renderer, -		const float (*color)[4], const float (*matrix)[16]); -	void (*render_ellipse)(struct wlr_renderer *renderer, -		const float (*color)[4], const float (*matrix)[16]); +	bool (*render_texture_with_matrix)(struct wlr_renderer *renderer, +		struct wlr_texture *texture, const float matrix[static 9], +		float alpha); +	void (*render_quad_with_matrix)(struct wlr_renderer *renderer, +		const float color[static 4], const float matrix[static 9]); +	void (*render_ellipse_with_matrix)(struct wlr_renderer *renderer, +		const float color[static 4], const float matrix[static 9]);  	const enum wl_shm_format *(*formats)(  		struct wlr_renderer *renderer, size_t *len);  	bool (*buffer_is_drm)(struct wlr_renderer *renderer, @@ -41,7 +45,7 @@ struct wlr_renderer_impl {  };  void wlr_renderer_init(struct wlr_renderer *renderer, -		struct wlr_renderer_impl *impl); +		const struct wlr_renderer_impl *impl);  struct wlr_texture_impl {  	bool (*upload_pixels)(struct wlr_texture *texture, @@ -58,18 +62,16 @@ struct wlr_texture_impl {  		struct wl_resource *drm_buf);  	bool (*upload_eglimage)(struct wlr_texture *texture, EGLImageKHR image,  		uint32_t width, uint32_t height); -	void (*get_matrix)(struct wlr_texture *state, -		float (*matrix)[16], const float (*projection)[16], int x, int y); +	bool (*upload_dmabuf)(struct wlr_texture *texture, +		struct wl_resource *dmabuf_resource);  	void (*get_buffer_size)(struct wlr_texture *texture,  		struct wl_resource *resource, int *width, int *height); -	void (*bind)(struct wlr_texture *texture);  	void (*destroy)(struct wlr_texture *texture);  };  void wlr_texture_init(struct wlr_texture *texture, -		struct wlr_texture_impl *impl); -void wlr_texture_bind(struct wlr_texture *texture); +	const struct wlr_texture_impl *impl);  void wlr_texture_get_buffer_size(struct wlr_texture *texture, -		struct wl_resource *resource, int *width, int *height); +	struct wl_resource *resource, int *width, int *height);  #endif diff --git a/include/wlr/render/matrix.h b/include/wlr/render/matrix.h deleted file mode 100644 index a333bf0f..00000000 --- a/include/wlr/render/matrix.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef WLR_RENDER_MATRIX_H -#define WLR_RENDER_MATRIX_H - -#include <stdint.h> -#include <wlr/types/wlr_box.h> - -void wlr_matrix_identity(float (*output)[16]); -void wlr_matrix_translate(float (*output)[16], float x, float y, float z); -void wlr_matrix_scale(float (*output)[16], float x, float y, float z); -void wlr_matrix_rotate(float (*output)[16], float radians); -void wlr_matrix_mul(const float (*x)[16], const float (*y)[16], float (*product)[16]); - -enum wl_output_transform; -void wlr_matrix_transform(float mat[static 16], -		enum wl_output_transform transform); -void wlr_matrix_texture(float mat[static 16], int32_t width, int32_t height, -		enum wl_output_transform transform); -void wlr_matrix_project_box(float (*mat)[16], struct wlr_box *box, -		enum wl_output_transform transform, float rotation, float -		(*projection)[16]); - -#endif diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h new file mode 100644 index 00000000..5c78089e --- /dev/null +++ b/include/wlr/render/wlr_renderer.h @@ -0,0 +1,85 @@ +#ifndef WLR_RENDER_WLR_RENDERER_H +#define WLR_RENDER_WLR_RENDERER_H + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <stdint.h> +#include <wayland-server-protocol.h> +#include <wlr/render/wlr_texture.h> +#include <wlr/types/wlr_box.h> + +struct wlr_output; + +struct wlr_renderer; + +void wlr_renderer_begin(struct wlr_renderer *r, int width, int height); +void wlr_renderer_end(struct wlr_renderer *r); +void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); +/** + * Defines a scissor box. Only pixels that lie within the scissor box can be + * modified by drawing functions. Providing a NULL `box` disables the scissor + * box. + */ +void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box); +/** + * Requests a texture handle from this renderer. + */ +struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r); +/** + * Renders the requested texture. + */ +bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture, +	const float projection[static 9], int x, int y, float alpha); +/** + * Renders the requested texture using the provided matrix. + */ +bool wlr_render_texture_with_matrix(struct wlr_renderer *r, +	struct wlr_texture *texture, const float matrix[static 9], float alpha); +/** + * Renders a solid rectangle in the specified color. + */ +void wlr_render_rect(struct wlr_renderer *r, const struct wlr_box *box, +	const float color[static 4], const float projection[static 9]); +/** + * Renders a solid quadrangle in the specified color with the specified matrix. + */ +void wlr_render_quad_with_matrix(struct wlr_renderer *r, +	const float color[static 4], const float matrix[static 9]); +/** + * Renders a solid ellipse in the specified color. + */ +void wlr_render_ellipse(struct wlr_renderer *r, const struct wlr_box *box, +	const float color[static 4], const float projection[static 9]); +/** + * Renders a solid ellipse in the specified color with the specified matrix. + */ +void wlr_render_ellipse_with_matrix(struct wlr_renderer *r, +	const float color[static 4], const float matrix[static 9]); +/** + * Returns a list of pixel formats supported by this renderer. + */ +const enum wl_shm_format *wlr_renderer_get_formats(struct wlr_renderer *r, +	size_t *len); +/** + * Returns true if this wl_buffer is a DRM buffer. + */ +bool wlr_renderer_buffer_is_drm(struct wlr_renderer *renderer, +	struct wl_resource *buffer); +/** + * Reads out of pixels of the currently bound surface into data. `stride` is in + * bytes. + */ +bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt, +	uint32_t stride, uint32_t width, uint32_t height, +	uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, void *data); +/** + * Checks if a format is supported. + */ +bool wlr_renderer_format_supported(struct wlr_renderer *r, +	enum wl_shm_format fmt); +/** + * Destroys this wlr_renderer. Textures must be destroyed separately. + */ +void wlr_renderer_destroy(struct wlr_renderer *renderer); + +#endif diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h new file mode 100644 index 00000000..095097e6 --- /dev/null +++ b/include/wlr/render/wlr_texture.h @@ -0,0 +1,69 @@ +#ifndef WLR_RENDER_WLR_TEXTURE_H +#define WLR_RENDER_WLR_TEXTURE_H + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <stdint.h> +#include <wayland-server-protocol.h> + +struct wlr_texture_impl; + +struct wlr_texture { +	const struct wlr_texture_impl *impl; + +	bool valid; +	uint32_t format; +	int width, height; +	bool inverted_y; +	struct wl_signal destroy_signal; +	struct wl_resource *resource; +}; + +/** + * Copies pixels to this texture. The buffer is not accessed after this function + * returns. + */ +bool wlr_texture_upload_pixels(struct wlr_texture *tex, +	enum wl_shm_format format, int stride, int width, int height, +	const unsigned char *pixels); +/** + * Copies pixels to this texture. The buffer is not accessed after this function + * returns. Under some circumstances, this function may re-upload the entire + * buffer - therefore, the entire buffer must be valid. + */ +bool wlr_texture_update_pixels(struct wlr_texture *surf, +	enum wl_shm_format format, int stride, int x, int y, +	int width, int height, const unsigned char *pixels); +/** + * Copies pixels from a wl_shm_buffer into this texture. The buffer is not + * accessed after this function returns. + */ +bool wlr_texture_upload_shm(struct wlr_texture *tex, uint32_t format, +	struct wl_shm_buffer *shm); +/** + * Attaches the contents from the given wl_drm wl_buffer resource onto the + * texture. The wl_resource is not used after this call. + * Will fail (return false) if the given resource is no drm buffer. + */ +bool wlr_texture_upload_drm(struct wlr_texture *tex, +	struct wl_resource *drm_buffer); + +bool wlr_texture_upload_eglimage(struct wlr_texture *tex, +	EGLImageKHR image, uint32_t width, uint32_t height); + +bool wlr_texture_upload_dmabuf(struct wlr_texture *tex, +	struct wl_resource *dmabuf_resource); +/** + * Copies a rectangle of pixels from a wl_shm_buffer onto the texture. The + * buffer is not accessed after this function returns. Under some circumstances, + * this function may re-upload the entire buffer - therefore, the entire buffer + * must be valid. + */ +bool wlr_texture_update_shm(struct wlr_texture *surf, uint32_t format, +	int x, int y, int width, int height, struct wl_shm_buffer *shm); +/** + * Destroys this wlr_texture. + */ +void wlr_texture_destroy(struct wlr_texture *texture); + +#endif diff --git a/include/wlr/types/wlr_box.h b/include/wlr/types/wlr_box.h index fc86f0ac..0e586a18 100644 --- a/include/wlr/types/wlr_box.h +++ b/include/wlr/types/wlr_box.h @@ -27,7 +27,7 @@ void wlr_box_transform(const struct wlr_box *box,  	struct wlr_box *dest);  /** - * Creates the smallest box that contains a rotated box. + * Creates the smallest box that contains the box rotated about its center.   */  void wlr_box_rotated_bounds(const struct wlr_box *box, float rotation,  	struct wlr_box *dest); diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 5919b934..11bfac71 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -2,7 +2,7 @@  #define WLR_TYPES_WLR_COMPOSITOR_H  #include <wayland-server.h> -#include <wlr/render.h> +#include <wlr/render/wlr_renderer.h>  struct wlr_compositor {  	struct wl_global *wl_global; diff --git a/include/wlr/types/wlr_linux_dmabuf.h b/include/wlr/types/wlr_linux_dmabuf.h new file mode 100644 index 00000000..9d71e598 --- /dev/null +++ b/include/wlr/types/wlr_linux_dmabuf.h @@ -0,0 +1,84 @@ +#ifndef WLR_TYPES_WLR_LINUX_DMABUF_H +#define WLR_TYPES_WLR_LINUX_DMABUF_H + +#define WLR_LINUX_DMABUF_MAX_PLANES 4 + +#include <stdint.h> +#include <wayland-server-protocol.h> + +/* So we don't have to pull in linux specific drm headers */ +#ifndef DRM_FORMAT_MOD_INVALID +#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1) +#endif + +struct wlr_dmabuf_buffer_attribs { +	/* set via params_add */ +	int n_planes; +	uint32_t offset[WLR_LINUX_DMABUF_MAX_PLANES]; +	uint32_t stride[WLR_LINUX_DMABUF_MAX_PLANES]; +	uint64_t modifier[WLR_LINUX_DMABUF_MAX_PLANES]; +	int fd[WLR_LINUX_DMABUF_MAX_PLANES]; +	/* set via params_create */ +	int32_t width; +	int32_t height; +	uint32_t format; +	uint32_t flags; /* enum zlinux_buffer_params_flags */ +}; + +struct wlr_dmabuf_buffer { +	struct wlr_egl *egl; +	struct wl_resource *buffer_resource; +	struct wl_resource *params_resource; +	struct wlr_dmabuf_buffer_attribs attributes; +}; + +/** + * Returns true if the given resource was created via the linux-dmabuf + * buffer protocol, false otherwise + */ +bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource); + +/** + * Returns the wlr_dmabuf_buffer if the given resource was created + * via the linux-dmabuf buffer protocol + */ +struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource( +	struct wl_resource *buffer_resource); + +/** + * Returns the wlr_dmabuf_buffer if the given resource was created + * via the linux-dmabuf params protocol + */ +struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource( +	struct wl_resource *params_resource); + +/** + * Returns true if the given dmabuf has y-axis inverted, false otherwise + */ +bool wlr_dmabuf_buffer_has_inverted_y(struct wlr_dmabuf_buffer *dmabuf); + +/* the protocol interface */ +struct wlr_linux_dmabuf { +	struct wl_global *wl_global; +	struct wl_listener display_destroy; +	struct wlr_egl *egl; +}; + +/** + * Create linux-dmabuf interface + */ +struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display, +	struct wlr_egl *egl); +/** + * Destroy the linux-dmabuf interface + */ +void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf); + +/** + * Returns the wlr_linux_dmabuf if the given resource was created + * via the linux_dmabuf protocol + */ +struct wlr_linux_dmabuf *wlr_linux_dmabuf_from_resource( +	struct wl_resource *resource); + +#endif diff --git a/include/wlr/types/wlr_matrix.h b/include/wlr/types/wlr_matrix.h new file mode 100644 index 00000000..02111db8 --- /dev/null +++ b/include/wlr/types/wlr_matrix.h @@ -0,0 +1,22 @@ +#ifndef WLR_TYPES_WLR_MATRIX_H +#define WLR_TYPES_WLR_MATRIX_H + +#include <wayland-server.h> +#include <wlr/types/wlr_box.h> + +void wlr_matrix_identity(float mat[static 9]); +void wlr_matrix_multiply(float mat[static 9], const float a[static 9], +	const float b[static 9]); +void wlr_matrix_transpose(float mat[static 9], const float a[static 9]); +void wlr_matrix_translate(float mat[static 9], float x, float y); +void wlr_matrix_scale(float mat[static 9], float x, float y); +void wlr_matrix_rotate(float mat[static 9], float rad); +void wlr_matrix_transform(float mat[static 9], +	enum wl_output_transform transform); +void wlr_matrix_projection(float mat[static 9], int width, int height, +	enum wl_output_transform transform); +void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box, +	enum wl_output_transform transform, float rotation, +	const float projection[static 9]); + +#endif diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index a8138a80..b838a737 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -76,7 +76,7 @@ struct wlr_output {  	// damage for cursors and fullscreen surface, in output-local coordinates  	pixman_region32_t damage;  	bool frame_pending; -	float transform_matrix[16]; +	float transform_matrix[9];  	struct {  		struct wl_signal frame; diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 203345bd..5c5b012f 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -70,8 +70,8 @@ struct wlr_surface {  	struct wlr_surface_state *current, *pending;  	const char *role; // the lifetime-bound role or null -	float buffer_to_surface_matrix[16]; -	float surface_to_buffer_matrix[16]; +	float buffer_to_surface_matrix[9]; +	float surface_to_buffer_matrix[9];  	struct {  		struct wl_signal commit; @@ -99,19 +99,6 @@ struct wlr_surface {  struct wlr_renderer;  struct wlr_surface *wlr_surface_create(struct wl_resource *res,  		struct wlr_renderer *renderer); -/** - * Gets a matrix you can pass into wlr_render_with_matrix to display this - * surface. `matrix` is the output matrix, `projection` is the wlr_output - * projection matrix, and `transform` is any additional transformations you want - * to perform on the surface (or NULL/the identity matrix if you don't). - * `transform` is used before the surface is scaled, so its geometry extends - * from 0 to 1 in both dimensions. - */ -void wlr_surface_get_matrix(struct wlr_surface *surface, -		float (*matrix)[16], -		const float (*projection)[16], -		const float (*transform)[16]); -  /**   * Set the lifetime role for this surface. Returns 0 on success or -1 if the diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 8422863c..fa808b60 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -40,6 +40,9 @@ struct wlr_xdg_popup {  	bool committed;  	struct wlr_xdg_surface *parent;  	struct wlr_seat *seat; + +	// Position of the popup relative to the upper left corner of the window +	// geometry of the parent surface  	struct wlr_box geometry;  	struct wl_list grab_link; // wlr_xdg_popup_grab::popups @@ -53,6 +56,7 @@ struct wlr_xdg_popup_grab {  	struct wlr_seat *seat;  	struct wl_list popups;  	struct wl_list link; // wlr_xdg_shell::popup_grabs +	struct wl_listener seat_destroy;  };  enum wlr_xdg_surface_role { @@ -62,19 +66,10 @@ enum wlr_xdg_surface_role {  };  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; +	bool maximized, fullscreen, resizing, activated; +	uint32_t width, height; +	uint32_t max_width, max_height; +	uint32_t min_width, min_height;  };  struct wlr_xdg_toplevel { @@ -90,7 +85,8 @@ struct wlr_xdg_toplevel {  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_toplevel_state *toplevel_state;  };  struct wlr_xdg_surface { @@ -101,14 +97,13 @@ struct wlr_xdg_surface {  	enum wlr_xdg_surface_role role;  	union { -		struct wlr_xdg_toplevel *toplevel_state; -		struct wlr_xdg_popup *popup_state; +		struct wlr_xdg_toplevel *toplevel; +		struct wlr_xdg_popup *popup;  	};  	struct wl_list popups; // wlr_xdg_popup::link -	bool configured; -	bool added; +	bool added, configured, mapped;  	uint32_t configure_serial;  	struct wl_event_source *configure_idle;  	uint32_t configure_next_serial; @@ -118,8 +113,8 @@ struct wlr_xdg_surface {  	char *app_id;  	bool has_next_geometry; -	struct wlr_box *next_geometry; -	struct wlr_box *geometry; +	struct wlr_box next_geometry; +	struct wlr_box geometry;  	struct wl_listener surface_destroy_listener; @@ -127,6 +122,8 @@ struct wlr_xdg_surface {  		struct wl_signal destroy;  		struct wl_signal ping_timeout;  		struct wl_signal new_popup; +		struct wl_signal map; +		struct wl_signal unmap;  		struct wl_signal request_maximize;  		struct wl_signal request_fullscreen; @@ -210,9 +207,9 @@ uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface,  		bool resizing);  /** - * Request that this toplevel surface closes. + * Request that this xdg surface closes.   */ -void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface); +void wlr_xdg_surface_send_close(struct wlr_xdg_surface *surface);  /**   * Compute the popup position in surface-local coordinates. diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 7dc746ce..ae3986ed 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -40,6 +40,9 @@ struct wlr_xdg_popup_v6 {  	bool committed;  	struct wlr_xdg_surface_v6 *parent;  	struct wlr_seat *seat; + +	// Position of the popup relative to the upper left corner of the window +	// geometry of the parent surface  	struct wlr_box geometry;  	struct wl_list grab_link; // wlr_xdg_popup_grab_v6::popups @@ -53,6 +56,7 @@ struct wlr_xdg_popup_grab_v6 {  	struct wlr_seat *seat;  	struct wl_list popups;  	struct wl_list link; // wlr_xdg_shell_v6::popup_grabs +	struct wl_listener seat_destroy;  };  enum wlr_xdg_surface_v6_role { @@ -62,19 +66,10 @@ enum wlr_xdg_surface_v6_role {  };  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; +	bool maximized, fullscreen, resizing, activated; +	uint32_t width, height; +	uint32_t max_width, max_height; +	uint32_t min_width, min_height;  };  struct wlr_xdg_toplevel_v6 { @@ -90,7 +85,8 @@ struct wlr_xdg_toplevel_v6 {  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_toplevel_v6_state *toplevel_state;  };  struct wlr_xdg_surface_v6 { @@ -101,14 +97,13 @@ struct wlr_xdg_surface_v6 {  	enum wlr_xdg_surface_v6_role role;  	union { -		struct wlr_xdg_toplevel_v6 *toplevel_state; -		struct wlr_xdg_popup_v6 *popup_state; +		struct wlr_xdg_toplevel_v6 *toplevel; +		struct wlr_xdg_popup_v6 *popup;  	};  	struct wl_list popups; // wlr_xdg_popup_v6::link -	bool configured; -	bool added; +	bool added, configured, mapped;  	uint32_t configure_serial;  	struct wl_event_source *configure_idle;  	uint32_t configure_next_serial; @@ -118,8 +113,8 @@ struct wlr_xdg_surface_v6 {  	char *app_id;  	bool has_next_geometry; -	struct wlr_box *next_geometry; -	struct wlr_box *geometry; +	struct wlr_box next_geometry; +	struct wlr_box geometry;  	struct wl_listener surface_destroy_listener; @@ -127,6 +122,8 @@ struct wlr_xdg_surface_v6 {  		struct wl_signal destroy;  		struct wl_signal ping_timeout;  		struct wl_signal new_popup; +		struct wl_signal map; +		struct wl_signal unmap;  		struct wl_signal request_maximize;  		struct wl_signal request_fullscreen; @@ -210,9 +207,9 @@ uint32_t wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface,  		bool resizing);  /** - * Request that this toplevel surface closes. + * Request that this xdg surface closes.   */ -void wlr_xdg_toplevel_v6_send_close(struct wlr_xdg_surface_v6 *surface); +void wlr_xdg_surface_v6_send_close(struct wlr_xdg_surface_v6 *surface);  /**   * Compute the popup position in surface-local coordinates. diff --git a/include/wlr/util/region.h b/include/wlr/util/region.h index 7883af97..c0fe6063 100644 --- a/include/wlr/util/region.h +++ b/include/wlr/util/region.h @@ -26,4 +26,11 @@ void wlr_region_transform(pixman_region32_t *dst, pixman_region32_t *src,  void wlr_region_expand(pixman_region32_t *dst, pixman_region32_t *src,  	int distance); +/* + * Builds the smallest possible region that contains the region rotated about + * the point (ox, oy). + */ +void wlr_region_rotated_bounds(pixman_region32_t *dst, pixman_region32_t *src, +	float rotation, int ox, int oy); +  #endif diff --git a/meson.build b/meson.build index e3c9a315..7740b416 100644 --- a/meson.build +++ b/meson.build @@ -210,7 +210,7 @@ git = find_program('git', required: false)  if git.found()  	all_files = run_command(  		git, -		['--git-dir=@0@/.git'.format(meson.source_root()), +		['--git-dir=@0@/.git'.format(meson.current_source_dir()),  		 'ls-files',  		 ':/*.[ch]'])  	all_files = files(all_files.stdout().split()) diff --git a/protocol/meson.build b/protocol/meson.build index 6c87a887..638b0c46 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -21,9 +21,10 @@ wayland_scanner_client = generator(  )  protocols = [ -	[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],  	[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],  	[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], +	[wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], +	[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],  	'gamma-control.xml',  	'gtk-primary-selection.xml',  	'idle.xml', diff --git a/render/egl.c b/render/egl.c index 0a68d6e5..e582b6d3 100644 --- a/render/egl.c +++ b/render/egl.c @@ -1,4 +1,5 @@  #include <assert.h> +#include <stdio.h>  #include <EGL/egl.h>  #include <EGL/eglext.h>  #include <GLES2/gl2.h> @@ -11,43 +12,6 @@  // https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt.  // https://cgit.freedesktop.org/mesa/mesa/tree/docs/specs/WL_bind_wayland_display.spec -const char *egl_error(void) { -	switch (eglGetError()) { -	case EGL_SUCCESS: -		return "Success"; -	case EGL_NOT_INITIALIZED: -		return "Not initialized"; -	case EGL_BAD_ACCESS: -		return "Bad access"; -	case EGL_BAD_ALLOC: -		return "Bad alloc"; -	case EGL_BAD_ATTRIBUTE: -		return "Bad attribute"; -	case EGL_BAD_CONTEXT: -		return "Bad Context"; -	case EGL_BAD_CONFIG: -		return "Bad Config"; -	case EGL_BAD_CURRENT_SURFACE: -		return "Bad current surface"; -	case EGL_BAD_DISPLAY: -		return "Bad display"; -	case EGL_BAD_SURFACE: -		return "Bad surface"; -	case EGL_BAD_MATCH: -		return "Bad match"; -	case EGL_BAD_PARAMETER: -		return "Bad parameter"; -	case EGL_BAD_NATIVE_PIXMAP: -		return "Bad native pixmap"; -	case EGL_BAD_NATIVE_WINDOW: -		return "Bad native window"; -	case EGL_CONTEXT_LOST: -		return "Context lost"; -	default: -		return "Unknown"; -	} -} -  static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out,  		EGLint visual_id) {  	EGLint count = 0, matched = 0, ret; @@ -83,6 +47,21 @@ static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out,  	return false;  } +static log_importance_t egl_log_importance_to_wlr(EGLint type) { +	switch (type) { +	case EGL_DEBUG_MSG_CRITICAL_KHR: return L_ERROR; +	case EGL_DEBUG_MSG_ERROR_KHR:    return L_ERROR; +	case EGL_DEBUG_MSG_WARN_KHR:     return L_ERROR; +	case EGL_DEBUG_MSG_INFO_KHR:     return L_INFO; +	default:                         return L_INFO; +	} +} + +static void egl_log(EGLenum error, const char *command, EGLint msg_type, +		EGLLabelKHR thread, EGLLabelKHR obj, const char *msg) { +	_wlr_log(egl_log_importance_to_wlr(msg_type), "[EGL] %s: %s", command, msg); +} +  static bool check_egl_ext(const char *egl_exts, const char *ext) {  	size_t extlen = strlen(ext);  	const char *end = egl_exts + strlen(egl_exts); @@ -101,14 +80,45 @@ static bool check_egl_ext(const char *egl_exts, const char *ext) {  	return false;  } +static void print_dmabuf_formats(struct wlr_egl *egl) { +	/* Avoid log msg if extension is not present */ +	if (!egl->egl_exts.dmabuf_import_modifiers) { +		return; +	} + +	int *formats; +	int num = wlr_egl_get_dmabuf_formats(egl, &formats); +	if (num < 0) { +		return; +	} + +	char str_formats[num * 5 + 1]; +	for (int i = 0; i < num; i++) { +		snprintf(&str_formats[i*5], (num - i) * 5 + 1, "%.4s ", (char*)&formats[i]); +	} +	wlr_log(L_INFO, "Supported dmabuf buffer formats: %s", str_formats); +	free(formats); +} +  bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display,  		EGLint *config_attribs, EGLint visual_id) {  	if (!load_glapi()) {  		return false;  	} +	if (eglDebugMessageControlKHR) { +		static const EGLAttrib debug_attribs[] = { +			EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, +			EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, +			EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, +			EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, +			EGL_NONE, +		}; +		eglDebugMessageControlKHR(egl_log, debug_attribs); +	} +  	if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) { -		wlr_log(L_ERROR, "Failed to bind to the OpenGL ES API: %s", egl_error()); +		wlr_log(L_ERROR, "Failed to bind to the OpenGL ES API");  		goto error;  	} @@ -119,13 +129,13 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display,  		egl->display = eglGetPlatformDisplayEXT(platform, remote_display, NULL);  	}  	if (egl->display == EGL_NO_DISPLAY) { -		wlr_log(L_ERROR, "Failed to create EGL display: %s", egl_error()); +		wlr_log(L_ERROR, "Failed to create EGL display");  		goto error;  	}  	EGLint major, minor;  	if (eglInitialize(egl->display, &major, &minor) == EGL_FALSE) { -		wlr_log(L_ERROR, "Failed to initialize EGL: %s", egl_error()); +		wlr_log(L_ERROR, "Failed to initialize EGL");  		goto error;  	} @@ -140,7 +150,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display,  		EGL_NO_CONTEXT, attribs);  	if (egl->context == EGL_NO_CONTEXT) { -		wlr_log(L_ERROR, "Failed to create EGL context: %s", egl_error()); +		wlr_log(L_ERROR, "Failed to create EGL context");  		goto error;  	} @@ -167,16 +177,29 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display,  		check_egl_ext(egl->egl_exts_str, "EGL_EXT_swap_buffers_with_damage") ||  		check_egl_ext(egl->egl_exts_str, "EGL_KHR_swap_buffers_with_damage"); +	egl->egl_exts.dmabuf_import = +		check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import"); +	egl->egl_exts.dmabuf_import_modifiers = +		check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import_modifiers") +		&& eglQueryDmaBufFormatsEXT && eglQueryDmaBufModifiersEXT; +	print_dmabuf_formats(egl); +  	return true;  error:  	eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); -	eglTerminate(egl->display); +	if (egl->display) { +		eglTerminate(egl->display); +	}  	eglReleaseThread();  	return false;  }  void wlr_egl_finish(struct wlr_egl *egl) { +	if (egl == NULL) { +		return; +	} +  	eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);  	if (egl->wl_display && eglUnbindWaylandDisplayWL) {  		eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); @@ -231,7 +254,7 @@ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) {  	EGLSurface surf = eglCreatePlatformWindowSurfaceEXT(egl->display, egl->config,  		window, NULL);  	if (surf == EGL_NO_SURFACE) { -		wlr_log(L_ERROR, "Failed to create EGL surface: %s", egl_error()); +		wlr_log(L_ERROR, "Failed to create EGL surface");  		return EGL_NO_SURFACE;  	}  	return surf; @@ -246,7 +269,7 @@ int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) {  	EGLBoolean ok = eglQuerySurface(egl->display, surface,  		EGL_BUFFER_AGE_EXT, &buffer_age);  	if (!ok) { -		wlr_log(L_ERROR, "Failed to get EGL surface buffer age: %s", egl_error()); +		wlr_log(L_ERROR, "Failed to get EGL surface buffer age");  		return -1;  	} @@ -256,7 +279,7 @@ int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) {  bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface,  		int *buffer_age) {  	if (!eglMakeCurrent(egl->display, surface, surface, egl->context)) { -		wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); +		wlr_log(L_ERROR, "eglMakeCurrent failed");  		return false;  	} @@ -294,8 +317,170 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface,  	}  	if (!ret) { -		wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); +		wlr_log(L_ERROR, "eglSwapBuffers failed");  		return false;  	}  	return true;  } + +EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, +		struct wlr_dmabuf_buffer_attribs *attributes) { +	bool has_modifier = false; +	if (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID) { +		if (!egl->egl_exts.dmabuf_import_modifiers) { +			return NULL; +		} +		has_modifier = true; +	} + +	unsigned int atti = 0; +	EGLint attribs[50]; +	attribs[atti++] = EGL_WIDTH; +	attribs[atti++] = attributes->width; +	attribs[atti++] = EGL_HEIGHT; +	attribs[atti++] = attributes->height; +	attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; +	attribs[atti++] = attributes->format; + +	struct { +		EGLint fd; +		EGLint offset; +		EGLint pitch; +		EGLint mod_lo; +		EGLint mod_hi; +	} attr_names[WLR_LINUX_DMABUF_MAX_PLANES] = { +		{ +			EGL_DMA_BUF_PLANE0_FD_EXT, +			EGL_DMA_BUF_PLANE0_OFFSET_EXT, +			EGL_DMA_BUF_PLANE0_PITCH_EXT, +			EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, +			EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT +		}, { +			EGL_DMA_BUF_PLANE1_FD_EXT, +			EGL_DMA_BUF_PLANE1_OFFSET_EXT, +			EGL_DMA_BUF_PLANE1_PITCH_EXT, +			EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, +			EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT +		}, { +			EGL_DMA_BUF_PLANE2_FD_EXT, +			EGL_DMA_BUF_PLANE2_OFFSET_EXT, +			EGL_DMA_BUF_PLANE2_PITCH_EXT, +			EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, +			EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT +		}, { +			EGL_DMA_BUF_PLANE3_FD_EXT, +			EGL_DMA_BUF_PLANE3_OFFSET_EXT, +			EGL_DMA_BUF_PLANE3_PITCH_EXT, +			EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, +			EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT +		} +	}; + +	for (int i=0; i < attributes->n_planes; i++) { +		attribs[atti++] = attr_names[i].fd; +		attribs[atti++] = attributes->fd[i]; +		attribs[atti++] = attr_names[i].offset; +		attribs[atti++] = attributes->offset[i]; +		attribs[atti++] = attr_names[i].pitch; +		attribs[atti++] = attributes->stride[i]; +		if (has_modifier) { +			attribs[atti++] = attr_names[i].mod_lo; +			attribs[atti++] = attributes->modifier[i] & 0xFFFFFFFF; +			attribs[atti++] = attr_names[i].mod_hi; +			attribs[atti++] = attributes->modifier[i] >> 32; +		} +	} +	attribs[atti++] = EGL_NONE; +	assert(atti < sizeof(attribs)/sizeof(attribs[0])); + +	return eglCreateImageKHR(egl->display, EGL_NO_CONTEXT, +		EGL_LINUX_DMA_BUF_EXT, NULL, attribs); +} + +#ifndef DRM_FORMAT_BIG_ENDIAN +# define DRM_FORMAT_BIG_ENDIAN 0x80000000 +#endif +bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, +		struct wlr_dmabuf_buffer *dmabuf) { +	switch (dmabuf->attributes.format & ~DRM_FORMAT_BIG_ENDIAN) { +		/* TODO: YUV based formats not yet supported, require multiple +		 * wlr_create_image_from_dmabuf */ +	case WL_SHM_FORMAT_YUYV: +	case WL_SHM_FORMAT_YVYU: +	case WL_SHM_FORMAT_UYVY: +	case WL_SHM_FORMAT_VYUY: +	case WL_SHM_FORMAT_AYUV: +		return false; +	default: +		break; +	} + +	EGLImage egl_image = wlr_egl_create_image_from_dmabuf(egl, +		&dmabuf->attributes); +	if (egl_image) { +		/* We can import the image, good. No need to keep it +		   since wlr_texture_upload_dmabuf will import it again */ +		wlr_egl_destroy_image(egl, egl_image); +		return true; +	} +	/* TODO: import yuv dmabufs */ +	return false; +} + +int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, +		int **formats) { +	if (!egl->egl_exts.dmabuf_import || +		!egl->egl_exts.dmabuf_import_modifiers) { +		wlr_log(L_ERROR, "dmabuf extension not present"); +		return -1; +	} + +	EGLint num; +	if (!eglQueryDmaBufFormatsEXT(egl->display, 0, NULL, &num)) { +		wlr_log(L_ERROR, "failed to query number of dmabuf formats"); +		return -1; +	} + +	*formats = calloc(num, sizeof(int)); +	if (*formats == NULL) { +		wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); +		return -1; +	} + +	if (!eglQueryDmaBufFormatsEXT(egl->display, num, *formats, &num)) { +		wlr_log(L_ERROR, "failed to query dmabuf format"); +		free(*formats); +		return -1; +	} +	return num; +} + +int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, +		int format, uint64_t **modifiers) { +	if (!egl->egl_exts.dmabuf_import || +		!egl->egl_exts.dmabuf_import_modifiers) { +		wlr_log(L_ERROR, "dmabuf extension not present"); +		return -1; +	} + +	EGLint num; +	if (!eglQueryDmaBufModifiersEXT(egl->display, format, 0, +			NULL, NULL, &num)) { +		wlr_log(L_ERROR, "failed to query dmabuf number of modifiers"); +		return -1; +	} + +	*modifiers = calloc(num, sizeof(uint64_t)); +	if (*modifiers == NULL) { +		wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); +		return -1; +	} + +	if (!eglQueryDmaBufModifiersEXT(egl->display, format, num, +		*modifiers, NULL, &num)) { +		wlr_log(L_ERROR, "failed to query dmabuf modifiers"); +		free(*modifiers); +		return -1; +	} +	return num; +} diff --git a/render/glapi.txt b/render/glapi.txt index 0b0b452c..a8e4aaba 100644 --- a/render/glapi.txt +++ b/render/glapi.txt @@ -8,3 +8,10 @@ eglCreatePlatformWindowSurfaceEXT  -glEGLImageTargetTexture2DOES  -eglSwapBuffersWithDamageEXT  -eglSwapBuffersWithDamageKHR +-eglQueryDmaBufFormatsEXT +-eglQueryDmaBufModifiersEXT +-eglDebugMessageControlKHR +-glDebugMessageCallbackKHR +-glDebugMessageControlKHR +-glPopDebugGroupKHR +-glPushDebugGroupKHR diff --git a/render/gles2/pixel_format.c b/render/gles2/pixel_format.c index a544077b..89ba762f 100644 --- a/render/gles2/pixel_format.c +++ b/render/gles2/pixel_format.c @@ -6,14 +6,14 @@  * The wayland formats are little endian while the GL formats are big endian,  * so WL_SHM_FORMAT_ARGB8888 is actually compatible with GL_BGRA_EXT.  */ -struct pixel_format formats[] = { +static const struct gles2_pixel_format formats[] = {  	{  		.wl_format = WL_SHM_FORMAT_ARGB8888,  		.depth = 32,  		.bpp = 32,  		.gl_format = GL_BGRA_EXT,  		.gl_type = GL_UNSIGNED_BYTE, -		.shader = &shaders.rgba +		.has_alpha = true,  	},  	{  		.wl_format = WL_SHM_FORMAT_XRGB8888, @@ -21,7 +21,7 @@ struct pixel_format formats[] = {  		.bpp = 32,  		.gl_format = GL_BGRA_EXT,  		.gl_type = GL_UNSIGNED_BYTE, -		.shader = &shaders.rgbx +		.has_alpha = false,  	},  	{  		.wl_format = WL_SHM_FORMAT_XBGR8888, @@ -29,7 +29,7 @@ struct pixel_format formats[] = {  		.bpp = 32,  		.gl_format = GL_RGBA,  		.gl_type = GL_UNSIGNED_BYTE, -		.shader = &shaders.rgbx +		.has_alpha = false,  	},  	{  		.wl_format = WL_SHM_FORMAT_ABGR8888, @@ -37,12 +37,20 @@ struct pixel_format formats[] = {  		.bpp = 32,  		.gl_format = GL_RGBA,  		.gl_type = GL_UNSIGNED_BYTE, -		.shader = &shaders.rgba +		.has_alpha = true,  	},  }; + +static const enum wl_shm_format wl_formats[] = { +	WL_SHM_FORMAT_ARGB8888, +	WL_SHM_FORMAT_XRGB8888, +	WL_SHM_FORMAT_ABGR8888, +	WL_SHM_FORMAT_XBGR8888, +}; +  // TODO: more pixel formats -const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt) { +const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt) {  	for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) {  		if (formats[i].wl_format == fmt) {  			return &formats[i]; @@ -50,3 +58,8 @@ const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt) {  	}  	return NULL;  } + +const enum wl_shm_format *gles2_formats(size_t *len) { +	*len = sizeof(wl_formats) / sizeof(wl_formats[0]); +	return wl_formats; +} diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index ad739cf8..61665a07 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -2,143 +2,80 @@  #include <GLES2/gl2.h>  #include <GLES2/gl2ext.h>  #include <stdint.h> +#include <stdio.h>  #include <stdlib.h>  #include <wayland-server-protocol.h>  #include <wayland-util.h>  #include <wlr/backend.h> -#include <wlr/render.h>  #include <wlr/render/egl.h>  #include <wlr/render/interface.h> -#include <wlr/render/matrix.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/util/log.h>  #include "render/gles2.h"  #include "glapi.h" -struct shaders shaders; - -static bool compile_shader(GLuint type, const GLchar *src, GLuint *shader) { -	*shader = GL_CALL(glCreateShader(type)); -	int len = strlen(src); -	GL_CALL(glShaderSource(*shader, 1, &src, &len)); -	GL_CALL(glCompileShader(*shader)); -	GLint success; -	GL_CALL(glGetShaderiv(*shader, GL_COMPILE_STATUS, &success)); -	if (success == GL_FALSE) { -		GLint loglen; -		GL_CALL(glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &loglen)); -		GLchar msg[loglen]; -		GL_CALL(glGetShaderInfoLog(*shader, loglen, &loglen, msg)); -		wlr_log(L_ERROR, "Shader compilation failed"); -		wlr_log(L_ERROR, "%s", msg); -		glDeleteShader(*shader); -		return false; -	} -	return true; -} +static const struct wlr_renderer_impl renderer_impl; -static bool compile_program(const GLchar *vert_src, -		const GLchar *frag_src, GLuint *program) { -	GLuint vertex, fragment; -	if (!compile_shader(GL_VERTEX_SHADER, vert_src, &vertex)) { -		return false; -	} -	if (!compile_shader(GL_FRAGMENT_SHADER, frag_src, &fragment)) { -		glDeleteShader(vertex); -		return false; -	} -	*program = GL_CALL(glCreateProgram()); -	GL_CALL(glAttachShader(*program, vertex)); -	GL_CALL(glAttachShader(*program, fragment)); -	GL_CALL(glLinkProgram(*program)); -	GLint success; -	GL_CALL(glGetProgramiv(*program, GL_LINK_STATUS, &success)); -	if (success == GL_FALSE) { -		GLint loglen; -		GL_CALL(glGetProgramiv(*program, GL_INFO_LOG_LENGTH, &loglen)); -		GLchar msg[loglen]; -		GL_CALL(glGetProgramInfoLog(*program, loglen, &loglen, msg)); -		wlr_log(L_ERROR, "Program link failed"); -		wlr_log(L_ERROR, "%s", msg); -		glDeleteProgram(*program); -		glDeleteShader(vertex); -		glDeleteShader(fragment); -		return false; -	} -	glDetachShader(*program, vertex); -	glDetachShader(*program, fragment); -	glDeleteShader(vertex); -	glDeleteShader(fragment); - -	return true; +static struct wlr_gles2_renderer *gles2_get_renderer( +		struct wlr_renderer *wlr_renderer) { +	assert(wlr_renderer->impl == &renderer_impl); +	struct wlr_gles2_renderer *renderer = +		(struct wlr_gles2_renderer *)wlr_renderer; +	assert(eglGetCurrentContext() == renderer->egl->context); +	return renderer;  } -static void init_default_shaders() { -	if (shaders.initialized) { -		return; -	} -	if (!compile_program(vertex_src, fragment_src_rgba, &shaders.rgba)) { -		goto error; -	} -	if (!compile_program(vertex_src, fragment_src_rgbx, &shaders.rgbx)) { -		goto error; -	} -	if (!compile_program(quad_vertex_src, quad_fragment_src, &shaders.quad)) { -		goto error; -	} -	if (!compile_program(quad_vertex_src, ellipse_fragment_src, &shaders.ellipse)) { -		goto error; -	} -	if (glEGLImageTargetTexture2DOES) { -		if (!compile_program(quad_vertex_src, fragment_src_external, &shaders.external)) { -			goto error; -		} -	} +static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, +		uint32_t height) { +	gles2_get_renderer(wlr_renderer); -	wlr_log(L_DEBUG, "Compiled default shaders"); -	shaders.initialized = true; -	return; -error: -	wlr_log(L_ERROR, "Failed to set up default shaders!"); -} - -static void init_globals() { -	init_default_shaders(); -} +	GLES2_DEBUG_PUSH; -static void wlr_gles2_begin(struct wlr_renderer *wlr_renderer, -		struct wlr_output *output) { -	GL_CALL(glViewport(0, 0, output->width, output->height)); +	glViewport(0, 0, width, height);  	// enable transparency -	GL_CALL(glEnable(GL_BLEND)); -	GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); +	glEnable(GL_BLEND); +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -	// Note: maybe we should save output projection and remove some of the need +	// XXX: maybe we should save output projection and remove some of the need  	// for users to sling matricies themselves + +	GLES2_DEBUG_POP;  } -static void wlr_gles2_end(struct wlr_renderer *wlr_renderer) { +static void gles2_end(struct wlr_renderer *wlr_renderer) { +	gles2_get_renderer(wlr_renderer);  	// no-op  } -static void wlr_gles2_clear(struct wlr_renderer *wlr_renderer, -		const float (*color)[4]) { -	glClearColor((*color)[0], (*color)[1], (*color)[2], (*color)[3]); +static void gles2_clear(struct wlr_renderer *wlr_renderer, +		const float color[static 4]) { +	gles2_get_renderer(wlr_renderer); + +	GLES2_DEBUG_PUSH; +	glClearColor(color[0], color[1], color[2], color[3]);  	glClear(GL_COLOR_BUFFER_BIT); +	GLES2_DEBUG_POP;  } -static void wlr_gles2_scissor(struct wlr_renderer *wlr_renderer, +static void gles2_scissor(struct wlr_renderer *wlr_renderer,  		struct wlr_box *box) { +	gles2_get_renderer(wlr_renderer); + +	GLES2_DEBUG_PUSH;  	if (box != NULL) {  		glScissor(box->x, box->y, box->width, box->height);  		glEnable(GL_SCISSOR_TEST);  	} else {  		glDisable(GL_SCISSOR_TEST);  	} +	GLES2_DEBUG_POP;  } -static struct wlr_texture *wlr_gles2_texture_create( +static struct wlr_texture *gles2_renderer_texture_create(  		struct wlr_renderer *wlr_renderer) { +	assert(wlr_renderer->impl == &renderer_impl);  	struct wlr_gles2_renderer *renderer =  		(struct wlr_gles2_renderer *)wlr_renderer;  	return gles2_texture_create(renderer->egl); @@ -158,80 +95,117 @@ static void draw_quad() {  		0, 1, // bottom left  	}; -	GL_CALL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts)); -	GL_CALL(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord)); +	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts); +	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord); -	GL_CALL(glEnableVertexAttribArray(0)); -	GL_CALL(glEnableVertexAttribArray(1)); +	glEnableVertexAttribArray(0); +	glEnableVertexAttribArray(1); -	GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); +	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); -	GL_CALL(glDisableVertexAttribArray(0)); -	GL_CALL(glDisableVertexAttribArray(1)); +	glDisableVertexAttribArray(0); +	glDisableVertexAttribArray(1);  } -static bool wlr_gles2_render_texture(struct wlr_renderer *wlr_renderer, -		struct wlr_texture *texture, const float (*matrix)[16], float alpha) { -	if (!texture || !texture->valid) { +static bool gles2_render_texture_with_matrix( +		struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture, +		const float matrix[static 9], float alpha) { +	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); +	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); +	if (!wlr_texture->valid) {  		wlr_log(L_ERROR, "attempt to render invalid texture");  		return false;  	} -	wlr_texture_bind(texture); -	GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix)); -	GL_CALL(glUniform1f(2, alpha)); +	GLuint prog = renderer->shaders.tex_rgba; +	if (texture->target == GL_TEXTURE_EXTERNAL_OES) { +		prog = renderer->shaders.tex_ext; +	} else if (!texture->pixel_format->has_alpha) { +		prog = renderer->shaders.tex_rgbx; +	} + +	// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set +	// to GL_FALSE +	float transposition[9]; +	wlr_matrix_transpose(transposition, matrix); + +	GLES2_DEBUG_PUSH; +	glBindTexture(texture->target, texture->tex_id); +	glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +	glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +	glUseProgram(prog); + +	glUniformMatrix3fv(0, 1, GL_FALSE, transposition); +	glUniform1i(1, wlr_texture->inverted_y); +	glUniform1f(3, alpha);  	draw_quad(); +	GLES2_DEBUG_POP;  	return true;  } -static void wlr_gles2_render_quad(struct wlr_renderer *wlr_renderer, -		const float (*color)[4], const float (*matrix)[16]) { -	GL_CALL(glUseProgram(shaders.quad)); -	GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix)); -	GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3])); +static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer, +		const float color[static 4], const float matrix[static 9]) { +	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + +	// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set +	// to GL_FALSE +	float transposition[9]; +	wlr_matrix_transpose(transposition, matrix); + +	GLES2_DEBUG_PUSH; +	glUseProgram(renderer->shaders.quad); +	glUniformMatrix3fv(0, 1, GL_FALSE, transposition); +	glUniform4f(1, color[0], color[1], color[2], color[3]);  	draw_quad(); +	GLES2_DEBUG_POP;  } -static void wlr_gles2_render_ellipse(struct wlr_renderer *wlr_renderer, -		const float (*color)[4], const float (*matrix)[16]) { -	GL_CALL(glUseProgram(shaders.ellipse)); -	GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, *matrix)); -	GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3])); +static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, +		const float color[static 4], const float matrix[static 9]) { +	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + +	// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set +	// to GL_FALSE +	float transposition[9]; +	wlr_matrix_transpose(transposition, matrix); + +	GLES2_DEBUG_PUSH; +	glUseProgram(renderer->shaders.ellipse); +	glUniformMatrix3fv(0, 1, GL_FALSE, transposition); +	glUniform4f(1, color[0], color[1], color[2], color[3]);  	draw_quad(); +	GLES2_DEBUG_POP;  } -static const enum wl_shm_format *wlr_gles2_formats( -		struct wlr_renderer *renderer, size_t *len) { -	static enum wl_shm_format formats[] = { -		WL_SHM_FORMAT_ARGB8888, -		WL_SHM_FORMAT_XRGB8888, -		WL_SHM_FORMAT_ABGR8888, -		WL_SHM_FORMAT_XBGR8888, -	}; -	*len = sizeof(formats) / sizeof(formats[0]); -	return formats; +static const enum wl_shm_format *gles2_renderer_formats( +		struct wlr_renderer *wlr_renderer, size_t *len) { +	return gles2_formats(len);  } -static bool wlr_gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer, +static bool gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer,  		struct wl_resource *buffer) { -	struct wlr_gles2_renderer *renderer = -		(struct wlr_gles2_renderer *)wlr_renderer; +	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); +  	EGLint format; -	return wlr_egl_query_buffer(renderer->egl, buffer, -		EGL_TEXTURE_FORMAT, &format); +	return wlr_egl_query_buffer(renderer->egl, buffer, EGL_TEXTURE_FORMAT, +		&format);  } -static bool wlr_gles2_read_pixels(struct wlr_renderer *renderer, +static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer,  		enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,  		uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x,  		uint32_t dst_y, void *data) { -	const struct pixel_format *fmt = gl_format_for_wl_format(wl_fmt); +	gles2_get_renderer(wlr_renderer); + +	const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt);  	if (fmt == NULL) {  		wlr_log(L_ERROR, "Cannot read pixels: unsupported pixel format");  		return false;  	} +	GLES2_DEBUG_PUSH; +  	// Make sure any pending drawing is finished before we try to read it  	glFinish(); @@ -243,38 +217,225 @@ static bool wlr_gles2_read_pixels(struct wlr_renderer *renderer,  			fmt->gl_type, p + i * stride + dst_x * fmt->bpp / 8);  	} +	GLES2_DEBUG_POP; +  	return true;  } -static bool wlr_gles2_format_supported(struct wlr_renderer *r, +static bool gles2_format_supported(struct wlr_renderer *r,  		enum wl_shm_format wl_fmt) { -	return gl_format_for_wl_format(wl_fmt); +	return gles2_format_from_wl(wl_fmt) != NULL; +} + +static void gles2_destroy(struct wlr_renderer *wlr_renderer) { +	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + +	wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); + +	GLES2_DEBUG_PUSH; +	glDeleteProgram(renderer->shaders.quad); +	glDeleteProgram(renderer->shaders.ellipse); +	glDeleteProgram(renderer->shaders.tex_rgba); +	glDeleteProgram(renderer->shaders.tex_rgbx); +	glDeleteProgram(renderer->shaders.tex_ext); +	GLES2_DEBUG_POP; + +	if (glDebugMessageCallbackKHR) { +		glDisable(GL_DEBUG_OUTPUT_KHR); +		glDebugMessageCallbackKHR(NULL, NULL); +	} + +	free(renderer);  } -static struct wlr_renderer_impl wlr_renderer_impl = { -	.begin = wlr_gles2_begin, -	.end = wlr_gles2_end, -	.clear = wlr_gles2_clear, -	.scissor = wlr_gles2_scissor, -	.texture_create = wlr_gles2_texture_create, -	.render_with_matrix = wlr_gles2_render_texture, -	.render_quad = wlr_gles2_render_quad, -	.render_ellipse = wlr_gles2_render_ellipse, -	.formats = wlr_gles2_formats, -	.buffer_is_drm = wlr_gles2_buffer_is_drm, -	.read_pixels = wlr_gles2_read_pixels, -	.format_supported = wlr_gles2_format_supported, +static const struct wlr_renderer_impl renderer_impl = { +	.destroy = gles2_destroy, +	.begin = gles2_begin, +	.end = gles2_end, +	.clear = gles2_clear, +	.scissor = gles2_scissor, +	.texture_create = gles2_renderer_texture_create, +	.render_texture_with_matrix = gles2_render_texture_with_matrix, +	.render_quad_with_matrix = gles2_render_quad_with_matrix, +	.render_ellipse_with_matrix = gles2_render_ellipse_with_matrix, +	.formats = gles2_renderer_formats, +	.buffer_is_drm = gles2_buffer_is_drm, +	.read_pixels = gles2_read_pixels, +	.format_supported = gles2_format_supported,  }; +void gles2_push_marker(const char *file, const char *func) { +	if (!glPushDebugGroupKHR) { +		return; +	} + +	int len = snprintf(NULL, 0, "%s:%s", file, func) + 1; +	char str[len]; +	snprintf(str, len, "%s:%s", file, func); +	glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); +} + +void gles2_pop_marker(void) { +	if (glPopDebugGroupKHR) { +		glPopDebugGroupKHR(); +	} +} + +static log_importance_t gles2_log_importance_to_wlr(GLenum type) { +	switch (type) { +	case GL_DEBUG_TYPE_ERROR_KHR:               return L_ERROR; +	case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR: return L_DEBUG; +	case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR:  return L_ERROR; +	case GL_DEBUG_TYPE_PORTABILITY_KHR:         return L_DEBUG; +	case GL_DEBUG_TYPE_PERFORMANCE_KHR:         return L_DEBUG; +	case GL_DEBUG_TYPE_OTHER_KHR:               return L_INFO; +	case GL_DEBUG_TYPE_MARKER_KHR:              return L_DEBUG; +	case GL_DEBUG_TYPE_PUSH_GROUP_KHR:          return L_DEBUG; +	case GL_DEBUG_TYPE_POP_GROUP_KHR:           return L_DEBUG; +	default:                                    return L_INFO; +	} +} + +static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity, +		GLsizei len, const GLchar *msg, const void *user) { +	_wlr_log(gles2_log_importance_to_wlr(type), "[GLES2] %s", msg); +} + +static GLuint compile_shader(GLuint type, const GLchar *src) { +	GLES2_DEBUG_PUSH; + +	GLuint shader = glCreateShader(type); +	glShaderSource(shader, 1, &src, NULL); +	glCompileShader(shader); + +	GLint ok; +	glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); +	if (ok == GL_FALSE) { +		glDeleteShader(shader); +		shader = 0; +	} + +	GLES2_DEBUG_POP; +	return shader; +} + +static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) { +	GLES2_DEBUG_PUSH; + +	GLuint vert = compile_shader(GL_VERTEX_SHADER, vert_src); +	if (!vert) { +		goto error; +	} + +	GLuint frag = compile_shader(GL_FRAGMENT_SHADER, frag_src); +	if (!frag) { +		glDeleteShader(vert); +		goto error; +	} + +	GLuint prog = glCreateProgram(); +	glAttachShader(prog, vert); +	glAttachShader(prog, frag); +	glLinkProgram(prog); + +	glDetachShader(prog, vert); +	glDetachShader(prog, frag); +	glDeleteShader(vert); +	glDeleteShader(frag); + +	GLint ok; +	glGetProgramiv(prog, GL_LINK_STATUS, &ok); +	if (ok == GL_FALSE) { +		glDeleteProgram(prog); +		goto error; +	} + +	GLES2_DEBUG_POP; +	return prog; + +error: +	GLES2_DEBUG_POP; +	return 0; +} + +extern const GLchar quad_vertex_src[]; +extern const GLchar quad_fragment_src[]; +extern const GLchar ellipse_fragment_src[]; +extern const GLchar tex_vertex_src[]; +extern const GLchar tex_fragment_src_rgba[]; +extern const GLchar tex_fragment_src_rgbx[]; +extern const GLchar tex_fragment_src_external[]; +  struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend) { -	init_globals(); -	struct wlr_gles2_renderer *renderer; -	if (!(renderer = calloc(1, sizeof(struct wlr_gles2_renderer)))) { +	struct wlr_gles2_renderer *renderer = +		calloc(1, sizeof(struct wlr_gles2_renderer)); +	if (renderer == NULL) {  		return NULL;  	} -	wlr_renderer_init(&renderer->wlr_renderer, &wlr_renderer_impl); +	wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl);  	renderer->egl = wlr_backend_get_egl(backend); +	wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); + +	if (glDebugMessageCallbackKHR && glDebugMessageControlKHR) { +		glEnable(GL_DEBUG_OUTPUT_KHR); +		glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR); +		glDebugMessageCallbackKHR(gles2_log, NULL); + +		// Silence unwanted message types +		glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_POP_GROUP_KHR, +			GL_DONT_CARE, 0, NULL, GL_FALSE); +		glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_PUSH_GROUP_KHR, +			GL_DONT_CARE, 0, NULL, GL_FALSE); +	} + +	GLES2_DEBUG_PUSH; + +	renderer->shaders.quad = link_program(quad_vertex_src, quad_fragment_src); +	if (!renderer->shaders.quad) { +		goto error; +	} +	renderer->shaders.ellipse = +		link_program(quad_vertex_src, ellipse_fragment_src); +	if (!renderer->shaders.ellipse) { +		goto error; +	} +	renderer->shaders.tex_rgba = +		link_program(tex_vertex_src, tex_fragment_src_rgba); +	if (!renderer->shaders.tex_rgba) { +		goto error; +	} +	renderer->shaders.tex_rgbx = +		link_program(tex_vertex_src, tex_fragment_src_rgbx); +	if (!renderer->shaders.tex_rgbx) { +		goto error; +	} +	if (glEGLImageTargetTexture2DOES) { +		renderer->shaders.tex_ext = +			link_program(tex_vertex_src, tex_fragment_src_external); +		if (!renderer->shaders.tex_ext) { +			goto error; +		} +	} + +	GLES2_DEBUG_POP;  	return &renderer->wlr_renderer; + +error: +	glDeleteProgram(renderer->shaders.quad); +	glDeleteProgram(renderer->shaders.ellipse); +	glDeleteProgram(renderer->shaders.tex_rgba); +	glDeleteProgram(renderer->shaders.tex_rgbx); +	glDeleteProgram(renderer->shaders.tex_ext); + +	GLES2_DEBUG_POP; + +	if (glDebugMessageCallbackKHR) { +		glDisable(GL_DEBUG_OUTPUT_KHR); +		glDebugMessageCallbackKHR(NULL, NULL); +	} + +	free(renderer); +	return NULL;  } diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index 46a10248..ba3bd971 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -3,100 +3,88 @@  // Colored quads  const GLchar quad_vertex_src[] = -"uniform mat4 proj;" -"uniform vec4 color;" -"attribute vec2 pos;" -"attribute vec2 texcoord;" -"varying vec4 v_color;" -"varying vec2 v_texcoord;" -"mat4 transpose(in mat4 inMatrix) {" -"    vec4 i0 = inMatrix[0];" -"    vec4 i1 = inMatrix[1];" -"    vec4 i2 = inMatrix[2];" -"    vec4 i3 = inMatrix[3];" -"    mat4 outMatrix = mat4(" -"                 vec4(i0.x, i1.x, i2.x, i3.x)," -"                 vec4(i0.y, i1.y, i2.y, i3.y)," -"                 vec4(i0.z, i1.z, i2.z, i3.z)," -"                 vec4(i0.w, i1.w, i2.w, i3.w)" -"                 );" -"    return outMatrix;" -"}" -"void main() {" -"  gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);" -"  v_color = color;" -"  v_texcoord = texcoord;" -"}"; +"uniform mat3 proj;\n" +"uniform vec4 color;\n" +"attribute vec2 pos;\n" +"attribute vec2 texcoord;\n" +"varying vec4 v_color;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +"	gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" +"	v_color = color;\n" +"	v_texcoord = texcoord;\n" +"}\n";  const GLchar quad_fragment_src[] = -"precision mediump float;" -"varying vec4 v_color;" -"varying vec2 v_texcoord;" -"void main() {" -"  gl_FragColor = v_color;" -"}"; +"precision mediump float;\n" +"varying vec4 v_color;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +"	gl_FragColor = v_color;\n" +"}\n";  // Colored ellipses  const GLchar ellipse_fragment_src[] = -"precision mediump float;" -"varying vec4 v_color;" -"varying vec2 v_texcoord;" -"void main() {" -"  float l = length(v_texcoord - vec2(0.5, 0.5));" -"  if (l > 0.5) discard;" -"  gl_FragColor = v_color;" -"}"; +"precision mediump float;\n" +"varying vec4 v_color;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +"	float l = length(v_texcoord - vec2(0.5, 0.5));\n" +"	if (l > 0.5) {\n" +"		discard;\n" +"	}\n" +"	gl_FragColor = v_color;\n" +"}\n";  // Textured quads -const GLchar vertex_src[] = -"uniform mat4 proj;" -"attribute vec2 pos;" -"attribute vec2 texcoord;" -"varying vec2 v_texcoord;" -"mat4 transpose(in mat4 inMatrix) {" -"    vec4 i0 = inMatrix[0];" -"    vec4 i1 = inMatrix[1];" -"    vec4 i2 = inMatrix[2];" -"    vec4 i3 = inMatrix[3];" -"    mat4 outMatrix = mat4(" -"                 vec4(i0.x, i1.x, i2.x, i3.x)," -"                 vec4(i0.y, i1.y, i2.y, i3.y)," -"                 vec4(i0.z, i1.z, i2.z, i3.z)," -"                 vec4(i0.w, i1.w, i2.w, i3.w)" -"                 );" -"" -"    return outMatrix;" -"}" -"void main() {" -"	gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);" -"	v_texcoord = texcoord;" -"}"; +const GLchar tex_vertex_src[] = +"uniform mat3 proj;\n" +"uniform bool invert_y;\n" +"attribute vec2 pos;\n" +"attribute vec2 texcoord;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +"	gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" +"	if (invert_y) {\n" +"		v_texcoord = vec2(texcoord.s, 1.0 - texcoord.t);\n" +"	} else {\n" +"		v_texcoord = texcoord;\n" +"	}\n" +"}\n"; -const GLchar fragment_src_rgba[] = -"precision mediump float;" -"varying vec2 v_texcoord;" -"uniform sampler2D tex;" -"uniform float alpha;" -"void main() {" -"	gl_FragColor = alpha * texture2D(tex, v_texcoord);" -"}"; +const GLchar tex_fragment_src_rgba[] = +"precision mediump float;\n" +"varying vec2 v_texcoord;\n" +"uniform sampler2D tex;\n" +"uniform float alpha;\n" +"\n" +"void main() {\n" +"	gl_FragColor = alpha * texture2D(tex, v_texcoord);\n" +"}\n"; -const GLchar fragment_src_rgbx[] = -"precision mediump float;" -"varying vec2 v_texcoord;" -"uniform sampler2D tex;" -"uniform float alpha;" -"void main() {" -"   gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;" -"   gl_FragColor.a = alpha;" -"}"; +const GLchar tex_fragment_src_rgbx[] = +"precision mediump float;\n" +"varying vec2 v_texcoord;\n" +"uniform sampler2D tex;\n" +"uniform float alpha;\n" +"\n" +"void main() {\n" +"	gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;\n" +"	gl_FragColor.a = alpha;\n" +"}\n"; -const GLchar fragment_src_external[] = -"#extension GL_OES_EGL_image_external : require\n" -"precision mediump float;" -"varying vec2 v_texcoord;" -"uniform samplerExternalOES texture0;" -"void main() {" -"  vec4 col = texture2D(texture0, v_texcoord);" -"  gl_FragColor = vec4(col.rgb, col.a);" -"}"; +const GLchar tex_fragment_src_external[] = +"#extension GL_OES_EGL_image_external : require\n\n" +"precision mediump float;\n" +"varying vec2 v_texcoord;\n" +"uniform samplerExternalOES texture0;\n" +"uniform float alpha;\n" +"\n" +"void main() {\n" +"	vec4 col = texture2D(texture0, v_texcoord);\n" +"	gl_FragColor = vec4(col.rgb, col.a * alpha);\n" +"}\n"; diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 241b94a8..46193c78 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -5,39 +5,47 @@  #include <stdlib.h>  #include <wayland-server-protocol.h>  #include <wayland-util.h> -#include <wlr/render.h> +#include <wlr/render/wlr_texture.h>  #include <wlr/render/egl.h>  #include <wlr/render/interface.h> -#include <wlr/render/matrix.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/util/log.h>  #include "render/gles2.h"  #include "util/signal.h" -static struct pixel_format external_pixel_format = { +static struct gles2_pixel_format external_pixel_format = {  	.wl_format = 0,  	.depth = 0,  	.bpp = 0,  	.gl_format = 0,  	.gl_type = 0, -	.shader = &shaders.external  }; -static void gles2_texture_ensure_texture(struct wlr_gles2_texture *texture) { +static void gles2_texture_ensure(struct wlr_gles2_texture *texture, +		GLenum target) {  	if (texture->tex_id) {  		return;  	} -	GL_CALL(glGenTextures(1, &texture->tex_id)); -	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); -	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); -	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); +	texture->target = target; +	glGenTextures(1, &texture->tex_id); +	glBindTexture(target, texture->tex_id); +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  } -static bool gles2_texture_upload_pixels(struct wlr_texture *_texture, +static const struct wlr_texture_impl texture_impl; + +struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture) { +	assert(wlr_texture->impl == &texture_impl); +	return (struct wlr_gles2_texture *)wlr_texture; +} + +static bool gles2_texture_upload_pixels(struct wlr_texture *wlr_texture,  		enum wl_shm_format format, int stride, int width, int height,  		const unsigned char *pixels) { -	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; -	assert(texture); -	const struct pixel_format *fmt = gl_format_for_wl_format(format); +	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); + +	const struct gles2_pixel_format *fmt = gles2_format_from_wl(format);  	if (!fmt || !fmt->gl_format) {  		wlr_log(L_ERROR, "No supported pixel format for this texture");  		return false; @@ -47,44 +55,50 @@ static bool gles2_texture_upload_pixels(struct wlr_texture *_texture,  	texture->wlr_texture.format = format;  	texture->pixel_format = fmt; -	gles2_texture_ensure_texture(texture); -	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); -	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride)); -	GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, -			fmt->gl_format, fmt->gl_type, pixels)); +	GLES2_DEBUG_PUSH; +	gles2_texture_ensure(texture, GL_TEXTURE_2D); +	glBindTexture(GL_TEXTURE_2D, texture->tex_id); +	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); +	glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, +		fmt->gl_format, fmt->gl_type, pixels); +	GLES2_DEBUG_POP; +  	texture->wlr_texture.valid = true;  	return true;  } -static bool gles2_texture_update_pixels(struct wlr_texture *_texture, +static bool gles2_texture_update_pixels(struct wlr_texture *wlr_texture,  		enum wl_shm_format format, int stride, int x, int y,  		int width, int height, const unsigned char *pixels) { -	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; -	assert(texture); +	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); +  	// TODO: Test if the unpack subimage extension is supported and adjust the  	// upload strategy if not  	if (!texture->wlr_texture.valid  			|| texture->wlr_texture.format != format  		/*	|| unpack not supported */) { -		return gles2_texture_upload_pixels(&texture->wlr_texture, -				format, stride, width, height, pixels); +		return gles2_texture_upload_pixels(&texture->wlr_texture, format, +			stride, width, height, pixels);  	} -	const struct pixel_format *fmt = texture->pixel_format; -	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); -	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride)); -	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x)); -	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y)); -	GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, -			fmt->gl_format, fmt->gl_type, pixels)); -	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); -	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); +	const struct gles2_pixel_format *fmt = texture->pixel_format; +	GLES2_DEBUG_PUSH; +	glBindTexture(GL_TEXTURE_2D, texture->tex_id); +	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); +	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x); +	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y); +	glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, fmt->gl_format, +		fmt->gl_type, pixels); +	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); +	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); +	GLES2_DEBUG_POP;  	return true;  } -static bool gles2_texture_upload_shm(struct wlr_texture *_texture, +static bool gles2_texture_upload_shm(struct wlr_texture *wlr_texture,  		uint32_t format, struct wl_shm_buffer *buffer) { -	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; -	const struct pixel_format *fmt = gl_format_for_wl_format(format); +	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); + +	const struct gles2_pixel_format *fmt = gles2_format_from_wl(format);  	if (!fmt || !fmt->gl_format) {  		wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32" for this texture",  				format); @@ -100,23 +114,26 @@ static bool gles2_texture_upload_shm(struct wlr_texture *_texture,  	texture->wlr_texture.format = format;  	texture->pixel_format = fmt; -	gles2_texture_ensure_texture(texture); -	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); -	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch)); -	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); -	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); -	GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, -				fmt->gl_format, fmt->gl_type, pixels)); +	GLES2_DEBUG_PUSH; +	gles2_texture_ensure(texture, GL_TEXTURE_2D); +	glBindTexture(GL_TEXTURE_2D, texture->tex_id); +	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch); +	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); +	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); +	glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, +		fmt->gl_format, fmt->gl_type, pixels); +	GLES2_DEBUG_POP;  	texture->wlr_texture.valid = true;  	wl_shm_buffer_end_access(buffer);  	return true;  } -static bool gles2_texture_update_shm(struct wlr_texture *_texture, +static bool gles2_texture_update_shm(struct wlr_texture *wlr_texture,  		uint32_t format, int x, int y, int width, int height,  		struct wl_shm_buffer *buffer) { -	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; +	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); +  	// TODO: Test if the unpack subimage extension is supported and adjust the  	// upload strategy if not  	assert(texture); @@ -125,28 +142,30 @@ static bool gles2_texture_update_shm(struct wlr_texture *_texture,  		/*	|| unpack not supported */) {  		return gles2_texture_upload_shm(&texture->wlr_texture, format, buffer);  	} -	const struct pixel_format *fmt = texture->pixel_format; +	const struct gles2_pixel_format *fmt = texture->pixel_format;  	wl_shm_buffer_begin_access(buffer);  	uint8_t *pixels = wl_shm_buffer_get_data(buffer);  	int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8); -	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); -	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch)); -	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x)); -	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y)); -	GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, -			fmt->gl_format, fmt->gl_type, pixels)); -	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); -	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); +	GLES2_DEBUG_PUSH; +	glBindTexture(GL_TEXTURE_2D, texture->tex_id); +	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch); +	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x); +	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y); +	glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, +			fmt->gl_format, fmt->gl_type, pixels); +	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); +	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); +	GLES2_DEBUG_POP;  	wl_shm_buffer_end_access(buffer);  	return true;  } -static bool gles2_texture_upload_drm(struct wlr_texture *_tex, +static bool gles2_texture_upload_drm(struct wlr_texture *wlr_texture,  		struct wl_resource *buf) { -	struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)_tex; +	struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);  	if (!glEGLImageTargetTexture2DOES) {  		return false;  	} @@ -158,20 +177,23 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex,  	}  	wlr_egl_query_buffer(tex->egl, buf, EGL_WIDTH, -			(EGLint*)&tex->wlr_texture.width); +		(EGLint*)&tex->wlr_texture.width);  	wlr_egl_query_buffer(tex->egl, buf, EGL_HEIGHT, -			(EGLint*)&tex->wlr_texture.height); +		(EGLint*)&tex->wlr_texture.height);  	EGLint inverted_y; -	wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL, &inverted_y); +	if (wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL, +			&inverted_y)) { +		tex->wlr_texture.inverted_y = !!inverted_y; +	}  	GLenum target; -	const struct pixel_format *pf; +	const struct gles2_pixel_format *pf;  	switch (format) {  	case EGL_TEXTURE_RGB:  	case EGL_TEXTURE_RGBA:  		target = GL_TEXTURE_2D; -		pf = gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888); +		pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888);  		break;  	case EGL_TEXTURE_EXTERNAL_WL:  		target = GL_TEXTURE_EXTERNAL_OES; @@ -182,8 +204,10 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex,  		return false;  	} -	gles2_texture_ensure_texture(tex); -	GL_CALL(glBindTexture(GL_TEXTURE_2D, tex->tex_id)); +	GLES2_DEBUG_PUSH; +	gles2_texture_ensure(tex, target); +	glBindTexture(GL_TEXTURE_2D, tex->tex_id); +	GLES2_DEBUG_POP;  	EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE }; @@ -194,22 +218,24 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex,  	tex->image = wlr_egl_create_image(tex->egl, EGL_WAYLAND_BUFFER_WL,  		(EGLClientBuffer*) buf, attribs);  	if (!tex->image) { -		wlr_log(L_ERROR, "failed to create egl image: %s", egl_error()); +		wlr_log(L_ERROR, "failed to create EGL image");   		return false;  	} -	GL_CALL(glActiveTexture(GL_TEXTURE0)); -	GL_CALL(glBindTexture(target, tex->tex_id)); -	GL_CALL(glEGLImageTargetTexture2DOES(target, tex->image)); +	GLES2_DEBUG_PUSH; +	glActiveTexture(GL_TEXTURE0); +	glBindTexture(target, tex->tex_id); +	glEGLImageTargetTexture2DOES(target, tex->image); +	GLES2_DEBUG_POP;  	tex->wlr_texture.valid = true;  	tex->pixel_format = pf;  	return true;  } -static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex, +static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_texture,  		EGLImageKHR image, uint32_t width, uint32_t height) { -	struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)wlr_tex; +	struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);  	tex->image = image;  	tex->pixel_format = &external_pixel_format; @@ -217,30 +243,74 @@ static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex,  	tex->wlr_texture.width = width;  	tex->wlr_texture.height = height; -	gles2_texture_ensure_texture(tex); - -	GL_CALL(glActiveTexture(GL_TEXTURE0)); -	GL_CALL(glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id)); -	GL_CALL(glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image)); +	GLES2_DEBUG_PUSH; +	gles2_texture_ensure(tex, GL_TEXTURE_2D); +	glActiveTexture(GL_TEXTURE0); +	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id); +	glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image); +	GLES2_DEBUG_POP;  	return true;  } -static void gles2_texture_get_matrix(struct wlr_texture *_texture, -		float (*matrix)[16], const float (*projection)[16], int x, int y) { -	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; -	float world[16]; -	wlr_matrix_identity(matrix); -	wlr_matrix_translate(&world, x, y, 0); -	wlr_matrix_mul(matrix, &world, matrix); -	wlr_matrix_scale(&world, -			texture->wlr_texture.width, texture->wlr_texture.height, 1); -	wlr_matrix_mul(matrix, &world, matrix); -	wlr_matrix_mul(projection, matrix, matrix); +static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture, +		struct wl_resource *dmabuf_resource) { +	struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); +	struct wlr_dmabuf_buffer *dmabuf = +		wlr_dmabuf_buffer_from_buffer_resource(dmabuf_resource); + +	if (!tex->egl->egl_exts.dmabuf_import) { +		wlr_log(L_ERROR, "Want dmabuf but extension not present"); +		return false; +	} + +	tex->wlr_texture.width = dmabuf->attributes.width; +	tex->wlr_texture.height = dmabuf->attributes.height; + +	if (tex->image) { +		wlr_egl_destroy_image(tex->egl, tex->image); +	} + +	if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) { +		wlr_texture->inverted_y = true; +	} + +	GLenum target; +	const struct gles2_pixel_format *pf; +	if (dmabuf->attributes.n_planes > 1) { +		target = GL_TEXTURE_EXTERNAL_OES; +		pf = &external_pixel_format; +	} else { +		target = GL_TEXTURE_2D; +		pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888); +	} +	GLES2_DEBUG_PUSH; +	gles2_texture_ensure(tex, target); +	glBindTexture(target, tex->tex_id); +	tex->image = wlr_egl_create_image_from_dmabuf(tex->egl, &dmabuf->attributes); +	glActiveTexture(GL_TEXTURE0); +	glEGLImageTargetTexture2DOES(target, tex->image); +	GLES2_DEBUG_POP; +	tex->pixel_format = pf; +	tex->wlr_texture.valid = true; +	return true;  } -static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct +static bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct  		wl_resource *resource, int *width, int *height) { +	if (!wlr_dmabuf_resource_is_buffer(resource)) { +		return false; +	} + +	struct wlr_dmabuf_buffer *dmabuf = +		wlr_dmabuf_buffer_from_buffer_resource(resource); +	*width = dmabuf->attributes.width; +	*height = dmabuf->attributes.height; +	return true; +} + +static void gles2_texture_get_buffer_size(struct wlr_texture *texture, +		struct wl_resource *resource, int *width, int *height) {  	struct wl_shm_buffer *buffer = wl_shm_buffer_get(resource);  	if (!buffer) {  		struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)texture; @@ -249,12 +319,13 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct  		}  		if (!wlr_egl_query_buffer(tex->egl, resource, EGL_WIDTH,  				(EGLint*)width)) { -			wlr_log(L_ERROR, "could not get size of the buffer " -				"(no buffer found)"); -			return; -		}; -		wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, -			(EGLint*)height); +			if (!gles2_texture_get_dmabuf_size(texture, resource, width, +					height)) { +				wlr_log(L_ERROR, "could not get size of the buffer"); +				return; +			} +		} +		wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, (EGLint*)height);  		return;  	} @@ -263,19 +334,15 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct  	*height = wl_shm_buffer_get_height(buffer);  } -static void gles2_texture_bind(struct wlr_texture *_texture) { -	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; -	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); -	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); -	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); -	GL_CALL(glUseProgram(*texture->pixel_format->shader)); -} +static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { +	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); -static void gles2_texture_destroy(struct wlr_texture *_texture) { -	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; -	wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, &texture->wlr_texture); +	wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, +		&texture->wlr_texture);  	if (texture->tex_id) { -		GL_CALL(glDeleteTextures(1, &texture->tex_id)); +		GLES2_DEBUG_PUSH; +		glDeleteTextures(1, &texture->tex_id); +		GLES2_DEBUG_POP;  	}  	if (texture->image) { @@ -285,16 +352,15 @@ static void gles2_texture_destroy(struct wlr_texture *_texture) {  	free(texture);  } -static struct wlr_texture_impl wlr_texture_impl = { +static const struct wlr_texture_impl texture_impl = {  	.upload_pixels = gles2_texture_upload_pixels,  	.update_pixels = gles2_texture_update_pixels,  	.upload_shm = gles2_texture_upload_shm,  	.update_shm = gles2_texture_update_shm,  	.upload_drm = gles2_texture_upload_drm, +	.upload_dmabuf = gles2_texture_upload_dmabuf,  	.upload_eglimage = gles2_texture_upload_eglimage, -	.get_matrix = gles2_texture_get_matrix,  	.get_buffer_size = gles2_texture_get_buffer_size, -	.bind = gles2_texture_bind,  	.destroy = gles2_texture_destroy,  }; @@ -303,7 +369,7 @@ struct wlr_texture *gles2_texture_create(struct wlr_egl *egl) {  	if (!(texture = calloc(1, sizeof(struct wlr_gles2_texture)))) {  		return NULL;  	} -	wlr_texture_init(&texture->wlr_texture, &wlr_texture_impl); +	wlr_texture_init(&texture->wlr_texture, &texture_impl);  	texture->egl = egl;  	return &texture->wlr_texture;  } diff --git a/render/matrix.c b/render/matrix.c deleted file mode 100644 index d5d7f49d..00000000 --- a/render/matrix.c +++ /dev/null @@ -1,210 +0,0 @@ -#include <math.h> -#include <string.h> -#include <wayland-server-protocol.h> -#include <wlr/render/matrix.h> -#include <wlr/types/wlr_box.h> -#include <wlr/types/wlr_output.h> - -/* Obtains the index for the given row/column */ -static inline int mind(int row, int col) { -	return (row - 1) * 4 + col - 1; -} - -void wlr_matrix_identity(float (*output)[16]) { -	static const float identity[16] = { -		1.0f, 0.0f, 0.0f, 0.0f, -		0.0f, 1.0f, 0.0f, 0.0f, -		0.0f, 0.0f, 1.0f, 0.0f, -		0.0f, 0.0f, 0.0f, 1.0f -	}; -	memcpy(*output, identity, sizeof(identity)); -} - -void wlr_matrix_translate(float (*output)[16], float x, float y, float z) { -	wlr_matrix_identity(output); -	(*output)[mind(1, 4)] = x; -	(*output)[mind(2, 4)] = y; -	(*output)[mind(3, 4)] = z; -} - -void wlr_matrix_scale(float (*output)[16], float x, float y, float z) { -	wlr_matrix_identity(output); -	(*output)[mind(1, 1)] = x; -	(*output)[mind(2, 2)] = y; -	(*output)[mind(3, 3)] = z; -} - -void wlr_matrix_rotate(float (*output)[16], float radians) { -	wlr_matrix_identity(output); -	float _cos = cosf(radians); -	float _sin = sinf(radians); -	(*output)[mind(1, 1)] = _cos; -	(*output)[mind(1, 2)] = _sin; -	(*output)[mind(2, 1)] = -_sin; -	(*output)[mind(2, 2)] = _cos; -} - -void wlr_matrix_mul(const float (*x)[16], const float (*y)[16], float (*product)[16]) { -	float _product[16] = { -		(*x)[mind(1, 1)] * (*y)[mind(1, 1)] + (*x)[mind(1, 2)] * (*y)[mind(2, 1)] + -			(*x)[mind(1, 3)] * (*y)[mind(3, 1)] + (*x)[mind(1, 4)] * (*y)[mind(4, 1)], -		(*x)[mind(1, 1)] * (*y)[mind(1, 2)] + (*x)[mind(1, 2)] * (*y)[mind(2, 2)] + -			(*x)[mind(1, 3)] * (*y)[mind(3, 2)] + (*x)[mind(1, 4)] * (*y)[mind(4, 2)], -		(*x)[mind(1, 1)] * (*y)[mind(1, 3)] + (*x)[mind(1, 2)] * (*y)[mind(2, 3)] + -			(*x)[mind(1, 3)] * (*y)[mind(3, 3)] + (*x)[mind(1, 4)] * (*y)[mind(4, 3)], -		(*x)[mind(1, 1)] * (*y)[mind(1, 4)] + (*x)[mind(1, 2)] * (*y)[mind(2, 4)] + -			(*x)[mind(1, 4)] * (*y)[mind(3, 4)] + (*x)[mind(1, 4)] * (*y)[mind(4, 4)], - -		(*x)[mind(2, 1)] * (*y)[mind(1, 1)] + (*x)[mind(2, 2)] * (*y)[mind(2, 1)] + -			(*x)[mind(2, 3)] * (*y)[mind(3, 1)] + (*x)[mind(2, 4)] * (*y)[mind(4, 1)], -		(*x)[mind(2, 1)] * (*y)[mind(1, 2)] + (*x)[mind(2, 2)] * (*y)[mind(2, 2)] + -			(*x)[mind(2, 3)] * (*y)[mind(3, 2)] + (*x)[mind(2, 4)] * (*y)[mind(4, 2)], -		(*x)[mind(2, 1)] * (*y)[mind(1, 3)] + (*x)[mind(2, 2)] * (*y)[mind(2, 3)] + -			(*x)[mind(2, 3)] * (*y)[mind(3, 3)] + (*x)[mind(2, 4)] * (*y)[mind(4, 3)], -		(*x)[mind(2, 1)] * (*y)[mind(1, 4)] + (*x)[mind(2, 2)] * (*y)[mind(2, 4)] + -			(*x)[mind(2, 4)] * (*y)[mind(3, 4)] + (*x)[mind(2, 4)] * (*y)[mind(4, 4)], - -		(*x)[mind(3, 1)] * (*y)[mind(1, 1)] + (*x)[mind(3, 2)] * (*y)[mind(2, 1)] + -			(*x)[mind(3, 3)] * (*y)[mind(3, 1)] + (*x)[mind(3, 4)] * (*y)[mind(4, 1)], -		(*x)[mind(3, 1)] * (*y)[mind(1, 2)] + (*x)[mind(3, 2)] * (*y)[mind(2, 2)] + -			(*x)[mind(3, 3)] * (*y)[mind(3, 2)] + (*x)[mind(3, 4)] * (*y)[mind(4, 2)], -		(*x)[mind(3, 1)] * (*y)[mind(1, 3)] + (*x)[mind(3, 2)] * (*y)[mind(2, 3)] + -			(*x)[mind(3, 3)] * (*y)[mind(3, 3)] + (*x)[mind(3, 4)] * (*y)[mind(4, 3)], -		(*x)[mind(3, 1)] * (*y)[mind(1, 4)] + (*x)[mind(3, 2)] * (*y)[mind(2, 4)] + -			(*x)[mind(3, 4)] * (*y)[mind(3, 4)] + (*x)[mind(3, 4)] * (*y)[mind(4, 4)], - -		(*x)[mind(4, 1)] * (*y)[mind(1, 1)] + (*x)[mind(4, 2)] * (*y)[mind(2, 1)] + -			(*x)[mind(4, 3)] * (*y)[mind(3, 1)] + (*x)[mind(4, 4)] * (*y)[mind(4, 1)], -		(*x)[mind(4, 1)] * (*y)[mind(1, 2)] + (*x)[mind(4, 2)] * (*y)[mind(2, 2)] + -			(*x)[mind(4, 3)] * (*y)[mind(3, 2)] + (*x)[mind(4, 4)] * (*y)[mind(4, 2)], -		(*x)[mind(4, 1)] * (*y)[mind(1, 3)] + (*x)[mind(4, 2)] * (*y)[mind(2, 3)] + -			(*x)[mind(4, 3)] * (*y)[mind(3, 3)] + (*x)[mind(4, 4)] * (*y)[mind(4, 3)], -		(*x)[mind(4, 1)] * (*y)[mind(1, 4)] + (*x)[mind(4, 2)] * (*y)[mind(2, 4)] + -			(*x)[mind(4, 4)] * (*y)[mind(3, 4)] + (*x)[mind(4, 4)] * (*y)[mind(4, 4)], -	}; -	memcpy(*product, _product, sizeof(_product)); -} - -static const float transforms[][4] = { -	[WL_OUTPUT_TRANSFORM_NORMAL] = { -		1.0f, 0.0f, -		0.0f, 1.0f, -	}, -	[WL_OUTPUT_TRANSFORM_90] = { -		0.0f, -1.0f, -		1.0f, 0.0f, -	}, -	[WL_OUTPUT_TRANSFORM_180] = { -		-1.0f, 0.0f, -		0.0f, -1.0f, -	}, -	[WL_OUTPUT_TRANSFORM_270] = { -		0.0f, 1.0f, -		-1.0f, 0.0f, -	}, -	[WL_OUTPUT_TRANSFORM_FLIPPED] = { -		-1.0f, 0.0f, -		0.0f, 1.0f, -	}, -	[WL_OUTPUT_TRANSFORM_FLIPPED_90] = { -		0.0f, -1.0f, -		-1.0f, 0.0f, -	}, -	[WL_OUTPUT_TRANSFORM_FLIPPED_180] = { -		1.0f, 0.0f, -		0.0f, -1.0f, -	}, -	[WL_OUTPUT_TRANSFORM_FLIPPED_270] = { -		0.0f, 1.0f, -		1.0f, 0.0f, -	}, -}; - -void wlr_matrix_transform(float mat[static 16], -		enum wl_output_transform transform) { -	memset(mat, 0, sizeof(*mat) * 16); - -	const float *t = transforms[transform]; - -	// Rotation + reflection -	mat[0] = t[0]; -	mat[1] = t[1]; -	mat[4] = t[2]; -	mat[5] = t[3]; - -	// Identity -	mat[10] = 1.0f; -	mat[15] = 1.0f; -} - -// Equivilent to glOrtho(0, width, 0, height, 1, -1) with the transform applied -void wlr_matrix_texture(float mat[static 16], int32_t width, int32_t height, -		enum wl_output_transform transform) { -	memset(mat, 0, sizeof(*mat) * 16); - -	const float *t = transforms[transform]; -	float x = 2.0f / width; -	float y = 2.0f / height; - -	// Rotation + reflection -	mat[0] = x * t[0]; -	mat[1] = x * t[1]; -	mat[4] = y * -t[2]; -	mat[5] = y * -t[3]; - -	// Translation -	mat[3] = -copysign(1.0f, mat[0] + mat[1]); -	mat[7] = -copysign(1.0f, mat[4] + mat[5]); - -	// Identity -	mat[10] = 1.0f; -	mat[15] = 1.0f; -} - -void wlr_matrix_project_box(float (*mat)[16], struct wlr_box *box, -		enum wl_output_transform transform, float rotation, -		float (*projection)[16]) { -	int x = box->x; -	int y = box->y; -	int width = box->width; -	int height = box->height; - -	wlr_matrix_translate(mat, x, y, 0); - -	if (rotation != 0) { -		float translate_center[16]; -		wlr_matrix_translate(&translate_center, width/2, height/2, 0); - -		float rotate[16]; -		wlr_matrix_rotate(&rotate, rotation); - -		float translate_origin[16]; -		wlr_matrix_translate(&translate_origin, -width/2, -height/2, 0); - -		wlr_matrix_mul(mat, &translate_center, mat); -		wlr_matrix_mul(mat, &rotate, mat); -		wlr_matrix_mul(mat, &translate_origin, mat); -	} - -	float scale[16]; -	wlr_matrix_scale(&scale, width, height, 1); - -	wlr_matrix_mul(mat, &scale, mat); - -	if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { -		float surface_translate_center[16]; -		wlr_matrix_translate(&surface_translate_center, 0.5, 0.5, 0); - -		float surface_transform[16]; -		wlr_matrix_transform(surface_transform, transform); - -		float surface_translate_origin[16]; -		wlr_matrix_translate(&surface_translate_origin, -0.5, -0.5, 0); - -		wlr_matrix_mul(mat, &surface_translate_center, mat); -		wlr_matrix_mul(mat, &surface_transform, mat); -		wlr_matrix_mul(mat, &surface_translate_origin, mat); -	} - -	wlr_matrix_mul(projection, mat, mat); -} diff --git a/render/meson.build b/render/meson.build index 8aa70cea..4fe9ea67 100644 --- a/render/meson.build +++ b/render/meson.build @@ -15,7 +15,6 @@ lib_wlr_render = static_library(  		'gles2/shaders.c',  		'gles2/texture.c',  		'gles2/util.c', -		'matrix.c',  		'wlr_renderer.c',  		'wlr_texture.c',  	), diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index ce8fbe36..5598a0e7 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -1,9 +1,11 @@  #include <stdbool.h>  #include <stdlib.h>  #include <wlr/render/interface.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_matrix.h>  void wlr_renderer_init(struct wlr_renderer *renderer, -		struct wlr_renderer_impl *impl) { +		const struct wlr_renderer_impl *impl) {  	renderer->impl = impl;  } @@ -15,15 +17,15 @@ void wlr_renderer_destroy(struct wlr_renderer *r) {  	}  } -void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *o) { -	r->impl->begin(r, o); +void wlr_renderer_begin(struct wlr_renderer *r, int width, int height) { +	r->impl->begin(r, width, height);  }  void wlr_renderer_end(struct wlr_renderer *r) {  	r->impl->end(r);  } -void wlr_renderer_clear(struct wlr_renderer *r, const float (*color)[4]) { +void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]) {  	r->impl->clear(r, color);  } @@ -35,19 +37,52 @@ struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r) {  	return r->impl->texture_create(r);  } -bool wlr_render_with_matrix(struct wlr_renderer *r, -		struct wlr_texture *texture, const float (*matrix)[16], float alpha) { -	return r->impl->render_with_matrix(r, texture, matrix, alpha); +bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture, +		const float projection[static 9], int x, int y, float alpha) { +	const struct wlr_box box = { +		.x = x, .y = y, +		.width = texture->width, .height = texture->height, +	}; + +	float matrix[9]; +	wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, +		projection); + +	return wlr_render_texture_with_matrix(r, texture, matrix, alpha); +} + +bool wlr_render_texture_with_matrix(struct wlr_renderer *r, +		struct wlr_texture *texture, const float matrix[static 9], +		float alpha) { +	return r->impl->render_texture_with_matrix(r, texture, matrix, alpha); +} + +void wlr_render_rect(struct wlr_renderer *r, const struct wlr_box *box, +		const float color[static 4], const float projection[static 9]) { +	float matrix[9]; +	wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, +		projection); + +	wlr_render_quad_with_matrix(r, color, matrix);  } -void wlr_render_colored_quad(struct wlr_renderer *r, -		const float (*color)[4], const float (*matrix)[16]) { -	r->impl->render_quad(r, color, matrix); +void wlr_render_quad_with_matrix(struct wlr_renderer *r, +		const float color[static 4], const float matrix[static 9]) { +	r->impl->render_quad_with_matrix(r, color, matrix); +} + +void wlr_render_ellipse(struct wlr_renderer *r, const struct wlr_box *box, +		const float color[static 4], const float projection[static 9]) { +	float matrix[9]; +	wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, +		projection); + +	wlr_render_ellipse_with_matrix(r, color, matrix);  } -void wlr_render_colored_ellipse(struct wlr_renderer *r, -		const float (*color)[4], const float (*matrix)[16]) { -	r->impl->render_ellipse(r, color, matrix); +void wlr_render_ellipse_with_matrix(struct wlr_renderer *r, +		const float color[static 4], const float matrix[static 9]) { +	r->impl->render_ellipse_with_matrix(r, color, matrix);  }  const enum wl_shm_format *wlr_renderer_get_formats( diff --git a/render/wlr_texture.c b/render/wlr_texture.c index a82a16b2..33c91822 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -1,9 +1,10 @@  #include <stdbool.h>  #include <stdlib.h>  #include <wlr/render/interface.h> +#include <wlr/render/wlr_texture.h>  void wlr_texture_init(struct wlr_texture *texture, -		struct wlr_texture_impl *impl) { +		const struct wlr_texture_impl *impl) {  	texture->impl = impl;  	wl_signal_init(&texture->destroy_signal);  } @@ -16,10 +17,6 @@ void wlr_texture_destroy(struct wlr_texture *texture) {  	}  } -void wlr_texture_bind(struct wlr_texture *texture) { -	texture->impl->bind(texture); -} -  bool wlr_texture_upload_pixels(struct wlr_texture *texture, uint32_t format,  		int stride, int width, int height, const unsigned char *pixels) {  	return texture->impl->upload_pixels(texture, format, stride, @@ -53,9 +50,9 @@ bool wlr_texture_upload_eglimage(struct wlr_texture *texture,  	return texture->impl->upload_eglimage(texture, image, width, height);  } -void wlr_texture_get_matrix(struct wlr_texture *texture, -		float (*matrix)[16], const float (*projection)[16], int x, int y) { -	texture->impl->get_matrix(texture, matrix, projection, x, y); +bool wlr_texture_upload_dmabuf(struct wlr_texture *texture, +		struct wl_resource *dmabuf_resource) { +	return texture->impl->upload_dmabuf(texture, dmabuf_resource);  }  void wlr_texture_get_buffer_size(struct wlr_texture *texture, struct wl_resource diff --git a/rootston/config.c b/rootston/config.c index e63efc0b..0883f6d4 100644 --- a/rootston/config.c +++ b/rootston/config.c @@ -25,7 +25,9 @@ static void usage(const char *name, int ret) {  		"                (default: rootston.ini).\n"  		"                See `rootston.ini.example` for config\n"  		"                file documentation.\n" -		" -E <COMMAND>   Command that will be ran at startup.\n" , name); +		" -E <COMMAND>   Command that will be ran at startup.\n" +		" -D             Enable damage tracking debugging.\n", +		name);  	exit(ret);  } @@ -394,7 +396,7 @@ struct roots_config *roots_config_create_from_args(int argc, char *argv[]) {  	wl_list_init(&config->bindings);  	int c; -	while ((c = getopt(argc, argv, "C:E:h")) != -1) { +	while ((c = getopt(argc, argv, "C:E:hD")) != -1) {  		switch (c) {  		case 'C':  			config->config_path = strdup(optarg); @@ -402,6 +404,9 @@ struct roots_config *roots_config_create_from_args(int argc, char *argv[]) {  		case 'E':  			config->startup_cmd = strdup(optarg);  			break; +		case 'D': +			config->debug_damage_tracking = true; +			break;  		case 'h':  		case '?':  			usage(argv[0], c != 'h'); diff --git a/rootston/cursor.c b/rootston/cursor.c index aa94daeb..52439dff 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -200,7 +200,7 @@ static void roots_cursor_update_position(struct roots_cursor *cursor,  				uy = cursor->offs_y - oy;  			int vx = cursor->cursor->x - ox,  				vy = cursor->cursor->y - oy; -			float angle = atan2(vx*uy - vy*ux, vx*ux + vy*uy); +			float angle = atan2(ux*vy - uy*vx, vx*ux + vy*uy);  			int steps = 12;  			angle = round(angle/M_PI*steps) / (steps/M_PI);  			view_rotate(view, cursor->view_rotation + angle); diff --git a/rootston/desktop.c b/rootston/desktop.c index 3628b051..65d9a280 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -9,6 +9,7 @@  #include <wlr/types/wlr_cursor.h>  #include <wlr/types/wlr_gamma_control.h>  #include <wlr/types/wlr_idle.h> +#include <wlr/types/wlr_linux_dmabuf.h>  #include <wlr/types/wlr_output_layout.h>  #include <wlr/types/wlr_idle_inhibit_v1.h>  #include <wlr/types/wlr_primary_selection.h> @@ -23,13 +24,16 @@  #include "rootston/view.h"  #include "rootston/xcursor.h" - -struct roots_view *view_create() { +struct roots_view *view_create(struct roots_desktop *desktop) {  	struct roots_view *view = calloc(1, sizeof(struct roots_view));  	if (!view) {  		return NULL;  	} +	view->desktop = desktop;  	view->alpha = 1.0f; +	wl_signal_init(&view->events.unmap); +	wl_signal_init(&view->events.destroy); +	wl_list_init(&view->children);  	return view;  } @@ -52,7 +56,8 @@ void view_get_deco_box(const struct roots_view *view, struct wlr_box *box) {  	box->height += (view->border_width * 2 + view->titlebar_height);  } -enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, double sy) { +enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, +		double sy) {  	if (!view->decorated) {  		return ROOTS_DECO_PART_NONE;  	} @@ -92,9 +97,15 @@ enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, doub  static void view_update_output(const struct roots_view *view,  		const struct wlr_box *before) {  	struct roots_desktop *desktop = view->desktop; -	struct roots_output *output; + +	if (view->wlr_surface == NULL) { +		return; +	} +  	struct wlr_box box;  	view_get_box(view, &box); + +	struct roots_output *output;  	wl_list_for_each(output, &desktop->outputs, link) {  		bool intersected = before != NULL && wlr_output_layout_intersects(  			desktop->layout, output->wlr_output, before); @@ -402,20 +413,22 @@ struct roots_subsurface *subsurface_create(struct roots_view *view,  	return subsurface;  } -void view_finish(struct roots_view *view) { -	view_damage_whole(view); -	wl_signal_emit(&view->events.destroy, view); +void view_destroy(struct roots_view *view) { +	if (view == NULL) { +		return; +	} -	wl_list_remove(&view->new_subsurface.link); +	wl_signal_emit(&view->events.destroy, view); -	struct roots_view_child *child, *tmp; -	wl_list_for_each_safe(child, tmp, &view->children, link) { -		child->destroy(child); +	if (view->wlr_surface != NULL) { +		view_unmap(view);  	} -	if (view->fullscreen_output) { -		view->fullscreen_output->fullscreen_view = NULL; +	if (view->destroy) { +		view->destroy(view);  	} + +	free(view);  }  static void view_handle_new_subsurface(struct wl_listener *listener, @@ -425,12 +438,10 @@ static void view_handle_new_subsurface(struct wl_listener *listener,  	subsurface_create(view, wlr_subsurface);  } -void view_init(struct roots_view *view, struct roots_desktop *desktop) { -	assert(view->wlr_surface); +void view_map(struct roots_view *view, struct wlr_surface *surface) { +	assert(view->wlr_surface == NULL); -	view->desktop = desktop; -	wl_signal_init(&view->events.destroy); -	wl_list_init(&view->children); +	view->wlr_surface = surface;  	struct wlr_subsurface *subsurface;  	wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list, @@ -442,9 +453,35 @@ void view_init(struct roots_view *view, struct roots_desktop *desktop) {  	wl_signal_add(&view->wlr_surface->events.new_subsurface,  		&view->new_subsurface); +	wl_list_insert(&view->desktop->views, &view->link);  	view_damage_whole(view);  } +void view_unmap(struct roots_view *view) { +	assert(view->wlr_surface != NULL); + +	wl_signal_emit(&view->events.unmap, view); + +	view_damage_whole(view); +	wl_list_remove(&view->link); + +	wl_list_remove(&view->new_subsurface.link); + +	struct roots_view_child *child, *tmp; +	wl_list_for_each_safe(child, tmp, &view->children, link) { +		child->destroy(child); +	} + +	if (view->fullscreen_output != NULL) { +		output_damage_whole(view->fullscreen_output); +		view->fullscreen_output->fullscreen_view = NULL; +		view->fullscreen_output = NULL; +	} + +	view->wlr_surface = NULL; +	view->width = view->height = 0; +} +  void view_initial_focus(struct roots_view *view) {  	struct roots_input *input = view->desktop->server->input;  	// TODO what seat gets focus? the one with the last input event? @@ -457,7 +494,10 @@ void view_initial_focus(struct roots_view *view) {  void view_setup(struct roots_view *view) {  	view_initial_focus(view); -	view_center(view); +	if (view->fullscreen_output == NULL && !view->maximized) { +		view_center(view); +	} +  	view_update_output(view, NULL);  } @@ -517,8 +557,8 @@ static bool view_at(struct roots_view *view, double lx, double ly,  		double ox = view_sx - (double)box.width/2,  			oy = view_sy - (double)box.height/2;  		// Rotated coordinates -		double rx = cos(view->rotation)*ox - sin(view->rotation)*oy, -			ry = cos(view->rotation)*oy + sin(view->rotation)*ox; +		double rx = cos(view->rotation)*ox + sin(view->rotation)*oy, +			ry = cos(view->rotation)*oy - sin(view->rotation)*ox;  		view_sx = rx + (double)box.width/2;  		view_sy = ry + (double)box.height/2;  	} @@ -729,6 +769,8 @@ struct roots_desktop *desktop_create(struct roots_server *server,  	desktop->idle = wlr_idle_create(server->wl_display);  	desktop->idle_inhibit = wlr_idle_inhibit_v1_create(server->wl_display); +	struct wlr_egl *egl = wlr_backend_get_egl(server->backend); +	desktop->linux_dmabuf = wlr_linux_dmabuf_create(server->wl_display, egl);  	return desktop;  } diff --git a/rootston/main.c b/rootston/main.c index 5450ade2..d85701ca 100644 --- a/rootston/main.c +++ b/rootston/main.c @@ -7,7 +7,7 @@  #include <wlr/backend/headless.h>  #include <wlr/backend/multi.h>  #include <wlr/config.h> -#include <wlr/render.h> +#include <wlr/render/wlr_renderer.h>  #include <wlr/util/log.h>  #include "rootston/config.h"  #include "rootston/server.h" diff --git a/rootston/output.c b/rootston/output.c index 4d0a9c05..8d6444d6 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -3,7 +3,7 @@  #include <stdbool.h>  #include <stdlib.h>  #include <time.h> -#include <wlr/render/matrix.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/types/wlr_compositor.h>  #include <wlr/types/wlr_output_layout.h>  #include <wlr/types/wlr_wl_shell.h> @@ -29,8 +29,8 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh,  		double ox = *sx - pw/2 + sw/2,  			oy = *sy - ph/2 + sh/2;  		// Rotated coordinates -		double rx = cos(-rotation)*ox - sin(-rotation)*oy, -			ry = cos(-rotation)*oy + sin(-rotation)*ox; +		double rx = cos(rotation)*ox - sin(rotation)*oy, +			ry = cos(rotation)*oy + sin(rotation)*ox;  		*sx = rx + pw/2 - sw/2;  		*sy = ry + ph/2 - sh/2;  	} @@ -227,7 +227,7 @@ static bool surface_intersect_output(struct wlr_surface *surface,  		.x = lx, .y = ly,  		.width = surface->current->width, .height = surface->current->height,  	}; -	wlr_box_rotated_bounds(&layout_box, -rotation, &layout_box); +	wlr_box_rotated_bounds(&layout_box, rotation, &layout_box);  	return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box);  } @@ -275,7 +275,7 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly,  	}  	struct wlr_box rotated; -	wlr_box_rotated_bounds(&box, -rotation, &rotated); +	wlr_box_rotated_bounds(&box, rotation, &rotated);  	pixman_region32_t damage;  	pixman_region32_init(&damage); @@ -287,17 +287,17 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly,  		goto damage_finish;  	} -	float matrix[16]; +	float matrix[9];  	enum wl_output_transform transform =  		wlr_output_transform_invert(surface->current->transform); -	wlr_matrix_project_box(&matrix, &box, transform, rotation, -		&output->wlr_output->transform_matrix); +	wlr_matrix_project_box(matrix, &box, transform, rotation, +		output->wlr_output->transform_matrix);  	int nrects;  	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);  	for (int i = 0; i < nrects; ++i) {  		scissor_output(output, &rects[i]); -		wlr_render_with_matrix(renderer, surface->texture, &matrix, data->alpha); +		wlr_render_texture_with_matrix(renderer, surface->texture, matrix, data->alpha);  	}  damage_finish: @@ -341,7 +341,7 @@ static void render_decorations(struct roots_view *view,  	get_decoration_box(view, output, &box);  	struct wlr_box rotated; -	wlr_box_rotated_bounds(&box, -view->rotation, &rotated); +	wlr_box_rotated_bounds(&box, view->rotation, &rotated);  	pixman_region32_t damage;  	pixman_region32_init(&damage); @@ -353,9 +353,9 @@ static void render_decorations(struct roots_view *view,  		goto damage_finish;  	} -	float matrix[16]; -	wlr_matrix_project_box(&matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, -		view->rotation, &output->wlr_output->transform_matrix); +	float matrix[9]; +	wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, +		view->rotation, output->wlr_output->transform_matrix);  	float color[] = { 0.2, 0.2, 0.2, view->alpha };  	int nrects; @@ -363,7 +363,7 @@ static void render_decorations(struct roots_view *view,  		pixman_region32_rectangles(&damage, &nrects);  	for (int i = 0; i < nrects; ++i) {  		scissor_output(output, &rects[i]); -		wlr_render_colored_quad(renderer, &color, &matrix); +		wlr_render_quad_with_matrix(renderer, color, matrix);  	}  damage_finish: @@ -433,7 +433,8 @@ static void render_output(struct roots_output *output) {  	float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};  	// Check if we can delegate the fullscreen surface to the output -	if (output->fullscreen_view != NULL) { +	if (output->fullscreen_view != NULL && +			output->fullscreen_view->wlr_surface != NULL) {  		struct roots_view *view = output->fullscreen_view;  		// Make sure the view is centered on screen @@ -478,18 +479,22 @@ static void render_output(struct roots_output *output) {  		goto damage_finish;  	} -	wlr_renderer_begin(renderer, wlr_output); +	wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);  	if (!pixman_region32_not_empty(&damage)) {  		// Output isn't damaged but needs buffer swap  		goto renderer_end;  	} +	if (server->config->debug_damage_tracking) { +		wlr_renderer_clear(renderer, (float[]){1, 1, 0, 0}); +	} +  	int nrects;  	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);  	for (int i = 0; i < nrects; ++i) {  		scissor_output(output, &rects[i]); -		wlr_renderer_clear(renderer, &clear_color); +		wlr_renderer_clear(renderer, clear_color);  	}  	// If a view is fullscreen on this output, render it @@ -501,7 +506,9 @@ static void render_output(struct roots_output *output) {  			goto renderer_end;  		} -		view_for_each_surface(view, render_surface, &data); +		if (view->wlr_surface != NULL) { +			view_for_each_surface(view, render_surface, &data); +		}  		// During normal rendering the xwayland window tree isn't traversed  		// because all windows are rendered. Here we only want to render @@ -570,6 +577,9 @@ void output_damage_whole(struct roots_output *output) {  static bool view_accept_damage(struct roots_output *output,  		struct roots_view *view) { +	if (view->wlr_surface == NULL) { +		return false; +	}  	if (output->fullscreen_view == NULL) {  		return true;  	} @@ -610,7 +620,7 @@ static void damage_whole_surface(struct wlr_surface *surface,  		return;  	} -	wlr_box_rotated_bounds(&box, -rotation, &box); +	wlr_box_rotated_bounds(&box, rotation, &box);  	wlr_output_damage_add_box(output->damage, &box);  } @@ -624,7 +634,7 @@ static void damage_whole_decoration(struct roots_view *view,  	struct wlr_box box;  	get_decoration_box(view, output, &box); -	wlr_box_rotated_bounds(&box, -view->rotation, &box); +	wlr_box_rotated_bounds(&box, view->rotation, &box);  	wlr_output_damage_add_box(output->damage, &box);  } @@ -661,31 +671,23 @@ static void damage_from_surface(struct wlr_surface *surface,  	surface_intersect_output(surface, output->desktop->layout,  		wlr_output, lx, ly, rotation, &box); -	if (rotation == 0) { -		pixman_region32_t damage; -		pixman_region32_init(&damage); -		pixman_region32_copy(&damage, &surface->current->surface_damage); -		wlr_region_scale(&damage, &damage, wlr_output->scale); -		if (ceil(wlr_output->scale) > surface->current->scale) { -			// When scaling up a surface, it'll become blurry so we need to -			// expand the damage region -			wlr_region_expand(&damage, &damage, -				ceil(wlr_output->scale) - surface->current->scale); -		} -		pixman_region32_translate(&damage, box.x, box.y); -		wlr_output_damage_add(output->damage, &damage); -	} else { -		pixman_box32_t *extents = -			pixman_region32_extents(&surface->current->surface_damage); -		struct wlr_box damage_box = { -			.x = box.x + extents->x1 * wlr_output->scale, -			.y = box.y + extents->y1 * wlr_output->scale, -			.width = (extents->x2 - extents->x1) * wlr_output->scale, -			.height = (extents->y2 - extents->y1) * wlr_output->scale, -		}; -		wlr_box_rotated_bounds(&damage_box, -rotation, &damage_box); -		wlr_output_damage_add_box(output->damage, &damage_box); -	} +	int center_x = box.x + box.width/2; +	int center_y = box.y + box.height/2; + +	pixman_region32_t damage; +	pixman_region32_init(&damage); +	pixman_region32_copy(&damage, &surface->current->surface_damage); +	wlr_region_scale(&damage, &damage, wlr_output->scale); +	if (ceil(wlr_output->scale) > surface->current->scale) { +		// When scaling up a surface, it'll become blurry so we need to +		// expand the damage region +		wlr_region_expand(&damage, &damage, +			ceil(wlr_output->scale) - surface->current->scale); +	} +	pixman_region32_translate(&damage, box.x, box.y); +	wlr_region_rotated_bounds(&damage, &damage, rotation, center_x, center_y); +	wlr_output_damage_add(output->damage, &damage); +	pixman_region32_fini(&damage);  }  void output_damage_from_view(struct roots_output *output, diff --git a/rootston/seat.c b/rootston/seat.c index 9acbb737..d2d211ba 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -514,13 +514,13 @@ static void seat_add_tablet_pad(struct roots_seat *seat,  static void handle_tablet_tool_destroy(struct wl_listener *listener,  		void *data) { -	struct roots_pointer *tablet_tool = +	struct roots_tablet_tool *tablet_tool =  		wl_container_of(listener, tablet_tool, device_destroy);  	struct roots_seat *seat = tablet_tool->seat; -	wl_list_remove(&tablet_tool->link);  	wlr_cursor_detach_input_device(seat->cursor->cursor, tablet_tool->device);  	wl_list_remove(&tablet_tool->device_destroy.link); +	wl_list_remove(&tablet_tool->link);  	free(tablet_tool);  	seat_update_capabilities(seat); @@ -645,6 +645,7 @@ static void seat_view_destroy(struct roots_seat_view *seat_view) {  		seat->cursor->pointer_view = NULL;  	} +	wl_list_remove(&seat_view->view_unmap.link);  	wl_list_remove(&seat_view->view_destroy.link);  	wl_list_remove(&seat_view->link);  	free(seat_view); @@ -657,6 +658,12 @@ static void seat_view_destroy(struct roots_seat_view *seat_view) {  	}  } +static void seat_view_handle_unmap(struct wl_listener *listener, void *data) { +	struct roots_seat_view *seat_view = +		wl_container_of(listener, seat_view, view_unmap); +	seat_view_destroy(seat_view); +} +  static void seat_view_handle_destroy(struct wl_listener *listener, void *data) {  	struct roots_seat_view *seat_view =  		wl_container_of(listener, seat_view, view_destroy); @@ -675,6 +682,8 @@ static struct roots_seat_view *seat_add_view(struct roots_seat *seat,  	wl_list_insert(seat->views.prev, &seat_view->link); +	seat_view->view_unmap.notify = seat_view_handle_unmap; +	wl_signal_add(&view->events.unmap, &seat_view->view_unmap);  	seat_view->view_destroy.notify = seat_view_handle_destroy;  	wl_signal_add(&view->events.destroy, &seat_view->view_destroy); diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index 899df1c6..d58f030a 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -78,6 +78,19 @@ static void close(struct roots_view *view) {  	wl_client_destroy(surf->client);  } +static void destroy(struct roots_view *view) { +	assert(view->type == ROOTS_WL_SHELL_VIEW); +	struct roots_wl_shell_surface *roots_surface = view->roots_wl_shell_surface; +	wl_list_remove(&roots_surface->destroy.link); +	wl_list_remove(&roots_surface->request_move.link); +	wl_list_remove(&roots_surface->request_resize.link); +	wl_list_remove(&roots_surface->request_maximize.link); +	wl_list_remove(&roots_surface->request_fullscreen.link); +	wl_list_remove(&roots_surface->set_state.link); +	wl_list_remove(&roots_surface->surface_commit.link); +	free(roots_surface); +} +  static void handle_request_move(struct wl_listener *listener, void *data) {  	struct roots_wl_shell_surface *roots_surface =  		wl_container_of(listener, roots_surface, request_move); @@ -174,17 +187,7 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {  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->request_move.link); -	wl_list_remove(&roots_surface->request_resize.link); -	wl_list_remove(&roots_surface->request_maximize.link); -	wl_list_remove(&roots_surface->request_fullscreen.link); -	wl_list_remove(&roots_surface->set_state.link); -	wl_list_remove(&roots_surface->surface_commit.link); -	wl_list_remove(&roots_surface->view->link); -	view_finish(roots_surface->view); -	free(roots_surface->view); -	free(roots_surface); +	view_destroy(roots_surface->view);  }  void handle_wl_shell_surface(struct wl_listener *listener, void *data) { @@ -227,7 +230,7 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {  	roots_surface->surface_commit.notify = handle_surface_commit;  	wl_signal_add(&surface->surface->events.commit, &roots_surface->surface_commit); -	struct roots_view *view = view_create(); +	struct roots_view *view = view_create(desktop);  	if (!view) {  		free(roots_surface);  		return; @@ -238,13 +241,12 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {  	view->wl_shell_surface = surface;  	view->roots_wl_shell_surface = roots_surface; -	view->wlr_surface = surface->surface;  	view->resize = resize;  	view->close = close; +	view->destroy = destroy;  	roots_surface->view = view; -	view_init(view, desktop); -	wl_list_insert(&desktop->views, &view->link); +	view_map(view, surface->surface);  	view_setup(view);  	if (surface->state == WLR_WL_SHELL_SURFACE_STATE_TRANSIENT) { diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c index 9368ce0b..099e622c 100644 --- a/rootston/xdg_shell.c +++ b/rootston/xdg_shell.c @@ -60,12 +60,14 @@ 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 { +	if (surface->geometry.width > 0 && surface->geometry.height > 0) { +		box->width = surface->geometry.width; +		box->height = surface->geometry.height; +	} else if (view->wlr_surface != NULL) {  		box->width = view->wlr_surface->current->width;  		box->height = view->wlr_surface->current->height; +	} else { +		box->width = box->height = 0;  	}  } @@ -83,7 +85,7 @@ static void apply_size_constraints(struct wlr_xdg_surface *surface,  	*dest_width = width;  	*dest_height = height; -	struct wlr_xdg_toplevel_state *state = &surface->toplevel_state->current; +	struct wlr_xdg_toplevel_state *state = &surface->toplevel->current;  	if (width < state->min_width) {  		*dest_width = state->min_width;  	} else if (state->max_width > 0 && @@ -175,9 +177,26 @@ static void set_fullscreen(struct roots_view *view, bool 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); +	struct wlr_xdg_popup *popup = NULL; +	wl_list_for_each(popup, &surface->popups, link) { +		wlr_xdg_surface_send_close(popup->base);  	} +	wlr_xdg_surface_send_close(surface); +} + +static void destroy(struct roots_view *view) { +	assert(view->type == ROOTS_XDG_SHELL_VIEW); +	struct roots_xdg_surface *roots_xdg_surface = view->roots_xdg_surface; +	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->map.link); +	wl_list_remove(&roots_xdg_surface->unmap.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); +	free(roots_xdg_surface);  }  static void handle_request_move(struct wl_listener *listener, void *data) { @@ -219,7 +238,7 @@ static void handle_request_maximize(struct wl_listener *listener, void *data) {  		return;  	} -	view_maximize(view, surface->toplevel_state->next.maximized); +	view_maximize(view, surface->toplevel->next.maximized);  }  static void handle_request_fullscreen(struct wl_listener *listener, @@ -243,6 +262,10 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {  	struct roots_view *view = roots_surface->view;  	struct wlr_xdg_surface *surface = view->xdg_surface; +	if (!surface->mapped) { +		return; +	} +  	view_apply_damage(view);  	struct wlr_box size; @@ -277,20 +300,30 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {  	popup_create(roots_xdg_surface->view, wlr_popup);  } +static void handle_map(struct wl_listener *listener, void *data) { +	struct roots_xdg_surface *roots_xdg_surface = +		wl_container_of(listener, roots_xdg_surface, map); +	struct roots_view *view = roots_xdg_surface->view; + +	struct wlr_box box; +	get_size(view, &box); +	view->width = box.width; +	view->height = box.height; + +	view_map(view, view->xdg_surface->surface); +	view_setup(view); +} + +static void handle_unmap(struct wl_listener *listener, void *data) { +	struct roots_xdg_surface *roots_xdg_surface = +		wl_container_of(listener, roots_xdg_surface, unmap); +	view_unmap(roots_xdg_surface->view); +} +  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); +	view_destroy(roots_xdg_surface->view);  }  void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { @@ -319,6 +352,10 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {  		&roots_surface->surface_commit);  	roots_surface->destroy.notify = handle_destroy;  	wl_signal_add(&surface->events.destroy, &roots_surface->destroy); +	roots_surface->map.notify = handle_map; +	wl_signal_add(&surface->events.map, &roots_surface->map); +	roots_surface->unmap.notify = handle_unmap; +	wl_signal_add(&surface->events.unmap, &roots_surface->unmap);  	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; @@ -333,7 +370,7 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {  	roots_surface->new_popup.notify = handle_new_popup;  	wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); -	struct roots_view *view = view_create(); +	struct roots_view *view = view_create(desktop);  	if (!view) {  		free(roots_surface);  		return; @@ -342,22 +379,19 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {  	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; +	view->destroy = destroy;  	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); +	if (surface->toplevel->next.maximized) { +		view_maximize(view, true); +	} +	if (surface->toplevel->next.fullscreen) { +		view_set_fullscreen(view, true, NULL); +	}  } diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index eda349cb..001232ab 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -60,12 +60,14 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) {  	assert(view->type == ROOTS_XDG_SHELL_V6_VIEW);  	struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; -	if (surface->geometry->width > 0 && surface->geometry->height > 0) { -		box->width = surface->geometry->width; -		box->height = surface->geometry->height; -	} else { +	if (surface->geometry.width > 0 && surface->geometry.height > 0) { +		box->width = surface->geometry.width; +		box->height = surface->geometry.height; +	} else if (view->wlr_surface != NULL) {  		box->width = view->wlr_surface->current->width;  		box->height = view->wlr_surface->current->height; +	} else { +		box->width = box->height = 0;  	}  } @@ -83,7 +85,7 @@ static void apply_size_constraints(struct wlr_xdg_surface_v6 *surface,  	*dest_width = width;  	*dest_height = height; -	struct wlr_xdg_toplevel_v6_state *state = &surface->toplevel_state->current; +	struct wlr_xdg_toplevel_v6_state *state = &surface->toplevel->current;  	if (width < state->min_width) {  		*dest_width = state->min_width;  	} else if (state->max_width > 0 && @@ -175,9 +177,26 @@ static void set_fullscreen(struct roots_view *view, bool fullscreen) {  static void close(struct roots_view *view) {  	assert(view->type == ROOTS_XDG_SHELL_V6_VIEW);  	struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; -	if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { -		wlr_xdg_toplevel_v6_send_close(surface); +	struct wlr_xdg_popup_v6 *popup = NULL; +	wl_list_for_each(popup, &surface->popups, link) { +		wlr_xdg_surface_v6_send_close(popup->base);  	} +	wlr_xdg_surface_v6_send_close(surface); +} + +static void destroy(struct roots_view *view) { +	assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); +	struct roots_xdg_surface_v6 *roots_xdg_surface = view->roots_xdg_surface_v6; +	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->map.link); +	wl_list_remove(&roots_xdg_surface->unmap.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); +	free(roots_xdg_surface);  }  static void handle_request_move(struct wl_listener *listener, void *data) { @@ -219,7 +238,7 @@ static void handle_request_maximize(struct wl_listener *listener, void *data) {  		return;  	} -	view_maximize(view, surface->toplevel_state->next.maximized); +	view_maximize(view, surface->toplevel->next.maximized);  }  static void handle_request_fullscreen(struct wl_listener *listener, @@ -243,6 +262,10 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {  	struct roots_view *view = roots_surface->view;  	struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; +	if (!surface->mapped) { +		return; +	} +  	view_apply_damage(view);  	struct wlr_box size; @@ -277,20 +300,30 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {  	popup_create(roots_xdg_surface->view, wlr_popup);  } +static void handle_map(struct wl_listener *listener, void *data) { +	struct roots_xdg_surface_v6 *roots_xdg_surface = +		wl_container_of(listener, roots_xdg_surface, map); +	struct roots_view *view = roots_xdg_surface->view; + +	struct wlr_box box; +	get_size(view, &box); +	view->width = box.width; +	view->height = box.height; + +	view_map(view, view->xdg_surface_v6->surface); +	view_setup(view); +} + +static void handle_unmap(struct wl_listener *listener, void *data) { +	struct roots_xdg_surface_v6 *roots_xdg_surface = +		wl_container_of(listener, roots_xdg_surface, unmap); +	view_unmap(roots_xdg_surface->view); +} +  static void handle_destroy(struct wl_listener *listener, void *data) {  	struct roots_xdg_surface_v6 *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); +	view_destroy(roots_xdg_surface->view);  }  void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { @@ -319,6 +352,10 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {  		&roots_surface->surface_commit);  	roots_surface->destroy.notify = handle_destroy;  	wl_signal_add(&surface->events.destroy, &roots_surface->destroy); +	roots_surface->map.notify = handle_map; +	wl_signal_add(&surface->events.map, &roots_surface->map); +	roots_surface->unmap.notify = handle_unmap; +	wl_signal_add(&surface->events.unmap, &roots_surface->unmap);  	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; @@ -333,7 +370,7 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {  	roots_surface->new_popup.notify = handle_new_popup;  	wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); -	struct roots_view *view = view_create(); +	struct roots_view *view = view_create(desktop);  	if (!view) {  		free(roots_surface);  		return; @@ -342,22 +379,19 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {  	view->xdg_surface_v6 = surface;  	view->roots_xdg_surface_v6 = 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; +	view->destroy = destroy;  	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); +	if (surface->toplevel->next.maximized) { +		view_maximize(view, true); +	} +	if (surface->toplevel->next.fullscreen) { +		view_set_fullscreen(view, true, NULL); +	}  } diff --git a/rootston/xwayland.c b/rootston/xwayland.c index 56f068ea..53331b1f 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -106,11 +106,9 @@ static void set_fullscreen(struct roots_view *view, bool fullscreen) {  	wlr_xwayland_surface_set_fullscreen(view->xwayland_surface, fullscreen);  } -static void handle_destroy(struct wl_listener *listener, void *data) { -	struct roots_xwayland_surface *roots_surface = -		wl_container_of(listener, roots_surface, destroy); -	struct wlr_xwayland_surface *xwayland_surface = -		roots_surface->view->xwayland_surface; +static void destroy(struct roots_view *view) { +	assert(view->type == ROOTS_XWAYLAND_VIEW); +	struct roots_xwayland_surface *roots_surface = view->roots_xwayland_surface;  	wl_list_remove(&roots_surface->destroy.link);  	wl_list_remove(&roots_surface->request_configure.link);  	wl_list_remove(&roots_surface->request_move.link); @@ -118,14 +116,15 @@ static void handle_destroy(struct wl_listener *listener, void *data) {  	wl_list_remove(&roots_surface->request_maximize.link);  	wl_list_remove(&roots_surface->map_notify.link);  	wl_list_remove(&roots_surface->unmap_notify.link); -	if (xwayland_surface->mapped) { -		wl_list_remove(&roots_surface->view->link); -	} -	view_finish(roots_surface->view); -	free(roots_surface->view);  	free(roots_surface);  } +static void handle_destroy(struct wl_listener *listener, void *data) { +	struct roots_xwayland_surface *roots_surface = +		wl_container_of(listener, roots_surface, destroy); +	view_destroy(roots_surface->view); +} +  static void handle_request_configure(struct wl_listener *listener, void *data) {  	struct roots_xwayland_surface *roots_surface =  		wl_container_of(listener, roots_surface, request_configure); @@ -231,22 +230,13 @@ static void handle_map_notify(struct wl_listener *listener, void *data) {  		wl_container_of(listener, roots_surface, map_notify);  	struct wlr_xwayland_surface *xsurface = data;  	struct roots_view *view = roots_surface->view; -	struct roots_desktop *desktop = view->desktop; -	view->wlr_surface = xsurface->surface;  	view->x = xsurface->x;  	view->y = xsurface->y;  	view->width = xsurface->surface->current->width;  	view->height = xsurface->surface->current->height; -	wl_list_insert(&desktop->views, &view->link); -	struct wlr_subsurface *subsurface; -	wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list, -			parent_link) { -		subsurface_create(view, subsurface); -	} - -	view_damage_whole(view); +	view_map(view, xsurface->surface);  	roots_surface->surface_commit.notify = handle_surface_commit;  	wl_signal_add(&xsurface->surface->events.commit, @@ -260,22 +250,7 @@ static void handle_unmap_notify(struct wl_listener *listener, void *data) {  	wl_list_remove(&roots_surface->surface_commit.link); -	view_damage_whole(view); - -	struct roots_view_child *child, *tmp; -	wl_list_for_each_safe(child, tmp, &view->children, link) { -		child->destroy(child); -	} - -	if (view->fullscreen_output != NULL) { -		output_damage_whole(view->fullscreen_output); -		view->fullscreen_output->fullscreen_view = NULL; -		view->fullscreen_output = NULL; -	} - -	view->wlr_surface = NULL; -	view->width = view->height = 0; -	wl_list_remove(&view->link); +	view_unmap(view);  }  void handle_xwayland_surface(struct wl_listener *listener, void *data) { @@ -317,7 +292,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {  	wl_signal_add(&surface->surface->events.commit,  		&roots_surface->surface_commit); -	struct roots_view *view = view_create(); +	struct roots_view *view = view_create(desktop);  	if (view == NULL) {  		free(roots_surface);  		return; @@ -330,7 +305,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {  	view->xwayland_surface = surface;  	view->roots_xwayland_surface = roots_surface; -	view->wlr_surface = surface->surface;  	view->activate = activate;  	view->resize = resize;  	view->move = move; @@ -338,9 +312,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {  	view->maximize = maximize;  	view->set_fullscreen = set_fullscreen;  	view->close = close; +	view->destroy = destroy;  	roots_surface->view = view; -	view_init(view, desktop); -	wl_list_insert(&desktop->views, &view->link); + +	view_map(view, surface->surface);  	if (!surface->override_redirect) {  		if (surface->decorations == WLR_XWAYLAND_SURFACE_DECORATIONS_ALL) { diff --git a/types/meson.build b/types/meson.build index 703b06ca..94993b52 100644 --- a/types/meson.build +++ b/types/meson.build @@ -6,10 +6,13 @@ lib_wlr_types = static_library(  		'wlr_cursor.c',  		'wlr_data_device.c',  		'wlr_gamma_control.c', +		'wlr_idle_inhibit_v1.c',  		'wlr_idle.c',  		'wlr_input_device.c',  		'wlr_keyboard.c', +		'wlr_linux_dmabuf.c',  		'wlr_list.c', +		'wlr_matrix.c',  		'wlr_output_damage.c',  		'wlr_output_layout.c',  		'wlr_output.c', @@ -27,7 +30,6 @@ lib_wlr_types = static_library(  		'wlr_xcursor_manager.c',  		'wlr_xdg_shell_v6.c',  		'wlr_xdg_shell.c', -		'wlr_idle_inhibit_v1.c',  	),  	include_directories: wlr_inc,  	dependencies: [pixman, xkbcommon, wayland_server, wlr_protos], diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c new file mode 100644 index 00000000..a61d0ea5 --- /dev/null +++ b/types/wlr_linux_dmabuf.c @@ -0,0 +1,467 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> +#include <wayland-server.h> +#include <wlr/render/egl.h> +#include <wlr/types/wlr_linux_dmabuf.h> +#include <wlr/util/log.h> +#include "linux-dmabuf-unstable-v1-protocol.h" + +static void wl_buffer_destroy(struct wl_client *client, +		struct wl_resource *resource) { +	wl_resource_destroy(resource); +} + +static const struct wl_buffer_interface wl_buffer_impl = { +	wl_buffer_destroy, +}; + +bool wlr_dmabuf_buffer_has_inverted_y(struct wlr_dmabuf_buffer *dmabuf) { +	return dmabuf->attributes.flags +		& ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT; +} + +bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) { +	if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface, +		&wl_buffer_impl)) { +		return false; +	} + +	struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(buffer_resource); +	if (buffer && buffer->buffer_resource && !buffer->params_resource && +		buffer->buffer_resource == buffer_resource) { +		return true; +	} + +	return false; +} + +struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource( +		struct wl_resource *buffer_resource) { +	assert(wl_resource_instance_of(buffer_resource, &wl_buffer_interface, +			&wl_buffer_impl)); + +	struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(buffer_resource); +	assert(buffer); +	assert(buffer->buffer_resource); +	assert(!buffer->params_resource); +	assert(buffer->buffer_resource == buffer_resource); + +	return buffer; +} + +static void linux_dmabuf_buffer_destroy(struct wlr_dmabuf_buffer *buffer) { +	for (int i = 0; i < buffer->attributes.n_planes; i++) { +		close(buffer->attributes.fd[i]); +		buffer->attributes.fd[i] = -1; +	} +	buffer->attributes.n_planes = 0; +	free(buffer); +} + +static void params_destroy(struct wl_client *client, struct wl_resource *resource) { +	wl_resource_destroy(resource); +} + +static void params_add(struct wl_client *client, +		struct wl_resource *params_resource, int32_t name_fd, +		uint32_t plane_idx, uint32_t offset, uint32_t stride, +		uint32_t modifier_hi, uint32_t modifier_lo) { +	struct wlr_dmabuf_buffer *buffer = wlr_dmabuf_buffer_from_params_resource( +		params_resource); + +	if (!buffer) { +		wl_resource_post_error(params_resource, +			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, +			"params was already used to create a wl_buffer"); +		close(name_fd); +		return; +	} + +	if (plane_idx >= WLR_LINUX_DMABUF_MAX_PLANES) { +		wl_resource_post_error(params_resource, +			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX, +			"plane index %u > %u", plane_idx, WLR_LINUX_DMABUF_MAX_PLANES); +		close(name_fd); +		return; +	} + +	if (buffer->attributes.fd[plane_idx] != -1) { +		wl_resource_post_error(params_resource, +			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET, +			"a dmabuf with id %d has already been added for plane %u", +			buffer->attributes.fd[plane_idx], +			plane_idx); +		close(name_fd); +		return; +	} + +	buffer->attributes.fd[plane_idx] = name_fd; +	buffer->attributes.offset[plane_idx] = offset; +	buffer->attributes.stride[plane_idx] = stride; +	buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) | +		modifier_lo; +	buffer->attributes.n_planes++; +} + +static void handle_buffer_destroy(struct wl_resource *buffer_resource) +{ +	struct wlr_dmabuf_buffer *buffer = wlr_dmabuf_buffer_from_buffer_resource( +		buffer_resource); + +	linux_dmabuf_buffer_destroy(buffer); +} + +static void params_create_common(struct wl_client *client, +		struct wl_resource *params_resource, uint32_t buffer_id, int32_t width, +		int32_t height, uint32_t format, uint32_t flags) { +	if (!wl_resource_get_user_data(params_resource)) { +		wl_resource_post_error(params_resource, +			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, +			"params was already used to create a wl_buffer"); +		return; +	} +	struct wlr_dmabuf_buffer *buffer = wlr_dmabuf_buffer_from_params_resource( +		params_resource); + +	/* Switch the linux_dmabuf_buffer object from params resource to +	 * eventually wl_buffer resource. */ +	wl_resource_set_user_data(buffer->params_resource, NULL); +	buffer->params_resource = NULL; + +	if (!buffer->attributes.n_planes) { +		wl_resource_post_error(params_resource, +			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, +			"no dmabuf has been added to the params"); +		goto err_out; +	} + +	if (buffer->attributes.fd[0] == -1) { +		wl_resource_post_error(params_resource, +			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, +			"no dmabuf has been added for plane 0"); +		goto err_out; +	} + +	if ((buffer->attributes.fd[3] >= 0 || buffer->attributes.fd[2] >= 0) && +			(buffer->attributes.fd[2] == -1 || buffer->attributes.fd[1] == -1)) { +		wl_resource_post_error (params_resource, +			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, +			"gap in dmabuf planes"); +		goto err_out; +	} + +	buffer->attributes.width = width; +	buffer->attributes.height = height; +	buffer->attributes.format = format; +	buffer->attributes.flags = flags; + +	if (width < 1 || height < 1) { +		wl_resource_post_error(params_resource, +			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS, +			"invalid width %d or height %d", width, height); +		goto err_out; +	} + +	for (int i = 0; i < buffer->attributes.n_planes; i++) { +		if ((uint64_t)buffer->attributes.offset[i] +				+ buffer->attributes.stride[i] > UINT32_MAX) { +			wl_resource_post_error(params_resource, +				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, +				"size overflow for plane %d", i); +			goto err_out; +		} + +		if ((uint64_t)buffer->attributes.offset[i] +				+ (uint64_t)buffer->attributes.stride[i] * height > UINT32_MAX) { +			wl_resource_post_error(params_resource, +				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, +				"size overflow for plane %d", i); +			goto err_out; +		} + +		off_t size = lseek(buffer->attributes.fd[i], 0, SEEK_END); +		if (size == -1) { /* Skip checks if kernel does no support seek on buffer */ +			continue; +		} +		if (buffer->attributes.offset[i] >= size) { +			wl_resource_post_error(params_resource, +				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, +				"invalid offset %i for plane %d", +				buffer->attributes.offset[i], i); +			goto err_out; +		} + +		if (buffer->attributes.offset[i] + buffer->attributes.stride[i]	> size) { +			wl_resource_post_error(params_resource, +				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, +				"invalid stride %i for plane %d", +				buffer->attributes.stride[i], i); +			goto err_out; +		} + +		if (i == 0 && /* planes > 0 might be subsampled according to fourcc format */ +			buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) { +			wl_resource_post_error(params_resource, +				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, +				"invalid buffer stride or height for plane %d", i); +			goto err_out; +		} +	} + +	/* reject unknown flags */ +	if (buffer->attributes.flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT) { +		wl_resource_post_error(params_resource, +			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, +			"Unknown dmabuf flags %"PRIu32, buffer->attributes.flags); +		goto err_out; +	} + +	/* Check if dmabuf is usable */ +	if (!wlr_egl_check_import_dmabuf(buffer->egl, buffer)) { +		goto err_failed; +	} + +	buffer->buffer_resource = wl_resource_create(client, &wl_buffer_interface, +		1, buffer_id); +	if (!buffer->buffer_resource) { +		wl_resource_post_no_memory(params_resource); +		goto err_failed; +	} + +	wl_resource_set_implementation(buffer->buffer_resource, +		&wl_buffer_impl, buffer, handle_buffer_destroy); + +	/* send 'created' event when the request is not for an immediate +	 * import, that is buffer_id is zero */ +	if (buffer_id == 0) { +		zwp_linux_buffer_params_v1_send_created(params_resource, +			buffer->buffer_resource); +	} +	return; + +err_failed: +	if (buffer_id == 0) { +		zwp_linux_buffer_params_v1_send_failed(params_resource); +	} else { +		/* since the behavior is left implementation defined by the +		 * protocol in case of create_immed failure due to an unknown cause, +		 * we choose to treat it as a fatal error and immediately kill the +		 * client instead of creating an invalid handle and waiting for it +		 * to be used. +		 */ +		wl_resource_post_error(params_resource, +			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER, +			"importing the supplied dmabufs failed"); +	} +err_out: +	linux_dmabuf_buffer_destroy(buffer); +	return; +} + +static void params_create(struct wl_client *client, +		struct wl_resource *params_resource, +		int32_t width, int32_t height,uint32_t format, uint32_t flags) { +	params_create_common(client, params_resource, 0, width, height, format, flags); +} + +static void params_create_immed(struct wl_client *client, +		struct wl_resource *params_resource, uint32_t buffer_id, +		int32_t width, int32_t height,uint32_t format, uint32_t flags) { +	params_create_common(client, params_resource, buffer_id, width, height, format, flags); +} + +static const struct zwp_linux_buffer_params_v1_interface linux_buffer_params_impl = { +	params_destroy, +	params_add, +	params_create, +	params_create_immed, +}; + +struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource( +		struct wl_resource *params_resource) { +	assert(wl_resource_instance_of(params_resource, +		&zwp_linux_buffer_params_v1_interface, +		&linux_buffer_params_impl)); + +	struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(params_resource); +	assert(buffer); +	assert(buffer->params_resource); +	assert(!buffer->buffer_resource); +	assert(buffer->params_resource == params_resource); + +	return buffer; +} + +static void handle_params_destroy(struct wl_resource *params_resource) { +	/* Check for NULL since wlr_dmabuf_buffer_from_params_resource will choke */ +	if (!wl_resource_get_user_data(params_resource)) { +		return; +	} + +	struct wlr_dmabuf_buffer *buffer = +		wlr_dmabuf_buffer_from_params_resource(params_resource); +	linux_dmabuf_buffer_destroy(buffer); +} + +static void linux_dmabuf_create_params(struct wl_client *client, +		struct wl_resource *linux_dmabuf_resource, +		uint32_t params_id) { +	struct wlr_linux_dmabuf *linux_dmabuf = wlr_linux_dmabuf_from_resource( +		linux_dmabuf_resource); + +	uint32_t version = wl_resource_get_version(linux_dmabuf_resource); +	struct wlr_dmabuf_buffer *buffer = calloc(1, sizeof *buffer); +	if (!buffer) { +		goto err; +	} + +	for (int i = 0; i < WLR_LINUX_DMABUF_MAX_PLANES; i++) { +		buffer->attributes.fd[i] = -1; +	} + +	buffer->egl = linux_dmabuf->egl; +	buffer->params_resource = wl_resource_create(client, +		&zwp_linux_buffer_params_v1_interface, +		version, params_id); +	if (!buffer->params_resource) { +		goto err_free; +	} + +	wl_resource_set_implementation(buffer->params_resource, +		&linux_buffer_params_impl,buffer, handle_params_destroy); +	return; + +err_free: +	free(buffer); +err: +	wl_resource_post_no_memory(linux_dmabuf_resource); +} + +static void linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource) { +	wl_resource_destroy(resource); +} + +static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_impl = { +	linux_dmabuf_destroy, +	linux_dmabuf_create_params +}; + +struct wlr_linux_dmabuf *wlr_linux_dmabuf_from_resource( +		struct wl_resource *resource) { +	assert(wl_resource_instance_of(resource, &zwp_linux_dmabuf_v1_interface, +			&linux_dmabuf_impl)); + +	struct wlr_linux_dmabuf *dmabuf = wl_resource_get_user_data(resource); +	assert(dmabuf); +	return dmabuf; +} + +static void linux_dmabuf_send_modifiers(struct wlr_linux_dmabuf *linux_dmabuf, +		struct wl_resource *resource) { +	struct wlr_egl *egl = linux_dmabuf->egl; +	/* +	 * Use EGL_EXT_image_dma_buf_import_modifiers to query and advertise +	 * format/modifier codes. +	 */ +	uint64_t modifier_invalid = DRM_FORMAT_MOD_INVALID; +	int *formats = NULL; +	int num_formats = wlr_egl_get_dmabuf_formats(egl, &formats); + +	if (num_formats < 0) { +		return; +	} + +	for (int i = 0; i < num_formats; i++) { +		int num_modifiers; +		uint64_t *modifiers = NULL; + +		num_modifiers = wlr_egl_get_dmabuf_modifiers(egl, formats[i], +			&modifiers); +		if (num_modifiers < 0) { +			return; +		} +		/* send DRM_FORMAT_MOD_INVALID token when no modifiers are supported +		 * for this format */ +		if (num_modifiers == 0) { +			num_modifiers = 1; +			modifiers = &modifier_invalid; +		} +		for (int j = 0; j < num_modifiers; j++) { +			uint32_t modifier_lo = modifiers[j] & 0xFFFFFFFF; +			uint32_t modifier_hi = modifiers[j] >> 32; +			zwp_linux_dmabuf_v1_send_modifier(resource, formats[i], +				modifier_hi, +				modifier_lo); +		} +		if (modifiers != &modifier_invalid) { +			free(modifiers); +		} +	} +	free(formats); +} + +static void linux_dmabuf_bind(struct wl_client *client, +		void *data, uint32_t version, uint32_t id) { +	struct wlr_linux_dmabuf *linux_dmabuf = data; +	struct wl_resource *resource = wl_resource_create(client, +		  &zwp_linux_dmabuf_v1_interface, +		  version, id); + +	if (resource == NULL) { +		wl_client_post_no_memory(client); +		return; +	} + +	wl_resource_set_implementation(resource, &linux_dmabuf_impl, +		linux_dmabuf, NULL); +	if (version < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) { +                return; +	} + +	linux_dmabuf_send_modifiers(linux_dmabuf, resource); +} + +void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf) { +	if (!linux_dmabuf) { +		return; +	} +	wl_list_remove(&linux_dmabuf->display_destroy.link); + +	wl_global_destroy(linux_dmabuf->wl_global); +	free(linux_dmabuf); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { +	struct wlr_linux_dmabuf *linux_dmabuf = wl_container_of(listener, linux_dmabuf, display_destroy); +	wlr_linux_dmabuf_destroy(linux_dmabuf); +} + +struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display, +		struct wlr_egl *egl) { +	struct wlr_linux_dmabuf *linux_dmabuf = +		calloc(1, sizeof(struct wlr_linux_dmabuf)); +	if (linux_dmabuf == NULL) { +		wlr_log(L_ERROR, "could not create simple dmabuf manager"); +		return NULL; +	} + +	linux_dmabuf->display_destroy.notify = handle_display_destroy; +	wl_display_add_destroy_listener(display, &linux_dmabuf->display_destroy); + +	linux_dmabuf->wl_global = +		wl_global_create(display, &zwp_linux_dmabuf_v1_interface, +			3, linux_dmabuf, linux_dmabuf_bind); + +	linux_dmabuf->egl = egl; +	if (!linux_dmabuf->wl_global) { +		wlr_log(L_ERROR, "could not create linux dmabuf v1 wl global"); +		free(linux_dmabuf); +		return NULL; +	} + +	return linux_dmabuf; +} diff --git a/types/wlr_matrix.c b/types/wlr_matrix.c new file mode 100644 index 00000000..6eb47ca8 --- /dev/null +++ b/types/wlr_matrix.c @@ -0,0 +1,169 @@ +#include <math.h> +#include <string.h> +#include <wayland-server-protocol.h> +#include <wlr/types/wlr_matrix.h> +#include <wlr/types/wlr_box.h> +#include <wlr/types/wlr_output.h> + +void wlr_matrix_identity(float mat[static 9]) { +	static const float identity[9] = { +		1.0f, 0.0f, 0.0f, +		0.0f, 1.0f, 0.0f, +		0.0f, 0.0f, 1.0f, +	}; +	memcpy(mat, identity, sizeof(identity)); +} + +void wlr_matrix_multiply(float mat[static 9], const float a[static 9], +		const float b[static 9]) { +	float product[9]; + +	product[0] = a[0]*b[0] + a[1]*b[3] + a[2]*b[6]; +	product[1] = a[0]*b[1] + a[1]*b[4] + a[2]*b[7]; +	product[2] = a[0]*b[2] + a[1]*b[5] + a[2]*b[8]; + +	product[3] = a[3]*b[0] + a[4]*b[3] + a[5]*b[6]; +	product[4] = a[3]*b[1] + a[4]*b[4] + a[5]*b[7]; +	product[5] = a[3]*b[2] + a[4]*b[5] + a[5]*b[8]; + +	product[6] = a[6]*b[0] + a[7]*b[3] + a[8]*b[6]; +	product[7] = a[6]*b[1] + a[7]*b[4] + a[8]*b[7]; +	product[8] = a[6]*b[2] + a[7]*b[5] + a[8]*b[8]; + +	memcpy(mat, product, sizeof(product)); +} + +void wlr_matrix_transpose(float mat[static 9], const float a[static 9]) { +	float transposition[9] = { +		a[0], a[3], a[6], +		a[1], a[4], a[7], +		a[2], a[5], a[8], +	}; +	memcpy(mat, transposition, sizeof(transposition)); +} + +void wlr_matrix_translate(float mat[static 9], float x, float y) { +	float translate[9] = { +		1.0f, 0.0f, x, +		0.0f, 1.0f, y, +		0.0f, 0.0f, 1.0f, +	}; +	wlr_matrix_multiply(mat, mat, translate); +} + +void wlr_matrix_scale(float mat[static 9], float x, float y) { +	float scale[9] = { +		x,    0.0f, 0.0f, +		0.0f, y,    0.0f, +		0.0f, 0.0f, 1.0f, +	}; +	wlr_matrix_multiply(mat, mat, scale); +} + +void wlr_matrix_rotate(float mat[static 9], float rad) { +	float rotate[9] = { +		cos(rad), -sin(rad), 0.0f, +		sin(rad),  cos(rad), 0.0f, +		0.0f,      0.0f,     1.0f, +	}; +	wlr_matrix_multiply(mat, mat, rotate); +} + +static const float transforms[][9] = { +	[WL_OUTPUT_TRANSFORM_NORMAL] = { +		1.0f, 0.0f, 0.0f, +		0.0f, 1.0f, 0.0f, +		0.0f, 0.0f, 1.0f, +	}, +	[WL_OUTPUT_TRANSFORM_90] = { +		0.0f, -1.0f, 0.0f, +		1.0f, 0.0f, 0.0f, +		0.0f, 0.0f, 1.0f, +	}, +	[WL_OUTPUT_TRANSFORM_180] = { +		-1.0f, 0.0f, 0.0f, +		0.0f, -1.0f, 0.0f, +		0.0f, 0.0f, 1.0f, +	}, +	[WL_OUTPUT_TRANSFORM_270] = { +		0.0f, 1.0f, 0.0f, +		-1.0f, 0.0f, 0.0f, +		0.0f, 0.0f, 1.0f, +	}, +	[WL_OUTPUT_TRANSFORM_FLIPPED] = { +		-1.0f, 0.0f, 0.0f, +		0.0f, 1.0f, 0.0f, +		0.0f, 0.0f, 1.0f, +	}, +	[WL_OUTPUT_TRANSFORM_FLIPPED_90] = { +		0.0f, -1.0f, 0.0f, +		-1.0f, 0.0f, 0.0f, +		0.0f, 0.0f, 1.0f, +	}, +	[WL_OUTPUT_TRANSFORM_FLIPPED_180] = { +		1.0f, 0.0f, 0.0f, +		0.0f, -1.0f, 0.0f, +		0.0f, 0.0f, 1.0f, +	}, +	[WL_OUTPUT_TRANSFORM_FLIPPED_270] = { +		0.0f, 1.0f, 0.0f, +		1.0f, 0.0f, 0.0f, +		0.0f, 0.0f, 1.0f, +	}, +}; + +void wlr_matrix_transform(float mat[static 9], +		enum wl_output_transform transform) { +	wlr_matrix_multiply(mat, mat, transforms[transform]); +} + +// Equivilent to glOrtho(0, width, 0, height, 1, -1) with the transform applied +void wlr_matrix_projection(float mat[static 9], int width, int height, +		enum wl_output_transform transform) { +	memset(mat, 0, sizeof(*mat) * 9); + +	const float *t = transforms[transform]; +	float x = 2.0f / width; +	float y = 2.0f / height; + +	// Rotation + reflection +	mat[0] = x * t[0]; +	mat[1] = x * t[1]; +	mat[3] = y * -t[3]; +	mat[4] = y * -t[4]; + +	// Translation +	mat[2] = -copysign(1.0f, mat[0] + mat[1]); +	mat[5] = -copysign(1.0f, mat[3] + mat[4]); + +	// Identity +	mat[8] = 1.0f; +} + +void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box, +		enum wl_output_transform transform, float rotation, +		const float projection[static 9]) { +	int x = box->x; +	int y = box->y; +	int width = box->width; +	int height = box->height; + +	wlr_matrix_identity(mat); +	wlr_matrix_translate(mat, x, y); + +	if (rotation != 0) { +		wlr_matrix_translate(mat, width/2, height/2); +		wlr_matrix_rotate(mat, rotation); +		wlr_matrix_translate(mat, -width/2, -height/2); +	} + +	wlr_matrix_scale(mat, width, height); + +	if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { +		wlr_matrix_translate(mat, 0.5, 0.5); +		wlr_matrix_transform(mat, transform); +		wlr_matrix_translate(mat, -0.5, -0.5); +	} + +	wlr_matrix_multiply(mat, projection, mat); +} diff --git a/types/wlr_output.c b/types/wlr_output.c index 96c9d324..e30c3b78 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -6,8 +6,8 @@  #include <time.h>  #include <wayland-server.h>  #include <wlr/interfaces/wlr_output.h> -#include <wlr/render.h> -#include <wlr/render/matrix.h> +#include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/types/wlr_box.h>  #include <wlr/types/wlr_output.h>  #include <wlr/types/wlr_surface.h> @@ -139,8 +139,8 @@ void wlr_output_update_enabled(struct wlr_output *output, bool enabled) {  }  static void wlr_output_update_matrix(struct wlr_output *output) { -	wlr_matrix_texture(output->transform_matrix, output->width, output->height, -		output->transform); +	wlr_matrix_projection(output->transform_matrix, output->width, +		output->height, output->transform);  }  void wlr_output_enable(struct wlr_output *output, bool enable) { @@ -368,25 +368,25 @@ static void output_fullscreen_surface_render(struct wlr_output *output,  	assert(renderer);  	if (!wlr_surface_has_buffer(surface)) { -		wlr_renderer_clear(renderer, &(float[]){0, 0, 0, 0}); +		wlr_renderer_clear(renderer, (float[]){0, 0, 0, 0});  		return;  	}  	struct wlr_box box;  	output_fullscreen_surface_get_box(output, surface, &box); -	float matrix[16]; +	float matrix[9];  	enum wl_output_transform transform =  		wlr_output_transform_invert(surface->current->transform); -	wlr_matrix_project_box(&matrix, &box, transform, 0, -		&output->transform_matrix); +	wlr_matrix_project_box(matrix, &box, transform, 0, +		output->transform_matrix);  	int nrects;  	pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);  	for (int i = 0; i < nrects; ++i) {  		output_scissor(output, &rects[i]); -		wlr_renderer_clear(renderer, &(float[]){0, 0, 0, 0}); -		wlr_render_with_matrix(surface->renderer, surface->texture, &matrix, 1.0f); +		wlr_renderer_clear(renderer, (float[]){0, 0, 0, 0}); +		wlr_render_texture_with_matrix(surface->renderer, surface->texture, matrix, 1.0f);  	}  	wlr_renderer_scissor(renderer, NULL); @@ -435,15 +435,15 @@ static void output_cursor_render(struct wlr_output_cursor *cursor,  		goto surface_damage_finish;  	} -	float matrix[16]; -	wlr_matrix_project_box(&matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, -		&cursor->output->transform_matrix); +	float matrix[9]; +	wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, +		cursor->output->transform_matrix);  	int nrects;  	pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects);  	for (int i = 0; i < nrects; ++i) {  		output_scissor(cursor->output, &rects[i]); -		wlr_render_with_matrix(renderer, texture, &matrix, 1.0f); +		wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f);  	}  	wlr_renderer_scissor(renderer, NULL); @@ -669,6 +669,31 @@ static void output_cursor_reset(struct wlr_output_cursor *cursor) {  	}  } +static void output_cursor_update_visible(struct wlr_output_cursor *cursor) { +	struct wlr_box output_box; +	output_box.x = output_box.y = 0; +	wlr_output_transformed_resolution(cursor->output, &output_box.width, +		&output_box.height); + +	struct wlr_box cursor_box; +	output_cursor_get_box(cursor, &cursor_box); + +	struct wlr_box intersection; +	bool visible = +		wlr_box_intersection(&output_box, &cursor_box, &intersection); + +	if (cursor->surface != NULL) { +		if (cursor->visible && !visible) { +			wlr_surface_send_leave(cursor->surface, cursor->output); +		} +		if (!cursor->visible && visible) { +			wlr_surface_send_enter(cursor->surface, cursor->output); +		} +	} + +	cursor->visible = visible; +} +  bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,  		const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height,  		int32_t hotspot_x, int32_t hotspot_y) { @@ -682,6 +707,7 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,  	cursor->height = height;  	cursor->hotspot_x = hotspot_x;  	cursor->hotspot_y = hotspot_y; +	output_cursor_update_visible(cursor);  	struct wlr_output_cursor *hwcur = cursor->output->hardware_cursor;  	if (cursor->output->impl->set_cursor && (hwcur == NULL || hwcur == cursor)) { @@ -716,31 +742,6 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,  		stride, width, height, pixels);  } -static void output_cursor_update_visible(struct wlr_output_cursor *cursor) { -	struct wlr_box output_box; -	output_box.x = output_box.y = 0; -	wlr_output_transformed_resolution(cursor->output, &output_box.width, -		&output_box.height); - -	struct wlr_box cursor_box; -	output_cursor_get_box(cursor, &cursor_box); - -	struct wlr_box intersection; -	bool visible = -		wlr_box_intersection(&output_box, &cursor_box, &intersection); - -	if (cursor->surface != NULL) { -		if (cursor->visible && !visible) { -			wlr_surface_send_leave(cursor->surface, cursor->output); -		} -		if (!cursor->visible && visible) { -			wlr_surface_send_enter(cursor->surface, cursor->output); -		} -	} - -	cursor->visible = visible; -} -  static void output_cursor_commit(struct wlr_output_cursor *cursor) {  	if (cursor->output->hardware_cursor != cursor) {  		output_cursor_damage_whole(cursor); @@ -846,12 +847,18 @@ bool wlr_output_cursor_move(struct wlr_output_cursor *cursor,  		output_cursor_damage_whole(cursor);  	} +	bool was_visible = cursor->visible;  	x *= cursor->output->scale;  	y *= cursor->output->scale;  	cursor->x = x;  	cursor->y = y;  	output_cursor_update_visible(cursor); +	if (!was_visible && !cursor->visible) { +		// Cursor is still hidden, do nothing +		return true; +	} +  	if (cursor->output->hardware_cursor != cursor) {  		output_cursor_damage_whole(cursor);  		return true; @@ -876,6 +883,7 @@ struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output) {  	wl_list_init(&cursor->surface_destroy.link);  	cursor->surface_destroy.notify = output_cursor_handle_destroy;  	wl_list_insert(&output->cursors, &cursor->link); +	cursor->visible = true; // default position is at (0, 0)  	return cursor;  } diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index c305f04d..2462bdd2 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -48,6 +48,7 @@ struct wlr_output_layout *wlr_output_layout_create() {  static void wlr_output_layout_output_destroy(  		struct wlr_output_layout_output *l_output) {  	wlr_signal_emit_safe(&l_output->events.destroy, l_output); +	wlr_output_destroy_global(l_output->output);  	wl_list_remove(&l_output->state->mode.link);  	wl_list_remove(&l_output->state->scale.link);  	wl_list_remove(&l_output->state->transform.link); @@ -64,7 +65,7 @@ void wlr_output_layout_destroy(struct wlr_output_layout *layout) {  	wlr_signal_emit_safe(&layout->events.destroy, layout); -	struct wlr_output_layout_output *l_output, *temp = NULL; +	struct wlr_output_layout_output *l_output, *temp;  	wl_list_for_each_safe(l_output, temp, &layout->outputs, link) {  		wlr_output_layout_output_destroy(l_output);  	} @@ -291,7 +292,6 @@ void wlr_output_layout_remove(struct wlr_output_layout *layout,  		wlr_output_layout_output_destroy(l_output);  		wlr_output_layout_reconfigure(layout);  	} -	wlr_output_destroy_global(output);  }  void wlr_output_layout_output_coords(struct wlr_output_layout *layout, diff --git a/types/wlr_pointer.c b/types/wlr_pointer.c index bc9efd8c..9d5dc08c 100644 --- a/types/wlr_pointer.c +++ b/types/wlr_pointer.c @@ -14,7 +14,10 @@ void wlr_pointer_init(struct wlr_pointer *pointer,  }  void wlr_pointer_destroy(struct wlr_pointer *pointer) { -	if (pointer && pointer->impl && pointer->impl->destroy) { +	if (!pointer) { +		return; +	} +	if (pointer->impl && pointer->impl->destroy) {  		pointer->impl->destroy(pointer);  	} else {  		wl_list_remove(&pointer->events.motion.listener_list); diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index e756b6aa..e1386be6 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -3,7 +3,7 @@  #include <string.h>  #include <wayland-server.h>  #include <wlr/backend.h> -#include <wlr/render.h> +#include <wlr/render/wlr_renderer.h>  #include <wlr/types/wlr_output.h>  #include <wlr/types/wlr_screenshooter.h>  #include <wlr/util/log.h> diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 23966cd1..e700853a 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -3,7 +3,7 @@  #include <wayland-server.h>  #include <wlr/render/egl.h>  #include <wlr/render/interface.h> -#include <wlr/render/matrix.h> +#include <wlr/types/wlr_matrix.h>  #include <wlr/types/wlr_region.h>  #include <wlr/types/wlr_surface.h>  #include <wlr/util/log.h> @@ -325,6 +325,9 @@ static void wlr_surface_apply_damage(struct wlr_surface *surface,  					surface->current->buffer)) {  			wlr_texture_upload_drm(surface->texture, surface->current->buffer);  			goto release; +		} else if (wlr_dmabuf_resource_is_buffer(surface->current->buffer)) { +			wlr_texture_upload_dmabuf(surface->texture, surface->current->buffer); +			goto release;  		} else {  			wlr_log(L_INFO, "Unknown buffer handle attached");  			return; @@ -624,22 +627,6 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res,  	return surface;  } -void wlr_surface_get_matrix(struct wlr_surface *surface, -		float (*matrix)[16], -		const float (*projection)[16], -		const float (*transform)[16]) { -	int width = surface->texture->width; -	int height = surface->texture->height; -	float scale[16]; -	wlr_matrix_identity(matrix); -	if (transform) { -		wlr_matrix_mul(matrix, transform, matrix); -	} -	wlr_matrix_scale(&scale, width, height, 1); -	wlr_matrix_mul(matrix, &scale, matrix); -	wlr_matrix_mul(projection, matrix, matrix); -} -  bool wlr_surface_has_buffer(struct wlr_surface *surface) {  	return surface->texture && surface->texture->valid;  } diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 990926cf..cf713eb9 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -34,7 +34,7 @@ struct wlr_xdg_positioner {  }; -static void resource_destroy(struct wl_client *client, +static void resource_handle_destroy(struct wl_client *client,  		struct wl_resource *resource) {  	wl_resource_destroy(resource);  } @@ -131,6 +131,24 @@ static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = {  	.cancel = xdg_keyboard_grab_cancel,  }; +static void xdg_surface_destroy(struct wlr_xdg_surface *surface); + +static void wlr_xdg_popup_grab_handle_seat_destroy( +		struct wl_listener *listener, void *data) { +	struct wlr_xdg_popup_grab *xdg_grab = +		wl_container_of(listener, xdg_grab, seat_destroy); + +	wl_list_remove(&xdg_grab->seat_destroy.link); + +	struct wlr_xdg_popup *popup, *next; +	wl_list_for_each_safe(popup, next, &xdg_grab->popups, grab_link) { +		xdg_surface_destroy(popup->base); +	} + +	wl_list_remove(&xdg_grab->link); +	free(xdg_grab); +} +  static struct wlr_xdg_popup_grab *xdg_shell_popup_grab_from_seat(  		struct wlr_xdg_shell *shell, struct wlr_seat *seat) {  	struct wlr_xdg_popup_grab *xdg_grab; @@ -155,47 +173,46 @@ static struct wlr_xdg_popup_grab *xdg_shell_popup_grab_from_seat(  	wl_list_insert(&shell->popup_grabs, &xdg_grab->link);  	xdg_grab->seat = seat; +	xdg_grab->seat_destroy.notify = wlr_xdg_popup_grab_handle_seat_destroy; +	wl_signal_add(&seat->events.destroy, &xdg_grab->seat_destroy); +  	return xdg_grab;  } -static void xdg_surface_destroy(struct wlr_xdg_surface *surface) { -	// TODO: probably need to ungrab before this event -	wlr_signal_emit_safe(&surface->events.destroy, surface); - -	if (surface->configure_idle) { -		wl_event_source_remove(surface->configure_idle); +static void xdg_surface_configure_destroy( +		struct wlr_xdg_surface_configure *configure) { +	if (configure == NULL) { +		return;  	} +	wl_list_remove(&configure->link); +	free(configure->toplevel_state); +	free(configure); +} -	struct wlr_xdg_surface_configure *configure, *tmp; -	wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { -		free(configure); +static void xdg_surface_unmap(struct wlr_xdg_surface *surface) { +	assert(surface->role != WLR_XDG_SURFACE_ROLE_NONE); + +	// TODO: probably need to ungrab before this event +	if (surface->mapped) { +		wlr_signal_emit_safe(&surface->events.unmap, surface);  	}  	if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { -		wl_resource_set_user_data(surface->toplevel_state->resource, NULL); -		free(surface->toplevel_state); +		wl_resource_set_user_data(surface->toplevel->resource, NULL); +		free(surface->toplevel); +		surface->toplevel = NULL;  	}  	if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { -		wl_resource_set_user_data(surface->popup_state->resource, NULL); +		wl_resource_set_user_data(surface->popup->resource, NULL); -		if (surface->popup_state->seat) { +		if (surface->popup->seat) {  			struct wlr_xdg_popup_grab *grab =  				xdg_shell_popup_grab_from_seat(surface->client->shell, -					surface->popup_state->seat); +					surface->popup->seat); -			struct wlr_xdg_surface *topmost = -				xdg_popup_grab_get_topmost(grab); - -			if (topmost != surface) { -				wl_resource_post_error(surface->client->resource, -						XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, -						"xdg_popup was destroyed while it was not the topmost " -						"popup."); -			} - -			wl_list_remove(&surface->popup_state->grab_link); +			wl_list_remove(&surface->popup->grab_link);  			if (wl_list_empty(&grab->popups)) {  				if (grab->seat->pointer_state.grab == &grab->pointer_grab) { @@ -207,18 +224,46 @@ static void xdg_surface_destroy(struct wlr_xdg_surface *surface) {  			}  		} -		wl_list_remove(&surface->popup_state->link); -		free(surface->popup_state); +		wl_list_remove(&surface->popup->link); +		free(surface->popup); +		surface->popup = NULL; +	} + +	struct wlr_xdg_surface_configure *configure, *tmp; +	wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { +		xdg_surface_configure_destroy(configure); +	} + +	surface->role = WLR_XDG_SURFACE_ROLE_NONE; +	free(surface->title); +	surface->title = NULL; +	free(surface->app_id); +	surface->app_id = NULL; + +	surface->added = surface->configured = surface->mapped = false; +	surface->configure_serial = 0; +	if (surface->configure_idle) { +		wl_event_source_remove(surface->configure_idle); +		surface->configure_idle = NULL;  	} +	surface->configure_next_serial = 0; + +	surface->has_next_geometry = false; +	memset(&surface->geometry, 0, sizeof(struct wlr_box)); +	memset(&surface->next_geometry, 0, sizeof(struct wlr_box)); +} + +static void xdg_surface_destroy(struct wlr_xdg_surface *surface) { +	if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) { +		xdg_surface_unmap(surface); +	} + +	wlr_signal_emit_safe(&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);  	wlr_surface_set_role_committed(surface->surface, NULL, NULL); -	free(surface->geometry); -	free(surface->next_geometry); -	free(surface->title); -	free(surface->app_id);  	free(surface);  } @@ -238,7 +283,7 @@ static void xdg_positioner_destroy(struct wl_resource *resource) {  	free(positioner);  } -static void xdg_positioner_protocol_set_size(struct wl_client *client, +static void xdg_positioner_handle_set_size(struct wl_client *client,  		struct wl_resource *resource, int32_t width, int32_t height) {  	struct wlr_xdg_positioner *positioner =  		xdg_positioner_from_resource(resource); @@ -254,7 +299,7 @@ static void xdg_positioner_protocol_set_size(struct wl_client *client,  	positioner->size.height = height;  } -static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, +static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client,  		struct wl_resource *resource, int32_t x, int32_t y, int32_t width,  		int32_t height) {  	struct wlr_xdg_positioner *positioner = @@ -273,7 +318,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client,  	positioner->anchor_rect.height = height;  } -static void xdg_positioner_protocol_set_anchor(struct wl_client *client, +static void xdg_positioner_handle_set_anchor(struct wl_client *client,  		struct wl_resource *resource, uint32_t anchor) {  	struct wlr_xdg_positioner *positioner =  		xdg_positioner_from_resource(resource); @@ -288,7 +333,7 @@ static void xdg_positioner_protocol_set_anchor(struct wl_client *client,  	positioner->anchor = anchor;  } -static void xdg_positioner_protocol_set_gravity(struct wl_client *client, +static void xdg_positioner_handle_set_gravity(struct wl_client *client,  		struct wl_resource *resource, uint32_t gravity) {  	struct wlr_xdg_positioner *positioner =  		xdg_positioner_from_resource(resource); @@ -303,7 +348,7 @@ static void xdg_positioner_protocol_set_gravity(struct wl_client *client,  	positioner->gravity = gravity;  } -static void xdg_positioner_protocol_set_constraint_adjustment( +static void xdg_positioner_handle_set_constraint_adjustment(  		struct wl_client *client, struct wl_resource *resource,  		uint32_t constraint_adjustment) {  	struct wlr_xdg_positioner *positioner = @@ -312,7 +357,7 @@ static void xdg_positioner_protocol_set_constraint_adjustment(  	positioner->constraint_adjustment = constraint_adjustment;  } -static void xdg_positioner_protocol_set_offset(struct wl_client *client, +static void xdg_positioner_handle_set_offset(struct wl_client *client,  		struct wl_resource *resource, int32_t x, int32_t y) {  	struct wlr_xdg_positioner *positioner =  		xdg_positioner_from_resource(resource); @@ -323,17 +368,17 @@ static void xdg_positioner_protocol_set_offset(struct wl_client *client,  static const struct xdg_positioner_interface  		xdg_positioner_implementation = { -	.destroy = resource_destroy, -	.set_size = xdg_positioner_protocol_set_size, -	.set_anchor_rect = xdg_positioner_protocol_set_anchor_rect, -	.set_anchor = xdg_positioner_protocol_set_anchor, -	.set_gravity = xdg_positioner_protocol_set_gravity, +	.destroy = resource_handle_destroy, +	.set_size = xdg_positioner_handle_set_size, +	.set_anchor_rect = xdg_positioner_handle_set_anchor_rect, +	.set_anchor = xdg_positioner_handle_set_anchor, +	.set_gravity = xdg_positioner_handle_set_gravity,  	.set_constraint_adjustment = -		xdg_positioner_protocol_set_constraint_adjustment, -	.set_offset = xdg_positioner_protocol_set_offset, +		xdg_positioner_handle_set_constraint_adjustment, +	.set_offset = xdg_positioner_handle_set_offset,  }; -static void xdg_shell_create_positioner(struct wl_client *wl_client, +static void xdg_shell_handle_create_positioner(struct wl_client *wl_client,  		struct wl_resource *resource, uint32_t id) {  	struct wlr_xdg_positioner *positioner =  		calloc(1, sizeof(struct wlr_xdg_positioner)); @@ -458,7 +503,7 @@ static struct wlr_xdg_surface *xdg_surface_from_xdg_popup_resource(  	return wl_resource_get_user_data(resource);  } -static void xdg_popup_protocol_grab(struct wl_client *client, +static void xdg_popup_handle_grab(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *seat_resource,  		uint32_t serial) {  	struct wlr_xdg_surface *surface = @@ -466,8 +511,8 @@ static void xdg_popup_protocol_grab(struct wl_client *client,  	struct wlr_seat_client *seat_client =  		wlr_seat_client_from_resource(seat_resource); -	if (surface->popup_state->committed) { -		wl_resource_post_error(surface->popup_state->resource, +	if (surface->popup->committed) { +		wl_resource_post_error(surface->popup->resource,  			XDG_POPUP_ERROR_INVALID_GRAB,  			"xdg_popup is already mapped");  		return; @@ -479,10 +524,10 @@ static void xdg_popup_protocol_grab(struct wl_client *client,  	struct wlr_xdg_surface *topmost = xdg_popup_grab_get_topmost(popup_grab);  	bool parent_is_toplevel = -		surface->popup_state->parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL; +		surface->popup->parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL;  	if ((topmost == NULL && !parent_is_toplevel) || -			(topmost != NULL && topmost != surface->popup_state->parent)) { +			(topmost != NULL && topmost != surface->popup->parent)) {  		wl_resource_post_error(surface->client->resource,  			XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,  			"xdg_popup was not created on the topmost popup"); @@ -490,9 +535,9 @@ static void xdg_popup_protocol_grab(struct wl_client *client,  	}  	popup_grab->client = surface->client->client; -	surface->popup_state->seat = seat_client->seat; +	surface->popup->seat = seat_client->seat; -	wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); +	wl_list_insert(&popup_grab->popups, &surface->popup->grab_link);  	wlr_seat_pointer_start_grab(seat_client->seat,  		&popup_grab->pointer_grab); @@ -500,16 +545,36 @@ static void xdg_popup_protocol_grab(struct wl_client *client,  		&popup_grab->keyboard_grab);  } +static void xdg_popup_handle_destroy(struct wl_client *client, +		struct wl_resource *resource) { +	struct wlr_xdg_surface *surface = +		xdg_surface_from_xdg_popup_resource(resource); +	struct wlr_xdg_popup_grab *grab = +		xdg_shell_popup_grab_from_seat(surface->client->shell, +			surface->popup->seat); +	struct wlr_xdg_surface *topmost = +		xdg_popup_grab_get_topmost(grab); + +	if (topmost != surface) { +		wl_resource_post_error(surface->client->resource, +			XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, +			"xdg_popup was destroyed while it was not the topmost popup"); +		return; +	} + +	wl_resource_destroy(resource); +} +  static const struct xdg_popup_interface xdg_popup_implementation = { -	.destroy = resource_destroy, -	.grab = xdg_popup_protocol_grab, +	.destroy = xdg_popup_handle_destroy, +	.grab = xdg_popup_handle_grab,  };  static void xdg_popup_resource_destroy(struct wl_resource *resource) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_popup_resource(resource);  	if (surface != NULL) { -		xdg_surface_destroy(surface); +		xdg_surface_unmap(surface);  	}  } @@ -522,7 +587,7 @@ static struct wlr_xdg_surface *xdg_surface_from_resource(  	return wl_resource_get_user_data(resource);  } -static void xdg_surface_get_popup(struct wl_client *client, +static void xdg_surface_handle_get_popup(struct wl_client *client,  		struct wl_resource *resource, uint32_t id,  		struct wl_resource *parent_resource,  		struct wl_resource *positioner_resource) { @@ -545,33 +610,33 @@ static void xdg_surface_get_popup(struct wl_client *client,  		return;  	} -	surface->popup_state = calloc(1, sizeof(struct wlr_xdg_popup)); -	if (!surface->popup_state) { +	surface->popup = calloc(1, sizeof(struct wlr_xdg_popup)); +	if (!surface->popup) {  		wl_resource_post_no_memory(resource);  		return;  	} -	surface->popup_state->resource = +	surface->popup->resource =  		wl_resource_create(client, &xdg_popup_interface,  			wl_resource_get_version(resource), id); -	if (surface->popup_state->resource == NULL) { -		free(surface->popup_state); +	if (surface->popup->resource == NULL) { +		free(surface->popup);  		wl_resource_post_no_memory(resource);  		return;  	}  	surface->role = WLR_XDG_SURFACE_ROLE_POPUP; -	surface->popup_state->base = surface; -	surface->popup_state->parent = parent; -	surface->popup_state->geometry = +	surface->popup->base = surface; +	surface->popup->parent = parent; +	surface->popup->geometry =  		xdg_positioner_get_geometry(positioner, surface, parent); -	wl_list_insert(&parent->popups, &surface->popup_state->link); +	wl_list_insert(&parent->popups, &surface->popup->link); -	wl_resource_set_implementation(surface->popup_state->resource, +	wl_resource_set_implementation(surface->popup->resource,  		&xdg_popup_implementation, surface,  		xdg_popup_resource_destroy); -	wlr_signal_emit_safe(&parent->events.new_popup, surface->popup_state); +	wlr_signal_emit_safe(&parent->events.new_popup, surface->popup);  } @@ -584,7 +649,7 @@ static struct wlr_xdg_surface *xdg_surface_from_xdg_toplevel_resource(  	return wl_resource_get_user_data(resource);  } -static void xdg_toplevel_protocol_set_parent(struct wl_client *client, +static void xdg_toplevel_handle_set_parent(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *parent_resource) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); @@ -594,10 +659,10 @@ static void xdg_toplevel_protocol_set_parent(struct wl_client *client,  		parent = xdg_surface_from_xdg_toplevel_resource(parent_resource);  	} -	surface->toplevel_state->parent = parent; +	surface->toplevel->parent = parent;  } -static void xdg_toplevel_protocol_set_title(struct wl_client *client, +static void xdg_toplevel_handle_set_title(struct wl_client *client,  		struct wl_resource *resource, const char *title) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); @@ -612,7 +677,7 @@ static void xdg_toplevel_protocol_set_title(struct wl_client *client,  	surface->title = tmp;  } -static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, +static void xdg_toplevel_handle_set_app_id(struct wl_client *client,  		struct wl_resource *resource, const char *app_id) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); @@ -627,7 +692,7 @@ static void xdg_toplevel_protocol_set_app_id(struct wl_client *client,  	surface->app_id = tmp;  } -static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, +static void xdg_toplevel_handle_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 *surface = @@ -636,7 +701,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client,  		wlr_seat_client_from_resource(seat_resource);  	if (!surface->configured) { -		wl_resource_post_error(surface->toplevel_state->resource, +		wl_resource_post_error(surface->toplevel->resource,  			XDG_SURFACE_ERROR_NOT_CONSTRUCTED,  			"surface has not been configured yet");  		return; @@ -658,7 +723,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client,  	wlr_signal_emit_safe(&surface->events.request_show_window_menu, &event);  } -static void xdg_toplevel_protocol_move(struct wl_client *client, +static void xdg_toplevel_handle_move(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *seat_resource,  		uint32_t serial) {  	struct wlr_xdg_surface *surface = @@ -667,7 +732,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client,  		wlr_seat_client_from_resource(seat_resource);  	if (!surface->configured) { -		wl_resource_post_error(surface->toplevel_state->resource, +		wl_resource_post_error(surface->toplevel->resource,  			XDG_SURFACE_ERROR_NOT_CONSTRUCTED,  			"surface has not been configured yet");  		return; @@ -687,7 +752,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client,  	wlr_signal_emit_safe(&surface->events.request_move, &event);  } -static void xdg_toplevel_protocol_resize(struct wl_client *client, +static void xdg_toplevel_handle_resize(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *seat_resource,  		uint32_t serial, uint32_t edges) {  	struct wlr_xdg_surface *surface = @@ -696,7 +761,7 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client,  		wlr_seat_client_from_resource(seat_resource);  	if (!surface->configured) { -		wl_resource_post_error(surface->toplevel_state->resource, +		wl_resource_post_error(surface->toplevel->resource,  			XDG_SURFACE_ERROR_NOT_CONSTRUCTED,  			"surface has not been configured yet");  		return; @@ -717,39 +782,39 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client,  	wlr_signal_emit_safe(&surface->events.request_resize, &event);  } -static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, +static void xdg_toplevel_handle_set_max_size(struct wl_client *client,  		struct wl_resource *resource, int32_t width, int32_t height) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); -	surface->toplevel_state->next.max_width = width; -	surface->toplevel_state->next.max_height = height; +	surface->toplevel->next.max_width = width; +	surface->toplevel->next.max_height = height;  } -static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, +static void xdg_toplevel_handle_set_min_size(struct wl_client *client,  		struct wl_resource *resource, int32_t width, int32_t height) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); -	surface->toplevel_state->next.min_width = width; -	surface->toplevel_state->next.min_height = height; +	surface->toplevel->next.min_width = width; +	surface->toplevel->next.min_height = height;  } -static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, +static void xdg_toplevel_handle_set_maximized(struct wl_client *client,  		struct wl_resource *resource) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); -	surface->toplevel_state->next.maximized = true; +	surface->toplevel->next.maximized = true;  	wlr_signal_emit_safe(&surface->events.request_maximize, surface);  } -static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, +static void xdg_toplevel_handle_unset_maximized(struct wl_client *client,  		struct wl_resource *resource) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); -	surface->toplevel_state->next.maximized = false; +	surface->toplevel->next.maximized = false;  	wlr_signal_emit_safe(&surface->events.request_maximize, surface);  } -static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, +static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *output_resource) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); @@ -759,7 +824,7 @@ static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client,  		output = wlr_output_from_resource(output_resource);  	} -	surface->toplevel_state->next.fullscreen = true; +	surface->toplevel->next.fullscreen = true;  	struct wlr_xdg_toplevel_set_fullscreen_event event = {  		.surface = surface, @@ -770,12 +835,12 @@ static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client,  	wlr_signal_emit_safe(&surface->events.request_fullscreen, &event);  } -static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, +static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client,  		struct wl_resource *resource) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); -	surface->toplevel_state->next.fullscreen = false; +	surface->toplevel->next.fullscreen = false;  	struct wlr_xdg_toplevel_set_fullscreen_event event = {  		.surface = surface, @@ -786,7 +851,7 @@ static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client,  	wlr_signal_emit_safe(&surface->events.request_fullscreen, &event);  } -static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, +static void xdg_toplevel_handle_set_minimized(struct wl_client *client,  		struct wl_resource *resource) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); @@ -794,20 +859,20 @@ static void xdg_toplevel_protocol_set_minimized(struct wl_client *client,  }  static const struct xdg_toplevel_interface xdg_toplevel_implementation = { -	.destroy = resource_destroy, -	.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 +	.destroy = resource_handle_destroy, +	.set_parent = xdg_toplevel_handle_set_parent, +	.set_title = xdg_toplevel_handle_set_title, +	.set_app_id = xdg_toplevel_handle_set_app_id, +	.show_window_menu = xdg_toplevel_handle_show_window_menu, +	.move = xdg_toplevel_handle_move, +	.resize = xdg_toplevel_handle_resize, +	.set_max_size = xdg_toplevel_handle_set_max_size, +	.set_min_size = xdg_toplevel_handle_set_min_size, +	.set_maximized = xdg_toplevel_handle_set_maximized, +	.unset_maximized = xdg_toplevel_handle_unset_maximized, +	.set_fullscreen = xdg_toplevel_handle_set_fullscreen, +	.unset_fullscreen = xdg_toplevel_handle_unset_fullscreen, +	.set_minimized = xdg_toplevel_handle_set_minimized,  };  static void xdg_surface_resource_destroy(struct wl_resource *resource) { @@ -822,11 +887,11 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) {  	struct wlr_xdg_surface *surface =  		xdg_surface_from_xdg_toplevel_resource(resource);  	if (surface != NULL) { -		xdg_surface_destroy(surface); +		xdg_surface_unmap(surface);  	}  } -static void xdg_surface_get_toplevel(struct wl_client *client, +static void xdg_surface_handle_get_toplevel(struct wl_client *client,  		struct wl_resource *resource, uint32_t id) {  	struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); @@ -835,24 +900,24 @@ static void xdg_surface_get_toplevel(struct wl_client *client,  		return;  	} -	surface->toplevel_state = calloc(1, sizeof(struct wlr_xdg_toplevel)); -	if (surface->toplevel_state == NULL) { +	surface->toplevel = calloc(1, sizeof(struct wlr_xdg_toplevel)); +	if (surface->toplevel == NULL) {  		wl_resource_post_no_memory(resource);  		return;  	}  	surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL; -	surface->toplevel_state->base = surface; +	surface->toplevel->base = surface;  	struct wl_resource *toplevel_resource = wl_resource_create(client,  		&xdg_toplevel_interface, wl_resource_get_version(resource), id);  	if (toplevel_resource == NULL) { -		free(surface->toplevel_state); +		free(surface->toplevel);  		wl_resource_post_no_memory(resource);  		return;  	} -	surface->toplevel_state->resource = toplevel_resource; +	surface->toplevel->resource = toplevel_resource;  	wl_resource_set_implementation(toplevel_resource,  		&xdg_toplevel_implementation, surface, @@ -863,12 +928,19 @@ static void wlr_xdg_toplevel_ack_configure(  		struct wlr_xdg_surface *surface,  		struct wlr_xdg_surface_configure *configure) {  	assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); -	surface->toplevel_state->next = configure->state; -	surface->toplevel_state->pending.width = 0; -	surface->toplevel_state->pending.height = 0; +	assert(configure->toplevel_state != NULL); + +	surface->toplevel->current.maximized = +		configure->toplevel_state->maximized; +	surface->toplevel->current.fullscreen = +		configure->toplevel_state->fullscreen; +	surface->toplevel->current.resizing = +		configure->toplevel_state->resizing; +	surface->toplevel->current.activated = +		configure->toplevel_state->activated;  } -static void xdg_surface_ack_configure(struct wl_client *client, +static void xdg_surface_handle_ack_configure(struct wl_client *client,  		struct wl_resource *resource, uint32_t serial) {  	struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); @@ -883,10 +955,8 @@ static void xdg_surface_ack_configure(struct wl_client *client,  	struct wlr_xdg_surface_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); +			xdg_surface_configure_destroy(configure);  		} else if (configure->serial == serial) { -			wl_list_remove(&configure->link);  			found = true;  			break;  		} else { @@ -914,10 +984,10 @@ static void xdg_surface_ack_configure(struct wl_client *client,  	surface->configured = true;  	surface->configure_serial = serial; -	free(configure); +	xdg_surface_configure_destroy(configure);  } -static void xdg_surface_set_window_geometry(struct wl_client *client, +static void xdg_surface_handle_set_window_geometry(struct wl_client *client,  		struct wl_resource *resource, int32_t x, int32_t y, int32_t width,  		int32_t height) {  	struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); @@ -930,19 +1000,31 @@ static void xdg_surface_set_window_geometry(struct wl_client *client,  	}  	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; +	surface->next_geometry.height = height; +	surface->next_geometry.width = width; +	surface->next_geometry.x = x; +	surface->next_geometry.y = y; +} +static void xdg_surface_handle_destroy(struct wl_client *client, +		struct wl_resource *resource) { +	struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); + +	if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) { +		wlr_log(L_ERROR, "Tried to destroy an xdg_surface before its role " +			"object"); +		return; +	} + +	wl_resource_destroy(resource);  }  static const struct xdg_surface_interface xdg_surface_implementation = { -	.destroy = resource_destroy, -	.get_toplevel = xdg_surface_get_toplevel, -	.get_popup = xdg_surface_get_popup, -	.ack_configure = xdg_surface_ack_configure, -	.set_window_geometry = xdg_surface_set_window_geometry, +	.destroy = xdg_surface_handle_destroy, +	.get_toplevel = xdg_surface_handle_get_toplevel, +	.get_popup = xdg_surface_handle_get_popup, +	.ack_configure = xdg_surface_handle_ack_configure, +	.set_window_geometry = xdg_surface_handle_set_window_geometry,  };  static bool wlr_xdg_surface_toplevel_state_compare( @@ -965,9 +1047,9 @@ static bool wlr_xdg_surface_toplevel_state_compare(  	} else {  		struct wlr_xdg_surface_configure *configure =  			wl_container_of(state->base->configure_list.prev, configure, link); -		configured.state = configure->state; -		configured.width = configure->state.width; -		configured.height = configure->state.height; +		configured.state = *configure->toplevel_state; +		configured.width = configure->toplevel_state->width; +		configured.height = configure->toplevel_state->height;  	}  	if (state->pending.activated != configured.state.activated) { @@ -999,13 +1081,19 @@ static void wlr_xdg_toplevel_send_configure(  		struct wlr_xdg_surface *surface,  		struct wlr_xdg_surface_configure *configure) {  	assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); -	uint32_t *s; -	struct wl_array states; -	configure->state = surface->toplevel_state->pending; +	configure->toplevel_state = malloc(sizeof(*configure->toplevel_state)); +	if (configure->toplevel_state == NULL) { +		wlr_log(L_ERROR, "Allocation failed"); +		wl_resource_post_no_memory(surface->toplevel->resource); +		return; +	} +	*configure->toplevel_state = surface->toplevel->pending; +	uint32_t *s; +	struct wl_array states;  	wl_array_init(&states); -	if (surface->toplevel_state->pending.maximized) { +	if (surface->toplevel->pending.maximized) {  		s = wl_array_add(&states, sizeof(uint32_t));  		if (!s) {  			wlr_log(L_ERROR, "Could not allocate state for maximized xdg_toplevel"); @@ -1013,7 +1101,7 @@ static void wlr_xdg_toplevel_send_configure(  		}  		*s = XDG_TOPLEVEL_STATE_MAXIMIZED;  	} -	if (surface->toplevel_state->pending.fullscreen) { +	if (surface->toplevel->pending.fullscreen) {  		s = wl_array_add(&states, sizeof(uint32_t));  		if (!s) {  			wlr_log(L_ERROR, "Could not allocate state for fullscreen xdg_toplevel"); @@ -1021,7 +1109,7 @@ static void wlr_xdg_toplevel_send_configure(  		}  		*s = XDG_TOPLEVEL_STATE_FULLSCREEN;  	} -	if (surface->toplevel_state->pending.resizing) { +	if (surface->toplevel->pending.resizing) {  		s = wl_array_add(&states, sizeof(uint32_t));  		if (!s) {  			wlr_log(L_ERROR, "Could not allocate state for resizing xdg_toplevel"); @@ -1029,7 +1117,7 @@ static void wlr_xdg_toplevel_send_configure(  		}  		*s = XDG_TOPLEVEL_STATE_RESIZING;  	} -	if (surface->toplevel_state->pending.activated) { +	if (surface->toplevel->pending.activated) {  		s = wl_array_add(&states, sizeof(uint32_t));  		if (!s) {  			wlr_log(L_ERROR, "Could not allocate state for activated xdg_toplevel"); @@ -1038,23 +1126,17 @@ static void wlr_xdg_toplevel_send_configure(  		*s = XDG_TOPLEVEL_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; -	} - -	xdg_toplevel_send_configure(surface->toplevel_state->resource, width, -		height, &states); +	uint32_t width = surface->toplevel->pending.width; +	uint32_t height = surface->toplevel->pending.height; +	xdg_toplevel_send_configure(surface->toplevel->resource, width, height, +		&states);  	wl_array_release(&states);  	return;  error_out:  	wl_array_release(&states); -	wl_resource_post_no_memory(surface->toplevel_state->resource); +	wl_resource_post_no_memory(surface->toplevel->resource);  }  static void wlr_xdg_surface_send_configure(void *user_data) { @@ -1080,11 +1162,11 @@ static void wlr_xdg_surface_send_configure(void *user_data) {  		wlr_xdg_toplevel_send_configure(surface, configure);  		break;  	case WLR_XDG_SURFACE_ROLE_POPUP: -		xdg_popup_send_configure(surface->popup_state->resource, -			surface->popup_state->geometry.x, -			surface->popup_state->geometry.y, -			surface->popup_state->geometry.width, -			surface->popup_state->geometry.height); +		xdg_popup_send_configure(surface->popup->resource, +			surface->popup->geometry.x, +			surface->popup->geometry.y, +			surface->popup->geometry.width, +			surface->popup->geometry.height);  		break;  	} @@ -1103,7 +1185,7 @@ static uint32_t wlr_xdg_surface_schedule_configure(  		break;  	case WLR_XDG_SURFACE_ROLE_TOPLEVEL:  		pending_same = -			wlr_xdg_surface_toplevel_state_compare(surface->toplevel_state); +			wlr_xdg_surface_toplevel_state_compare(surface->toplevel);  		break;  	case WLR_XDG_SURFACE_ROLE_POPUP:  		break; @@ -1143,29 +1225,32 @@ static void wlr_xdg_surface_toplevel_committed(  		struct wlr_xdg_surface *surface) {  	assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); -	if (!wlr_surface_has_buffer(surface->surface) -			&& !surface->toplevel_state->added) { +	if (!surface->toplevel->added) {  		// on the first commit, send a configure request to tell the client it  		// is added  		wlr_xdg_surface_schedule_configure(surface); -		surface->toplevel_state->added = true; +		surface->toplevel->added = true;  		return;  	} -	if (!wlr_surface_has_buffer(surface->surface)) { -		return; -	} - -	surface->toplevel_state->current = surface->toplevel_state->next; +	// update state that doesn't need compositor approval +	surface->toplevel->current.max_width = +		surface->toplevel->next.max_width; +	surface->toplevel->current.min_width = +		surface->toplevel->next.min_width; +	surface->toplevel->current.max_height = +		surface->toplevel->next.max_height; +	surface->toplevel->current.min_height = +		surface->toplevel->next.min_height;  }  static void wlr_xdg_surface_popup_committed(  		struct wlr_xdg_surface *surface) {  	assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); -	if (!surface->popup_state->committed) { +	if (!surface->popup->committed) {  		wlr_xdg_surface_schedule_configure(surface); -		surface->popup_state->committed = true; +		surface->popup->committed = true;  	}  } @@ -1182,10 +1267,10 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface,  	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; +		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) { @@ -1202,9 +1287,19 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface,  		break;  	} -	if (surface->configured && !surface->added) { +	if (!surface->added) {  		surface->added = true; -		wlr_signal_emit_safe(&surface->client->shell->events.new_surface, surface); +		wlr_signal_emit_safe(&surface->client->shell->events.new_surface, +			surface); +	} +	if (surface->configured && wlr_surface_has_buffer(surface->surface) && +			!surface->mapped) { +		surface->mapped = true; +		wlr_signal_emit_safe(&surface->events.map, surface); +	} +	if (surface->configured && !wlr_surface_has_buffer(surface->surface) && +			surface->mapped) { +		xdg_surface_unmap(surface);  	}  } @@ -1217,27 +1312,15 @@ static struct wlr_xdg_client *xdg_client_from_resource(  	return wl_resource_get_user_data(resource);  } -static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, +static void xdg_shell_handle_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 *client =  		xdg_client_from_resource(client_resource); -	struct wlr_xdg_surface *surface; -	if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface)))) { -		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; -	} - -	if (!(surface->next_geometry = calloc(1, sizeof(struct wlr_box)))) { -		free(surface->geometry); -		free(surface); +	struct wlr_xdg_surface *surface = +		calloc(1, sizeof(struct wlr_xdg_surface)); +	if (surface == NULL) {  		wl_client_post_no_memory(wl_client);  		return;  	} @@ -1249,8 +1332,6 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client,  		&xdg_surface_interface, wl_resource_get_version(client_resource),  		id);  	if (surface->resource == NULL) { -		free(surface->next_geometry); -		free(surface->geometry);  		free(surface);  		wl_client_post_no_memory(wl_client);  		return; @@ -1258,8 +1339,6 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client,  	if (wlr_surface_has_buffer(surface->surface)) {  		wl_resource_destroy(surface->resource); -		free(surface->next_geometry); -		free(surface->geometry);  		free(surface);  		wl_resource_post_error(surface_resource,  			XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, @@ -1279,6 +1358,8 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client,  	wl_signal_init(&surface->events.destroy);  	wl_signal_init(&surface->events.ping_timeout);  	wl_signal_init(&surface->events.new_popup); +	wl_signal_init(&surface->events.map); +	wl_signal_init(&surface->events.unmap);  	wl_signal_add(&surface->surface->events.destroy,  		&surface->surface_destroy_listener); @@ -1293,7 +1374,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client,  	wl_list_insert(&client->surfaces, &surface->link);  } -static void xdg_shell_pong(struct wl_client *wl_client, +static void xdg_shell_handle_pong(struct wl_client *wl_client,  		struct wl_resource *resource, uint32_t serial) {  	struct wlr_xdg_client *client = xdg_client_from_resource(resource); @@ -1305,11 +1386,25 @@ static void xdg_shell_pong(struct wl_client *wl_client,  	client->ping_serial = 0;  } +static void xdg_shell_handle_destroy(struct wl_client *wl_client, +		struct wl_resource *resource) { +	struct wlr_xdg_client *client = xdg_client_from_resource(resource); + +	if (!wl_list_empty(&client->surfaces)) { +		wl_resource_post_error(client->resource, +			XDG_WM_BASE_ERROR_DEFUNCT_SURFACES, +			"xdg_wm_base was destroyed before children"); +		return; +	} + +	wl_resource_destroy(resource); +} +  static const struct xdg_wm_base_interface xdg_shell_impl = { -	.destroy = resource_destroy, -	.create_positioner = xdg_shell_create_positioner, -	.get_xdg_surface = xdg_shell_get_xdg_surface, -	.pong = xdg_shell_pong, +	.destroy = xdg_shell_handle_destroy, +	.create_positioner = xdg_shell_handle_create_positioner, +	.get_xdg_surface = xdg_shell_handle_get_xdg_surface, +	.pong = xdg_shell_handle_pong,  };  static void wlr_xdg_client_destroy(struct wl_resource *resource) { @@ -1437,8 +1532,8 @@ void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface) {  uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface,  		uint32_t width, uint32_t height) {  	assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); -	surface->toplevel_state->pending.width = width; -	surface->toplevel_state->pending.height = height; +	surface->toplevel->pending.width = width; +	surface->toplevel->pending.height = height;  	return wlr_xdg_surface_schedule_configure(surface);  } @@ -1446,7 +1541,7 @@ uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface,  uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface,  		bool activated) {  	assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); -	surface->toplevel_state->pending.activated = activated; +	surface->toplevel->pending.activated = activated;  	return wlr_xdg_surface_schedule_configure(surface);  } @@ -1454,7 +1549,7 @@ uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface,  uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface,  		bool maximized) {  	assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); -	surface->toplevel_state->pending.maximized = maximized; +	surface->toplevel->pending.maximized = maximized;  	return wlr_xdg_surface_schedule_configure(surface);  } @@ -1462,7 +1557,7 @@ uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface,  uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface,  		bool fullscreen) {  	assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); -	surface->toplevel_state->pending.fullscreen = fullscreen; +	surface->toplevel->pending.fullscreen = fullscreen;  	return wlr_xdg_surface_schedule_configure(surface);  } @@ -1470,24 +1565,37 @@ uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface,  uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface,  		bool resizing) {  	assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); -	surface->toplevel_state->pending.resizing = resizing; +	surface->toplevel->pending.resizing = resizing;  	return wlr_xdg_surface_schedule_configure(surface);  } -void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface) { -	assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); -	xdg_toplevel_send_close(surface->toplevel_state->resource); +void wlr_xdg_surface_send_close(struct wlr_xdg_surface *surface) { +	switch (surface->role) { +	case WLR_XDG_SURFACE_ROLE_NONE: +		assert(0 && "not reached"); +		break; +	case WLR_XDG_SURFACE_ROLE_TOPLEVEL: +		if (surface->toplevel) { +			xdg_toplevel_send_close(surface->toplevel->resource); +		} +		break; +	case WLR_XDG_SURFACE_ROLE_POPUP: +		if (surface->popup) { +			xdg_popup_send_popup_done(surface->popup->resource); +		} +		break; +	}  }  void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface,  		double *popup_sx, double *popup_sy) {  	assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); -	struct wlr_xdg_surface *parent = surface->popup_state->parent; -	*popup_sx = parent->geometry->x + surface->popup_state->geometry.x - -		surface->geometry->x; -	*popup_sy = parent->geometry->y + surface->popup_state->geometry.y - -		surface->geometry->y; +	struct wlr_xdg_surface *parent = surface->popup->parent; +	*popup_sx = parent->geometry.x + surface->popup->geometry.x - +		surface->geometry.x; +	*popup_sy = parent->geometry.y + surface->popup->geometry.y - +		surface->geometry.y;  }  struct wlr_xdg_surface *wlr_xdg_surface_popup_at( @@ -1501,30 +1609,30 @@ struct wlr_xdg_surface *wlr_xdg_surface_popup_at(  		struct wlr_xdg_surface *popup = popup_state->base;  		double _popup_sx = -			surface->geometry->x + popup_state->geometry.x; +			surface->geometry.x + popup_state->geometry.x;  		double _popup_sy = -			surface->geometry->y + popup_state->geometry.y; +			surface->geometry.y + popup_state->geometry.y;  		int popup_width =  popup_state->geometry.width;  		int popup_height =  popup_state->geometry.height;  		struct wlr_xdg_surface *_popup =  			wlr_xdg_surface_popup_at(popup, -				sx - _popup_sx + popup->geometry->x, -				sy - _popup_sy + popup->geometry->y, +				sx - _popup_sx + popup->geometry.x, +				sy - _popup_sy + popup->geometry.y,  				popup_sx, popup_sy);  		if (_popup) { -			*popup_sx = *popup_sx + _popup_sx - popup->geometry->x; -			*popup_sy = *popup_sy + _popup_sy - popup->geometry->y; +			*popup_sx = *popup_sx + _popup_sx - popup->geometry.x; +			*popup_sy = *popup_sy + _popup_sy - popup->geometry.y;  			return _popup;  		}  		if ((sx > _popup_sx && sx < _popup_sx + popup_width) &&  				(sy > _popup_sy && sy < _popup_sy + popup_height)) {  			if (pixman_region32_contains_point(&popup->surface->current->input, -						sx - _popup_sx + popup->geometry->x, -						sy - _popup_sy + popup->geometry->y, NULL)) { -				*popup_sx = _popup_sx - popup->geometry->x; -				*popup_sy = _popup_sy - popup->geometry->y; +						sx - _popup_sx + popup->geometry.x, +						sy - _popup_sy + popup->geometry.y, NULL)) { +				*popup_sx = _popup_sx - popup->geometry.x; +				*popup_sy = _popup_sy - popup->geometry.y;  				return popup;  			}  		} diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index e07d78a1..464e0157 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -13,8 +13,8 @@  #include "util/signal.h"  #include "xdg-shell-unstable-v6-protocol.h" -static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel"; -static const char *wlr_desktop_xdg_popup_role = "xdg_popup"; +static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel_v6"; +static const char *wlr_desktop_xdg_popup_role = "xdg_popup_v6";  struct wlr_xdg_positioner_v6 {  	struct wl_resource *resource; @@ -34,7 +34,7 @@ struct wlr_xdg_positioner_v6 {  }; -static void resource_destroy(struct wl_client *client, +static void resource_handle_destroy(struct wl_client *client,  		struct wl_resource *resource) {  	wl_resource_destroy(resource);  } @@ -131,6 +131,24 @@ static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = {  	.cancel = xdg_keyboard_grab_cancel,  }; +static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface); + +static void wlr_xdg_popup_grab_handle_seat_destroy( +		struct wl_listener *listener, void *data) { +	struct wlr_xdg_popup_grab_v6 *xdg_grab = +		wl_container_of(listener, xdg_grab, seat_destroy); + +	wl_list_remove(&xdg_grab->seat_destroy.link); + +	struct wlr_xdg_popup_v6 *popup, *next; +	wl_list_for_each_safe(popup, next, &xdg_grab->popups, grab_link) { +		xdg_surface_destroy(popup->base); +	} + +	wl_list_remove(&xdg_grab->link); +	free(xdg_grab); +} +  static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat(  		struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat) {  	struct wlr_xdg_popup_grab_v6 *xdg_grab; @@ -155,47 +173,46 @@ static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat(  	wl_list_insert(&shell->popup_grabs, &xdg_grab->link);  	xdg_grab->seat = seat; +	xdg_grab->seat_destroy.notify = wlr_xdg_popup_grab_handle_seat_destroy; +	wl_signal_add(&seat->events.destroy, &xdg_grab->seat_destroy); +  	return xdg_grab;  } -static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { -	// TODO: probably need to ungrab before this event -	wlr_signal_emit_safe(&surface->events.destroy, surface); - -	if (surface->configure_idle) { -		wl_event_source_remove(surface->configure_idle); +static void xdg_surface_configure_destroy( +		struct wlr_xdg_surface_v6_configure *configure) { +	if (configure == NULL) { +		return;  	} +	wl_list_remove(&configure->link); +	free(configure->toplevel_state); +	free(configure); +} -	struct wlr_xdg_surface_v6_configure *configure, *tmp; -	wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { -		free(configure); +static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) { +	assert(surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE); + +	// TODO: probably need to ungrab before this event +	if (surface->mapped) { +		wlr_signal_emit_safe(&surface->events.unmap, surface);  	}  	if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { -		wl_resource_set_user_data(surface->toplevel_state->resource, NULL); -		free(surface->toplevel_state); +		wl_resource_set_user_data(surface->toplevel->resource, NULL); +		free(surface->toplevel); +		surface->toplevel = NULL;  	}  	if (surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { -		wl_resource_set_user_data(surface->popup_state->resource, NULL); +		wl_resource_set_user_data(surface->popup->resource, NULL); -		if (surface->popup_state->seat) { +		if (surface->popup->seat) {  			struct wlr_xdg_popup_grab_v6 *grab =  				xdg_shell_popup_grab_from_seat(surface->client->shell, -					surface->popup_state->seat); +					surface->popup->seat); -			struct wlr_xdg_surface_v6 *topmost = -				xdg_popup_grab_get_topmost(grab); - -			if (topmost != surface) { -				wl_resource_post_error(surface->client->resource, -						ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, -						"xdg_popup was destroyed while it was not the topmost " -						"popup."); -			} - -			wl_list_remove(&surface->popup_state->grab_link); +			wl_list_remove(&surface->popup->grab_link);  			if (wl_list_empty(&grab->popups)) {  				if (grab->seat->pointer_state.grab == &grab->pointer_grab) { @@ -207,18 +224,46 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) {  			}  		} -		wl_list_remove(&surface->popup_state->link); -		free(surface->popup_state); +		wl_list_remove(&surface->popup->link); +		free(surface->popup); +		surface->popup = NULL;  	} +	struct wlr_xdg_surface_v6_configure *configure, *tmp; +	wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { +		xdg_surface_configure_destroy(configure); +	} + +	surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; +	free(surface->title); +	surface->title = NULL; +	free(surface->app_id); +	surface->app_id = NULL; + +	surface->added = surface->configured = surface->mapped = false; +	surface->configure_serial = 0; +	if (surface->configure_idle) { +		wl_event_source_remove(surface->configure_idle); +		surface->configure_idle = NULL; +	} +	surface->configure_next_serial = 0; + +	surface->has_next_geometry = false; +	memset(&surface->geometry, 0, sizeof(struct wlr_box)); +	memset(&surface->next_geometry, 0, sizeof(struct wlr_box)); +} + +static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { +	if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) { +		xdg_surface_unmap(surface); +	} + +	wlr_signal_emit_safe(&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);  	wlr_surface_set_role_committed(surface->surface, NULL, NULL); -	free(surface->geometry); -	free(surface->next_geometry); -	free(surface->title); -	free(surface->app_id);  	free(surface);  } @@ -237,10 +282,9 @@ static void xdg_positioner_destroy(struct wl_resource *resource) {  	struct wlr_xdg_positioner_v6 *positioner =  		xdg_positioner_from_resource(resource);  	free(positioner); -  } -static void xdg_positioner_protocol_set_size(struct wl_client *client, +static void xdg_positioner_handle_set_size(struct wl_client *client,  		struct wl_resource *resource, int32_t width, int32_t height) {  	struct wlr_xdg_positioner_v6 *positioner =  		xdg_positioner_from_resource(resource); @@ -256,7 +300,7 @@ static void xdg_positioner_protocol_set_size(struct wl_client *client,  	positioner->size.height = height;  } -static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, +static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client,  		struct wl_resource *resource, int32_t x, int32_t y, int32_t width,  		int32_t height) {  	struct wlr_xdg_positioner_v6 *positioner = @@ -275,7 +319,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client,  	positioner->anchor_rect.height = height;  } -static void xdg_positioner_protocol_set_anchor(struct wl_client *client, +static void xdg_positioner_handle_set_anchor(struct wl_client *client,  		struct wl_resource *resource, uint32_t anchor) {  	struct wlr_xdg_positioner_v6 *positioner =  		xdg_positioner_from_resource(resource); @@ -293,7 +337,7 @@ static void xdg_positioner_protocol_set_anchor(struct wl_client *client,  	positioner->anchor = anchor;  } -static void xdg_positioner_protocol_set_gravity(struct wl_client *client, +static void xdg_positioner_handle_set_gravity(struct wl_client *client,  		struct wl_resource *resource, uint32_t gravity) {  	struct wlr_xdg_positioner_v6 *positioner =  		xdg_positioner_from_resource(resource); @@ -311,7 +355,7 @@ static void xdg_positioner_protocol_set_gravity(struct wl_client *client,  	positioner->gravity = gravity;  } -static void xdg_positioner_protocol_set_constraint_adjustment( +static void xdg_positioner_handle_set_constraint_adjustment(  		struct wl_client *client, struct wl_resource *resource,  		uint32_t constraint_adjustment) {  	struct wlr_xdg_positioner_v6 *positioner = @@ -320,7 +364,7 @@ static void xdg_positioner_protocol_set_constraint_adjustment(  	positioner->constraint_adjustment = constraint_adjustment;  } -static void xdg_positioner_protocol_set_offset(struct wl_client *client, +static void xdg_positioner_handle_set_offset(struct wl_client *client,  		struct wl_resource *resource, int32_t x, int32_t y) {  	struct wlr_xdg_positioner_v6 *positioner =  		xdg_positioner_from_resource(resource); @@ -331,17 +375,17 @@ static void xdg_positioner_protocol_set_offset(struct wl_client *client,  static const struct zxdg_positioner_v6_interface  		zxdg_positioner_v6_implementation = { -	.destroy = resource_destroy, -	.set_size = xdg_positioner_protocol_set_size, -	.set_anchor_rect = xdg_positioner_protocol_set_anchor_rect, -	.set_anchor = xdg_positioner_protocol_set_anchor, -	.set_gravity = xdg_positioner_protocol_set_gravity, +	.destroy = resource_handle_destroy, +	.set_size = xdg_positioner_handle_set_size, +	.set_anchor_rect = xdg_positioner_handle_set_anchor_rect, +	.set_anchor = xdg_positioner_handle_set_anchor, +	.set_gravity = xdg_positioner_handle_set_gravity,  	.set_constraint_adjustment = -		xdg_positioner_protocol_set_constraint_adjustment, -	.set_offset = xdg_positioner_protocol_set_offset, +		xdg_positioner_handle_set_constraint_adjustment, +	.set_offset = xdg_positioner_handle_set_offset,  }; -static void xdg_shell_create_positioner(struct wl_client *wl_client, +static void xdg_shell_handle_create_positioner(struct wl_client *wl_client,  		struct wl_resource *resource, uint32_t id) {  	struct wlr_xdg_positioner_v6 *positioner =  		calloc(1, sizeof(struct wlr_xdg_positioner_v6)); @@ -430,7 +474,7 @@ static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_popup_resource(  	return wl_resource_get_user_data(resource);  } -static void xdg_popup_protocol_grab(struct wl_client *client, +static void xdg_popup_handle_grab(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *seat_resource,  		uint32_t serial) {  	struct wlr_xdg_surface_v6 *surface = @@ -438,8 +482,8 @@ static void xdg_popup_protocol_grab(struct wl_client *client,  	struct wlr_seat_client *seat_client =  		wlr_seat_client_from_resource(seat_resource); -	if (surface->popup_state->committed) { -		wl_resource_post_error(surface->popup_state->resource, +	if (surface->popup->committed) { +		wl_resource_post_error(surface->popup->resource,  			ZXDG_POPUP_V6_ERROR_INVALID_GRAB,  			"xdg_popup is already mapped");  		return; @@ -451,10 +495,10 @@ static void xdg_popup_protocol_grab(struct wl_client *client,  	struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(popup_grab);  	bool parent_is_toplevel = -		surface->popup_state->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; +		surface->popup->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL;  	if ((topmost == NULL && !parent_is_toplevel) || -			(topmost != NULL && topmost != surface->popup_state->parent)) { +			(topmost != NULL && topmost != surface->popup->parent)) {  		wl_resource_post_error(surface->client->resource,  			ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP,  			"xdg_popup was not created on the topmost popup"); @@ -462,9 +506,9 @@ static void xdg_popup_protocol_grab(struct wl_client *client,  	}  	popup_grab->client = surface->client->client; -	surface->popup_state->seat = seat_client->seat; +	surface->popup->seat = seat_client->seat; -	wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); +	wl_list_insert(&popup_grab->popups, &surface->popup->grab_link);  	wlr_seat_pointer_start_grab(seat_client->seat,  		&popup_grab->pointer_grab); @@ -472,16 +516,36 @@ static void xdg_popup_protocol_grab(struct wl_client *client,  		&popup_grab->keyboard_grab);  } +static void xdg_popup_handle_destroy(struct wl_client *client, +		struct wl_resource *resource) { +	struct wlr_xdg_surface_v6 *surface = +		xdg_surface_from_xdg_popup_resource(resource); +	struct wlr_xdg_popup_grab_v6 *grab = +		xdg_shell_popup_grab_from_seat(surface->client->shell, +			surface->popup->seat); +	struct wlr_xdg_surface_v6 *topmost = +		xdg_popup_grab_get_topmost(grab); + +	if (topmost != surface) { +		wl_resource_post_error(surface->client->resource, +			ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, +			"xdg_popup was destroyed while it was not the topmost popup"); +		return; +	} + +	wl_resource_destroy(resource); +} +  static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = { -	.destroy = resource_destroy, -	.grab = xdg_popup_protocol_grab, +	.destroy = xdg_popup_handle_destroy, +	.grab = xdg_popup_handle_grab,  };  static void xdg_popup_resource_destroy(struct wl_resource *resource) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_popup_resource(resource);  	if (surface != NULL) { -		xdg_surface_destroy(surface); +		xdg_surface_unmap(surface);  	}  } @@ -494,7 +558,7 @@ static struct wlr_xdg_surface_v6 *xdg_surface_from_resource(  	return wl_resource_get_user_data(resource);  } -static void xdg_surface_get_popup(struct wl_client *client, +static void xdg_surface_handle_get_popup(struct wl_client *client,  		struct wl_resource *resource, uint32_t id,  		struct wl_resource *parent_resource,  		struct wl_resource *positioner_resource) { @@ -517,33 +581,33 @@ static void xdg_surface_get_popup(struct wl_client *client,  		return;  	} -	surface->popup_state = calloc(1, sizeof(struct wlr_xdg_popup_v6)); -	if (!surface->popup_state) { +	surface->popup = calloc(1, sizeof(struct wlr_xdg_popup_v6)); +	if (!surface->popup) {  		wl_resource_post_no_memory(resource);  		return;  	} -	surface->popup_state->resource = +	surface->popup->resource =  		wl_resource_create(client, &zxdg_popup_v6_interface,  			wl_resource_get_version(resource), id); -	if (surface->popup_state->resource == NULL) { -		free(surface->popup_state); +	if (surface->popup->resource == NULL) { +		free(surface->popup);  		wl_resource_post_no_memory(resource);  		return;  	}  	surface->role = WLR_XDG_SURFACE_V6_ROLE_POPUP; -	surface->popup_state->base = surface; -	surface->popup_state->parent = parent; -	surface->popup_state->geometry = +	surface->popup->base = surface; +	surface->popup->parent = parent; +	surface->popup->geometry =  		xdg_positioner_get_geometry(positioner, surface, parent); -	wl_list_insert(&parent->popups, &surface->popup_state->link); +	wl_list_insert(&parent->popups, &surface->popup->link); -	wl_resource_set_implementation(surface->popup_state->resource, +	wl_resource_set_implementation(surface->popup->resource,  		&zxdg_popup_v6_implementation, surface,  		xdg_popup_resource_destroy); -	wlr_signal_emit_safe(&parent->events.new_popup, surface->popup_state); +	wlr_signal_emit_safe(&parent->events.new_popup, surface->popup);  } @@ -556,7 +620,7 @@ static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_toplevel_resource(  	return wl_resource_get_user_data(resource);  } -static void xdg_toplevel_protocol_set_parent(struct wl_client *client, +static void xdg_toplevel_handle_set_parent(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *parent_resource) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); @@ -566,10 +630,10 @@ static void xdg_toplevel_protocol_set_parent(struct wl_client *client,  		parent = xdg_surface_from_xdg_toplevel_resource(parent_resource);  	} -	surface->toplevel_state->parent = parent; +	surface->toplevel->parent = parent;  } -static void xdg_toplevel_protocol_set_title(struct wl_client *client, +static void xdg_toplevel_handle_set_title(struct wl_client *client,  		struct wl_resource *resource, const char *title) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); @@ -583,7 +647,7 @@ static void xdg_toplevel_protocol_set_title(struct wl_client *client,  	surface->title = tmp;  } -static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, +static void xdg_toplevel_handle_set_app_id(struct wl_client *client,  		struct wl_resource *resource, const char *app_id) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); @@ -597,7 +661,7 @@ static void xdg_toplevel_protocol_set_app_id(struct wl_client *client,  	surface->app_id = tmp;  } -static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, +static void xdg_toplevel_handle_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 = @@ -606,7 +670,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client,  		wlr_seat_client_from_resource(seat_resource);  	if (!surface->configured) { -		wl_resource_post_error(surface->toplevel_state->resource, +		wl_resource_post_error(surface->toplevel->resource,  			ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,  			"surface has not been configured yet");  		return; @@ -628,7 +692,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client,  	wlr_signal_emit_safe(&surface->events.request_show_window_menu, &event);  } -static void xdg_toplevel_protocol_move(struct wl_client *client, +static void xdg_toplevel_handle_move(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *seat_resource,  		uint32_t serial) {  	struct wlr_xdg_surface_v6 *surface = @@ -637,7 +701,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client,  		wlr_seat_client_from_resource(seat_resource);  	if (!surface->configured) { -		wl_resource_post_error(surface->toplevel_state->resource, +		wl_resource_post_error(surface->toplevel->resource,  			ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,  			"surface has not been configured yet");  		return; @@ -657,7 +721,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client,  	wlr_signal_emit_safe(&surface->events.request_move, &event);  } -static void xdg_toplevel_protocol_resize(struct wl_client *client, +static void xdg_toplevel_handle_resize(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *seat_resource,  		uint32_t serial, uint32_t edges) {  	struct wlr_xdg_surface_v6 *surface = @@ -666,7 +730,7 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client,  		wlr_seat_client_from_resource(seat_resource);  	if (!surface->configured) { -		wl_resource_post_error(surface->toplevel_state->resource, +		wl_resource_post_error(surface->toplevel->resource,  			ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,  			"surface has not been configured yet");  		return; @@ -687,39 +751,39 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client,  	wlr_signal_emit_safe(&surface->events.request_resize, &event);  } -static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, +static void xdg_toplevel_handle_set_max_size(struct wl_client *client,  		struct wl_resource *resource, int32_t width, int32_t height) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); -	surface->toplevel_state->next.max_width = width; -	surface->toplevel_state->next.max_height = height; +	surface->toplevel->next.max_width = width; +	surface->toplevel->next.max_height = height;  } -static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, +static void xdg_toplevel_handle_set_min_size(struct wl_client *client,  		struct wl_resource *resource, int32_t width, int32_t height) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); -	surface->toplevel_state->next.min_width = width; -	surface->toplevel_state->next.min_height = height; +	surface->toplevel->next.min_width = width; +	surface->toplevel->next.min_height = height;  } -static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, +static void xdg_toplevel_handle_set_maximized(struct wl_client *client,  		struct wl_resource *resource) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); -	surface->toplevel_state->next.maximized = true; +	surface->toplevel->next.maximized = true;  	wlr_signal_emit_safe(&surface->events.request_maximize, surface);  } -static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, +static void xdg_toplevel_handle_unset_maximized(struct wl_client *client,  		struct wl_resource *resource) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); -	surface->toplevel_state->next.maximized = false; +	surface->toplevel->next.maximized = false;  	wlr_signal_emit_safe(&surface->events.request_maximize, surface);  } -static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, +static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client,  		struct wl_resource *resource, struct wl_resource *output_resource) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); @@ -729,7 +793,7 @@ static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client,  		output = wlr_output_from_resource(output_resource);  	} -	surface->toplevel_state->next.fullscreen = true; +	surface->toplevel->next.fullscreen = true;  	struct wlr_xdg_toplevel_v6_set_fullscreen_event event = {  		.surface = surface, @@ -740,12 +804,12 @@ static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client,  	wlr_signal_emit_safe(&surface->events.request_fullscreen, &event);  } -static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, +static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client,  		struct wl_resource *resource) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource); -	surface->toplevel_state->next.fullscreen = false; +	surface->toplevel->next.fullscreen = false;  	struct wlr_xdg_toplevel_v6_set_fullscreen_event event = {  		.surface = surface, @@ -756,29 +820,29 @@ static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client,  	wlr_signal_emit_safe(&surface->events.request_fullscreen, &event);  } -static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, +static void xdg_toplevel_handle_set_minimized(struct wl_client *client,  		struct wl_resource *resource) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource);  	wlr_signal_emit_safe(&surface->events.request_minimize, surface);  } -static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = -{ -	.destroy = resource_destroy, -	.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 const struct zxdg_toplevel_v6_interface +		zxdg_toplevel_v6_implementation = { +	.destroy = resource_handle_destroy, +	.set_parent = xdg_toplevel_handle_set_parent, +	.set_title = xdg_toplevel_handle_set_title, +	.set_app_id = xdg_toplevel_handle_set_app_id, +	.show_window_menu = xdg_toplevel_handle_show_window_menu, +	.move = xdg_toplevel_handle_move, +	.resize = xdg_toplevel_handle_resize, +	.set_max_size = xdg_toplevel_handle_set_max_size, +	.set_min_size = xdg_toplevel_handle_set_min_size, +	.set_maximized = xdg_toplevel_handle_set_maximized, +	.unset_maximized = xdg_toplevel_handle_unset_maximized, +	.set_fullscreen = xdg_toplevel_handle_set_fullscreen, +	.unset_fullscreen = xdg_toplevel_handle_unset_fullscreen, +	.set_minimized = xdg_toplevel_handle_set_minimized,  };  static void xdg_surface_resource_destroy(struct wl_resource *resource) { @@ -792,11 +856,11 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) {  	struct wlr_xdg_surface_v6 *surface =  		xdg_surface_from_xdg_toplevel_resource(resource);  	if (surface != NULL) { -		xdg_surface_destroy(surface); +		xdg_surface_unmap(surface);  	}  } -static void xdg_surface_get_toplevel(struct wl_client *client, +static void xdg_surface_handle_get_toplevel(struct wl_client *client,  		struct wl_resource *resource, uint32_t id) {  	struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); @@ -805,24 +869,24 @@ static void xdg_surface_get_toplevel(struct wl_client *client,  		return;  	} -	surface->toplevel_state = calloc(1, sizeof(struct wlr_xdg_toplevel_v6)); -	if (surface->toplevel_state == NULL) { +	surface->toplevel = calloc(1, sizeof(struct wlr_xdg_toplevel_v6)); +	if (surface->toplevel == NULL) {  		wl_resource_post_no_memory(resource);  		return;  	}  	surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; -	surface->toplevel_state->base = surface; +	surface->toplevel->base = surface;  	struct wl_resource *toplevel_resource = wl_resource_create(client,  		&zxdg_toplevel_v6_interface, wl_resource_get_version(resource), id);  	if (toplevel_resource == NULL) { -		free(surface->toplevel_state); +		free(surface->toplevel);  		wl_resource_post_no_memory(resource);  		return;  	} -	surface->toplevel_state->resource = toplevel_resource; +	surface->toplevel->resource = toplevel_resource;  	wl_resource_set_implementation(toplevel_resource,  		&zxdg_toplevel_v6_implementation, surface, @@ -833,12 +897,19 @@ 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; +	assert(configure->toplevel_state != NULL); + +	surface->toplevel->current.maximized = +		configure->toplevel_state->maximized; +	surface->toplevel->current.fullscreen = +		configure->toplevel_state->fullscreen; +	surface->toplevel->current.resizing = +		configure->toplevel_state->resizing; +	surface->toplevel->current.activated = +		configure->toplevel_state->activated;  } -static void xdg_surface_ack_configure(struct wl_client *client, +static void xdg_surface_handle_ack_configure(struct wl_client *client,  		struct wl_resource *resource, uint32_t serial) {  	struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); @@ -853,10 +924,8 @@ static void xdg_surface_ack_configure(struct wl_client *client,  	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); +			xdg_surface_configure_destroy(configure);  		} else if (configure->serial == serial) { -			wl_list_remove(&configure->link);  			found = true;  			break;  		} else { @@ -884,10 +953,10 @@ static void xdg_surface_ack_configure(struct wl_client *client,  	surface->configured = true;  	surface->configure_serial = serial; -	free(configure); +	xdg_surface_configure_destroy(configure);  } -static void xdg_surface_set_window_geometry(struct wl_client *client, +static void xdg_surface_handle_set_window_geometry(struct wl_client *client,  		struct wl_resource *resource, int32_t x, int32_t y, int32_t width,  		int32_t height) {  	struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); @@ -900,19 +969,31 @@ static void xdg_surface_set_window_geometry(struct wl_client *client,  	}  	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; +	surface->next_geometry.height = height; +	surface->next_geometry.width = width; +	surface->next_geometry.x = x; +	surface->next_geometry.y = y; +} +static void xdg_surface_handle_destroy(struct wl_client *client, +		struct wl_resource *resource) { +	struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); + +	if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) { +		wlr_log(L_ERROR, "Tried to destroy an xdg_surface before its role " +			"object"); +		return; +	} + +	wl_resource_destroy(resource);  }  static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation = { -	.destroy = resource_destroy, -	.get_toplevel = xdg_surface_get_toplevel, -	.get_popup = xdg_surface_get_popup, -	.ack_configure = xdg_surface_ack_configure, -	.set_window_geometry = xdg_surface_set_window_geometry, +	.destroy = xdg_surface_handle_destroy, +	.get_toplevel = xdg_surface_handle_get_toplevel, +	.get_popup = xdg_surface_handle_get_popup, +	.ack_configure = xdg_surface_handle_ack_configure, +	.set_window_geometry = xdg_surface_handle_set_window_geometry,  };  static bool wlr_xdg_surface_v6_toplevel_state_compare( @@ -935,9 +1016,9 @@ static bool wlr_xdg_surface_v6_toplevel_state_compare(  	} else {  		struct wlr_xdg_surface_v6_configure *configure =  			wl_container_of(state->base->configure_list.prev, configure, link); -		configured.state = configure->state; -		configured.width = configure->state.width; -		configured.height = configure->state.height; +		configured.state = *configure->toplevel_state; +		configured.width = configure->toplevel_state->width; +		configured.height = configure->toplevel_state->height;  	}  	if (state->pending.activated != configured.state.activated) { @@ -969,13 +1050,19 @@ 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; +	configure->toplevel_state = malloc(sizeof(*configure->toplevel_state)); +	if (configure->toplevel_state == NULL) { +		wlr_log(L_ERROR, "Allocation failed"); +		wl_resource_post_no_memory(surface->toplevel->resource); +		return; +	} +	*configure->toplevel_state = surface->toplevel->pending; +	uint32_t *s; +	struct wl_array states;  	wl_array_init(&states); -	if (surface->toplevel_state->pending.maximized) { +	if (surface->toplevel->pending.maximized) {  		s = wl_array_add(&states, sizeof(uint32_t));  		if (!s) {  			wlr_log(L_ERROR, "Could not allocate state for maximized xdg_toplevel"); @@ -983,7 +1070,7 @@ static void wlr_xdg_toplevel_v6_send_configure(  		}  		*s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED;  	} -	if (surface->toplevel_state->pending.fullscreen) { +	if (surface->toplevel->pending.fullscreen) {  		s = wl_array_add(&states, sizeof(uint32_t));  		if (!s) {  			wlr_log(L_ERROR, "Could not allocate state for fullscreen xdg_toplevel"); @@ -991,7 +1078,7 @@ static void wlr_xdg_toplevel_v6_send_configure(  		}  		*s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN;  	} -	if (surface->toplevel_state->pending.resizing) { +	if (surface->toplevel->pending.resizing) {  		s = wl_array_add(&states, sizeof(uint32_t));  		if (!s) {  			wlr_log(L_ERROR, "Could not allocate state for resizing xdg_toplevel"); @@ -999,7 +1086,7 @@ static void wlr_xdg_toplevel_v6_send_configure(  		}  		*s = ZXDG_TOPLEVEL_V6_STATE_RESIZING;  	} -	if (surface->toplevel_state->pending.activated) { +	if (surface->toplevel->pending.activated) {  		s = wl_array_add(&states, sizeof(uint32_t));  		if (!s) {  			wlr_log(L_ERROR, "Could not allocate state for activated xdg_toplevel"); @@ -1008,15 +1095,9 @@ static void wlr_xdg_toplevel_v6_send_configure(  		*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, +	uint32_t width = surface->toplevel->pending.width; +	uint32_t height = surface->toplevel->pending.height; +	zxdg_toplevel_v6_send_configure(surface->toplevel->resource, width,  		height, &states);  	wl_array_release(&states); @@ -1024,7 +1105,7 @@ static void wlr_xdg_toplevel_v6_send_configure(  error_out:  	wl_array_release(&states); -	wl_resource_post_no_memory(surface->toplevel_state->resource); +	wl_resource_post_no_memory(surface->toplevel->resource);  }  static void wlr_xdg_surface_send_configure(void *user_data) { @@ -1050,11 +1131,11 @@ static void wlr_xdg_surface_send_configure(void *user_data) {  		wlr_xdg_toplevel_v6_send_configure(surface, configure);  		break;  	case WLR_XDG_SURFACE_V6_ROLE_POPUP: -		zxdg_popup_v6_send_configure(surface->popup_state->resource, -			surface->popup_state->geometry.x, -			surface->popup_state->geometry.y, -			surface->popup_state->geometry.width, -			surface->popup_state->geometry.height); +		zxdg_popup_v6_send_configure(surface->popup->resource, +			surface->popup->geometry.x, +			surface->popup->geometry.y, +			surface->popup->geometry.width, +			surface->popup->geometry.height);  		break;  	} @@ -1073,7 +1154,7 @@ static uint32_t wlr_xdg_surface_v6_schedule_configure(  		break;  	case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:  		pending_same = -			wlr_xdg_surface_v6_toplevel_state_compare(surface->toplevel_state); +			wlr_xdg_surface_v6_toplevel_state_compare(surface->toplevel);  		break;  	case WLR_XDG_SURFACE_V6_ROLE_POPUP:  		break; @@ -1113,29 +1194,32 @@ static void wlr_xdg_surface_v6_toplevel_committed(  		struct wlr_xdg_surface_v6 *surface) {  	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); -	if (!wlr_surface_has_buffer(surface->surface) -			&& !surface->toplevel_state->added) { +	if (!surface->toplevel->added) {  		// on the first commit, send a configure request to tell the client it  		// is added  		wlr_xdg_surface_v6_schedule_configure(surface); -		surface->toplevel_state->added = true; +		surface->toplevel->added = true;  		return;  	} -	if (!wlr_surface_has_buffer(surface->surface)) { -		return; -	} - -	surface->toplevel_state->current = surface->toplevel_state->next; +	// update state that doesn't need compositor approval +	surface->toplevel->current.max_width = +		surface->toplevel->next.max_width; +	surface->toplevel->current.min_width = +		surface->toplevel->next.min_width; +	surface->toplevel->current.max_height = +		surface->toplevel->next.max_height; +	surface->toplevel->current.min_height = +		surface->toplevel->next.min_height;  }  static void wlr_xdg_surface_v6_popup_committed(  		struct wlr_xdg_surface_v6 *surface) {  	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP); -	if (!surface->popup_state->committed) { +	if (!surface->popup->committed) {  		wlr_xdg_surface_v6_schedule_configure(surface); -		surface->popup_state->committed = true; +		surface->popup->committed = true;  	}  } @@ -1152,10 +1236,10 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface,  	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; +		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) { @@ -1172,9 +1256,19 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface,  		break;  	} -	if (surface->configured && !surface->added) { +	if (!surface->added) {  		surface->added = true; -		wlr_signal_emit_safe(&surface->client->shell->events.new_surface, surface); +		wlr_signal_emit_safe(&surface->client->shell->events.new_surface, +			surface); +	} +	if (surface->configured && wlr_surface_has_buffer(surface->surface) && +			!surface->mapped) { +		surface->mapped = true; +		wlr_signal_emit_safe(&surface->events.map, surface); +	} +	if (surface->configured && !wlr_surface_has_buffer(surface->surface) && +			surface->mapped) { +		xdg_surface_unmap(surface);  	}  } @@ -1187,27 +1281,15 @@ static struct wlr_xdg_client_v6 *xdg_client_from_resource(  	return wl_resource_get_user_data(resource);  } -static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, +static void xdg_shell_handle_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 =  		xdg_client_from_resource(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; -	} - -	if (!(surface->next_geometry = calloc(1, sizeof(struct wlr_box)))) { -		free(surface->geometry); -		free(surface); +	struct wlr_xdg_surface_v6 *surface = +		calloc(1, sizeof(struct wlr_xdg_surface_v6)); +	if (surface == NULL) {  		wl_client_post_no_memory(wl_client);  		return;  	} @@ -1219,8 +1301,6 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client,  		&zxdg_surface_v6_interface, wl_resource_get_version(client_resource),  		id);  	if (surface->resource == NULL) { -		free(surface->next_geometry); -		free(surface->geometry);  		free(surface);  		wl_client_post_no_memory(wl_client);  		return; @@ -1228,8 +1308,6 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client,  	if (wlr_surface_has_buffer(surface->surface)) {  		wl_resource_destroy(surface->resource); -		free(surface->next_geometry); -		free(surface->geometry);  		free(surface);  		wl_resource_post_error(surface_resource,  			ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, @@ -1249,6 +1327,8 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client,  	wl_signal_init(&surface->events.destroy);  	wl_signal_init(&surface->events.ping_timeout);  	wl_signal_init(&surface->events.new_popup); +	wl_signal_init(&surface->events.map); +	wl_signal_init(&surface->events.unmap);  	wl_signal_add(&surface->surface->events.destroy,  		&surface->surface_destroy_listener); @@ -1263,7 +1343,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client,  	wl_list_insert(&client->surfaces, &surface->link);  } -static void xdg_shell_pong(struct wl_client *wl_client, +static void xdg_shell_handle_pong(struct wl_client *wl_client,  		struct wl_resource *resource, uint32_t serial) {  	struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); @@ -1275,11 +1355,25 @@ static void xdg_shell_pong(struct wl_client *wl_client,  	client->ping_serial = 0;  } +static void xdg_shell_handle_destroy(struct wl_client *wl_client, +		struct wl_resource *resource) { +	struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); + +	if (!wl_list_empty(&client->surfaces)) { +		wl_resource_post_error(client->resource, +			ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, +			"xdg_wm_base was destroyed before children"); +		return; +	} + +	wl_resource_destroy(resource); +} +  static const struct zxdg_shell_v6_interface xdg_shell_impl = { -	.destroy = resource_destroy, -	.create_positioner = xdg_shell_create_positioner, -	.get_xdg_surface = xdg_shell_get_xdg_surface, -	.pong = xdg_shell_pong, +	.destroy = xdg_shell_handle_destroy, +	.create_positioner = xdg_shell_handle_create_positioner, +	.get_xdg_surface = xdg_shell_handle_get_xdg_surface, +	.pong = xdg_shell_handle_pong,  };  static void wlr_xdg_client_v6_destroy(struct wl_resource *resource) { @@ -1407,8 +1501,8 @@ void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface) {  uint32_t 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; +	surface->toplevel->pending.width = width; +	surface->toplevel->pending.height = height;  	return wlr_xdg_surface_v6_schedule_configure(surface);  } @@ -1416,7 +1510,7 @@ uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface,  uint32_t 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; +	surface->toplevel->pending.activated = activated;  	return wlr_xdg_surface_v6_schedule_configure(surface);  } @@ -1424,7 +1518,7 @@ uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface,  uint32_t 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; +	surface->toplevel->pending.maximized = maximized;  	return wlr_xdg_surface_v6_schedule_configure(surface);  } @@ -1432,7 +1526,7 @@ uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface,  uint32_t 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; +	surface->toplevel->pending.fullscreen = fullscreen;  	return wlr_xdg_surface_v6_schedule_configure(surface);  } @@ -1440,24 +1534,37 @@ uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface,  uint32_t 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.resizing = resizing; +	surface->toplevel->pending.resizing = resizing;  	return wlr_xdg_surface_v6_schedule_configure(surface);  } -void wlr_xdg_toplevel_v6_send_close(struct wlr_xdg_surface_v6 *surface) { -	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); -	zxdg_toplevel_v6_send_close(surface->toplevel_state->resource); +void wlr_xdg_surface_v6_send_close(struct wlr_xdg_surface_v6 *surface) { +	switch (surface->role) { +	case WLR_XDG_SURFACE_V6_ROLE_NONE: +		assert(0 && "not reached"); +		break; +	case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: +		if (surface->toplevel) { +			zxdg_toplevel_v6_send_close(surface->toplevel->resource); +		} +		break; +	case WLR_XDG_SURFACE_V6_ROLE_POPUP: +		if (surface->popup) { +			zxdg_popup_v6_send_popup_done(surface->popup->resource); +		} +		break; +	}  }  void wlr_xdg_surface_v6_popup_get_position(struct wlr_xdg_surface_v6 *surface,  		double *popup_sx, double *popup_sy) {  	assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP); -	struct wlr_xdg_surface_v6 *parent = surface->popup_state->parent; -	*popup_sx = parent->geometry->x + surface->popup_state->geometry.x - -		surface->geometry->x; -	*popup_sy = parent->geometry->y + surface->popup_state->geometry.y - -		surface->geometry->y; +	struct wlr_xdg_surface_v6 *parent = surface->popup->parent; +	*popup_sx = parent->geometry.x + surface->popup->geometry.x - +		surface->geometry.x; +	*popup_sy = parent->geometry.y + surface->popup->geometry.y - +		surface->geometry.y;  }  struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_popup_at( @@ -1471,30 +1578,30 @@ struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_popup_at(  		struct wlr_xdg_surface_v6 *popup = popup_state->base;  		double _popup_sx = -			surface->geometry->x + popup_state->geometry.x; +			surface->geometry.x + popup_state->geometry.x;  		double _popup_sy = -			surface->geometry->y + popup_state->geometry.y; +			surface->geometry.y + popup_state->geometry.y;  		int popup_width =  popup_state->geometry.width;  		int popup_height =  popup_state->geometry.height;  		struct wlr_xdg_surface_v6 *_popup =  			wlr_xdg_surface_v6_popup_at(popup, -				sx - _popup_sx + popup->geometry->x, -				sy - _popup_sy + popup->geometry->y, +				sx - _popup_sx + popup->geometry.x, +				sy - _popup_sy + popup->geometry.y,  				popup_sx, popup_sy);  		if (_popup) { -			*popup_sx = *popup_sx + _popup_sx - popup->geometry->x; -			*popup_sy = *popup_sy + _popup_sy - popup->geometry->y; +			*popup_sx = *popup_sx + _popup_sx - popup->geometry.x; +			*popup_sy = *popup_sy + _popup_sy - popup->geometry.y;  			return _popup;  		}  		if ((sx > _popup_sx && sx < _popup_sx + popup_width) &&  				(sy > _popup_sy && sy < _popup_sy + popup_height)) {  			if (pixman_region32_contains_point(&popup->surface->current->input, -						sx - _popup_sx + popup->geometry->x, -						sy - _popup_sy + popup->geometry->y, NULL)) { -				*popup_sx = _popup_sx - popup->geometry->x; -				*popup_sy = _popup_sy - popup->geometry->y; +						sx - _popup_sx + popup->geometry.x, +						sy - _popup_sy + popup->geometry.y, NULL)) { +				*popup_sx = _popup_sx - popup->geometry.x; +				*popup_sy = _popup_sy - popup->geometry.y;  				return popup;  			}  		} diff --git a/util/region.c b/util/region.c index 88e38fd2..38f84c5e 100644 --- a/util/region.c +++ b/util/region.c @@ -128,3 +128,52 @@ void wlr_region_expand(pixman_region32_t *dst, pixman_region32_t *src,  	pixman_region32_init_rects(dst, dst_rects, nrects);  	free(dst_rects);  } + +void wlr_region_rotated_bounds(pixman_region32_t *dst, pixman_region32_t *src, +		float rotation, int ox, int oy) { +	if (rotation == 0) { +		pixman_region32_copy(dst, src); +		return; +	} + +	int nrects; +	pixman_box32_t *src_rects = pixman_region32_rectangles(src, &nrects); + +	pixman_box32_t *dst_rects = malloc(nrects * sizeof(pixman_box32_t)); +	if (dst_rects == NULL) { +		return; +	} + +	for (int i = 0; i < nrects; ++i) { +		double x1 = src_rects[i].x1 - ox; +		double y1 = src_rects[i].y1 - oy; +		double x2 = src_rects[i].x2 - ox; +		double y2 = src_rects[i].y2 - oy; + +		double rx1 = x1 * cos(rotation) - y1 * sin(rotation); +		double ry1 = x1 * sin(rotation) + y1 * cos(rotation); + +		double rx2 = x2 * cos(rotation) - y1 * sin(rotation); +		double ry2 = x2 * sin(rotation) + y1 * cos(rotation); + +		double rx3 = x2 * cos(rotation) - y2 * sin(rotation); +		double ry3 = x2 * sin(rotation) + y2 * cos(rotation); + +		double rx4 = x1 * cos(rotation) - y2 * sin(rotation); +		double ry4 = x1 * sin(rotation) + y2 * cos(rotation); + +		x1 = fmin(fmin(rx1, rx2), fmin(rx3, rx4)); +		y1 = fmin(fmin(ry1, ry2), fmin(ry3, ry4)); +		x2 = fmax(fmax(rx1, rx2), fmax(rx3, rx4)); +		y2 = fmax(fmax(ry1, ry2), fmax(ry3, ry4)); + +		dst_rects[i].x1 = floor(ox + x1); +		dst_rects[i].x2 = ceil(ox + x2); +		dst_rects[i].y1 = floor(oy + y1); +		dst_rects[i].y2 = ceil(oy + y2); +	} + +	pixman_region32_fini(dst); +	pixman_region32_init_rects(dst, dst_rects, nrects); +	free(dst_rects); +} diff --git a/wlroots.syms b/wlroots.syms index 3f45e045..cb030a6d 100644 --- a/wlroots.syms +++ b/wlroots.syms @@ -15,8 +15,8 @@ WLROOTS_0_0_0 {          wlr_drm_get_connector_props;          wlr_drm_get_crtc_props;          wlr_drm_get_plane_props; -        wlr_drm_get_prop;          wlr_drm_get_prop_blob; +        wlr_drm_get_prop;          wlr_drm_plane_surfaces_init;          wlr_drm_renderer_finish;          wlr_drm_renderer_init;  | 
