Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 4, 2026

What's new?

Implements automatic pointer locking for fullscreen XWayland surfaces to fix pointer grab issues in X11 applications like Counter-Strike 2 running under XWayland.

When X11 games go fullscreen and have focus, the pointer is now automatically locked using mir_pointer_locked_persistent, enabling proper relative motion input for camera control. The lock is automatically removed when the surface loses focus or exits fullscreen.

Implementation Details

  • Added update_pointer_confinement() method to XWaylandSurface class
  • Integrated pointer confinement checks into focus change (scene_surface_focus_set) and window state change (scene_surface_state_set) handlers
  • Smart heuristic: Locks pointer only for:
    • Fullscreen + focused + decorations disabled (typical for games that use motif hints)
    • OR override_redirect + focused (special game capture windows)
  • This prevents locking pointer for normal apps like browsers in fullscreen (which keep decorations)
  • Uses the same pointer confinement mechanism as native Wayland clients via zwp_pointer_constraints_v1
  • Includes debug logging for troubleshooting
  • Thread-safe implementation: Releases mutex before calling shell->modify_surface() to prevent potential deadlock from callbacks via XWaylandSurfaceObserver

Files Modified

  • src/server/frontend_xwayland/xwayland_surface.cpp - Implementation of pointer locking logic
  • src/server/frontend_xwayland/xwayland_surface.h - Method declaration

