From 1b6c7293608717943a296675b1ab228fed72277c Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 29 Oct 2017 09:09:21 +0100 Subject: [PATCH 01/18] Add wlr_output_cursor --- backend/drm/drm.c | 61 +++--- include/wlr/types/wlr_cursor.h | 20 +- include/wlr/types/wlr_output.h | 45 ++-- types/wlr_cursor.c | 33 ++- types/wlr_output.c | 372 ++++++++++++++++----------------- 5 files changed, 280 insertions(+), 251 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 27a8490c..e3f2bfe1 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -558,36 +558,37 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, } } - switch (output->transform) { - case WL_OUTPUT_TRANSFORM_90: - output->cursor.hotspot_x = hotspot_x; - output->cursor.hotspot_y = -plane->surf.height + hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_180: - output->cursor.hotspot_x = plane->surf.width - hotspot_x; - output->cursor.hotspot_y = plane->surf.height - hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_270: - output->cursor.hotspot_x = -plane->surf.height + hotspot_x; - output->cursor.hotspot_y = hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED: - output->cursor.hotspot_x = plane->surf.width - hotspot_x; - output->cursor.hotspot_y = hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - output->cursor.hotspot_x = hotspot_x; - output->cursor.hotspot_y = -hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - output->cursor.hotspot_x = hotspot_x; - output->cursor.hotspot_y = plane->surf.height - hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - output->cursor.hotspot_x = -plane->surf.height + hotspot_x; - output->cursor.hotspot_y = plane->surf.width - hotspot_y; - break; - } + // TODO: this doesn't belong here + // switch (output->transform) { + // case WL_OUTPUT_TRANSFORM_90: + // output->cursor.hotspot_x = hotspot_x; + // output->cursor.hotspot_y = -plane->surf.height + hotspot_y; + // break; + // case WL_OUTPUT_TRANSFORM_180: + // output->cursor.hotspot_x = plane->surf.width - hotspot_x; + // output->cursor.hotspot_y = plane->surf.height - hotspot_y; + // break; + // case WL_OUTPUT_TRANSFORM_270: + // output->cursor.hotspot_x = -plane->surf.height + hotspot_x; + // output->cursor.hotspot_y = hotspot_y; + // break; + // case WL_OUTPUT_TRANSFORM_FLIPPED: + // output->cursor.hotspot_x = plane->surf.width - hotspot_x; + // output->cursor.hotspot_y = hotspot_y; + // break; + // case WL_OUTPUT_TRANSFORM_FLIPPED_90: + // output->cursor.hotspot_x = hotspot_x; + // output->cursor.hotspot_y = -hotspot_y; + // break; + // case WL_OUTPUT_TRANSFORM_FLIPPED_180: + // output->cursor.hotspot_x = hotspot_x; + // output->cursor.hotspot_y = plane->surf.height - hotspot_y; + // break; + // case WL_OUTPUT_TRANSFORM_FLIPPED_270: + // output->cursor.hotspot_x = -plane->surf.height + hotspot_x; + // output->cursor.hotspot_y = plane->surf.width - hotspot_y; + // break; + // } if (!update_pixels) { // Only update the cursor hotspot diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index e8c13b1d..be4f322f 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -48,10 +48,10 @@ void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur); * Returns true when the mouse warp was successful. */ bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, - double x, double y); + double x, double y); void wlr_cursor_warp_absolute(struct wlr_cursor *cur, - struct wlr_input_device *dev, double x_mm, double y_mm); + struct wlr_input_device *dev, double x_mm, double y_mm); /** * Move the cursor in the direction of the given x and y coordinates. @@ -60,7 +60,13 @@ void wlr_cursor_warp_absolute(struct wlr_cursor *cur, * device mapping constraints will be ignored. */ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, - double delta_x, double delta_y); + double delta_x, double delta_y); + +void wlr_cursor_set_image(struct wlr_cursor *cur, const uint8_t *pixels, + int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, + int32_t hotspot_y); +void wlr_cursor_set_surface(struct wlr_cursor *cur, struct wlr_surface *surface, + int32_t hotspot_x, int32_t hotspot_y); /** * Attaches this input device to this cursor. The input device must be one of: @@ -80,7 +86,7 @@ void wlr_cursor_detach_input_device(struct wlr_cursor *cur, * direction and do not support absolute input events. */ void wlr_cursor_attach_output_layout(struct wlr_cursor *cur, - struct wlr_output_layout *l); + struct wlr_output_layout *l); /** * Attaches this cursor to the given output, which must be among the outputs in @@ -88,7 +94,7 @@ void wlr_cursor_attach_output_layout(struct wlr_cursor *cur, * without an associated output layout. */ void wlr_cursor_map_to_output(struct wlr_cursor *cur, - struct wlr_output *output); + struct wlr_output *output); /** * Maps all input from a specific input device to a given output. The input @@ -96,7 +102,7 @@ void wlr_cursor_map_to_output(struct wlr_cursor *cur, * outputs in the attached output layout. */ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, - struct wlr_input_device *dev, struct wlr_output *output); + struct wlr_input_device *dev, struct wlr_output *output); /** * Maps this cursor to an arbitrary region on the associated wlr_output_layout. @@ -108,6 +114,6 @@ void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_box *box); * wlr_output_layout. */ void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, - struct wlr_input_device *dev, struct wlr_box *box); + struct wlr_input_device *dev, struct wlr_box *box); #endif diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 74eb15ed..b6ea3a47 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -12,6 +12,21 @@ struct wlr_output_mode { struct wl_list link; }; +struct wlr_output_cursor { + struct wlr_output *output; + int32_t x, y; + int32_t hotspot_x, hotspot_y; + struct wl_list link; + + struct wlr_renderer *renderer; + struct wlr_texture *texture; + + // only when using a cursor surface + struct wlr_surface *surface; + struct wl_listener surface_commit; + struct wl_listener surface_destroy; +}; + struct wlr_output_impl; struct wlr_output { @@ -44,19 +59,8 @@ struct wlr_output { struct wl_signal destroy; } events; - struct { - bool is_sw; - int32_t x, y; - uint32_t width, height; - int32_t hotspot_x, hotspot_y; - struct wlr_renderer *renderer; - struct wlr_texture *texture; - - // only when using a cursor surface - struct wlr_surface *surface; - struct wl_listener surface_commit; - struct wl_listener surface_destroy; - } cursor; + struct wl_list cursors; // wlr_output_cursor::link + struct wlr_output_cursor *hardware_cursor; // the output position in layout space reported to clients int32_t lx, ly; @@ -72,12 +76,6 @@ bool wlr_output_set_mode(struct wlr_output *output, void wlr_output_transform(struct wlr_output *output, enum wl_output_transform transform); void wlr_output_set_position(struct wlr_output *output, int32_t lx, int32_t ly); -bool wlr_output_set_cursor(struct wlr_output *output, - const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height, - int32_t hotspot_x, int32_t hotspot_y); -void wlr_output_set_cursor_surface(struct wlr_output *output, - struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y); -bool wlr_output_move_cursor(struct wlr_output *output, int x, int y); void wlr_output_destroy(struct wlr_output *output); void wlr_output_effective_resolution(struct wlr_output *output, int *width, int *height); @@ -87,4 +85,13 @@ void wlr_output_set_gamma(struct wlr_output *output, uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); uint32_t wlr_output_get_gamma_size(struct wlr_output *output); +struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output); +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); +void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, + struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y); +bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, int x, int y); +void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor); + #endif diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 20781f0a..f07b57ab 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -33,9 +33,16 @@ struct wlr_cursor_device { struct wl_listener destroy; }; +struct wlr_cursor_output_cursor { + struct wlr_cursor *cursor; + struct wlr_output_cursor *output_cursor; + struct wl_list link; +}; + struct wlr_cursor_state { struct wlr_cursor *cursor; - struct wl_list devices; + struct wl_list devices; // wlr_cursor_device::link + struct wl_list output_cursors; // wlr_cursor_output_cursor::link struct wlr_output_layout *layout; struct wlr_xcursor *xcursor; struct wlr_output *mapped_output; @@ -132,16 +139,15 @@ static void wlr_cursor_warp_unchecked(struct wlr_cursor *cur, double x, double y) { assert(cur->state->layout); - struct wlr_output_layout_output *l_output; - wl_list_for_each(l_output, &cur->state->layout->outputs, link) { + struct wlr_cursor_output_cursor *output_cursor; + wl_list_for_each(output_cursor, &cur->state->output_cursors, link) { double output_x = x; double output_y = y; - wlr_output_layout_output_coords(cur->state->layout, - l_output->output, &output_x, &output_y); - wlr_output_move_cursor(l_output->output, - output_x - l_output->output->cursor.hotspot_x, - output_y - l_output->output->cursor.hotspot_y); + output_cursor->output_cursor->output, &output_x, &output_y); + wlr_output_cursor_move(output_cursor->output_cursor, + output_x - output_cursor->output_cursor->hotspot_x, + output_y - output_cursor->output_cursor->hotspot_y); } cur->x = x; @@ -254,6 +260,17 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, wlr_cursor_warp_unchecked(cur, x, y); } +void wlr_cursor_set_image(struct wlr_cursor *cur, const uint8_t *pixels, + int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, + int32_t hotspot_y) { + // TODO +} + +void wlr_cursor_set_surface(struct wlr_cursor *cur, struct wlr_surface *surface, + int32_t hotspot_x, int32_t hotspot_y) { + // TODO +} + static void handle_pointer_motion(struct wl_listener *listener, void *data) { struct wlr_event_pointer_motion *event = data; struct wlr_cursor_device *device = diff --git a/types/wlr_output.c b/types/wlr_output.c index e8d4af3e..338494b6 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -188,94 +188,159 @@ void wlr_output_set_position(struct wlr_output *output, int32_t lx, } } -static bool set_cursor(struct wlr_output *output, const uint8_t *buf, - int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, - int32_t hotspot_y) { - if (output->impl->set_cursor - && output->impl->set_cursor(output, buf, stride, width, height, - hotspot_x, hotspot_y, true)) { - output->cursor.is_sw = false; - return true; +void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, + const struct wlr_output_impl *impl) { + output->backend = backend; + output->impl = impl; + wl_list_init(&output->modes); + output->transform = WL_OUTPUT_TRANSFORM_NORMAL; + output->scale = 1; + wl_list_init(&output->cursors); + wl_signal_init(&output->events.frame); + wl_signal_init(&output->events.swap_buffers); + wl_signal_init(&output->events.resolution); + wl_signal_init(&output->events.destroy); +} + +void wlr_output_destroy(struct wlr_output *output) { + if (!output) { + return; } - wlr_log(L_INFO, "Falling back to software cursor"); + wl_signal_emit(&output->events.destroy, output); - output->cursor.is_sw = true; - output->cursor.width = width; - output->cursor.height = height; + struct wlr_output_mode *mode, *tmp_mode; + wl_list_for_each_safe(mode, tmp_mode, &output->modes, link) { + free(mode); + } + wl_list_remove(&output->modes); + if (output->impl && output->impl->destroy) { + output->impl->destroy(output); + } else { + free(output); + } +} - if (!output->cursor.renderer) { - output->cursor.renderer = wlr_gles2_renderer_create(output->backend); - if (!output->cursor.renderer) { - return false; - } +void wlr_output_effective_resolution(struct wlr_output *output, + int *width, int *height) { + // TODO: Scale factor + if (output->transform % 2 == 1) { + *width = output->height; + *height = output->width; + } else { + *width = output->width; + *height = output->height; } +} - if (!output->cursor.texture) { - output->cursor.texture = - wlr_render_texture_create(output->cursor.renderer); - if (!output->cursor.texture) { - return false; - } +void wlr_output_make_current(struct wlr_output *output) { + output->impl->make_current(output); +} + +static void output_cursor_render(struct wlr_output_cursor *cursor) { + struct wlr_texture *texture = cursor->texture; + struct wlr_renderer *renderer = cursor->renderer; + if (cursor->surface != NULL) { + texture = cursor->surface->texture; + renderer = cursor->surface->renderer; } - return wlr_texture_upload_pixels(output->cursor.texture, - WL_SHM_FORMAT_ARGB8888, stride, width, height, buf); + // We check texture->valid because some clients set a cursor surface + // with a NULL buffer to hide it + if (renderer && texture && texture->valid) { + glViewport(0, 0, cursor->output->width, cursor->output->height); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + float matrix[16]; + wlr_texture_get_matrix(texture, &matrix, + &cursor->output->transform_matrix, cursor->x, cursor->y); + wlr_render_with_matrix(renderer, texture, &matrix); + } } -bool wlr_output_set_cursor(struct wlr_output *output, - const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height, - int32_t hotspot_x, int32_t hotspot_y) { - if (output->cursor.surface) { - wl_list_remove(&output->cursor.surface_commit.link); - wl_list_remove(&output->cursor.surface_destroy.link); - output->cursor.surface = NULL; +void wlr_output_swap_buffers(struct wlr_output *output) { + struct wlr_output_cursor *cursor; + wl_list_for_each(cursor, &output->cursors, link) { + if (output->hardware_cursor == cursor) { + continue; + } + output_cursor_render(cursor); } - output->cursor.hotspot_x = hotspot_x; - output->cursor.hotspot_y = hotspot_y; + wl_signal_emit(&output->events.swap_buffers, &output); - return set_cursor(output, buf, stride, width, height, hotspot_x, hotspot_y); + output->impl->swap_buffers(output); } -static inline int64_t timespec_to_msec(const struct timespec *a) { - return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; +void wlr_output_set_gamma(struct wlr_output *output, + uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { + if (output->impl->set_gamma) { + output->impl->set_gamma(output, size, r, g, b); + } } -static void commit_cursor_surface(struct wlr_output *output, - struct wlr_surface *surface) { - if (output->cursor.is_sw) { - return; +uint32_t wlr_output_get_gamma_size(struct wlr_output *output) { + if (!output->impl->get_gamma_size) { + return 0; + } + return output->impl->get_gamma_size(output); +} + +static void wlr_output_cursor_reset(struct wlr_output_cursor *cursor) { + if (cursor->surface != NULL) { + wl_list_remove(&cursor->surface_commit.link); + wl_list_remove(&cursor->surface_destroy.link); + cursor->surface = NULL; } +} - struct wl_shm_buffer *buffer = wl_shm_buffer_get(surface->current->buffer); - if (buffer == NULL) { - return; +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) { + wlr_output_cursor_reset(cursor); + cursor->hotspot_x = hotspot_x; + cursor->hotspot_y = hotspot_y; + + if (cursor->output->hardware_cursor == NULL && + cursor->output->impl->set_cursor && + cursor->output->impl->set_cursor(cursor->output, pixels, stride, + width, height, hotspot_x, hotspot_y, true)) { + cursor->output->hardware_cursor = cursor; + return true; } - uint32_t format = wl_shm_buffer_get_format(buffer); - if (format != WL_SHM_FORMAT_ARGB8888) { - return; + wlr_log(L_INFO, "Falling back to software cursor"); + + if (cursor->renderer == NULL) { + cursor->renderer = wlr_gles2_renderer_create(cursor->output->backend); + if (cursor->renderer == NULL) { + return false; + } + } + + if (cursor->texture == NULL) { + cursor->texture = wlr_render_texture_create(cursor->renderer); + if (cursor->texture == NULL) { + return false; + } } - void *buffer_data = wl_shm_buffer_get_data(buffer); - int32_t width = wl_shm_buffer_get_width(buffer); - int32_t height = wl_shm_buffer_get_height(buffer); - int32_t stride = wl_shm_buffer_get_stride(buffer); - wl_shm_buffer_begin_access(buffer); - wlr_output_set_cursor(output, buffer_data, stride/4, width, height, - output->cursor.hotspot_x - surface->current->sx, - output->cursor.hotspot_y - surface->current->sy); - wl_shm_buffer_end_access(buffer); + return wlr_texture_upload_pixels(cursor->texture, WL_SHM_FORMAT_ARGB8888, + stride, width, height, pixels); } -static void handle_cursor_surface_commit(struct wl_listener *listener, +static inline int64_t timespec_to_msec(const struct timespec *a) { + return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; +} + +static void output_cursor_handle_commit(struct wl_listener *listener, void *data) { - struct wlr_output *output = wl_container_of(listener, output, - cursor.surface_commit); + struct wlr_output_cursor *cursor = wl_container_of(listener, cursor, + surface_commit); struct wlr_surface *surface = data; - commit_cursor_surface(output, surface); + // TODO: if hardware cursor, upload pixels struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -288,170 +353,103 @@ static void handle_cursor_surface_commit(struct wl_listener *listener, } } -static void handle_cursor_surface_destroy(struct wl_listener *listener, +static void output_cursor_handle_destroy(struct wl_listener *listener, void *data) { - struct wlr_output *output = wl_container_of(listener, output, - cursor.surface_destroy); - - wl_list_remove(&output->cursor.surface_commit.link); - wl_list_remove(&output->cursor.surface_destroy.link); - output->cursor.surface = NULL; + struct wlr_output_cursor *cursor = wl_container_of(listener, cursor, + surface_destroy); + wlr_output_cursor_reset(cursor); } -void wlr_output_set_cursor_surface(struct wlr_output *output, +void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y) { if (surface && strcmp(surface->role, "wl_pointer-cursor") != 0) { return; } - output->cursor.hotspot_x = hotspot_x; - output->cursor.hotspot_y = hotspot_y; + cursor->hotspot_x = hotspot_x; + cursor->hotspot_y = hotspot_y; - if (surface && surface == output->cursor.surface) { - if (output->impl->set_cursor && !output->cursor.is_sw) { - // Only update the hotspot - output->impl->set_cursor(output, NULL, 0, 0, 0, hotspot_x, - hotspot_y, false); + if (surface && surface == cursor->surface) { + if (cursor->output->hardware_cursor == cursor && + cursor->output->impl->set_cursor) { + // If the surface hasn't changed and it's an hardware cursor, only + // update the hotspot + cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, 0, + hotspot_x, hotspot_y, false); } return; } - if (output->cursor.surface) { - wl_list_remove(&output->cursor.surface_commit.link); - wl_list_remove(&output->cursor.surface_destroy.link); - output->cursor.surface = NULL; - } + wlr_output_cursor_reset(cursor); - // Disable hardware cursor + // Disable hardware cursor for surfaces // TODO: support hardware cursors - output->cursor.is_sw = true; - if (output->impl->set_cursor) { - output->impl->set_cursor(output, NULL, 0, 0, 0, hotspot_x, hotspot_y, - true); + if (cursor->output->hardware_cursor == cursor && + cursor->output->impl->set_cursor) { + cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, 0, + hotspot_x, hotspot_y, true); + cursor->output->hardware_cursor = NULL; } - //output->cursor.is_sw = output->impl->set_cursor == NULL; - output->cursor.surface = surface; + cursor->surface = surface; if (surface != NULL) { - wl_signal_add(&surface->events.commit, &output->cursor.surface_commit); - wl_signal_add(&surface->events.destroy, - &output->cursor.surface_destroy); - commit_cursor_surface(output, surface); + wl_signal_add(&surface->events.commit, &cursor->surface_commit); + wl_signal_add(&surface->events.destroy, &cursor->surface_destroy); + // TODO: if hardware cursor, upload pixels } else { - set_cursor(output, NULL, 0, 0, 0, hotspot_x, hotspot_y); + // TODO: if hardware cursor, disable cursor } } -bool wlr_output_move_cursor(struct wlr_output *output, int x, int y) { - output->cursor.x = x; - output->cursor.y = y; +bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, int x, int y) { + cursor->x = x; + cursor->y = y; - if (output->cursor.is_sw) { + if (cursor->output->hardware_cursor != cursor) { return true; } - if (!output->impl->move_cursor) { + if (!cursor->output->impl->move_cursor) { return false; } - - return output->impl->move_cursor(output, x, y); + return cursor->output->impl->move_cursor(cursor->output, x, y); } -void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, - const struct wlr_output_impl *impl) { - output->backend = backend; - output->impl = impl; - wl_list_init(&output->modes); - output->transform = WL_OUTPUT_TRANSFORM_NORMAL; - output->scale = 1; - wl_signal_init(&output->events.frame); - wl_signal_init(&output->events.swap_buffers); - wl_signal_init(&output->events.resolution); - wl_signal_init(&output->events.destroy); - - wl_list_init(&output->cursor.surface_commit.link); - output->cursor.surface_commit.notify = handle_cursor_surface_commit; - wl_list_init(&output->cursor.surface_destroy.link); - output->cursor.surface_destroy.notify = handle_cursor_surface_destroy; +struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output) { + struct wlr_output_cursor *cursor = + calloc(1, sizeof(struct wlr_output_cursor)); + if (cursor == NULL) { + return NULL; + } + cursor->output = output; + wl_list_init(&cursor->surface_commit.link); + cursor->surface_commit.notify = output_cursor_handle_commit; + wl_list_init(&cursor->surface_destroy.link); + cursor->surface_destroy.notify = output_cursor_handle_destroy; + wl_list_insert(&output->cursors, &cursor->link); + return cursor; } -void wlr_output_destroy(struct wlr_output *output) { - if (!output) { +void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) { + if (cursor == NULL) { return; } - - wl_signal_emit(&output->events.destroy, output); - - wlr_texture_destroy(output->cursor.texture); - wlr_renderer_destroy(output->cursor.renderer); - - struct wlr_output_mode *mode, *tmp_mode; - wl_list_for_each_safe(mode, tmp_mode, &output->modes, link) { - free(mode); - } - wl_list_remove(&output->modes); - if (output->impl && output->impl->destroy) { - output->impl->destroy(output); - } else { - free(output); - } -} - -void wlr_output_effective_resolution(struct wlr_output *output, - int *width, int *height) { - // TODO: Scale factor - if (output->transform % 2 == 1) { - *width = output->height; - *height = output->width; - } else { - *width = output->width; - *height = output->height; - } -} - -void wlr_output_make_current(struct wlr_output *output) { - output->impl->make_current(output); -} - -void wlr_output_swap_buffers(struct wlr_output *output) { - if (output->cursor.is_sw) { - glViewport(0, 0, output->width, output->height); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - struct wlr_texture *texture = output->cursor.texture; - struct wlr_renderer *renderer = output->cursor.renderer; - if (output->cursor.surface) { - texture = output->cursor.surface->texture; - renderer = output->cursor.surface->renderer; - } - - // We check texture->valid because some clients set a cursor surface - // with a NULL buffer to hide it - if (renderer && texture && texture->valid) { - float matrix[16]; - wlr_texture_get_matrix(texture, &matrix, &output->transform_matrix, - output->cursor.x, output->cursor.y); - wlr_render_with_matrix(renderer, texture, &matrix); + wlr_output_cursor_reset(cursor); + if (cursor->output->hardware_cursor == cursor) { + // If this cursor was the hardware cursor, disable it + if (cursor->output->impl->set_cursor) { + cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, 0, 0, + 0, true); } + cursor->output->hardware_cursor = NULL; } - - wl_signal_emit(&output->events.swap_buffers, &output); - - output->impl->swap_buffers(output); -} - -void wlr_output_set_gamma(struct wlr_output *output, - uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { - if (output->impl->set_gamma) { - output->impl->set_gamma(output, size, r, g, b); + if (cursor->texture != NULL) { + wlr_texture_destroy(cursor->texture); } -} - -uint32_t wlr_output_get_gamma_size(struct wlr_output *output) { - if (!output->impl->get_gamma_size) { - return 0; + if (cursor->renderer != NULL) { + wlr_renderer_destroy(cursor->renderer); } - return output->impl->get_gamma_size(output); + wl_list_remove(&cursor->link); + free(cursor); } From c45f2eef0e0fb805d88b54b65db23bb8a49ebea6 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 29 Oct 2017 10:39:47 +0100 Subject: [PATCH 02/18] Fix rootston --- examples/pointer.c | 20 +++++--------------- rootston/cursor.c | 23 ++++------------------- rootston/output.c | 30 +++++++++++++----------------- 3 files changed, 22 insertions(+), 51 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index 66598ad4..b2fef4e8 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -93,8 +93,6 @@ static void handle_output_frame(struct output_state *output, static void handle_output_add(struct output_state *ostate) { struct sample_state *sample = ostate->compositor->data; - struct wlr_output *wlr_output = ostate->output; - struct wlr_xcursor_image *image = sample->xcursor->images[0]; struct output_config *o_config = example_config_get_output(sample->config, ostate->output); @@ -112,12 +110,9 @@ static void handle_output_add(struct output_state *ostate) { // TODO the cursor must be set depending on which surface it is displayed // over which should happen in the compositor. - if (!wlr_output_set_cursor(wlr_output, image->buffer, - image->width, image->width, image->height, - image->hotspot_x, image->hotspot_y)) { - wlr_log(L_DEBUG, "Failed to set hardware cursor"); - return; - } + struct wlr_xcursor_image *image = sample->xcursor->images[0]; + wlr_cursor_set_image(sample->cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); wlr_cursor_warp(sample->cursor, NULL, sample->cursor->x, sample->cursor->y); } @@ -162,13 +157,8 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, sample->cur_y = event->y_mm; struct wlr_xcursor_image *image = sample->xcursor->images[0]; - - struct output_state *output; - wl_list_for_each(output, &sample->compositor->outputs, link) { - wlr_output_move_cursor(output->output, - sample->cur_x - image->hotspot_x, - sample->cur_y - image->hotspot_y); - } + wlr_cursor_warp_absolute(sample->cursor, event->device, + sample->cur_x - image->hotspot_x, sample->cur_y - image->hotspot_y); } static void handle_cursor_button(struct wl_listener *listener, void *data) { diff --git a/rootston/cursor.c b/rootston/cursor.c index 3fa8afb6..7307b6b2 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -33,24 +33,8 @@ const struct roots_input_event *get_input_event(struct roots_input *input, static void cursor_set_xcursor_image(struct roots_input *input, struct wlr_xcursor_image *image) { - struct roots_output *output; - wl_list_for_each(output, &input->server->desktop->outputs, link) { - if (!wlr_output_set_cursor(output->wlr_output, image->buffer, - image->width, image->width, image->height, - image->hotspot_x, image->hotspot_y)) { - wlr_log(L_DEBUG, "Failed to set hardware cursor"); - return; - } - } -} - -static void cursor_set_surface(struct roots_input *input, - struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y) { - struct roots_output *output; - wl_list_for_each(output, &input->server->desktop->outputs, link) { - wlr_output_set_cursor_surface(output->wlr_output, surface, - hotspot_x, hotspot_y); - } + wlr_cursor_set_image(input->cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); } void view_begin_move(struct roots_input *input, struct wlr_cursor *cursor, @@ -487,7 +471,8 @@ static void handle_request_set_cursor(struct wl_listener *listener, } wlr_log(L_DEBUG, "Setting client cursor"); - cursor_set_surface(input, event->surface, event->hotspot_x, event->hotspot_y); + wlr_cursor_set_surface(input->cursor, event->surface, event->hotspot_x, + event->hotspot_y); input->cursor_client = event->seat_client->client; } diff --git a/rootston/output.c b/rootston/output.c index 6bc28996..6ca302d8 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -186,20 +186,20 @@ static void set_mode(struct wlr_output *output, struct output_config *oc) { } void output_add_notify(struct wl_listener *listener, void *data) { + struct roots_desktop *desktop = wl_container_of(listener, desktop, + output_add); struct wlr_output *wlr_output = data; - struct roots_desktop *desktop = wl_container_of(listener, desktop, output_add); struct roots_input *input = desktop->server->input; struct roots_config *config = desktop->config; wlr_log(L_DEBUG, "Output '%s' added", wlr_output->name); - wlr_log(L_DEBUG, "%s %s %"PRId32"mm x %"PRId32"mm", - wlr_output->make, wlr_output->model, - wlr_output->phys_width, wlr_output->phys_height); - if (wl_list_length(&wlr_output->modes) > 0) { - struct wlr_output_mode *mode = NULL; - mode = wl_container_of((&wlr_output->modes)->prev, mode, link); - wlr_output_set_mode(wlr_output, mode); - } + wlr_log(L_DEBUG, "%s %s %"PRId32"mm x %"PRId32"mm", wlr_output->make, + wlr_output->model, wlr_output->phys_width, wlr_output->phys_height); + if (wl_list_length(&wlr_output->modes) > 0) { + struct wlr_output_mode *mode = NULL; + mode = wl_container_of((&wlr_output->modes)->prev, mode, link); + wlr_output_set_mode(wlr_output, mode); + } struct roots_output *output = calloc(1, sizeof(struct roots_output)); clock_gettime(CLOCK_MONOTONIC, &output->last_frame); @@ -223,16 +223,12 @@ void output_add_notify(struct wl_listener *listener, void *data) { cursor_load_config(config, input->cursor, input, desktop); - struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme); - struct wlr_xcursor_image *image = xcursor->images[0]; // TODO the cursor must be set depending on which surface it is displayed // over which should happen in the compositor. - if (!wlr_output_set_cursor(wlr_output, image->buffer, - image->width, image->width, image->height, - image->hotspot_x, image->hotspot_y)) { - wlr_log(L_DEBUG, "Failed to set hardware cursor"); - return; - } + struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme); + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_cursor_set_image(input->cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); wlr_cursor_warp(input->cursor, NULL, input->cursor->x, input->cursor->y); } From 2e2d63a16482135bb61db6a24cd09cd04c068c22 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 29 Oct 2017 11:20:11 +0100 Subject: [PATCH 03/18] Manage wlr_output_cursor from wlr_cursor --- examples/pointer.c | 5 +-- include/wlr/types/wlr_output_layout.h | 5 +++ types/wlr_cursor.c | 60 +++++++++++++++++++++++++-- types/wlr_output_layout.c | 6 ++- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index b2fef4e8..26d50b95 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -156,9 +156,8 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, sample->cur_x = event->x_mm; sample->cur_y = event->y_mm; - struct wlr_xcursor_image *image = sample->xcursor->images[0]; - wlr_cursor_warp_absolute(sample->cursor, event->device, - sample->cur_x - image->hotspot_x, sample->cur_y - image->hotspot_y); + wlr_cursor_warp_absolute(sample->cursor, event->device, sample->cur_x, + sample->cur_y); } static void handle_cursor_button(struct wl_listener *listener, void *data) { diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index ea8dbcd2..a99debf6 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -12,6 +12,7 @@ struct wlr_output_layout { struct wlr_output_layout_state *state; struct { + struct wl_signal add; struct wl_signal change; struct wl_signal destroy; } events; @@ -24,6 +25,10 @@ struct wlr_output_layout_output { int x, y; struct wl_list link; struct wlr_output_layout_output_state *state; + + struct { + struct wl_signal destroy; + } events; }; struct wlr_output_layout *wlr_output_layout_create(); diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index f07b57ab..dac290cb 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -37,6 +37,8 @@ struct wlr_cursor_output_cursor { struct wlr_cursor *cursor; struct wlr_output_cursor *output_cursor; struct wl_list link; + + struct wl_listener layout_output_destroy; }; struct wlr_cursor_state { @@ -48,6 +50,7 @@ struct wlr_cursor_state { struct wlr_output *mapped_output; struct wlr_box *mapped_box; + struct wl_listener layout_add; struct wl_listener layout_change; struct wl_listener layout_destroy; }; @@ -70,6 +73,7 @@ struct wlr_cursor *wlr_cursor_create() { cur->state->mapped_output = NULL; wl_list_init(&cur->state->devices); + wl_list_init(&cur->state->output_cursors); // pointer signals wl_signal_init(&cur->events.motion); @@ -102,6 +106,7 @@ static void wlr_cursor_detach_output_layout(struct wlr_cursor *cur) { wl_list_remove(&cur->state->layout_destroy.link); wl_list_remove(&cur->state->layout_change.link); + wl_list_remove(&cur->state->layout_add.link); cur->state->layout = NULL; } @@ -263,12 +268,20 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, void wlr_cursor_set_image(struct wlr_cursor *cur, const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y) { - // TODO + struct wlr_cursor_output_cursor *output_cursor; + wl_list_for_each(output_cursor, &cur->state->output_cursors, link) { + wlr_output_cursor_set_image(output_cursor->output_cursor, pixels, + stride, width, height, hotspot_x, hotspot_y); + } } void wlr_cursor_set_surface(struct wlr_cursor *cur, struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y) { - // TODO + struct wlr_cursor_output_cursor *output_cursor; + wl_list_for_each(output_cursor, &cur->state->output_cursors, link) { + wlr_output_cursor_set_surface(output_cursor->output_cursor, surface, + hotspot_x, hotspot_y); + } } static void handle_pointer_motion(struct wl_listener *listener, void *data) { @@ -489,10 +502,50 @@ static void handle_layout_destroy(struct wl_listener *listener, void *data) { wlr_cursor_detach_output_layout(state->cursor); } +static void handle_layout_output_destroy(struct wl_listener *listener, + void *data) { + struct wlr_cursor_output_cursor *output_cursor = + wl_container_of(listener, output_cursor, layout_output_destroy); + //struct wlr_output_layout_output *l_output = data; + + wl_list_remove(&output_cursor->link); + wlr_output_cursor_destroy(output_cursor->output_cursor); + wl_list_remove(&output_cursor->layout_output_destroy.link); + free(output_cursor); +} + +static void handle_layout_add(struct wl_listener *listener, void *data) { + struct wlr_cursor_state *state = + wl_container_of(listener, state, layout_add); + struct wlr_output_layout_output *l_output = data; + + struct wlr_cursor_output_cursor *output_cursor = + calloc(1, sizeof(struct wlr_cursor_output_cursor)); + if (output_cursor == NULL) { + wlr_log(L_ERROR, "Failed to allocate wlr_cursor_output_cursor"); + return; + } + output_cursor->cursor = state->cursor; + + output_cursor->output_cursor = wlr_output_cursor_create(l_output->output); + if (output_cursor->output_cursor == NULL) { + wlr_log(L_ERROR, "Failed to create wlr_output_cursor"); + free(output_cursor); + return; + } + + output_cursor->layout_output_destroy.notify = handle_layout_output_destroy; + wl_signal_add(&l_output->events.destroy, + &output_cursor->layout_output_destroy); + + wl_list_insert(&state->cursor->state->output_cursors, &output_cursor->link); +} + static void handle_layout_change(struct wl_listener *listener, void *data) { struct wlr_cursor_state *state = wl_container_of(listener, state, layout_change); struct wlr_output_layout *layout = data; + if (!wlr_output_layout_contains_point(layout, NULL, state->cursor->x, state->cursor->y)) { // the output we were on has gone away so go to the closest boundary @@ -513,9 +566,10 @@ void wlr_cursor_attach_output_layout(struct wlr_cursor *cur, return; } + wl_signal_add(&l->events.add, &cur->state->layout_add); + cur->state->layout_add.notify = handle_layout_add; wl_signal_add(&l->events.change, &cur->state->layout_change); cur->state->layout_change.notify = handle_layout_change; - wl_signal_add(&l->events.destroy, &cur->state->layout_destroy); cur->state->layout_destroy.notify = handle_layout_destroy; diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 817a03f6..190f2733 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -35,6 +35,7 @@ struct wlr_output_layout *wlr_output_layout_create() { } wl_list_init(&layout->outputs); + wl_signal_init(&layout->events.add); wl_signal_init(&layout->events.change); wl_signal_init(&layout->events.destroy); @@ -43,6 +44,7 @@ struct wlr_output_layout *wlr_output_layout_create() { static void wlr_output_layout_output_destroy( struct wlr_output_layout_output *l_output) { + wl_signal_emit(&l_output->events.destroy, l_output); wl_list_remove(&l_output->state->resolution.link); wl_list_remove(&l_output->state->output_destroy.link); wl_list_remove(&l_output->link); @@ -155,7 +157,7 @@ static struct wlr_output_layout_output *wlr_output_layout_output_create( l_output->state->l_output = l_output; l_output->state->layout = layout; l_output->output = output; - + wl_signal_init(&l_output->events.destroy); wl_list_insert(&layout->outputs, &l_output->link); wl_signal_add(&output->events.resolution, &l_output->state->resolution); @@ -163,6 +165,8 @@ static struct wlr_output_layout_output *wlr_output_layout_output_create( wl_signal_add(&output->events.destroy, &l_output->state->output_destroy); l_output->state->output_destroy.notify = handle_output_destroy; + wl_signal_emit(&layout->events.add, l_output); + return l_output; } From 6656e25fd4c5575400a2a3bc4d94a8f834630c5e Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 29 Oct 2017 11:42:09 +0100 Subject: [PATCH 04/18] Transform cursor hotspot --- backend/drm/drm.c | 32 ------------------------ types/wlr_output.c | 62 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index e3f2bfe1..23b9a9fa 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -558,38 +558,6 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, } } - // TODO: this doesn't belong here - // switch (output->transform) { - // case WL_OUTPUT_TRANSFORM_90: - // output->cursor.hotspot_x = hotspot_x; - // output->cursor.hotspot_y = -plane->surf.height + hotspot_y; - // break; - // case WL_OUTPUT_TRANSFORM_180: - // output->cursor.hotspot_x = plane->surf.width - hotspot_x; - // output->cursor.hotspot_y = plane->surf.height - hotspot_y; - // break; - // case WL_OUTPUT_TRANSFORM_270: - // output->cursor.hotspot_x = -plane->surf.height + hotspot_x; - // output->cursor.hotspot_y = hotspot_y; - // break; - // case WL_OUTPUT_TRANSFORM_FLIPPED: - // output->cursor.hotspot_x = plane->surf.width - hotspot_x; - // output->cursor.hotspot_y = hotspot_y; - // break; - // case WL_OUTPUT_TRANSFORM_FLIPPED_90: - // output->cursor.hotspot_x = hotspot_x; - // output->cursor.hotspot_y = -hotspot_y; - // break; - // case WL_OUTPUT_TRANSFORM_FLIPPED_180: - // output->cursor.hotspot_x = hotspot_x; - // output->cursor.hotspot_y = plane->surf.height - hotspot_y; - // break; - // case WL_OUTPUT_TRANSFORM_FLIPPED_270: - // output->cursor.hotspot_x = -plane->surf.height + hotspot_x; - // output->cursor.hotspot_y = plane->surf.width - hotspot_y; - // break; - // } - if (!update_pixels) { // Only update the cursor hotspot return true; diff --git a/types/wlr_output.c b/types/wlr_output.c index 338494b6..cb48ad63 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -287,7 +287,7 @@ uint32_t wlr_output_get_gamma_size(struct wlr_output *output) { return output->impl->get_gamma_size(output); } -static void wlr_output_cursor_reset(struct wlr_output_cursor *cursor) { +static void output_cursor_reset(struct wlr_output_cursor *cursor) { if (cursor->surface != NULL) { wl_list_remove(&cursor->surface_commit.link); wl_list_remove(&cursor->surface_destroy.link); @@ -295,17 +295,53 @@ static void wlr_output_cursor_reset(struct wlr_output_cursor *cursor) { } } +static void output_cursor_set_hotspot(struct wlr_output_cursor *cursor, + int32_t hotspot_x, int32_t hotspot_y, uint32_t width, uint32_t height) { + switch (cursor->output->transform) { + case WL_OUTPUT_TRANSFORM_90: + cursor->hotspot_x = hotspot_x; + cursor->hotspot_y = -height + hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_180: + cursor->hotspot_x = width - hotspot_x; + cursor->hotspot_y = height - hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_270: + cursor->hotspot_x = -height + hotspot_x; + cursor->hotspot_y = hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED: + cursor->hotspot_x = width - hotspot_x; + cursor->hotspot_y = hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + cursor->hotspot_x = hotspot_x; + cursor->hotspot_y = -hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + cursor->hotspot_x = hotspot_x; + cursor->hotspot_y = height - hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + cursor->hotspot_x = -height + hotspot_x; + cursor->hotspot_y = width - hotspot_y; + break; + default: // WL_OUTPUT_TRANSFORM_NORMAL + cursor->hotspot_x = hotspot_x; + cursor->hotspot_y = hotspot_y; + } +} + 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) { - wlr_output_cursor_reset(cursor); - cursor->hotspot_x = hotspot_x; - cursor->hotspot_y = hotspot_y; + output_cursor_reset(cursor); + output_cursor_set_hotspot(cursor, hotspot_x, hotspot_y, width, height); if (cursor->output->hardware_cursor == NULL && cursor->output->impl->set_cursor && cursor->output->impl->set_cursor(cursor->output, pixels, stride, - width, height, hotspot_x, hotspot_y, true)) { + width, height, cursor->hotspot_x, cursor->hotspot_y, true)) { cursor->output->hardware_cursor = cursor; return true; } @@ -357,7 +393,7 @@ static void output_cursor_handle_destroy(struct wl_listener *listener, void *data) { struct wlr_output_cursor *cursor = wl_container_of(listener, cursor, surface_destroy); - wlr_output_cursor_reset(cursor); + output_cursor_reset(cursor); } void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, @@ -366,8 +402,8 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, return; } - cursor->hotspot_x = hotspot_x; - cursor->hotspot_y = hotspot_y; + output_cursor_set_hotspot(cursor, hotspot_x, hotspot_y, + surface->current->width, surface->current->height); if (surface && surface == cursor->surface) { if (cursor->output->hardware_cursor == cursor && @@ -375,19 +411,19 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, // If the surface hasn't changed and it's an hardware cursor, only // update the hotspot cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, 0, - hotspot_x, hotspot_y, false); + cursor->hotspot_x, cursor->hotspot_y, false); } return; } - wlr_output_cursor_reset(cursor); + output_cursor_reset(cursor); // Disable hardware cursor for surfaces // TODO: support hardware cursors if (cursor->output->hardware_cursor == cursor && cursor->output->impl->set_cursor) { - cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, 0, - hotspot_x, hotspot_y, true); + cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, 0, 0, 0, + true); cursor->output->hardware_cursor = NULL; } @@ -435,7 +471,7 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) { if (cursor == NULL) { return; } - wlr_output_cursor_reset(cursor); + output_cursor_reset(cursor); if (cursor->output->hardware_cursor == cursor) { // If this cursor was the hardware cursor, disable it if (cursor->output->impl->set_cursor) { From 95566c6bdfb7048b2460b701747f4c9d3fcd4ebd Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 29 Oct 2017 17:43:26 +0100 Subject: [PATCH 05/18] Transform cursor hotspot, fix wayland cursor hotspot --- backend/wayland/output.c | 108 ++++++++++++++------------- backend/wayland/wl_seat.c | 4 +- include/backend/wayland.h | 17 +++-- include/wlr/types/wlr_output.h | 1 + types/wlr_cursor.c | 5 +- types/wlr_output.c | 129 ++++++++++++++++++++------------- 6 files changed, 152 insertions(+), 112 deletions(-) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 0dde343c..c336eeb7 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -55,25 +55,27 @@ static void wlr_wl_output_transform(struct wlr_output *_output, static bool wlr_wl_output_set_cursor(struct wlr_output *_output, const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y, bool update_pixels) { - struct wlr_wl_backend_output *output = (struct wlr_wl_backend_output *)_output; + struct wlr_wl_backend_output *output = + (struct wlr_wl_backend_output *)_output; struct wlr_wl_backend *backend = output->backend; + output->cursor.hotspot_x = hotspot_x; + output->cursor.hotspot_y = hotspot_y; + if (!update_pixels) { // Update hotspot without changing cursor image - wlr_wl_output_update_cursor(output, output->enter_serial, hotspot_x, - hotspot_y); + wlr_wl_output_update_cursor(output); return true; } if (!buf) { // Hide cursor - if (output->cursor_surface) { - wl_surface_destroy(output->cursor_surface); - munmap(output->cursor_data, output->cursor_buf_size); - output->cursor_surface = NULL; - output->cursor_buf_size = 0; + if (output->cursor.surface) { + wl_surface_destroy(output->cursor.surface); + munmap(output->cursor.data, output->cursor.buf_size); + output->cursor.surface = NULL; + output->cursor.buf_size = 0; } - wlr_wl_output_update_cursor(output, output->enter_serial, hotspot_x, - hotspot_y); + wlr_wl_output_update_cursor(output); return true; } @@ -84,73 +86,77 @@ static bool wlr_wl_output_set_cursor(struct wlr_output *_output, return false; } - if (!output->cursor_surface) { - output->cursor_surface = wl_compositor_create_surface(output->backend->compositor); + if (!output->cursor.surface) { + output->cursor.surface = + wl_compositor_create_surface(output->backend->compositor); } uint32_t size = stride * height; - if (output->cursor_buf_size != size) { - if (output->cursor_buffer) { - wl_buffer_destroy(output->cursor_buffer); + if (output->cursor.buf_size != size) { + if (output->cursor.buffer) { + wl_buffer_destroy(output->cursor.buffer); } - if (size > output->cursor_buf_size) { - if (output->cursor_pool) { - wl_shm_pool_destroy(output->cursor_pool); - output->cursor_pool = NULL; - munmap(output->cursor_data, output->cursor_buf_size); + if (size > output->cursor.buf_size) { + if (output->cursor.pool) { + wl_shm_pool_destroy(output->cursor.pool); + output->cursor.pool = NULL; + munmap(output->cursor.data, output->cursor.buf_size); } } - if (!output->cursor_pool) { + if (!output->cursor.pool) { int fd = os_create_anonymous_file(size); if (fd < 0) { - wlr_log_errno(L_INFO, "creating anonymous file for cursor buffer failed"); + wlr_log_errno(L_INFO, + "creating anonymous file for cursor buffer failed"); return false; } - output->cursor_data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (output->cursor_data == MAP_FAILED) { + output->cursor.data = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (output->cursor.data == MAP_FAILED) { close(fd); wlr_log_errno(L_INFO, "mmap failed"); return false; } - output->cursor_pool = wl_shm_create_pool(backend->shm, fd, size); + output->cursor.pool = wl_shm_create_pool(backend->shm, fd, size); close(fd); } - output->cursor_buffer = wl_shm_pool_create_buffer(output->cursor_pool, + output->cursor.buffer = wl_shm_pool_create_buffer(output->cursor.pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); - output->cursor_buf_size = size; + output->cursor.buf_size = size; } - memcpy(output->cursor_data, buf, size); - wl_surface_attach(output->cursor_surface, output->cursor_buffer, 0, 0); - wl_surface_damage(output->cursor_surface, 0, 0, width, height); - wl_surface_commit(output->cursor_surface); + memcpy(output->cursor.data, buf, size); + wl_surface_attach(output->cursor.surface, output->cursor.buffer, 0, 0); + wl_surface_damage(output->cursor.surface, 0, 0, width, height); + wl_surface_commit(output->cursor.surface); - wlr_wl_output_update_cursor(output, output->enter_serial, - hotspot_x, hotspot_y); + wlr_wl_output_update_cursor(output); return true; } static void wlr_wl_output_destroy(struct wlr_output *_output) { - struct wlr_wl_backend_output *output = (struct wlr_wl_backend_output *)_output; - wl_signal_emit(&output->backend->backend.events.output_remove, &output->wlr_output); - - if (output->cursor_buf_size != 0) { - assert(output->cursor_data); - assert(output->cursor_buffer); - assert(output->cursor_pool); - - wl_buffer_destroy(output->cursor_buffer); - munmap(output->cursor_data, output->cursor_buf_size); - wl_shm_pool_destroy(output->cursor_pool); + struct wlr_wl_backend_output *output = + (struct wlr_wl_backend_output *)_output; + wl_signal_emit(&output->backend->backend.events.output_remove, + &output->wlr_output); + + if (output->cursor.buf_size != 0) { + assert(output->cursor.data); + assert(output->cursor.buffer); + assert(output->cursor.pool); + + wl_buffer_destroy(output->cursor.buffer); + munmap(output->cursor.data, output->cursor.buf_size); + wl_shm_pool_destroy(output->cursor.pool); } - if (output->cursor_surface) { - wl_surface_destroy(output->cursor_surface); + if (output->cursor.surface) { + wl_surface_destroy(output->cursor.surface); } if (output->frame_callback) { @@ -164,11 +170,11 @@ static void wlr_wl_output_destroy(struct wlr_output *_output) { free(output); } -void wlr_wl_output_update_cursor(struct wlr_wl_backend_output *output, - uint32_t serial, int32_t hotspot_x, int32_t hotspot_y) { - if (output->backend->pointer && serial) { - wl_pointer_set_cursor(output->backend->pointer, serial, - output->cursor_surface, hotspot_x, hotspot_y); +void wlr_wl_output_update_cursor(struct wlr_wl_backend_output *output) { + if (output->backend->pointer && output->enter_serial) { + wl_pointer_set_cursor(output->backend->pointer, output->enter_serial, + output->cursor.surface, output->cursor.hotspot_x, + output->cursor.hotspot_y); } } diff --git a/backend/wayland/wl_seat.c b/backend/wayland/wl_seat.c index 903ca3ee..0d8e5b1f 100644 --- a/backend/wayland/wl_seat.c +++ b/backend/wayland/wl_seat.c @@ -23,8 +23,8 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, wlr_wl_output_for_surface(wlr_wl_dev->backend, surface); assert(output); wlr_wl_pointer->current_output = output; - wlr_wl_pointer->current_output->enter_serial = serial; - wlr_wl_output_update_cursor(wlr_wl_pointer->current_output, serial, 0, 0); + output->enter_serial = serial; + wlr_wl_output_update_cursor(output); } static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, diff --git a/include/backend/wayland.h b/include/backend/wayland.h index e1c89b11..1e8a55d2 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -43,11 +43,15 @@ struct wlr_wl_backend_output { struct wl_egl_window *egl_window; struct wl_callback *frame_callback; - struct wl_shm_pool *cursor_pool; - void *cursor_buffer; // actually a (client-side) struct wl_buffer* - uint8_t *cursor_data; - struct wl_surface *cursor_surface; - uint32_t cursor_buf_size; + struct { + struct wl_shm_pool *pool; + void *buffer; // actually a (client-side) struct wl_buffer* + uint32_t buf_size; + uint8_t *data; + struct wl_surface *surface; + int32_t hotspot_x, hotspot_y; + } cursor; + uint32_t enter_serial; void *egl_surface; @@ -68,8 +72,7 @@ struct wlr_wl_pointer { }; void wlr_wl_registry_poll(struct wlr_wl_backend *backend); -void wlr_wl_output_update_cursor(struct wlr_wl_backend_output *output, - uint32_t serial, int32_t hotspot_x, int32_t hotspot_y); +void wlr_wl_output_update_cursor(struct wlr_wl_backend_output *output); struct wlr_wl_backend_output *wlr_wl_output_for_surface( struct wlr_wl_backend *backend, struct wl_surface *surface); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index b6ea3a47..f9bce91f 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -15,6 +15,7 @@ struct wlr_output_mode { struct wlr_output_cursor { struct wlr_output *output; int32_t x, y; + uint32_t width, height; int32_t hotspot_x, hotspot_y; struct wl_list link; diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index dac290cb..76e20e9e 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -150,9 +150,8 @@ static void wlr_cursor_warp_unchecked(struct wlr_cursor *cur, double output_y = y; wlr_output_layout_output_coords(cur->state->layout, output_cursor->output_cursor->output, &output_x, &output_y); - wlr_output_cursor_move(output_cursor->output_cursor, - output_x - output_cursor->output_cursor->hotspot_x, - output_y - output_cursor->output_cursor->hotspot_y); + wlr_output_cursor_move(output_cursor->output_cursor, output_x, + output_y); } cur->x = x; diff --git a/types/wlr_output.c b/types/wlr_output.c index cb48ad63..5862d0fa 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -237,6 +237,44 @@ void wlr_output_make_current(struct wlr_output *output) { output->impl->make_current(output); } +static void output_cursor_get_effective_hotspot( + struct wlr_output_cursor *cursor, int32_t *hotspot_x, + int32_t *hotspot_y) { + switch (cursor->output->transform) { + case WL_OUTPUT_TRANSFORM_90: + *hotspot_x = cursor->hotspot_x; + *hotspot_y = -cursor->height + cursor->hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_180: + *hotspot_x = cursor->width - cursor->hotspot_x; + *hotspot_y = cursor->height - cursor->hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_270: + *hotspot_x = -cursor->height + cursor->hotspot_x; + *hotspot_y = cursor->hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED: + *hotspot_x = cursor->width - cursor->hotspot_x; + *hotspot_y = cursor->hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + *hotspot_x = cursor->hotspot_x; + *hotspot_y = -cursor->hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + *hotspot_x = cursor->hotspot_x; + *hotspot_y = cursor->height - cursor->hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + *hotspot_x = -cursor->height + cursor->hotspot_x; + *hotspot_y = cursor->width - cursor->hotspot_y; + break; + default: // WL_OUTPUT_TRANSFORM_NORMAL + *hotspot_x = cursor->hotspot_x; + *hotspot_y = cursor->hotspot_y; + } +} + static void output_cursor_render(struct wlr_output_cursor *cursor) { struct wlr_texture *texture = cursor->texture; struct wlr_renderer *renderer = cursor->renderer; @@ -252,9 +290,13 @@ static void output_cursor_render(struct wlr_output_cursor *cursor) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + int32_t hotspot_x, hotspot_y; + output_cursor_get_effective_hotspot(cursor, &hotspot_x, &hotspot_y); + float matrix[16]; wlr_texture_get_matrix(texture, &matrix, - &cursor->output->transform_matrix, cursor->x, cursor->y); + &cursor->output->transform_matrix, cursor->x - hotspot_x, + cursor->y - hotspot_y); wlr_render_with_matrix(renderer, texture, &matrix); } } @@ -295,55 +337,30 @@ static void output_cursor_reset(struct wlr_output_cursor *cursor) { } } -static void output_cursor_set_hotspot(struct wlr_output_cursor *cursor, - int32_t hotspot_x, int32_t hotspot_y, uint32_t width, uint32_t height) { - switch (cursor->output->transform) { - case WL_OUTPUT_TRANSFORM_90: - cursor->hotspot_x = hotspot_x; - cursor->hotspot_y = -height + hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_180: - cursor->hotspot_x = width - hotspot_x; - cursor->hotspot_y = height - hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_270: - cursor->hotspot_x = -height + hotspot_x; - cursor->hotspot_y = hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED: - cursor->hotspot_x = width - hotspot_x; - cursor->hotspot_y = hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - cursor->hotspot_x = hotspot_x; - cursor->hotspot_y = -hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - cursor->hotspot_x = hotspot_x; - cursor->hotspot_y = height - hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - cursor->hotspot_x = -height + hotspot_x; - cursor->hotspot_y = width - hotspot_y; - break; - default: // WL_OUTPUT_TRANSFORM_NORMAL - cursor->hotspot_x = hotspot_x; - cursor->hotspot_y = hotspot_y; - } -} - 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) { output_cursor_reset(cursor); - output_cursor_set_hotspot(cursor, hotspot_x, hotspot_y, width, height); + + cursor->width = width; + cursor->height = height; + cursor->hotspot_x = hotspot_x; + cursor->hotspot_y = hotspot_y; if (cursor->output->hardware_cursor == NULL && - cursor->output->impl->set_cursor && - cursor->output->impl->set_cursor(cursor->output, pixels, stride, - width, height, cursor->hotspot_x, cursor->hotspot_y, true)) { - cursor->output->hardware_cursor = cursor; - return true; + cursor->output->impl->set_cursor) { + int32_t hotspot_eff_x, hotspot_eff_y; + output_cursor_get_effective_hotspot(cursor, &hotspot_eff_x, + &hotspot_eff_y); + + // TODO: also transform pixels with output->transform before calling + // set_cursor + int ok = cursor->output->impl->set_cursor(cursor->output, pixels, + stride, width, height, hotspot_eff_x, hotspot_eff_y, true); + if (ok) { + cursor->output->hardware_cursor = cursor; + return true; + } } wlr_log(L_INFO, "Falling back to software cursor"); @@ -366,6 +383,13 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, stride, width, height, pixels); } +static void output_cursor_commit(struct wlr_output_cursor *cursor) { + cursor->width = cursor->surface->current->width; + cursor->height = cursor->surface->current->height; + + // TODO: if hardware cursor, upload pixels +} + static inline int64_t timespec_to_msec(const struct timespec *a) { return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; } @@ -376,7 +400,7 @@ static void output_cursor_handle_commit(struct wl_listener *listener, surface_commit); struct wlr_surface *surface = data; - // TODO: if hardware cursor, upload pixels + output_cursor_commit(cursor); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -402,16 +426,23 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, return; } - output_cursor_set_hotspot(cursor, hotspot_x, hotspot_y, - surface->current->width, surface->current->height); + if (surface) { + cursor->width = surface->current->width; + cursor->height = surface->current->height; + } + cursor->hotspot_x = hotspot_x; + cursor->hotspot_y = hotspot_y; if (surface && surface == cursor->surface) { if (cursor->output->hardware_cursor == cursor && cursor->output->impl->set_cursor) { // If the surface hasn't changed and it's an hardware cursor, only // update the hotspot + int32_t hotspot_eff_x, hotspot_eff_y; + output_cursor_get_effective_hotspot(cursor, &hotspot_eff_x, + &hotspot_eff_y); cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, 0, - cursor->hotspot_x, cursor->hotspot_y, false); + hotspot_eff_x, hotspot_eff_y, false); } return; } @@ -432,7 +463,7 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, if (surface != NULL) { wl_signal_add(&surface->events.commit, &cursor->surface_commit); wl_signal_add(&surface->events.destroy, &cursor->surface_destroy); - // TODO: if hardware cursor, upload pixels + output_cursor_commit(cursor); } else { // TODO: if hardware cursor, disable cursor } From 4230a577cc878607c2db1e6e5e7051b9e7653584 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 29 Oct 2017 18:14:58 +0100 Subject: [PATCH 06/18] Remove wlr_cursor_set_xcursor for now --- examples/pointer.c | 4 +++- include/wlr/types/wlr_cursor.h | 2 -- rootston/input.c | 5 ++++- types/wlr_cursor.c | 5 ----- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index 26d50b95..77f5192f 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -321,7 +321,9 @@ int main(int argc, char *argv[]) { return 1; } - wlr_cursor_set_xcursor(state.cursor, state.xcursor); + struct wlr_xcursor_image *image = state.xcursor->images[0]; + wlr_cursor_set_image(state.cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); compositor_init(&compositor); if (!wlr_backend_start(compositor.backend)) { diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index be4f322f..1aac2b94 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -36,8 +36,6 @@ struct wlr_cursor *wlr_cursor_create(); void wlr_cursor_destroy(struct wlr_cursor *cur); -void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur); - /** * Warp the cursor to the given x and y in layout coordinates. If x and y are * out of the layout boundaries or constraints, no warp will happen. diff --git a/rootston/input.c b/rootston/input.c index a6792bdb..8109d2b6 100644 --- a/rootston/input.c +++ b/rootston/input.c @@ -118,7 +118,10 @@ struct roots_input *input_create(struct roots_server *server, input->cursor = wlr_cursor_create(); cursor_initialize(input); - wlr_cursor_set_xcursor(input->cursor, xcursor); + + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_cursor_set_image(input->cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); wlr_cursor_attach_output_layout(input->cursor, server->desktop->layout); wlr_cursor_map_to_region(input->cursor, config->cursor.mapped_box); diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 76e20e9e..ece3d842 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -46,7 +46,6 @@ struct wlr_cursor_state { struct wl_list devices; // wlr_cursor_device::link struct wl_list output_cursors; // wlr_cursor_output_cursor::link struct wlr_output_layout *layout; - struct wlr_xcursor *xcursor; struct wlr_output *mapped_output; struct wlr_box *mapped_box; @@ -123,10 +122,6 @@ void wlr_cursor_destroy(struct wlr_cursor *cur) { free(cur); } -void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur) { - cur->state->xcursor = xcur; -} - static struct wlr_cursor_device *get_cursor_device(struct wlr_cursor *cur, struct wlr_input_device *device) { struct wlr_cursor_device *c_device, *ret = NULL; From c3b09f73da0d1fc4815f4b085ca07e30d175f549 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 29 Oct 2017 18:45:53 +0100 Subject: [PATCH 07/18] Fix cursor hotspot with rotated outputs on DRM backend --- backend/drm/drm.c | 38 +++++++++++++++++++++++++ include/backend/drm/drm.h | 1 + rootston/xcursor.c | 2 +- types/wlr_output.c | 58 +++------------------------------------ 4 files changed, 44 insertions(+), 55 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 23b9a9fa..6cbb0535 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -558,6 +558,40 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, } } + switch (output->transform) { + case WL_OUTPUT_TRANSFORM_90: + plane->cursor_hotspot_x = hotspot_x; + plane->cursor_hotspot_y = -plane->surf.height + hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_180: + plane->cursor_hotspot_x = plane->surf.width - hotspot_x; + plane->cursor_hotspot_y = plane->surf.height - hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_270: + plane->cursor_hotspot_x = -plane->surf.height + hotspot_x; + plane->cursor_hotspot_y = hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED: + plane->cursor_hotspot_x = plane->surf.width - hotspot_x; + plane->cursor_hotspot_y = hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + plane->cursor_hotspot_x = hotspot_x; + plane->cursor_hotspot_y = -hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + plane->cursor_hotspot_x = hotspot_x; + plane->cursor_hotspot_y = plane->surf.height - hotspot_y; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + plane->cursor_hotspot_x = -plane->surf.height + hotspot_x; + plane->cursor_hotspot_y = plane->surf.width - hotspot_y; + break; + default: // WL_OUTPUT_TRANSFORM_NORMAL + plane->cursor_hotspot_x = hotspot_x; + plane->cursor_hotspot_y = hotspot_y; + } + if (!update_pixels) { // Only update the cursor hotspot return true; @@ -605,6 +639,10 @@ static bool wlr_drm_connector_move_cursor(struct wlr_output *output, struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; + struct wlr_drm_plane *plane = conn->crtc->cursor; + x -= plane->cursor_hotspot_x; + y -= plane->cursor_hotspot_y; + int width, height, tmp; wlr_output_effective_resolution(output, &width, &height); diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index a6dd247c..e08965e5 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -34,6 +34,7 @@ struct wlr_drm_plane { struct wlr_texture *wlr_tex; struct gbm_bo *cursor_bo; bool cursor_enabled; + int32_t cursor_hotspot_x, cursor_hotspot_y; union wlr_drm_plane_props props; }; diff --git a/rootston/xcursor.c b/rootston/xcursor.c index 43cbfc51..0d18e1f0 100644 --- a/rootston/xcursor.c +++ b/rootston/xcursor.c @@ -2,7 +2,7 @@ #include "rootston/input.h" struct wlr_xcursor *get_default_xcursor(struct wlr_xcursor_theme *theme) { - return wlr_xcursor_theme_get_cursor(theme, "left_ptr"); + return wlr_xcursor_theme_get_cursor(theme, "grabbing"); } struct wlr_xcursor *get_move_xcursor(struct wlr_xcursor_theme *theme) { diff --git a/types/wlr_output.c b/types/wlr_output.c index 5862d0fa..3cdeecfe 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -237,44 +237,6 @@ void wlr_output_make_current(struct wlr_output *output) { output->impl->make_current(output); } -static void output_cursor_get_effective_hotspot( - struct wlr_output_cursor *cursor, int32_t *hotspot_x, - int32_t *hotspot_y) { - switch (cursor->output->transform) { - case WL_OUTPUT_TRANSFORM_90: - *hotspot_x = cursor->hotspot_x; - *hotspot_y = -cursor->height + cursor->hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_180: - *hotspot_x = cursor->width - cursor->hotspot_x; - *hotspot_y = cursor->height - cursor->hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_270: - *hotspot_x = -cursor->height + cursor->hotspot_x; - *hotspot_y = cursor->hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED: - *hotspot_x = cursor->width - cursor->hotspot_x; - *hotspot_y = cursor->hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - *hotspot_x = cursor->hotspot_x; - *hotspot_y = -cursor->hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - *hotspot_x = cursor->hotspot_x; - *hotspot_y = cursor->height - cursor->hotspot_y; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - *hotspot_x = -cursor->height + cursor->hotspot_x; - *hotspot_y = cursor->width - cursor->hotspot_y; - break; - default: // WL_OUTPUT_TRANSFORM_NORMAL - *hotspot_x = cursor->hotspot_x; - *hotspot_y = cursor->hotspot_y; - } -} - static void output_cursor_render(struct wlr_output_cursor *cursor) { struct wlr_texture *texture = cursor->texture; struct wlr_renderer *renderer = cursor->renderer; @@ -290,13 +252,10 @@ static void output_cursor_render(struct wlr_output_cursor *cursor) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - int32_t hotspot_x, hotspot_y; - output_cursor_get_effective_hotspot(cursor, &hotspot_x, &hotspot_y); - float matrix[16]; wlr_texture_get_matrix(texture, &matrix, - &cursor->output->transform_matrix, cursor->x - hotspot_x, - cursor->y - hotspot_y); + &cursor->output->transform_matrix, cursor->x - cursor->hotspot_x, + cursor->y - cursor->hotspot_y); wlr_render_with_matrix(renderer, texture, &matrix); } } @@ -349,14 +308,8 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, if (cursor->output->hardware_cursor == NULL && cursor->output->impl->set_cursor) { - int32_t hotspot_eff_x, hotspot_eff_y; - output_cursor_get_effective_hotspot(cursor, &hotspot_eff_x, - &hotspot_eff_y); - - // TODO: also transform pixels with output->transform before calling - // set_cursor int ok = cursor->output->impl->set_cursor(cursor->output, pixels, - stride, width, height, hotspot_eff_x, hotspot_eff_y, true); + stride, width, height, hotspot_x, hotspot_y, true); if (ok) { cursor->output->hardware_cursor = cursor; return true; @@ -438,11 +391,8 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, cursor->output->impl->set_cursor) { // If the surface hasn't changed and it's an hardware cursor, only // update the hotspot - int32_t hotspot_eff_x, hotspot_eff_y; - output_cursor_get_effective_hotspot(cursor, &hotspot_eff_x, - &hotspot_eff_y); cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0, 0, - hotspot_eff_x, hotspot_eff_y, false); + hotspot_x, hotspot_y, false); } return; } From 044173d1dfbce7bdc3ae134a829f2bb0d88d208b Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 29 Oct 2017 20:03:56 +0100 Subject: [PATCH 08/18] Add multi-pointer example --- examples/meson.build | 2 + examples/multi-pointer.c | 202 +++++++++++++++++++++++++++++++++++++++ examples/pointer.c | 22 ++--- rootston/xcursor.c | 2 +- types/wlr_cursor.c | 45 ++++++--- 5 files changed, 250 insertions(+), 23 deletions(-) create mode 100644 examples/multi-pointer.c diff --git a/examples/meson.build b/examples/meson.build index a29a3310..3402441b 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -8,6 +8,8 @@ executable('simple', 'simple.c', dependencies: wlroots, link_with: lib_shared) executable('pointer', 'pointer.c', dependencies: wlroots, link_with: lib_shared) executable('touch', 'touch.c', dependencies: wlroots, link_with: lib_shared) executable('tablet', 'tablet.c', dependencies: wlroots, link_with: lib_shared) +executable('multi-pointer', 'multi-pointer.c', dependencies: wlroots, + link_with: lib_shared) executable( 'rotation', diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c new file mode 100644 index 00000000..c3a02cc7 --- /dev/null +++ b/examples/multi-pointer.c @@ -0,0 +1,202 @@ +#define _POSIX_C_SOURCE 199309L +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "shared.h" +#include "config.h" +#include "cat.h" + +struct sample_state; + +struct sample_cursor { + struct sample_state *state; + struct wlr_input_device *device; + struct wlr_cursor *cursor; + struct wl_list link; + + struct wl_listener cursor_motion; + struct wl_listener cursor_motion_absolute; + struct wl_listener cursor_button; + struct wl_listener cursor_axis; +}; + +struct sample_state { + struct compositor_state *compositor; + struct example_config *config; + struct wlr_xcursor *xcursor; + float default_color[4]; + float clear_color[4]; + struct wlr_output_layout *layout; + struct wl_list cursors; // sample_cursor::link +}; + +static void handle_output_frame(struct output_state *output, + struct timespec *ts) { + struct compositor_state *state = output->compositor; + struct sample_state *sample = state->data; + struct wlr_output *wlr_output = output->output; + + wlr_output_make_current(wlr_output); + + glClearColor(sample->clear_color[0], sample->clear_color[1], + sample->clear_color[2], sample->clear_color[3]); + glClear(GL_COLOR_BUFFER_BIT); + + wlr_output_swap_buffers(wlr_output); +} + +static void handle_output_add(struct output_state *ostate) { + struct sample_state *sample = ostate->compositor->data; + + struct output_config *o_config = + example_config_get_output(sample->config, ostate->output); + + if (o_config) { + wlr_output_transform(ostate->output, o_config->transform); + wlr_output_layout_add(sample->layout, ostate->output, o_config->x, + o_config->y); + } else { + wlr_output_layout_add_auto(sample->layout, ostate->output); + } + + struct sample_cursor *cursor; + wl_list_for_each(cursor, &sample->cursors, link) { + example_config_configure_cursor(sample->config, cursor->cursor, + sample->compositor); + + // TODO the cursor must be set depending on which surface it is + // displayed over which should happen in the compositor. + struct wlr_xcursor_image *image = sample->xcursor->images[0]; + wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); + + wlr_cursor_warp(cursor->cursor, NULL, cursor->cursor->x, + cursor->cursor->y); + } +} + +static void handle_output_remove(struct output_state *ostate) { + struct sample_state *sample = ostate->compositor->data; + + wlr_output_layout_remove(sample->layout, ostate->output); + + struct sample_cursor *cursor; + wl_list_for_each(cursor, &sample->cursors, link) { + example_config_configure_cursor(sample->config, cursor->cursor, + sample->compositor); + } +} + +static void handle_cursor_motion(struct wl_listener *listener, void *data) { + struct sample_cursor *cursor = + wl_container_of(listener, cursor, cursor_motion); + struct wlr_event_pointer_motion *event = data; + wlr_cursor_move(cursor->cursor, event->device, event->delta_x, + event->delta_y); +} + +static void handle_cursor_motion_absolute(struct wl_listener *listener, + void *data) { + struct sample_cursor *cursor = + wl_container_of(listener, cursor, cursor_motion_absolute); + struct wlr_event_pointer_motion_absolute *event = data; + wlr_cursor_warp_absolute(cursor->cursor, event->device, + event->x_mm / event->width_mm, event->y_mm / event->height_mm); +} + +static void handle_input_add(struct compositor_state *state, + struct wlr_input_device *device) { + struct sample_state *sample = state->data; + + if (device->type != WLR_INPUT_DEVICE_POINTER) { + return; + } + + struct sample_cursor *cursor = calloc(1, sizeof(struct sample_cursor)); + cursor->state = sample; + + cursor->cursor = wlr_cursor_create(); + wlr_cursor_attach_output_layout(cursor->cursor, sample->layout); + wlr_cursor_map_to_region(cursor->cursor, sample->config->cursor.mapped_box); + + wl_signal_add(&cursor->cursor->events.motion, &cursor->cursor_motion); + cursor->cursor_motion.notify = handle_cursor_motion; + wl_signal_add(&cursor->cursor->events.motion_absolute, + &cursor->cursor_motion_absolute); + cursor->cursor_motion_absolute.notify = handle_cursor_motion_absolute; + + wlr_cursor_attach_input_device(cursor->cursor, device); + example_config_configure_cursor(sample->config, cursor->cursor, + sample->compositor); + + struct wlr_xcursor_image *image = sample->xcursor->images[0]; + wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); + + wl_list_insert(&sample->cursors, &cursor->link); +} + +int main(int argc, char *argv[]) { + struct sample_state state = { + .default_color = { 0.25f, 0.25f, 0.25f, 1 }, + .clear_color = { 0.25f, 0.25f, 0.25f, 1 }, + }; + + wl_list_init(&state.cursors); + + state.config = parse_args(argc, argv); + state.layout = wlr_output_layout_create(); + + struct compositor_state compositor = { 0 }; + compositor.data = &state; + compositor.output_add_cb = handle_output_add; + compositor.output_remove_cb = handle_output_remove; + compositor.output_frame_cb = handle_output_frame; + compositor.input_add_cb = handle_input_add; + + state.compositor = &compositor; + + struct wlr_xcursor_theme *theme = wlr_xcursor_theme_load("default", 16); + if (!theme) { + wlr_log(L_ERROR, "Failed to load cursor theme"); + return 1; + } + state.xcursor = wlr_xcursor_theme_get_cursor(theme, "left_ptr"); + if (!state.xcursor) { + wlr_log(L_ERROR, "Failed to load left_ptr cursor"); + return 1; + } + + compositor_init(&compositor); + if (!wlr_backend_start(compositor.backend)) { + wlr_log(L_ERROR, "Failed to start backend"); + wlr_backend_destroy(compositor.backend); + exit(1); + } + wl_display_run(compositor.display); + compositor_fini(&compositor); + + wlr_xcursor_theme_destroy(theme); + example_config_destroy(state.config); + wlr_output_layout_destroy(state.layout); +} diff --git a/examples/pointer.c b/examples/pointer.c index 77f5192f..83122421 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -60,7 +60,7 @@ struct touch_point { }; static void warp_to_touch(struct sample_state *sample, - struct wlr_input_device *dev) { + struct wlr_input_device *dev) { if (sample->touch_points->length == 0) { return; } @@ -77,7 +77,7 @@ static void warp_to_touch(struct sample_state *sample, } static void handle_output_frame(struct output_state *output, - struct timespec *ts) { + struct timespec *ts) { struct compositor_state *state = output->compositor; struct sample_state *sample = state->data; struct wlr_output *wlr_output = output->output; @@ -127,7 +127,7 @@ static void handle_output_remove(struct output_state *ostate) { } static void handle_input_add(struct compositor_state *state, - struct wlr_input_device *device) { + struct wlr_input_device *device) { struct sample_state *sample = state->data; if (device->type == WLR_INPUT_DEVICE_POINTER || @@ -141,16 +141,16 @@ static void handle_input_add(struct compositor_state *state, static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct sample_state *sample = - wl_container_of(listener, sample, cursor_motion); + wl_container_of(listener, sample, cursor_motion); struct wlr_event_pointer_motion *event = data; wlr_cursor_move(sample->cursor, event->device, event->delta_x, - event->delta_y); + event->delta_y); } static void handle_cursor_motion_absolute(struct wl_listener *listener, - void *data) { + void *data) { struct sample_state *sample = - wl_container_of(listener, sample, cursor_motion_absolute); + wl_container_of(listener, sample, cursor_motion_absolute); struct wlr_event_pointer_motion_absolute *event = data; sample->cur_x = event->x_mm; @@ -162,7 +162,7 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, static void handle_cursor_button(struct wl_listener *listener, void *data) { struct sample_state *sample = - wl_container_of(listener, sample, cursor_button); + wl_container_of(listener, sample, cursor_button); struct wlr_event_pointer_button *event = data; float (*color)[4]; @@ -179,7 +179,7 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { static void handle_cursor_axis(struct wl_listener *listener, void *data) { struct sample_state *sample = - wl_container_of(listener, sample, cursor_axis); + wl_container_of(listener, sample, cursor_axis); struct wlr_event_pointer_axis *event = data; for (size_t i = 0; i < 3; ++i) { @@ -226,7 +226,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { static void handle_touch_motion(struct wl_listener *listener, void *data) { struct sample_state *sample = - wl_container_of(listener, sample, touch_motion); + wl_container_of(listener, sample, touch_motion); struct wlr_event_touch_motion *event = data; for (size_t i = 0; i < sample->touch_points->length; ++i) { struct touch_point *point = sample->touch_points->items[i]; @@ -246,7 +246,7 @@ static void handle_touch_cancel(struct wl_listener *listener, void *data) { static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { struct sample_state *sample = - wl_container_of(listener, sample, tablet_tool_axis); + wl_container_of(listener, sample, tablet_tool_axis); struct wlr_event_tablet_tool_axis *event = data; if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) && (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { diff --git a/rootston/xcursor.c b/rootston/xcursor.c index 0d18e1f0..43cbfc51 100644 --- a/rootston/xcursor.c +++ b/rootston/xcursor.c @@ -2,7 +2,7 @@ #include "rootston/input.h" struct wlr_xcursor *get_default_xcursor(struct wlr_xcursor_theme *theme) { - return wlr_xcursor_theme_get_cursor(theme, "grabbing"); + return wlr_xcursor_theme_get_cursor(theme, "left_ptr"); } struct wlr_xcursor *get_move_xcursor(struct wlr_xcursor_theme *theme) { diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index ece3d842..ece7973c 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -98,11 +98,30 @@ struct wlr_cursor *wlr_cursor_create() { return cur; } +static void output_cursor_remove( + struct wlr_cursor_output_cursor *output_cursor) { + wl_list_remove(&output_cursor->link); + wlr_output_cursor_destroy(output_cursor->output_cursor); + wl_list_remove(&output_cursor->layout_output_destroy.link); + free(output_cursor); +} + static void wlr_cursor_detach_output_layout(struct wlr_cursor *cur) { if (!cur->state->layout) { return; } + struct wlr_output_layout_output *l_output; + wl_list_for_each(l_output, &cur->state->layout->outputs, link) { + struct wlr_cursor_output_cursor *output_cursor, *tmp; + wl_list_for_each_safe(output_cursor, tmp, &cur->state->output_cursors, + link) { + if (output_cursor->output_cursor->output == l_output->output) { + output_cursor_remove(output_cursor); + } + } + } + wl_list_remove(&cur->state->layout_destroy.link); wl_list_remove(&cur->state->layout_change.link); wl_list_remove(&cur->state->layout_add.link); @@ -477,7 +496,6 @@ static void wlr_cursor_device_destroy(struct wlr_cursor_device *c_device) { wl_list_remove(&c_device->link); wl_list_remove(&c_device->destroy.link); free(c_device); - } void wlr_cursor_detach_input_device(struct wlr_cursor *cur, @@ -501,18 +519,11 @@ static void handle_layout_output_destroy(struct wl_listener *listener, struct wlr_cursor_output_cursor *output_cursor = wl_container_of(listener, output_cursor, layout_output_destroy); //struct wlr_output_layout_output *l_output = data; - - wl_list_remove(&output_cursor->link); - wlr_output_cursor_destroy(output_cursor->output_cursor); - wl_list_remove(&output_cursor->layout_output_destroy.link); - free(output_cursor); + output_cursor_remove(output_cursor); } -static void handle_layout_add(struct wl_listener *listener, void *data) { - struct wlr_cursor_state *state = - wl_container_of(listener, state, layout_add); - struct wlr_output_layout_output *l_output = data; - +static void layout_add(struct wlr_cursor_state *state, + struct wlr_output_layout_output *l_output) { struct wlr_cursor_output_cursor *output_cursor = calloc(1, sizeof(struct wlr_cursor_output_cursor)); if (output_cursor == NULL) { @@ -535,6 +546,13 @@ static void handle_layout_add(struct wl_listener *listener, void *data) { wl_list_insert(&state->cursor->state->output_cursors, &output_cursor->link); } +static void handle_layout_add(struct wl_listener *listener, void *data) { + struct wlr_cursor_state *state = + wl_container_of(listener, state, layout_add); + struct wlr_output_layout_output *l_output = data; + layout_add(state, l_output); +} + static void handle_layout_change(struct wl_listener *listener, void *data) { struct wlr_cursor_state *state = wl_container_of(listener, state, layout_change); @@ -568,6 +586,11 @@ void wlr_cursor_attach_output_layout(struct wlr_cursor *cur, cur->state->layout_destroy.notify = handle_layout_destroy; cur->state->layout = l; + + struct wlr_output_layout_output *l_output; + wl_list_for_each(l_output, &l->outputs, link) { + layout_add(cur->state, l_output); + } } void wlr_cursor_map_to_output(struct wlr_cursor *cur, From 6a74a3586fba7b8c3592d2a94d6b06190c3165b1 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 29 Oct 2017 20:58:58 +0100 Subject: [PATCH 09/18] Fix wlr_cursor_destroy, handle device remove in examples/multi-cursor --- examples/multi-pointer.c | 18 ++++++++++++++ types/wlr_cursor.c | 51 ++++++++++++++++++++-------------------- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index c3a02cc7..3cfa3910 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -134,6 +134,7 @@ static void handle_input_add(struct compositor_state *state, struct sample_cursor *cursor = calloc(1, sizeof(struct sample_cursor)); cursor->state = sample; + cursor->device = device; cursor->cursor = wlr_cursor_create(); wlr_cursor_attach_output_layout(cursor->cursor, sample->layout); @@ -156,6 +157,22 @@ static void handle_input_add(struct compositor_state *state, wl_list_insert(&sample->cursors, &cursor->link); } +static void handle_input_remove(struct compositor_state *state, + struct wlr_input_device *device) { + struct sample_state *sample = state->data; + struct sample_cursor *cursor; + wl_list_for_each(cursor, &sample->cursors, link) { + if (cursor->device == device) { + wl_list_remove(&cursor->link); + wl_list_remove(&cursor->cursor_motion.link); + wl_list_remove(&cursor->cursor_motion_absolute.link); + wlr_cursor_destroy(cursor->cursor); + free(cursor); + break; + } + } +} + int main(int argc, char *argv[]) { struct sample_state state = { .default_color = { 0.25f, 0.25f, 0.25f, 1 }, @@ -173,6 +190,7 @@ int main(int argc, char *argv[]) { compositor.output_remove_cb = handle_output_remove; compositor.output_frame_cb = handle_output_frame; compositor.input_add_cb = handle_input_add; + compositor.input_remove_cb = handle_input_remove; state.compositor = &compositor; diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index ece7973c..70ddea47 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -129,13 +129,36 @@ static void wlr_cursor_detach_output_layout(struct wlr_cursor *cur) { cur->state->layout = NULL; } +static void wlr_cursor_device_destroy(struct wlr_cursor_device *c_device) { + struct wlr_input_device *dev = c_device->device; + if (dev->type == WLR_INPUT_DEVICE_POINTER) { + wl_list_remove(&c_device->motion.link); + wl_list_remove(&c_device->motion_absolute.link); + wl_list_remove(&c_device->button.link); + wl_list_remove(&c_device->axis.link); + } else if (dev->type == WLR_INPUT_DEVICE_TOUCH) { + wl_list_remove(&c_device->touch_down.link); + wl_list_remove(&c_device->touch_up.link); + wl_list_remove(&c_device->touch_motion.link); + wl_list_remove(&c_device->touch_cancel.link); + } else if (dev->type == WLR_INPUT_DEVICE_TABLET_TOOL) { + wl_list_remove(&c_device->tablet_tool_axis.link); + wl_list_remove(&c_device->tablet_tool_proximity.link); + wl_list_remove(&c_device->tablet_tool_tip.link); + wl_list_remove(&c_device->tablet_tool_button.link); + } + + wl_list_remove(&c_device->link); + wl_list_remove(&c_device->destroy.link); + free(c_device); +} + void wlr_cursor_destroy(struct wlr_cursor *cur) { wlr_cursor_detach_output_layout(cur); struct wlr_cursor_device *device, *device_tmp = NULL; wl_list_for_each_safe(device, device_tmp, &cur->state->devices, link) { - wl_list_remove(&device->link); - free(device); + wlr_cursor_device_destroy(device); } free(cur); @@ -474,30 +497,6 @@ void wlr_cursor_attach_input_device(struct wlr_cursor *cur, wlr_cursor_device_create(cur, dev); } -static void wlr_cursor_device_destroy(struct wlr_cursor_device *c_device) { - struct wlr_input_device *dev = c_device->device; - if (dev->type == WLR_INPUT_DEVICE_POINTER) { - wl_list_remove(&c_device->motion.link); - wl_list_remove(&c_device->motion_absolute.link); - wl_list_remove(&c_device->button.link); - wl_list_remove(&c_device->axis.link); - } else if (dev->type == WLR_INPUT_DEVICE_TOUCH) { - wl_list_remove(&c_device->touch_down.link); - wl_list_remove(&c_device->touch_up.link); - wl_list_remove(&c_device->touch_motion.link); - wl_list_remove(&c_device->touch_cancel.link); - } else if (dev->type == WLR_INPUT_DEVICE_TABLET_TOOL) { - wl_list_remove(&c_device->tablet_tool_axis.link); - wl_list_remove(&c_device->tablet_tool_proximity.link); - wl_list_remove(&c_device->tablet_tool_tip.link); - wl_list_remove(&c_device->tablet_tool_button.link); - } - - wl_list_remove(&c_device->link); - wl_list_remove(&c_device->destroy.link); - free(c_device); -} - void wlr_cursor_detach_input_device(struct wlr_cursor *cur, struct wlr_input_device *dev) { struct wlr_cursor_device *c_device, *tmp = NULL; From ae9a46fc9bc81051ef732a178b47017d8c2e591f Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 31 Oct 2017 10:54:05 +0100 Subject: [PATCH 10/18] Remove outdated TODOs, use wlr_surface_has_buffer --- examples/multi-pointer.c | 2 -- examples/pointer.c | 2 -- rootston/output.c | 2 -- types/wlr_output.c | 8 +++++--- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 3cfa3910..e1ac2734 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -84,8 +84,6 @@ static void handle_output_add(struct output_state *ostate) { example_config_configure_cursor(sample->config, cursor->cursor, sample->compositor); - // TODO the cursor must be set depending on which surface it is - // displayed over which should happen in the compositor. struct wlr_xcursor_image *image = sample->xcursor->images[0]; wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, image->width, image->height, image->hotspot_x, image->hotspot_y); diff --git a/examples/pointer.c b/examples/pointer.c index 83122421..8927314e 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -108,8 +108,6 @@ static void handle_output_add(struct output_state *ostate) { example_config_configure_cursor(sample->config, sample->cursor, sample->compositor); - // TODO the cursor must be set depending on which surface it is displayed - // over which should happen in the compositor. struct wlr_xcursor_image *image = sample->xcursor->images[0]; wlr_cursor_set_image(sample->cursor, image->buffer, image->width, image->width, image->height, image->hotspot_x, image->hotspot_y); diff --git a/rootston/output.c b/rootston/output.c index 6ca302d8..9e1cd4d5 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -223,8 +223,6 @@ void output_add_notify(struct wl_listener *listener, void *data) { cursor_load_config(config, input->cursor, input, desktop); - // TODO the cursor must be set depending on which surface it is displayed - // over which should happen in the compositor. struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme); struct wlr_xcursor_image *image = xcursor->images[0]; wlr_cursor_set_image(input->cursor, image->buffer, image->width, diff --git a/types/wlr_output.c b/types/wlr_output.c index 3cdeecfe..3804f2e3 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -241,13 +241,15 @@ static void output_cursor_render(struct wlr_output_cursor *cursor) { struct wlr_texture *texture = cursor->texture; struct wlr_renderer *renderer = cursor->renderer; if (cursor->surface != NULL) { + // Some clients commit a cursor surface with a NULL buffer to hide it. + if (!wlr_surface_has_buffer(cursor->surface)) { + return; + } texture = cursor->surface->texture; renderer = cursor->surface->renderer; } - // We check texture->valid because some clients set a cursor surface - // with a NULL buffer to hide it - if (renderer && texture && texture->valid) { + if (texture != NULL && renderer != NULL) { glViewport(0, 0, cursor->output->width, cursor->output->height); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); From ca9dfd2e14fbebcf4f0ae2c56fc1df5d85d2bc4f Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 31 Oct 2017 11:12:05 +0100 Subject: [PATCH 11/18] Emit add event after configuring wlr_output_layout_output --- types/wlr_output_layout.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 190f2733..b2bcb113 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -165,8 +165,6 @@ static struct wlr_output_layout_output *wlr_output_layout_output_create( wl_signal_add(&output->events.destroy, &l_output->state->output_destroy); l_output->state->output_destroy.notify = handle_output_destroy; - wl_signal_emit(&layout->events.add, l_output); - return l_output; } @@ -185,6 +183,7 @@ void wlr_output_layout_add(struct wlr_output_layout *layout, l_output->y = y; l_output->state->auto_configured = false; wlr_output_layout_reconfigure(layout); + wl_signal_emit(&layout->events.add, l_output); } struct wlr_output_layout_output *wlr_output_layout_get( @@ -367,6 +366,7 @@ void wlr_output_layout_add_auto(struct wlr_output_layout *layout, l_output->state->auto_configured = true; wlr_output_layout_reconfigure(layout); + wl_signal_emit(&layout->events.add, l_output); } struct wlr_output *wlr_output_layout_get_center_output( From 9142def292f300827c5c8e75e239e0f8c1da7138 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 31 Oct 2017 12:57:20 +0100 Subject: [PATCH 12/18] Do not render off-screen software cursors --- types/wlr_output.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/types/wlr_output.c b/types/wlr_output.c index 3804f2e3..706f12fb 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -237,6 +238,14 @@ void wlr_output_make_current(struct wlr_output *output) { output->impl->make_current(output); } +static void output_cursor_get_box(struct wlr_output_cursor *cursor, + struct wlr_box *box) { + box->x = cursor->x - cursor->hotspot_x; + box->y = cursor->y - cursor->hotspot_y; + box->width = cursor->width; + box->height = cursor->height; +} + static void output_cursor_render(struct wlr_output_cursor *cursor) { struct wlr_texture *texture = cursor->texture; struct wlr_renderer *renderer = cursor->renderer; @@ -249,17 +258,33 @@ static void output_cursor_render(struct wlr_output_cursor *cursor) { renderer = cursor->surface->renderer; } - if (texture != NULL && renderer != NULL) { - glViewport(0, 0, cursor->output->width, cursor->output->height); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (texture == NULL || renderer == NULL) { + return; + } + + struct wlr_box output_box; + memset(&output_box, 0, sizeof(output_box)); + wlr_output_effective_resolution(cursor->output, &output_box.width, + &output_box.height); - float matrix[16]; - wlr_texture_get_matrix(texture, &matrix, - &cursor->output->transform_matrix, cursor->x - cursor->hotspot_x, - cursor->y - cursor->hotspot_y); - wlr_render_with_matrix(renderer, texture, &matrix); + struct wlr_box cursor_box; + output_cursor_get_box(cursor, &cursor_box); + + struct wlr_box intersection; + struct wlr_box *intersection_ptr = &intersection; + if (!wlr_box_intersection(&output_box, &cursor_box, &intersection_ptr)) { + return; } + + glViewport(0, 0, cursor->output->width, cursor->output->height); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + float matrix[16]; + wlr_texture_get_matrix(texture, &matrix, + &cursor->output->transform_matrix, cursor->x - cursor->hotspot_x, + cursor->y - cursor->hotspot_y); + wlr_render_with_matrix(renderer, texture, &matrix); } void wlr_output_swap_buffers(struct wlr_output *output) { From c97b5ac4ce43794b68b8aabcf8005b9cbd60a51a Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 31 Oct 2017 13:48:09 +0100 Subject: [PATCH 13/18] Fix output_cursor_render bounds check --- types/wlr_output.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/types/wlr_output.c b/types/wlr_output.c index 706f12fb..38bb03d5 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -263,9 +263,9 @@ static void output_cursor_render(struct wlr_output_cursor *cursor) { } struct wlr_box output_box; - memset(&output_box, 0, sizeof(output_box)); - wlr_output_effective_resolution(cursor->output, &output_box.width, - &output_box.height); + output_box.x = output_box.y = 0; + output_box.width = cursor->output->width; + output_box.height = cursor->output->height; struct wlr_box cursor_box; output_cursor_get_box(cursor, &cursor_box); @@ -335,12 +335,12 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, if (cursor->output->hardware_cursor == NULL && cursor->output->impl->set_cursor) { - int ok = cursor->output->impl->set_cursor(cursor->output, pixels, - stride, width, height, hotspot_x, hotspot_y, true); - if (ok) { - cursor->output->hardware_cursor = cursor; - return true; - } + // int ok = cursor->output->impl->set_cursor(cursor->output, pixels, + // stride, width, height, hotspot_x, hotspot_y, true); + // if (ok) { + // cursor->output->hardware_cursor = cursor; + // return true; + // } } wlr_log(L_INFO, "Falling back to software cursor"); From 2c63aa2056d564be2fee50a175b3400bdfb96660 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 31 Oct 2017 14:21:12 +0100 Subject: [PATCH 14/18] Destroy x11 output with backend --- backend/x11/backend.c | 5 ++++- types/wlr_cursor.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 37bbdaec..97b0dd8c 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -298,6 +298,9 @@ static void wlr_x11_backend_destroy(struct wlr_backend *backend) { struct wlr_x11_backend *x11 = (struct wlr_x11_backend *)backend; + struct wlr_x11_output *output = &x11->output; + wlr_output_destroy(&output->wlr_output); + wl_event_source_remove(x11->frame_timer); wlr_egl_free(&x11->egl); @@ -331,7 +334,7 @@ static void output_destroy(struct wlr_output *wlr_output) { eglDestroySurface(x11->egl.display, output->surf); xcb_destroy_window(x11->xcb_conn, output->win); - free(wlr_output); + // output has been allocated on the stack, do not free it } static void output_make_current(struct wlr_output *wlr_output) { diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 70ddea47..e44b957a 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -100,9 +100,9 @@ struct wlr_cursor *wlr_cursor_create() { static void output_cursor_remove( struct wlr_cursor_output_cursor *output_cursor) { + wl_list_remove(&output_cursor->layout_output_destroy.link); wl_list_remove(&output_cursor->link); wlr_output_cursor_destroy(output_cursor->output_cursor); - wl_list_remove(&output_cursor->layout_output_destroy.link); free(output_cursor); } From 7dc716a2bbfd765171fff24257affb2b1eeb24f7 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 31 Oct 2017 14:58:58 +0100 Subject: [PATCH 15/18] Fix memory leak in wlr_cursor --- examples/multi-pointer.c | 5 +++++ types/wlr_cursor.c | 20 ++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index e1ac2734..c69acc5f 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -212,6 +212,11 @@ int main(int argc, char *argv[]) { wl_display_run(compositor.display); compositor_fini(&compositor); + struct sample_cursor *cursor; + wl_list_for_each(cursor, &state.cursors, link) { + // TODO + } + wlr_xcursor_theme_destroy(theme); example_config_destroy(state.config); wlr_output_layout_destroy(state.layout); diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index e44b957a..83d36d14 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -98,7 +98,7 @@ struct wlr_cursor *wlr_cursor_create() { return cur; } -static void output_cursor_remove( +static void output_cursor_destroy( struct wlr_cursor_output_cursor *output_cursor) { wl_list_remove(&output_cursor->layout_output_destroy.link); wl_list_remove(&output_cursor->link); @@ -111,15 +111,10 @@ static void wlr_cursor_detach_output_layout(struct wlr_cursor *cur) { return; } - struct wlr_output_layout_output *l_output; - wl_list_for_each(l_output, &cur->state->layout->outputs, link) { - struct wlr_cursor_output_cursor *output_cursor, *tmp; - wl_list_for_each_safe(output_cursor, tmp, &cur->state->output_cursors, - link) { - if (output_cursor->output_cursor->output == l_output->output) { - output_cursor_remove(output_cursor); - } - } + struct wlr_cursor_output_cursor *output_cursor, *tmp; + wl_list_for_each_safe(output_cursor, tmp, &cur->state->output_cursors, + link) { + output_cursor_destroy(output_cursor); } wl_list_remove(&cur->state->layout_destroy.link); @@ -161,6 +156,7 @@ void wlr_cursor_destroy(struct wlr_cursor *cur) { wlr_cursor_device_destroy(device); } + free(cur->state); free(cur); } @@ -518,7 +514,7 @@ static void handle_layout_output_destroy(struct wl_listener *listener, struct wlr_cursor_output_cursor *output_cursor = wl_container_of(listener, output_cursor, layout_output_destroy); //struct wlr_output_layout_output *l_output = data; - output_cursor_remove(output_cursor); + output_cursor_destroy(output_cursor); } static void layout_add(struct wlr_cursor_state *state, @@ -542,7 +538,7 @@ static void layout_add(struct wlr_cursor_state *state, wl_signal_add(&l_output->events.destroy, &output_cursor->layout_output_destroy); - wl_list_insert(&state->cursor->state->output_cursors, &output_cursor->link); + wl_list_insert(&state->output_cursors, &output_cursor->link); } static void handle_layout_add(struct wl_listener *listener, void *data) { From 6b6895168b46e8d5a8c231f083962172dc942e32 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 31 Oct 2017 15:02:41 +0100 Subject: [PATCH 16/18] Fix segfaults on exit in examples/mutli-pointer --- examples/multi-pointer.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index c69acc5f..e0993987 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -155,17 +155,21 @@ static void handle_input_add(struct compositor_state *state, wl_list_insert(&sample->cursors, &cursor->link); } +static void cursor_destroy(struct sample_cursor *cursor) { + wl_list_remove(&cursor->link); + wl_list_remove(&cursor->cursor_motion.link); + wl_list_remove(&cursor->cursor_motion_absolute.link); + wlr_cursor_destroy(cursor->cursor); + free(cursor); +} + static void handle_input_remove(struct compositor_state *state, struct wlr_input_device *device) { struct sample_state *sample = state->data; struct sample_cursor *cursor; wl_list_for_each(cursor, &sample->cursors, link) { if (cursor->device == device) { - wl_list_remove(&cursor->link); - wl_list_remove(&cursor->cursor_motion.link); - wl_list_remove(&cursor->cursor_motion_absolute.link); - wlr_cursor_destroy(cursor->cursor); - free(cursor); + cursor_destroy(cursor); break; } } @@ -212,9 +216,9 @@ int main(int argc, char *argv[]) { wl_display_run(compositor.display); compositor_fini(&compositor); - struct sample_cursor *cursor; - wl_list_for_each(cursor, &state.cursors, link) { - // TODO + struct sample_cursor *cursor, *tmp_cursor; + wl_list_for_each_safe(cursor, tmp_cursor, &state.cursors, link) { + cursor_destroy(cursor); } wlr_xcursor_theme_destroy(theme); From d2581eadbc8cc1613a04f10b8bdf113a00eaa240 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 31 Oct 2017 15:08:45 +0100 Subject: [PATCH 17/18] Assert mandatory impl fields in wlr_output_init --- types/wlr_output.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/types/wlr_output.c b/types/wlr_output.c index 38bb03d5..abfc6d26 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -191,6 +191,8 @@ void wlr_output_set_position(struct wlr_output *output, int32_t lx, void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, const struct wlr_output_impl *impl) { + assert(impl->enable && impl->make_current && impl->swap_buffers && + impl->transform); output->backend = backend; output->impl = impl; wl_list_init(&output->modes); From ec22fe713445977c1a122572107495b584117b16 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 31 Oct 2017 15:19:55 +0100 Subject: [PATCH 18/18] Make wlr_output_interface.enable optional --- backend/wayland/output.c | 2 +- types/wlr_output.c | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index c336eeb7..494e0522 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -189,7 +189,7 @@ static struct wlr_output_impl output_impl = { .make_current = wlr_wl_output_make_current, .swap_buffers = wlr_wl_output_swap_buffers, .set_cursor = wlr_wl_output_set_cursor, - .move_cursor = wlr_wl_output_move_cursor + .move_cursor = wlr_wl_output_move_cursor, }; static void xdg_surface_handle_configure(void *data, struct zxdg_surface_v6 *xdg_surface, diff --git a/types/wlr_output.c b/types/wlr_output.c index abfc6d26..44d24ae3 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -136,7 +136,9 @@ static void wlr_output_update_matrix(struct wlr_output *output) { } void wlr_output_enable(struct wlr_output *output, bool enable) { - output->impl->enable(output, enable); + if (output->impl->enable) { + output->impl->enable(output, enable); + } } bool wlr_output_set_mode(struct wlr_output *output, @@ -191,8 +193,7 @@ void wlr_output_set_position(struct wlr_output *output, int32_t lx, void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, const struct wlr_output_impl *impl) { - assert(impl->enable && impl->make_current && impl->swap_buffers && - impl->transform); + assert(impl->make_current && impl->swap_buffers && impl->transform); output->backend = backend; output->impl = impl; wl_list_init(&output->modes); @@ -337,12 +338,12 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, if (cursor->output->hardware_cursor == NULL && cursor->output->impl->set_cursor) { - // int ok = cursor->output->impl->set_cursor(cursor->output, pixels, - // stride, width, height, hotspot_x, hotspot_y, true); - // if (ok) { - // cursor->output->hardware_cursor = cursor; - // return true; - // } + int ok = cursor->output->impl->set_cursor(cursor->output, pixels, + stride, width, height, hotspot_x, hotspot_y, true); + if (ok) { + cursor->output->hardware_cursor = cursor; + return true; + } } wlr_log(L_INFO, "Falling back to software cursor");