Compose Multiplatform Desktop UI
Window Management APIs
Creating and Managing Windows
In Compose for Desktop, every application lives inside a window. The simplest way to get started is with singleWindowApplication. It's a convenient wrapper that creates a single, main window for your entire app. This is great for simple utilities or when you're just starting a project.
However, for more complex applications, you'll need direct control. This is where the Window composable comes in. Instead of singleWindowApplication, you can use a standard application scope and create Window composables within it. This approach allows you to manage multiple windows, each with its own state and content.
```kotlin
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
fun main() = application {
Window(onCloseRequest = ::exitApplication) {
// Your app's UI content goes here
}
}
Notice the onCloseRequest parameter. This lambda is your hook into the window's lifecycle. It's invoked when the user tries to close the window, like by clicking the 'X' button. Simply calling exitApplication is the default behavior, but you can insert custom logic here. For example, you could show a 'Save changes?' dialog or minimize the app to the system tray instead of closing it.
Controlling Window State
A window isn't just a container; it has properties like size, position, and title. You manage these using WindowState. By creating an instance of WindowState, you can programmatically control and observe the window's dimensions and location on the screen.
For example, you can set an initial size using DpSize. If you want the window to automatically size itself based on its content, you can use Dp.Unspecified for the width or height. This is particularly useful for dialogs or tool windows that should be just large enough to fit their controls.
```kotlin
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowState
import androidx.compose.ui.window.application
fun main() = application {
val state = WindowState(size = DpSize(400.dp, 600.dp))
Window(
onCloseRequest = ::exitApplication,
state = state,
title = "My Awesome App"
) {
// Window content
}
}
The WindowState also tracks the window's position. You can set an initial position with WindowPosition. This is helpful for ensuring your app opens in a predictable spot, such as centered on the screen. The state object persists across recompositions, so any changes the user makes (like resizing or moving the window) are automatically remembered.
For temporary, short-lived windows, like a settings panel or a confirmation prompt, there's DialogWindow. It behaves much like a regular Window but is modal by default, meaning it blocks interaction with its parent window until it's closed. It's a specialized tool for creating dialogs that are still top-level OS windows, unlike the in-app Dialog composable.
Advanced Window Behaviors
Compose Multiplatform offers several powerful options for customizing window behavior. You can create a window with a transparent background by setting transparent = true. This is perfect for creating custom-shaped windows, overlays, or desktop widgets. When you combine transparency with undecorated = true, you get a completely borderless, title-bar-free window—a blank canvas for your UI.
An window gives you full creative control but also means you're responsible for implementing your own close, minimize, and maximize buttons if you need them. It's a trade-off between custom aesthetics and standard platform conventions.
```kotlin
Window(
onCloseRequest = ::exitApplication,
undecorated = true, // No title bar or border
transparent = true, // The window background is clear
alwaysOnTop = true // Stays on top of other windows
) {
// UI for a widget or overlay
}
The alwaysOnTop property is another useful flag. When set to true, it forces the window to stay visible above all other application windows. This is ideal for things like video call pop-ups, progress indicators, or monitoring tools that need to remain in the user's view.
For managing the window's icon, you can pass a painter to the icon parameter. A common practice is to load your application's icon from the resources directory using painterResource.
Now, let's test your understanding of these window management concepts.
When building a simple utility app in Compose for Desktop that only requires one main window, what is the most convenient starting point?
What is the primary purpose of the onCloseRequest parameter in a Window composable?
Properly managing windows is fundamental to creating a professional and user-friendly desktop application. By mastering these APIs, you can build everything from simple, single-window tools to complex, multi-window productivity software.
