} surface;
struct wl_cursor *wl_cursor;
+ int scale;
};
struct _GdkWaylandCursorClass
}
static gboolean
-set_cursor_from_theme (GdkWaylandCursor *cursor,
- struct wl_cursor_theme *theme)
+_gdk_wayland_cursor_update (GdkWaylandDisplay *wayland_display,
+ GdkWaylandCursor *cursor)
{
struct wl_cursor *c;
+ struct wl_cursor_theme *theme;
+ /* Do nothing if this is not a wl_cursor cursor. */
+ if (cursor->name == NULL)
+ return FALSE;
+
+ theme = _gdk_wayland_display_get_scaled_cursor_theme (wayland_display,
+ cursor->scale);
c = wl_cursor_theme_get_cursor (theme, cursor->name);
if (!c)
{
}
void
-_gdk_wayland_display_update_cursors (GdkWaylandDisplay *display,
- struct wl_cursor_theme *theme)
+_gdk_wayland_display_update_cursors (GdkWaylandDisplay *display)
{
GHashTableIter iter;
const char *name;
g_hash_table_iter_init (&iter, display->cursor_cache);
while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &cursor))
- set_cursor_from_theme (cursor, theme);
+ _gdk_wayland_cursor_update (display, cursor);
}
static void
*w = image->width;
*h = image->height;
- *scale = 1;
+ *scale = wayland_cursor->scale;
return wl_cursor_image_get_buffer (image);
}
return current_image_index;
}
+void
+_gdk_wayland_cursor_set_scale (GdkCursor *cursor,
+ guint scale)
+{
+ GdkWaylandDisplay *wayland_display =
+ GDK_WAYLAND_DISPLAY (gdk_cursor_get_display (cursor));
+ GdkWaylandCursor *wayland_cursor = GDK_WAYLAND_CURSOR (cursor);
+
+ if (scale > GDK_WAYLAND_MAX_THEME_SCALE)
+ {
+ g_warning (G_STRLOC ": cursor theme size %u too large", scale);
+ scale = GDK_WAYLAND_MAX_THEME_SCALE;
+ }
+
+ if (wayland_cursor->scale == scale)
+ return;
+
+ wayland_cursor->scale = scale;
+
+ _gdk_wayland_cursor_update (wayland_display, wayland_cursor);
+}
+
static void
_gdk_wayland_cursor_class_init (GdkWaylandCursorClass *wayland_cursor_class)
{
{
}
+static GdkCursor *
+_gdk_wayland_display_get_cursor_for_name_with_scale (GdkDisplay *display,
+ const gchar *name,
+ guint scale);
+
GdkCursor *
-_gdk_wayland_display_get_cursor_for_type (GdkDisplay *display,
- GdkCursorType cursor_type)
+_gdk_wayland_display_get_cursor_for_type_with_scale (GdkDisplay *display,
+ GdkCursorType cursor_type,
+ guint scale)
{
GEnumClass *enum_class;
GEnumValue *enum_value;
g_strdelimit (cursor_name, "-", '_');
g_type_class_unref (enum_class);
- result = _gdk_wayland_display_get_cursor_for_name (display, cursor_name);
+ result = _gdk_wayland_display_get_cursor_for_name_with_scale (display,
+ cursor_name,
+ scale);
g_free (cursor_name);
}
GdkCursor *
-_gdk_wayland_display_get_cursor_for_name (GdkDisplay *display,
- const gchar *name)
+_gdk_wayland_display_get_cursor_for_type (GdkDisplay *display,
+ GdkCursorType cursor_type)
+{
+ return _gdk_wayland_display_get_cursor_for_type_with_scale (display,
+ cursor_type,
+ 1);
+}
+
+static GdkCursor *
+_gdk_wayland_display_get_cursor_for_name_with_scale (GdkDisplay *display,
+ const gchar *name,
+ guint scale)
{
GdkWaylandCursor *private;
GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (display);
"display", display,
NULL);
private->name = g_strdup (name);
+ private->scale = scale;
/* Blank cursor case */
if (!name || g_str_equal (name, "blank_cursor"))
return GDK_CURSOR (private);
- if (!set_cursor_from_theme (private, wayland_display->cursor_theme))
+ if (!_gdk_wayland_cursor_update (wayland_display, private))
return GDK_CURSOR (private);
/* Insert into cache. */
return GDK_CURSOR (private);
}
+GdkCursor *
+_gdk_wayland_display_get_cursor_for_name (GdkDisplay *display,
+ const gchar *name)
+{
+ return _gdk_wayland_display_get_cursor_for_name_with_scale (display, name, 1);
+}
+
GdkCursor *
_gdk_wayland_display_get_cursor_for_surface (GdkDisplay *display,
cairo_surface_t *surface,
GdkDragContext *drop_context;
struct wl_surface *pointer_surface;
+ guint current_output_scale;
+ GSList *pointer_surface_outputs;
};
struct _GdkWaylandDevice
* the default cursor
*/
if (!cursor)
- cursor = _gdk_wayland_display_get_cursor_for_type (device->display, GDK_LEFT_PTR);
+ {
+ guint scale = wd->current_output_scale;
+ cursor =
+ _gdk_wayland_display_get_cursor_for_type_with_scale (wd->display,
+ GDK_LEFT_PTR,
+ scale);
+ }
+ else
+ _gdk_wayland_cursor_set_scale (cursor, wd->current_output_scale);
if (cursor == wd->cursor)
return;
_gdk_device_set_associated_device (device->master_keyboard, device->master_pointer);
}
+static void
+pointer_surface_update_scale (GdkWaylandDeviceData *device)
+{
+ GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (device->display);
+ guint32 scale;
+ GSList *l;
+
+ if (wayland_display->compositor_version < WL_SURFACE_HAS_BUFFER_SCALE)
+ {
+ /* We can't set the scale on this surface */
+ return;
+ }
+
+ scale = 1;
+ for (l = device->pointer_surface_outputs; l != NULL; l = l->next)
+ {
+ guint32 output_scale =
+ _gdk_wayland_screen_get_output_scale (wayland_display->screen,
+ l->data);
+ scale = MAX (scale, output_scale);
+ }
+
+ device->current_output_scale = scale;
+
+ if (device->grab_cursor)
+ _gdk_wayland_cursor_set_scale (device->grab_cursor, scale);
+ if (device->cursor)
+ _gdk_wayland_cursor_set_scale (device->cursor, scale);
+
+ gdk_wayland_device_update_window_cursor (device);
+}
+
+static void
+pointer_surface_enter (void *data,
+ struct wl_surface *wl_surface,
+ struct wl_output *output)
+
+{
+ GdkWaylandDeviceData *device = data;
+
+ GDK_NOTE (EVENTS,
+ g_message ("pointer surface of device %p entered output %p",
+ device, output));
+
+ device->pointer_surface_outputs =
+ g_slist_append (device->pointer_surface_outputs, output);
+
+ pointer_surface_update_scale (device);
+}
+
+static void
+pointer_surface_leave (void *data,
+ struct wl_surface *wl_surface,
+ struct wl_output *output)
+{
+ GdkWaylandDeviceData *device = data;
+
+ GDK_NOTE (EVENTS,
+ g_message ("pointer surface of device %p left output %p",
+ device, output));
+
+ device->pointer_surface_outputs =
+ g_slist_remove (device->pointer_surface_outputs, output);
+
+ pointer_surface_update_scale (device);
+}
+
+static const struct wl_surface_listener pointer_surface_listener = {
+ pointer_surface_enter,
+ pointer_surface_leave
+};
+
void
_gdk_wayland_device_manager_add_seat (GdkDeviceManager *device_manager,
guint32 id,
wl_data_device_add_listener (device->data_device,
&data_device_listener, device);
+ device->current_output_scale = 1;
device->pointer_surface =
wl_compositor_create_surface (display_wayland->compositor);
+ wl_surface_add_listener (device->pointer_surface,
+ &pointer_surface_listener,
+ device);
init_devices (device);
}
{
GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY(display);
struct wl_cursor_theme *theme;
+ int i;
g_assert (wayland_display);
g_assert (wayland_display->shm);
return;
}
- _gdk_wayland_display_update_cursors (wayland_display, theme);
+ for (i = 0; i < GDK_WAYLAND_THEME_SCALES_COUNT; i++)
+ {
+ if (wayland_display->scaled_cursor_themes[i])
+ {
+ wl_cursor_theme_destroy (wayland_display->scaled_cursor_themes[i]);
+ wayland_display->scaled_cursor_themes[i] = NULL;
+ }
+ }
+ wayland_display->scaled_cursor_themes[0] = theme;
+ if (wayland_display->cursor_theme_name != NULL)
+ free (wayland_display->cursor_theme_name);
+ wayland_display->cursor_theme_name = g_strdup (name);
+ wayland_display->cursor_theme_size = size;
+
+ _gdk_wayland_display_update_cursors (wayland_display);
+}
+
+struct wl_cursor_theme *
+_gdk_wayland_display_get_scaled_cursor_theme (GdkWaylandDisplay *wayland_display,
+ guint scale)
+{
+ struct wl_cursor_theme *theme;
+
+ g_assert (wayland_display->cursor_theme_name);
+ g_assert (scale <= GDK_WAYLAND_MAX_THEME_SCALE);
+ g_assert (scale >= 1);
+
+ theme = wayland_display->scaled_cursor_themes[scale - 1];
+ if (!theme)
+ {
+ theme = wl_cursor_theme_load (wayland_display->cursor_theme_name,
+ wayland_display->cursor_theme_size * scale,
+ wayland_display->shm);
+ if (theme == NULL)
+ {
+ g_warning ("Failed to load cursor theme %s with scale %u\n",
+ wayland_display->cursor_theme_name, scale);
+ return NULL;
+ }
+ wayland_display->scaled_cursor_themes[scale - 1] = theme;
+ }
- if (wayland_display->cursor_theme != NULL)
- wl_cursor_theme_destroy (wayland_display->cursor_theme);
- wayland_display->cursor_theme = theme;
+ return theme;
}
static void
G_BEGIN_DECLS
+#define GDK_WAYLAND_MAX_THEME_SCALE 2
+#define GDK_WAYLAND_THEME_SCALES_COUNT GDK_WAYLAND_MAX_THEME_SCALE
+
typedef struct _GdkWaylandSelection GdkWaylandSelection;
struct _GdkWaylandDisplay
struct wl_data_device_manager *data_device_manager;
struct wl_subcompositor *subcompositor;
- struct wl_cursor_theme *cursor_theme;
+ struct wl_cursor_theme *scaled_cursor_themes[GDK_WAYLAND_THEME_SCALES_COUNT];
+ gchar *cursor_theme_name;
+ int cursor_theme_size;
GHashTable *cursor_cache;
GSource *event_source;
void _gdk_wayland_display_init_cursors (GdkWaylandDisplay *display);
void _gdk_wayland_display_finalize_cursors (GdkWaylandDisplay *display);
-void _gdk_wayland_display_update_cursors (GdkWaylandDisplay *display,
- struct wl_cursor_theme *theme);
+void _gdk_wayland_display_update_cursors (GdkWaylandDisplay *display);
+
+struct wl_cursor_theme * _gdk_wayland_display_get_scaled_cursor_theme (GdkWaylandDisplay *wayland_display,
+ guint scale);
GdkCursor *_gdk_wayland_display_get_cursor_for_type (GdkDisplay *display,
GdkCursorType cursor_type);
+GdkCursor *_gdk_wayland_display_get_cursor_for_type_with_scale (GdkDisplay *display,
+ GdkCursorType cursor_type,
+ guint scale);
GdkCursor *_gdk_wayland_display_get_cursor_for_name (GdkDisplay *display,
const gchar *name);
GdkCursor *_gdk_wayland_display_get_cursor_for_surface (GdkDisplay *display,
guint current_image_index,
guint *next_image_delay);
+void _gdk_wayland_cursor_set_scale (GdkCursor *cursor,
+ guint scale);
+
GdkDragProtocol _gdk_wayland_window_get_drag_protocol (GdkWindow *window,
GdkWindow **target);