From d96b053c9d5eb602407578481bbd3b9f1af47499 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Mon, 18 Nov 2013 19:19:42 -0500 Subject: [PATCH] cursor-tracker: Use a sync methodology for the cursor image Rather than have MetaWaylandSeat do all the state management itself, put the split between the root cursor and the window cursor in the cursor tracker itself. We'll expand this to add a "grab" cursor in the next commit, allowing us to force a cursor on grab operations. --- src/core/meta-cursor-tracker-private.h | 16 +- src/core/meta-cursor-tracker.c | 281 ++++++++++++++----------- src/wayland/meta-wayland-seat.c | 26 +-- 3 files changed, 176 insertions(+), 147 deletions(-) diff --git a/src/core/meta-cursor-tracker-private.h b/src/core/meta-cursor-tracker-private.h index e18d31522..ffa08df2b 100644 --- a/src/core/meta-cursor-tracker-private.h +++ b/src/core/meta-cursor-tracker-private.h @@ -31,18 +31,16 @@ gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, XEvent *xevent); -void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, - MetaCursor cursor); -void meta_cursor_tracker_revert_root (MetaCursorTracker *tracker); -void meta_cursor_tracker_set_buffer (MetaCursorTracker *tracker, - struct wl_resource *buffer, - int hot_x, - int hot_y); +void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker, + struct wl_resource *buffer, + int hot_x, + int hot_y); +void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker); +void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, + MetaCursor cursor); void meta_cursor_tracker_update_position (MetaCursorTracker *tracker, int new_x, int new_y); void meta_cursor_tracker_paint (MetaCursorTracker *tracker); -void meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker, - ClutterActor *stage); #endif diff --git a/src/core/meta-cursor-tracker.c b/src/core/meta-cursor-tracker.c index cff5f3eee..e4cf92f50 100644 --- a/src/core/meta-cursor-tracker.c +++ b/src/core/meta-cursor-tracker.c @@ -68,11 +68,31 @@ struct _MetaCursorTracker { MetaScreen *screen; gboolean is_showing; - gboolean has_cursor; gboolean has_hw_cursor; - MetaCursorReference *sprite; + /* The cursor tracker stores the cursor for the window with + * pointer focus, and the cursor for the root window, which + * contains either the default arrow cursor or the 'busy' + * hourglass if we're launching an app. + * + * We choose the first one available -- if there's a window + * cursor, we choose that, otherwise we choose the root + * cursor. + * + * The displayed_cursor contains the chosen cursor. + */ + MetaCursorReference *displayed_cursor; + + /* Wayland clients can set a NULL buffer as their cursor + * explicitly, which means that we shouldn't display anything. + * So, we can't simply store a NULL in window_cursor to + * determine an unset window cursor; we need an extra boolean. + */ + gboolean has_window_cursor; + MetaCursorReference *window_cursor; + MetaCursorReference *root_cursor; + MetaCursorReference *default_cursors[META_CURSOR_LAST]; int current_x, current_y; @@ -98,9 +118,6 @@ enum { static guint signals[LAST_SIGNAL]; -static void meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker, - MetaCursorReference *sprite); - static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker, MetaCRTC *crtc, gboolean has_hw_cursor); @@ -354,7 +371,7 @@ meta_cursor_reference_from_buffer (MetaCursorTracker *tracker, self->ref_count = 1; self->hot_x = hot_x; self->hot_y = hot_y; - + backend = clutter_get_default_backend (); cogl_context = clutter_backend_get_cogl_context (backend); @@ -520,8 +537,8 @@ meta_cursor_tracker_finalize (GObject *object) MetaCursorTracker *self = META_CURSOR_TRACKER (object); int i; - if (self->sprite) - meta_cursor_reference_unref (self->sprite); + if (self->displayed_cursor) + meta_cursor_reference_unref (self->displayed_cursor); if (self->root_cursor) meta_cursor_reference_unref (self->root_cursor); @@ -646,6 +663,17 @@ meta_cursor_tracker_get_for_screen (MetaScreen *screen) return self; } +static void +set_window_cursor (MetaCursorTracker *tracker, + gboolean has_cursor, + MetaCursorReference *cursor) +{ + g_clear_pointer (&tracker->window_cursor, meta_cursor_reference_unref); + if (cursor) + tracker->window_cursor = meta_cursor_reference_ref (cursor); + tracker->has_window_cursor = has_cursor; +} + gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, XEvent *xevent) @@ -662,7 +690,7 @@ meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, if (notify_event->subtype != XFixesDisplayCursorNotify) return FALSE; - g_clear_pointer (&tracker->sprite, meta_cursor_reference_unref); + set_window_cursor (tracker, FALSE, NULL); g_signal_emit (tracker, signals[CURSOR_CHANGED], 0); return TRUE; @@ -677,7 +705,7 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker) gboolean free_cursor_data; CoglContext *ctx; - if (tracker->sprite) + if (tracker->has_window_cursor) return; cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay); @@ -725,9 +753,11 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker) if (sprite != NULL) { - tracker->sprite = meta_cursor_reference_take_texture (sprite); - tracker->sprite->hot_x = cursor_image->xhot; - tracker->sprite->hot_y = cursor_image->yhot; + MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite); + cursor->hot_x = cursor_image->xhot; + cursor->hot_y = cursor_image->yhot; + + set_window_cursor (tracker, TRUE, cursor); } XFree (cursor_image); } @@ -745,8 +775,8 @@ meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker) if (!meta_is_wayland_compositor ()) ensure_xfixes_cursor (tracker); - if (tracker->sprite) - return COGL_TEXTURE (tracker->sprite->texture); + if (tracker->displayed_cursor) + return COGL_TEXTURE (tracker->displayed_cursor->texture); else return NULL; } @@ -768,12 +798,13 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker, if (!meta_is_wayland_compositor ()) ensure_xfixes_cursor (tracker); - if (tracker->sprite) + if (tracker->displayed_cursor) { + MetaCursorReference *displayed_cursor = tracker->displayed_cursor; if (x) - *x = tracker->sprite->hot_x; + *x = displayed_cursor->hot_x; if (y) - *y = tracker->sprite->hot_y; + *y = displayed_cursor->hot_y; } else { @@ -798,6 +829,28 @@ ensure_wayland_cursor (MetaCursorTracker *tracker, return tracker->default_cursors[cursor]; } +void +meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker, + struct wl_resource *buffer, + int hot_x, + int hot_y) +{ + MetaCursorReference *cursor; + + if (buffer) + cursor = meta_cursor_reference_from_buffer (tracker, buffer, hot_x, hot_y); + else + cursor = NULL; + + set_window_cursor (tracker, TRUE, cursor); +} + +void +meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker) +{ + set_window_cursor (tracker, FALSE, NULL); +} + void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, MetaCursor cursor) @@ -824,12 +877,6 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, } } -void -meta_cursor_tracker_revert_root (MetaCursorTracker *tracker) -{ - meta_cursor_tracker_set_sprite (tracker, tracker->root_cursor); -} - static void update_hw_cursor (MetaCursorTracker *tracker) { @@ -838,7 +885,7 @@ update_hw_cursor (MetaCursorTracker *tracker) unsigned int i, n_crtcs; gboolean enabled; - enabled = tracker->has_cursor && tracker->sprite->bo != NULL; + enabled = tracker->displayed_cursor && tracker->displayed_cursor->bo != NULL; tracker->has_hw_cursor = enabled; monitors = meta_monitor_manager_get (); @@ -884,105 +931,45 @@ move_hw_cursor (MetaCursorTracker *tracker) } } -void -meta_cursor_tracker_set_buffer (MetaCursorTracker *tracker, - struct wl_resource *buffer, - int hot_x, - int hot_y) +static MetaCursorReference * +get_displayed_cursor (MetaCursorTracker *tracker) { - MetaCursorReference *new_cursor; + if (!tracker->is_showing) + return NULL; - if (buffer) - { - new_cursor = meta_cursor_reference_from_buffer (tracker, buffer, hot_x, hot_y); - meta_cursor_tracker_set_sprite (tracker, new_cursor); - meta_cursor_reference_unref (new_cursor); - } - else - meta_cursor_tracker_set_sprite (tracker, NULL); + if (tracker->has_window_cursor) + return tracker->window_cursor; + + return tracker->root_cursor; } static void -meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker, - MetaCursorReference *sprite) +sync_displayed_cursor (MetaCursorTracker *tracker) { - g_assert (meta_is_wayland_compositor ()); + MetaCursorReference *displayed_cursor = get_displayed_cursor (tracker); - if (sprite == tracker->sprite) + if (tracker->displayed_cursor == displayed_cursor) return; - g_clear_pointer (&tracker->sprite, meta_cursor_reference_unref); + g_clear_pointer (&tracker->displayed_cursor, meta_cursor_reference_unref); + if (displayed_cursor) + tracker->displayed_cursor = meta_cursor_reference_ref (displayed_cursor); - if (sprite) - { - tracker->sprite = meta_cursor_reference_ref (sprite); - cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (tracker->sprite->texture)); - } + if (displayed_cursor) + cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (displayed_cursor->texture)); else cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL); - tracker->has_cursor = tracker->sprite != NULL && tracker->is_showing; update_hw_cursor (tracker); g_signal_emit (tracker, signals[CURSOR_CHANGED], 0); - - meta_cursor_tracker_update_position (tracker, tracker->current_x, tracker->current_y); } -void -meta_cursor_tracker_update_position (MetaCursorTracker *tracker, - int new_x, - int new_y) -{ - g_assert (meta_is_wayland_compositor ()); - - tracker->current_x = new_x; - tracker->current_y = new_y; - - if (tracker->sprite) - { - tracker->current_rect.x = tracker->current_x - tracker->sprite->hot_x; - tracker->current_rect.y = tracker->current_y - tracker->sprite->hot_y; - tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (tracker->sprite->texture)); - tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (tracker->sprite->texture)); - } - else - { - tracker->current_rect.x = 0; - tracker->current_rect.y = 0; - tracker->current_rect.width = 0; - tracker->current_rect.height = 0; - } - - if (tracker->has_hw_cursor) - move_hw_cursor (tracker); -} - -void -meta_cursor_tracker_paint (MetaCursorTracker *tracker) -{ - g_assert (meta_is_wayland_compositor ()); - - if (tracker->has_hw_cursor || !tracker->has_cursor) - return; - - cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (), - tracker->pipeline, - tracker->current_rect.x, - tracker->current_rect.y, - tracker->current_rect.x + - tracker->current_rect.width, - tracker->current_rect.y + - tracker->current_rect.height); - - tracker->previous_rect = tracker->current_rect; - tracker->previous_is_valid = TRUE; -} - -void -meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker, - ClutterActor *stage) +static void +meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker) { + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + ClutterActor *stage = compositor->stage; cairo_rectangle_int_t clip; g_assert (meta_is_wayland_compositor ()); @@ -999,7 +986,7 @@ meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker, tracker->previous_is_valid = FALSE; } - if (tracker->has_hw_cursor || !tracker->has_cursor) + if (tracker->has_hw_cursor || !tracker->displayed_cursor) return; clip.x = tracker->current_rect.x; @@ -1009,6 +996,69 @@ meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker, clutter_actor_queue_redraw_with_clip (stage, &clip); } +static void +sync_cursor (MetaCursorTracker *tracker) +{ + MetaCursorReference *displayed_cursor; + + sync_displayed_cursor (tracker); + displayed_cursor = tracker->displayed_cursor; + + if (displayed_cursor) + { + tracker->current_rect.x = tracker->current_x - displayed_cursor->hot_x; + tracker->current_rect.y = tracker->current_y - displayed_cursor->hot_y; + tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (displayed_cursor->texture)); + tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (displayed_cursor->texture)); + } + else + { + tracker->current_rect.x = 0; + tracker->current_rect.y = 0; + tracker->current_rect.width = 0; + tracker->current_rect.height = 0; + } + + if (tracker->has_hw_cursor) + move_hw_cursor (tracker); + else + meta_cursor_tracker_queue_redraw (tracker); +} + +void +meta_cursor_tracker_update_position (MetaCursorTracker *tracker, + int new_x, + int new_y) +{ + g_assert (meta_is_wayland_compositor ()); + + tracker->current_x = new_x; + tracker->current_y = new_y; + + sync_cursor (tracker); +} + +void +meta_cursor_tracker_paint (MetaCursorTracker *tracker) +{ + g_assert (meta_is_wayland_compositor ()); + + if (tracker->has_hw_cursor || !tracker->displayed_cursor) + return; + + cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (), + tracker->pipeline, + tracker->current_rect.x, + tracker->current_rect.y, + tracker->current_rect.x + + tracker->current_rect.width, + tracker->current_rect.y + + tracker->current_rect.height); + + tracker->previous_rect = tracker->current_rect; + tracker->previous_is_valid = TRUE; +} + static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker, MetaCRTC *crtc, @@ -1016,15 +1066,16 @@ meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker, { if (has) { + MetaCursorReference *displayed_cursor = tracker->displayed_cursor; union gbm_bo_handle handle; int width, height; int hot_x, hot_y; - handle = gbm_bo_get_handle (tracker->sprite->bo); - width = gbm_bo_get_width (tracker->sprite->bo); - height = gbm_bo_get_height (tracker->sprite->bo); - hot_x = tracker->sprite->hot_x; - hot_y = tracker->sprite->hot_y; + handle = gbm_bo_get_handle (displayed_cursor->bo); + width = gbm_bo_get_width (displayed_cursor->bo); + height = gbm_bo_get_height (displayed_cursor->bo); + hot_x = displayed_cursor->hot_x; + hot_y = displayed_cursor->hot_y; drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, handle.u32, width, height, hot_x, hot_y); @@ -1100,13 +1151,7 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker, if (meta_is_wayland_compositor ()) { - MetaWaylandCompositor *compositor; - - compositor = meta_wayland_compositor_get_default (); - - tracker->has_cursor = tracker->sprite != NULL && visible; - update_hw_cursor (tracker); - meta_cursor_tracker_queue_redraw (tracker, compositor->stage); + sync_cursor (tracker); } else { diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c index 0b9415a83..377e7f2c7 100644 --- a/src/wayland/meta-wayland-seat.c +++ b/src/wayland/meta-wayland-seat.c @@ -51,14 +51,7 @@ static void pointer_unmap_sprite (MetaWaylandSeat *seat) { if (seat->cursor_tracker) - { - meta_cursor_tracker_set_buffer (seat->cursor_tracker, - NULL, 0, 0); - - if (seat->current_stage) - meta_cursor_tracker_queue_redraw (seat->cursor_tracker, - CLUTTER_ACTOR (seat->current_stage)); - } + meta_cursor_tracker_set_window_cursor (seat->cursor_tracker, NULL, 0, 0); if (seat->sprite) { @@ -76,14 +69,10 @@ meta_wayland_seat_update_sprite (MetaWaylandSeat *seat) return; buffer = seat->sprite->buffer_ref.buffer->resource; - meta_cursor_tracker_set_buffer (seat->cursor_tracker, - buffer, - seat->hotspot_x, - seat->hotspot_y); - - if (seat->current_stage) - meta_cursor_tracker_queue_redraw (seat->cursor_tracker, - CLUTTER_ACTOR (seat->current_stage)); + meta_cursor_tracker_set_window_cursor (seat->cursor_tracker, + buffer, + seat->hotspot_x, + seat->hotspot_y); } static void @@ -377,10 +366,7 @@ meta_wayland_seat_update_pointer (MetaWaylandSeat *seat, wl_fixed_to_int (seat->pointer.y)); if (seat->pointer.current == NULL) - meta_cursor_tracker_revert_root (seat->cursor_tracker); - - meta_cursor_tracker_queue_redraw (seat->cursor_tracker, - CLUTTER_ACTOR (event->any.stage)); + meta_cursor_tracker_unset_window_cursor (seat->cursor_tracker); } }