Musings about window decorations
Tags: java, kotlin, ux
Published: 2021-01-02 12:14:11

If you have read my previous article [Automatically switch to Dark Mode (and back) in Compose for Desktop](https://dev.to/tkuenneth/automatically-switch-to-dark-mode-and-back-in-compose-for-desktop-303l) you know I am on a mission to bring Dark Mode to Compose for Desktop apps. What has been missing in the previous episode is

- the color of the window borders
- the menu bar

In this installment I will be focussing on windows.

To get an idea how we could change the colors of window decorations we need to remember that to some extent Compose for Desktop relies on Swing components. Swing is based on the concept of pluggable look and feels. The look and feel is responsible for how a Swing component looks and works. Whereas AWT relied on native ui components, Swing does all the painting. Generally speaking this is done by classes ending in `UI`. What is important that window decorations can be provided by the system, but look and feels may paint them by itself. 

Client code can request this (as early as possible, ideally in `main()`) with

```kotlin
JFrame.setDefaultLookAndFeelDecorated(true)
```

Also, we need to create the Compose window like this:

```kotlin
AppWindow(
    undecorated = true,
```

And here is the code to change some color. It's part of my [TKDupeFinder app](https://github.com/tkuenneth/TKDupeFinder).

```kotlin
val window = AppManager.windows.first().window
getDefaults()["activeCaption"] =
    ColorUIResource(colors.background.toArgb())
getDefaults()["activeCaptionText"] =
    ColorUIResource(colors.primary.toArgb())
window.rootPane.windowDecorationStyle = JRootPane.FRAME
UIManager.setLookAndFeel(
           UIManager.getCrossPlatformLookAndFeelClassName())
SwingUtilities.updateComponentTreeUI(window.rootPane)
```

The app then looks like this:

{% youtube hxQRhU2D74M %}

You are probably asking yourself why I am deliberately using `getCrossPlatformLookAndFeelClassName()` instead of `getSystemLookAndFeelClassName`.

The latter one doesn't work. Windows and macOS Look and Feels do not support custom window decorations. You can check this like this:

```kotlin
println(UIManager.getLookAndFeel().supportsWindowDecorations)
```

So, if we want the color of our window decorations to change, we must either use the cross platform look and feel or another look and feel which supports window decorations. I might take a look at some in a future post. Before I close this article I will answer another question you probably have: why does he set the look and feel in the composable? Wouldn't it be better to set it as early as possible?

Currently Compose for Desktop deliberately sets the system look and feel upon its initialization, for example (but probably in other places as well) in `androidx.compose.ui.window.MenuBar`:

![androidx.compose.ui.window.MenuBar](https://dev-to-uploads.s3.amazonaws.com/i/l3vdkhy6qi9v6dtj7t6l.png)

`Library.load()` invokes `miscSystemInit()` which looks like this:

![miscSystemInit()](https://dev-to-uploads.s3.amazonaws.com/i/uu2say16kel4p5aprwjt.png)

What does this mean, then? Ideally, Compose for Desktop would provide a means for specifying which look and feel should be used for the parts of an app that do not rely on composables. Alternatively it would bring its own look and feel which picks up the Material Design style. This way Compose for Desktop apps would look even more beautiful.