tests: Add basic ref-test based cursor sprite test case
It currently contains some basic tests using the built in cursor as well as traditional buffer scale using Wayland client in different monitor configurations. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3859>
@ -38,6 +38,7 @@ MetaCursor meta_cursor_sprite_xcursor_get_cursor (MetaCursorSpriteXcursor *sprit
|
||||
|
||||
XcursorImage * meta_cursor_sprite_xcursor_get_current_image (MetaCursorSpriteXcursor *sprite_xcursor);
|
||||
|
||||
META_EXPORT_TEST
|
||||
const char * meta_cursor_get_name (MetaCursor cursor);
|
||||
|
||||
const char * meta_cursor_get_legacy_name (MetaCursor cursor);
|
||||
|
@ -42,6 +42,9 @@ void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
|
||||
|
||||
void meta_cursor_tracker_invalidate_position (MetaCursorTracker *tracker);
|
||||
|
||||
META_EXPORT_TEST
|
||||
gboolean meta_cursor_tracker_has_window_cursor (MetaCursorTracker *tracker);
|
||||
|
||||
void meta_cursor_tracker_track_position (MetaCursorTracker *tracker);
|
||||
|
||||
void meta_cursor_tracker_untrack_position (MetaCursorTracker *tracker);
|
||||
|
@ -346,6 +346,15 @@ set_window_cursor (MetaCursorTracker *tracker,
|
||||
sync_cursor (tracker);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_cursor_tracker_has_window_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
MetaCursorTrackerPrivate *priv =
|
||||
meta_cursor_tracker_get_instance_private (tracker);
|
||||
|
||||
return priv->has_window_cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_cursor_tracker_get_sprite:
|
||||
* @tracker: a #MetaCursorTracker
|
||||
|
@ -47,6 +47,7 @@ struct _MetaLogicalMonitor
|
||||
typedef struct _MetaLogicalMonitorId MetaLogicalMonitorId;
|
||||
|
||||
#define META_TYPE_LOGICAL_MONITOR (meta_logical_monitor_get_type ())
|
||||
META_EXPORT_TEST
|
||||
G_DECLARE_FINAL_TYPE (MetaLogicalMonitor, meta_logical_monitor,
|
||||
META, LOGICAL_MONITOR,
|
||||
GObject)
|
||||
@ -75,6 +76,7 @@ gboolean meta_logical_monitor_is_primary (MetaLogicalMonitor *logical_monitor);
|
||||
|
||||
void meta_logical_monitor_make_primary (MetaLogicalMonitor *logical_monitor);
|
||||
|
||||
META_EXPORT_TEST
|
||||
float meta_logical_monitor_get_scale (MetaLogicalMonitor *logical_monitor);
|
||||
|
||||
MtkMonitorTransform meta_logical_monitor_get_transform (MetaLogicalMonitor *logical_monitor);
|
||||
|
@ -19,10 +19,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/util-private.h"
|
||||
|
||||
typedef struct _MetaFraction
|
||||
{
|
||||
int num;
|
||||
int denom;
|
||||
} MetaFraction;
|
||||
|
||||
META_EXPORT_TEST
|
||||
MetaFraction meta_fraction_from_double (double src);
|
||||
|
431
src/tests/cursor-tests.c
Normal file
@ -0,0 +1,431 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/meta-cursor-sprite-xcursor.h"
|
||||
#include "backends/meta-cursor-tracker-private.h"
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "clutter/clutter.h"
|
||||
#include "compositor/meta-window-actor-private.h"
|
||||
#include "core/meta-fraction.h"
|
||||
#include "core/util-private.h"
|
||||
#include "meta/meta-wayland-compositor.h"
|
||||
#include "tests/meta-test/meta-context-test.h"
|
||||
#include "tests/meta-monitor-test-utils.h"
|
||||
#include "tests/meta-ref-test.h"
|
||||
#include "tests/meta-wayland-test-driver.h"
|
||||
#include "tests/meta-wayland-test-utils.h"
|
||||
|
||||
struct _MetaCrossOverlay
|
||||
{
|
||||
GObject parent;
|
||||
};
|
||||
|
||||
static MetaContext *test_context;
|
||||
static MetaWaylandTestDriver *test_driver;
|
||||
|
||||
static void clutter_content_iface_init (ClutterContentInterface *iface);
|
||||
|
||||
#define META_TYPE_CROSS_OVERLAY (meta_cross_overlay_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaCrossOverlay, meta_cross_overlay,
|
||||
META, CROSS_OVERLAY, GObject)
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaCrossOverlay, meta_cross_overlay,
|
||||
G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
|
||||
clutter_content_iface_init))
|
||||
|
||||
static void
|
||||
meta_cross_overlay_paint_content (ClutterContent *content,
|
||||
ClutterActor *actor,
|
||||
ClutterPaintNode *node,
|
||||
ClutterPaintContext *paint_context)
|
||||
{
|
||||
g_autoptr (ClutterPaintNode) cross_node = NULL;
|
||||
ClutterActorBox allocation;
|
||||
ClutterActorBox horizontal;
|
||||
ClutterActorBox vertical;
|
||||
CoglColor color;
|
||||
|
||||
clutter_actor_get_allocation_box (actor, &allocation);
|
||||
|
||||
cogl_color_init_from_4f (&color, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
cross_node = clutter_color_node_new (&color);
|
||||
clutter_paint_node_add_child (node, cross_node);
|
||||
|
||||
horizontal = (ClutterActorBox) {
|
||||
.x1 = allocation.x1,
|
||||
.y1 = (allocation.y2 - allocation.y1) / 2 - 0.5f,
|
||||
.x2 = allocation.x2,
|
||||
.y2 = (allocation.y2 - allocation.y1) / 2 + 0.5f,
|
||||
};
|
||||
vertical = (ClutterActorBox) {
|
||||
.x1 = (allocation.x2 - allocation.x1) / 2 - 0.5f,
|
||||
.y1 = allocation.y1,
|
||||
.x2 = (allocation.x2 - allocation.x1) / 2 + 0.5f,
|
||||
.y2 = allocation.y2,
|
||||
};
|
||||
|
||||
clutter_paint_node_add_rectangle (cross_node, &horizontal);
|
||||
clutter_paint_node_add_rectangle (cross_node, &vertical);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_content_iface_init (ClutterContentInterface *iface)
|
||||
{
|
||||
iface->paint_content = meta_cross_overlay_paint_content;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cross_overlay_class_init (MetaCrossOverlayClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cross_overlay_init (MetaCrossOverlay *overlay)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
on_stage_size_changed (ClutterActor *stage,
|
||||
GParamSpec *pspec,
|
||||
ClutterActor *overlay_actor)
|
||||
{
|
||||
float width, height;
|
||||
|
||||
clutter_actor_get_size (stage, &width, &height);
|
||||
clutter_actor_set_size (overlay_actor, width, height);
|
||||
}
|
||||
|
||||
static ClutterActor *
|
||||
create_overlay_actor (void)
|
||||
{
|
||||
MetaBackend *backend = meta_context_get_backend (test_context);
|
||||
ClutterActor *stage = meta_backend_get_stage (backend);
|
||||
ClutterActor *actor;
|
||||
g_autoptr (ClutterContent) content = NULL;
|
||||
|
||||
content = g_object_new (META_TYPE_CROSS_OVERLAY, NULL);
|
||||
actor = clutter_actor_new ();
|
||||
clutter_actor_set_content (actor, content);
|
||||
clutter_actor_set_name (actor, "cross-overlay");
|
||||
clutter_actor_show (actor);
|
||||
|
||||
clutter_actor_add_child (stage, actor);
|
||||
g_signal_connect_object (stage, "notify::size",
|
||||
G_CALLBACK (on_stage_size_changed),
|
||||
actor,
|
||||
G_CONNECT_DEFAULT);
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
static ClutterStageView *
|
||||
setup_test_case (int width,
|
||||
int height,
|
||||
float scale,
|
||||
MetaLogicalMonitorLayoutMode layout_mode,
|
||||
ClutterVirtualInputDevice *virtual_pointer)
|
||||
{
|
||||
MetaBackend *backend = meta_context_get_backend (test_context);
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_backend_get_monitor_manager (backend);
|
||||
MetaMonitorManagerTest *monitor_manager_test =
|
||||
META_MONITOR_MANAGER_TEST (monitor_manager);
|
||||
MetaRenderer *renderer = meta_backend_get_renderer (backend);
|
||||
GList *logical_monitors;
|
||||
MetaLogicalMonitor *logical_monitor;
|
||||
MetaFraction scale_fraction;
|
||||
GList *views;
|
||||
g_autofree char *output_serial = NULL;
|
||||
MetaMonitorTestSetup *test_setup;
|
||||
MonitorTestCaseSetup test_case_setup = {
|
||||
.modes = {
|
||||
{
|
||||
.width = width,
|
||||
.height = height,
|
||||
.refresh_rate = 60.0
|
||||
},
|
||||
},
|
||||
.n_modes = 1,
|
||||
.outputs = {
|
||||
{
|
||||
.crtc = 0,
|
||||
.modes = { 0 },
|
||||
.n_modes = 1,
|
||||
.preferred_mode = 0,
|
||||
.possible_crtcs = { 0 },
|
||||
.n_possible_crtcs = 1,
|
||||
.width_mm = 150,
|
||||
.height_mm = 85,
|
||||
.scale = scale,
|
||||
},
|
||||
},
|
||||
.n_outputs = 1,
|
||||
.crtcs = {
|
||||
{
|
||||
.current_mode = -1
|
||||
},
|
||||
},
|
||||
.n_crtcs = 1
|
||||
};
|
||||
static int output_serial_counter = 0x12300000;
|
||||
|
||||
/* Always generate unique serials to never trigger policy trying to inherit
|
||||
* the scale from previous configurations.
|
||||
*/
|
||||
output_serial = g_strdup_printf ("0x%x", output_serial_counter++);
|
||||
test_case_setup.outputs[0].serial = output_serial;
|
||||
|
||||
meta_monitor_manager_test_set_layout_mode (monitor_manager_test,
|
||||
layout_mode);
|
||||
test_setup = meta_create_monitor_test_setup (backend,
|
||||
&test_case_setup,
|
||||
MONITOR_TEST_FLAG_NO_STORED);
|
||||
meta_monitor_manager_test_emulate_hotplug (monitor_manager_test, test_setup);
|
||||
|
||||
logical_monitors = meta_monitor_manager_get_logical_monitors (monitor_manager);
|
||||
g_assert_cmpuint (g_list_length (logical_monitors), ==, 1);
|
||||
logical_monitor = META_LOGICAL_MONITOR (logical_monitors->data);
|
||||
g_assert_cmpfloat_with_epsilon (meta_logical_monitor_get_scale (logical_monitor),
|
||||
scale,
|
||||
FLT_EPSILON);
|
||||
|
||||
scale_fraction = meta_fraction_from_double (scale);
|
||||
|
||||
meta_wayland_test_driver_set_property_int (test_driver,
|
||||
"scale-num",
|
||||
scale_fraction.num);
|
||||
meta_wayland_test_driver_set_property_int (test_driver,
|
||||
"scale-denom",
|
||||
scale_fraction.denom);
|
||||
|
||||
switch (layout_mode)
|
||||
{
|
||||
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
|
||||
clutter_virtual_input_device_notify_absolute_motion (virtual_pointer,
|
||||
g_get_monotonic_time (),
|
||||
width / scale / 2.0f,
|
||||
height / scale / 2.0f);
|
||||
break;
|
||||
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
|
||||
clutter_virtual_input_device_notify_absolute_motion (virtual_pointer,
|
||||
g_get_monotonic_time (),
|
||||
width / 2.0f,
|
||||
height / 2.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
meta_flush_input (test_context);
|
||||
|
||||
views = meta_renderer_get_views (renderer);
|
||||
g_assert_cmpuint (g_list_length (views), ==, 1);
|
||||
return CLUTTER_STAGE_VIEW (views->data);
|
||||
}
|
||||
|
||||
static const char *
|
||||
layout_mode_to_string (MetaLogicalMonitorLayoutMode layout_mode)
|
||||
{
|
||||
switch (layout_mode)
|
||||
{
|
||||
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
|
||||
return "logical";
|
||||
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
|
||||
return "physical";
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
wait_for_no_windows (void)
|
||||
{
|
||||
MetaDisplay *display = meta_context_get_display (test_context);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
g_autoptr (GList) windows = NULL;
|
||||
|
||||
windows = meta_display_list_all_windows (display);
|
||||
if (!windows)
|
||||
return;
|
||||
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wait_for_window_cursor (void)
|
||||
{
|
||||
MetaBackend *backend = meta_context_get_backend (test_context);
|
||||
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
|
||||
|
||||
while (!meta_cursor_tracker_has_window_cursor (cursor_tracker))
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_native_cursor_scaling (void)
|
||||
{
|
||||
MetaBackend *backend = meta_context_get_backend (test_context);
|
||||
MetaDisplay *display = meta_context_get_display (test_context);
|
||||
ClutterSeat *seat = meta_backend_get_default_seat (backend);
|
||||
g_autoptr (ClutterVirtualInputDevice) virtual_pointer = NULL;
|
||||
ClutterActor *overlay_actor;
|
||||
ClutterStageView *view;
|
||||
MetaCursor cursor;
|
||||
const char *cursor_name;
|
||||
struct {
|
||||
int width;
|
||||
int height;
|
||||
float scale;
|
||||
MetaLogicalMonitorLayoutMode layout_mode;
|
||||
} test_cases[] = {
|
||||
{
|
||||
.width = 1920, .height = 1080, .scale = 1.0,
|
||||
.layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL,
|
||||
},
|
||||
{
|
||||
.width = 1920, .height = 1080, .scale = 1.0,
|
||||
.layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL,
|
||||
},
|
||||
{
|
||||
.width = 1920, .height = 1080, .scale = 2.0,
|
||||
.layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL,
|
||||
},
|
||||
{
|
||||
.width = 1920, .height = 1080, .scale = 2.0,
|
||||
.layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL,
|
||||
},
|
||||
};
|
||||
int i;
|
||||
|
||||
cursor = META_CURSOR_MOVE_OR_RESIZE_WINDOW;
|
||||
meta_display_set_cursor (display, cursor);
|
||||
virtual_pointer = clutter_seat_create_virtual_device (seat,
|
||||
CLUTTER_POINTER_DEVICE);
|
||||
overlay_actor = create_overlay_actor ();
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_cases); i++)
|
||||
{
|
||||
MetaWaylandTestClient *test_client;
|
||||
g_autofree char *ref_test_name = NULL;
|
||||
MetaWindow *window;
|
||||
MetaWindowActor *window_actor;
|
||||
|
||||
g_debug ("Testing monitor resolution %dx%d with scale %f and "
|
||||
"%s layout mode",
|
||||
test_cases[i].width, test_cases[i].height, test_cases[i].scale,
|
||||
layout_mode_to_string (test_cases[i].layout_mode));
|
||||
|
||||
wait_for_no_windows ();
|
||||
|
||||
ref_test_name = g_strdup_printf ("%s/%d", g_test_get_path (), i);
|
||||
|
||||
view = setup_test_case (test_cases[i].width, test_cases[i].height,
|
||||
test_cases[i].scale,
|
||||
test_cases[i].layout_mode,
|
||||
virtual_pointer);
|
||||
meta_ref_test_verify_view (view,
|
||||
ref_test_name,
|
||||
0,
|
||||
meta_ref_test_determine_ref_test_flag ());
|
||||
|
||||
cursor_name = meta_cursor_get_name (cursor);
|
||||
test_client =
|
||||
meta_wayland_test_client_new_with_args (test_context,
|
||||
"cursor-tests-client",
|
||||
cursor_name,
|
||||
NULL);
|
||||
meta_wayland_test_driver_wait_for_sync_point (test_driver, 0);
|
||||
|
||||
window = meta_find_window_from_title (test_context,
|
||||
"cursor-tests-surface");
|
||||
g_assert_nonnull (window);
|
||||
meta_wait_for_window_shown (window);
|
||||
window_actor = meta_window_actor_from_window (window);
|
||||
g_assert_nonnull (window_actor);
|
||||
meta_wait_for_window_cursor ();
|
||||
|
||||
meta_ref_test_verify_view (view,
|
||||
ref_test_name,
|
||||
1,
|
||||
meta_ref_test_determine_ref_test_flag ());
|
||||
|
||||
meta_wayland_test_driver_emit_sync_event (test_driver, 0);
|
||||
|
||||
g_object_add_weak_pointer (G_OBJECT (window_actor),
|
||||
(gpointer *) &window_actor);
|
||||
meta_wayland_test_client_finish (test_client);
|
||||
while (window_actor)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
clutter_actor_destroy (overlay_actor);
|
||||
}
|
||||
|
||||
static void
|
||||
init_tests (void)
|
||||
{
|
||||
g_test_add_func ("/backends/native/cursor/scaling",
|
||||
meta_test_native_cursor_scaling);
|
||||
}
|
||||
|
||||
static void
|
||||
on_before_tests (void)
|
||||
{
|
||||
MetaWaylandCompositor *compositor =
|
||||
meta_context_get_wayland_compositor (test_context);
|
||||
|
||||
test_driver = meta_wayland_test_driver_new (compositor);
|
||||
meta_wayland_test_driver_set_property_int (test_driver,
|
||||
"cursor-theme-size",
|
||||
meta_prefs_get_cursor_size ());
|
||||
}
|
||||
|
||||
static void
|
||||
on_after_tests (void)
|
||||
{
|
||||
g_clear_object (&test_driver);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
g_autoptr (MetaContext) context = NULL;
|
||||
|
||||
context = meta_create_test_context (META_CONTEXT_TEST_TYPE_TEST,
|
||||
(META_CONTEXT_TEST_FLAG_NO_X11 |
|
||||
META_CONTEXT_TEST_FLAG_TEST_CLIENT |
|
||||
META_CONTEXT_TEST_FLAG_NO_ANIMATIONS));
|
||||
g_assert_true (meta_context_configure (context, &argc, &argv, NULL));
|
||||
meta_context_test_set_background_color (META_CONTEXT_TEST (context),
|
||||
COGL_COLOR_INIT (255, 255, 255, 255));
|
||||
|
||||
test_context = context;
|
||||
|
||||
init_tests ();
|
||||
|
||||
g_signal_connect (context, "before-tests",
|
||||
G_CALLBACK (on_before_tests), NULL);
|
||||
g_signal_connect (context, "after-tests",
|
||||
G_CALLBACK (on_after_tests), NULL);
|
||||
|
||||
return meta_context_test_run_tests (META_CONTEXT_TEST (context),
|
||||
META_TEST_RUN_FLAG_NONE);
|
||||
}
|
@ -447,6 +447,17 @@ test_cases += [
|
||||
'meta-thread-impl-test.h',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'cursor-tests',
|
||||
'suite': 'backends/native',
|
||||
'sources': [
|
||||
'cursor-tests.c',
|
||||
wayland_test_utils,
|
||||
],
|
||||
'depends': [
|
||||
test_client_executables.get('cursor-tests-client'),
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
# KMS tests
|
||||
|
BIN
src/tests/ref-tests/backends_native_cursor_scaling_0_0.ref.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
src/tests/ref-tests/backends_native_cursor_scaling_0_1.ref.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
src/tests/ref-tests/backends_native_cursor_scaling_1_0.ref.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
src/tests/ref-tests/backends_native_cursor_scaling_1_1.ref.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
src/tests/ref-tests/backends_native_cursor_scaling_2_0.ref.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
src/tests/ref-tests/backends_native_cursor_scaling_2_1.ref.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
src/tests/ref-tests/backends_native_cursor_scaling_3_0.ref.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
src/tests/ref-tests/backends_native_cursor_scaling_3_1.ref.png
Normal file
After Width: | Height: | Size: 10 KiB |
99
src/tests/wayland-test-clients/cursor-tests-client.c
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <wayland-cursor.h>
|
||||
|
||||
#include "wayland-test-client-utils.h"
|
||||
|
||||
static char *cursor_name;
|
||||
|
||||
static struct wl_surface *cursor_surface;
|
||||
|
||||
static void
|
||||
on_pointer_enter (WaylandSurface *surface,
|
||||
struct wl_pointer *pointer,
|
||||
uint32_t serial)
|
||||
{
|
||||
WaylandDisplay *display = surface->display;
|
||||
struct wl_cursor_theme *cursor_theme;
|
||||
struct wl_cursor *cursor;
|
||||
struct wl_cursor_image *image;
|
||||
struct wl_buffer *buffer;
|
||||
int theme_size;
|
||||
int num, denom;
|
||||
float scale;
|
||||
int ceiled_scale;
|
||||
|
||||
theme_size = lookup_property_int (display, "cursor-theme-size");
|
||||
num = lookup_property_int (display, "scale-num");
|
||||
denom = lookup_property_int (display, "scale-denom");
|
||||
scale = (float) num / (float) denom;
|
||||
ceiled_scale = (int) ceilf (scale);
|
||||
|
||||
cursor_theme = wl_cursor_theme_load (NULL,
|
||||
(int) (theme_size * ceilf (scale)),
|
||||
display->shm);
|
||||
cursor = wl_cursor_theme_get_cursor (cursor_theme, cursor_name);
|
||||
|
||||
if (!cursor_surface)
|
||||
cursor_surface = wl_compositor_create_surface (display->compositor);
|
||||
|
||||
image = cursor->images[0];
|
||||
buffer = wl_cursor_image_get_buffer (image);
|
||||
g_assert_nonnull (buffer);
|
||||
|
||||
wl_pointer_set_cursor (pointer, serial,
|
||||
cursor_surface,
|
||||
image->hotspot_x / ceiled_scale,
|
||||
image->hotspot_y / ceiled_scale);
|
||||
wl_surface_attach (cursor_surface, buffer, 0, 0);
|
||||
wl_surface_damage (cursor_surface, 0, 0,
|
||||
image->width, image->height);
|
||||
wl_surface_set_buffer_scale (cursor_surface,
|
||||
ceiled_scale);
|
||||
wl_surface_commit (cursor_surface);
|
||||
|
||||
wl_cursor_theme_destroy (cursor_theme);
|
||||
|
||||
test_driver_sync_point (display->test_driver, 0, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
g_autoptr (WaylandDisplay) display = NULL;
|
||||
g_autoptr (WaylandSurface) surface = NULL;
|
||||
|
||||
cursor_name = argv[1];
|
||||
|
||||
display = wayland_display_new (WAYLAND_DISPLAY_CAPABILITY_TEST_DRIVER);
|
||||
surface = wayland_surface_new (display,
|
||||
"cursor-tests-surface",
|
||||
100, 100, 0xffffffff);
|
||||
g_signal_connect (surface, "pointer-enter",
|
||||
G_CALLBACK (on_pointer_enter), NULL);
|
||||
xdg_toplevel_set_fullscreen (surface->xdg_toplevel, NULL);
|
||||
wl_surface_commit (surface->wl_surface);
|
||||
|
||||
wait_for_sync_event (display, 0);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -102,6 +102,12 @@ wayland_test_clients = [
|
||||
{
|
||||
'name': 'ycbcr',
|
||||
},
|
||||
{
|
||||
'name': 'cursor-tests-client',
|
||||
'extra_deps': [
|
||||
wayland_cursor_dep,
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
test_client_executables = {}
|
||||
|