Commit 377587a1 authored by Roman Sedaikin's avatar Roman Sedaikin

Fullscreen support

parent 428c3dc6
......@@ -93,6 +93,10 @@ private:
set<LayerHandler *> *layerStorage = NULL;
LayerHandler *findByObject(JNIEnv *env, jobject object)
{
if (layerStorage == NULL)
{
return NULL;
}
for (auto &layer : *layerStorage)
{
if (env->IsSameObject(object, layer->canvasGlobalRef) == JNI_TRUE)
......
......@@ -64,6 +64,10 @@ private:
set<LayerHandler *> *layerStorage = NULL;
LayerHandler *findByObject(JNIEnv *env, jobject object)
{
if (layerStorage == NULL)
{
return NULL;
}
for (auto &layer : *layerStorage)
{
if (env->IsSameObject(object, layer->canvasGlobalRef) == JNI_TRUE)
......
......@@ -5,7 +5,8 @@ import java.awt.Canvas
import javax.swing.SwingUtilities.convertPoint
import javax.swing.SwingUtilities.getRootPane
open class HardwareLayer : Canvas(), Drawable {
abstract class HardwareLayer : Canvas(), Drawable {
companion object {
init {
Library.load()
......@@ -15,20 +16,33 @@ open class HardwareLayer : Canvas(), Drawable {
override fun paint(g: Graphics) {
display()
}
open fun display() {
this.updateLayer()
this.redrawLayer()
}
open fun draw() {}
external override fun redrawLayer()
external override fun updateLayer()
external override fun disposeLayer()
override val windowHandle: Long
external get
override val contentScale: Float
get() = graphicsConfiguration.defaultTransform.scaleX.toFloat()
val absoluteX: Int
get() = convertPoint(this, x, y, getRootPane(this)).x
val absoluteY: Int
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
import java.awt.event.ComponentAdapter
import java.awt.event.ComponentEvent
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() {
val layer: SkiaLayer = SkiaLayer()
......@@ -138,4 +20,9 @@ open class SkiaWindow : JFrame() {
fun display() {
layer.display()
}
override fun setVisible(value: Boolean) {
super.setVisible(value)
display()
}
}
......@@ -70,6 +70,7 @@ JavaVM *jvm = NULL;
@property (retain, strong) CALayer *container;
@property (retain, strong) AWTGLLayer *glLayer;
@property (retain, strong) NSWindow *window;
@end
......@@ -83,6 +84,7 @@ JavaVM *jvm = NULL;
{
self.container = NULL;
self.glLayer = NULL;
self.window = NULL;
}
return self;
......@@ -182,10 +184,30 @@ JavaVM *jvm = NULL;
self.glLayer.canvasGlobalRef = NULL;
self.glLayer = 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
NSMutableArray *unknownWindows = nil;
NSMutableSet *layerStorage = nil;
pthread_mutex_t layerStorageMutex = { 0 };
......@@ -199,6 +221,10 @@ void unlockLayers() {
LayerHandler * findByObject(JNIEnv *env, jobject object)
{
if (layerStorage == nil)
{
return NULL;
}
for (LayerHandler* layer in layerStorage)
{
if ((*env)->IsSameObject(env, object, layer.glLayer.canvasGlobalRef) == JNI_TRUE)
......@@ -275,6 +301,28 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_HardwareLayer_updateLayer(JNIEnv
[layersSet.glLayer setCanvasGlobalRef: canvasGlobalRef];
[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);
......@@ -311,10 +359,33 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_HardwareLayer_getWindowHandle(J
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)
{
id<MTLDevice> fDevice = MTLCreateSystemDefaultDevice();
id<MTLCommandQueue> fQueue = [fDevice newCommandQueue];
*device = (__bridge void*)fDevice;
*queue = (__bridge void*)fQueue;
}
\ No newline at end of file
}
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