アプリ開発備忘録

PlayStationMobile、Android、UWPの開発備忘録

フレームなしウィンドウを作成してウィンドウを移動させるまで【Jetpack Compose Desktop】

バージョン

plugins {
    kotlin("jvm") version "1.4.30"
    id("org.jetbrains.compose") version "0.3.0-build150"
}

目標

こんな感じのを作ります。
f:id:matsudamper:20210208024321p:plain:w400

フレームを消す

これだけです。

fun main() = Window(
    undecorated = true,
) {
}

移動する

これが大変です。Modifier作ったのでドラッグ可能にさせたいViewに適用してください。

@Composable
fun Modifier.windowDraggable(): Modifier {
    val window = LocalAppWindow.current
    return pointerInput(Unit) {
        forEachGesture {
            awaitPointerEventScope {
                val firstEvent = awaitPointerEvent()
                val firstWindowPointer = firstEvent.mouseEvent?.point ?: return@awaitPointerEventScope

                while (true) {
                    val event = awaitPointerEvent()

                    val displayPointer = event.mouseEvent?.locationOnScreen ?: break
                    window.setLocation(
                        (displayPointer.x - firstWindowPointer.x),
                        (displayPointer.y - firstWindowPointer.y),
                    )

                    when (event.mouseEvent?.id) {
                        null,
                        MouseEvent.MOUSE_RELEASED -> {
                            break
                        }
                    }
                }
            }
        }
    }
}

自分はタブに付けてみました。

TopAppBar(
    modifier = Modifier.windowDraggable()
) {}

ディスプレイを跨ぐ

ディスプレイを跨ぐと描画が壊れる場合があります。DPIとかが違うと多分起きます。
以下のようにディスプレイが変わったらJFrameに更新してもらうようにします。 addNotify は名前的に微妙な感じがあるので、別の適切な関数があったら教えて下さい。
跨いだ場合にカーソルが外れてしまうので、いい方法があったら教えて下さい。

fun main() = Window(
    title = "Review requested",
    undecorated = true,
    size = IntSize(400, 600),
) {
    jFrameReLayoutIfDisplayChanged()
    // layout
}

@Composable
fun jFrameReLayoutIfDisplayChanged() {
    val window = LocalAppWindow.current
    val listener = remember {
        PropertyChangeListener {
            window.window.addNotify()
        }
    }

    remember {
        object : RememberObserver {
            override fun onAbandoned() {}
            override fun onForgotten() {
                window.window.removePropertyChangeListener(listener)
            }

            override fun onRemembered() {
                window.window.addPropertyChangeListener(listener)
            }
        }
    }
}