diff --git a/Makefile b/Makefile index abfb256f..19519ed0 100644 --- a/Makefile +++ b/Makefile @@ -29,9 +29,9 @@ libwayland.so : $(libwayland_objs) $(compositors) $(clients) : CFLAGS += $(shell pkg-config --cflags libdrm) -egl_compositor_objs = egl-compositor.o -egl-compositor.so : CFLAGS += $(EAGLE_CFLAGS) $(shell pkg-config --cflags libpng) -egl-compositor.so : LDLIBS += $(EAGLE_LDLIBS) $(shell pkg-config --libs libpng) -rdynamic +egl_compositor_objs = egl-compositor.o cairo-util.o +egl-compositor.so : CFLAGS += $(EAGLE_CFLAGS) $(shell pkg-config --cflags libpng cairo) +egl-compositor.so : LDLIBS += $(EAGLE_LDLIBS) $(shell pkg-config --libs libpng cairo) -rdynamic egl-compositor.so : $(egl_compositor_objs) diff --git a/egl-compositor.c b/egl-compositor.c index 8e693551..c6180155 100644 --- a/egl-compositor.c +++ b/egl-compositor.c @@ -9,15 +9,22 @@ #include #include #include +#include #include #include "wayland.h" +#include "cairo-util.h" #include #include #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) +struct pointer { + struct wl_map map; + GLuint texture; +}; + struct egl_compositor { struct wl_compositor base; EGLDisplay display; @@ -27,6 +34,7 @@ struct egl_compositor { struct wl_display *wl_display; int gem_fd; int width, height; + struct pointer *pointer; }; struct surface_data { @@ -171,6 +179,119 @@ screenshot(struct egl_compositor *ec) free(data); } +static void +pointer_path(cairo_t *cr, int x, int y) +{ + const int end = 3, tx = 4, ty = 12, dx = 5, dy = 10; + const int width = 16, height = 16; + + cairo_move_to(cr, x, y); + cairo_line_to(cr, x + tx, y + ty); + cairo_line_to(cr, x + dx, y + dy); + cairo_line_to(cr, x + width - end, y + height); + cairo_line_to(cr, x + width, y + height - end); + cairo_line_to(cr, x + dy, y + dx); + cairo_line_to(cr, x + ty, y + tx); + cairo_close_path(cr); +} + +static struct pointer * +pointer_create(int x, int y, int width, int height) +{ + const int hotspot_x = 16, hotspot_y = 16; + struct pointer *pointer; + cairo_surface_t *surface; + cairo_t *cr; + int stride; + void *data; + + pointer = malloc(sizeof *pointer); + if (pointer == NULL) + return NULL; + + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + width, height); + + cr = cairo_create(surface); + pointer_path(cr, hotspot_x + 5, hotspot_y + 4); + cairo_set_line_width (cr, 2); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_stroke_preserve(cr); + cairo_fill(cr); + blur_surface(surface, width); + + pointer_path(cr, hotspot_x, hotspot_y); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_fill(cr); + cairo_destroy(cr); + + stride = cairo_image_surface_get_stride(surface); + data = cairo_image_surface_get_data(surface); + + glGenTextures(1, &pointer->texture); + glBindTexture(GL_TEXTURE_2D, pointer->texture); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + GL_BGRA, GL_UNSIGNED_BYTE, data); + + cairo_surface_destroy(surface); + + pointer->map.x = x; + pointer->map.y = y; + pointer->map.width = width; + pointer->map.height = height; + + return pointer; +} + +static void +pointer_destroy(struct pointer *pointer) +{ + glDeleteTextures(1, &pointer->texture); + free(pointer); +} + +static void +draw_surface(struct wl_map *map, GLuint texture) +{ + GLint vertices[12]; + GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 }; + GLuint indices[4] = { 0, 1, 2, 3 }; + + vertices[0] = map->x; + vertices[1] = map->y; + vertices[2] = 0; + + vertices[3] = map->x; + vertices[4] = map->y + map->height; + vertices[5] = 0; + + vertices[6] = map->x + map->width; + vertices[7] = map->y; + vertices[8] = 0; + + vertices[9] = map->x + map->width; + vertices[10] = map->y + map->height; + vertices[11] = 0; + + glBindTexture(GL_TEXTURE_2D, texture); + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + /* Assume pre-multiplied alpha for now, this probably + * needs to be a wayland visual type of thing. */ + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(3, GL_INT, 0, vertices); + glTexCoordPointer(2, GL_INT, 0, tex_coords); + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices); +} + static void repaint(void *data) { @@ -178,9 +299,6 @@ repaint(void *data) struct wl_surface_iterator *iterator; struct wl_surface *surface; struct surface_data *sd; - GLint vertices[12]; - GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 }; - GLuint indices[4] = { 0, 1, 2, 3 }; iterator = wl_surface_iterator_create(ec->wl_display, 0); while (wl_surface_iterator_next(iterator, &surface)) { @@ -188,37 +306,12 @@ repaint(void *data) if (sd == NULL) continue; - vertices[0] = sd->map.x; - vertices[1] = sd->map.y; - vertices[2] = 0; - - vertices[3] = sd->map.x; - vertices[4] = sd->map.y + sd->map.height; - vertices[5] = 0; - - vertices[6] = sd->map.x + sd->map.width; - vertices[7] = sd->map.y; - vertices[8] = 0; - - vertices[9] = sd->map.x + sd->map.width; - vertices[10] = sd->map.y + sd->map.height; - vertices[11] = 0; - - glBindTexture(GL_TEXTURE_2D, sd->texture); - glEnable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - /* Assume pre-multiplied alpha for now, this probably - * needs to be a wayland visual type of thing. */ - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(3, GL_INT, 0, vertices); - glTexCoordPointer(2, GL_INT, 0, tex_coords); - glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices); + draw_surface(&sd->map, sd->texture); } wl_surface_iterator_destroy(iterator); + draw_surface(&ec->pointer->map, ec->pointer->texture); + eglSwapBuffers(ec->display, ec->surface); if (do_screenshot) { @@ -363,13 +456,25 @@ notify_surface_damage(struct wl_compositor *compositor, schedule_repaint(ec); } +static void +notify_pointer_motion(struct wl_compositor *compositor, + struct wl_object *source, int x, int y) +{ + struct egl_compositor *ec = (struct egl_compositor *) compositor; + + ec->pointer->map.x = x; + ec->pointer->map.y = y; + schedule_repaint(ec); +} + static const struct wl_compositor_interface interface = { notify_surface_create, notify_surface_destroy, notify_surface_attach, notify_surface_map, notify_surface_copy, - notify_surface_damage + notify_surface_damage, + notify_pointer_motion }; static const char gem_device[] = "/dev/dri/card0"; @@ -433,6 +538,8 @@ wl_compositor_create(struct wl_display *display) glMatrixMode(GL_MODELVIEW); glClearColor(0.0, 0.05, 0.2, 0.0); + ec->pointer = pointer_create(100, 100, 64, 64); + ec->gem_fd = open(gem_device, O_RDWR); if (ec->gem_fd < 0) { fprintf(stderr, "failed to open drm device\n"); diff --git a/wayland.c b/wayland.c index d2b00366..15bb6bf2 100644 --- a/wayland.c +++ b/wayland.c @@ -588,11 +588,16 @@ void wl_display_post_relative_event(struct wl_display *display, struct wl_object *source, int dx, int dy) { + const struct wl_compositor_interface *interface; uint32_t p[4]; display->pointer_x += dx; display->pointer_y += dy; + interface = display->compositor->interface; + interface->notify_pointer_motion(display->compositor, source, + display->pointer_x, display->pointer_y); + p[0] = source->id; p[1] = (sizeof p << 16) | WL_POINTER_MOTION; p[2] = display->pointer_x; @@ -605,11 +610,16 @@ void wl_display_post_absolute_event(struct wl_display *display, struct wl_object *source, int x, int y) { + const struct wl_compositor_interface *interface; uint32_t p[4]; display->pointer_x = x; display->pointer_y = y; + interface = display->compositor->interface; + interface->notify_pointer_motion(display->compositor, source, + display->pointer_x, display->pointer_y); + p[0] = source->id; p[1] = (sizeof p << 16) | WL_POINTER_MOTION; p[2] = display->pointer_x; diff --git a/wayland.h b/wayland.h index 64a1c360..b82dfaec 100644 --- a/wayland.h +++ b/wayland.h @@ -159,6 +159,10 @@ struct wl_compositor_interface { struct wl_surface *surface, int32_t x, int32_t y, int32_t width, int32_t height); + void (*notify_pointer_motion)(struct wl_compositor *compositor, + struct wl_object *source, + int32_t x, int32_t y); + }; void wl_display_set_compositor(struct wl_display *display,