@@ -592,16 +592,9 @@ static void pointer_dispatch_absolute_motion(SDL_WaylandSeat *seat)
592
592
seat -> pointer .last_motion .x = (int )SDL_floorf (sx );
593
593
seat -> pointer .last_motion .y = (int )SDL_floorf (sy );
594
594
595
- /* Pointer confinement regions are created only when the pointer actually enters the region via
596
- * a motion event received from the compositor.
597
- */
598
- if (!SDL_RectEmpty (& window -> mouse_rect ) && !seat -> pointer .confined_pointer ) {
599
- SDL_Rect scaled_mouse_rect ;
600
- Wayland_GetScaledMouseRect (window , & scaled_mouse_rect );
601
-
602
- if (SDL_PointInRect (& seat -> pointer .last_motion , & scaled_mouse_rect )) {
603
- Wayland_SeatUpdatePointerGrab (seat );
604
- }
595
+ // If the pointer should be confined, but wasn't for some reason, keep trying until it is.
596
+ if (!SDL_RectEmpty (& window -> mouse_rect ) && !seat -> pointer .is_confined ) {
597
+ Wayland_SeatUpdatePointerGrab (seat );
605
598
}
606
599
607
600
if (window -> hit_test ) {
@@ -802,7 +795,7 @@ static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
802
795
803
796
static bool Wayland_ProcessHitTest (SDL_WaylandSeat * seat , Uint32 serial )
804
797
{
805
- // Locked in relative mode , do nothing.
798
+ // Pointer is immobilized , do nothing.
806
799
if (seat -> pointer .locked_pointer ) {
807
800
return false;
808
801
}
@@ -1259,29 +1252,33 @@ static const struct zwp_relative_pointer_v1_listener relative_pointer_listener =
1259
1252
relative_pointer_handle_relative_motion ,
1260
1253
};
1261
1254
1262
- static void locked_pointer_locked (void * data ,
1263
- struct zwp_locked_pointer_v1 * locked_pointer )
1255
+ static void locked_pointer_locked (void * data , struct zwp_locked_pointer_v1 * locked_pointer )
1264
1256
{
1257
+ SDL_WaylandSeat * seat = (SDL_WaylandSeat * )data ;
1258
+ seat -> pointer .is_confined = true;
1265
1259
}
1266
1260
1267
- static void locked_pointer_unlocked (void * data ,
1268
- struct zwp_locked_pointer_v1 * locked_pointer )
1261
+ static void locked_pointer_unlocked (void * data , struct zwp_locked_pointer_v1 * locked_pointer )
1269
1262
{
1263
+ SDL_WaylandSeat * seat = (SDL_WaylandSeat * )data ;
1264
+ seat -> pointer .is_confined = false;
1270
1265
}
1271
1266
1272
1267
static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
1273
1268
locked_pointer_locked ,
1274
1269
locked_pointer_unlocked ,
1275
1270
};
1276
1271
1277
- static void confined_pointer_confined (void * data ,
1278
- struct zwp_confined_pointer_v1 * confined_pointer )
1272
+ static void confined_pointer_confined (void * data , struct zwp_confined_pointer_v1 * confined_pointer )
1279
1273
{
1274
+ SDL_WaylandSeat * seat = (SDL_WaylandSeat * )data ;
1275
+ seat -> pointer .is_confined = true;
1280
1276
}
1281
1277
1282
- static void confined_pointer_unconfined (void * data ,
1283
- struct zwp_confined_pointer_v1 * confined_pointer )
1278
+ static void confined_pointer_unconfined (void * data , struct zwp_confined_pointer_v1 * confined_pointer )
1284
1279
{
1280
+ SDL_WaylandSeat * seat = (SDL_WaylandSeat * )data ;
1281
+ seat -> pointer .is_confined = false;
1285
1282
}
1286
1283
1287
1284
static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = {
@@ -3664,17 +3661,18 @@ void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat)
3664
3661
SDL_Rect scaled_mouse_rect ;
3665
3662
Wayland_GetScaledMouseRect (window , & scaled_mouse_rect );
3666
3663
3664
+ confine_rect = wl_compositor_create_region (display -> compositor );
3665
+ wl_region_add (confine_rect ,
3666
+ scaled_mouse_rect .x ,
3667
+ scaled_mouse_rect .y ,
3668
+ scaled_mouse_rect .w ,
3669
+ scaled_mouse_rect .h );
3670
+
3667
3671
/* Some compositors will only confine the pointer to an arbitrary region if the pointer
3668
- * is already within the confinement area when it is created.
3672
+ * is already within the confinement area when it is created. Warp the pointer to the
3673
+ * closest point within the confinement zone if outside.
3669
3674
*/
3670
- if (SDL_PointInRect (& seat -> pointer .last_motion , & scaled_mouse_rect )) {
3671
- confine_rect = wl_compositor_create_region (display -> compositor );
3672
- wl_region_add (confine_rect ,
3673
- scaled_mouse_rect .x ,
3674
- scaled_mouse_rect .y ,
3675
- scaled_mouse_rect .w ,
3676
- scaled_mouse_rect .h );
3677
- } else {
3675
+ if (!SDL_PointInRect (& seat -> pointer .last_motion , & scaled_mouse_rect )) {
3678
3676
/* Warp the pointer to the closest point within the confinement zone if outside,
3679
3677
* The confinement region will be created when a true position event is received.
3680
3678
*/
@@ -3698,16 +3696,32 @@ void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat)
3698
3696
}
3699
3697
3700
3698
if (confine_rect || (window -> flags & SDL_WINDOW_MOUSE_GRABBED )) {
3701
- seat -> pointer .confined_pointer =
3702
- zwp_pointer_constraints_v1_confine_pointer (display -> pointer_constraints ,
3703
- w -> surface ,
3704
- seat -> pointer .wl_pointer ,
3705
- confine_rect ,
3706
- ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT );
3707
- zwp_confined_pointer_v1_add_listener (seat -> pointer .confined_pointer ,
3708
- & confined_pointer_listener ,
3709
- window );
3710
-
3699
+ if (window -> mouse_rect .w != 1 && window -> mouse_rect .h != 1 ) {
3700
+ seat -> pointer .confined_pointer =
3701
+ zwp_pointer_constraints_v1_confine_pointer (display -> pointer_constraints ,
3702
+ w -> surface ,
3703
+ seat -> pointer .wl_pointer ,
3704
+ confine_rect ,
3705
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT );
3706
+ zwp_confined_pointer_v1_add_listener (seat -> pointer .confined_pointer ,
3707
+ & confined_pointer_listener ,
3708
+ seat );
3709
+ } else {
3710
+ /* Use a lock for 1x1 confinement regions, as the pointer can exhibit subpixel motion otherwise.
3711
+ * A null region is used since the warp *should* have placed the pointer where we want it, but
3712
+ * better to lock it slightly off than let the pointer escape, as confining to a specific region
3713
+ * seems to be a racy operation on some compositors.
3714
+ */
3715
+ seat -> pointer .locked_pointer =
3716
+ zwp_pointer_constraints_v1_lock_pointer (display -> pointer_constraints ,
3717
+ w -> surface ,
3718
+ seat -> pointer .wl_pointer ,
3719
+ NULL ,
3720
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT );
3721
+ zwp_locked_pointer_v1_add_listener (seat -> pointer .locked_pointer ,
3722
+ & locked_pointer_listener ,
3723
+ seat );
3724
+ }
3711
3725
if (confine_rect ) {
3712
3726
wl_region_destroy (confine_rect );
3713
3727
}
0 commit comments