compose-multiplatform
compose-multiplatform copied to clipboard
Maximizing undecorated windows seems to result in full-screen behavior
If a window is undecorated, setting the window placement to Maximized seems to make the window cover the entire screen including the taskbar. I don't know if I'm doing anything wrong to result in this behavior, but this occurred in a small test project I was working on and again in a new project I made to test the problem after I noticed it.
The following program should demonstrate the problem:
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.ui.window.WindowPlacement
import androidx.compose.ui.window.singleWindowApplication
fun main() = singleWindowApplication(
undecorated = true
) {
Button(
onClick = {
window.placement = WindowPlacement.Maximized
}
) {
Text("Maximize")
}
}
Please let me know if there is a work-around, or if I'm approaching this the wrong way.
is a work-around,
Workaround is to use window.setLocation and window.setSize. The size can be calculated via window.graphicsConfiguration.bounds and Toolkit.getDefaultToolkit().getScreenInsets(window.graphicsConfiguration) see example
As for the issue, it seems either Swing or the system window manager maximizes this way. Intuitively this looks wrong. We probably can use the same workaround inside Compose, not sure yet. Or maybe we should set some parameter directly for the native window.
I can confirm that this workaround does indeed work. I was able to use the following code to get the window to fit the proper area without issue:
val mode = remember { mutableStateOf(window.placement) }
val size = remember { mutableStateOf(window.size) }
val pos = remember { mutableStateOf(window.position) }
// Lower down in a button
onClick = {
mode.value = if (mode.value == WindowPlacement.Floating) {
size.value = window.size
pos.value = window.position
val insets = Toolkit.getDefaultToolkit().getScreenInsets(graphicsConfiguration)
val bounds = graphicsConfiguration.bounds
setSize(bounds.width, bounds.height - insets.bottom)
setLocation(0, 0)
WindowPlacement.Maximized
} else {
window.size = size.value
window.position = pos.value
WindowPlacement.Floating
}
}
This is a fairly messy solution but it does otherwise seem to work as expected. I'll probably continue experimenting with it to see if I can improve it at all.
This also seems to remove the possibility to open the Taskbar, if set to autohiding, just with mouse. It forces to use the super key to acces the Taskbar. This makes the maximize option pretty much useless. I hope this gets fixed soon.
Also when used with WindowDragabbleArea to simulate windows toolbar and un-maximizing window by dragging, if you reset window size with window.setSize, then window.setLocation does nothing and you end up holding "nothing" under the mouse (if you drag the right part of the window, floating window will be at the left of the screen instead). Maybe its get updated every onDrag event with positions of the original maximized window, but it should be adjusted with proportions formula probably.
If you use WindowPlacement setter instead, the size of the window is also not reverting back to old size
UPD: solved my problem with that code:
WindowDraggableArea(
modifier = Modifier.pointerInput(Unit) {
awaitEachGesture {
awaitFirstDown(pass = PointerEventPass.Initial)
if (mode == WindowPlacement.Maximized) {
mode = WindowPlacement.Floating
val x = when {
window.mousePosition.x < oldSize.width / 2 -> 0
window.mousePosition.x > windowState.size.width - oldSize.width / 2 -> windowState.size.width - oldSize.width
else -> window.mousePosition.x - oldSize.width / 2
}
windowState.size = oldSize
window.setLocation(x.toInt(), 0)
}
}
}
)
And i also think that the general support of windows docking feature should be addressed instead. Got used to that feature that much, that forgot, how deep is the rabbit hole.
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.