From 7ea3f41b86da6d09eb4831a85d3dfee3182ece3e Mon Sep 17 00:00:00 2001 From: Pavel Date: Mon, 26 Apr 2021 20:09:13 +0300 Subject: [PATCH] Macos headerless window (#96) * check that drawing surface lock is successful * add disable title bar * bump skija * make window handle accessible after `window.pack()` but before `window.setVisible(true)` * rollback changes in demo App * fix warning and return value in `lockDrawingSurface` * reduce code duplication --- skiko/gradle.properties | 10 ++-- skiko/src/jvmMain/cpp/common/awt_jni.cc | 4 +- .../jvmMain/kotlin/org/jetbrains/skiko/AWT.kt | 4 +- .../org/jetbrains/skiko/PlatformOperations.kt | 12 ++++ .../kotlin/org/jetbrains/skiko/SkiaWindow.kt | 6 ++ .../src/jvmMain/objectiveC/macos/Drawlayer.mm | 59 ++++++++++++------- 6 files changed, 65 insertions(+), 30 deletions(-) diff --git a/skiko/gradle.properties b/skiko/gradle.properties index deea05e705..122b65bdf6 100644 --- a/skiko/gradle.properties +++ b/skiko/gradle.properties @@ -1,10 +1,10 @@ kotlin.code.style=official deploy.version=0.0.0 -dependencies.skija.git.commit=adbb8c2926045af424a2ff93f5f0110f965bdbbb -dependencies.skia.windows-x64=m89-109bfc9052/Skia-m89-109bfc9052-windows-Release-x64 -dependencies.skia.linux-x64=m89-109bfc9052/Skia-m89-109bfc9052-linux-Release-x64 -dependencies.skia.macos-x64=m89-109bfc9052/Skia-m89-109bfc9052-macos-Release-x64 -dependencies.skia.macos-arm64=m89-109bfc9052/Skia-m89-109bfc9052-macos-Release-arm64 +dependencies.skija.git.commit=a5d6dfd746b8a8ec2ef52ebea4baa53f299d080c +dependencies.skia.windows-x64=m90-adbb69cd7f-2/Skia-m90-adbb69cd7f-2-windows-Release-x64 +dependencies.skia.linux-x64=m90-adbb69cd7f-2/Skia-m90-adbb69cd7f-2-linux-Release-x64 +dependencies.skia.macos-x64=m90-adbb69cd7f-2/Skia-m90-adbb69cd7f-2-macos-Release-x64 +dependencies.skia.macos-arm64=m90-adbb69cd7f-2/Skia-m90-adbb69cd7f-2-macos-Release-arm64 # signer=Apple Distribution: Nikolay Igotti (N462MKSJ7M) diff --git a/skiko/src/jvmMain/cpp/common/awt_jni.cc b/skiko/src/jvmMain/cpp/common/awt_jni.cc index 3875ebe77d..703e404ae0 100644 --- a/skiko/src/jvmMain/cpp/common/awt_jni.cc +++ b/skiko/src/jvmMain/cpp/common/awt_jni.cc @@ -36,10 +36,10 @@ extern "C" awt->FreeDrawingSurface(ds); } - JNIEXPORT void JNICALL Java_org_jetbrains_skiko_AWTKt_lockDrawingSurface(JNIEnv *env, jobject obj, jlong drawingSurfacePtr) + JNIEXPORT jint JNICALL Java_org_jetbrains_skiko_AWTKt_lockDrawingSurface(JNIEnv *env, jobject obj, jlong drawingSurfacePtr) { JAWT_DrawingSurface *ds = fromJavaPointer(drawingSurfacePtr); - ds->Lock(ds); + return (ds->Lock(ds) & JAWT_LOCK_ERROR) != 0; } JNIEXPORT void JNICALL Java_org_jetbrains_skiko_AWTKt_unlockDrawingSurface(JNIEnv *env, jobject obj, jlong drawingSurfacePtr) diff --git a/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/AWT.kt b/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/AWT.kt index 19d62b9efc..fa36266b85 100644 --- a/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/AWT.kt +++ b/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/AWT.kt @@ -31,7 +31,7 @@ internal class DrawingSurface( } private set - fun lock() = lockDrawingSurface(ptr) + fun lock() = lockDrawingSurface(ptr).also { check(it == 0) } fun unlock() = unlockDrawingSurface(ptr) @@ -74,7 +74,7 @@ private external fun getAWT(): Long private external fun getDrawingSurface(awt: Long, layer: Component): Long private external fun freeDrawingSurface(awt: Long, drawingSurface: Long) -private external fun lockDrawingSurface(drawingSurface: Long) +private external fun lockDrawingSurface(drawingSurface: Long): Int private external fun unlockDrawingSurface(drawingSurface: Long) private external fun getDrawingSurfaceInfo(drawingSurface: Long): Long diff --git a/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/PlatformOperations.kt b/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/PlatformOperations.kt index 0fd1eab219..8805e8b75e 100644 --- a/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/PlatformOperations.kt +++ b/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/PlatformOperations.kt @@ -14,6 +14,7 @@ import javax.swing.SwingUtilities internal interface PlatformOperations { fun isFullscreen(component: Component): Boolean fun setFullscreen(component: Component, value: Boolean) + fun disableTitleBar(platformInfo: Long) fun getDpiScale(component: Component): Float fun createRedrawer(layer: SkiaLayer, renderApi: GraphicsApi, properties: SkiaLayerProperties): Redrawer } @@ -33,6 +34,10 @@ internal val platformOperations: PlatformOperations by lazy { return component.graphicsConfiguration.defaultTransform.scaleX.toFloat() } + override fun disableTitleBar(platformInfo: Long) { + osxDisableTitleBar(platformInfo) + } + override fun createRedrawer( layer: SkiaLayer, renderApi: GraphicsApi, @@ -57,6 +62,9 @@ internal val platformOperations: PlatformOperations by lazy { device.setFullScreenWindow(if (value) window else null) } + override fun disableTitleBar(platformInfo: Long) { + } + override fun getDpiScale(component: Component): Float { return component.graphicsConfiguration.defaultTransform.scaleX.toFloat() } @@ -86,6 +94,9 @@ internal val platformOperations: PlatformOperations by lazy { device.setFullScreenWindow(if (value) window else null) } + override fun disableTitleBar(platformInfo: Long) { + } + override fun getDpiScale(component: Component): Float { return component.graphicsConfiguration.defaultTransform.scaleX.toFloat() // TODO doesn't work well because java doesn't scale windows (content has offset with 200% scale) @@ -118,6 +129,7 @@ internal val platformOperations: PlatformOperations by lazy { // OSX external private fun osxIsFullscreenNative(component: Component): Boolean external private fun osxSetFullscreenNative(component: Component, value: Boolean) +external private fun osxDisableTitleBar(platformInfo: Long) // Linux external private fun linuxGetDpiScaleNative(platformInfo: Long): Float diff --git a/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/SkiaWindow.kt b/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/SkiaWindow.kt index dec8970c43..a529fa3bab 100644 --- a/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/SkiaWindow.kt +++ b/skiko/src/jvmMain/kotlin/org/jetbrains/skiko/SkiaWindow.kt @@ -15,4 +15,10 @@ open class SkiaWindow( layer.dispose() super.dispose() } + + fun disableTitleBar() { + useDrawingSurfacePlatformInfo { + platformOperations.disableTitleBar(it) + } + } } diff --git a/skiko/src/jvmMain/objectiveC/macos/Drawlayer.mm b/skiko/src/jvmMain/objectiveC/macos/Drawlayer.mm index 0b630952c2..8b3f94d21d 100755 --- a/skiko/src/jvmMain/objectiveC/macos/Drawlayer.mm +++ b/skiko/src/jvmMain/objectiveC/macos/Drawlayer.mm @@ -104,6 +104,22 @@ - (void) makeFullscreen: (BOOL) value return recursiveWindowSearch(rootView, layer); } +NSWindow *findWindow(jlong platformInfoPtr) +{ + NSObject* dsi_mac = (__bridge NSObject *) platformInfoPtr; + CALayer* ca_layer = [dsi_mac windowLayer]; + + NSWindow* target_window = nil; + + NSMutableArray *windows = [NSMutableArray arrayWithArray: [[NSApplication sharedApplication] windows]]; + for (NSWindow* window in windows) + { + target_window = findCALayerWindow(window.contentView, ca_layer); + if (target_window != nil) break; + } + return target_window; +} + JNIEXPORT void JNICALL Java_org_jetbrains_skiko_HardwareLayer_nativeInit(JNIEnv *env, jobject canvas, jlong platformInfoPtr) { if (layerStorage == nil) @@ -111,21 +127,12 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_HardwareLayer_nativeInit(JNIEnv layerStorage = [[NSMutableSet alloc] init]; } - NSObject* dsi_mac = (__bridge NSObject *) platformInfoPtr; - LayerHandler *layersSet = [[LayerHandler alloc] init]; - + NSObject* dsi_mac = (__bridge NSObject *) platformInfoPtr; layersSet.container = [dsi_mac windowLayer]; jobject canvasGlobalRef = env->NewGlobalRef(canvas); [layersSet setCanvasGlobalRef: canvasGlobalRef]; - - NSMutableArray *windows = [NSMutableArray arrayWithArray: [[NSApplication sharedApplication] windows]]; - for (NSWindow* window in windows) { - layersSet.window = findCALayerWindow(window.contentView, layersSet.container); - if (layersSet.window != nil) { - break; - } - } + layersSet.window = findWindow(platformInfoPtr); [layerStorage addObject: layersSet]; } @@ -141,16 +148,6 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_HardwareLayer_nativeDispose(JNIE } } -JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_HardwareLayer_getWindowHandle(JNIEnv *env, jobject canvas) -{ - LayerHandler *layer = findByObject(env, canvas); - if (layer != NULL) - { - return (jlong)[layer window]; - } - return (jlong)kNullWindowHandle; -} - JNIEXPORT jboolean JNICALL Java_org_jetbrains_skiko_PlatformOperationsKt_osxIsFullscreenNative(JNIEnv *env, jobject properties, jobject component) { LayerHandler *layer = findByObject(env, component); @@ -170,6 +167,26 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_PlatformOperationsKt_osxSetFulls } } +JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_HardwareLayer_getWindowHandle(JNIEnv *env, jobject canvas, jlong platformInfoPtr) +{ + NSWindow* window = findWindow(platformInfoPtr); + return (jlong)window; +} + +JNIEXPORT void JNICALL Java_org_jetbrains_skiko_PlatformOperationsKt_osxDisableTitleBar(JNIEnv *env, jobject properties, jlong platformInfoPtr) +{ + NSWindow* window = findWindow(platformInfoPtr); + if (window == nil) return; + dispatch_async(dispatch_get_main_queue(), ^{ + [window setTitlebarAppearsTransparent:YES]; + [window setTitleVisibility:NSWindowTitleHidden]; + [window setStyleMask:[window styleMask]|NSWindowStyleMaskFullSizeContentView]; + // always show `fullscreen` green traffic light button instead of `maximize/zoom` button + [window setCollectionBehavior:[window collectionBehavior]|NSWindowCollectionBehaviorFullScreenPrimary]; + [window setMovable:NO]; + }); +} + void getMetalDeviceAndQueue(void** device, void** queue) { id fDevice = MTLCreateSystemDefaultDevice();