DEV Community

Cover image for Musings about window decorations
Thomas Künneth
Thomas Künneth

Posted on

Musings about window decorations

If you have read my previous article Automatically switch to Dark Mode (and back) in Compose for Desktop 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

JFrame.setDefaultLookAndFeelDecorated(true)
Enter fullscreen mode Exit fullscreen mode

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

AppWindow(
    undecorated = true,
Enter fullscreen mode Exit fullscreen mode

And here is the code to change some color. It's part of my TKDupeFinder app.

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)
Enter fullscreen mode Exit fullscreen mode

The app then looks like this:

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:

println(UIManager.getLookAndFeel().supportsWindowDecorations)
Enter fullscreen mode Exit fullscreen mode

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

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

miscSystemInit()

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.

Top comments (0)