diff --git a/12to11-test.xml b/12to11-test.xml
index eeac4b5..f20eb4c 100644
--- a/12to11-test.xml
+++ b/12to11-test.xml
@@ -55,6 +55,26 @@
summary="the specified label is invalid"/>
+
+
+
+
+
+
+ These values are used to indicate which edge of a surface
+ is being dragged in a resize or move operation.
+
+
+
+
+
+
+
+
+
+
+
@@ -155,12 +175,25 @@
-
+
Force the subcompositor to be garbaged, and all contents
redrawn from scratch upon any damage.
+
+
+ Begin a move or resize event with the specified resize edge
+ and event serial on the given seat. Send a resize_rejected
+ event if the edge is invalid or the serial is out of date, or
+ the specified role no longer has a surface.
+
+
+
+
+
+
The map event is sent once the window is mapped and its
@@ -208,6 +241,13 @@
+
+
+
+ The resize_finished event is sent immediately after a resize
+ completes.
+
+
diff --git a/compositor.h b/compositor.h
index a3e5a93..d000c0f 100644
--- a/compositor.h
+++ b/compositor.h
@@ -1632,7 +1632,7 @@ extern void XLDispatchGEForSeats (XEvent *, Surface *,
extern void XLSelectStandardEvents (Window);
extern void XLInitSeats (void);
extern Bool XLResizeToplevel (Seat *, Surface *, uint32_t, uint32_t);
-extern void XLMoveToplevel (Seat *, Surface *, uint32_t);
+extern Bool XLMoveToplevel (Seat *, Surface *, uint32_t);
extern Bool XLSeatExplicitlyGrabSurface (Seat *, Surface *, uint32_t);
extern void *XLSeatRunAfterResize (Seat *, void (*) (void *, void *),
diff --git a/seat.c b/seat.c
index 2891900..24fd775 100644
--- a/seat.c
+++ b/seat.c
@@ -2051,6 +2051,7 @@ CancelResizeOperation (Seat *seat, Time time, Subcompositor *subcompositor,
/* Stop the resize operation. */
XLSurfaceCancelUnmapCallback (seat->resize_surface_callback);
seat->resize_surface = NULL;
+ seat->resize_surface_callback = NULL;
/* Run resize completion callbacks. */
RunResizeDoneCallbacks (seat);
@@ -5098,21 +5099,30 @@ FakePointerEdge (Seat *seat, Surface *target, uint32_t serial,
XISetMask (mask.mask, XI_ButtonPress);
XISetMask (mask.mask, XI_ButtonRelease);
- /* Grab the pointer, and don't let go until the button is
- released. */
- state = XIGrabDevice (compositor.display, seat->master_pointer,
- window, seat->its_press_time, cursor,
- XIGrabModeAsync, XIGrabModeAsync, False, &mask);
+ if (!(seat->flags & IsTestSeat))
+ {
+ /* Grab the pointer, and don't let go until the button is
+ released. */
+ state = XIGrabDevice (compositor.display, seat->master_pointer,
+ window, seat->its_press_time, cursor,
+ XIGrabModeAsync, XIGrabModeAsync, False, &mask);
- if (state != Success)
- return False;
+ if (state != Success)
+ return False;
+ }
/* On the other hand, cancel focus locking and leave the surface,
since we will not be reporting motion events until the resize
operation completes. */
if (seat->grab_held)
- CancelGrabEarly (seat);
+ {
+ CancelGrabEarly (seat);
+
+ /* CancelGrabEarly may not have left the focus surface if the
+ pointer remains on it. Force a leave event to be sent. */
+ EnteredSurface (seat, NULL, seat->its_press_time, 0, 0, False);
+ }
/* Set the surface as the surface undergoing resize. */
seat->resize_surface = target;
@@ -5139,6 +5149,7 @@ HandlePointerEdge (Seat *seat, Surface *target, uint32_t serial,
return False;
if (!XLWmSupportsHint (_NET_WM_MOVERESIZE)
+ || (seat->flags & IsTestSeat)
|| getenv ("USE_BUILTIN_RESIZE"))
return FakePointerEdge (seat, target, serial, edge);
@@ -5417,10 +5428,10 @@ XLResizeToplevel (Seat *seat, Surface *surface, uint32_t serial,
return StartResizeTracking (seat, surface, serial, edge);
}
-void
+Bool
XLMoveToplevel (Seat *seat, Surface *surface, uint32_t serial)
{
- StartResizeTracking (seat, surface, serial, MoveEdge);
+ return StartResizeTracking (seat, surface, serial, MoveEdge);
}
void *
diff --git a/test.c b/test.c
index 3ffa684..3ea23aa 100644
--- a/test.c
+++ b/test.c
@@ -47,6 +47,9 @@ struct _TestSurface
/* The associated buffer release helper. */
BufferReleaseHelper *release_helper;
+ /* List of live resize callbacks. */
+ XLList *resize_callbacks;
+
/* The associated window. */
Window window;
@@ -71,6 +74,19 @@ static struct wl_global *test_manager_global;
/* Hash table of all surfaces. */
static XLAssocTable *surfaces;
+static void
+HandleResizeDone (void *key, void *data)
+{
+ TestSurface *test;
+
+ test = data;
+ test->resize_callbacks
+ = XLListRemove (test->resize_callbacks, key);
+
+ if (test->role.resource)
+ test_surface_send_resize_finished (test->role.resource);
+}
+
static void
DestroyBacking (TestSurface *test)
{
@@ -90,6 +106,10 @@ DestroyBacking (TestSurface *test)
/* Free the subcompositor. */
SubcompositorFree (test->subcompositor);
+ /* Free all resize callbacks. */
+ XLListFree (test->resize_callbacks,
+ XLSeatCancelResizeCallback);
+
/* And since there are no C level references to the role anymore, it
can be freed. */
XLFree (test);
@@ -369,6 +389,18 @@ Activate (Surface *surface, Role *role, int deviceid,
}
}
+static void
+GetResizeDimensions (Surface *surface, Role *role, int *width,
+ int *height)
+{
+ TestSurface *test;
+
+ test = TestSurfaceFromRole (role);
+
+ *width = SubcompositorWidth (test->subcompositor);
+ *height = SubcompositorHeight (test->subcompositor);
+}
+
static void
SetAlwaysGarbage (struct wl_client *client, struct wl_resource *resource)
{
@@ -380,10 +412,46 @@ SetAlwaysGarbage (struct wl_client *client, struct wl_resource *resource)
SubcompositorSetAlwaysGarbaged (test->subcompositor);
}
+static void
+MoveResize (struct wl_client *client, struct wl_resource *resource,
+ uint32_t edge, uint32_t serial,
+ struct wl_resource *seat_resource)
+{
+ TestSurface *test;
+ Seat *seat;
+ void *key;
+
+ test = wl_resource_get_user_data (resource);
+ seat = wl_resource_get_user_data (seat_resource);
+
+ if (!test->role.surface)
+ {
+ wl_resource_post_error (resource, TEST_MANAGER_ERROR_RESIZE_REJECTED,
+ "trying to resize test surface without surface");
+ return;
+ }
+
+ if (edge == TEST_MANAGER_RESIZE_EDGE_MOVE)
+ {
+ if (!XLMoveToplevel (seat, test->role.surface, serial))
+ wl_resource_post_error (resource, TEST_MANAGER_ERROR_RESIZE_REJECTED,
+ "move rejected for unspecified reason");
+ }
+ else if (!XLResizeToplevel (seat, test->role.surface, serial, edge))
+ wl_resource_post_error (resource, TEST_MANAGER_ERROR_RESIZE_REJECTED,
+ "resize rejected for unspecified reason");
+
+ /* Now attach a resize complete callback. */
+ key = XLSeatRunAfterResize (seat, HandleResizeDone, test);
+ test->resize_callbacks = XLListPrepend (test->resize_callbacks,
+ key);
+}
+
static const struct test_surface_interface test_surface_impl =
{
.destroy = Destroy,
.set_always_garbage = SetAlwaysGarbage,
+ .move_resize = MoveResize,
};
static void
@@ -535,6 +603,7 @@ GetTestSurface (struct wl_client *client, struct wl_resource *resource,
test->role.funcs.subsurface_update = SubsurfaceUpdate;
test->role.funcs.get_window = GetWindow;
test->role.funcs.activate = Activate;
+ test->role.funcs.get_resize_dimensions = GetResizeDimensions;
/* Add the resource implementation. */
wl_resource_set_implementation (test->role.resource, &test_surface_impl,
diff --git a/tests/seat_test.c b/tests/seat_test.c
index 9fbc0b1..84e44cd 100644
--- a/tests/seat_test.c
+++ b/tests/seat_test.c
@@ -33,6 +33,7 @@ enum test_expect_event_kind
KEYBOARD_ENTER_EVENT,
KEYBOARD_KEY_EVENT,
KEYBOARD_MODIFIERS_EVENT,
+ SURFACE_RESIZE_FINISHED_EVENT,
};
struct test_recorded_event
@@ -84,6 +85,9 @@ struct test_recorded_button_event
/* The button and state. */
uint32_t button, state;
+
+ /* The serial. */
+ uint32_t serial;
};
struct test_recorded_axis_value120_event
@@ -137,6 +141,12 @@ struct test_recorded_keyboard_modifiers_event
uint32_t group;
};
+struct test_recorded_resize_finished_event
+{
+ /* The event header. */
+ struct test_recorded_event header;
+};
+
struct test_subsurface
{
/* The subsurface itself. */
@@ -154,6 +164,7 @@ enum test_kind
TEST_GRAB_KIND,
TEST_VALUATOR_KIND,
TEST_KEY_KIND,
+ TEST_RESIZE_KIND,
};
static const char *test_names[] =
@@ -164,9 +175,10 @@ static const char *test_names[] =
"test_grab",
"test_valuator",
"test_key",
+ "test_resize",
};
-#define LAST_TEST TEST_KEY_KIND
+#define LAST_TEST TEST_RESIZE_KIND
#define TEST_SOURCE_DEVICE 4500000
/* The display. */
@@ -206,13 +218,14 @@ static void expect_frame_event (void);
static void expect_enter_event (struct wl_surface *, double, double);
static void expect_motion_event (double, double);
static void expect_leave_event (void);
-static void expect_button_event (int, int);
+static uint32_t expect_button_event (int, int);
static void expect_axis_value120_event (uint32_t, int32_t);
static void expect_keyboard_enter_event (struct wl_surface *, uint32_t *,
size_t);
static void expect_keyboard_key_event (uint32_t, uint32_t);
static void expect_keyboard_modifiers_event (uint32_t, uint32_t,
uint32_t, uint32_t);
+static void expect_resize_finished_event (void);
static void expect_no_events (void);
@@ -749,6 +762,62 @@ run_key_test (void)
expect_keyboard_enter_event (wayland_surface, NULL, 0);
}
+static void
+run_resize_test (struct test_XIButtonState *button_state)
+{
+ uint32_t serial;
+
+ test_seat_controller_dispatch_XI_ButtonPress (display->seat->controller,
+ test_get_time (),
+ TEST_SOURCE_DEVICE,
+ 1,
+ test_get_root (),
+ test_surface_window,
+ None,
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ 0,
+ button_state,
+ NULL, NULL, NULL);
+ test_XIButtonState_add_button (button_state, 1);
+ record_events ();
+
+ /* Obtain the serial. */
+ expect_frame_event ();
+ serial = expect_button_event (BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
+ expect_no_events ();
+
+ /* Now, start resize. */
+ test_surface_move_resize (test_surface, TEST_MANAGER_RESIZE_EDGE_MOVE,
+ serial, display->seat->seat);
+
+ /* And dispatch the button release. */
+ test_seat_controller_dispatch_XI_ButtonRelease (display->seat->controller,
+ test_get_time (),
+ TEST_SOURCE_DEVICE,
+ 1,
+ test_get_root (),
+ test_surface_window,
+ None,
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ 0,
+ button_state,
+ NULL, NULL, NULL);
+ test_XIButtonState_remove_button (button_state, 1);
+
+ record_events ();
+ expect_frame_event ();
+ expect_enter_event (wayland_surface, 2.0, 2.0);
+ expect_resize_finished_event ();
+ expect_frame_event ();
+ expect_leave_event ();
+}
+
static void
test_single_step (enum test_kind kind)
{
@@ -1007,6 +1076,24 @@ test_single_step (enum test_kind kind)
key (SERIAL, TIME, 59, WL_KEYBOARD_KEY_STATE_RELEASED) */
run_key_test ();
+ kind = TEST_RESIZE_KIND;
+ goto again;
+
+ case TEST_RESIZE_KIND:
+ /* Test simple resize (or rather movement). Dispatch a
+ ButtonPress event, obtain the serial of said event, start
+ resize, and dispatch a ButtonRelease event. Verify that the
+ following events are sent to the pointer and surface.
+
+ button (SERIAL, TIME, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED)
+ frame ()
+ leave ()
+ resize_finished ()
+ frame ();
+ enter (SERIAL, SURFACE, 2.0, 2.0)
+ frame (); */
+
+ run_resize_test (button_state);
break;
}
@@ -1118,11 +1205,12 @@ expect_leave_event (void)
report_test_failure ("a leave event was expected, but not received");
}
-static void
+static uint32_t
expect_button_event (int button, int state)
{
struct test_recorded_event *event;
struct test_recorded_button_event *button_event;
+ uint32_t serial;
event = record_tail;
@@ -1136,7 +1224,12 @@ expect_button_event (int button, int state)
button_event = (struct test_recorded_button_event *) event;
if (button_event->button == button && button_event->state == state)
- free (event);
+ {
+ serial = button_event->serial;
+ free (event);
+
+ return serial;
+ }
else
report_test_failure ("expected button event received "
"with incorrect parameters");
@@ -1283,6 +1376,25 @@ expect_no_events (void)
"yet some arrived");
}
+static void
+expect_resize_finished_event (void)
+{
+ struct test_recorded_event *event;
+
+ event = record_tail;
+
+ if (!event)
+ return;
+
+ record_tail = record_tail->last;
+
+ if (event->kind == SURFACE_RESIZE_FINISHED_EVENT)
+ free (event);
+ else
+ report_test_failure ("expected resize_finished_event, but it was"
+ " not received");
+}
+
static void
expect_surface_enter (double x, double y)
{
@@ -1331,11 +1443,42 @@ handle_test_surface_committed (void *data, struct test_surface *surface,
}
+static void
+handle_test_surface_resize_finished (void *data, struct test_surface *surface)
+{
+ struct test_recorded_resize_finished_event *event;
+
+ if (!recording_events)
+ {
+ test_log ("ignored resize finish event");
+ return;
+ }
+
+ event = malloc (sizeof *event);
+
+ if (!event)
+ report_test_failure ("failed to record event");
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
+#endif
+
+ event->header.kind = SURFACE_RESIZE_FINISHED_EVENT;
+ event->header.last = record_tail;
+ record_tail = &event->header;
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+}
+
static const struct test_surface_listener test_surface_listener =
{
handle_test_surface_mapped,
NULL,
handle_test_surface_committed,
+ handle_test_surface_resize_finished,
};
@@ -1475,6 +1618,7 @@ handle_pointer_button (void *data, struct wl_pointer *wl_pointer,
event->button = button;
event->state = state;
+ event->serial = serial;
#ifdef __GNUC__
#pragma GCC diagnostic pop
@@ -1634,6 +1778,7 @@ handle_keyboard_enter (void *data, struct wl_keyboard *keyboard,
memcpy (event->keys, keys->data, keys->size);
event->num_keys = keys->size / sizeof (uint32_t);
+ event->surface = surface;
#ifdef __GNUC__
#pragma GCC diagnostic pop