JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.86k stars 1.15k forks source link

Transparent window doesn't ignore mouse events since it's still opaque #1401

Open nomis51 opened 2 years ago

nomis51 commented 2 years ago

What the problem ? With an overlay app, we want parts that are opaque (not affected by transparency), while having a window that is fully transparent, so you can have let's say a button floating on screen without any "visible" window around.

But, it seems like, the transparent=true property of Window (with undecorated=true, of course), basically makes the background transparent, but the window itself stays opaque (I've been looking at the ComposeWindow JFrame at the root of the app and isOpaque=true). That causes any mouse events to be "blocked" by the invisible window, which makes the overlay usable, since you can't interact with what's behind.

What have you tried so far ? Basically all the "solutions" I knew (Not really familiar with Swing to be honest, but knowledge from JavaFX and WPF) and a lot coming from StackOverflow, and none of them were 100% successfull.

They all ended up with one of the following ending :

Any workarounds ? Well, the only thing that kind of work, but that's horrible honestly, is to register to pointerInput on the root Composable of the app to find the ComposeWindow JFrame behind the app and set its background to RGBA(0,0,0,0) which allows mouse events (because the window doesn't exists anymore), re-send the same mouse event (so it simulate the pass through), then reset the background of the ComposeWindow... For situations where only mouse clicks matters, that's kind of usuable, cause the background switching is quick enough, but if I want to have mouse move events to pass through, it's flickering insanely.... as expected.

What do you need ? Basically, if you create an empty WPF app (C#), and set the attributes

and add a button in the middle of the window, you end up with a floating button on your screen and the mouse events are not blocked by the invisible window. The only time it does grab the events, is when you hover/interact with a opaque control (e.g. the button is this case)

So, I would be nice to be able to create transparent windows, that react exactly like if they were opacity=0f, but still allow opaque controls in it. I know it's doable in Swing, but since with Compose, we don't create the actual Window behind ourselve, I can't really workaround that myself so far..

Also, I know this is the kind of thing that is platform dependant, like, for example on Linux the WPF app won't react like described (e.g. it's going to block mouse events), but on Windows it does. I'm only targeting Windows myself.

Kotlin 1.5.31 Compose for Desktop 1.0.0-beta5 - 1.0.0-beta6-dev474 JDK 11 Windows 10

nomis51 commented 2 years ago

Just a follow up with some of my experimentations :

Here is an example where I initialized the ComposeWindow myself, and notice isOpaque=false, and it does react properly to mouse events, because the content (in this case, a JButton) was added after the background and opaque changes :

image

The background of the Window is transparent as expected

image

Here is an example where I initialized the window using the Window(...) { } composable, and notice isOpaque=true even with transparent=true

image

If I change the background of the ComposeWindow on a mouse event (after initialisation) or in the key(true) { ... } scope of the Window(...) { }, isOpaque=false, as expected. but it spreads to child components by making their opacity = 0, so no more window on screen..

image

And, trying to set the isOpaque property to false on any panel or sub-panel of the ComposeWindow after initialisation does basically nothing, because the Window itself is opaque since it's not transparent it seems.

image

So maybe the solution here, is to either make the contentPane to isOpaque=false of the Window (which is the ComposeWindowDelegate.pane panel located in the ComposeWindow) on the initialisation or add another param in the Window like isOpaque: Boolean so the developer can decide, like in Java

okushnikov commented 1 week ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.