[PATCH] wip: per-pixel surface picking

Tiago Vignatti tiago.vignatti at intel.com
Thu Feb 9 09:18:45 PST 2012


This is an unfinished work and I won't have time to deal with it next.

My intention was to come up with a protocol for applications specify the
effective shape of their windows. Say, flower client could send a bunch of
rectangles to the compositor telling about its real shape, so whenever an
input device touch/click in the transparent area, the event routes correctly
through another client that has an opaque area instead. In principle, the
whole idea is to circumvent similar issues that X Shape does.

This patch doesn't solve such problem at all. It neither uses another protocol
request telling about the client region.

This patch uses the costly glReadPixels call (could be async, dma, using
PBO, bla bla) to get alpha of the window and map it in a big matrix. It does
only once that (one redraw is performed only) and motion_handler is using the
matrix for getting the correct cursor pointer, based on the window shape. It
gives a nice effect already. One now would think in a way to convert this
alpha mask in a region of rectangles to be sent to the compositor, which in
turn would perform the correct picking of surfaces.

Note that flower has a very non-conventional shape though. Most of the windows
could simply send just a few rectangles to determine the drop shadows on each
side and maybe the rounded corners as well. That would make the things much
easier.

Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
---
 clients/flower.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 74 insertions(+), 1 deletions(-)

diff --git a/clients/flower.c b/clients/flower.c
index 0565eea..b4f4c0e 100644
--- a/clients/flower.c
+++ b/clients/flower.c
@@ -33,6 +33,10 @@
 #include <sys/time.h>
 #include <glib.h>
 
+#include <GL/gl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
 #include <linux/input.h>
 #include <wayland-client.h>
 #include "window.h"
@@ -42,6 +46,12 @@ struct flower {
 	struct window *window;
 	struct widget *widget;
 	int width, height;
+	int last_x, last_y;
+	unsigned char alpha[200][200];
+
+	EGLDisplay egldisplay;
+	EGLDisplay config;
+	EGLContext context;
 };
 
 static void
@@ -116,6 +126,40 @@ resize_handler(struct widget *widget,
 }
 
 static void
+fill_alpha(struct flower *flower)
+{
+	int i, j, tmp;
+
+	if (display_acquire_window_surface(flower->display, flower->window,
+				flower->context) != 0)
+		fprintf(stderr, "Unable to acquire egl surface\n");
+
+	/* million kittens being killed */
+	glPixelStorei(GL_PACK_ALIGNMENT, 1);
+	glReadPixels(0, 0, flower->width, flower->height, GL_ALPHA,
+			GL_UNSIGNED_BYTE, (void *)flower->alpha);
+
+	/* the order that glReadPixels returns is for some reason rotated 90
+	 * degrees clockwise; to get the original back, i.e a 90 degree ccw
+	 * rotated matrix, first transpose and then reverse the rows of it */
+	for (i = 0; i < flower->width; i++) {
+		for (j = i + 1; j < flower->height; j++) {
+			tmp = flower->alpha[i][j];
+			flower->alpha[i][j] = flower->alpha[j][i];
+			flower->alpha[j][i] = tmp;
+		}
+	}
+
+	for (i = 0; i < flower->width; i++) {
+		for (j = 0; j <= floor(flower->height / 2); j++) {
+			tmp = flower->alpha[i][j];
+			flower->alpha[i][j] = flower->alpha[i][flower->height - j - 1];
+			flower->alpha[i][flower->height - j - 1] = tmp;
+		}
+	}
+}
+
+static void
 redraw_handler(struct widget *widget, void *data)
 {
 	struct flower *flower = data;
@@ -129,6 +173,8 @@ redraw_handler(struct widget *widget, void *data)
 	}
 
 	draw_stuff(surface, flower->width, flower->height);
+	fill_alpha(flower);
+
 	cairo_surface_destroy(surface);
 }
 
@@ -136,7 +182,18 @@ static int
 motion_handler(struct widget *widget, struct input *input,
 	       uint32_t time, int32_t x, int32_t y, void *data)
 {
-	return POINTER_HAND1;
+	struct flower *flower = data;
+
+	if (x < 0 || y < 0 || x > flower->width || y > flower->height)
+		return POINTER_LEFT_PTR;
+
+	flower->last_x = x;
+	flower->last_y = y;
+
+	if (flower->alpha[x][y])
+		return POINTER_HAND1;
+	else
+		return POINTER_LEFT_PTR;
 }
 
 static void
@@ -148,6 +205,9 @@ button_handler(struct widget *widget,
 
 	switch (button) {
 	case BTN_LEFT:
+		if (!flower->alpha[flower->last_x][flower->last_y])
+			break;
+
 		if (state)
 			window_move(flower->window, input, time);
 		break;
@@ -179,6 +239,8 @@ int main(int argc, char *argv[])
 
 	flower.width = 200;
 	flower.height = 200;
+	flower.last_x = 0;
+	flower.last_y = 0;
 	flower.display = d;
 	flower.window = window_create(d);
 	flower.widget = window_add_widget(flower.window, &flower);
@@ -188,6 +250,17 @@ int main(int argc, char *argv[])
 	widget_set_motion_handler(flower.widget, motion_handler);
 	widget_set_button_handler(flower.widget, button_handler);
 
+	flower.egldisplay = display_get_egl_display(flower.display);
+	eglBindAPI(EGL_OPENGL_API);
+	flower.config = display_get_argb_egl_config(flower.display);
+	flower.context = eglCreateContext(flower.egldisplay, flower.config,
+			EGL_NO_CONTEXT, NULL);
+
+	if (flower.context == NULL) {
+		fprintf(stderr, "failed to create context\n");
+		return -1;
+	}
+
 	window_schedule_resize(flower.window, flower.width, flower.height);
 
 	display_run(d);
-- 
1.7.5.4



More information about the wayland-devel mailing list