Add new buffer scale tests

* 12to11-test.xml (test_manager): <error>: New errors
`scale_lock_exists' and `invalid_scale'.
(test_manager): <get_test_surface>: Reword documentation.
(test_manager): <get_scale_lock>: New request.
(test_scale_lock): New interface.

* compositor.h: Update prototypes.
* output.c (HandleScaleSettingChange): New function.  Ignore
scale changes while scale is locked.
(XLInitRROutputs): Initialize real output scale.
* test.c (DestroyScaleLock, SetScale, GetScaleLock): New
functions.
(test_manager_impl): Add new implementation.
* tests/Imakefile (SYSTEM_LIBRARIES): Add MathLibrary.
(SRCS7, OBJS7): Add scale_test.c/.o.
(PROGRAMS): Add scale_test.
(scale_test): New program target.
* tests/run_tests.sh (standard_tests): Add scale_test.
* tests/svnignore.txt: Add scale_test.
* tests/test_harness.c (exit_with_code): New function.
(open_test_display): Initialize scale.
(report_test_failure): Call it instead of just exit.
(test_set_scale): New function.
(test_complete): Call exit_with_code.
* tests/test_harness.h (struct test_display): New field
`scale_lock'.
This commit is contained in:
hujianwei 2022-11-05 08:18:18 +00:00
parent fa29286c98
commit 21aa7494cd
9 changed files with 233 additions and 17 deletions

View file

@ -33,25 +33,46 @@
<enum name="error">
<entry name="role_present" value="1"
summary="given wl_surface has/had another role"/>
<entry name="scale_lock_exists" value="2"
summary="another client has already locked the scale"/>
<entry name="invalid_scale" value="3"
summary="the specified scale is invalid"/>
</enum>
<request name="get_test_surface">
<description summary="obtain test surface role">
Get a test_surface object for a particular surface. If a role
was already attached to this surface, or a role of a different
type was previously attached, a role_present error is issued.
type was previously attached, post a role_present error.
The window is created immediately after get_test_surface is
called. It is mapped once a commit request with a non-nil
buffer is made.
Create the window immediately after get_test_surface is
called; the window is mapped once a commit request with a
non-nil buffer is made.
Once the window associated with the test_surface object is
mapped, a mapped event is sent.
mapped, send a mapped event.
</description>
<arg name="id" type="new_id" interface="test_surface"/>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<request name="get_scale_lock">
<description summary="obtain scale lock">
Create a new test_scale_lock object. As long as this object
exists, set the global output scale to the scale specified in
this request (or in a subsequent test_scale_lock.set_scale
request.)
If a test_scale_lock object already exists, generate a
scale_lock_exists error.
If the scale is invalid (by being less than 0), post an
invalid_scale error.
</description>
<arg name="id" type="new_id" interface="test_scale_lock"/>
<arg name="global_scale" type="uint"/>
</request>
<event name="display_string">
<description summary="X server name">
The display_string event sends the name of the X display to
@ -74,8 +95,8 @@
<request name="destroy" type="destructor">
<description summary="destroy role">
This request destroys the test_surface role. Subsequently,
get_test_surface can be called again with its surface.
Destroy the test_surface role. Subsequently, get_test_surface
can be called again with its surface.
</description>
</request>
@ -94,4 +115,29 @@
<arg name="display_string" type="string"/>
</event>
</interface>
<interface name="test_scale_lock" version="1">
<description summary="test scale lock">
A scale lock resource represents the "lock" a client holds on
the global output scale. While it still exists, the scale for
every output will be whatever was specified when the lock was
created or by the last set_scale request.
</description>
<request name="destroy" type="destructor">
<description summary="destroy scale lock">
Destroy the specified scale lock, restore the actual scale of
each output, and let clients call get_scale_lock again.
</description>
</request>
<request name="set_scale">
<description summary="set the global output scale">
Set the scale of each output to the specified scale, and
resize all surfaces accordingly. If the scale is invalid,
post an invalid_scale error.
</description>
<arg name="scale" type="uint"/>
</request>
</interface>
</protocol>

View file

@ -1206,6 +1206,7 @@ extern void XLRemoveScaleChangeCallback (void *);
extern void XLClearOutputs (Surface *);
extern void XLOutputSetChangeFunction (void (*) (Time));
extern void XLGetMaxOutputBounds (int *, int *, int *, int *);
extern void XLOutputHandleScaleChange (int);
/* Defined in atoms.c. */
@ -1799,6 +1800,8 @@ extern void XLInitPointerGestures (void);
/* Defined in test.c. */
extern int locked_output_scale;
extern void XLInitTest (void);
extern Bool XLHandleOneXEventForTest (XEvent *);

View file

@ -98,6 +98,9 @@ static ScaleChangeCallback scale_callbacks;
/* The scale factor currently applied on a global basis. */
int global_scale_factor;
/* The current real scale factor. */
static int real_scale_factor;
/* Function run upon any kind of XRandR notify event. */
static void (*change_hook) (Time);
@ -1035,6 +1038,19 @@ HandleScaleChange (int scale)
RunScaleChangeCallbacks ();
}
static void
HandleScaleSettingChange (int scale)
{
real_scale_factor = scale;
/* If the scale factor is locked, just return. */
if (locked_output_scale)
return;
/* Otherwise, update the scale. */
HandleScaleChange (scale);
}
void *
XLAddScaleChangeCallback (void *data, void (*func) (void *, int))
{
@ -1142,6 +1158,18 @@ XLGetMaxOutputBounds (int *x_min, int *y_min, int *x_max,
*y_max = y2;
}
void
XLOutputHandleScaleChange (int new_scale)
{
/* If the value is not -1, just use the new scale.
Otherwise, use the current non-locked scale. */
if (new_scale != -1)
HandleScaleChange (new_scale);
else
HandleScaleChange (real_scale_factor);
}
void
XLInitRROutputs (void)
{
@ -1179,7 +1207,10 @@ XLInitRROutputs (void)
factor was specified for debugging. */
if (!ApplyEnvironment ("GLOBAL_SCALE", &global_scale_factor))
XLListenToIntegerSetting ("Gdk/WindowScalingFactor",
HandleScaleChange);
HandleScaleSettingChange);
/* Set the real scale factor. */
real_scale_factor = global_scale_factor;
/* Initialize the scale change callback list sentinel node. */
scale_callbacks.next = &scale_callbacks;
@ -1204,4 +1235,3 @@ XLInitRROutputs (void)
all_outputs = BuildOutputTree ();
MakeGlobalsForOutputTree (all_outputs);
}

92
test.c
View file

@ -60,6 +60,11 @@ struct _TestSurface
int bounds_width, bounds_height;
};
/* The locked output scale. N.B. that a test_scale_lock is not an
actual resource, and just represents the state of this
variable. */
int locked_output_scale;
/* The test surface manager global. */
static struct wl_global *test_manager_global;
@ -348,6 +353,47 @@ HandleResourceDestroy (struct wl_resource *resource)
DestroyBacking (test);
}
static void
DestroyScaleLock (struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
SetScale (struct wl_client *client, struct wl_resource *resource,
uint32_t scale)
{
/* If the scale is invalid, reject it. */
if (!scale)
{
wl_resource_post_error (resource, TEST_MANAGER_ERROR_INVALID_SCALE,
"scale of 0 specified");
return;
}
/* Set the scale. As there can only be one lock at any given
time, there is no need to check the resource data. */
locked_output_scale = scale;
XLOutputHandleScaleChange (scale);
}
static const struct test_scale_lock_interface scale_lock_impl =
{
.destroy = DestroyScaleLock,
.set_scale = SetScale,
};
static void
HandleScaleLockResourceDestroy (struct wl_resource *resource)
{
/* There is no resource data associated with scale locks. Just
unlock the scale. */
locked_output_scale = 0;
XLOutputHandleScaleChange (-1);
}
static void
GetTestSurface (struct wl_client *client, struct wl_resource *resource,
uint32_t id, struct wl_resource *surface_resource)
@ -451,9 +497,55 @@ GetTestSurface (struct wl_client *client, struct wl_resource *resource,
abort ();
}
static void
GetScaleLock (struct wl_client *client, struct wl_resource *resource,
uint32_t id, uint32_t scale)
{
struct wl_resource *lock_resource;
if (!scale)
{
wl_resource_post_error (resource, TEST_MANAGER_ERROR_INVALID_SCALE,
"scale of 0 specified");
return;
}
if (locked_output_scale)
{
/* The scale is already locked, so don't create another
lock. */
wl_resource_post_error (resource, TEST_MANAGER_ERROR_SCALE_LOCK_EXISTS,
"a scale lock already exists (another test is"
" already running?)");
return;
}
lock_resource = wl_resource_create (client, &test_scale_lock_interface,
wl_resource_get_version (resource),
id);
if (!lock_resource)
{
wl_resource_post_no_memory (resource);
return;
}
/* Now, set the locked scale. */
locked_output_scale = scale;
/* And update the global scale factor if need be. */
if (scale != global_scale_factor)
XLOutputHandleScaleChange (scale);
/* And resource implementation. */
wl_resource_set_implementation (lock_resource, &scale_lock_impl,
NULL, HandleScaleLockResourceDestroy);
}
static const struct test_manager_interface test_manager_impl =
{
.get_test_surface = GetTestSurface,
.get_scale_lock = GetScaleLock,
};

View file

@ -2,6 +2,7 @@
12TO11ROOT = ..
DEPLIBS = $(DEPXLIB)
SYS_LIBRARIES = MathLibrary
LOCAL_LIBRARIES = $(WAYLAND_CLIENT) $(XLIB) $(PNG)
COMMONOBJS = test_harness.o
COMMONSRCS = test_harness.c
@ -35,7 +36,9 @@ ScannerTarget(viewporter)
OBJS5 = $(COMMONSRCS) viewporter_test.o
SRCS6 = $(COMMONSRCS) subsurface_test.c
OBJS6 = $(COMMONSRCS) subsurface_test.o
PROGRAMS = imgview simple_test damage_test transform_test viewporter_test subsurface_test
SRCS7 = $(COMMONSRCS) scale_test.c
OBJS7 = $(COMMONSRCS) scale_test.o
PROGRAMS = imgview simple_test damage_test transform_test viewporter_test subsurface_test scale_test
/* Make all objects depend on HEADER. */
$(OBJS1): $(HEADER)
@ -49,7 +52,9 @@ NormalProgramTarget(damage_test,$(OBJS3),NullParameter,$(LOCAL_LIBRARIES),NullPa
NormalProgramTarget(transform_test,$(OBJS4),NullParameter,$(LOCAL_LIBRARIES),NullParameter)
NormalProgramTarget(viewporter_test,$(OBJS5),NullParameter,$(LOCAL_LIBRARIES),NullParameter)
NormalProgramTarget(subsurface_test,$(OBJS6),NullParameter,$(LOCAL_LIBRARIES),NullParameter)
NormalProgramTarget(scale_test,$(OBJS7),NullParameter,$(LOCAL_LIBRARIES),NullParameter)
DependTarget3($(SRCS1),$(SRCS2),$(SRCS3))
DependTarget3($(SRCS4),$(SRCS5),$(SRCS6))
DependTarget3($(SRCS7),NullParameter,NullParameter)
all:: $(PROGRAMS)

View file

@ -21,14 +21,11 @@
pushd "$(dirname $0)"
declare -a standard_tests=(
simple_test damage_test transform_test viewporter_test
subsurface_test
subsurface_test scale_test
)
make -C . "${standard_tests[@]}"
# Run tandard tests, meaning those that should be run with a
# GLOBAL_SCALE of 1 and an OUTPUT_SCALE of 1.
export GLOBAL_SCALE=1
export OUTPUT_SCALE=1
exec 3< <(stdbuf -oL ../12to11 -printsocket)

View file

@ -6,6 +6,7 @@ damage_test
transform_test
viewporter_test
subsurface_test
scale_test
imgview
reject.dump
Makefile

View file

@ -45,6 +45,9 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
/* Whether or not to write image data instead of verifying it. */
static bool write_image_data_instead;
/* The test display. */
static struct test_display *display;
static void
handle_test_manager_display_string (void *data, struct test_manager *manager,
const char *display_string)
@ -154,10 +157,29 @@ die (const char *reason)
exit (1);
}
/* This should be called when a test failed due to a non-IO error. It
destroys the scale lock and synchronizes with the compositor so
that by the time the next test is run, the current test's scale
lock will have been released. */
static void __attribute__ ((noreturn))
exit_with_code (int code)
{
if (display)
{
test_scale_lock_destroy (display->scale_lock);
wl_display_roundtrip (display->display);
}
exit (code);
}
struct test_display *
open_test_display (struct test_interface *interfaces, int num_interfaces)
{
struct test_display *display;
if (display)
/* The display was already opened. */
return display;
display = malloc (sizeof *display);
@ -191,8 +213,17 @@ open_test_display (struct test_interface *interfaces, int num_interfaces)
if (!test_manager_check (display))
goto error_3;
/* And try to set up the scale lock. */
display->scale_lock
= test_manager_get_scale_lock (display->test_manager, 1);
if (!display->scale_lock)
goto error_4;
return display;
error_4:
XFree (display->pixmap_formats);
error_3:
if (display->x_display)
XCloseDisplay (display->x_display);
@ -200,6 +231,7 @@ open_test_display (struct test_interface *interfaces, int num_interfaces)
wl_display_disconnect (display->display);
error_1:
free (display);
display = NULL;
return NULL;
}
@ -325,7 +357,7 @@ report_test_failure (const char *format, ...)
fputs ("\n", stderr);
va_end (ap);
exit (1);
exit_with_code (1);
}
void __attribute__ ((format (gnu_printf, 1, 2)))
@ -766,6 +798,12 @@ verify_image_data (struct test_display *display, Window window,
test_log ("verified image data");
}
void
test_set_scale (struct test_display *display, int scale)
{
test_scale_lock_set_scale (display->scale_lock, scale);
}
void
test_init (void)
{
@ -777,5 +815,5 @@ void __attribute__ ((noreturn))
test_complete (void)
{
test_log ("test ran successfully");
exit (0);
exit_with_code (0);
}

View file

@ -51,6 +51,9 @@ struct test_display
struct wl_shm *shm;
struct test_manager *test_manager;
/* The test scale lock. */
struct test_scale_lock *scale_lock;
/* Test interfaces. */
struct test_interface *interfaces;
@ -119,6 +122,7 @@ extern unsigned char *load_image_data (const char *,
extern void verify_image_data (struct test_display *, Window, const char *);
extern void test_init (void);
extern void test_complete (void) __attribute__ ((noreturn));
extern void test_set_scale (struct test_display *, int);
#define ARRAYELTS(arr) (sizeof (arr) / sizeof (arr)[0])