Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mouse event pass-through support for window. #39944

Merged
merged 1 commit into from
Sep 17, 2020

Conversation

bruvzg
Copy link
Member

@bruvzg bruvzg commented Jun 29, 2020

Adds DisplayServer.window_set_mouse_passthrough function to set polygonal region of the window which accepts mouse events, mouse events outside the region will be passed through to the window behind it.

Region can be drawn using Path2D (or similar) node and set by calling:

DisplayServer.window_set_mouse_passthru($Path2D.curve.get_baked_points())

The same changes for 3.2 are available in click-through-3 branch.

  • macOS (implemented and tested on macOS 10.15.5)
  • Windows (implemented and tested on Windows 10)
  • Linux/X11 (implemented and tested on lubuntu 20.04)

Fixes #39914

@Technohacker
Copy link

If there's a sample project available, I can have a test for this on Linux :)

@bruvzg
Copy link
Member Author

bruvzg commented Jun 29, 2020

Test project (white polygon should be solid, rest of the window click-through): Transo4.zip

@Technohacker
Copy link

Technohacker commented Jun 30, 2020

Testing on Gentoo with KDE Plasma X11, opening the project as-is doesn't seem to be working. Click events don't pass through the window. I might need to check again with the 3.2 branch so I can use the per-pixel alpha to see it clearly

EDIT: Tried it with the 3.2.3 branch from your repository too, same result

EDIT 2: xeyes does work, and it uses the same SHAPE extension too

@Technohacker
Copy link

Nevermind, fixed it @bruvzg, you accidentally checked if the extension was not enabled 😂

@Technohacker
Copy link

I had @Ashesh3 test it on Windows and it didn't seem to work. I was looking through the MSDN Win32 docs about HTTRANSPARENT and this might be the reason why:

HTTRANSPARENT -1 | In a window currently covered by another window in the same thread (the message will be sent to underlying windows in the same thread until one of them returns a code that is not HTTRANSPARENT).

I didn't see any docs about whether the thread mentioned is the process thread, but I can have another look

@Technohacker
Copy link

@bruvzg More documentation diving and I see two possible methods:

  1. Use SetRegion to set which area of the window is to be drawn, hence the non-drawn regions will ignore input. The problem with that would be you can't have semi-transparent areas that don't accept input
  2. Do our own hit testing and use PostMessage and GetWindow to send the hit test message to the next window below ours if it's outside the polygon. This would allow the semi-transparent overlay with mouse clicks but would need custom code on our side

I could try to implement the second one, since it doesn't force a fully transparent region

@bruvzg
Copy link
Member Author

bruvzg commented Jun 30, 2020

I had @Ashesh3 test it on Windows and it didn't seem to work. I was looking through the MSDN Win32 docs about HTTRANSPARENT and this might be the reason why

I have tested it on Window 10 too, and it doesn't work.

Do our own hit testing and use PostMessage and GetWindow to send the hit test message to the next window below ours if it's outside the polygon. This would allow the semi-transparent overlay with mouse clicks but would need custom code on our side

Posting just hit test message doesn't work either, maybe forwarding all mouse events and activation messages do (with coordinate conversion, since mouse use client coodrs). Probably this will end up to be extremely complicated and bug prone.

For now, I have changed it to SetWindowRgn with the note about inconsistent behavior in the docs, it should be good enough for most use cases.

@Technohacker
Copy link

Yeah I ended up on the same conclusion as well, considering WS_EX_LAYERED worked the same way :)

@bruvzg bruvzg changed the title [WIP] Add mouse event pass-through support for window. Add mouse event pass-through support for window. Jul 8, 2020
@akien-mga
Copy link
Member

@Technohacker This is now updated if you want to test again on Windows (there's also a 3.2 PR: #40205).

@Technohacker
Copy link

Terribly sorry for the delay, had other projects to deal with 😅

Linux X11 KDE Plasma: Working perfectly :)
Windows: Pending

@kiesenverseist
Copy link

The feature is one I'm looking forward to, so I thought I'd go ahead and test it on windows. This is my first time compiling godot, so apologies in advance if I did anything incorrectly, but it does work on windows with the given test project.

@akien-mga
Copy link
Member

CC @pouleyKetchoupp to review X11 changes.

Copy link
Contributor

@pouleyKetchoupp pouleyKetchoupp left a comment

Choose a reason for hiding this comment

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

Great work!
The X11 code looks fine (apart from the little detail I've pointed out).

I've tested on Ubuntu 20.04:
Gnome - works only with borderless windows.
Plasma - works as intended.

Is the issue with Gnome a deal breaker? I'm not sure what real life use cases are for this feature. If needed, I can help investigate.

platform/linuxbsd/display_server_x11.cpp Outdated Show resolved Hide resolved
<description>
Sets a polygonal region of the window which accepts mouse events. Mouse events outside the region will be passed through.
Passing an empty array will disable passthrough support (all mouse events will be intercepted by the window, which is the default behavior).

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change

Copy link
Member

Choose a reason for hiding this comment

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

Line == paragraph in the XML.

# Reset region to default.
DisplayServer.window_set_mouse_passthrough([])
[/codeblock]

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change

@pouleyKetchoupp
Copy link
Contributor

Summoning ancient horror.

Wow.

If it's mostly used for widgets, I guess it's not a big deal for now if it doesn't play well with window decorations in some cases.

@akien-mga akien-mga merged commit 377c3bb into godotengine:master Sep 17, 2020
@akien-mga
Copy link
Member

Thanks!

@bruvzg bruvzg deleted the click-through-4 branch September 17, 2020 10:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Per Pixel Transparency misbehaving/broken in 3.2.2-stable on Windows
5 participants