Stacking subsurface siblings

Jonas Ã…dahl jadahl at gmail.com
Tue Jun 16 08:47:03 PDT 2015


On Tue, Jun 16, 2015 at 04:46:55PM +0200, Arnaud Vrac wrote:
> Hi,
> 
> I'm wondering if a behaviour of weston related to subsurfaces is either a
> bug or intended. The protocol description is not clear on what happens in
> the following cases:
> 
> Suppose I have a shell surface (BLUE) and two subsurfaces (RED, GREEN). I
> want to stack them to I get RED, GREEN, BLUE from bottom to top.
> 
> If I do:
> 
> wl_subsurface_place_below(GREEN->subsurface, BLUE->surface);
> wl_subsurface_place_below(RED->subsurface, GREEN->surface);
> 
> It works, but if I do:
> 
> wl_subsurface_place_below(RED->subsurface, GREEN->surface);
> wl_subsurface_place_below(GREEN->subsurface, BLUE->surface);
> 
> The order is GREEN, RED, BLUE instead.
> 
> Logically the sibling relative order should be kept in the second case, but
> it's not. The protocol is not clear on what should happen, what is the
> expected result ?

The protocol says "This sub-surface is taken from the stack, and put
back just above the reference surface, changing the z-order of the
sub-surfaces." Considering this, if you first placed a surface below
another, placing again, that relationship may have been broken by the
new operation. In other words, the "tree" is not moved, just the
subsurface you placed.


Jonas

> 
> I have attached a small sample to test easily.
> 
> -- 
> Arnaud

