diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index fc54ac8..05a4d50 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -58,6 +58,18 @@ struct _MwLLWaylandSublevel { MwLL topmost_parent; /* The parent at the top of all the other parents. Usually a toplevel. */ }; +/* Shared set of anything needed for a shm buffer. Used both for surface framebuffers, and cursors. */ +struct _MwLLWaylandShmBuffer { + struct wl_shm* shm; + struct wl_shm_pool* shm_pool; + struct wl_buffer* shm_buffer; + MwU8* buf; + MwU64 buf_size; + int fd; + MwBool setup; + struct wl_surface* surface; +}; + struct _MwLLWayland { struct _MwLLCommon common; @@ -88,10 +100,12 @@ struct _MwLLWayland { struct wl_display* display; struct wl_registry* registry; struct wl_compositor* compositor; - struct wl_surface* surface; struct wl_registry_listener registry_listener; struct wl_region* region; + struct wl_pointer* pointer; + MwU32 pointer_serial; + MwBool active; /* Whether or not the surface is the one being hovered over. */ MwU32 mod_state; @@ -102,12 +116,8 @@ struct _MwLLWayland { MwU32 x, y, ww, wh; /* Window position */ MwPoint cur_mouse_pos; /* Currently known mouse position */ - struct wl_shm* shm; - struct wl_shm_pool* shm_pool; - struct wl_buffer* shm_buffer; - void* mapped_shm_buf; - MwU64 mapped_shm_buf_size; - int shm_fd; + struct _MwLLWaylandShmBuffer framebuffer; + struct _MwLLWaylandShmBuffer cursor; cairo_surface_t* cs; cairo_t* cairo; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 4a7fe67..5695a83 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -17,10 +17,10 @@ #include #endif -/* Setup the wl_shm buffer with the saved width/height */ -static void buffer_setup(struct _MwLLWayland* wayland); -/* Destroy the wl_shm buffer */ -static void buffer_destroy(struct _MwLLWayland* handle); +/* Setup the framebuffer with the saved width/height */ +static void framebuffer_setup(struct _MwLLWayland* wayland); +/* Destroy the framebuffer */ +static void framebuffer_destroy(struct _MwLLWayland* handle); static void region_setup(MwLL handle); static void region_invalidate(MwLL handle); @@ -54,6 +54,10 @@ static void protocol_removed(void* data, static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + MwLL self = data; + self->wayland.pointer_serial = serial; + + wl_pointer_set_cursor(wl_pointer, serial, self->wayland.cursor.surface, 0, 0); }; /* `wl_pointer.leave` callback */ @@ -288,8 +292,8 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, wl_keyboard_add_listener(keyboard, &keyboard_listener, data); } if(capabilities & WL_SEAT_CAPABILITY_POINTER) { - struct wl_pointer* pointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(pointer, &pointer_listener, data); + self->wayland.pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data); } }; @@ -393,8 +397,8 @@ static void xdg_toplevel_configure(void* data, self->wayland.wh = height; xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); - buffer_destroy(&self->wayland); - buffer_setup(&self->wayland); + framebuffer_destroy(&self->wayland); + framebuffer_setup(&self->wayland); region_setup(self); MwLLDispatch(self, resize, NULL); @@ -436,7 +440,7 @@ static void xdg_surface_configure( xdg_surface_ack_configure(xdg_surface, serial); if(self->wayland.configured) { - wl_surface_commit(self->wayland.surface); + wl_surface_commit(self->wayland.framebuffer.surface); } self->wayland.configured = MwTRUE; @@ -445,76 +449,80 @@ static void xdg_surface_configure( /* wl_shm setup function */ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + wayland->framebuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + wayland->cursor.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); return NULL; } -static void update_buffer(MwLL handle) { - fsync(handle->wayland.shm_fd); +static void update_framebuffer(struct _MwLLWayland* wayland) { + struct _MwLLWaylandShmBuffer* buffer = &wayland->framebuffer; + fsync(buffer->fd); - if(handle->wayland.configured) { - wl_surface_attach(handle->wayland.surface, handle->wayland.shm_buffer, 0, 0); - wl_surface_commit(handle->wayland.surface); + if(wayland->configured && buffer->setup) { + wl_surface_attach(wayland->framebuffer.surface, buffer->shm_buffer, wayland->x, wayland->y); + wl_surface_commit(wayland->framebuffer.surface); } } -static void buffer_setup(struct _MwLLWayland* wayland) { +static void buffer_setup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { int x, y; - int stride = wayland->ww * 4; + int stride = width * 4; char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; - wayland->mapped_shm_buf_size = wayland->ww * wayland->wh * 4; + buffer->buf_size = width * height * 4; - wayland->shm_fd = mkstemp(temp_name); + buffer->fd = mkstemp(temp_name); unlink(temp_name); - if(posix_fallocate(wayland->shm_fd, 0, wayland->mapped_shm_buf_size) != 0) { + if(posix_fallocate(buffer->fd, 0, buffer->buf_size) != 0) { printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); - close(wayland->shm_fd); + close(buffer->fd); return; } - if(ftruncate(wayland->shm_fd, wayland->mapped_shm_buf_size) != 0) { + if(ftruncate(buffer->fd, buffer->buf_size) != 0) { printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); - close(wayland->shm_fd); + close(buffer->fd); return; } - wayland->mapped_shm_buf = mmap(NULL, wayland->mapped_shm_buf_size, PROT_WRITE, MAP_SHARED, wayland->shm_fd, 0); + buffer->buf = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd, 0); - fsync(wayland->shm_fd); + fsync(buffer->fd); - if(!(wayland->shm_pool = wl_shm_create_pool(wayland->shm, wayland->shm_fd, wayland->mapped_shm_buf_size))) { + if(!(buffer->shm_pool = wl_shm_create_pool(buffer->shm, buffer->fd, buffer->buf_size))) { printf("failure setting up wl_shm: could not create pool.\n"); } - wayland->shm_buffer = wl_shm_pool_create_buffer(wayland->shm_pool, 0, wayland->ww, wayland->wh, stride, WL_SHM_FORMAT_ARGB8888); - - if(wayland->configured) { - wl_surface_attach(wayland->surface, wayland->shm_buffer, 0, 0); - wl_surface_commit(wayland->surface); - } - - wayland->cs = cairo_image_surface_create_for_data(wayland->mapped_shm_buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); - wayland->cairo = cairo_create(wayland->cs); - - memset(wayland->mapped_shm_buf, 255, wayland->mapped_shm_buf_size); - update_buffer((MwLL)wayland); + buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + buffer->setup = MwTRUE; } -static void buffer_destroy(struct _MwLLWayland* wayland) { - if(!wayland->configured) { +static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer) { + if(!buffer->setup) { return; } + wl_buffer_destroy(buffer->shm_buffer); + wl_shm_pool_destroy(buffer->shm_pool); + close(buffer->fd); + buffer->setup = MwFALSE; +} + +static void framebuffer_setup(struct _MwLLWayland* wayland) { + buffer_setup(&wayland->framebuffer, wayland->ww, wayland->wh); + + wayland->cs = cairo_image_surface_create_for_data(wayland->framebuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); + wayland->cairo = cairo_create(wayland->cs); + + memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); + update_framebuffer(wayland); +}; +static void framebuffer_destroy(struct _MwLLWayland* wayland) { + buffer_destroy(&wayland->framebuffer); cairo_destroy(wayland->cairo); cairo_surface_destroy(wayland->cs); - - wl_buffer_destroy(wayland->shm_buffer); - // munmap(wayland->mapped_shm_buf, wayland->mapped_shm_buf_size); - wl_shm_pool_destroy(wayland->shm_pool); - close(wayland->shm_fd); -} +}; static void region_invalidate(MwLL handle) { if(!handle->wayland.configured) { @@ -527,8 +535,8 @@ static void region_setup(MwLL handle) { return; } wl_region_add(handle->wayland.region, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); - wl_surface_set_input_region(handle->wayland.surface, handle->wayland.region); - wl_surface_set_opaque_region(handle->wayland.surface, handle->wayland.region); + wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); + wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); } /* Standard Wayland event loop. */ @@ -574,7 +582,7 @@ static int event_loop(MwLL handle) { if(!poll(&fd, 1, timeout)) { wl_display_cancel_read(handle->wayland.display); /* In this case, we need to commit the surface for any animations, etc. */ - wl_surface_commit(handle->wayland.surface); + wl_surface_commit(handle->wayland.framebuffer.surface); return 0; } @@ -630,6 +638,8 @@ static void setup_toplevel(MwLL r, int x, int y) { return; } + r->wayland.framebuffer.surface = NULL; + /* Do a roundtrip to ensure all interfaces are setup. */ r->wayland.registry = wl_display_get_registry(r->wayland.display); wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); @@ -642,9 +652,9 @@ static void setup_toplevel(MwLL r, int x, int y) { r->wayland.toplevel->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); /* Create a wl_surface, a xdg_surface and a xdg_toplevel */ - r->wayland.surface = wl_compositor_create_surface(r->wayland.compositor); + r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); r->wayland.toplevel->xdg_surface = - xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.surface); + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); /* setup mandatory listeners */ @@ -661,7 +671,7 @@ static void setup_toplevel(MwLL r, int x, int y) { xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp"); /* Perform the initial commit and wait for the first configure event */ - wl_surface_commit(r->wayland.surface); + wl_surface_commit(r->wayland.framebuffer.surface); event_loop(r); /* setup decorations if we can */ @@ -685,7 +695,7 @@ static void setup_toplevel(MwLL r, int x, int y) { /* Sublevel setup function */ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { struct wl_compositor* compositor = parent->wayland.compositor; - struct wl_surface* parent_surface = parent->wayland.surface; + struct wl_surface* parent_surface = parent->wayland.framebuffer.surface; r->wayland.sublevel = malloc(sizeof(struct _MwLLWaylandSublevel)); @@ -693,7 +703,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { r->wayland.display = parent->wayland.display; - r->wayland.surface = wl_compositor_create_surface(compositor); + r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); setup_callbacks(&r->wayland); @@ -709,7 +719,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { return; } - r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.surface, parent_surface); + r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.framebuffer.surface, parent_surface); wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); @@ -719,6 +729,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); r->common.type = MwLLBackendWayland; @@ -746,7 +757,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_sublevel(parent, r, x, y); } - buffer_setup(&r->wayland); + framebuffer_setup(&r->wayland); r->wayland.region = wl_compositor_create_region(r->wayland.compositor); region_setup(r); @@ -759,7 +770,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); - buffer_destroy(&handle->wayland); + buffer_destroy(&handle->wayland.framebuffer); + buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); free(handle); @@ -802,8 +814,8 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { refresh: region_setup(handle); - buffer_destroy(&handle->wayland); - buffer_setup(&handle->wayland); + framebuffer_destroy(&handle->wayland); + framebuffer_setup(&handle->wayland); MwLLDispatch(handle, draw, NULL); } @@ -844,7 +856,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { } static void MwLLEndDrawImpl(MwLL handle) { - update_buffer(handle); + update_framebuffer(&handle->wayland); } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -944,7 +956,7 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } static void MwLLForceRenderImpl(MwLL handle) { - wl_surface_damage(handle->wayland.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); /* if(handle->wayland.egl_setup) { @@ -954,6 +966,53 @@ static void MwLLForceRenderImpl(MwLL handle) { } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + int x, y; + + if(handle->wayland.cursor.setup) { + buffer_destroy(&handle->wayland.cursor); + wl_surface_destroy(handle->wayland.cursor.surface); + } + buffer_setup(&handle->wayland.cursor, image->width, image->height); + memset(handle->wayland.cursor.buf, 0, handle->wayland.cursor.buf_size); + + for(y = 0; y < mask->height; y++) { + unsigned int d = mask->data[y]; + for(x = mask->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * mask->width) + x) * 4; + + if(d & 1) { + handle->wayland.cursor.buf[idx + 3] = 255; + }; + d = d >> 1; + } + } + for(y = 0; y < image->height; y++) { + unsigned int d = image->data[y]; + for(x = image->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * image->width) + x) * 4; + + if(d & 1) { + px = 255; + }; + + handle->wayland.cursor.buf[idx] = px; + handle->wayland.cursor.buf[idx + 1] = px; + handle->wayland.cursor.buf[idx + 2] = px; + d = d >> 1; + } + } + + handle->wayland.cursor.surface = wl_compositor_create_surface(handle->wayland.compositor); + + wl_surface_attach(handle->wayland.cursor.surface, handle->wayland.cursor.shm_buffer, 0, 0); + wl_surface_commit(handle->wayland.cursor.surface); + + /* If there's currently a pointer, set it up. (Otherwise, it'll be setup during the pointer enter event) */ + if(handle->wayland.pointer != NULL) { + wl_pointer_set_cursor(handle->wayland.pointer, handle->wayland.pointer_serial, handle->wayland.cursor.surface, 0, 0); + } } static void MwLLDetachImpl(MwLL handle, MwPoint* point) {