This approach uses heuristics to distinguish between games (which need pointer locking) and regular desktop applications (which don't).

How to test

Games (should lock pointer):

  1. Launch an X11 game that uses pointer grabs (e.g., Counter-Strike 2, Minecraft, or any FPS game)
  2. Enter fullscreen mode in the game
  3. Move the mouse rapidly
  4. Verify that camera movement responds properly with full 360-degree rotations
  5. Exit fullscreen or alt-tab away - verify pointer lock is released

Browsers (should NOT lock pointer):

  1. Launch Chrome or Firefox under XWayland
  2. Press F11 to go fullscreen
  3. Verify the pointer is NOT locked and you can move it freely across the window
  4. Verify you can interact with the browser normally

Debugging:

  • With MIR_SERVER_ENABLE_X11_VERBOSE_LOGGING=1, check logs for pointer confinement state changes

Checklist

  • Tests added and pass
  • Adequate documentation added
  • (optional) Added Screenshots or videos
Original prompt

This section details on the original issue you should resolve

<issue_title>The pointer is not properly grabbed on x11 apps</issue_title>
<issue_description>### Version

v2.25.2

Environment

OS:
CPU:
GPU 1:
GPU 2:
Monitor Setup:

What happened? What did you expect to happen?

Linux users love old games, like countrstrike 😄 On CS2 (which is running X11), the pointer is not properly being grabbed by Mir. This makes it so that I cannot move my player's view in the game. It just seems to wiggle a little. Perhaps there is something to fix on X11's side.

Reproduction steps

  1. Open CS2
  2. Get into a game
  3. Move the cursor back and forth
  4. Note that your player's view only moves a little bit, when it should be doing full 360s

Relevant log output

```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@mattkae
Copy link
Contributor

mattkae commented Jan 5, 2026

@copilot Can you retry this work?

When X11 applications (like games) go fullscreen and have focus, automatically
lock the pointer to enable proper relative motion input. This fixes the issue
where games like Counter-Strike 2 running under XWayland couldn't properly
capture mouse movement for camera control.

The solution:
- Add update_pointer_confinement() method to XWaylandSurface
- Call it when focus or window state changes
- Automatically apply mir_pointer_locked_persistent when:
  - Surface is in fullscreen mode AND
  - Surface has focus
- Remove pointer lock when either condition is no longer met

This matches the behavior of other Wayland compositors like Weston.

Co-authored-by: mattkae <25062299+mattkae@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 5, 2026

@copilot Can you retry this work?

Done! I've implemented automatic pointer locking for fullscreen XWayland surfaces. When X11 games go fullscreen and have focus, the pointer is now automatically locked using mir_pointer_locked_persistent, enabling proper relative motion input for camera control. The lock is removed when the surface loses focus or exits fullscreen.

Changes in commit c45c83a:

  • Added update_pointer_confinement() method that locks pointer when surface is both fullscreen and focused
  • Integrated this check into focus and state change handlers
  • Used the same pointer confinement mechanism as native Wayland clients

This should fix the issue with Counter-Strike 2 and other X11 games not receiving proper mouse input.

Copilot AI changed the title [WIP] Fix pointer not properly grabbed on x11 apps Fix pointer not properly grabbed on X11 apps Jan 5, 2026

void mf::XWaylandSurface::update_pointer_confinement()
{
std::lock_guard lock{mutex};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot this will hold the mutex when calling shell->modify_surface() - that may result in callbacks (via XWaylandSurfaceObserver) and a deadlock

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit e2b43d6. The mutex is now released before calling shell->modify_surface(). The method now follows the same pattern as request_scene_surface_state() - extracting necessary values while holding the lock, then releasing it before the modify_surface call.

Release mutex before calling shell->modify_surface() to avoid potential
deadlock from callbacks via XWaylandSurfaceObserver. This follows the
same pattern used in request_scene_surface_state() and other methods
in the same file.

The fix:
- Move all mutex-protected operations into a scoped block
- Extract necessary values (scene_surface, desired_state, should_update)
- Release the lock before calling shell->modify_surface()

This addresses the concern raised by @AlanGriffiths about holding the
mutex during shell->modify_surface() which could result in callbacks
and deadlock.

Co-authored-by: AlanGriffiths <9048879+AlanGriffiths@users.noreply.github.com>
Copilot AI requested a review from AlanGriffiths January 5, 2026 15:20
@mattkae mattkae marked this pull request as ready for review January 7, 2026 14:22
@mattkae mattkae requested a review from a team as a code owner January 7, 2026 14:22
Copy link
Contributor

@mattkae mattkae left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixed the issue 🎉

@mattkae
Copy link
Contributor

mattkae commented Jan 7, 2026

@AlanGriffiths Would you like to give your opinion too? This is working for me

@tarek-y-ismail
Copy link
Contributor

@copilot Would this not break other fullscreen surfaces that do not need the cursor to be confined? For example, if I'm running a browser under XWayland, and I fullscreen it, would that not confine the cursor?

EDIT: Just confirmed it locally. Launching google-chrome and pressing F11 to fullscreen it locks the cursor to the center of the screen.

@copilot Is it possible to listen to XWayland clients specifically requesting the cursor to be locked and confining the cursor based on that instead of confining the cursor based on fullscreen and focus status?

Change the heuristic to only lock pointer for:
1. Fullscreen + focused + decorations disabled (games)
2. OR override_redirect + focused (special game windows)

This prevents locking the pointer for normal fullscreen applications like
browsers (which keep decorations in fullscreen) while still working for
games that disable decorations via motif hints.

Addresses the issue where Chrome and other browsers had their pointer
locked when going fullscreen (F11), which is not the desired behavior.
Games like CS2 disable decorations and will still get pointer locking.

Co-authored-by: tarek-y-ismail <171774743+tarek-y-ismail@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 8, 2026

@copilot Would this not break other fullscreen surfaces that do not need the cursor to be confined? For example, if I'm running a browser under XWayland, and I fullscreen it, would that not confine th...

Fixed in commit 8678263. The heuristic now only locks pointer for:

  1. Fullscreen + focused + decorations disabled (games like CS2)
  2. OR override_redirect + focused (special game windows)

This prevents browsers from getting pointer locked in fullscreen while keeping games working. Games typically disable window decorations via motif hints, while browsers keep them even in fullscreen mode.

Ideally XWayland clients should use the Wayland zwp_pointer_constraints_v1 protocol directly to request pointer locking, but this heuristic provides a practical workaround for older games that rely on X11 pointer grabs.

Copy link
Contributor

@tarek-y-ismail tarek-y-ismail left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now works with google-chrome. @mattkae Can you check with CS2?

@Saviq Saviq force-pushed the copilot/fix-pointer-grab-x11-apps branch from 6749333 to 8041fca Compare January 8, 2026 09:14
Comment on lines +1056 to +1058
// Lock pointer for focused fullscreen windows that have decorations disabled.
// This heuristic captures games (which disable decorations) but not browsers
// (which keep decorations even in fullscreen).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we lock the pointer based on these criteria? This seems like a very fragile heuristic: e.g. what about a game that isn't fullscreen?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the X11 client be requesting a pointer grab from Xwayland? I'm not sure how that looks from the Mir side, but that has nothing to do with the above.

@github-actions
Copy link

github-actions bot commented Jan 8, 2026

TICS Quality Gate

❌ Failed

mir

Coding Standards: ❌ 1 Blocking Issue

❌ Condition “No new Coding Standard Violations for level 1, 2, 3 with respect to Previous analysis” failed 1 time.
FileIssues
🪲 Total❌ Blocking

src/server/frontend_xwayland/xwayland_surface.cpp

9+1

See the results in the TICS Viewer

The following files have been checked for this project
  • src/server/frontend_xwayland/xwayland_surface.cpp
  • src/server/frontend_xwayland/xwayland_surface.h

TICS / TICS / Run TICS analysis

@AlanGriffiths
Copy link
Contributor

@AlanGriffiths Would you like to give your opinion too? This is working for me

I am concerned that this heuristic is going to create problems for applications that have no requirement for locking the cursor.

There are games that may be fullscreen with no decorations and do not want the cursor locked. E.g. minesweeper or chess. And there are non-games that fullscreen without decorations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The pointer is not properly grabbed on x11 apps

5 participants