Skip to content

Commit

Permalink
Apply hack for window transparency to WINDOW layer too (#1185)
Browse files Browse the repository at this point in the history
## Proposed Changes

- Apply hack for window transparency that we already had for main window
to `WINDOW` layer too

## Testing

Test: Try mouse input at `WINDOW` layers on Windows

## Issues Fixed

Fixes
#1181 (comment)
  • Loading branch information
MatkovIvan committed Mar 12, 2024
1 parent d6cd2d0 commit ab9df91
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,40 +89,11 @@ internal class ComposeWindowPanel(
}
field = value
composeContainer.onChangeWindowTransparency(value)

/*
* Windows makes clicks on transparent pixels fall through, but it doesn't work
* with GPU accelerated rendering since this check requires having access to pixels from CPU.
*
* JVM doesn't allow override this behaviour with low-level windows methods, so hack this in this way.
* Based on tests, it doesn't affect resulting pixel color.
*
* Note: Do not set isOpaque = false for this container
*/
if (value && hostOs == OS.Windows) {
background = Color(0, 0, 0, 1)
isOpaque = true
} else {
background = null
isOpaque = false
}

window.background = if (value && !skikoTransparentWindowHack) Color(0, 0, 0, 0) else null
setTransparent(value)
window.background = getTransparentWindowBackground(value, renderApi)
}
}

/**
* There is a hack inside skiko OpenGL and Software redrawers for Windows that makes current
* window transparent without setting `background` to JDK's window. It's done by getting native
* component parent and calling `DwmEnableBlurBehindWindow`.
*
* FIXME: Make OpenGL work inside transparent window (background == Color(0, 0, 0, 0)) without this hack.
*
* See `enableTransparentWindow` (skiko/src/awtMain/cpp/windows/window_util.cc)
*/
private val skikoTransparentWindowHack: Boolean
get() = hostOs == OS.Windows && renderApi != GraphicsApi.DIRECT3D

init {
layout = null
focusTraversalPolicy = object : FocusTraversalPolicy() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ package androidx.compose.ui.awt

import androidx.compose.ui.graphics.Color
import java.awt.Component
import java.awt.Transparency
import javax.swing.JComponent
import org.jetbrains.skiko.ClipRectangle
import org.jetbrains.skiko.GraphicsApi
import org.jetbrains.skiko.OS
import org.jetbrains.skiko.hostOs

internal fun Component.isParentOf(component: Component?): Boolean {
var parent = component?.parent
Expand All @@ -31,3 +37,39 @@ internal fun Component.isParentOf(component: Component?): Boolean {
}

internal fun Color.toAwtColor() = java.awt.Color(red, green, blue, alpha)

internal fun getTransparentWindowBackground(
isWindowTransparent: Boolean,
renderApi: GraphicsApi
): java.awt.Color? {
/**
* There is a hack inside skiko OpenGL and Software redrawers for Windows that makes current
* window transparent without setting `background` to JDK's window. It's done by getting native
* component parent and calling `DwmEnableBlurBehindWindow`.
*
* FIXME: Make OpenGL work inside transparent window (background == Color(0, 0, 0, 0)) without this hack.
*
* See `enableTransparentWindow` (skiko/src/awtMain/cpp/windows/window_util.cc)
*/
val skikoTransparentWindowHack = hostOs == OS.Windows && renderApi != GraphicsApi.DIRECT3D
return if (isWindowTransparent && !skikoTransparentWindowHack) java.awt.Color(0, 0, 0, 0) else null
}

internal fun JComponent.setTransparent(transparent: Boolean) {
/*
* Windows makes clicks on transparent pixels fall through, but it doesn't work
* with GPU accelerated rendering since this check requires having access to pixels from CPU.
*
* JVM doesn't allow override this behaviour with low-level windows methods, so hack this in this way.
* Based on tests, it doesn't affect resulting pixel color.
*
* Note: Do not set isOpaque = false for this container
*/
if (transparent && hostOs == OS.Windows) {
background = java.awt.Color(0, 0, 0, 1)
isOpaque = true
} else {
background = null
isOpaque = false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package androidx.compose.ui.scene
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.CompositionLocalContext
import androidx.compose.ui.awt.getTransparentWindowBackground
import androidx.compose.ui.awt.setTransparent
import androidx.compose.ui.awt.toAwtColor
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.toRect
Expand Down Expand Up @@ -70,7 +72,10 @@ internal class WindowComposeSceneLayer(
).also {
it.isAlwaysOnTop = true
it.isUndecorated = true
it.background = Color.Transparent.toAwtColor()
it.background = getTransparentWindowBackground(
isWindowTransparent = true,
renderApi = composeContainer.renderApi
)
}
private val container = object : JLayeredPane() {
override fun addNotify() {
Expand All @@ -79,7 +84,7 @@ internal class WindowComposeSceneLayer(
}
}.also {
it.layout = null
it.isOpaque = false
it.setTransparent(true)

dialog.contentPane = it
}
Expand Down

0 comments on commit ab9df91

Please sign in to comment.