diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 9e5346a1..ff4dc7f6 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -470,7 +470,7 @@ static void wlr_drm_connector_transform(struct wlr_output *output, static bool wlr_drm_connector_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) { + int32_t hotspot_x, int32_t hotspot_y, bool update_pixels) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = conn->drm; struct wlr_drm_renderer *renderer = &drm->renderer; @@ -478,7 +478,8 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, struct wlr_drm_crtc *crtc = conn->crtc; struct wlr_drm_plane *plane = crtc->cursor; - if (!buf) { + if (!buf && update_pixels) { + // Hide the cursor return drm->iface->crtc_set_cursor(drm, crtc, NULL); } @@ -566,6 +567,11 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, break; } + if (!update_pixels) { + // Only update the cursor hotspot + return true; + } + struct gbm_bo *bo = plane->cursor_bo; uint32_t bo_width = gbm_bo_get_width(bo); uint32_t bo_height = gbm_bo_get_height(bo); diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 03b43b35..d308b907 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -54,13 +54,24 @@ 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) { + 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 *backend = output->backend; + if (!update_pixels) { + // Update hotspot without changing cursor image + wlr_wl_output_update_cursor(output, output->enter_serial, hotspot_x, + hotspot_y); + return true; + } if (!buf) { - wl_pointer_set_cursor(output->backend->pointer, output->enter_serial, - NULL, 0, 0); + // Hide cursor + 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); return true; } @@ -153,7 +164,7 @@ static void wlr_wl_output_destroy(struct wlr_output *_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->cursor_surface && output->backend->pointer && serial) { + if (output->backend->pointer && serial) { wl_pointer_set_cursor(output->backend->pointer, serial, output->cursor_surface, hotspot_x, hotspot_y); } diff --git a/include/rootston/input.h b/include/rootston/input.h index fbabbdb6..516104a7 100644 --- a/include/rootston/input.h +++ b/include/rootston/input.h @@ -79,7 +79,7 @@ struct roots_input { struct wlr_xcursor_theme *theme; struct wlr_xcursor *xcursor; struct wlr_seat *wl_seat; - struct roots_view *client_cursor_view; + struct wl_client *cursor_client; enum roots_cursor_mode mode; struct roots_view *active_view, *last_active_view; diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index 7d2821e0..b7927569 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -8,16 +8,16 @@ struct wlr_output_impl { void (*enable)(struct wlr_output *output, bool enable); bool (*set_mode)(struct wlr_output *output, struct wlr_output_mode *mode); void (*transform)(struct wlr_output *output, - enum wl_output_transform transform); + enum wl_output_transform transform); 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); + int32_t stride, uint32_t width, uint32_t height, + int32_t hotspot_x, int32_t hotspot_y, bool update_pixels); bool (*move_cursor)(struct wlr_output *output, int x, int y); void (*destroy)(struct wlr_output *output); void (*make_current)(struct wlr_output *output); void (*swap_buffers)(struct wlr_output *output); void (*set_gamma)(struct wlr_output *output, - uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b); + uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b); uint16_t (*get_gamma_size)(struct wlr_output *output); }; @@ -25,6 +25,6 @@ void wlr_output_init(struct wlr_output *output, const struct wlr_output_impl *im void wlr_output_free(struct wlr_output *output); void wlr_output_update_matrix(struct wlr_output *output); struct wl_global *wlr_output_create_global( - struct wlr_output *wlr_output, struct wl_display *display); + struct wlr_output *wlr_output, struct wl_display *display); #endif diff --git a/rootston/cursor.c b/rootston/cursor.c index 8790934c..65109534 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -83,10 +83,16 @@ void cursor_update_position(struct roots_input *input, uint32_t time) { case ROOTS_CURSOR_PASSTHROUGH: view = view_at(desktop, input->cursor->x, input->cursor->y, &surface, &sx, &sy); - if (view != input->client_cursor_view) { + bool set_compositor_cursor = !view && input->cursor_client; + if (view) { + struct wl_client *view_client = + wl_resource_get_client(view->wlr_surface->resource); + set_compositor_cursor = view_client != input->cursor_client; + } + if (set_compositor_cursor) { wlr_log(L_DEBUG, "Switching to compositor cursor"); cursor_set_xcursor_image(input, input->xcursor->images[0]); - input->client_cursor_view = NULL; + input->cursor_client = NULL; } if (view) { wlr_seat_pointer_notify_enter(input->wl_seat, surface, sx, sy); @@ -301,18 +307,16 @@ static void handle_request_set_cursor(struct wl_listener *listener, request_set_cursor); struct wlr_seat_pointer_request_set_cursor_event *event = data; - struct wlr_surface *focused_surface = NULL; - double sx, sy; - struct roots_view *focused_view = view_at(input->server->desktop, - input->cursor->x, input->cursor->y, &focused_surface, &sx, &sy); - bool ok = focused_surface != NULL; - if (focused_surface != NULL) { + struct wlr_surface *focused_surface = + event->seat_handle->wlr_seat->pointer_state.focused_surface; + bool ok = focused_surface != NULL && focused_surface->resource != NULL; + if (ok) { struct wl_client *focused_client = wl_resource_get_client(focused_surface->resource); ok = event->client == focused_client; } if (!ok) { - wlr_log(L_DEBUG, "Denying request to set cursor outside view"); + wlr_log(L_DEBUG, "Denying request to set cursor from unfocused client"); return; } @@ -324,7 +328,7 @@ static void handle_request_set_cursor(struct wl_listener *listener, event->hotspot_x, event->hotspot_y); } - input->client_cursor_view = focused_view; + input->cursor_client = event->client; } void cursor_initialize(struct roots_input *input) { diff --git a/types/wlr_output.c b/types/wlr_output.c index 723dd00b..4c9814ef 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -127,7 +127,7 @@ static bool set_cursor(struct wlr_output *output, const uint8_t *buf, int32_t hotspot_y) { if (output->impl->set_cursor && output->impl->set_cursor(output, buf, stride, width, height, - hotspot_x, hotspot_y)) { + hotspot_x, hotspot_y, true)) { output->cursor.is_sw = false; return true; } @@ -179,6 +179,10 @@ static inline int64_t timespec_to_msec(const struct timespec *a) { static void commit_cursor_surface(struct wlr_output *output, struct wlr_surface *surface) { + if (output->cursor.is_sw) { + return; + } + struct wl_shm_buffer *buffer = wl_shm_buffer_get(surface->current->buffer); if (buffer == NULL) { return; @@ -231,14 +235,19 @@ static void handle_cursor_surface_destroy(struct wl_listener *listener, void wlr_output_set_cursor_surface(struct wlr_output *output, struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y) { - if (surface && strcmp(surface->role, "cursor") != 0) { + if (surface && strcmp(surface->role, "wl_pointer-cursor") != 0) { return; } output->cursor.hotspot_x = hotspot_x; output->cursor.hotspot_y = hotspot_y; - if (surface && output->cursor.surface == surface) { + 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); + } return; } @@ -248,11 +257,22 @@ void wlr_output_set_cursor_surface(struct wlr_output *output, output->cursor.surface = NULL; } + // Disable hardware cursor + // 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); + } + + //output->cursor.is_sw = output->impl->set_cursor == NULL; output->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); + wl_signal_add(&surface->events.destroy, + &output->cursor.surface_destroy); + commit_cursor_surface(output, surface); } else { set_cursor(output, NULL, 0, 0, 0, hotspot_x, hotspot_y); } @@ -333,10 +353,20 @@ void wlr_output_swap_buffers(struct wlr_output *output) { glViewport(0, 0, output->width, output->height); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - float matrix[16]; - wlr_texture_get_matrix(output->cursor.texture, &matrix, &output->transform_matrix, - output->cursor.x, output->cursor.y); - wlr_render_with_matrix(output->cursor.renderer, output->cursor.texture, &matrix); + + 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; + } + + if (texture && renderer) { + 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); + } } wl_signal_emit(&output->events.swap_buffers, &output); diff --git a/types/wlr_seat.c b/types/wlr_seat.c index bbb66142..ce055520 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -28,7 +28,7 @@ static void wl_pointer_set_cursor(struct wl_client *client, if (surface_resource != NULL) { surface = wl_resource_get_user_data(surface_resource); - if (wlr_surface_set_role(surface, "cursor", resource, + if (wlr_surface_set_role(surface, "wl_pointer-cursor", resource, WL_POINTER_ERROR_ROLE) < 0) { return; }