diff --git a/src/Makefile.am b/src/Makefile.am index 491e78445..8c1b393e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -124,6 +124,8 @@ libmutter_la_SOURCES = \ core/keybindings.c \ core/keybindings-private.h \ core/main.c \ + core/meta-cursor-tracker.c \ + core/meta-cursor-tracker-private.h \ core/mutter-Xatomtype.h \ core/place.c \ core/place.h \ @@ -210,6 +212,7 @@ libmutterinclude_base_headers = \ meta/meta-background-actor.h \ meta/meta-background-group.h \ meta/meta-background.h \ + meta/meta-cursor-tracker.h \ meta/meta-plugin.h \ meta/meta-shaped-texture.h \ meta/meta-shadow-factory.h \ diff --git a/src/core/display.c b/src/core/display.c index c71b8c34a..316748d8a 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -2177,6 +2177,7 @@ meta_display_handle_event (MetaDisplay *display, gboolean bypass_compositor; gboolean filter_out_event; XIEvent *input_event; + MetaScreen *screen; #ifdef WITH_VERBOSE_MODE if (dump_events) @@ -2204,6 +2205,13 @@ meta_display_handle_event (MetaDisplay *display, display->server_focus_serial); } + screen = meta_display_screen_for_root (display, event->xany.window); + if (screen) + { + if (meta_screen_handle_xevent (screen, event)) + return TRUE; + } + modified = event_get_modified_window (display, event); input_event = get_input_event (display, event); diff --git a/src/core/meta-cursor-tracker-private.h b/src/core/meta-cursor-tracker-private.h new file mode 100644 index 000000000..773ac0020 --- /dev/null +++ b/src/core/meta-cursor-tracker-private.h @@ -0,0 +1,46 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Author: Giovanni Campagna + */ + +#ifndef META_CURSOR_TRACKER_PRIVATE_H +#define META_CURSOR_TRACKER_PRIVATE_H + +#include + +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_sprite (MetaCursorTracker *tracker, + CoglTexture2D *texture, + int hot_x, + int hot_y); + +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 new file mode 100644 index 000000000..4a374d54d --- /dev/null +++ b/src/core/meta-cursor-tracker.c @@ -0,0 +1,451 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Author: Giovanni Campagna + */ + +/** + * SECTION:cursor-tracker + * @title: MetaCursorTracker + * @short_description: Mutter cursor tracking helper + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include "meta-cursor-tracker-private.h" +#include "screen-private.h" +#include "meta-wayland-private.h" + +#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7 +#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4 + +struct _MetaCursorTracker { + GObject parent_instance; + + MetaScreen *screen; + + gboolean is_showing; + + CoglTexture2D *sprite; + int hot_x, hot_y; + + CoglTexture2D *root_cursor; + int root_hot_x, root_hot_y; + + CoglTexture2D *default_cursor; + + int current_x, current_y; + cairo_rectangle_int_t current_rect; + cairo_rectangle_int_t previous_rect; + gboolean previous_is_valid; + + CoglPipeline *pipeline; +}; + +struct _MetaCursorTrackerClass { + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT); + +enum { + CURSOR_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void +meta_cursor_tracker_init (MetaCursorTracker *self) +{ + /* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of + detecting if the system mouse cursor is showing or not. + + On wayland we start with the cursor showing + */ + self->is_showing = TRUE; +} + +static void +meta_cursor_tracker_finalize (GObject *object) +{ + MetaCursorTracker *self = META_CURSOR_TRACKER (object); + + if (self->sprite) + cogl_object_unref (self->sprite); + if (self->root_cursor) + cogl_object_unref (self->root_cursor); + if (self->default_cursor) + cogl_object_unref (self->default_cursor); + if (self->pipeline) + cogl_object_unref (self->pipeline); + + G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object); +} + +static void +meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_cursor_tracker_finalize; + + signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +static MetaCursorTracker * +make_wayland_cursor_tracker (MetaScreen *screen) +{ + MetaWaylandCompositor *compositor; + CoglContext *ctx; + MetaCursorTracker *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; + + 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 + * + * Retrieves the cursor tracker object for @screen. + * + * Returns: (transfer none): + */ +MetaCursorTracker * +meta_cursor_tracker_get_for_screen (MetaScreen *screen) +{ + MetaCursorTracker *self; + + if (screen->cursor_tracker) + return screen->cursor_tracker; + + if (meta_is_wayland_compositor ()) + self = make_wayland_cursor_tracker (screen); + else + self = make_x11_cursor_tracker (screen); + + screen->cursor_tracker = self; + return self; +} + +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; + + g_clear_pointer (&tracker->sprite, cogl_object_unref); + g_signal_emit (tracker, signals[CURSOR_CHANGED], 0); + + return TRUE; +} + +static void +ensure_xfixes_cursor (MetaCursorTracker *tracker) +{ + XFixesCursorImage *cursor_image; + CoglTexture2D *sprite; + guint8 *cursor_data; + gboolean free_cursor_data; + CoglContext *ctx; + + if (tracker->sprite) + 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, + COGL_PIXEL_FORMAT_ANY, + cursor_image->width * 4, /* stride */ + cursor_data, + NULL); + + if (free_cursor_data) + g_free (cursor_data); + + if (sprite != NULL) + { + tracker->sprite = sprite; + tracker->hot_x = cursor_image->xhot; + tracker->hot_y = cursor_image->yhot; + } + XFree (cursor_image); +} + +/** + * meta_cursor_tracker_get_sprite: + * + * Returns: (transfer none): + */ +CoglTexture * +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); + + return COGL_TEXTURE (tracker->sprite); +} + +/** + * meta_cursor_tracker_get_hot: + * @tracker: + * @x: (out): + * @y: (out): + * + */ +void +meta_cursor_tracker_get_hot (MetaCursorTracker *tracker, + int *x, + int *y) +{ + g_return_if_fail (META_IS_CURSOR_TRACKER (tracker)); + + if (!meta_is_wayland_compositor ()) + ensure_xfixes_cursor (tracker); + + if (x) + *x = tracker->hot_x; + if (y) + *y = tracker->hot_y; +} + +static void +ensure_wayland_cursor (MetaCursorTracker *tracker) +{ + CoglBitmap *bitmap; + char *filename; + + if (tracker->default_cursor) + return; + + filename = g_build_filename (MUTTER_PKGDATADIR, + "cursors/left_ptr.png", + NULL); + + bitmap = cogl_bitmap_new_from_file (filename, NULL); + tracker->default_cursor = cogl_texture_2d_new_from_bitmap (bitmap, + COGL_PIXEL_FORMAT_ANY, + NULL); + + cogl_object_unref (bitmap); + g_free (filename); +} + +void +meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, + MetaCursor cursor) +{ + Cursor xcursor; + MetaDisplay *display = tracker->screen->display; + + /* First create a cursor for X11 applications that don't specify their own */ + xcursor = meta_display_create_x_cursor (display, cursor); + + XDefineCursor (display->xdisplay, tracker->screen->xroot, xcursor); + XFlush (display->xdisplay); + XFreeCursor (display->xdisplay, xcursor); + + /* Now update the real root cursor */ + if (meta_is_wayland_compositor ()) + { + /* FIXME! We need to load all the other cursors too */ + ensure_wayland_cursor (tracker); + + g_clear_pointer (&tracker->root_cursor, cogl_object_unref); + tracker->root_cursor = cogl_object_ref (tracker->default_cursor); + tracker->root_hot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X; + tracker->root_hot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y; + } +} + +void +meta_cursor_tracker_revert_root (MetaCursorTracker *tracker) +{ + meta_cursor_tracker_set_sprite (tracker, + tracker->root_cursor, + tracker->root_hot_x, + tracker->root_hot_y); +} + +void +meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker, + CoglTexture2D *sprite, + int hot_x, + int hot_y) +{ + g_assert (meta_is_wayland_compositor ()); + + g_clear_pointer (&tracker->sprite, cogl_object_unref); + + if (sprite) + { + tracker->sprite = cogl_object_ref (sprite); + tracker->hot_x = hot_x; + tracker->hot_y = hot_y; + cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (tracker->sprite)); + } + else + cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL); + + 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; + tracker->current_rect.x = tracker->current_x - tracker->hot_x; + tracker->current_rect.y = tracker->current_y - tracker->hot_y; + + if (tracker->sprite) + { + tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (tracker->sprite)); + tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (tracker->sprite)); + } + else + { + tracker->current_rect.width = 0; + tracker->current_rect.height = 0; + } +} + +void +meta_cursor_tracker_paint (MetaCursorTracker *tracker) +{ + g_assert (meta_is_wayland_compositor ()); + + if (tracker->sprite == NULL) + return; + + /* FIXME: try to use a DRM cursor when possible */ + 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) +{ + g_assert (meta_is_wayland_compositor ()); + + if (tracker->previous_is_valid) + { + clutter_actor_queue_redraw_with_clip (stage, &tracker->previous_rect); + tracker->previous_is_valid = FALSE; + } + + if (tracker->sprite == NULL) + return; + + clutter_actor_queue_redraw_with_clip (stage, &tracker->current_rect); +} diff --git a/src/core/screen-private.h b/src/core/screen-private.h index 7e8a13318..6bb32f16d 100644 --- a/src/core/screen-private.h +++ b/src/core/screen-private.h @@ -93,6 +93,7 @@ struct _MetaScreen MetaStack *stack; MetaStackTracker *stack_tracker; + MetaCursorTracker *cursor_tracker; MetaCursor current_cursor; Window flash_window; @@ -259,4 +260,7 @@ void meta_screen_set_active_workspace_hint (MetaScreen *screen); Window meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen); +gboolean meta_screen_handle_xevent (MetaScreen *screen, + XEvent *xevent); + #endif diff --git a/src/core/screen.c b/src/core/screen.c index 073a8af71..3706d94c0 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -48,6 +48,7 @@ #ifdef HAVE_WAYLAND #include "meta-wayland-private.h" #endif +#include "meta-cursor-tracker-private.h" #include @@ -879,7 +880,8 @@ meta_screen_new (MetaDisplay *display, screen->last_monitor_index = 0; reload_monitor_infos (screen); - + + meta_cursor_tracker_get_for_screen (screen); meta_screen_set_cursor (screen, META_CURSOR_DEFAULT); /* Handle creating a no_focus_window for this screen */ @@ -1635,29 +1637,18 @@ void meta_screen_set_cursor (MetaScreen *screen, MetaCursor cursor) { - Cursor xcursor; - if (cursor == screen->current_cursor) return; screen->current_cursor = cursor; - - xcursor = meta_display_create_x_cursor (screen->display, cursor); - XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor); - XFlush (screen->display->xdisplay); - XFreeCursor (screen->display->xdisplay, xcursor); + meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor); } void meta_screen_update_cursor (MetaScreen *screen) { - Cursor xcursor; - - xcursor = meta_display_create_x_cursor (screen->display, - screen->current_cursor); - XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor); - XFlush (screen->display->xdisplay); - XFreeCursor (screen->display->xdisplay, xcursor); + meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, + screen->current_cursor); } void @@ -3869,3 +3860,13 @@ meta_screen_get_monitor_in_fullscreen (MetaScreen *screen, /* We use -1 as a flag to mean "not known yet" for notification purposes */ return screen->monitor_infos[monitor].in_fullscreen == TRUE; } + +gboolean +meta_screen_handle_xevent (MetaScreen *screen, + XEvent *xevent) +{ + if (meta_cursor_tracker_handle_xevent (screen->cursor_tracker, xevent)) + return TRUE; + + return FALSE; +} diff --git a/src/meta/meta-cursor-tracker.h b/src/meta/meta-cursor-tracker.h new file mode 100644 index 000000000..75199d666 --- /dev/null +++ b/src/meta/meta-cursor-tracker.h @@ -0,0 +1,49 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Author: Giovanni Campagna + */ + +#ifndef META_CURSOR_TRACKER_H +#define META_CURSOR_TRACKER_H + +#include +#include +#include + +#define META_TYPE_CURSOR_TRACKER (meta_cursor_tracker_get_type ()) +#define META_CURSOR_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_TRACKER, MetaCursorTracker)) +#define META_CURSOR_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_TRACKER, MetaCursorTrackerClass)) +#define META_IS_CURSOR_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_TRACKER)) +#define META_IS_CURSOR_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_TRACKER)) +#define META_CURSOR_TRACKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_TRACKER, MetaCursorTrackerClass)) + +typedef struct _MetaCursorTrackerClass MetaCursorTrackerClass; + +GType meta_cursor_tracker_get_type (void); + +MetaCursorTracker *meta_cursor_tracker_get_for_screen (MetaScreen *screen); + +void meta_cursor_tracker_get_hot (MetaCursorTracker *tracker, + int *x, + int *y); +CoglTexture *meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker); + +#endif diff --git a/src/meta/types.h b/src/meta/types.h index 25833207d..f13471146 100644 --- a/src/meta/types.h +++ b/src/meta/types.h @@ -38,5 +38,6 @@ typedef struct _MetaWorkspace MetaWorkspace; */ typedef struct _MetaGroup MetaGroup; typedef struct _MetaKeyBinding MetaKeyBinding; +typedef struct _MetaCursorTracker MetaCursorTracker; #endif diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h index a859378c1..89c145d0c 100644 --- a/src/wayland/meta-wayland-private.h +++ b/src/wayland/meta-wayland-private.h @@ -28,6 +28,7 @@ #include #include "window-private.h" +#include typedef struct _MetaWaylandCompositor MetaWaylandCompositor; @@ -335,6 +336,7 @@ struct _MetaWaylandSeat struct wl_display *display; + MetaCursorTracker *cursor_tracker; MetaWaylandSurface *sprite; int hotspot_x, hotspot_y; struct wl_listener sprite_destroy_listener; diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c index 0d2b729e5..3ea739919 100644 --- a/src/wayland/meta-wayland-seat.c +++ b/src/wayland/meta-wayland-seat.c @@ -36,6 +36,7 @@ #include "meta-window-actor-private.h" #include "meta/meta-shaped-texture.h" #include "meta-wayland-stage.h" +#include "meta-cursor-tracker-private.h" #define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10) @@ -73,10 +74,14 @@ transform_stage_point_fixed (MetaWaylandSurface *surface, static void pointer_unmap_sprite (MetaWaylandSeat *seat) { - if (seat->current_stage) + if (seat->cursor_tracker) { - MetaWaylandStage *stage = META_WAYLAND_STAGE (seat->current_stage); - meta_wayland_stage_set_invisible_cursor (stage); + meta_cursor_tracker_set_sprite (seat->cursor_tracker, + NULL, 0, 0); + + if (seat->current_stage) + meta_cursor_tracker_queue_redraw (seat->cursor_tracker, + CLUTTER_ACTOR (seat->current_stage)); } if (seat->sprite) @@ -89,22 +94,29 @@ pointer_unmap_sprite (MetaWaylandSeat *seat) void meta_wayland_seat_update_sprite (MetaWaylandSeat *seat) { + ClutterBackend *backend; + CoglContext *context; + struct wl_resource *buffer; + CoglTexture2D *texture; + + if (seat->cursor_tracker == NULL) + return; + + backend = clutter_get_default_backend (); + context = clutter_backend_get_cogl_context (backend); + buffer = seat->sprite->buffer_ref.buffer->resource; + texture = cogl_wayland_texture_2d_new_from_buffer (context, buffer, NULL); + + meta_cursor_tracker_set_sprite (seat->cursor_tracker, + texture, + seat->hotspot_x, + seat->hotspot_y); + if (seat->current_stage) - { - MetaWaylandStage *stage = META_WAYLAND_STAGE (seat->current_stage); - ClutterBackend *backend = clutter_get_default_backend (); - CoglContext *context = clutter_backend_get_cogl_context (backend); - struct wl_resource *buffer = seat->sprite->buffer_ref.buffer->resource; - CoglTexture2D *texture = - cogl_wayland_texture_2d_new_from_buffer (context, buffer, NULL); + meta_cursor_tracker_queue_redraw (seat->cursor_tracker, + CLUTTER_ACTOR (seat->current_stage)); - meta_wayland_stage_set_cursor_from_texture (stage, - COGL_TEXTURE (texture), - seat->hotspot_x, - seat->hotspot_y); - - cogl_object_unref (texture); - } + cogl_object_unref (texture); } static void diff --git a/src/wayland/meta-wayland-stage.c b/src/wayland/meta-wayland-stage.c index c3036084d..f7d28d419 100644 --- a/src/wayland/meta-wayland-stage.c +++ b/src/wayland/meta-wayland-stage.c @@ -28,157 +28,33 @@ #include "meta-wayland-stage.h" #include "meta/meta-window-actor.h" #include "meta/meta-shaped-texture.h" - -#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7 -#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4 +#include "meta-cursor-tracker-private.h" G_DEFINE_TYPE (MetaWaylandStage, meta_wayland_stage, CLUTTER_TYPE_STAGE); -static void -meta_wayland_stage_finalize (GObject *object) -{ - MetaWaylandStage *self = (MetaWaylandStage *) object; - - cogl_object_unref (self->default_cursor_pipeline); - cogl_object_unref (self->texture_cursor_pipeline); - - G_OBJECT_CLASS (meta_wayland_stage_parent_class)->finalize (object); -} - -static void -get_cursor_draw_position (MetaWaylandStage *self, - cairo_rectangle_int_t *rect) -{ - rect->x = self->cursor_x - self->cursor_hotspot_x; - rect->y = self->cursor_y - self->cursor_hotspot_y; - rect->width = self->cursor_width; - rect->height = self->cursor_height; -} - -static void -draw_cursor_pipeline (MetaWaylandStage *self, - CoglPipeline *pipeline) -{ - cairo_rectangle_int_t rect; - - get_cursor_draw_position (self, &rect); - - cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (), - pipeline, - rect.x, rect.y, - rect.x + rect.width, - rect.y + rect.height); - - self->has_last_cursor_position = TRUE; - self->last_cursor_position = rect; -} - static void meta_wayland_stage_paint (ClutterActor *actor) { - MetaWaylandStage *self = META_WAYLAND_STAGE (actor); + MetaWaylandCompositor *compositor; CLUTTER_ACTOR_CLASS (meta_wayland_stage_parent_class)->paint (actor); - /* Make sure the cursor is always painted on top of all of the other - actors */ - - switch (self->cursor_type) - { - case META_WAYLAND_STAGE_CURSOR_INVISIBLE: - break; - - case META_WAYLAND_STAGE_CURSOR_DEFAULT: - draw_cursor_pipeline (self, self->default_cursor_pipeline); - break; - - case META_WAYLAND_STAGE_CURSOR_TEXTURE: - draw_cursor_pipeline (self, self->texture_cursor_pipeline); - break; - } -} - -static void -update_cursor_position (MetaWaylandStage *self) -{ - cairo_rectangle_int_t rect; - - if (self->has_last_cursor_position) - { - clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (self), - &self->last_cursor_position); - self->has_last_cursor_position = FALSE; - } - - get_cursor_draw_position (self, &rect); - if (rect.width != 0 && rect.height != 0) - clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (self), &rect); + compositor = meta_wayland_compositor_get_default (); + if (compositor->seat->cursor_tracker) + meta_cursor_tracker_paint (compositor->seat->cursor_tracker); } static void meta_wayland_stage_class_init (MetaWaylandStageClass *klass) { - GObjectClass *gobject_class = (GObjectClass *) klass; ClutterActorClass *actor_class = (ClutterActorClass *) klass; - gobject_class->finalize = meta_wayland_stage_finalize; - actor_class->paint = meta_wayland_stage_paint; } -static void -load_default_cursor_pipeline (MetaWaylandStage *self) -{ - CoglContext *context = - clutter_backend_get_cogl_context (clutter_get_default_backend ()); - CoglTexture *texture; - CoglError *error = NULL; - char *filename; - - filename = g_build_filename (MUTTER_DATADIR, - "mutter/cursors/left_ptr.png", - NULL); - - texture = cogl_texture_new_from_file (filename, - COGL_TEXTURE_NONE, - COGL_PIXEL_FORMAT_ANY, - &error); - - g_free (filename); - - self->default_cursor_pipeline = cogl_pipeline_new (context); - cogl_pipeline_set_layer_filters (self->default_cursor_pipeline, - 0, /* layer */ - COGL_PIPELINE_FILTER_NEAREST, - COGL_PIPELINE_FILTER_NEAREST); - - if (texture == NULL) - { - g_warning ("Failed to load default cursor: %s", - error->message); - cogl_error_free (error); - } - else - { - self->default_cursor_width = cogl_texture_get_width (texture); - self->default_cursor_height = cogl_texture_get_height (texture); - - cogl_pipeline_set_layer_texture (self->default_cursor_pipeline, - 0, /* layer */ - texture); - cogl_object_unref (texture); - } -} - static void meta_wayland_stage_init (MetaWaylandStage *self) { - load_default_cursor_pipeline (self); - - self->texture_cursor_pipeline = - cogl_pipeline_copy (self->default_cursor_pipeline); - - meta_wayland_stage_set_default_cursor (self); } ClutterActor * @@ -188,56 +64,3 @@ meta_wayland_stage_new (void) "cursor-visible", FALSE, NULL); } - -void -meta_wayland_stage_set_cursor_position (MetaWaylandStage *self, - int x, - int y) -{ - self->cursor_x = x; - self->cursor_y = y; - update_cursor_position (self); -} - -void -meta_wayland_stage_set_cursor_from_texture (MetaWaylandStage *self, - CoglTexture *texture, - int hotspot_x, - int hotspot_y) -{ - CoglPipeline *pipeline; - - self->cursor_hotspot_x = hotspot_x; - self->cursor_hotspot_y = hotspot_y; - self->cursor_type = META_WAYLAND_STAGE_CURSOR_TEXTURE; - - pipeline = cogl_pipeline_copy (self->texture_cursor_pipeline); - cogl_pipeline_set_layer_texture (pipeline, 0, texture); - cogl_object_unref (self->texture_cursor_pipeline); - self->texture_cursor_pipeline = pipeline; - - self->cursor_width = cogl_texture_get_width (texture); - self->cursor_height = cogl_texture_get_height (texture); - - update_cursor_position (self); -} - -void -meta_wayland_stage_set_invisible_cursor (MetaWaylandStage *self) -{ - self->cursor_type = META_WAYLAND_STAGE_CURSOR_INVISIBLE; - self->cursor_width = 0; - self->cursor_height = 0; - update_cursor_position (self); -} - -void -meta_wayland_stage_set_default_cursor (MetaWaylandStage *self) -{ - self->cursor_type = META_WAYLAND_STAGE_CURSOR_DEFAULT; - self->cursor_hotspot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X; - self->cursor_hotspot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y; - self->cursor_width = self->default_cursor_width; - self->cursor_height = self->default_cursor_height; - update_cursor_position (self); -} diff --git a/src/wayland/meta-wayland-stage.h b/src/wayland/meta-wayland-stage.h index d25f2707f..c242fbd60 100644 --- a/src/wayland/meta-wayland-stage.h +++ b/src/wayland/meta-wayland-stage.h @@ -59,53 +59,12 @@ struct _MetaWaylandStageClass struct _MetaWaylandStage { ClutterStage parent; - - /* A pipeline containing the cursor texture that will be used when - the cursor is not over a surface */ - CoglPipeline *default_cursor_pipeline; - int default_cursor_width; - int default_cursor_height; - - CoglPipeline *texture_cursor_pipeline; - - int cursor_x; - int cursor_y; - int cursor_width; - int cursor_height; - int cursor_hotspot_x; - int cursor_hotspot_y; - - enum - { - /* No cursor will be drawn */ - META_WAYLAND_STAGE_CURSOR_INVISIBLE, - /* The cursor will be drawn from our default cursor image */ - META_WAYLAND_STAGE_CURSOR_DEFAULT, - /* The cursor will be drawn using a custom texture */ - META_WAYLAND_STAGE_CURSOR_TEXTURE - } cursor_type; - - gboolean has_last_cursor_position; - cairo_rectangle_int_t last_cursor_position; }; GType meta_wayland_stage_get_type (void) G_GNUC_CONST; ClutterActor *meta_wayland_stage_new (void); -void meta_wayland_stage_set_cursor_position (MetaWaylandStage *stage, - int x, - int y); - -void meta_wayland_stage_set_default_cursor (MetaWaylandStage *self); - -void meta_wayland_stage_set_cursor_from_texture (MetaWaylandStage *self, - CoglTexture *texture, - int hotspot_x, - int hotspot_y); - -void meta_wayland_stage_set_invisible_cursor (MetaWaylandStage *self); - G_END_DECLS #endif /* META_WAYLAND_STAGE_H */ diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 5b62e8967..600db9368 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -43,6 +43,7 @@ #include "meta-wayland-keyboard.h" #include "meta-wayland-pointer.h" #include "meta-wayland-data-device.h" +#include "meta-cursor-tracker-private.h" #include "display-private.h" #include "window-private.h" #include @@ -1290,12 +1291,17 @@ event_cb (ClutterActor *stage, } } - meta_wayland_stage_set_cursor_position (META_WAYLAND_STAGE (stage), - wl_fixed_to_int (pointer->x), - wl_fixed_to_int (pointer->y)); + if (seat->cursor_tracker) + { + meta_cursor_tracker_update_position (seat->cursor_tracker, + wl_fixed_to_int (pointer->x), + wl_fixed_to_int (pointer->y)); - if (pointer->current == NULL) - meta_wayland_stage_set_default_cursor (META_WAYLAND_STAGE (stage)); + if (pointer->current == NULL) + meta_cursor_tracker_revert_root (seat->cursor_tracker); + + meta_cursor_tracker_queue_redraw (seat->cursor_tracker, stage); + } display = meta_get_display (); if (!display)