diff --git a/src/Makefile.am b/src/Makefile.am index aacec1829..e001eb55e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,12 +70,16 @@ libmutter_wayland_la_SOURCES = \ backends/meta-monitor-manager-dummy.h \ backends/edid-parse.c \ backends/edid.h \ + backends/native/meta-cursor-tracker-native.c \ + backends/native/meta-cursor-tracker-native.h \ backends/native/meta-idle-monitor-native.c \ backends/native/meta-idle-monitor-native.h \ backends/native/meta-monitor-manager-kms.c \ backends/native/meta-monitor-manager-kms.h \ backends/native/meta-weston-launch.c \ backends/native/meta-weston-launch.h \ + backends/x11/meta-cursor-tracker-x11.c \ + backends/x11/meta-cursor-tracker-x11.h \ backends/x11/meta-idle-monitor-xsync.c \ backends/x11/meta-idle-monitor-xsync.h \ backends/x11/meta-monitor-manager-xrandr.c \ diff --git a/src/backends/meta-cursor-private.h b/src/backends/meta-cursor-private.h index b1490212a..dd28cf5e5 100644 --- a/src/backends/meta-cursor-private.h +++ b/src/backends/meta-cursor-private.h @@ -27,6 +27,11 @@ #include #include +#include +#include +#include +#include + typedef struct { CoglTexture2D *texture; struct gbm_bo *bo; @@ -47,4 +52,26 @@ struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor, int *hot_x, int *hot_y); +void meta_cursor_reference_load_gbm_buffer (MetaCursorReference *cursor, + struct gbm_device *gbm, + uint8_t *pixels, + int width, + int height, + int rowstride, + uint32_t gbm_format); + +void meta_cursor_reference_import_gbm_buffer (MetaCursorReference *cursor, + struct gbm_device *gbm, + struct wl_resource *buffer, + int width, + int height); + +MetaCursorReference *meta_cursor_reference_from_xfixes_cursor_image (XFixesCursorImage *cursor_image); + +MetaCursorReference *meta_cursor_reference_from_xcursor_image (XcursorImage *xc_image); + +MetaCursorReference *meta_cursor_reference_from_buffer (struct wl_resource *buffer, + int hot_x, + int hot_y); + #endif /* META_CURSOR_PRIVATE_H */ diff --git a/src/backends/meta-cursor-tracker-private.h b/src/backends/meta-cursor-tracker-private.h index ef8de4b98..c2a25e9bf 100644 --- a/src/backends/meta-cursor-tracker-private.h +++ b/src/backends/meta-cursor-tracker-private.h @@ -30,10 +30,7 @@ struct _MetaCursorTracker { GObject parent_instance; - MetaScreen *screen; - gboolean is_showing; - gboolean has_hw_cursor; /* The cursor tracker stores the cursor for the current grab * operation, the cursor for the window with pointer focus, and @@ -51,7 +48,7 @@ struct _MetaCursorTracker { MetaCursorReference *grab_cursor; - /* Wayland clients can set a NULL buffer as their 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. @@ -62,23 +59,37 @@ struct _MetaCursorTracker { MetaCursorReference *root_cursor; MetaCursorReference *theme_cursors[META_CURSOR_LAST]; - - int current_x, current_y; - MetaRectangle current_rect; - MetaRectangle previous_rect; - gboolean previous_is_valid; - - CoglPipeline *pipeline; - int drm_fd; - struct gbm_device *gbm; }; struct _MetaCursorTrackerClass { GObjectClass parent_class; + + void (*get_pointer) (MetaCursorTracker *tracker, + int *x, + int *y, + ClutterModifierType *mods); + + void (*sync_cursor) (MetaCursorTracker *tracker); + + void (*ensure_cursor) (MetaCursorTracker *tracker); + + void (*load_cursor_pixels) (MetaCursorTracker *tracker, + MetaCursorReference *cursor, + uint8_t *pixels, + int width, + int height, + int rowstride, + uint32_t format); + + void (*load_cursor_buffer) (MetaCursorTracker *tracker, + MetaCursorReference *cursor, + struct wl_resource *buffer); }; -gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, - XEvent *xevent); +void _meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker, + gboolean has_cursor, + MetaCursorReference *cursor); +void _meta_cursor_tracker_sync_cursor (MetaCursorTracker *tracker); void meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker, MetaCursorReference *cursor); @@ -87,12 +98,13 @@ void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker, void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker); void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, MetaCursorReference *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_force_update (MetaCursorTracker *tracker); +MetaCursorReference * +meta_cursor_tracker_get_cursor_from_theme (MetaCursorTracker *tracker, + MetaCursor cursor); +MetaCursorReference * +meta_cursor_tracker_get_cursor_from_buffer (MetaCursorTracker *tracker, + struct wl_resource *buffer, + int hot_x, + int hot_y); #endif diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c index 28a6af2fc..c0d5072b5 100644 --- a/src/backends/meta-cursor-tracker.c +++ b/src/backends/meta-cursor-tracker.c @@ -33,20 +33,11 @@ #include #include -#include -#include -#include -#include - -#include -#include - #include "meta-cursor-private.h" #include "meta-cursor-tracker-private.h" +#include "backends/native/meta-cursor-tracker-native.h" +#include "backends/x11/meta-cursor-tracker-x11.h" #include "screen-private.h" -#include "meta-monitor-manager.h" - -#include "wayland/meta-wayland-private.h" G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT); @@ -57,11 +48,6 @@ enum { static guint signals[LAST_SIGNAL]; -static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker, - MetaCRTC *crtc, - gboolean has_hw_cursor); -static void sync_cursor (MetaCursorTracker *tracker); - static void meta_cursor_tracker_init (MetaCursorTracker *self) { @@ -88,14 +74,32 @@ meta_cursor_tracker_finalize (GObject *object) if (self->theme_cursors[i]) meta_cursor_reference_unref (self->theme_cursors[i]); - if (self->pipeline) - cogl_object_unref (self->pipeline); - if (self->gbm) - gbm_device_destroy (self->gbm); - G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object); } +static void +default_do_nothing (MetaCursorTracker *tracker) +{ +} + +static void +default_load_cursor_pixels (MetaCursorTracker *tracker, + MetaCursorReference *cursor, + uint8_t *pixels, + int width, + int height, + int rowstride, + uint32_t format) +{ +} + +static void +default_load_cursor_buffer (MetaCursorTracker *tracker, + MetaCursorReference *cursor, + struct wl_resource *buffer) +{ +} + static void meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass) { @@ -103,6 +107,11 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass) object_class->finalize = meta_cursor_tracker_finalize; + klass->sync_cursor = default_do_nothing; + klass->ensure_cursor = default_do_nothing; + klass->load_cursor_pixels = default_load_cursor_pixels; + klass->load_cursor_buffer = default_load_cursor_buffer; + signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, @@ -111,81 +120,6 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass) G_TYPE_NONE, 0); } -static void -on_monitors_changed (MetaMonitorManager *monitors, - MetaCursorTracker *tracker) -{ - MetaCRTC *crtcs; - unsigned int i, n_crtcs; - - if (!tracker->has_hw_cursor) - return; - - /* Go through the new list of monitors, find out where the cursor is */ - meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); - - for (i = 0; i < n_crtcs; i++) - { - MetaRectangle *rect = &crtcs[i].rect; - gboolean has; - - has = meta_rectangle_overlap (&tracker->current_rect, rect); - - /* Need to do it unconditionally here, our tracking is - wrong because we reloaded the CRTCs */ - meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has); - } -} - -static MetaCursorTracker * -make_wayland_cursor_tracker (MetaScreen *screen) -{ - MetaWaylandCompositor *compositor; - CoglContext *ctx; - MetaMonitorManager *monitors; - MetaCursorTracker *self; - - self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL); - self->screen = screen; - - ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - self->pipeline = cogl_pipeline_new (ctx); - - compositor = meta_wayland_compositor_get_default (); - compositor->seat->cursor_tracker = self; - meta_cursor_tracker_update_position (self, - wl_fixed_to_int (compositor->seat->pointer.x), - wl_fixed_to_int (compositor->seat->pointer.y)); - -#if defined(CLUTTER_WINDOWING_EGL) - if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) - { - CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx)); - self->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer); - self->gbm = gbm_create_device (self->drm_fd); - } -#endif - - monitors = meta_monitor_manager_get (); - g_signal_connect_object (monitors, "monitors-changed", - G_CALLBACK (on_monitors_changed), self, 0); - - return self; -} - -static MetaCursorTracker * -make_x11_cursor_tracker (MetaScreen *screen) -{ - MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL); - self->screen = screen; - - XFixesSelectCursorInput (screen->display->xdisplay, - screen->xroot, - XFixesDisplayCursorNotifyMask); - - return self; -} - /** * meta_cursor_tracker_get_for_screen: * @screen: the #MetaScreen @@ -203,127 +137,14 @@ meta_cursor_tracker_get_for_screen (MetaScreen *screen) return screen->cursor_tracker; if (meta_is_wayland_compositor ()) - self = make_wayland_cursor_tracker (screen); + self = g_object_new (META_TYPE_CURSOR_TRACKER_NATIVE, NULL); else - self = make_x11_cursor_tracker (screen); + self = g_object_new (META_TYPE_CURSOR_TRACKER_X11, NULL); screen->cursor_tracker = self; 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; - sync_cursor (tracker); -} - -gboolean -meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, - XEvent *xevent) -{ - XFixesCursorNotifyEvent *notify_event; - - if (meta_is_wayland_compositor ()) - return FALSE; - - if (xevent->xany.type != tracker->screen->display->xfixes_event_base + XFixesCursorNotify) - return FALSE; - - notify_event = (XFixesCursorNotifyEvent *)xevent; - if (notify_event->subtype != XFixesDisplayCursorNotify) - return FALSE; - - set_window_cursor (tracker, FALSE, NULL); - - return TRUE; -} - -static MetaCursorReference * -meta_cursor_reference_take_texture (CoglTexture2D *texture, - int hot_x, - int hot_y) -{ - MetaCursorReference *self; - - self = g_slice_new0 (MetaCursorReference); - self->ref_count = 1; - self->image.texture = texture; - self->image.hot_x = hot_x; - self->image.hot_y = hot_y; - - return self; -} - -static void -ensure_xfixes_cursor (MetaCursorTracker *tracker) -{ - XFixesCursorImage *cursor_image; - CoglTexture2D *sprite; - guint8 *cursor_data; - gboolean free_cursor_data; - CoglContext *ctx; - - if (tracker->has_window_cursor) - return; - - cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay); - if (!cursor_image) - return; - - /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit - * quantities as arrays of long; we need to convert on 64 bit */ - if (sizeof(long) == 4) - { - cursor_data = (guint8 *)cursor_image->pixels; - free_cursor_data = FALSE; - } - else - { - int i, j; - guint32 *cursor_words; - gulong *p; - guint32 *q; - - cursor_words = g_new (guint32, cursor_image->width * cursor_image->height); - cursor_data = (guint8 *)cursor_words; - - p = cursor_image->pixels; - q = cursor_words; - for (j = 0; j < cursor_image->height; j++) - for (i = 0; i < cursor_image->width; i++) - *(q++) = *(p++); - - free_cursor_data = TRUE; - } - - ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - sprite = cogl_texture_2d_new_from_data (ctx, - cursor_image->width, - cursor_image->height, - CLUTTER_CAIRO_FORMAT_ARGB32, - cursor_image->width * 4, /* stride */ - cursor_data, - NULL); - - if (free_cursor_data) - g_free (cursor_data); - - if (sprite != NULL) - { - MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite, - cursor_image->xhot, - cursor_image->yhot); - set_window_cursor (tracker, TRUE, cursor); - } - XFree (cursor_image); -} - /** * meta_cursor_tracker_get_sprite: * @@ -334,8 +155,7 @@ meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker) { g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL); - if (!meta_is_wayland_compositor ()) - ensure_xfixes_cursor (tracker); + META_CURSOR_TRACKER_GET_CLASS (tracker)->ensure_cursor (tracker); if (tracker->displayed_cursor) return meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, NULL, NULL); @@ -357,8 +177,7 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker, { g_return_if_fail (META_IS_CURSOR_TRACKER (tracker)); - if (!meta_is_wayland_compositor ()) - ensure_xfixes_cursor (tracker); + META_CURSOR_TRACKER_GET_CLASS (tracker)->ensure_cursor (tracker); if (tracker->displayed_cursor) meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, x, y); @@ -371,6 +190,32 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker, } } +void +_meta_cursor_tracker_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; + + _meta_cursor_tracker_sync_cursor (tracker); +} + +void +meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor) +{ + _meta_cursor_tracker_set_window_cursor (tracker, TRUE, cursor); +} + +void +meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker) +{ + _meta_cursor_tracker_set_window_cursor (tracker, FALSE, NULL); +} + void meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker, MetaCursorReference *cursor) @@ -379,20 +224,7 @@ meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker, if (cursor) tracker->grab_cursor = meta_cursor_reference_ref (cursor); - sync_cursor (tracker); -} - -void -meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker, - MetaCursorReference *cursor) -{ - set_window_cursor (tracker, TRUE, cursor); -} - -void -meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker) -{ - set_window_cursor (tracker, FALSE, NULL); + _meta_cursor_tracker_sync_cursor (tracker); } void @@ -403,70 +235,7 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, if (cursor) tracker->root_cursor = meta_cursor_reference_ref (cursor); - sync_cursor (tracker); -} - -static gboolean -should_have_hw_cursor (MetaCursorTracker *tracker) -{ - if (tracker->displayed_cursor) - return (meta_cursor_reference_get_gbm_bo (tracker->displayed_cursor, NULL, NULL) != NULL); - else - return FALSE; -} - -static void -update_hw_cursor (MetaCursorTracker *tracker) -{ - MetaMonitorManager *monitors; - MetaCRTC *crtcs; - unsigned int i, n_crtcs; - gboolean enabled; - - enabled = should_have_hw_cursor (tracker); - tracker->has_hw_cursor = enabled; - - monitors = meta_monitor_manager_get (); - meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); - - for (i = 0; i < n_crtcs; i++) - { - MetaRectangle *rect = &crtcs[i].rect; - gboolean has; - - has = enabled && meta_rectangle_overlap (&tracker->current_rect, rect); - - if (has || crtcs[i].has_hw_cursor) - meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has); - } -} - -static void -move_hw_cursor (MetaCursorTracker *tracker) -{ - MetaMonitorManager *monitors; - MetaCRTC *crtcs; - unsigned int i, n_crtcs; - - monitors = meta_monitor_manager_get (); - meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); - - g_assert (tracker->has_hw_cursor); - - for (i = 0; i < n_crtcs; i++) - { - MetaRectangle *rect = &crtcs[i].rect; - gboolean has; - - has = meta_rectangle_overlap (&tracker->current_rect, rect); - - if (has != crtcs[i].has_hw_cursor) - meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has); - if (has) - drmModeMoveCursor (tracker->drm_fd, crtcs[i].crtc_id, - tracker->current_rect.x - rect->x, - tracker->current_rect.y - rect->y); - } + _meta_cursor_tracker_sync_cursor (tracker); } static MetaCursorReference * @@ -484,25 +253,8 @@ get_displayed_cursor (MetaCursorTracker *tracker) return tracker->root_cursor; } -static void -update_displayed_cursor (MetaCursorTracker *tracker) -{ - if (meta_is_wayland_compositor ()) - { - if (tracker->displayed_cursor) - { - CoglTexture *texture = meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, NULL, NULL); - cogl_pipeline_set_layer_texture (tracker->pipeline, 0, texture); - } - else - cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL); - - update_hw_cursor (tracker); - } -} - -static void -sync_displayed_cursor (MetaCursorTracker *tracker) +void +_meta_cursor_tracker_sync_cursor (MetaCursorTracker *tracker) { MetaCursorReference *displayed_cursor = get_displayed_cursor (tracker); @@ -513,196 +265,18 @@ sync_displayed_cursor (MetaCursorTracker *tracker) if (displayed_cursor) tracker->displayed_cursor = meta_cursor_reference_ref (displayed_cursor); - update_displayed_cursor (tracker); + META_CURSOR_TRACKER_GET_CLASS (tracker)->sync_cursor (tracker); + g_signal_emit (tracker, signals[CURSOR_CHANGED], 0); } -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 ()); - - /* Clear the location the cursor was at before, if we need to. */ - if (tracker->previous_is_valid) - { - clip.x = tracker->previous_rect.x; - clip.y = tracker->previous_rect.y; - clip.width = tracker->previous_rect.width; - clip.height = tracker->previous_rect.height; - clutter_actor_queue_redraw_with_clip (stage, &clip); - tracker->previous_is_valid = FALSE; - } - - if (tracker->has_hw_cursor || !tracker->displayed_cursor) - return; - - clip.x = tracker->current_rect.x; - clip.y = tracker->current_rect.y; - clip.width = tracker->current_rect.width; - clip.height = tracker->current_rect.height; - 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) - { - CoglTexture *texture; - int hot_x, hot_y; - - texture = meta_cursor_reference_get_cogl_texture (displayed_cursor, &hot_x, &hot_y); - - tracker->current_rect.x = tracker->current_x - hot_x; - tracker->current_rect.y = tracker->current_y - hot_y; - tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture)); - tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture)); - } - else - { - tracker->current_rect.x = 0; - tracker->current_rect.y = 0; - tracker->current_rect.width = 0; - tracker->current_rect.height = 0; - } - - if (meta_is_wayland_compositor ()) - { - 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, - gboolean has) -{ - if (has) - { - MetaCursorReference *displayed_cursor = tracker->displayed_cursor; - struct gbm_bo *bo; - union gbm_bo_handle handle; - int width, height; - int hot_x, hot_y; - - bo = meta_cursor_reference_get_gbm_bo (displayed_cursor, &hot_x, &hot_y); - - handle = gbm_bo_get_handle (bo); - width = gbm_bo_get_width (bo); - height = gbm_bo_get_height (bo); - - drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, handle.u32, - width, height, hot_x, hot_y); - crtc->has_hw_cursor = TRUE; - } - else - { - drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0); - crtc->has_hw_cursor = FALSE; - } -} - -static void -get_pointer_position_gdk (int *x, - int *y, - int *mods) -{ - GdkDeviceManager *gmanager; - GdkDevice *gdevice; - GdkScreen *gscreen; - - gmanager = gdk_display_get_device_manager (gdk_display_get_default ()); - gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID); - - gdk_device_get_position (gdevice, &gscreen, x, y); - if (mods) - gdk_device_get_state (gdevice, - gdk_screen_get_root_window (gscreen), - NULL, (GdkModifierType*)mods); -} - -static void -get_pointer_position_clutter (int *x, - int *y, - int *mods) -{ - ClutterDeviceManager *cmanager; - ClutterInputDevice *cdevice; - ClutterPoint point; - - cmanager = clutter_device_manager_get_default (); - cdevice = clutter_device_manager_get_core_device (cmanager, CLUTTER_POINTER_DEVICE); - - clutter_input_device_get_coords (cdevice, NULL, &point); - if (x) - *x = point.x; - if (y) - *y = point.y; - if (mods) - *mods = clutter_input_device_get_modifier_state (cdevice); -} - void meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker, int *x, int *y, ClutterModifierType *mods) { - /* We can't use the clutter interface when not running as a wayland compositor, - because we need to query the server, rather than using the last cached value. - OTOH, on wayland we can't use GDK, because that only sees the events - we forward to xwayland. - */ - if (meta_is_wayland_compositor ()) - get_pointer_position_clutter (x, y, (int*)mods); - else - get_pointer_position_gdk (x, y, (int*)mods); + META_CURSOR_TRACKER_GET_CLASS (tracker)->get_pointer (tracker, x, y, mods); } void @@ -713,26 +287,51 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker, return; tracker->is_showing = visible; - if (meta_is_wayland_compositor ()) - { - sync_cursor (tracker); - } - else - { - if (visible) - XFixesShowCursor (tracker->screen->display->xdisplay, - tracker->screen->xroot); - else - XFixesHideCursor (tracker->screen->display->xdisplay, - tracker->screen->xroot); - } + _meta_cursor_tracker_sync_cursor (tracker); } -void -meta_cursor_tracker_force_update (MetaCursorTracker *tracker) +MetaCursorReference * +meta_cursor_tracker_get_cursor_from_theme (MetaCursorTracker *tracker, + MetaCursor meta_cursor) { - g_assert (meta_is_wayland_compositor ()); + MetaCursorReference *cursor; + XcursorImage *xc_image; - update_hw_cursor (tracker); - sync_cursor (tracker); + if (tracker->theme_cursors[meta_cursor]) + return meta_cursor_reference_ref (tracker->theme_cursors[meta_cursor]); + + xc_image = meta_display_load_x_cursor (meta_get_display (), meta_cursor); + if (!xc_image) + return NULL; + + cursor = meta_cursor_reference_from_xcursor_image (xc_image); + + META_CURSOR_TRACKER_GET_CLASS (tracker)->load_cursor_pixels (tracker, + cursor, + (uint8_t *) xc_image->pixels, + xc_image->width, + xc_image->height, + xc_image->width * 4, + GBM_FORMAT_ARGB8888); + XcursorImageDestroy (xc_image); + + tracker->theme_cursors[meta_cursor] = cursor; + + return meta_cursor_reference_ref (cursor); +} + +MetaCursorReference * +meta_cursor_tracker_get_cursor_from_buffer (MetaCursorTracker *tracker, + struct wl_resource *buffer, + int hot_x, + int hot_y) +{ + MetaCursorReference *cursor; + + cursor = meta_cursor_reference_from_buffer (buffer, hot_x, hot_y); + + META_CURSOR_TRACKER_GET_CLASS (tracker)->load_cursor_buffer (tracker, + cursor, + buffer); + return cursor; } diff --git a/src/backends/meta-cursor.c b/src/backends/meta-cursor.c index 2a78328ef..5551ef5b0 100644 --- a/src/backends/meta-cursor.c +++ b/src/backends/meta-cursor.c @@ -27,16 +27,23 @@ #include "display-private.h" #include "screen-private.h" -#include "meta-cursor-tracker-private.h" /* for tracker->gbm */ +#include "meta-cursor-tracker-private.h" #include -#include -#include -#include - #include +static MetaCursorReference * +meta_cursor_reference_new (void) +{ + MetaCursorReference *self; + + self = g_slice_new0 (MetaCursorReference); + self->ref_count = 1; + + return self; +} + MetaCursorReference * meta_cursor_reference_ref (MetaCursorReference *self) { @@ -190,14 +197,21 @@ load_cursor_on_client (MetaDisplay *display, return image; } -static void -meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm, - MetaCursorImage *image, - uint8_t *pixels, - int width, - int height, - int rowstride, - uint32_t gbm_format) +XcursorImage * +meta_display_load_x_cursor (MetaDisplay *display, + MetaCursor cursor) +{ + return load_cursor_on_client (display, cursor); +} + +void +meta_cursor_reference_load_gbm_buffer (MetaCursorReference *cursor, + struct gbm_device *gbm, + uint8_t *pixels, + int width, + int height, + int rowstride, + uint32_t gbm_format) { if (width > 64 || height > 64) { @@ -211,180 +225,154 @@ meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm, uint8_t buf[4 * 64 * 64]; int i; - image->bo = gbm_bo_create (gbm, 64, 64, - gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE); + cursor->image.bo = gbm_bo_create (gbm, 64, 64, + gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE); memset (buf, 0, sizeof(buf)); for (i = 0; i < height; i++) memcpy (buf + i * 4 * 64, pixels + i * rowstride, width * 4); - gbm_bo_write (image->bo, buf, 64 * 64 * 4); + gbm_bo_write (cursor->image.bo, buf, 64 * 64 * 4); } else meta_warning ("HW cursor for format %d not supported\n", gbm_format); } -static void -meta_cursor_image_load_from_xcursor_image (MetaCursorTracker *tracker, - MetaCursorImage *image, - XcursorImage *xc_image) +void +meta_cursor_reference_import_gbm_buffer (MetaCursorReference *cursor, + struct gbm_device *gbm, + struct wl_resource *buffer, + int width, + int height) { + /* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses + that, so themed cursors must be padded with transparent pixels to fill the + overlay. This is trivial if we have CPU access to the data, but it's not + possible if the buffer is in GPU memory (and possibly tiled too), so if we + don't get the right size, we fallback to GL. + */ + if (width != 64 || height != 64) + { + meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n"); + return; + } + + cursor->image.bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER, + buffer, GBM_BO_USE_CURSOR_64X64); + if (!cursor->image.bo) + meta_warning ("Importing HW cursor from wl_buffer failed\n"); +} + +MetaCursorReference * +meta_cursor_reference_from_xfixes_cursor_image (XFixesCursorImage *cursor_image) +{ + MetaCursorReference *cursor; + CoglTexture2D *sprite; + CoglContext *ctx; + guint8 *cursor_data; + gboolean free_cursor_data; + + cursor = meta_cursor_reference_new (); + + /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit + * quantities as arrays of long; we need to convert on 64 bit */ + if (sizeof(long) == 4) + { + cursor_data = (guint8 *)cursor_image->pixels; + free_cursor_data = FALSE; + } + else + { + int i, j; + guint32 *cursor_words; + gulong *p; + guint32 *q; + + cursor_words = g_new (guint32, cursor_image->width * cursor_image->height); + cursor_data = (guint8 *)cursor_words; + + p = cursor_image->pixels; + q = cursor_words; + for (j = 0; j < cursor_image->height; j++) + for (i = 0; i < cursor_image->width; i++) + *(q++) = *(p++); + + free_cursor_data = TRUE; + } + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + sprite = cogl_texture_2d_new_from_data (ctx, + cursor_image->width, + cursor_image->height, + CLUTTER_CAIRO_FORMAT_ARGB32, + cursor_image->width * 4, /* stride */ + cursor_data, + NULL); + if (free_cursor_data) + g_free (cursor_data); + + cursor->image.texture = sprite; + cursor->image.hot_x = cursor_image->xhot; + cursor->image.hot_y = cursor_image->yhot; + + return cursor; +} + +MetaCursorReference * +meta_cursor_reference_from_xcursor_image (XcursorImage *xc_image) +{ + MetaCursorReference *cursor; int width, height, rowstride; CoglPixelFormat cogl_format; - uint32_t gbm_format; ClutterBackend *clutter_backend; CoglContext *cogl_context; + cursor = meta_cursor_reference_new (); + width = xc_image->width; height = xc_image->height; rowstride = width * 4; - gbm_format = GBM_FORMAT_ARGB8888; #if G_BYTE_ORDER == G_LITTLE_ENDIAN cogl_format = COGL_PIXEL_FORMAT_BGRA_8888; #else cogl_format = COGL_PIXEL_FORMAT_ARGB_8888; #endif - image->hot_x = xc_image->xhot; - image->hot_y = xc_image->yhot; + cursor->image.hot_x = xc_image->xhot; + cursor->image.hot_y = xc_image->yhot; clutter_backend = clutter_get_default_backend (); cogl_context = clutter_backend_get_cogl_context (clutter_backend); - image->texture = cogl_texture_2d_new_from_data (cogl_context, - width, height, - cogl_format, - rowstride, - (uint8_t *) xc_image->pixels, - NULL); - - if (tracker->gbm) - meta_cursor_image_load_gbm_buffer (tracker->gbm, - image, - (uint8_t *) xc_image->pixels, - width, height, rowstride, - gbm_format); + cursor->image.texture = cogl_texture_2d_new_from_data (cogl_context, + width, height, + cogl_format, + rowstride, + (uint8_t *) xc_image->pixels, + NULL); + return cursor; } MetaCursorReference * -meta_cursor_reference_from_theme (MetaCursorTracker *tracker, - MetaCursor cursor) -{ - MetaCursorReference *self; - XcursorImage *image; - - if (tracker->theme_cursors[cursor]) - return meta_cursor_reference_ref (tracker->theme_cursors[cursor]); - - image = load_cursor_on_client (tracker->screen->display, cursor); - if (!image) - return NULL; - - self = g_slice_new0 (MetaCursorReference); - self->ref_count = 1; - meta_cursor_image_load_from_xcursor_image (tracker, &self->image, image); - - XcursorImageDestroy (image); - return self; -} - -static void -meta_cursor_image_load_from_buffer (MetaCursorTracker *tracker, - MetaCursorImage *image, - struct wl_resource *buffer, - int hot_x, - int hot_y) +meta_cursor_reference_from_buffer (struct wl_resource *buffer, + int hot_x, + int hot_y) { + MetaCursorReference *cursor; ClutterBackend *backend; CoglContext *cogl_context; - struct wl_shm_buffer *shm_buffer; - uint32_t gbm_format; - int width, height; - image->hot_x = hot_x; - image->hot_y = hot_y; + cursor = meta_cursor_reference_new (); + + cursor->image.hot_x = hot_x; + cursor->image.hot_y = hot_y; backend = clutter_get_default_backend (); cogl_context = clutter_backend_get_cogl_context (backend); - image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL); + cursor->image.texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL); - width = cogl_texture_get_width (COGL_TEXTURE (image->texture)); - height = cogl_texture_get_height (COGL_TEXTURE (image->texture)); - - shm_buffer = wl_shm_buffer_get (buffer); - if (shm_buffer) - { - if (tracker->gbm) - { - int rowstride = wl_shm_buffer_get_stride (shm_buffer); - - switch (wl_shm_buffer_get_format (shm_buffer)) - { -#if G_BYTE_ORDER == G_BIG_ENDIAN - case WL_SHM_FORMAT_ARGB8888: - gbm_format = GBM_FORMAT_ARGB8888; - break; - case WL_SHM_FORMAT_XRGB8888: - gbm_format = GBM_FORMAT_XRGB8888; - break; -#else - case WL_SHM_FORMAT_ARGB8888: - gbm_format = GBM_FORMAT_ARGB8888; - break; - case WL_SHM_FORMAT_XRGB8888: - gbm_format = GBM_FORMAT_XRGB8888; - break; -#endif - default: - g_warn_if_reached (); - gbm_format = GBM_FORMAT_ARGB8888; - } - - meta_cursor_image_load_gbm_buffer (tracker->gbm, - image, - (uint8_t *) wl_shm_buffer_get_data (shm_buffer), - width, height, rowstride, - gbm_format); - } - } - else - { - /* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses - that, so themed cursors must be padded with transparent pixels to fill the - overlay. This is trivial if we have CPU access to the data, but it's not - possible if the buffer is in GPU memory (and possibly tiled too), so if we - don't get the right size, we fallback to GL. - */ - if (width != 64 || height != 64) - { - meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n"); - return; - } - - if (tracker->gbm) - { - image->bo = gbm_bo_import (tracker->gbm, GBM_BO_IMPORT_WL_BUFFER, - buffer, GBM_BO_USE_CURSOR_64X64); - if (!image->bo) - meta_warning ("Importing HW cursor from wl_buffer failed\n"); - } - } -} - -MetaCursorReference * -meta_cursor_reference_from_buffer (MetaCursorTracker *tracker, - struct wl_resource *buffer, - int hot_x, - int hot_y) -{ - MetaCursorReference *self; - - self = g_slice_new0 (MetaCursorReference); - self->ref_count = 1; - meta_cursor_image_load_from_buffer (tracker, &self->image, buffer, hot_x, hot_y); - - return self; + return cursor; } CoglTexture * diff --git a/src/backends/meta-cursor.h b/src/backends/meta-cursor.h index 50ad086e7..6d5bc3ec3 100644 --- a/src/backends/meta-cursor.h +++ b/src/backends/meta-cursor.h @@ -27,16 +27,4 @@ typedef struct _MetaCursorReference MetaCursorReference; MetaCursorReference * meta_cursor_reference_ref (MetaCursorReference *cursor); void meta_cursor_reference_unref (MetaCursorReference *cursor); -#include -#include -#include - -MetaCursorReference * meta_cursor_reference_from_theme (MetaCursorTracker *tracker, - MetaCursor cursor); - -MetaCursorReference * meta_cursor_reference_from_buffer (MetaCursorTracker *tracker, - struct wl_resource *buffer, - int hot_x, - int hot_y); - #endif /* META_CURSOR_H */ diff --git a/src/backends/native/meta-cursor-tracker-native.c b/src/backends/native/meta-cursor-tracker-native.c new file mode 100644 index 000000000..e3093edde --- /dev/null +++ b/src/backends/native/meta-cursor-tracker-native.c @@ -0,0 +1,443 @@ +/* + * Copyright 2014 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "display-private.h" +#include "meta-cursor-tracker-native.h" +#include "meta-cursor-tracker-private.h" +#include "meta-monitor-manager.h" +#include "meta-cursor-private.h" + +#include "wayland/meta-wayland-private.h" + +struct _MetaCursorTrackerNative +{ + MetaCursorTracker parent; + + gboolean has_hw_cursor; + + int current_x, current_y; + MetaRectangle current_rect; + MetaRectangle previous_rect; + gboolean previous_is_valid; + + CoglPipeline *pipeline; + int drm_fd; + struct gbm_device *gbm; +}; + +struct _MetaCursorTrackerNativeClass +{ + MetaCursorTrackerClass parent_class; +}; + +G_DEFINE_TYPE (MetaCursorTrackerNative, meta_cursor_tracker_native, META_TYPE_CURSOR_TRACKER); + +static void +meta_cursor_tracker_native_load_cursor_pixels (MetaCursorTracker *tracker, + MetaCursorReference *cursor, + uint8_t *pixels, + int width, + int height, + int rowstride, + uint32_t format) +{ + MetaCursorTrackerNative *self = META_CURSOR_TRACKER_NATIVE (tracker); + + if (!self->gbm) + return; + + meta_cursor_reference_load_gbm_buffer (cursor, + self->gbm, + pixels, + width, height, rowstride, + format); +} + +static void +meta_cursor_tracker_native_load_cursor_buffer (MetaCursorTracker *tracker, + MetaCursorReference *cursor, + struct wl_resource *buffer) +{ + struct wl_shm_buffer *shm_buffer; + int width, height; + + width = cogl_texture_get_width (COGL_TEXTURE (cursor->image.texture)); + height = cogl_texture_get_height (COGL_TEXTURE (cursor->image.texture)); + + shm_buffer = wl_shm_buffer_get (buffer); + if (shm_buffer) + { + uint32_t gbm_format; + uint8_t *pixels = wl_shm_buffer_get_data (shm_buffer); + int rowstride = wl_shm_buffer_get_stride (shm_buffer); + + switch (wl_shm_buffer_get_format (shm_buffer)) + { +#if G_BYTE_ORDER == G_BIG_ENDIAN + case WL_SHM_FORMAT_ARGB8888: + gbm_format = GBM_FORMAT_ARGB8888; + break; + case WL_SHM_FORMAT_XRGB8888: + gbm_format = GBM_FORMAT_XRGB8888; + break; +#else + case WL_SHM_FORMAT_ARGB8888: + gbm_format = GBM_FORMAT_ARGB8888; + break; + case WL_SHM_FORMAT_XRGB8888: + gbm_format = GBM_FORMAT_XRGB8888; + break; +#endif + default: + g_warn_if_reached (); + gbm_format = GBM_FORMAT_ARGB8888; + } + + meta_cursor_tracker_native_load_cursor_pixels (tracker, + cursor, + pixels, + width, + height, + rowstride, + gbm_format); + } + else + { + MetaCursorTrackerNative *self = META_CURSOR_TRACKER_NATIVE (tracker); + if (!self->gbm) + return; + meta_cursor_reference_import_gbm_buffer (cursor, self->gbm, buffer, width, height); + } +} + +static void +set_crtc_has_hw_cursor (MetaCursorTrackerNative *self, + MetaCRTC *crtc, + gboolean has) +{ + MetaCursorTracker *tracker = META_CURSOR_TRACKER (self); + + if (has) + { + MetaCursorReference *displayed_cursor = tracker->displayed_cursor; + struct gbm_bo *bo; + union gbm_bo_handle handle; + int width, height; + int hot_x, hot_y; + + bo = meta_cursor_reference_get_gbm_bo (displayed_cursor, &hot_x, &hot_y); + + handle = gbm_bo_get_handle (bo); + width = gbm_bo_get_width (bo); + height = gbm_bo_get_height (bo); + + drmModeSetCursor2 (self->drm_fd, crtc->crtc_id, handle.u32, + width, height, hot_x, hot_y); + crtc->has_hw_cursor = TRUE; + } + else + { + drmModeSetCursor2 (self->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0); + crtc->has_hw_cursor = FALSE; + } +} + +static void +on_monitors_changed (MetaMonitorManager *monitors, + MetaCursorTrackerNative *self) +{ + MetaCRTC *crtcs; + unsigned int i, n_crtcs; + + if (!self->has_hw_cursor) + return; + + /* Go through the new list of monitors, find out where the cursor is */ + meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); + + for (i = 0; i < n_crtcs; i++) + { + MetaRectangle *rect = &crtcs[i].rect; + gboolean has; + + has = meta_rectangle_overlap (&self->current_rect, rect); + + /* Need to do it unconditionally here, our tracking is + wrong because we reloaded the CRTCs */ + set_crtc_has_hw_cursor (self, &crtcs[i], has); + } +} + +static gboolean +should_have_hw_cursor (MetaCursorTrackerNative *self) +{ + MetaCursorTracker *tracker = META_CURSOR_TRACKER (self); + + if (tracker->displayed_cursor) + return (meta_cursor_reference_get_gbm_bo (tracker->displayed_cursor, NULL, NULL) != NULL); + else + return FALSE; +} + +static void +update_hw_cursor (MetaCursorTrackerNative *self) +{ + MetaMonitorManager *monitors; + MetaCRTC *crtcs; + unsigned int i, n_crtcs; + gboolean enabled; + + enabled = should_have_hw_cursor (self); + self->has_hw_cursor = enabled; + + monitors = meta_monitor_manager_get (); + meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); + + for (i = 0; i < n_crtcs; i++) + { + MetaRectangle *rect = &crtcs[i].rect; + gboolean has; + + has = enabled && meta_rectangle_overlap (&self->current_rect, rect); + + if (has || crtcs[i].has_hw_cursor) + set_crtc_has_hw_cursor (self, &crtcs[i], has); + } +} + +static void +move_hw_cursor (MetaCursorTrackerNative *self) +{ + MetaMonitorManager *monitors; + MetaCRTC *crtcs; + unsigned int i, n_crtcs; + + monitors = meta_monitor_manager_get (); + meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); + + g_assert (self->has_hw_cursor); + + for (i = 0; i < n_crtcs; i++) + { + MetaRectangle *rect = &crtcs[i].rect; + gboolean has; + + has = meta_rectangle_overlap (&self->current_rect, rect); + + if (has != crtcs[i].has_hw_cursor) + set_crtc_has_hw_cursor (self, &crtcs[i], has); + if (has) + drmModeMoveCursor (self->drm_fd, crtcs[i].crtc_id, + self->current_rect.x - rect->x, + self->current_rect.y - rect->y); + } +} + +static void +queue_redraw (MetaCursorTrackerNative *self) +{ + MetaCursorTracker *tracker = META_CURSOR_TRACKER (self); + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + ClutterActor *stage = compositor->stage; + cairo_rectangle_int_t clip; + + /* Clear the location the cursor was at before, if we need to. */ + if (self->previous_is_valid) + { + clip.x = self->previous_rect.x; + clip.y = self->previous_rect.y; + clip.width = self->previous_rect.width; + clip.height = self->previous_rect.height; + clutter_actor_queue_redraw_with_clip (stage, &clip); + self->previous_is_valid = FALSE; + } + + if (self->has_hw_cursor || !tracker->displayed_cursor) + return; + + clip.x = self->current_rect.x; + clip.y = self->current_rect.y; + clip.width = self->current_rect.width; + clip.height = self->current_rect.height; + clutter_actor_queue_redraw_with_clip (stage, &clip); +} + +static void +meta_cursor_tracker_native_sync_cursor (MetaCursorTracker *tracker) +{ + MetaCursorTrackerNative *self = META_CURSOR_TRACKER_NATIVE (tracker); + MetaCursorReference *displayed_cursor; + + displayed_cursor = tracker->displayed_cursor; + + if (displayed_cursor) + { + CoglTexture *texture; + int hot_x, hot_y; + + texture = meta_cursor_reference_get_cogl_texture (displayed_cursor, &hot_x, &hot_y); + cogl_pipeline_set_layer_texture (self->pipeline, 0, texture); + + self->current_rect.x = self->current_x - hot_x; + self->current_rect.y = self->current_y - hot_y; + self->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture)); + self->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture)); + } + else + { + cogl_pipeline_set_layer_texture (self->pipeline, 0, NULL); + + self->current_rect.x = 0; + self->current_rect.y = 0; + self->current_rect.width = 0; + self->current_rect.height = 0; + } + + update_hw_cursor (self); + + if (self->has_hw_cursor) + move_hw_cursor (self); + else + queue_redraw (self); +} + +static void +meta_cursor_tracker_native_get_pointer (MetaCursorTracker *tracker, + int *x, + int *y, + ClutterModifierType *mods) +{ + ClutterDeviceManager *cmanager; + ClutterInputDevice *cdevice; + ClutterPoint point; + + /* On wayland we can't use GDK, because that only sees the events we + * forward to xwayland. + */ + cmanager = clutter_device_manager_get_default (); + cdevice = clutter_device_manager_get_core_device (cmanager, CLUTTER_POINTER_DEVICE); + + clutter_input_device_get_coords (cdevice, NULL, &point); + if (x) + *x = point.x; + if (y) + *y = point.y; + if (mods) + *mods = clutter_input_device_get_modifier_state (cdevice); +} + +static void +meta_cursor_tracker_native_finalize (GObject *object) +{ + MetaCursorTrackerNative *self = META_CURSOR_TRACKER_NATIVE (object); + + if (self->pipeline) + cogl_object_unref (self->pipeline); + if (self->gbm) + gbm_device_destroy (self->gbm); + + G_OBJECT_CLASS (meta_cursor_tracker_native_parent_class)->finalize (object); +} + +static void +meta_cursor_tracker_native_class_init (MetaCursorTrackerNativeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaCursorTrackerClass *cursor_tracker_class = META_CURSOR_TRACKER_CLASS (klass); + + object_class->finalize = meta_cursor_tracker_native_finalize; + + cursor_tracker_class->get_pointer = meta_cursor_tracker_native_get_pointer; + cursor_tracker_class->sync_cursor = meta_cursor_tracker_native_sync_cursor; + cursor_tracker_class->load_cursor_pixels = meta_cursor_tracker_native_load_cursor_pixels; + cursor_tracker_class->load_cursor_buffer = meta_cursor_tracker_native_load_cursor_buffer; +} + +static void +meta_cursor_tracker_native_init (MetaCursorTrackerNative *self) +{ + MetaWaylandCompositor *compositor; + CoglContext *ctx; + MetaMonitorManager *monitors; + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + self->pipeline = cogl_pipeline_new (ctx); + + compositor = meta_wayland_compositor_get_default (); + compositor->seat->cursor_tracker = META_CURSOR_TRACKER (self); + meta_cursor_tracker_native_update_position (self, + wl_fixed_to_int (compositor->seat->pointer.x), + wl_fixed_to_int (compositor->seat->pointer.y)); + +#if defined(CLUTTER_WINDOWING_EGL) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + { + CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx)); + self->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer); + self->gbm = gbm_create_device (self->drm_fd); + } +#endif + + monitors = meta_monitor_manager_get (); + g_signal_connect_object (monitors, "monitors-changed", + G_CALLBACK (on_monitors_changed), self, 0); +} + +void +meta_cursor_tracker_native_update_position (MetaCursorTrackerNative *self, + int new_x, + int new_y) +{ + self->current_x = new_x; + self->current_y = new_y; + + _meta_cursor_tracker_sync_cursor (META_CURSOR_TRACKER (self)); +} + +void +meta_cursor_tracker_native_paint (MetaCursorTrackerNative *self) +{ + MetaCursorTracker *tracker = META_CURSOR_TRACKER (self); + + if (self->has_hw_cursor || !tracker->displayed_cursor) + return; + + cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (), + self->pipeline, + self->current_rect.x, + self->current_rect.y, + self->current_rect.x + + self->current_rect.width, + self->current_rect.y + + self->current_rect.height); + + self->previous_rect = self->current_rect; + self->previous_is_valid = TRUE; +} + +void +meta_cursor_tracker_native_force_update (MetaCursorTrackerNative *self) +{ + _meta_cursor_tracker_sync_cursor (META_CURSOR_TRACKER (self)); +} diff --git a/src/backends/native/meta-cursor-tracker-native.h b/src/backends/native/meta-cursor-tracker-native.h new file mode 100644 index 000000000..9f969de4b --- /dev/null +++ b/src/backends/native/meta-cursor-tracker-native.h @@ -0,0 +1,43 @@ +/* + * Copyright 2014 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef META_CURSOR_TRACKER_NATIVE_H +#define META_CURSOR_TRACKER_NATIVE_H + +#include +#include + +#define META_TYPE_CURSOR_TRACKER_NATIVE (meta_cursor_tracker_native_get_type ()) +#define META_CURSOR_TRACKER_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_TRACKER_NATIVE, MetaCursorTrackerNative)) +#define META_CURSOR_TRACKER_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_TRACKER_NATIVE, MetaCursorTrackerNativeClass)) +#define META_IS_CURSOR_TRACKER_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_TRACKER_NATIVE)) +#define META_IS_CURSOR_TRACKER_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_TRACKER_NATIVE)) +#define META_CURSOR_TRACKER_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_TRACKER_NATIVE, MetaCursorTrackerNativeClass)) + +typedef struct _MetaCursorTrackerNative MetaCursorTrackerNative; +typedef struct _MetaCursorTrackerNativeClass MetaCursorTrackerNativeClass; + +GType meta_cursor_tracker_native_get_type (void); + +void meta_cursor_tracker_native_update_position (MetaCursorTrackerNative *tracker, + int new_x, + int new_y); +void meta_cursor_tracker_native_paint (MetaCursorTrackerNative *tracker); + +void meta_cursor_tracker_native_force_update (MetaCursorTrackerNative *tracker); + +#endif /* META_CURSOR_TRACKER_NATIVE_H */ diff --git a/src/backends/native/meta-weston-launch.c b/src/backends/native/meta-weston-launch.c index a77b2eaf7..43d7d25b7 100644 --- a/src/backends/native/meta-weston-launch.c +++ b/src/backends/native/meta-weston-launch.c @@ -44,6 +44,7 @@ #include "wayland/meta-wayland-private.h" #include "meta-cursor-tracker-private.h" +#include "meta-cursor-tracker-native.h" #include "meta-weston-launch.h" struct _MetaLauncher @@ -219,7 +220,7 @@ meta_launcher_enter (MetaLauncher *launcher) * update. */ clutter_actor_queue_redraw (compositor->stage); - meta_cursor_tracker_force_update (compositor->seat->cursor_tracker); + meta_cursor_tracker_native_force_update (META_CURSOR_TRACKER_NATIVE (compositor->seat->cursor_tracker)); } } diff --git a/src/backends/x11/meta-cursor-tracker-x11.c b/src/backends/x11/meta-cursor-tracker-x11.c new file mode 100644 index 000000000..d775275fc --- /dev/null +++ b/src/backends/x11/meta-cursor-tracker-x11.c @@ -0,0 +1,138 @@ +/* + * Copyright 2014 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "config.h" + +#include + +#include + +#include "display-private.h" +#include "meta-cursor-tracker-x11.h" +#include "meta-cursor-tracker-private.h" +#include "meta-cursor-private.h" + +struct _MetaCursorTrackerX11 +{ + MetaCursorTracker parent; +}; + +struct _MetaCursorTrackerX11Class +{ + MetaCursorTrackerClass parent_class; +}; + +G_DEFINE_TYPE (MetaCursorTrackerX11, meta_cursor_tracker_x11, META_TYPE_CURSOR_TRACKER); + +static void +meta_cursor_tracker_x11_get_pointer (MetaCursorTracker *tracker, + int *x, + int *y, + ClutterModifierType *mods) +{ + GdkDeviceManager *gmanager; + GdkDevice *gdevice; + GdkScreen *gscreen; + + /* We can't use the clutter interface when not running as a wayland + * compositor, because we need to query the server, rather than + * using the last cached value. + */ + gmanager = gdk_display_get_device_manager (gdk_display_get_default ()); + gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID); + + gdk_device_get_position (gdevice, &gscreen, x, y); + if (mods) + gdk_device_get_state (gdevice, + gdk_screen_get_root_window (gscreen), + NULL, (GdkModifierType*)mods); +} + +static void +meta_cursor_tracker_x11_sync_cursor (MetaCursorTracker *tracker) +{ + MetaDisplay *display = meta_get_display (); + + meta_error_trap_push (display); + if (tracker->is_showing) + XFixesShowCursor (display->xdisplay, + DefaultRootWindow (display->xdisplay)); + else + XFixesHideCursor (display->xdisplay, + DefaultRootWindow (display->xdisplay)); + meta_error_trap_pop (display); +} + +static void +meta_cursor_tracker_x11_ensure_cursor (MetaCursorTracker *tracker) +{ + MetaDisplay *display = meta_get_display (); + XFixesCursorImage *cursor_image; + MetaCursorReference *cursor; + + if (tracker->has_window_cursor) + return; + + cursor_image = XFixesGetCursorImage (display->xdisplay); + if (!cursor_image) + return; + + cursor = meta_cursor_reference_from_xfixes_cursor_image (cursor_image); + + _meta_cursor_tracker_set_window_cursor (tracker, TRUE, cursor); + + XFree (cursor_image); +} + +static void +meta_cursor_tracker_x11_class_init (MetaCursorTrackerX11Class *klass) +{ + MetaCursorTrackerClass *cursor_tracker_class = META_CURSOR_TRACKER_CLASS (klass); + + cursor_tracker_class->get_pointer = meta_cursor_tracker_x11_get_pointer; + cursor_tracker_class->sync_cursor = meta_cursor_tracker_x11_sync_cursor; + cursor_tracker_class->ensure_cursor = meta_cursor_tracker_x11_ensure_cursor; +} + +static void +meta_cursor_tracker_x11_init (MetaCursorTrackerX11 *self) +{ + MetaDisplay *display = meta_get_display (); + + XFixesSelectCursorInput (display->xdisplay, + DefaultRootWindow (display->xdisplay), + XFixesDisplayCursorNotifyMask); +} + +gboolean +meta_cursor_tracker_x11_handle_xevent (MetaCursorTrackerX11 *tracker, + XEvent *xevent) +{ + MetaDisplay *display = meta_get_display (); + XFixesCursorNotifyEvent *notify_event; + + if (xevent->xany.type != display->xfixes_event_base + XFixesCursorNotify) + return FALSE; + + notify_event = (XFixesCursorNotifyEvent *)xevent; + if (notify_event->subtype != XFixesDisplayCursorNotify) + return FALSE; + + _meta_cursor_tracker_set_window_cursor (META_CURSOR_TRACKER (tracker), FALSE, NULL); + + return TRUE; +} diff --git a/src/backends/x11/meta-cursor-tracker-x11.h b/src/backends/x11/meta-cursor-tracker-x11.h new file mode 100644 index 000000000..30b844658 --- /dev/null +++ b/src/backends/x11/meta-cursor-tracker-x11.h @@ -0,0 +1,40 @@ +/* + * Copyright 2014 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef META_CURSOR_TRACKER_X11_H +#define META_CURSOR_TRACKER_X11_H + +#include +#include + +#define META_TYPE_CURSOR_TRACKER_X11 (meta_cursor_tracker_x11_get_type ()) +#define META_CURSOR_TRACKER_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_TRACKER_X11, MetaCursorTrackerX11)) +#define META_CURSOR_TRACKER_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_TRACKER_X11, MetaCursorTrackerX11Class)) +#define META_IS_CURSOR_TRACKER_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_TRACKER_X11)) +#define META_IS_CURSOR_TRACKER_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_TRACKER_X11)) +#define META_CURSOR_TRACKER_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_TRACKER_X11, MetaCursorTrackerX11Class)) + +typedef struct _MetaCursorTrackerX11 MetaCursorTrackerX11; +typedef struct _MetaCursorTrackerX11Class MetaCursorTrackerX11Class; + +GType meta_cursor_tracker_x11_get_type (void); + +gboolean +meta_cursor_tracker_x11_handle_xevent (MetaCursorTrackerX11 *tracker, + XEvent *xevent); + +#endif /* META_CURSOR_TRACKER_X11_H */ diff --git a/src/core/display-private.h b/src/core/display-private.h index 1b8355c72..64751d0ad 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -397,6 +398,8 @@ MetaDisplay* meta_get_display (void); Cursor meta_display_create_x_cursor (MetaDisplay *display, MetaCursor cursor); +XcursorImage *meta_display_load_x_cursor (MetaDisplay *display, + MetaCursor cursor); void meta_display_set_grab_op_cursor (MetaDisplay *display, MetaScreen *screen, diff --git a/src/core/display.c b/src/core/display.c index 716f864f9..cb1b7739b 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -1873,7 +1873,7 @@ meta_display_set_grab_op_cursor (MetaDisplay *display, meta_error_trap_pop (display); - cursor_ref = meta_cursor_reference_from_theme (screen->cursor_tracker, cursor); + cursor_ref = meta_cursor_tracker_get_cursor_from_theme (screen->cursor_tracker, cursor); meta_cursor_tracker_set_grab_cursor (screen->cursor_tracker, cursor_ref); meta_cursor_reference_unref (cursor_ref); } diff --git a/src/core/screen.c b/src/core/screen.c index 030bab78c..e00c4e6a6 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -43,6 +43,7 @@ #include "mutter-enum-types.h" #include "core.h" #include "meta-cursor-tracker-private.h" +#include "backends/x11/meta-cursor-tracker-x11.h" #include @@ -1389,7 +1390,7 @@ meta_screen_update_cursor (MetaScreen *screen) Cursor xcursor; MetaCursorReference *cursor_ref; - cursor_ref = meta_cursor_reference_from_theme (screen->cursor_tracker, cursor); + cursor_ref = meta_cursor_tracker_get_cursor_from_theme (screen->cursor_tracker, cursor); meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor_ref); meta_cursor_reference_unref (cursor_ref); @@ -3305,7 +3306,10 @@ gboolean meta_screen_handle_xevent (MetaScreen *screen, XEvent *xevent) { - if (meta_cursor_tracker_handle_xevent (screen->cursor_tracker, xevent)) + if (meta_is_wayland_compositor ()) + return FALSE; + + if (meta_cursor_tracker_x11_handle_xevent (META_CURSOR_TRACKER_X11 (screen->cursor_tracker), xevent)) return TRUE; return FALSE; diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c index f5e3867a4..eb025bc59 100644 --- a/src/wayland/meta-wayland-seat.c +++ b/src/wayland/meta-wayland-seat.c @@ -38,6 +38,7 @@ #include "meta-shaped-texture-private.h" #include "meta-wayland-stage.h" #include "meta-cursor-tracker-private.h" +#include "backends/native/meta-cursor-tracker-native.h" #include "meta-surface-actor-wayland.h" #define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10) @@ -76,10 +77,10 @@ meta_wayland_seat_update_cursor_surface (MetaWaylandSeat *seat) if (seat->cursor_surface && seat->cursor_surface->buffer) { struct wl_resource *buffer = seat->cursor_surface->buffer->resource; - cursor = meta_cursor_reference_from_buffer (seat->cursor_tracker, - buffer, - seat->hotspot_x, - seat->hotspot_y); + cursor = meta_cursor_tracker_get_cursor_from_buffer (seat->cursor_tracker, + buffer, + seat->hotspot_x, + seat->hotspot_y); } else cursor = NULL; @@ -386,9 +387,9 @@ meta_wayland_seat_update_pointer (MetaWaylandSeat *seat, if (seat->cursor_tracker) { - meta_cursor_tracker_update_position (seat->cursor_tracker, - wl_fixed_to_int (seat->pointer.x), - wl_fixed_to_int (seat->pointer.y)); + meta_cursor_tracker_native_update_position (META_CURSOR_TRACKER_NATIVE (seat->cursor_tracker), + wl_fixed_to_int (seat->pointer.x), + wl_fixed_to_int (seat->pointer.y)); if (seat->pointer.current == NULL) meta_cursor_tracker_unset_window_cursor (seat->cursor_tracker); diff --git a/src/wayland/meta-wayland-stage.c b/src/wayland/meta-wayland-stage.c index b795dd570..91d7be84d 100644 --- a/src/wayland/meta-wayland-stage.c +++ b/src/wayland/meta-wayland-stage.c @@ -30,6 +30,7 @@ #include "meta/meta-window-actor.h" #include "meta/meta-shaped-texture.h" #include "meta-cursor-tracker-private.h" +#include "backends/native/meta-cursor-tracker-native.h" G_DEFINE_TYPE (MetaWaylandStage, meta_wayland_stage, CLUTTER_TYPE_STAGE); @@ -42,7 +43,7 @@ meta_wayland_stage_paint (ClutterActor *actor) compositor = meta_wayland_compositor_get_default (); if (compositor->seat->cursor_tracker) - meta_cursor_tracker_paint (compositor->seat->cursor_tracker); + meta_cursor_tracker_native_paint (META_CURSOR_TRACKER_NATIVE (compositor->seat->cursor_tracker)); } static void