Unverified Commit 59e95480 authored by Roman Sedaikin's avatar Roman Sedaikin Committed by GitHub

Merge pull request #32 from JetBrains/fullscreen_2

Fullscreen support
parents 428c3dc6 377587a1
...@@ -93,6 +93,10 @@ private: ...@@ -93,6 +93,10 @@ private:
set<LayerHandler *> *layerStorage = NULL; set<LayerHandler *> *layerStorage = NULL;
LayerHandler *findByObject(JNIEnv *env, jobject object) LayerHandler *findByObject(JNIEnv *env, jobject object)
{ {
if (layerStorage == NULL)
{
return NULL;
}
for (auto &layer : *layerStorage) for (auto &layer : *layerStorage)
{ {
if (env->IsSameObject(object, layer->canvasGlobalRef) == JNI_TRUE) if (env->IsSameObject(object, layer->canvasGlobalRef) == JNI_TRUE)
......
...@@ -64,6 +64,10 @@ private: ...@@ -64,6 +64,10 @@ private:
set<LayerHandler *> *layerStorage = NULL; set<LayerHandler *> *layerStorage = NULL;
LayerHandler *findByObject(JNIEnv *env, jobject object) LayerHandler *findByObject(JNIEnv *env, jobject object)
{ {
if (layerStorage == NULL)
{
return NULL;
}
for (auto &layer : *layerStorage) for (auto &layer : *layerStorage)
{ {
if (env->IsSameObject(object, layer->canvasGlobalRef) == JNI_TRUE) if (env->IsSameObject(object, layer->canvasGlobalRef) == JNI_TRUE)
......
...@@ -5,7 +5,8 @@ import java.awt.Canvas ...@@ -5,7 +5,8 @@ import java.awt.Canvas
import javax.swing.SwingUtilities.convertPoint import javax.swing.SwingUtilities.convertPoint
import javax.swing.SwingUtilities.getRootPane import javax.swing.SwingUtilities.getRootPane
open class HardwareLayer : Canvas(), Drawable { abstract class HardwareLayer : Canvas(), Drawable {
companion object { companion object {
init { init {
Library.load() Library.load()
...@@ -15,20 +16,33 @@ open class HardwareLayer : Canvas(), Drawable { ...@@ -15,20 +16,33 @@ open class HardwareLayer : Canvas(), Drawable {
override fun paint(g: Graphics) { override fun paint(g: Graphics) {
display() display()
} }
open fun display() { open fun display() {
this.updateLayer() this.updateLayer()
this.redrawLayer() this.redrawLayer()
} }
open fun draw() {} open fun draw() {}
external override fun redrawLayer() external override fun redrawLayer()
external override fun updateLayer() external override fun updateLayer()
external override fun disposeLayer() external override fun disposeLayer()
override val windowHandle: Long override val windowHandle: Long
external get external get
override val contentScale: Float override val contentScale: Float
get() = graphicsConfiguration.defaultTransform.scaleX.toFloat() get() = graphicsConfiguration.defaultTransform.scaleX.toFloat()
val absoluteX: Int val absoluteX: Int
get() = convertPoint(this, x, y, getRootPane(this)).x get() = convertPoint(this, x, y, getRootPane(this)).x
val absoluteY: Int val absoluteY: Int
get() = convertPoint(this, x, y, getRootPane(this)).y get() = convertPoint(this, x, y, getRootPane(this)).y
var fullscreen: Boolean
get() = platformOperations.isFullscreen(this)
set(value) = platformOperations.setFullscreen(this, value)
} }
\ No newline at end of file
package org.jetbrains.skiko
import java.awt.Component
import java.awt.Window
import javax.swing.SwingUtilities
internal interface PlatformOperations {
fun isFullscreen(component: Component): Boolean
fun setFullscreen(component: Component, value: Boolean)
}
internal val platformOperations: PlatformOperations by lazy {
when (hostOs) {
OS.MacOS -> object: PlatformOperations {
override fun isFullscreen(component: Component): Boolean {
return osxIsFullscreenNative(component)
}
override fun setFullscreen(component: Component, value: Boolean) {
osxSetFullscreenNative(component, value)
}
}
else -> {
object: PlatformOperations {
override fun isFullscreen(component: Component): Boolean {
val window = SwingUtilities.getRoot(component) as Window
val device = window.graphicsConfiguration.device
return device.getFullScreenWindow() == window
}
override fun setFullscreen(component: Component, value: Boolean) {
val window = SwingUtilities.getRoot(component) as Window
val device = window.graphicsConfiguration.device
device.setFullScreenWindow(if (value) window else null)
}
}
}
}
}
external private fun osxIsFullscreenNative(component: Component): Boolean
external private fun osxSetFullscreenNative(component: Component, value: Boolean)
\ No newline at end of file
package org.jetbrains.skiko
import org.jetbrains.skija.BackendRenderTarget
import org.jetbrains.skija.Canvas
import org.jetbrains.skija.ColorSpace
import org.jetbrains.skija.DirectContext
import org.jetbrains.skija.FramebufferFormat
import org.jetbrains.skija.Surface
import org.jetbrains.skija.SurfaceColorFormat
import org.jetbrains.skija.SurfaceOrigin
private class SkijaState {
var context: DirectContext? = null
var renderTarget: BackendRenderTarget? = null
var surface: Surface? = null
var canvas: Canvas? = null
fun clear() {
surface?.close()
renderTarget?.close()
}
}
interface SkiaRenderer {
fun onInit()
fun onRender(canvas: Canvas, width: Int, height: Int)
fun onReshape(width: Int, height: Int)
fun onDispose()
}
open class SkiaLayer() : HardwareLayer() {
open val api: GraphicsApi = GraphicsApi.OPENGL
var renderer: SkiaRenderer? = null
private val skijaState = SkijaState()
protected var inited: Boolean = false
fun reinit() {
inited = false
}
override fun disposeLayer() {
super.disposeLayer()
renderer?.onDispose()
}
override fun draw() {
if (!inited) {
if (skijaState.context == null) {
skijaState.context = when (api) {
GraphicsApi.OPENGL -> makeGLContext()
GraphicsApi.METAL -> makeMetalContext()
else -> TODO("Unsupported yet")
}
}
renderer?.onInit()
inited = true
renderer?.onReshape(width, height)
}
initSkija()
skijaState.apply {
canvas!!.clear(-1)
renderer?.onRender(canvas!!, width, height)
context!!.flush()
}
}
private fun initSkija() {
val dpi = contentScale
initRenderTarget(dpi)
initSurface()
scaleCanvas(dpi)
}
private fun initRenderTarget(dpi: Float) {
skijaState.apply {
clear()
renderTarget = when (api) {
GraphicsApi.OPENGL -> {
val gl = OpenGLApi.instance
val fbId = gl.glGetIntegerv(gl.GL_DRAW_FRAMEBUFFER_BINDING)
makeGLRenderTarget(
(width * dpi).toInt(),
(height * dpi).toInt(),
0,
8,
fbId,
FramebufferFormat.GR_GL_RGBA8
)
}
GraphicsApi.METAL -> makeMetalRenderTarget(
(width * dpi).toInt(),
(height * dpi).toInt(),
0
)
else -> TODO("Unsupported yet")
}
}
}
private fun initSurface() {
skijaState.apply {
surface = Surface.makeFromBackendRenderTarget(
context,
renderTarget,
SurfaceOrigin.BOTTOM_LEFT,
SurfaceColorFormat.RGBA_8888,
ColorSpace.getSRGB()
)
canvas = surface!!.canvas
}
}
protected open fun scaleCanvas(dpi: Float) {
skijaState.apply {
canvas!!.scale(dpi, dpi)
}
}
}
...@@ -3,124 +3,6 @@ package org.jetbrains.skiko ...@@ -3,124 +3,6 @@ package org.jetbrains.skiko
import java.awt.event.ComponentAdapter import java.awt.event.ComponentAdapter
import java.awt.event.ComponentEvent import java.awt.event.ComponentEvent
import javax.swing.JFrame import javax.swing.JFrame
import org.jetbrains.skija.BackendRenderTarget
import org.jetbrains.skija.Canvas
import org.jetbrains.skija.ColorSpace
import org.jetbrains.skija.DirectContext
import org.jetbrains.skija.FramebufferFormat
import org.jetbrains.skija.Surface
import org.jetbrains.skija.SurfaceColorFormat
import org.jetbrains.skija.SurfaceOrigin
private class SkijaState {
var context: DirectContext? = null
var renderTarget: BackendRenderTarget? = null
var surface: Surface? = null
var canvas: Canvas? = null
fun clear() {
surface?.close()
renderTarget?.close()
}
}
interface SkiaRenderer {
fun onInit()
fun onRender(canvas: Canvas, width: Int, height: Int)
fun onReshape(width: Int, height: Int)
fun onDispose()
}
open class SkiaLayer() : HardwareLayer() {
open val api: GraphicsApi = GraphicsApi.OPENGL
var renderer: SkiaRenderer? = null
private val skijaState = SkijaState()
protected var inited: Boolean = false
fun reinit() {
inited = false
}
override fun disposeLayer() {
super.disposeLayer()
renderer?.onDispose()
}
override fun draw() {
if (!inited) {
if (skijaState.context == null) {
skijaState.context = when (api) {
GraphicsApi.OPENGL -> makeGLContext()
GraphicsApi.METAL -> makeMetalContext()
else -> TODO("Unsupported yet")
}
}
renderer?.onInit()
inited = true
renderer?.onReshape(width, height)
}
initSkija()
skijaState.apply {
canvas!!.clear(-1)
renderer?.onRender(canvas!!, width, height)
context!!.flush()
}
}
private fun initSkija() {
val dpi = contentScale
initRenderTarget(dpi)
initSurface()
scaleCanvas(dpi)
}
private fun initRenderTarget(dpi: Float) {
skijaState.apply {
clear()
renderTarget = when (api) {
GraphicsApi.OPENGL -> {
val gl = OpenGLApi.instance
val fbId = gl.glGetIntegerv(gl.GL_DRAW_FRAMEBUFFER_BINDING)
makeGLRenderTarget(
(width * dpi).toInt(),
(height * dpi).toInt(),
0,
8,
fbId,
FramebufferFormat.GR_GL_RGBA8
)
}
GraphicsApi.METAL -> makeMetalRenderTarget(
(width * dpi).toInt(),
(height * dpi).toInt(),
0
)
else -> TODO("Unsupported yet")
}
}
}
private fun initSurface() {
skijaState.apply {
surface = Surface.makeFromBackendRenderTarget(
context,
renderTarget,
SurfaceOrigin.BOTTOM_LEFT,
SurfaceColorFormat.RGBA_8888,
ColorSpace.getSRGB()
)
canvas = surface!!.canvas
}
}
protected open fun scaleCanvas(dpi: Float) {
skijaState.apply {
canvas!!.scale(dpi, dpi)
}
}
}
open class SkiaWindow : JFrame() { open class SkiaWindow : JFrame() {
val layer: SkiaLayer = SkiaLayer() val layer: SkiaLayer = SkiaLayer()
...@@ -138,4 +20,9 @@ open class SkiaWindow : JFrame() { ...@@ -138,4 +20,9 @@ open class SkiaWindow : JFrame() {
fun display() { fun display() {
layer.display() layer.display()
} }
override fun setVisible(value: Boolean) {
super.setVisible(value)
display()
}
} }
...@@ -70,6 +70,7 @@ JavaVM *jvm = NULL; ...@@ -70,6 +70,7 @@ JavaVM *jvm = NULL;
@property (retain, strong) CALayer *container; @property (retain, strong) CALayer *container;
@property (retain, strong) AWTGLLayer *glLayer; @property (retain, strong) AWTGLLayer *glLayer;
@property (retain, strong) NSWindow *window;
@end @end
...@@ -83,6 +84,7 @@ JavaVM *jvm = NULL; ...@@ -83,6 +84,7 @@ JavaVM *jvm = NULL;
{ {
self.container = NULL; self.container = NULL;
self.glLayer = NULL; self.glLayer = NULL;
self.window = NULL;
} }
return self; return self;
...@@ -182,10 +184,30 @@ JavaVM *jvm = NULL; ...@@ -182,10 +184,30 @@ JavaVM *jvm = NULL;
self.glLayer.canvasGlobalRef = NULL; self.glLayer.canvasGlobalRef = NULL;
self.glLayer = NULL; self.glLayer = NULL;
self.container = NULL; self.container = NULL;
self.window = NULL;
}
- (BOOL) isFullScreen {
NSUInteger masks = [self.window styleMask];
return (masks & NSWindowStyleMaskFullScreen) != 0;
}
- (void) makeFullscreen: (BOOL) value
{
if (value && !self.isFullScreen)
{
[self.window performSelectorOnMainThread:@selector(toggleFullScreen:) withObject:nil waitUntilDone:NO];
}
else if (!value && self.isFullScreen)
{
[self.window performSelectorOnMainThread:@selector(toggleFullScreen:) withObject:nil waitUntilDone:NO];
}
} }
@end @end
NSMutableArray *unknownWindows = nil;
NSMutableSet *layerStorage = nil; NSMutableSet *layerStorage = nil;
pthread_mutex_t layerStorageMutex = { 0 }; pthread_mutex_t layerStorageMutex = { 0 };
...@@ -199,6 +221,10 @@ void unlockLayers() { ...@@ -199,6 +221,10 @@ void unlockLayers() {
LayerHandler * findByObject(JNIEnv *env, jobject object) LayerHandler * findByObject(JNIEnv *env, jobject object)
{ {
if (layerStorage == nil)
{
return NULL;
}
for (LayerHandler* layer in layerStorage) for (LayerHandler* layer in layerStorage)
{ {
if ((*env)->IsSameObject(env, object, layer.glLayer.canvasGlobalRef) == JNI_TRUE) if ((*env)->IsSameObject(env, object, layer.glLayer.canvasGlobalRef) == JNI_TRUE)
...@@ -275,6 +301,28 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_HardwareLayer_updateLayer(JNIEnv ...@@ -275,6 +301,28 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_HardwareLayer_updateLayer(JNIEnv
[layersSet.glLayer setCanvasGlobalRef: canvasGlobalRef]; [layersSet.glLayer setCanvasGlobalRef: canvasGlobalRef];
[layersSet syncLayersSize]; [layersSet syncLayersSize];
if (unknownWindows == nil)
{
NSMutableArray<NSWindow *> *windows = [NSMutableArray arrayWithArray: [[NSApplication sharedApplication] windows]];
NSWindow *mainWindow = [[NSApplication sharedApplication] mainWindow];
layersSet.window = mainWindow;
[windows removeObject: mainWindow];
unknownWindows = windows;
}
else
{
NSMutableArray<NSWindow *> *windows = [NSMutableArray arrayWithArray: [[NSApplication sharedApplication] windows]];
for (NSWindow* value in unknownWindows)
{
[windows removeObject: value];
}
for (LayerHandler* value in layerStorage)
{
[windows removeObject: value.window];
}
layersSet.window = [windows firstObject];
}
} }
ds->FreeDrawingSurfaceInfo(dsi); ds->FreeDrawingSurfaceInfo(dsi);
...@@ -311,6 +359,29 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_HardwareLayer_getWindowHandle(J ...@@ -311,6 +359,29 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_HardwareLayer_getWindowHandle(J
return (jlong)kNullWindowHandle; return (jlong)kNullWindowHandle;
} }
JNIEXPORT jboolean JNICALL Java_org_jetbrains_skiko_PlatformOperationsKt_osxIsFullscreenNative(JNIEnv *env, jobject properties, jobject component)
{
lockLayers();
LayerHandler *layer = findByObject(env, component);
unlockLayers();
if (layer != NULL)
{
return [layer isFullScreen];
}
return false;
}
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_PlatformOperationsKt_osxSetFullscreenNative(JNIEnv *env, jobject properties, jobject component, jboolean value)
{
lockLayers();
LayerHandler *layer = findByObject(env, component);
unlockLayers();
if (layer != NULL)
{
[layer makeFullscreen:value];
}
}
void getMetalDeviceAndQueue(void** device, void** queue) void getMetalDeviceAndQueue(void** device, void** queue)
{ {
id<MTLDevice> fDevice = MTLCreateSystemDefaultDevice(); id<MTLDevice> fDevice = MTLCreateSystemDefaultDevice();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment