Skip to content

Production-ready template for custom window decorations in Compose Desktop. Features draggable title bars, native minimize/maximize/close behaviors, and full Material 3 theming support.

License

Notifications You must be signed in to change notification settings

numq/compose-desktop-window-decoration

Repository files navigation

Kotlin Compose

Compose desktop window decoration

🌟 Support this project
Bitcoin (BTC) bc1qs6qq0fkqqhp4whwq8u8zc5egprakvqxewr5pmx
Ethereum (ETH) 0x3147bEE3179Df0f6a0852044BFe3C59086072e12
USDT (TRC-20) TKznmR65yhPt5qmYCML4tNSWFeeUkgYSEV

preview

A template for creating custom window decorations in Jetpack Compose Desktop applications. Provides complete control over window chrome while maintaining native functionality.

Key Features

  • 🖼️ Complete Window Customization

    • Fully customizable title bar with draggable area
    • Double-click to maximize/restore
    • Themed window controls
    • Flexible layout options
  • 🎨 Material Design Integration

    • Built-in light/dark theme support
    • Custom color schemes
    • Adaptive icon colors
  • ⚙️ Enhanced Window Controls

    • Standard buttons (minimize/maximize/close)
    • Theme switcher
    • Custom controls section
    • Responsive layout
  • 🖱️ Native Behavior

    • Smooth window dragging
    • DPI-aware scaling
    • Full multi-monitor support
    • Window state management

Installation

  1. Add the icons dependency:

    implementation("org.jetbrains.compose.material:material-icons-extended:1.7.3")
  2. Copy these components to your project:

Usage

Important

If you use SwingPanel, some components may not be compatible with a transparent window - in this case the background remains transparent or flickers. Use the isTransparent = false flag.

@Composable
fun ApplicationScope.WindowDecoration(
    isDarkTheme: Boolean,
    setIsDarkTheme: (Boolean) -> Unit = {},
    title: String = "Untitled", /** Application name in the taskbar */
    icon: Painter? = null,      /** Application icon in the taskbar */
    windowDecorationHeight: Dp = 32.dp,
    windowDecorationColors: WindowDecorationColors = WindowDecorationColors(
        decoration = {
            MaterialTheme.colorScheme.surface
        },
        content = {
            MaterialTheme.colorScheme.background
        },
        switchSchemeButton = {
            MaterialTheme.colorScheme.primary
        },
        minimizeButton = {
            MaterialTheme.colorScheme.primary
        },
        fullscreenButton = {
            MaterialTheme.colorScheme.primary
        },
        closeButton = {
            MaterialTheme.colorScheme.primary
        },
    ),
    initialWindowPosition: WindowPosition? = null,
    initialWindowSize: DpSize? = null,
    minimumWindowSize: DpSize? = null,
    isVisible: Boolean = true,
    isTransparent: Boolean = true,
    isResizable: Boolean = true,
    isEnabled: Boolean = true,
    isFocusable: Boolean = true,
    isAlwaysOnTop: Boolean = false,
    onPreviewKeyEvent: (KeyEvent) -> Boolean = { false },
    onKeyEvent: (KeyEvent) -> Boolean = { false },
    onCloseRequest: () -> Unit = ::exitApplication,
    titleContent: @Composable RowScope.() -> Unit,          /** Left side of the top panel */
    controlsContent: @Composable RowScope.() -> Unit = {},  /** Right side of the top panel */
    windowContent: @Composable (ComposeWindow.(WindowDecorationState) -> Unit),
)

Customization

WindowDecorationColors

Customize colors for different parts of the window:

windowDecorationColors = WindowDecorationColors().copy(
    decoration = { Color(0xFF2E3440) },         /** Window decoration background */
    content = { Color(0xFF3B4252) },            /** Content area background */
    switchSchemeButton = { Color.Unspecified }, /** Hide button */
    closeButton = { Color.Red }                 /** Make close button red */
)

Window State

Access window state in your content:

content = { windowState: WindowDecorationState ->
    if (windowState.isFullscreen) {
        FullscreenContent()
    } else {
        NormalContent()
    }
}

Custom Controls

Add your own controls:

controls = {
    Box(
        modifier = Modifier.fillMaxHeight().aspectRatio(1f).clickable {
            /* handle action */
        }, contentAlignment = Alignment.Center
    ) {
        Icon(
            Icons.Default.Settings, null, tint = MaterialTheme.colorScheme.primary
        )
    }
}

Window Parameters

Control window behavior:

WindowDecoration(
    initialWindowPosition = WindowPosition(100.dp, 100.dp),
    initialWindowSize = DpSize(800.dp, 600.dp),
    minimumWindowSize = DpSize(400.dp, 300.dp),
    isResizable = true,
    isAlwaysOnTop = false,
    // ...
)

Example

See complete example: Application.kt