> #include <stdio.h>
> #include <stdlib.h>
> #include <stdint.h>
> #include <stdarg.h>
> #include <string.h>
> #include <assert.h>
> #include <unistd.h>
> #include <fcntl.h>
> #include <sys/mman.h>
> 
> #include <wayland-client.h>
> #include <wayland-util.h>
> 
> struct surface {
> 	struct context *context;
> 	struct wl_surface *surface;
> 	struct wl_subsurface *subsurface;
> 	struct wl_shell_surface *shell_surface;
> 	struct wl_buffer *buffer;
> 
> 	int width;
> 	int height;
> 	int stride;
> 	int fd;
> 	uint32_t *data;
> 	uint32_t color;
> 
> 	struct surface *parent;
> };
> 
> struct context {
> 	struct wl_display *display;
> 	struct wl_registry *registry;
> 	struct wl_compositor *compositor;
> 	struct wl_subcompositor *subcompositor;
> 	struct wl_shell *shell;
> 	struct wl_shm *shm;
> };
> 
> static void
> die(const char *fmt, ...)
> {
> 	va_list ap;
> 
> 	va_start(ap, fmt);
> 	vfprintf(stderr, fmt, ap);
> 	fprintf(stderr, "\n");
> 	va_end(ap);
> 	exit(EXIT_FAILURE);
> }
> 
> static int
> surface_alloc_data(struct surface *surface)
> {
> 	char filename[] = "/tmp/wayland-shm-XXXXXX";
> 	uint32_t *data;
> 	int stride;
> 	int size;
> 	int fd;
> 	int i;
> 
> 	fd = mkstemp(filename);
> 	if (fd < 0)
> 		die("failed to create file for SHM buffer: %m");
> 
> 	unlink(filename);
> 
> 	stride = surface->width * 4;
> 	size = surface->height * stride;
> 
> 	if (fallocate(fd, 0, 0, size) < 0)
> 		die("failed to allocate %d bytes for SHM buffer: %m", size);
> 
> 	data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
> 	if (data == MAP_FAILED)
> 		die("failed to map SHM buffer data: %m");
> 
> 	for (i = 0; i < surface->width * surface->height; i++)
> 		data[i] = surface->color;
> 
> 	surface->fd = fd;
> 	surface->data = data;
> 	surface->stride = stride;
> 
> 	return 0;
> }
> 
> static struct surface *
> surface_create(struct context *context, struct surface *parent,
> 	       int width, int height, int x, int y, uint32_t color)
> {
> 	struct surface *surface;
> 	struct wl_shm_pool *pool;
> 
> 	surface = calloc(1, sizeof *surface);
> 	if (!surface)
> 		return NULL;
> 
> 	surface->fd = -1;
> 	surface->context = context;
> 	surface->width = width;
> 	surface->height = height;
> 	surface->color = color;
> 	surface->parent = parent;
> 
> 	if (surface_alloc_data(surface)) {
> 		free(surface);
> 		return NULL;
> 	}
> 
> 	pool = wl_shm_create_pool(context->shm, surface->fd,
> 				  surface->stride * surface->height);
> 
> 	surface->buffer = wl_shm_pool_create_buffer(pool, 0,
> 						    surface->width,
> 						    surface->height,
> 						    surface->stride,
> 						    WL_SHM_FORMAT_ARGB8888);
> 
> 	wl_shm_pool_destroy(pool);
> 
> 	surface->surface = wl_compositor_create_surface(context->compositor);
> 	if (surface->parent) {
> 		surface->subsurface = wl_subcompositor_get_subsurface(
> 			context->subcompositor, surface->surface,
> 			parent->surface);
> 
> 		wl_subsurface_set_position(surface->subsurface, x, y);
> 		wl_subsurface_set_desync(surface->subsurface);
> 	} else {
> 		surface->shell_surface =
> 			wl_shell_get_shell_surface(context->shell,
> 						   surface->surface);
> 		wl_shell_surface_set_toplevel(surface->shell_surface);
> 	}
> 
> 	wl_surface_attach(surface->surface, surface->buffer, 0, 0);
> 	wl_surface_damage(surface->surface, 0, 0,
> 			  surface->width, surface->height);
> 	wl_surface_commit(surface->surface);
> 
> 	return surface;
> }
> 
> static void
> registry_handle_global(void *data, struct wl_registry *registry,
> 		       uint32_t id, const char *interface, uint32_t version)
> {
> 	struct context *ctx = data;
> 
> 	if (!strcmp(interface, "wl_compositor")) {
> 		ctx->compositor =
> 			wl_registry_bind(registry, id,
> 					 &wl_compositor_interface, 1);
> 	} else if (!strcmp(interface, "wl_subcompositor")) {
> 		ctx->subcompositor =
> 			wl_registry_bind(registry, id,
> 					 &wl_subcompositor_interface, 1);
> 	} else if (!strcmp(interface, "wl_shell")) {
> 		ctx->shell =
> 			wl_registry_bind(registry, id, &wl_shell_interface, 1);
> 	} else if (!strcmp(interface, "wl_shm")) {
> 		ctx->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
> 	}
> }
> 
> static void
> registry_handle_global_remove(void *data, struct wl_registry *registry,
> 			      uint32_t id)
> {
> }
> 
> static const struct wl_registry_listener registry_listener = {
> 	registry_handle_global,
> 	registry_handle_global_remove
> };
> 
> enum {
> 	RED,
> 	GREEN,
> 	BLUE,
> 	COUNT
> };
> 
> static struct context *
> context_init(void)
> {
> 	struct context *ctx;
> 	struct surface *surf[COUNT];
> 
> 	ctx = calloc(1, sizeof (*ctx));
> 	ctx->display = wl_display_connect(NULL);
> 	if (!ctx->display)
> 		die("failed to init wayland display");
> 
> 	ctx->registry = wl_display_get_registry(ctx->display);
> 	wl_registry_add_listener(ctx->registry, &registry_listener, ctx);
> 	wl_display_roundtrip(ctx->display);
> 
> 	assert(ctx->compositor != NULL);
> 	assert(ctx->subcompositor != NULL);
> 	assert(ctx->shell != NULL);
> 
> 	surf[BLUE] = surface_create(ctx, NULL, 100, 100, 0, 0, 0xff0000ff);
> 	if (!surf[BLUE])
> 		die("failed to create root surface");
> 
> 	surf[RED] = surface_create(ctx, surf[BLUE], 100, 100, -100, -100,
> 				   0xffff0000);
> 
> 	surf[GREEN] = surface_create(ctx, surf[BLUE], 100, 100, -50, -50,
> 				     0xff00ff00);
> 
> #if 0
> 	wl_subsurface_place_below(surf[GREEN]->subsurface, surf[BLUE]->surface);
> 	wl_subsurface_place_below(surf[RED]->subsurface, surf[GREEN]->surface);
> #else
> 	wl_subsurface_place_below(surf[RED]->subsurface, surf[GREEN]->surface);
> 	wl_subsurface_place_below(surf[GREEN]->subsurface, surf[BLUE]->surface);
> #endif
> 
> 	wl_surface_commit(surf[BLUE]->surface);
> 
> 	return ctx;
> }
> 
> static void
> context_destroy(struct context *ctx)
> {
> 	wl_display_disconnect(ctx->display);
> 
> 	free(ctx);
> }
> 
> static void
> seed(void)
> {
> 	int fd = open("/dev/urandom", O_RDONLY);
> 	unsigned int s;
> 
> 	if (fd < 0)
> 		return;
> 
> 	read(fd, &s, sizeof (s));
> 	srand(s);
> 	close(fd);
> }
> 
> int main(int argc, char *argv[])
> {
> 	struct context *ctx;
> 
> 	seed();
> 
> 	ctx = context_init();
> 
> 	while (wl_display_dispatch(ctx->display) >= 0)
> 		;
> 
> 	context_destroy(ctx);
> 
> 	return 0;
> }

> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel



More information about the wayland-devel mailing list