Skip to content

Conversation

@Cmdv
Copy link

@Cmdv Cmdv commented Oct 5, 2025

Add screen-absolute mouse position to CursorMoved event

Problem:
When implementing custom window resize handles, window-relative mouse coordinates become unreliable as the window dimensions change. The position jumps around because it's relative to a moving target.

This is particularly problematic for audio plugins (using nih-plug + baseview) where you can't access native window resize controls and have to implement resize handles yourself.

Solution:
Add screen_position: Point to mouse::Event::CursorMoved alongside the existing window-relative position.

  CursorMoved {
      position: Point,           // window-relative
      screen_position: Point,    // screen-absolute
  }

The screen position stays constant during resize operations, making drag calculations straightforward.

Implementation:

  • Winit backend: calculates as window.outer_position() + cursor_position
  • Falls back to window-relative position if window position unavailable (Wayland limitations)
  • Updated conversion::window_event() to accept pre-extracted window_position parameter (consistent with existing scale_factor pattern)

Breaking Changes:

  • CursorMoved has new field - existing pattern matches need ..
  • conversion::window_event() signature changed

It closes #2773 (only issue I could find related to it)

Working Result:
2025-10-05 00 09 13

@edwloef
Copy link
Contributor

edwloef commented Oct 6, 2025

Could you make the screen position field optional? As-is right now I'm fairly sure this'll result in no mouse movement events being emitted on Wayland anymore, since outer_position is unsupported there.

@Cmdv
Copy link
Author

Cmdv commented Oct 6, 2025

Optional might be valid, here's my actual user case

Baseview → Conversion → Iced → Widget

Baseview provides MouseEvent::CursorMoved with both position (window coords) and screen_position (screen coords) natively from the OS

Conversion layer does simple type conversion: f64 → f32, creating iced::Event::Mouse(CursorMoved { position, screen_position })

Iced runtime dispatches the event to all widgets. Standard widgets use { position, .. } ignoring screen_position. My custom widget extracts both.

Widget ResizeHandle widget uses screen_position for delta calculations because window coordinates shift during resize, but screen coordinates stay stable.

Why I modified iced: Core iced didn't have screen_position in CursorMoved events. I added it so backends(winit/baseview) can provide screen-absolute coordinates alongside window-relative coordinates. This enables custom widgets to perform stable calculations during window geometry changes.

Baseview vs Winit: Baseview provides both coordinates natively (simple passthrough). Winit must calculate screen_position = window.outer_position() + position.

@edwloef
Copy link
Contributor

edwloef commented Oct 6, 2025

Yeah, I just misread the code at first. It might be better to have users explicitly handle the case where screenspace coordinates aren't available or might be incorrect, but this way works too. In the end that's a design decision hecrj will have to make though.

@Cmdv
Copy link
Author

Cmdv commented Oct 6, 2025

I was also trying to think of a way to make it an opt-in so it wouldn't be a breaking change but couldn't see a logical way of doing that unfortunately. It's a really useful feature for us audio plugin devs, but might be out of scope and too niche to have it in iced 🤷

edit: I'm happy to have a scenario where users explicitly handle the case you mentioned, it was more I had this code that made my resizing work perfectly, so though why not share it upstream just incase 😄

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.

get absolute mouse position in screen space

2 participants