From e496e63afdb291446f10e5444faeb777feb6e599 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Sat, 24 Jun 2023 19:42:29 -0600 Subject: [PATCH 01/22] Monocle for JDK 8.0.372 --- build.gradle | 39 ++-- gradle.properties | 2 +- gradlew | 0 .../glass/ui/monocle/LinuxMouseProcessor.java | 6 +- .../glass/ui/monocle/MonocleApplication.java | 69 ++++-- .../sun/glass/ui/monocle/MonoclePixels.java | 6 +- .../sun/glass/ui/monocle/MonocleRobot.java | 218 ++++++++---------- .../sun/glass/ui/monocle/MonocleWindow.java | 4 +- .../com/sun/glass/ui/monocle/MouseState.java | 8 +- .../com/sun/glass/ui/monocle/VNCScreen.java | 17 +- src/main/java/com/sun/glass/ui/monocle/X.java | 6 +- .../ui/monocle/X11InputDeviceRegistry.java | 4 +- 12 files changed, 176 insertions(+), 203 deletions(-) mode change 100644 => 100755 gradlew diff --git a/build.gradle b/build.gradle index d2d3ced..e0a369c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,18 +1,18 @@ buildscript { repositories { - jcenter() + mavenCentral() maven { url "https://plugins.gradle.org/m2/" } } - dependencies { - classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4" - classpath 'org.openjfx:javafx-plugin:0.0.7' - } +// dependencies { +// classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4" +// classpath 'org.openjfx:javafx-plugin:0.0.7' +// } } -apply plugin: 'org.openjfx.javafxplugin' +//apply plugin: 'org.openjfx.javafxplugin' // print welcome message. apply from: rootProject.file("gradle/welcome.gradle") @@ -26,6 +26,7 @@ wrapper { // task to print gradle and groovy versions. task("versions", group: "help").doLast { println "Java version: ${System.properties["java.version"]}" + println "JavaFX version: ${System.properties["javafx.version"]}" println "Gradle version: ${gradle.gradleVersion}" println "Groovy version: ${GroovySystem.version}" } @@ -47,20 +48,20 @@ task("initSourceDirs", group: "build setup").doLast { apply plugin: "java" repositories { - jcenter() + mavenCentral() } -javafx { - modules = [ 'javafx.controls', 'javafx.graphics' ] - version = '12.0.1' -} +//javafx { +// modules = [ 'javafx.controls', 'javafx.graphics' ] +// version = '12.0.1' +//} // java language level. -sourceCompatibility = "9" -targetCompatibility = "9" +sourceCompatibility = "8" +targetCompatibility = "8" // configure publish tasks. -apply from: rootProject.file("gradle/publish-bintray.gradle") +//apply from: rootProject.file("gradle/publish-bintray.gradle") // task to create jar with source code. task("sourceJar", type: Jar) { @@ -90,11 +91,11 @@ artifacts { compileJava { javadoc { options.addStringOption("Xdoclint:none", "-quiet") - options.addMultilineStringsOption('-add-exports').setValue(['javafx.graphics/com.sun.glass.ui=ALL-UNNAMED', - 'javafx.graphics/com.sun.glass.events=ALL-UNNAMED', - 'javafx.graphics/com.sun.glass.ui.delegate=ALL-UNNAMED', - 'javafx.graphics/com.sun.glass.utils=ALL-UNNAMED', - 'javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED',]) +// options.addMultilineStringsOption('-add-exports').setValue(['javafx.graphics/com.sun.glass.ui=ALL-UNNAMED', +// 'javafx.graphics/com.sun.glass.events=ALL-UNNAMED', +// 'javafx.graphics/com.sun.glass.ui.delegate=ALL-UNNAMED', +// 'javafx.graphics/com.sun.glass.utils=ALL-UNNAMED', +// 'javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED',]) } } diff --git a/gradle.properties b/gradle.properties index 690f811..92d0e17 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group = org.testfx -version = jdk-12.0.1+2 +version = jdk-8.0.372 description = Headless graphics driver for JavaFX. vendor = The OpenJDK Community diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxMouseProcessor.java b/src/main/java/com/sun/glass/ui/monocle/LinuxMouseProcessor.java index 071457a..b88dc7a 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxMouseProcessor.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxMouseProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,10 +127,6 @@ private static int mouseButtonForKeyCode(int keyCode) { return MouseEvent.BUTTON_OTHER; case LinuxInput.BTN_RIGHT: return MouseEvent.BUTTON_RIGHT; - case LinuxInput.BTN_BACK: - return MouseEvent.BUTTON_BACK; - case LinuxInput.BTN_FORWARD: - return MouseEvent.BUTTON_FORWARD; default: return -1; } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java b/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java index b45422f..31ec9ca 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,8 +28,8 @@ import com.sun.glass.ui.CommonDialogs.ExtensionFilter; import com.sun.glass.ui.CommonDialogs.FileChooserResult; import com.sun.glass.ui.Cursor; -import com.sun.glass.ui.GlassRobot; import com.sun.glass.ui.Pixels; +import com.sun.glass.ui.Robot; import com.sun.glass.ui.Screen; import com.sun.glass.ui.Size; import com.sun.glass.ui.Timer; @@ -38,6 +38,7 @@ import javafx.collections.SetChangeListener; import java.io.File; +import java.lang.reflect.Constructor; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.security.AccessController; @@ -197,9 +198,8 @@ public Pixels createPixels(int width, int height, IntBuffer data) { @Override public Pixels createPixels(int width, int height, IntBuffer data, - float scalex, float scaley) - { - return new MonoclePixels(width, height, data, scalex, scaley); + float scale) { + return new MonoclePixels(width, height, data, scale); } @Override @@ -208,7 +208,7 @@ protected int staticPixels_getNativeFormat() { } @Override - public GlassRobot createRobot() { + public Robot createRobot() { return new MonocleRobot(); } @@ -219,20 +219,49 @@ protected double staticScreen_getVideoRefreshPeriod() { @Override protected Screen[] staticScreen_getScreens() { - NativeScreen ns = platform.getScreen(); - Screen screen = new Screen(1l, // dummy native pointer; - ns.getDepth(), - 0, 0, ns.getWidth(), ns.getHeight(), - 0, 0, ns.getWidth(), ns.getHeight(), - 0, 0, ns.getWidth(), ns.getHeight(), - ns.getDPI(), ns.getDPI(), - ns.getScale(), ns.getScale(), - ns.getScale(), ns.getScale()); - // Move the cursor to the middle of the screen - MouseState mouseState = new MouseState(); - mouseState.setX(ns.getWidth() / 2); - mouseState.setY(ns.getHeight() / 2); - MouseInput.getInstance().setState(mouseState, false); + Screen screen = null; + try { + NativeScreen ns = platform.getScreen(); + Constructor c = AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public Constructor run() { + try { + Constructor c = Screen.class.getDeclaredConstructor( + Long.TYPE, + Integer.TYPE, + Integer.TYPE, Integer.TYPE, + Integer.TYPE, Integer.TYPE, + Integer.TYPE, Integer.TYPE, + Integer.TYPE, Integer.TYPE, + Integer.TYPE, Integer.TYPE, Float.TYPE); + c.setAccessible(true); + return c; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + }); + if (c != null) { + screen = (Screen) c.newInstance( + 1l, // dummy native pointer; + ns.getDepth(), + 0, 0, ns.getWidth(), ns.getHeight(), + 0, 0, ns.getWidth(), ns.getHeight(), + ns.getDPI(), ns.getDPI(), + ns.getScale()); + // Move the cursor to the middle of the screen + MouseState mouseState = new MouseState(); + mouseState.setX(ns.getWidth() / 2); + mouseState.setY(ns.getHeight() / 2); + MouseInput.getInstance().setState(mouseState, false); + } + } catch (Exception e) { + e.printStackTrace(); + } catch (UnsatisfiedLinkError e) { + e.printStackTrace(); + } return new Screen[] { screen }; } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java b/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java index bbb17ce..bbce23c 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,8 +41,8 @@ final class MonoclePixels extends Pixels { super(width, height, data); } - MonoclePixels(int width, int height, IntBuffer data, float scalex, float scaley) { - super(width, height, data, scalex, scaley); + MonoclePixels(int width, int height, IntBuffer data, float scale) { + super(width, height, data, scale); } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java b/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java index b055e4c..f982a2e 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,161 +25,132 @@ package com.sun.glass.ui.monocle; +import com.sun.glass.events.MouseEvent; +import com.sun.glass.ui.Pixels; +import com.sun.glass.ui.Robot; +import javafx.application.Platform; + import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; -import javafx.scene.input.KeyCode; -import javafx.scene.input.MouseButton; -import javafx.scene.paint.Color; - -import com.sun.glass.events.MouseEvent; -import com.sun.glass.ui.Application; -import com.sun.glass.ui.GlassRobot; - -class MonocleRobot extends GlassRobot { +class MonocleRobot extends Robot { @Override - public void create() { - // no-op + protected void _create() { } @Override - public void destroy() { - // no-op + protected void _destroy() { } @Override - public void keyPress(KeyCode code) { - Application.checkEventThread(); - KeyState state = new KeyState(); - KeyInput.getInstance().getState(state); - state.pressKey(code.getCode()); - KeyInput.getInstance().setState(state); + protected void _keyPress(int code) { + Platform.runLater(() -> { + KeyState state = new KeyState(); + KeyInput.getInstance().getState(state); + state.pressKey(code); + KeyInput.getInstance().setState(state); + }); } @Override - public void keyRelease(KeyCode code) { - Application.checkEventThread(); - KeyState state = new KeyState(); - KeyInput.getInstance().getState(state); - state.releaseKey(code.getCode()); - KeyInput.getInstance().setState(state); + protected void _keyRelease(int code) { + Platform.runLater(() -> { + KeyState state = new KeyState(); + KeyInput.getInstance().getState(state); + state.releaseKey(code); + KeyInput.getInstance().setState(state); + }); } @Override - public void mouseMove(double x, double y) { - Application.checkEventThread(); - MouseState state = new MouseState(); - MouseInput.getInstance().getState(state); - state.setX((int) x); - state.setY((int) y); - MouseInput.getInstance().setState(state, false); - } - - private static MouseState convertToMouseState(boolean press, MouseState state, MouseButton... buttons) { - for (MouseButton button : buttons) { - switch (button) { - case PRIMARY: - if (press) { - state.pressButton(MouseEvent.BUTTON_LEFT); - } else { - state.releaseButton(MouseEvent.BUTTON_LEFT); - } - break; - case SECONDARY: - if (press) { - state.pressButton(MouseEvent.BUTTON_RIGHT); - } else { - state.releaseButton(MouseEvent.BUTTON_RIGHT); - } - break; - case MIDDLE: - if (press) { - state.pressButton(MouseEvent.BUTTON_OTHER); - } else { - state.releaseButton(MouseEvent.BUTTON_OTHER); - } - break; - case BACK: - if (press) { - state.pressButton(MouseEvent.BUTTON_BACK); - } else { - state.releaseButton(MouseEvent.BUTTON_BACK); - } - break; - case FORWARD: - if (press) { - state.pressButton(MouseEvent.BUTTON_FORWARD); - } else { - state.releaseButton(MouseEvent.BUTTON_FORWARD); - } - break; - default: throw new IllegalArgumentException("MouseButton: " + button + - " not supported by Monocle Robot"); - } - } - return state; + protected void _mouseMove(int x, int y) { + Platform.runLater(() -> { + MouseState state = new MouseState(); + MouseInput.getInstance().getState(state); + state.setX(x); + state.setY(y); + MouseInput.getInstance().setState(state, false); + }); } @Override - public void mousePress(MouseButton... buttons) { - Application.checkEventThread(); - MouseState state = new MouseState(); - MouseInput.getInstance().getState(state); - MouseInput.getInstance().setState(convertToMouseState(true, state, buttons), false); + protected void _mousePress(int buttons) { + Platform.runLater(() -> { + MouseState state = new MouseState(); + MouseInput.getInstance().getState(state); + if ((buttons & MOUSE_LEFT_BTN) != 0) { + state.pressButton(MouseEvent.BUTTON_LEFT); + } + if ((buttons & MOUSE_MIDDLE_BTN) != 0) { + state.pressButton(MouseEvent.BUTTON_OTHER); + } + if ((buttons & MOUSE_RIGHT_BTN) != 0) { + state.pressButton(MouseEvent.BUTTON_RIGHT); + } + MouseInput.getInstance().setState(state, false); + }); } @Override - public void mouseRelease(MouseButton... buttons) { - Application.checkEventThread(); - MouseState state = new MouseState(); - MouseInput.getInstance().getState(state); - MouseInput.getInstance().setState(convertToMouseState(false, state, buttons), false); + protected void _mouseRelease(int buttons) { + Platform.runLater(() -> { + MouseState state = new MouseState(); + MouseInput.getInstance().getState(state); + if ((buttons & MOUSE_LEFT_BTN) != 0) { + state.releaseButton(MouseEvent.BUTTON_LEFT); + } + if ((buttons & MOUSE_MIDDLE_BTN) != 0) { + state.releaseButton(MouseEvent.BUTTON_OTHER); + } + if ((buttons & MOUSE_RIGHT_BTN) != 0) { + state.releaseButton(MouseEvent.BUTTON_RIGHT); + } + MouseInput.getInstance().setState(state, false); + }); } @Override - public void mouseWheel(int wheelAmt) { - Application.checkEventThread(); - MouseState state = new MouseState(); - MouseInput mouse = MouseInput.getInstance(); - mouse.getState(state); - int direction = wheelAmt < 0 - ? MouseState.WHEEL_DOWN - : MouseState.WHEEL_UP; - for (int i = 0; i < Math.abs(wheelAmt); i++) { - state.setWheel(direction); - mouse.setState(state, false); - state.setWheel(MouseState.WHEEL_NONE); - mouse.setState(state, false); - } + protected void _mouseWheel(int wheelAmt) { + Platform.runLater(() -> { + MouseState state = new MouseState(); + MouseInput mouse = MouseInput.getInstance(); + mouse.getState(state); + int direction = wheelAmt < 0 + ? MouseState.WHEEL_DOWN + : MouseState.WHEEL_UP; + for (int i = 0; i < Math.abs(wheelAmt); i++) { + state.setWheel(direction); + mouse.setState(state, false); + state.setWheel(MouseState.WHEEL_NONE); + mouse.setState(state, false); + } + }); } @Override - public double getMouseX() { - Application.checkEventThread(); + protected int _getMouseX() { MouseState state = new MouseState(); MouseInput.getInstance().getState(state); return state.getX(); } @Override - public double getMouseY() { - Application.checkEventThread(); + protected int _getMouseY() { MouseState state = new MouseState(); MouseInput.getInstance().getState(state); return state.getY(); } @Override - public Color getPixelColor(double x, double y) { - Application.checkEventThread(); + protected int _getPixelColor(int x, int y) { NativeScreen screen = NativePlatformFactory.getNativePlatform().getScreen(); final int byteDepth = screen.getDepth() >>> 3; final int bwidth = screen.getWidth(); final int bheight = screen.getHeight(); if (x < 0 || x > bwidth || y < 0 || y > bheight) { - return GlassRobot.convertFromIntArgb(0); + return 0; } synchronized (NativeScreen.framebufferSwapLock) { @@ -189,29 +160,30 @@ public Color getPixelColor(double x, double y) { if (byteDepth == 2) { ShortBuffer shortbuf = buffer.asShortBuffer(); - int v = shortbuf.get((int) (y * bwidth) + (int) x); - int red = (v & 0xF800) >> 11 << 3; - int green = (v & 0x7E0) >> 5 << 2; - int blue = (v & 0x1F) << 3; + int v = shortbuf.get((y * bwidth) + x); + int red = (int) ((v & 0xF800) >> 11) << 3; + int green = (int) ((v & 0x7E0) >> 5) << 2; + int blue = (int) (v & 0x1F) << 3; int p = (0xff000000 | (red << 16) | (green << 8) | blue); - return GlassRobot.convertFromIntArgb(p); + return p; } else if (byteDepth >= 4) { IntBuffer intbuf = buffer.asIntBuffer(); - return GlassRobot.convertFromIntArgb(intbuf.get((int) (y * bwidth) + (int) x)); + return intbuf.get((y * bwidth) + x); } else { - throw new RuntimeException("Unknown bit depth: " + byteDepth); + throw new RuntimeException("Unknown bit depth"); } } } @Override - public void getScreenCapture(int x, int y, int width, int height, int[] data, boolean scaleToFit) { - Application.checkEventThread(); + protected Pixels _getScreenCapture(int x, int y, int width, int height, + boolean isHiDPI) { NativeScreen screen = NativePlatformFactory.getNativePlatform().getScreen(); + final int byteDepth = screen.getDepth() >>> 3; final int scrWidth = screen.getWidth(); final int scrHeight = screen.getHeight(); @@ -219,18 +191,20 @@ public void getScreenCapture(int x, int y, int width, int height, int[] data, bo IntBuffer buffer = screen.getScreenCapture().asIntBuffer(); if (x == 0 && y == 0 && width == scrWidth && height == scrHeight) { - // Easy case, the entire screen is being captured. - System.arraycopy(buffer.array(), 0, data, 0, buffer.array().length); - return; + return new MonoclePixels(width, height, buffer); } + IntBuffer ret = IntBuffer.allocate(width * height); int rowStop = Math.min(y + height, scrHeight); int colStop = Math.min(x + width, scrWidth); for (int row = y; row < rowStop; row++) { for (int col = x; col < colStop; col++) { - data[(row - y) * (colStop - x) + (col - x)] = buffer.get(row * scrWidth + col); + ret.put(buffer.get(row * scrWidth + col)); } } + + ret.rewind(); + return new MonoclePixels(width, height, ret); } } } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java b/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java index f064f39..385db87 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,7 +112,7 @@ protected void _setBounds(long nativeWindowPointer, if (h > 0) { //window height surpass window content height(ch) height = h; - } else if (ch > 0) { + } else if (cw > 0) { //content height changed height = ch; } else { diff --git a/src/main/java/com/sun/glass/ui/monocle/MouseState.java b/src/main/java/com/sun/glass/ui/monocle/MouseState.java index 9ff3591..2358277 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MouseState.java +++ b/src/main/java/com/sun/glass/ui/monocle/MouseState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,12 +115,6 @@ int getModifiers() { case MouseEvent.BUTTON_RIGHT: modifiers |= KeyEvent.MODIFIER_BUTTON_SECONDARY; break; - case MouseEvent.BUTTON_BACK: - modifiers |= KeyEvent.MODIFIER_BUTTON_BACK; - break; - case MouseEvent.BUTTON_FORWARD: - modifiers |= KeyEvent.MODIFIER_BUTTON_FORWARD; - break; } } return modifiers; diff --git a/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java b/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java index 3555110..b4ff676 100644 --- a/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -275,7 +275,6 @@ public void run() { final MouseState state = new MouseState(); state.setX(x); state.setY(y); - // These values are from RFC 6143 Section 7.5.5. if (buttons.get(0)) { state.pressButton(MouseEvent.BUTTON_LEFT); } @@ -285,20 +284,6 @@ public void run() { if (buttons.get(2)) { state.pressButton(MouseEvent.BUTTON_RIGHT); } - if (buttons.get(3)) { - state.setWheel(MouseState.WHEEL_UP); - } - if (buttons.get(4)) { - state.setWheel(MouseState.WHEEL_DOWN); - } - // TODO: Buttons from here on are not officially mentioned in the docs, can someone confirm - // on a real device? - if (buttons.get(5)) { - state.pressButton(MouseEvent.BUTTON_BACK); - } - if (buttons.get(6)) { - state.pressButton(MouseEvent.BUTTON_FORWARD); - } Platform.runLater(() -> MouseInput.getInstance().setState(state, false)); break; } diff --git a/src/main/java/com/sun/glass/ui/monocle/X.java b/src/main/java/com/sun/glass/ui/monocle/X.java index 6eda9f6..f291b1b 100644 --- a/src/main/java/com/sun/glass/ui/monocle/X.java +++ b/src/main/java/com/sun/glass/ui/monocle/X.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,10 +85,6 @@ private static void checkPermissions() { static final int Button3 = 3; static final int Button4 = 4; static final int Button5 = 5; - // 4th button (aka browser backward button). - static final int Button8 = 8; - // 5th button (aka browser forward button). - static final int Button9 = 9; static final long _NET_WM_STATE_REMOVE = 0; static final long _NET_WM_STATE_ADD = 1; diff --git a/src/main/java/com/sun/glass/ui/monocle/X11InputDeviceRegistry.java b/src/main/java/com/sun/glass/ui/monocle/X11InputDeviceRegistry.java index 73bcd67..0ff89e6 100644 --- a/src/main/java/com/sun/glass/ui/monocle/X11InputDeviceRegistry.java +++ b/src/main/java/com/sun/glass/ui/monocle/X11InputDeviceRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,8 +178,6 @@ private static int buttonToGlassButton(int button) { case X.Button1: return MouseEvent.BUTTON_LEFT; case X.Button2: return MouseEvent.BUTTON_OTHER; case X.Button3: return MouseEvent.BUTTON_RIGHT; - case X.Button8: return MouseEvent.BUTTON_BACK; - case X.Button9: return MouseEvent.BUTTON_FORWARD; default: return MouseEvent.BUTTON_NONE; } } From 62df5be9a82d705f08cab5ce80494e06027ca667 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Sat, 24 Jun 2023 19:46:34 -0600 Subject: [PATCH 02/22] Enable GitHub actions --- .github/workflows/entry.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/entry.yml b/.github/workflows/entry.yml index 4cd5cf6..8b0ed24 100644 --- a/.github/workflows/entry.yml +++ b/.github/workflows/entry.yml @@ -34,6 +34,6 @@ jobs: uses: ./.github/workflows/build.yml with: os: ubuntu-22.04 - jdk: 11 - openjfx: 11 + jdk: 8 + openjfx: 8 secrets: inherit From 75edd4bb680cd579bbd96b184c012b5da4df48c1 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Sat, 24 Jun 2023 19:47:22 -0600 Subject: [PATCH 03/22] Set JDK to 8.0.372 --- .github/workflows/entry.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/entry.yml b/.github/workflows/entry.yml index 8b0ed24..c856c36 100644 --- a/.github/workflows/entry.yml +++ b/.github/workflows/entry.yml @@ -34,6 +34,6 @@ jobs: uses: ./.github/workflows/build.yml with: os: ubuntu-22.04 - jdk: 8 + jdk: 8.0.372 openjfx: 8 secrets: inherit From 36192617110460f4bf498c924a9aee2ba0ff8036 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Fri, 30 Jun 2023 10:28:58 -0600 Subject: [PATCH 04/22] Fix gradle build for JDK 8 --- build.gradle | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/build.gradle b/build.gradle index e0a369c..9f6dc25 100644 --- a/build.gradle +++ b/build.gradle @@ -5,15 +5,8 @@ buildscript { url "https://plugins.gradle.org/m2/" } } - -// dependencies { -// classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4" -// classpath 'org.openjfx:javafx-plugin:0.0.7' -// } } -//apply plugin: 'org.openjfx.javafxplugin' - // print welcome message. apply from: rootProject.file("gradle/welcome.gradle") @@ -51,18 +44,10 @@ repositories { mavenCentral() } -//javafx { -// modules = [ 'javafx.controls', 'javafx.graphics' ] -// version = '12.0.1' -//} - // java language level. sourceCompatibility = "8" targetCompatibility = "8" -// configure publish tasks. -//apply from: rootProject.file("gradle/publish-bintray.gradle") - // task to create jar with source code. task("sourceJar", type: Jar) { group "Build" @@ -91,11 +76,6 @@ artifacts { compileJava { javadoc { options.addStringOption("Xdoclint:none", "-quiet") -// options.addMultilineStringsOption('-add-exports').setValue(['javafx.graphics/com.sun.glass.ui=ALL-UNNAMED', -// 'javafx.graphics/com.sun.glass.events=ALL-UNNAMED', -// 'javafx.graphics/com.sun.glass.ui.delegate=ALL-UNNAMED', -// 'javafx.graphics/com.sun.glass.utils=ALL-UNNAMED', -// 'javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED',]) } } From bb2e5066cba1f8bdb0399d125aebbff58d841cd5 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Fri, 30 Jun 2023 10:30:15 -0600 Subject: [PATCH 05/22] Fix gradle build for JDK 8 --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9f6dc25..99d8d2c 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,6 @@ wrapper { // task to print gradle and groovy versions. task("versions", group: "help").doLast { println "Java version: ${System.properties["java.version"]}" - println "JavaFX version: ${System.properties["javafx.version"]}" println "Gradle version: ${gradle.gradleVersion}" println "Groovy version: ${GroovySystem.version}" } From 86ec055477d2927ff49e1b7ba94a72b3211eac4c Mon Sep 17 00:00:00 2001 From: msoderquist Date: Thu, 28 Sep 2023 12:19:51 -0600 Subject: [PATCH 06/22] Initial release script --- scripts/release.sh | 193 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100755 scripts/release.sh diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..07fdad4 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,193 @@ +#!/usr/bin/env bash +set -eu -o pipefail + +function cleanup { + EXIT_CODE=$? + set +e # disable termination on error + if [[ $EXIT_CODE != 0 ]]; then + # Something went wrong... + originMessage=$(git log -1 HEAD --pretty=format:%s) + if [ ! -z ${newVersion+x} ]; then + if [ "$originMessage" == "(release) TestFX $newVersion" ]; then + # Roll back the commit + git reset --hard HEAD^ + else + # Didn't actually make a commit, so just reset local work-tree + git reset --hard HEAD + fi + + # Check if we pushed this commit to upstream + upstreamMessage=$(git log "$upstream"/master -1 HEAD --pretty=format:%s) + if [ "$upstreamMessage" == "(release) TestFX $newVersion" ]; then + git push upstream master --force + fi + + # Check if we tagged the commit + if git ls-remote --tags "$upstream" | grep \""$newVersion"\"; then + git push origin :"$newVersion" + fi + fi + fi + exit $EXIT_CODE +} +trap cleanup EXIT INT TERM # Are all three of these the right choice? + +# Usage info +show_help() { +cat << EOF +Usage: ${0##*/} [-h] +Helper for issuing a new release of TestFX. + +Requires a Github API key for the TestFX repository. + +You can skip manually entering the API key be specifying +the \$TESTFX_GITHUB_API_KEY environment variable. + +Options: + -h / --help display this help and exit +EOF +} + +if [[ $# -gt 0 ]]; then + if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then + show_help + exit 0 + else + show_help + exit 1 + fi +fi + +if ! [ -x "$(command -v git)" ]; then + echo 'Error: git is not installed.' >&2 + exit 1 +fi + +if ! [ -x "$(command -v ruby)" ]; then + echo 'Error: ruby is not installed (needed to generate changelog).' >&2 + exit 1 +fi + +if [ "$(gem list -i github_changelog_generator)" != true ]; then + echo 'Error: github_changelog_generator is not installed).' >&2 + echo 'Run \"[sudo] gem install github_changelog_generator\" to install it.' >&2 +fi + +if [[ ! $(git rev-parse --show-toplevel 2>/dev/null) = "$PWD" ]]; then + echo "You are not currently at the root of the TestFX git repository." + exit +fi + +if [ -z "${TESTFX_GITHUB_API_KEY-}" ]; then + echo "\"TESTFX_GITHUB_API_KEY\" environment variable not set" + read -rp "Please enter your Github API key for TestFX: " githubApiKey +else + githubApiKey="$TESTFX_GITHUB_API_KEY" +fi + +currentVersion=$(git tag --list --sort=taggerdate | grep 'v*[0-9].*[0-9].*[0-9]' | tail -n1) + +# echo "Current version of TestFX: $currentVersion" +# IFS='.' read -ra version_parts <<< "$currentVersion" +# IFS='-' read -ra classifier_parts <<< "$currentVersion" + +# major=${version_parts[0]:1} +# minor=${version_parts[1]} +# patch=${version_parts[2]%%-*} +# classifier=${classifier_parts[1]} + +# echo "major: $major" +# echo "minor: $minor" +# echo "patch: $patch" +# echo "classifier: $classifier" + +# echo "Would you like to bump the major, minor, or patch version?" +# echo "In x.y.z x = major, y = minor, z = patch" +# echo "Enter the number corresponding to the part you want to increment:" +# options=("Major" "Minor" "Patch"); + +# select bumpType in "${options[@]}"; do +# case $bumpType in +# "Major") major=$((major + 1)); break;; +# "Minor") minor=$((minor + 1)); break;; +# "Patch") patch=$((patch + 1)); break;; +# *) echo "Invalid option"; break;; +# esac +# done + +# newVersion="v$major.$minor.$patch-$classifier" +# echo "The next release of TestFX will be: $newVersion" +# echo "Bumping version in gradle.properties to ${newVersion:1}" +# sed -i "/version =/ s/=.*/= ${newVersion:1}/" gradle.properties +# echo "Replacing ${currentVersion:1} with ${newVersion:1} in README.md..." +# sed -i -e "s/${currentVersion:1}/${newVersion:1}/g" README.md +# echo "Generating changelog..." +# github_changelog_generator -u testfx -p testfx --token "$githubApiKey" \ +# --output CHANGES.md --no-issues \ +# --future-release "$newVersion" +# git commit -am "(release) TestFX $newVersion" +# upstream=$(git remote -v | awk '$2 ~ /github.com[:\/]testfx\/testfx/ && $3 == "(fetch)" {print $1; exit}') +# if [[ -z "$upstream" ]]; then +# echo "Could not find a git remote for the upstream TestFX repository." +# echo "See: https://github.com/TestFX/TestFX/wiki/Issuing-a-Release#local-git-repository-setup" +# exit 1 +# fi +# echo "Pushing tagged release commit to remote: $upstream" +# git push "$upstream" master +# git fetch "$upstream" +# git rebase "$upstream"/master + +# # Find GPG key that has "(TestFX)" in its' name +# gpgKey=$(gpg --list-keys --with-colon | grep '^pub' | grep '(TestFX)' | cut -d':' -f5) +# if [[ -z "$gpgKey" ]]; then +# echo "Could not find a GPG key with (TestFX) in its' name." +# echo "See: https://github.com/TestFX/TestFX/wiki/Issuing-a-Release#create-a-testfx-gpg-key" +# exit 1 +# fi +# git tag -s "$newVersion" -m \""$newVersion"\" -u "$gpgKey" +# git push upstream "$newVersion" + +# # The below method uses a pull request, keep it in case we change our mind. +# if false ; then +# git push origin "$newVersion"-release + +# installedHub=false +# if ! [ -x "$(command -v hub)" ]; then +# if [[ "$OSTYPE" == "darwin"* ]]; then +# echo "Installing hub (command-line Github tool) via Homebrew" +# brew install hub +# installedHub=true +# elif [[ "$OSTYPE" == "linux-gnu" ]]; then +# if ! [ -x "$(command -v dnf)" ]; then +# echo "Installing hub (command-line Github tool) via dnf" +# sudo dnf install hub +# installedHub=true +# fi +# fi + +# if [ "$installedHub" = false ] ; then +# echo "Downloading hub (command-line Github tool)" +# wget --quiet --output-document=hub.tgz https://github.com/github/hub/releases/download/v2.3.0-pre10/hub-linux-amd64-2.3.0-pre10.tgz +# if [[ $(sha256sum hub.tgz | head -c 64) != "015297eb81e8fe11f3989d8f65c213111e508cecf0e9de8af1b7741de2077320" ]]; then +# echo "Error (integrity): hub release download had bad checksum: $(sha256sum hub.tgz | head -c 64)" >&2 +# exit +# fi +# mkdir hub-dir +# tar -xf hub.tgz -C hub-dir --strip-components 1 +# rm hub.tgz +# mkdir -p .sync +# cp ./hub-dir/bin/hub .sync/ +# rm -r hub-dir +# hub='./.sync/hub' +# fi +# fi + +# hub='hub' +# if [ "$installedHub" = false ] ; then +# hub='./.sync/hub' +# fi + +# "${hub}" pull-request -o -m "$newVersion" -b "$upstream:master" +# fi + +# vim :set ts=2 sw=2 sts=2 et: From eec629ca0bc639bd1b2b6c3575c465f1243d5a95 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Thu, 28 Sep 2023 12:33:10 -0600 Subject: [PATCH 07/22] Initial bundle script --- scripts/bundle.sh | 100 +++++++++++++++++++++++ scripts/release.sh | 193 --------------------------------------------- 2 files changed, 100 insertions(+), 193 deletions(-) create mode 100755 scripts/bundle.sh delete mode 100755 scripts/release.sh diff --git a/scripts/bundle.sh b/scripts/bundle.sh new file mode 100755 index 0000000..705f678 --- /dev/null +++ b/scripts/bundle.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +# This script was derived from instructions found at https://central.sonatype.org/publish/publish-manual/#bundle-creation + +set -ue -o pipefail + +function cleanup { + EXIT_CODE=$? + set +e # disable termination on error +# if [[ $EXIT_CODE != 0 ]]; then +# # Logic to clean up from script +# fi + exit $EXIT_CODE +} +trap cleanup EXIT INT TERM # Are all three of these the right choice? + +# Usage info +show_help() { +cat << EOF +Usage: ${0##*/} [-h] +Helper for deploying a signed maven bundle of TestFX to Maven Central. + +Prerequisites: +- gpg - PGP encryption and signing tool + +Requires a Maven key for the TestFX repository. + +Options: + -h / --help display this help and exit +EOF +} + +# Show the help information +if [[ $# -gt 0 ]]; then + if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then + show_help + exit 0 + else + show_help + exit 1 + fi +fi + +# Check if the user is at the root level of the project +if [[ ! $(git rev-parse --show-toplevel 2>/dev/null) = "$PWD" ]]; then + echo "You are not currently at the root of the TestFX git repository." + exit +fi + +# Check if gpg is installed +if ! [ -x "$(command -v gpg)" ]; then + echo 'Error: gpg is not installed.' >&2 + exit 1 +fi + +# Determine which gpg key to use +gpgKey=$(gpg --list-keys --with-colon | grep '^uid' | grep '(TestFX)' | cut -d':' -f10) +if [[ -z "$gpgKey" ]]; then + echo "Could not find a GPG key with (TestFX) in its' name." + echo "See: https://github.com/TestFX/TestFX/wiki/Issuing-a-Release#create-a-testfx-gpg-key" + exit 1 +fi + +sign() { + libsPath=build/libs + + # Remove prior files + rm -f "$libsPath"/*.asc + + # Determine which gpg key to use + gpgKey=$(gpg --list-keys --with-colon | grep '^uid' | grep '(TestFX)' | cut -d':' -f10) + + # Sign each file in the libs folder + for file in $libsPath/*; do + echo Sign $file + gpg -ab --batch -u "$gpgKey" $file + done +} + +bundle() { + libsPath=build/libs + bundle="$1-bundle.jar" + target="build/bundles/" + + mkdir -p "$target" + + echo Create bundle + cd $libsPath || exit + rm -f bundle* + jar -cvf "$bundle" ./* + cd - || exit + + cp "$libsPath/$bundle" "$target" + + echo Bundle created "$target/$bundle" +} + +sign monocle +bundle monocle + diff --git a/scripts/release.sh b/scripts/release.sh deleted file mode 100755 index 07fdad4..0000000 --- a/scripts/release.sh +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -function cleanup { - EXIT_CODE=$? - set +e # disable termination on error - if [[ $EXIT_CODE != 0 ]]; then - # Something went wrong... - originMessage=$(git log -1 HEAD --pretty=format:%s) - if [ ! -z ${newVersion+x} ]; then - if [ "$originMessage" == "(release) TestFX $newVersion" ]; then - # Roll back the commit - git reset --hard HEAD^ - else - # Didn't actually make a commit, so just reset local work-tree - git reset --hard HEAD - fi - - # Check if we pushed this commit to upstream - upstreamMessage=$(git log "$upstream"/master -1 HEAD --pretty=format:%s) - if [ "$upstreamMessage" == "(release) TestFX $newVersion" ]; then - git push upstream master --force - fi - - # Check if we tagged the commit - if git ls-remote --tags "$upstream" | grep \""$newVersion"\"; then - git push origin :"$newVersion" - fi - fi - fi - exit $EXIT_CODE -} -trap cleanup EXIT INT TERM # Are all three of these the right choice? - -# Usage info -show_help() { -cat << EOF -Usage: ${0##*/} [-h] -Helper for issuing a new release of TestFX. - -Requires a Github API key for the TestFX repository. - -You can skip manually entering the API key be specifying -the \$TESTFX_GITHUB_API_KEY environment variable. - -Options: - -h / --help display this help and exit -EOF -} - -if [[ $# -gt 0 ]]; then - if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then - show_help - exit 0 - else - show_help - exit 1 - fi -fi - -if ! [ -x "$(command -v git)" ]; then - echo 'Error: git is not installed.' >&2 - exit 1 -fi - -if ! [ -x "$(command -v ruby)" ]; then - echo 'Error: ruby is not installed (needed to generate changelog).' >&2 - exit 1 -fi - -if [ "$(gem list -i github_changelog_generator)" != true ]; then - echo 'Error: github_changelog_generator is not installed).' >&2 - echo 'Run \"[sudo] gem install github_changelog_generator\" to install it.' >&2 -fi - -if [[ ! $(git rev-parse --show-toplevel 2>/dev/null) = "$PWD" ]]; then - echo "You are not currently at the root of the TestFX git repository." - exit -fi - -if [ -z "${TESTFX_GITHUB_API_KEY-}" ]; then - echo "\"TESTFX_GITHUB_API_KEY\" environment variable not set" - read -rp "Please enter your Github API key for TestFX: " githubApiKey -else - githubApiKey="$TESTFX_GITHUB_API_KEY" -fi - -currentVersion=$(git tag --list --sort=taggerdate | grep 'v*[0-9].*[0-9].*[0-9]' | tail -n1) - -# echo "Current version of TestFX: $currentVersion" -# IFS='.' read -ra version_parts <<< "$currentVersion" -# IFS='-' read -ra classifier_parts <<< "$currentVersion" - -# major=${version_parts[0]:1} -# minor=${version_parts[1]} -# patch=${version_parts[2]%%-*} -# classifier=${classifier_parts[1]} - -# echo "major: $major" -# echo "minor: $minor" -# echo "patch: $patch" -# echo "classifier: $classifier" - -# echo "Would you like to bump the major, minor, or patch version?" -# echo "In x.y.z x = major, y = minor, z = patch" -# echo "Enter the number corresponding to the part you want to increment:" -# options=("Major" "Minor" "Patch"); - -# select bumpType in "${options[@]}"; do -# case $bumpType in -# "Major") major=$((major + 1)); break;; -# "Minor") minor=$((minor + 1)); break;; -# "Patch") patch=$((patch + 1)); break;; -# *) echo "Invalid option"; break;; -# esac -# done - -# newVersion="v$major.$minor.$patch-$classifier" -# echo "The next release of TestFX will be: $newVersion" -# echo "Bumping version in gradle.properties to ${newVersion:1}" -# sed -i "/version =/ s/=.*/= ${newVersion:1}/" gradle.properties -# echo "Replacing ${currentVersion:1} with ${newVersion:1} in README.md..." -# sed -i -e "s/${currentVersion:1}/${newVersion:1}/g" README.md -# echo "Generating changelog..." -# github_changelog_generator -u testfx -p testfx --token "$githubApiKey" \ -# --output CHANGES.md --no-issues \ -# --future-release "$newVersion" -# git commit -am "(release) TestFX $newVersion" -# upstream=$(git remote -v | awk '$2 ~ /github.com[:\/]testfx\/testfx/ && $3 == "(fetch)" {print $1; exit}') -# if [[ -z "$upstream" ]]; then -# echo "Could not find a git remote for the upstream TestFX repository." -# echo "See: https://github.com/TestFX/TestFX/wiki/Issuing-a-Release#local-git-repository-setup" -# exit 1 -# fi -# echo "Pushing tagged release commit to remote: $upstream" -# git push "$upstream" master -# git fetch "$upstream" -# git rebase "$upstream"/master - -# # Find GPG key that has "(TestFX)" in its' name -# gpgKey=$(gpg --list-keys --with-colon | grep '^pub' | grep '(TestFX)' | cut -d':' -f5) -# if [[ -z "$gpgKey" ]]; then -# echo "Could not find a GPG key with (TestFX) in its' name." -# echo "See: https://github.com/TestFX/TestFX/wiki/Issuing-a-Release#create-a-testfx-gpg-key" -# exit 1 -# fi -# git tag -s "$newVersion" -m \""$newVersion"\" -u "$gpgKey" -# git push upstream "$newVersion" - -# # The below method uses a pull request, keep it in case we change our mind. -# if false ; then -# git push origin "$newVersion"-release - -# installedHub=false -# if ! [ -x "$(command -v hub)" ]; then -# if [[ "$OSTYPE" == "darwin"* ]]; then -# echo "Installing hub (command-line Github tool) via Homebrew" -# brew install hub -# installedHub=true -# elif [[ "$OSTYPE" == "linux-gnu" ]]; then -# if ! [ -x "$(command -v dnf)" ]; then -# echo "Installing hub (command-line Github tool) via dnf" -# sudo dnf install hub -# installedHub=true -# fi -# fi - -# if [ "$installedHub" = false ] ; then -# echo "Downloading hub (command-line Github tool)" -# wget --quiet --output-document=hub.tgz https://github.com/github/hub/releases/download/v2.3.0-pre10/hub-linux-amd64-2.3.0-pre10.tgz -# if [[ $(sha256sum hub.tgz | head -c 64) != "015297eb81e8fe11f3989d8f65c213111e508cecf0e9de8af1b7741de2077320" ]]; then -# echo "Error (integrity): hub release download had bad checksum: $(sha256sum hub.tgz | head -c 64)" >&2 -# exit -# fi -# mkdir hub-dir -# tar -xf hub.tgz -C hub-dir --strip-components 1 -# rm hub.tgz -# mkdir -p .sync -# cp ./hub-dir/bin/hub .sync/ -# rm -r hub-dir -# hub='./.sync/hub' -# fi -# fi - -# hub='hub' -# if [ "$installedHub" = false ] ; then -# hub='./.sync/hub' -# fi - -# "${hub}" pull-request -o -m "$newVersion" -b "$upstream:master" -# fi - -# vim :set ts=2 sw=2 sts=2 et: From fce76e451b4d8ba635da5acf31e9a6e3c7fc762e Mon Sep 17 00:00:00 2001 From: msoderquist Date: Thu, 28 Sep 2023 13:14:12 -0600 Subject: [PATCH 08/22] Include gradle script to publish a pom --- build.gradle | 12 +-- gradle.properties | 3 + gradle/publish-pom.gradle | 95 ++++++++++++++++++++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 gradle/publish-pom.gradle diff --git a/build.gradle b/build.gradle index d2d3ced..fe45b09 100644 --- a/build.gradle +++ b/build.gradle @@ -1,24 +1,24 @@ buildscript { repositories { - jcenter() + mavenCentral() maven { url "https://plugins.gradle.org/m2/" } } dependencies { - classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4" classpath 'org.openjfx:javafx-plugin:0.0.7' } } apply plugin: 'org.openjfx.javafxplugin' +apply plugin: 'maven' // print welcome message. apply from: rootProject.file("gradle/welcome.gradle") wrapper { - gradleVersion = '5.4.1' + gradleVersion = '6.5.1' distributionUrl = "https://services.gradle.org/distributions/" + "gradle-${gradleVersion}-bin.zip" } @@ -47,7 +47,7 @@ task("initSourceDirs", group: "build setup").doLast { apply plugin: "java" repositories { - jcenter() + mavenCentral() } javafx { @@ -60,7 +60,7 @@ sourceCompatibility = "9" targetCompatibility = "9" // configure publish tasks. -apply from: rootProject.file("gradle/publish-bintray.gradle") +apply from: rootProject.file("gradle/publish-pom.gradle") // task to create jar with source code. task("sourceJar", type: Jar) { @@ -78,6 +78,7 @@ task("javadocJar", type: Jar) { from javadoc } +jar.finalizedBy createPom jar.finalizedBy sourceJar jar.finalizedBy javadocJar @@ -85,6 +86,7 @@ artifacts { archives jar archives sourceJar archives javadocJar + createPom } compileJava { diff --git a/gradle.properties b/gradle.properties index 690f811..4dd6494 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,3 +18,6 @@ bintrayUsername = bintrayApiKey = sonatypeUsername = sonatypePassword = + +pomName = 'Monocle' +pomDescription = 'Headless graphics driver for JavaFX' diff --git a/gradle/publish-pom.gradle b/gradle/publish-pom.gradle new file mode 100644 index 0000000..75a76db --- /dev/null +++ b/gradle/publish-pom.gradle @@ -0,0 +1,95 @@ +/* + * Copyright 2013-2014 SmartBear Software + * Copyright 2014-2023 The TestFX Contributors + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may + * not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence at: + * http://ec.europa.eu/idabc/eupl + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. + */ + +task createPom { + description 'Generate the artifact pom file for Maven Central' + doLast { + pom { + project { + name "${project.pomName}" + description "${project.pomDescription}" + inceptionYear '2013' + url "http://testfx.org/" + + licenses { + license([:]) { + name "European Union Public Licence, Version 1.1" + url "http://ec.europa.eu/idabc/eupl.html" + distribution "repo" + } + } + + scm { + url "https://github.com/TestFX/TestFX" + } + + developers { + developer { + id "mvsoder" + name "Mark Soderquist" + url "https://github.com/mvsoder" + timezone "-7" + roles { + role "developer" + } + } + + developer { + id "svenruppert" + name "Sven Ruppert" + url "https://github.com/svenruppert" + timezone "+1" + roles { + role "developer" + } + } + + developer { + id "minisu" + name "Henrik Olsson" + url "https://github.com/minisu" + timezone "+1" + roles { + role "former developer" + } + } + + developer { + id "dainnilsson" + name "Dain Nilsson" + url "https://github.com/dainnilsson" + timezone "+1" + roles { + role "project founder" + role "former developer" + } + } + + developer { + id "hastebrot" + name "Benjamin Gudehus" + url "https://github.com/hastebrot" + timezone "+1" + roles { + role "project maintainer" + } + } + } + } + }.writeTo("$buildDir/libs/${project.name}-${project.version}.pom") + } +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f4d7b2b..bb8b2fc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 2df8d89ce0903fbd397512d70dcd7179649b557d Mon Sep 17 00:00:00 2001 From: msoderquist Date: Thu, 28 Sep 2023 13:53:16 -0600 Subject: [PATCH 09/22] Gradle build for Maven artifacts --- build.gradle | 23 --------------- gradle.properties | 9 +++--- gradle/publish-pom.gradle | 62 ++++----------------------------------- 3 files changed, 10 insertions(+), 84 deletions(-) diff --git a/build.gradle b/build.gradle index c56684a..a891ee3 100644 --- a/build.gradle +++ b/build.gradle @@ -5,20 +5,10 @@ buildscript { url "https://plugins.gradle.org/m2/" } } -<<<<<<< HEAD } -======= - - dependencies { - classpath 'org.openjfx:javafx-plugin:0.0.7' - } -} - -apply plugin: 'org.openjfx.javafxplugin' apply plugin: 'maven' ->>>>>>> main // print welcome message. apply from: rootProject.file("gradle/welcome.gradle") @@ -53,27 +43,14 @@ apply plugin: "java" repositories { mavenCentral() -<<<<<<< HEAD } // java language level. sourceCompatibility = "8" targetCompatibility = "8" -======= -} - -javafx { - modules = [ 'javafx.controls', 'javafx.graphics' ] - version = '12.0.1' -} - -// java language level. -sourceCompatibility = "9" -targetCompatibility = "9" // configure publish tasks. apply from: rootProject.file("gradle/publish-pom.gradle") ->>>>>>> main // task to create jar with source code. task("sourceJar", type: Jar) { diff --git a/gradle.properties b/gradle.properties index 4b23f7a..643245b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,11 @@ +pomName = OpenJFX Monocle + group = org.testfx +artifact = monocle version = jdk-8.0.372 +inceptionYear = 2014 -description = Headless graphics driver for JavaFX. +description = Headless graphics driver for JavaFX vendor = The OpenJDK Community url = https://github.com/TestFX/Monocle @@ -18,6 +22,3 @@ bintrayUsername = bintrayApiKey = sonatypeUsername = sonatypePassword = - -pomName = 'Monocle' -pomDescription = 'Headless graphics driver for JavaFX' diff --git a/gradle/publish-pom.gradle b/gradle/publish-pom.gradle index 75a76db..e957db0 100644 --- a/gradle/publish-pom.gradle +++ b/gradle/publish-pom.gradle @@ -21,14 +21,14 @@ task createPom { pom { project { name "${project.pomName}" - description "${project.pomDescription}" - inceptionYear '2013' - url "http://testfx.org/" + description "${project.description}" + inceptionYear "${project.inceptionYear}" + url "https://openjfx.io/" licenses { license([:]) { - name "European Union Public Licence, Version 1.1" - url "http://ec.europa.eu/idabc/eupl.html" + name "The GNU General Public License (GPL), Version 2, June 1991" + url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html" distribution "repo" } } @@ -37,58 +37,6 @@ task createPom { url "https://github.com/TestFX/TestFX" } - developers { - developer { - id "mvsoder" - name "Mark Soderquist" - url "https://github.com/mvsoder" - timezone "-7" - roles { - role "developer" - } - } - - developer { - id "svenruppert" - name "Sven Ruppert" - url "https://github.com/svenruppert" - timezone "+1" - roles { - role "developer" - } - } - - developer { - id "minisu" - name "Henrik Olsson" - url "https://github.com/minisu" - timezone "+1" - roles { - role "former developer" - } - } - - developer { - id "dainnilsson" - name "Dain Nilsson" - url "https://github.com/dainnilsson" - timezone "+1" - roles { - role "project founder" - role "former developer" - } - } - - developer { - id "hastebrot" - name "Benjamin Gudehus" - url "https://github.com/hastebrot" - timezone "+1" - roles { - role "project maintainer" - } - } - } } }.writeTo("$buildDir/libs/${project.name}-${project.version}.pom") } From 27eb7a3732584d012f48409698c724e4b3d965c3 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Fri, 29 Sep 2023 10:34:06 -0600 Subject: [PATCH 10/22] Gradle build for Maven artifacts --- gradle.properties | 6 +++--- gradle/publish-pom.gradle | 33 +++++++++++++++++++++++++++++---- src/docs/notes.md | 11 +++++++++++ 3 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 src/docs/notes.md diff --git a/gradle.properties b/gradle.properties index 643245b..c34034f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,13 +1,13 @@ -pomName = OpenJFX Monocle - group = org.testfx artifact = monocle version = jdk-8.0.372 -inceptionYear = 2014 description = Headless graphics driver for JavaFX vendor = The OpenJDK Community +pomName = OpenJFX Monocle +pomDependencyVersion = 8.0.372 + url = https://github.com/TestFX/Monocle sourceUrl = https://github.com/TestFX/Monocle issuesUrl = https://github.com/TestFX/Monocle/issues diff --git a/gradle/publish-pom.gradle b/gradle/publish-pom.gradle index e957db0..e114eb0 100644 --- a/gradle/publish-pom.gradle +++ b/gradle/publish-pom.gradle @@ -22,21 +22,46 @@ task createPom { project { name "${project.pomName}" description "${project.description}" - inceptionYear "${project.inceptionYear}" url "https://openjfx.io/" licenses { license([:]) { - name "The GNU General Public License (GPL), Version 2, June 1991" - url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html" + name "GNU General Public License, version 2, with the Classpath Exception" + url "https://github.com/TestFX/Monocle/blob/main/LICENSE" distribution "repo" } } scm { - url "https://github.com/TestFX/TestFX" + url "https://github.com/TestFX/Monocle" } + developers { + developer { + name "The OpenJDK Community" + } + } + + dependencies { + dependency { + groupId "org.openjfx" + artifactId "javafx-base" + version "${project.pomDependencyVersion}" + scope "runtime" + } + dependency { + groupId "org.openjfx" + artifactId "javafx-controls" + version "${project.pomDependencyVersion}" + scope "runtime" + } + dependency { + groupId "org.openjfx" + artifactId "javafx-graphics" + version "${project.pomDependencyVersion}" + scope "runtime" + } + } } }.writeTo("$buildDir/libs/${project.name}-${project.version}.pom") } diff --git a/src/docs/notes.md b/src/docs/notes.md new file mode 100644 index 0000000..6653918 --- /dev/null +++ b/src/docs/notes.md @@ -0,0 +1,11 @@ +# Engineer Notes 2023-09-29 + +## Uploading Maven Bundles for Monocle + +Signed Maven bundles can be generated by building the project as usual and then +using the bundle.sh script to generate the bundle for deployment to Maven +Central. Deploying to Maven Central is done in three steps: +1. Generate the signed bundle +2. Upload the bundle to https://oss.sonatype.org +3. Approve the bundle for release + From 1b8bd8e063dd0855bafe8ced5ca26ffb36cac694 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Fri, 29 Sep 2023 10:58:38 -0600 Subject: [PATCH 11/22] Add engineer notes --- src/docs/notes.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/docs/notes.md b/src/docs/notes.md index 6653918..300c048 100644 --- a/src/docs/notes.md +++ b/src/docs/notes.md @@ -1,11 +1,22 @@ # Engineer Notes 2023-09-29 +## Create Signed Bundle +Signed Maven bundles can be generated by building the project as usual and then +using the bundle.sh script to generate the bundle for deployment to Maven +Central. + ## Uploading Maven Bundles for Monocle +1. Sign in to https://oss.sonatype.org (TestFX artifacts are hosted on the old oss.sontatype.org server) +2. In the guide on the left click on 'Staging Upload' +3. For 'Upload Mode' choose 'Artifact Bundle' +4. Click the 'Select Bundle to Upload...' button +5. Navigate to and select the signed bundle on your local machine +6. Click the 'Upload Bundle' button + +After the bundle is uploaded, Maven Central will process the bundle. The results of the upload and processing can be viewed by +1. In the guide on the left click on 'Staging Repositories' +2. Select the repository corresponding to the bundle upload +3. In the tabbed pane select the 'Activity' tab +4. Review the actions taken and resolve any issues found -Signed Maven bundles can be generated by building the project as usual and then -using the bundle.sh script to generate the bundle for deployment to Maven -Central. Deploying to Maven Central is done in three steps: -1. Generate the signed bundle -2. Upload the bundle to https://oss.sonatype.org -3. Approve the bundle for release From f53fd0579f8446abe6cf0537bf057082ccadbc98 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Fri, 29 Sep 2023 13:36:03 -0600 Subject: [PATCH 12/22] Update developer notes --- src/docs/notes.md | 48 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/docs/notes.md b/src/docs/notes.md index 300c048..af4f65b 100644 --- a/src/docs/notes.md +++ b/src/docs/notes.md @@ -1,9 +1,55 @@ # Engineer Notes 2023-09-29 +## Updating the Monocle Code +Monocle is an OpenJFX project. When JavaFX was part of the JDK in Java 8, +the Monocle code was found in the OpenJDK code base. JavaFX was then moved to a +stand-alone module by Java 11. Therefore, when updating the Monocle code there are +separate locations for Java 8 and Java 11+. + +### Java 11+ Monocle Code + +The following table links the Git branch for each LTS release. It is more +appropriate to use the tag for a specific release, but these links will help +you get started. + +| LTS | Java Code | Resources | +|-----------|-----------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------| +| JavaFX 21 | [Java Code](https://github.com/openjdk/jfx/tree/jfx21/modules/javafx.graphics/src/main/java/com/sun/glass/ui/monocle) | [Resources](https://github.com/openjdk/jfx/tree/jfx21/modules/javafx.graphics/src/main/resources/com/sun/glass/ui/monocle) | +| JavaFX 17 | [Java Code](https://github.com/openjdk/jfx/tree/jfx17/modules/javafx.graphics/src/main/java/com/sun/glass/ui/monocle) | [Resources](https://github.com/openjdk/jfx/tree/jfx17/modules/javafx.graphics/src/main/resources/com/sun/glass/ui/monocle) | +| JavaFX 11 | [Java Code](https://github.com/openjdk/jfx/tree/jfx11/modules/javafx.graphics/src/main/java/com/sun/glass/ui/monocle) | [Resources](https://github.com/openjdk/jfx/tree/jfx11/modules/javafx.graphics/src/main/resources/com/sun/glass/ui/monocle) | + +Note that some JavaFX 8 tags are also in this repository. They are for very old +versions and should not be needed. + +### Java 8 Monocle Code + +Source code for Monocle in Java 8 is a bit harder to find. Many distributions +no longer include JavaFX even with a Java 8 build. BellSoft Liberica seems to +be the most reasonable to work with: https://bell-sw.com/libericajdk/ + +1. Navigate to BellSoft Liberica Download Center: https://bell-sw.com/pages/downloads/ +2. In the section 'DownloadLiberica JDK' select 'JDK 8 LTS' +3. Click the 'Source Code' link to download an archive of the source code +4. Unpack the source code archive +5. The Java code is in `openjfx/modules/graphics/src/main/java/com/sun/glass/ui/monocle` +6. The resources are in `openjfx/modules/graphics/src/main/resources/com/sun/glass/ui/monocle` + +Prior versions can be found by using the 'All versions' link going back to JDK 8u202+8. + +#### For Reference +The JavaFX releases available on GitHub +- openjdk/jfx: 8.0-b52 to 8u60-b08 +- openjdk/jdk: jdk8-b01 to jdk8-b120 + + ## Create Signed Bundle Signed Maven bundles can be generated by building the project as usual and then using the bundle.sh script to generate the bundle for deployment to Maven Central. +1. On your local machine, navigate to the project home +2. Execute `./gradle clean build` +3. Execute `scripts/bundle.sh` +4. The signed bundle is located in the `build/bundles` folder. ## Uploading Maven Bundles for Monocle 1. Sign in to https://oss.sonatype.org (TestFX artifacts are hosted on the old oss.sontatype.org server) @@ -18,5 +64,3 @@ After the bundle is uploaded, Maven Central will process the bundle. The results 2. Select the repository corresponding to the bundle upload 3. In the tabbed pane select the 'Activity' tab 4. Review the actions taken and resolve any issues found - - From 29d4e162af7e0300b68aa344f4ed1535aabda3f6 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Fri, 29 Sep 2023 15:18:11 -0600 Subject: [PATCH 13/22] Start work on Monocle 11 build --- build.gradle | 4 +- gradle.properties | 4 +- gradle/publish-pom.gradle | 6 +- src/docs/notes.md | 6 + .../glass/ui/monocle/MonocleApplication.java | 69 ++---- .../sun/glass/ui/monocle/MonoclePixels.java | 6 +- .../sun/glass/ui/monocle/MonocleRobot.java | 204 +++++++++--------- .../sun/glass/ui/monocle/MonocleTimer.java | 5 +- 8 files changed, 145 insertions(+), 159 deletions(-) diff --git a/build.gradle b/build.gradle index a891ee3..0c9b9ca 100644 --- a/build.gradle +++ b/build.gradle @@ -46,8 +46,8 @@ repositories { } // java language level. -sourceCompatibility = "8" -targetCompatibility = "8" +sourceCompatibility = "11" +targetCompatibility = "11" // configure publish tasks. apply from: rootProject.file("gradle/publish-pom.gradle") diff --git a/gradle.properties b/gradle.properties index c34034f..9082760 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,12 @@ group = org.testfx artifact = monocle -version = jdk-8.0.372 +version = 11.0.2 description = Headless graphics driver for JavaFX vendor = The OpenJDK Community pomName = OpenJFX Monocle -pomDependencyVersion = 8.0.372 +pomDependencyVersion = 11.0.2 url = https://github.com/TestFX/Monocle sourceUrl = https://github.com/TestFX/Monocle diff --git a/gradle/publish-pom.gradle b/gradle/publish-pom.gradle index e114eb0..07377b3 100644 --- a/gradle/publish-pom.gradle +++ b/gradle/publish-pom.gradle @@ -47,19 +47,19 @@ task createPom { groupId "org.openjfx" artifactId "javafx-base" version "${project.pomDependencyVersion}" - scope "runtime" + scope "provided" } dependency { groupId "org.openjfx" artifactId "javafx-controls" version "${project.pomDependencyVersion}" - scope "runtime" + scope "provided" } dependency { groupId "org.openjfx" artifactId "javafx-graphics" version "${project.pomDependencyVersion}" - scope "runtime" + scope "provided" } } } diff --git a/src/docs/notes.md b/src/docs/notes.md index af4f65b..2f5d80c 100644 --- a/src/docs/notes.md +++ b/src/docs/notes.md @@ -8,6 +8,12 @@ separate locations for Java 8 and Java 11+. ### Java 11+ Monocle Code +Source code for Monocle 11+ can be found in several places. + +#### Maven +https://repo1.maven.org/maven2/org/openjfx/javafx-graphics + +#### GitHub The following table links the Git branch for each LTS release. It is more appropriate to use the tag for a specific release, but these links will help you get started. diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java b/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java index 31ec9ca..b45422f 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,8 +28,8 @@ import com.sun.glass.ui.CommonDialogs.ExtensionFilter; import com.sun.glass.ui.CommonDialogs.FileChooserResult; import com.sun.glass.ui.Cursor; +import com.sun.glass.ui.GlassRobot; import com.sun.glass.ui.Pixels; -import com.sun.glass.ui.Robot; import com.sun.glass.ui.Screen; import com.sun.glass.ui.Size; import com.sun.glass.ui.Timer; @@ -38,7 +38,6 @@ import javafx.collections.SetChangeListener; import java.io.File; -import java.lang.reflect.Constructor; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.security.AccessController; @@ -198,8 +197,9 @@ public Pixels createPixels(int width, int height, IntBuffer data) { @Override public Pixels createPixels(int width, int height, IntBuffer data, - float scale) { - return new MonoclePixels(width, height, data, scale); + float scalex, float scaley) + { + return new MonoclePixels(width, height, data, scalex, scaley); } @Override @@ -208,7 +208,7 @@ protected int staticPixels_getNativeFormat() { } @Override - public Robot createRobot() { + public GlassRobot createRobot() { return new MonocleRobot(); } @@ -219,49 +219,20 @@ protected double staticScreen_getVideoRefreshPeriod() { @Override protected Screen[] staticScreen_getScreens() { - Screen screen = null; - try { - NativeScreen ns = platform.getScreen(); - Constructor c = AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public Constructor run() { - try { - Constructor c = Screen.class.getDeclaredConstructor( - Long.TYPE, - Integer.TYPE, - Integer.TYPE, Integer.TYPE, - Integer.TYPE, Integer.TYPE, - Integer.TYPE, Integer.TYPE, - Integer.TYPE, Integer.TYPE, - Integer.TYPE, Integer.TYPE, Float.TYPE); - c.setAccessible(true); - return c; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - }); - if (c != null) { - screen = (Screen) c.newInstance( - 1l, // dummy native pointer; - ns.getDepth(), - 0, 0, ns.getWidth(), ns.getHeight(), - 0, 0, ns.getWidth(), ns.getHeight(), - ns.getDPI(), ns.getDPI(), - ns.getScale()); - // Move the cursor to the middle of the screen - MouseState mouseState = new MouseState(); - mouseState.setX(ns.getWidth() / 2); - mouseState.setY(ns.getHeight() / 2); - MouseInput.getInstance().setState(mouseState, false); - } - } catch (Exception e) { - e.printStackTrace(); - } catch (UnsatisfiedLinkError e) { - e.printStackTrace(); - } + NativeScreen ns = platform.getScreen(); + Screen screen = new Screen(1l, // dummy native pointer; + ns.getDepth(), + 0, 0, ns.getWidth(), ns.getHeight(), + 0, 0, ns.getWidth(), ns.getHeight(), + 0, 0, ns.getWidth(), ns.getHeight(), + ns.getDPI(), ns.getDPI(), + ns.getScale(), ns.getScale(), + ns.getScale(), ns.getScale()); + // Move the cursor to the middle of the screen + MouseState mouseState = new MouseState(); + mouseState.setX(ns.getWidth() / 2); + mouseState.setY(ns.getHeight() / 2); + MouseInput.getInstance().setState(mouseState, false); return new Screen[] { screen }; } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java b/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java index bbce23c..bbb17ce 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,8 +41,8 @@ final class MonoclePixels extends Pixels { super(width, height, data); } - MonoclePixels(int width, int height, IntBuffer data, float scale) { - super(width, height, data, scale); + MonoclePixels(int width, int height, IntBuffer data, float scalex, float scaley) { + super(width, height, data, scalex, scaley); } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java b/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java index f982a2e..6d3451f 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,132 +25,147 @@ package com.sun.glass.ui.monocle; -import com.sun.glass.events.MouseEvent; -import com.sun.glass.ui.Pixels; -import com.sun.glass.ui.Robot; -import javafx.application.Platform; - import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; -class MonocleRobot extends Robot { +import javafx.scene.input.KeyCode; +import javafx.scene.input.MouseButton; +import javafx.scene.paint.Color; + +import com.sun.glass.events.MouseEvent; +import com.sun.glass.ui.Application; +import com.sun.glass.ui.GlassRobot; + +class MonocleRobot extends GlassRobot { @Override - protected void _create() { + public void create() { + // no-op } @Override - protected void _destroy() { + public void destroy() { + // no-op } @Override - protected void _keyPress(int code) { - Platform.runLater(() -> { - KeyState state = new KeyState(); - KeyInput.getInstance().getState(state); - state.pressKey(code); - KeyInput.getInstance().setState(state); - }); + public void keyPress(KeyCode code) { + Application.checkEventThread(); + KeyState state = new KeyState(); + KeyInput.getInstance().getState(state); + state.pressKey(code.getCode()); + KeyInput.getInstance().setState(state); } @Override - protected void _keyRelease(int code) { - Platform.runLater(() -> { - KeyState state = new KeyState(); - KeyInput.getInstance().getState(state); - state.releaseKey(code); - KeyInput.getInstance().setState(state); - }); + public void keyRelease(KeyCode code) { + Application.checkEventThread(); + KeyState state = new KeyState(); + KeyInput.getInstance().getState(state); + state.releaseKey(code.getCode()); + KeyInput.getInstance().setState(state); } @Override - protected void _mouseMove(int x, int y) { - Platform.runLater(() -> { - MouseState state = new MouseState(); - MouseInput.getInstance().getState(state); - state.setX(x); - state.setY(y); - MouseInput.getInstance().setState(state, false); - }); + public void mouseMove(double x, double y) { + Application.checkEventThread(); + MouseState state = new MouseState(); + MouseInput.getInstance().getState(state); + state.setX((int) x); + state.setY((int) y); + MouseInput.getInstance().setState(state, false); } - @Override - protected void _mousePress(int buttons) { - Platform.runLater(() -> { - MouseState state = new MouseState(); - MouseInput.getInstance().getState(state); - if ((buttons & MOUSE_LEFT_BTN) != 0) { - state.pressButton(MouseEvent.BUTTON_LEFT); - } - if ((buttons & MOUSE_MIDDLE_BTN) != 0) { - state.pressButton(MouseEvent.BUTTON_OTHER); - } - if ((buttons & MOUSE_RIGHT_BTN) != 0) { - state.pressButton(MouseEvent.BUTTON_RIGHT); + private static MouseState convertToMouseState(boolean press, MouseState state, MouseButton... buttons) { + for (MouseButton button : buttons) { + switch (button) { + case PRIMARY: + if (press) { + state.pressButton(MouseEvent.BUTTON_LEFT); + } else { + state.releaseButton(MouseEvent.BUTTON_LEFT); + } + break; + case SECONDARY: + if (press) { + state.pressButton(MouseEvent.BUTTON_RIGHT); + } else { + state.releaseButton(MouseEvent.BUTTON_RIGHT); + } + break; + case MIDDLE: + if (press) { + state.pressButton(MouseEvent.BUTTON_OTHER); + } else { + state.releaseButton(MouseEvent.BUTTON_OTHER); + } + break; + default: throw new IllegalArgumentException("MouseButton: " + button + + " not supported by Monocle Robot"); } - MouseInput.getInstance().setState(state, false); - }); + } + return state; } @Override - protected void _mouseRelease(int buttons) { - Platform.runLater(() -> { - MouseState state = new MouseState(); - MouseInput.getInstance().getState(state); - if ((buttons & MOUSE_LEFT_BTN) != 0) { - state.releaseButton(MouseEvent.BUTTON_LEFT); - } - if ((buttons & MOUSE_MIDDLE_BTN) != 0) { - state.releaseButton(MouseEvent.BUTTON_OTHER); - } - if ((buttons & MOUSE_RIGHT_BTN) != 0) { - state.releaseButton(MouseEvent.BUTTON_RIGHT); - } - MouseInput.getInstance().setState(state, false); - }); + public void mousePress(MouseButton... buttons) { + Application.checkEventThread(); + MouseState state = new MouseState(); + MouseInput.getInstance().getState(state); + MouseInput.getInstance().setState(convertToMouseState(true, state, buttons), false); } @Override - protected void _mouseWheel(int wheelAmt) { - Platform.runLater(() -> { - MouseState state = new MouseState(); - MouseInput mouse = MouseInput.getInstance(); - mouse.getState(state); - int direction = wheelAmt < 0 - ? MouseState.WHEEL_DOWN - : MouseState.WHEEL_UP; - for (int i = 0; i < Math.abs(wheelAmt); i++) { - state.setWheel(direction); - mouse.setState(state, false); - state.setWheel(MouseState.WHEEL_NONE); - mouse.setState(state, false); - } - }); + public void mouseRelease(MouseButton... buttons) { + Application.checkEventThread(); + MouseState state = new MouseState(); + MouseInput.getInstance().getState(state); + MouseInput.getInstance().setState(convertToMouseState(false, state, buttons), false); } @Override - protected int _getMouseX() { + public void mouseWheel(int wheelAmt) { + Application.checkEventThread(); + MouseState state = new MouseState(); + MouseInput mouse = MouseInput.getInstance(); + mouse.getState(state); + int direction = wheelAmt < 0 + ? MouseState.WHEEL_DOWN + : MouseState.WHEEL_UP; + for (int i = 0; i < Math.abs(wheelAmt); i++) { + state.setWheel(direction); + mouse.setState(state, false); + state.setWheel(MouseState.WHEEL_NONE); + mouse.setState(state, false); + } + } + + @Override + public double getMouseX() { + Application.checkEventThread(); MouseState state = new MouseState(); MouseInput.getInstance().getState(state); return state.getX(); } @Override - protected int _getMouseY() { + public double getMouseY() { + Application.checkEventThread(); MouseState state = new MouseState(); MouseInput.getInstance().getState(state); return state.getY(); } @Override - protected int _getPixelColor(int x, int y) { + public Color getPixelColor(double x, double y) { + Application.checkEventThread(); NativeScreen screen = NativePlatformFactory.getNativePlatform().getScreen(); final int byteDepth = screen.getDepth() >>> 3; final int bwidth = screen.getWidth(); final int bheight = screen.getHeight(); if (x < 0 || x > bwidth || y < 0 || y > bheight) { - return 0; + return GlassRobot.convertFromIntArgb(0); } synchronized (NativeScreen.framebufferSwapLock) { @@ -160,30 +175,29 @@ protected int _getPixelColor(int x, int y) { if (byteDepth == 2) { ShortBuffer shortbuf = buffer.asShortBuffer(); - int v = shortbuf.get((y * bwidth) + x); - int red = (int) ((v & 0xF800) >> 11) << 3; - int green = (int) ((v & 0x7E0) >> 5) << 2; - int blue = (int) (v & 0x1F) << 3; + int v = shortbuf.get((int) (y * bwidth) + (int) x); + int red = (v & 0xF800) >> 11 << 3; + int green = (v & 0x7E0) >> 5 << 2; + int blue = (v & 0x1F) << 3; int p = (0xff000000 | (red << 16) | (green << 8) | blue); - return p; + return GlassRobot.convertFromIntArgb(p); } else if (byteDepth >= 4) { IntBuffer intbuf = buffer.asIntBuffer(); - return intbuf.get((y * bwidth) + x); + return GlassRobot.convertFromIntArgb(intbuf.get((int) (y * bwidth) + (int) x)); } else { - throw new RuntimeException("Unknown bit depth"); + throw new RuntimeException("Unknown bit depth: " + byteDepth); } } } @Override - protected Pixels _getScreenCapture(int x, int y, int width, int height, - boolean isHiDPI) { + public void getScreenCapture(int x, int y, int width, int height, int[] data, boolean scaleToFit) { + Application.checkEventThread(); NativeScreen screen = NativePlatformFactory.getNativePlatform().getScreen(); - final int byteDepth = screen.getDepth() >>> 3; final int scrWidth = screen.getWidth(); final int scrHeight = screen.getHeight(); @@ -191,20 +205,18 @@ protected Pixels _getScreenCapture(int x, int y, int width, int height, IntBuffer buffer = screen.getScreenCapture().asIntBuffer(); if (x == 0 && y == 0 && width == scrWidth && height == scrHeight) { - return new MonoclePixels(width, height, buffer); + // Easy case, the entire screen is being captured. + System.arraycopy(buffer.array(), 0, data, 0, buffer.array().length); + return; } - IntBuffer ret = IntBuffer.allocate(width * height); int rowStop = Math.min(y + height, scrHeight); int colStop = Math.min(x + width, scrWidth); for (int row = y; row < rowStop; row++) { for (int col = x; col < colStop; col++) { - ret.put(buffer.get(row * scrWidth + col)); + data[row * scrWidth + col] = buffer.get(row * scrWidth + col); } } - - ret.rewind(); - return new MonoclePixels(width, height, ret); } } } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleTimer.java b/src/main/java/com/sun/glass/ui/monocle/MonocleTimer.java index 344ba8b..60ea0f0 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleTimer.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleTimer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,8 +73,5 @@ public void run() { task = null; } } - - @Override protected void _pause(long timer) {} - @Override protected void _resume(long timer) {} } From f43fc9578c5ffd07f14f3d9e85a9ec6c31a7bb00 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Fri, 29 Sep 2023 15:46:33 -0600 Subject: [PATCH 14/22] Fix build for Java 11 --- build.gradle | 106 +++++++++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 45 deletions(-) diff --git a/build.gradle b/build.gradle index 0c9b9ca..67e6e23 100644 --- a/build.gradle +++ b/build.gradle @@ -1,54 +1,80 @@ -buildscript { - repositories { - mavenCentral() - maven { - url "https://plugins.gradle.org/m2/" - } - } -} +//buildscript { +// repositories { +// mavenCentral() +// maven { +// url "https://plugins.gradle.org/m2/" +// } +// } +//} +apply plugin: "java" apply plugin: 'maven' // print welcome message. -apply from: rootProject.file("gradle/welcome.gradle") - -wrapper { - gradleVersion = '6.5.1' - distributionUrl = "https://services.gradle.org/distributions/" + - "gradle-${gradleVersion}-bin.zip" -} +//apply from: rootProject.file("gradle/welcome.gradle") +// +//wrapper { +// gradleVersion = '6.5.1' +// distributionUrl = "https://services.gradle.org/distributions/" + +// "gradle-${gradleVersion}-bin.zip" +//} +// +//// task to print gradle and groovy versions. +//task("versions", group: "help").doLast { +// println "Java version: ${System.properties["java.version"]}" +// println "Gradle version: ${gradle.gradleVersion}" +// println "Groovy version: ${GroovySystem.version}" +//} +// +//// task to create main and test source directories. +//task("initSourceDirs", group: "build setup").doLast { +// // ignore source directories for projects without source sets. +// if (!project.hasProperty("sourceSets")) { return } +// +// // list all source directories. +// def sourceSets = project.sourceSets as SourceSetContainer +// def sourceDirs = sourceSets*.allSource.srcDirs.flatten() as List +// +// // create source directories, for those who not exists. +// for (sourceDir in sourceDirs) { sourceDir.mkdirs() } +//} -// task to print gradle and groovy versions. -task("versions", group: "help").doLast { - println "Java version: ${System.properties["java.version"]}" - println "Gradle version: ${gradle.gradleVersion}" - println "Groovy version: ${GroovySystem.version}" +repositories { + mavenCentral() } -// task to create main and test source directories. -task("initSourceDirs", group: "build setup").doLast { - // ignore source directories for projects without source sets. - if (!project.hasProperty("sourceSets")) { return } - - // list all source directories. - def sourceSets = project.sourceSets as SourceSetContainer - def sourceDirs = sourceSets*.allSource.srcDirs.flatten() as List - - // create source directories, for those who not exists. - for (sourceDir in sourceDirs) { sourceDir.mkdirs() } +static def getOSName() { + final String osName = System.getProperty("os.name").toLowerCase() + if (osName.contains("linux")) { + return ("linux") + } else if (osName.contains("mac os x") || osName.contains("darwin") || osName.contains("osx")) { + return ("mac") + } else if (osName.contains("windows")) { + return ("win") + } + return "" } -// provide java tasks. -apply plugin: "java" +ext { + def buildTimeAndDate = new Date() + buildDate = buildTimeAndDate.format("yyyy-MM-dd") + buildTime = buildTimeAndDate.format("HH:mm:ss.SSSZ") -repositories { - mavenCentral() + javaVersion = System.properties["java.version"] + javaVendor = System.properties["java.vendor"] + javaVmVersion = System.properties["java.vm.version"] + platform = getOSName() } // java language level. sourceCompatibility = "11" targetCompatibility = "11" +dependencies { + implementation "org.openjfx:javafx-base:11.0.2:${platform}" + implementation "org.openjfx:javafx-graphics:11.0.2:${platform}" +} + // configure publish tasks. apply from: rootProject.file("gradle/publish-pom.gradle") @@ -85,16 +111,6 @@ compileJava { } } -ext { - def buildTimeAndDate = new Date() - buildDate = buildTimeAndDate.format("yyyy-MM-dd") - buildTime = buildTimeAndDate.format("HH:mm:ss.SSSZ") - - javaVersion = System.properties["java.version"] - javaVendor = System.properties["java.vendor"] - javaVmVersion = System.properties["java.vm.version"] -} - jar { manifest.attributes( "Created-By": project.javaVersion + From 5ad9b23924a270e5b6f2c1e8b56b0609ae6d5647 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Fri, 29 Sep 2023 16:00:20 -0600 Subject: [PATCH 15/22] Fix pom for Java 11 --- build.gradle | 7 +++---- gradle/publish-pom.gradle | 8 ++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 67e6e23..7083878 100644 --- a/build.gradle +++ b/build.gradle @@ -7,8 +7,7 @@ // } //} -apply plugin: "java" -apply plugin: 'maven' +apply plugin: 'java' // print welcome message. //apply from: rootProject.file("gradle/welcome.gradle") @@ -71,8 +70,8 @@ sourceCompatibility = "11" targetCompatibility = "11" dependencies { - implementation "org.openjfx:javafx-base:11.0.2:${platform}" - implementation "org.openjfx:javafx-graphics:11.0.2:${platform}" + compileOnly "org.openjfx:javafx-base:11.0.2:${platform}" + compileOnly "org.openjfx:javafx-graphics:11.0.2:${platform}" } // configure publish tasks. diff --git a/gradle/publish-pom.gradle b/gradle/publish-pom.gradle index 07377b3..8554f66 100644 --- a/gradle/publish-pom.gradle +++ b/gradle/publish-pom.gradle @@ -15,6 +15,8 @@ * specific language governing permissions and limitations under the Licence. */ +apply plugin: 'maven' + task createPom { description 'Generate the artifact pom file for Maven Central' doLast { @@ -49,12 +51,6 @@ task createPom { version "${project.pomDependencyVersion}" scope "provided" } - dependency { - groupId "org.openjfx" - artifactId "javafx-controls" - version "${project.pomDependencyVersion}" - scope "provided" - } dependency { groupId "org.openjfx" artifactId "javafx-graphics" From 61c0cc2f2b87301d77a124d0cd4110f641ddc0d7 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Sat, 10 Feb 2024 19:03:10 -0700 Subject: [PATCH 16/22] Update to version 17.0.10 --- src/docs/notes.md | 72 -- .../glass/ui/monocle/AcceleratedScreen.java | 18 +- .../monocle/AndroidInputDeviceRegistry.java | 9 +- .../ui/monocle/AndroidInputProcessor.java | 18 +- .../sun/glass/ui/monocle/AndroidPlatform.java | 4 +- .../ui/monocle/AndroidPlatformFactory.java | 3 +- src/main/java/com/sun/glass/ui/monocle/C.java | 3 +- .../ui/monocle/DispmanAcceleratedScreen.java | 4 +- .../sun/glass/ui/monocle/DispmanPlatform.java | 5 +- .../java/com/sun/glass/ui/monocle/EGL.java | 3 +- .../ui/monocle/EGLAcceleratedScreen.java | 92 +++ .../com/sun/glass/ui/monocle/EGLCursor.java | 77 ++ .../com/sun/glass/ui/monocle/EGLPlatform.java | 87 ++ .../glass/ui/monocle/EGLPlatformFactory.java | 50 ++ .../com/sun/glass/ui/monocle/EGLScreen.java | 125 +++ .../sun/glass/ui/monocle/EPDFrameBuffer.java | 714 +++++++++++++++++ .../ui/monocle/EPDInputDeviceRegistry.java | 196 +++++ .../com/sun/glass/ui/monocle/EPDPlatform.java | 53 ++ .../glass/ui/monocle/EPDPlatformFactory.java | 108 +++ .../com/sun/glass/ui/monocle/EPDScreen.java | 263 ++++++ .../com/sun/glass/ui/monocle/EPDSettings.java | 308 +++++++ .../com/sun/glass/ui/monocle/EPDSystem.java | 752 ++++++++++++++++++ .../com/sun/glass/ui/monocle/FBDevScreen.java | 6 +- .../sun/glass/ui/monocle/FramebufferY8.java | 258 ++++++ .../glass/ui/monocle/HeadlessPlatform.java | 4 +- .../sun/glass/ui/monocle/HeadlessScreen.java | 3 +- .../com/sun/glass/ui/monocle/KeyInput.java | 5 +- .../com/sun/glass/ui/monocle/LinuxArch.java | 15 +- .../glass/ui/monocle/LinuxEventBuffer.java | 4 +- .../glass/ui/monocle/LinuxInputDevice.java | 6 +- .../ui/monocle/LinuxInputDeviceRegistry.java | 4 +- .../glass/ui/monocle/LinuxMouseProcessor.java | 6 +- .../sun/glass/ui/monocle/LinuxPlatform.java | 5 +- .../ui/monocle/LinuxPlatformFactory.java | 3 +- .../com/sun/glass/ui/monocle/LinuxSystem.java | 3 +- .../glass/ui/monocle/LinuxTouchProcessor.java | 3 +- .../glass/ui/monocle/LinuxTouchTransform.java | 6 +- .../com/sun/glass/ui/monocle/MX6Platform.java | 5 +- .../glass/ui/monocle/MonocleApplication.java | 56 +- .../sun/glass/ui/monocle/MonoclePixels.java | 4 + .../sun/glass/ui/monocle/MonocleRobot.java | 16 +- .../sun/glass/ui/monocle/MonocleSettings.java | 3 +- .../sun/glass/ui/monocle/MonocleTimer.java | 34 +- .../sun/glass/ui/monocle/MonocleWindow.java | 24 +- .../ui/monocle/MonocleWindowManager.java | 2 +- .../com/sun/glass/ui/monocle/MouseInput.java | 34 +- .../com/sun/glass/ui/monocle/MouseState.java | 23 +- .../sun/glass/ui/monocle/NativePlatform.java | 91 ++- .../ui/monocle/NativePlatformFactory.java | 5 +- .../sun/glass/ui/monocle/NativeScreen.java | 18 +- .../sun/glass/ui/monocle/OMAPPlatform.java | 5 +- .../com/sun/glass/ui/monocle/TouchInput.java | 4 +- .../sun/glass/ui/monocle/TouchPipeline.java | 4 +- .../com/sun/glass/ui/monocle/VNCScreen.java | 18 +- src/main/java/com/sun/glass/ui/monocle/X.java | 7 +- .../ui/monocle/X11AcceleratedScreen.java | 3 +- .../ui/monocle/X11InputDeviceRegistry.java | 4 +- .../com/sun/glass/ui/monocle/X11Platform.java | 10 +- .../glass/ui/monocle/X11PlatformFactory.java | 3 +- .../com/sun/glass/ui/monocle/X11Screen.java | 3 +- 60 files changed, 3449 insertions(+), 222 deletions(-) delete mode 100644 src/docs/notes.md create mode 100644 src/main/java/com/sun/glass/ui/monocle/EGLAcceleratedScreen.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EGLCursor.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EGLPlatform.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EGLPlatformFactory.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EGLScreen.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EPDFrameBuffer.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EPDInputDeviceRegistry.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EPDPlatform.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EPDPlatformFactory.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EPDScreen.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EPDSettings.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/EPDSystem.java create mode 100644 src/main/java/com/sun/glass/ui/monocle/FramebufferY8.java diff --git a/src/docs/notes.md b/src/docs/notes.md deleted file mode 100644 index 2f5d80c..0000000 --- a/src/docs/notes.md +++ /dev/null @@ -1,72 +0,0 @@ -# Engineer Notes 2023-09-29 - -## Updating the Monocle Code -Monocle is an OpenJFX project. When JavaFX was part of the JDK in Java 8, -the Monocle code was found in the OpenJDK code base. JavaFX was then moved to a -stand-alone module by Java 11. Therefore, when updating the Monocle code there are -separate locations for Java 8 and Java 11+. - -### Java 11+ Monocle Code - -Source code for Monocle 11+ can be found in several places. - -#### Maven -https://repo1.maven.org/maven2/org/openjfx/javafx-graphics - -#### GitHub -The following table links the Git branch for each LTS release. It is more -appropriate to use the tag for a specific release, but these links will help -you get started. - -| LTS | Java Code | Resources | -|-----------|-----------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------| -| JavaFX 21 | [Java Code](https://github.com/openjdk/jfx/tree/jfx21/modules/javafx.graphics/src/main/java/com/sun/glass/ui/monocle) | [Resources](https://github.com/openjdk/jfx/tree/jfx21/modules/javafx.graphics/src/main/resources/com/sun/glass/ui/monocle) | -| JavaFX 17 | [Java Code](https://github.com/openjdk/jfx/tree/jfx17/modules/javafx.graphics/src/main/java/com/sun/glass/ui/monocle) | [Resources](https://github.com/openjdk/jfx/tree/jfx17/modules/javafx.graphics/src/main/resources/com/sun/glass/ui/monocle) | -| JavaFX 11 | [Java Code](https://github.com/openjdk/jfx/tree/jfx11/modules/javafx.graphics/src/main/java/com/sun/glass/ui/monocle) | [Resources](https://github.com/openjdk/jfx/tree/jfx11/modules/javafx.graphics/src/main/resources/com/sun/glass/ui/monocle) | - -Note that some JavaFX 8 tags are also in this repository. They are for very old -versions and should not be needed. - -### Java 8 Monocle Code - -Source code for Monocle in Java 8 is a bit harder to find. Many distributions -no longer include JavaFX even with a Java 8 build. BellSoft Liberica seems to -be the most reasonable to work with: https://bell-sw.com/libericajdk/ - -1. Navigate to BellSoft Liberica Download Center: https://bell-sw.com/pages/downloads/ -2. In the section 'DownloadLiberica JDK' select 'JDK 8 LTS' -3. Click the 'Source Code' link to download an archive of the source code -4. Unpack the source code archive -5. The Java code is in `openjfx/modules/graphics/src/main/java/com/sun/glass/ui/monocle` -6. The resources are in `openjfx/modules/graphics/src/main/resources/com/sun/glass/ui/monocle` - -Prior versions can be found by using the 'All versions' link going back to JDK 8u202+8. - -#### For Reference -The JavaFX releases available on GitHub -- openjdk/jfx: 8.0-b52 to 8u60-b08 -- openjdk/jdk: jdk8-b01 to jdk8-b120 - - -## Create Signed Bundle -Signed Maven bundles can be generated by building the project as usual and then -using the bundle.sh script to generate the bundle for deployment to Maven -Central. -1. On your local machine, navigate to the project home -2. Execute `./gradle clean build` -3. Execute `scripts/bundle.sh` -4. The signed bundle is located in the `build/bundles` folder. - -## Uploading Maven Bundles for Monocle -1. Sign in to https://oss.sonatype.org (TestFX artifacts are hosted on the old oss.sontatype.org server) -2. In the guide on the left click on 'Staging Upload' -3. For 'Upload Mode' choose 'Artifact Bundle' -4. Click the 'Select Bundle to Upload...' button -5. Navigate to and select the signed bundle on your local machine -6. Click the 'Upload Bundle' button - -After the bundle is uploaded, Maven Central will process the bundle. The results of the upload and processing can be viewed by -1. In the guide on the left click on 'Staging Repositories' -2. Select the repository corresponding to the bundle upload -3. In the tabbed pane select the 'Activity' tab -4. Review the actions taken and resolve any issues found diff --git a/src/main/java/com/sun/glass/ui/monocle/AcceleratedScreen.java b/src/main/java/com/sun/glass/ui/monocle/AcceleratedScreen.java index a96a81b..d47489d 100644 --- a/src/main/java/com/sun/glass/ui/monocle/AcceleratedScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/AcceleratedScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,10 +33,10 @@ public class AcceleratedScreen { private static long glesLibraryHandle; private static long eglLibraryHandle; private static boolean initialized = false; - private long eglSurface; - private long eglContext; - private long eglDisplay; - private long nativeWindow; + long eglSurface; + long eglContext; + long eglDisplay; + long nativeWindow; protected static final LinuxSystem ls = LinuxSystem.getLinuxSystem(); private EGL egl; long eglConfigs[] = {0}; @@ -55,6 +55,14 @@ protected long platformGetNativeWindow() { return 0L; } + /** + * Create and initialize an AcceleratedScreen. Subclasses should override + * this constructor in case the {@link #AcceleratedScreen(int[]) AcceleratedScreen(int[])} + * constructor is not sufficient. + */ + AcceleratedScreen() { + } + /** * Perform basic egl intialization - open the display, create the drawing * surface, and create a GL context to that drawing surface. diff --git a/src/main/java/com/sun/glass/ui/monocle/AndroidInputDeviceRegistry.java b/src/main/java/com/sun/glass/ui/monocle/AndroidInputDeviceRegistry.java index 216746e..fccb442 100644 --- a/src/main/java/com/sun/glass/ui/monocle/AndroidInputDeviceRegistry.java +++ b/src/main/java/com/sun/glass/ui/monocle/AndroidInputDeviceRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ public static void gotTouchEventFromNative(int count, int[] actions, int[] ids, touchState.addPoint(p); } } - instance.gotTouchEvent(touchState); + Platform.runLater(() -> instance.gotTouchEvent(touchState)); } private void gotTouchEvent(TouchState touchState) { @@ -77,6 +77,10 @@ private void gotTouchEvent(TouchState touchState) { } + public static void dispatchKeyEventFromNative(int type, int key, char[] chars, int modifiers) { + instance.processor.dispatchKeyEvent(type, key, chars, modifiers); + } + public static void gotKeyEventFromNative(int action, int linuxKey) { instance.gotKeyEvent (action, linuxKey); } @@ -124,6 +128,7 @@ private AndroidInputDevice addDeviceInternal(AndroidInputDevice device, String n } void removeDevice(AndroidInputDevice device) { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(new AllPermission()); diff --git a/src/main/java/com/sun/glass/ui/monocle/AndroidInputProcessor.java b/src/main/java/com/sun/glass/ui/monocle/AndroidInputProcessor.java index 31e2c91..dee4ffd 100644 --- a/src/main/java/com/sun/glass/ui/monocle/AndroidInputProcessor.java +++ b/src/main/java/com/sun/glass/ui/monocle/AndroidInputProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ */ package com.sun.glass.ui.monocle; +import javafx.application.Platform; + class AndroidInputProcessor { private final AndroidInputDevice device; @@ -54,4 +56,18 @@ synchronized void pushKeyEvent(KeyState keyState) { keyInput.setState(keyState); } + synchronized void dispatchKeyEvent(int type, int key, char[] chars, int modifiers) { + Platform.runLater( () -> { + MonocleWindow window = (MonocleWindow) MonocleWindowManager.getInstance().getFocusedWindow(); + if (window == null) { + return; + } + MonocleView view = (MonocleView) window.getView(); + if (view == null) { + return; + } + RunnableProcessor.runLater( () -> view.notifyKey(type, key, chars, modifiers)); + }); + } + } diff --git a/src/main/java/com/sun/glass/ui/monocle/AndroidPlatform.java b/src/main/java/com/sun/glass/ui/monocle/AndroidPlatform.java index d19c9dc..7a22f85 100644 --- a/src/main/java/com/sun/glass/ui/monocle/AndroidPlatform.java +++ b/src/main/java/com/sun/glass/ui/monocle/AndroidPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ protected InputDeviceRegistry createInputDeviceRegistry() { @Override protected NativeCursor createCursor() { - return new NullCursor(); + return logSelectedCursor(new NullCursor()); } @Override diff --git a/src/main/java/com/sun/glass/ui/monocle/AndroidPlatformFactory.java b/src/main/java/com/sun/glass/ui/monocle/AndroidPlatformFactory.java index 44b2ee3..e6cc87a 100644 --- a/src/main/java/com/sun/glass/ui/monocle/AndroidPlatformFactory.java +++ b/src/main/java/com/sun/glass/ui/monocle/AndroidPlatformFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ class AndroidPlatformFactory extends NativePlatformFactory { @Override protected boolean matches() { + @SuppressWarnings("removal") String platform = AccessController.doPrivileged( (PrivilegedAction) () -> System.getProperty("javafx.platform")); return platform != null && platform.equals("android"); diff --git a/src/main/java/com/sun/glass/ui/monocle/C.java b/src/main/java/com/sun/glass/ui/monocle/C.java index b119b21..ef37cf6 100644 --- a/src/main/java/com/sun/glass/ui/monocle/C.java +++ b/src/main/java/com/sun/glass/ui/monocle/C.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,6 +51,7 @@ static C getC() { } private static void checkPermissions() { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(permission); diff --git a/src/main/java/com/sun/glass/ui/monocle/DispmanAcceleratedScreen.java b/src/main/java/com/sun/glass/ui/monocle/DispmanAcceleratedScreen.java index 499924c..045b218 100644 --- a/src/main/java/com/sun/glass/ui/monocle/DispmanAcceleratedScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/DispmanAcceleratedScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,9 +38,11 @@ class DispmanAcceleratedScreen extends AcceleratedScreen { @Override protected long platformGetNativeWindow() { + @SuppressWarnings("removal") int displayID = AccessController.doPrivileged( (PrivilegedAction) () -> Integer.getInteger("dispman.display", 0 /* LCD */)); + @SuppressWarnings("removal") int layerID = AccessController.doPrivileged( (PrivilegedAction) () -> Integer.getInteger("dispman.layer", 1)); diff --git a/src/main/java/com/sun/glass/ui/monocle/DispmanPlatform.java b/src/main/java/com/sun/glass/ui/monocle/DispmanPlatform.java index e82c3b3..cec41a7 100644 --- a/src/main/java/com/sun/glass/ui/monocle/DispmanPlatform.java +++ b/src/main/java/com/sun/glass/ui/monocle/DispmanPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,8 @@ class DispmanPlatform extends LinuxPlatform { @Override protected NativeCursor createCursor() { - return new DispmanCursor(); + final NativeCursor c = useCursor ? new DispmanCursor() : new NullCursor(); + return logSelectedCursor(c); } @Override diff --git a/src/main/java/com/sun/glass/ui/monocle/EGL.java b/src/main/java/com/sun/glass/ui/monocle/EGL.java index 489808c..739adf9 100644 --- a/src/main/java/com/sun/glass/ui/monocle/EGL.java +++ b/src/main/java/com/sun/glass/ui/monocle/EGL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -165,6 +165,7 @@ static EGL getEGL() { } private static void checkPermissions() { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(permission); diff --git a/src/main/java/com/sun/glass/ui/monocle/EGLAcceleratedScreen.java b/src/main/java/com/sun/glass/ui/monocle/EGLAcceleratedScreen.java new file mode 100644 index 0000000..b6db852 --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EGLAcceleratedScreen.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +/** + * The EGLAcceleratedScreen manages the link to the hardware-accelerated + * component, using EGL. This class is not directly using EGL commands, + * as the order and meaning of parameters might vary between implementations. + * Also, implementation-specific logic may be applied before, in between, or + * after the EGL commands. + */ +public class EGLAcceleratedScreen extends AcceleratedScreen { + + private long eglWindowHandle = -1; + + /** + * Create a new EGLAcceleratedScreen with a set of attributes. + * This will create an EGL Context that can be used by the + * Prism component. + * @param attributes an array of attributes that will be used by the underlying + * implementation to get the best matching configuration. + */ + EGLAcceleratedScreen(int[] attributes) throws GLException { + eglWindowHandle = platformGetNativeWindow(); + eglDisplay = nGetEglDisplayHandle(); + nEglInitialize(eglDisplay); + nEglBindApi(EGL.EGL_OPENGL_ES_API); + long eglConfig = nEglChooseConfig(eglDisplay, attributes); + if (eglConfig == -1) { + throw new IllegalArgumentException("Could not create an EGLChooseConfig"); + } + eglSurface = nEglCreateWindowSurface(eglDisplay, eglConfig, eglWindowHandle); + eglContext = nEglCreateContext(eglDisplay, eglConfig); + } + + @Override + protected long platformGetNativeWindow() { + String displayID = System.getProperty("egl.displayid", "/dev/dri/card1" ); + return nPlatformGetNativeWindow(displayID); + } + + @Override + public void enableRendering(boolean flag) { + if (flag) { + nEglMakeCurrent(eglDisplay, eglSurface, eglSurface, + eglContext); + } else { + nEglMakeCurrent(eglDisplay, 0, 0, eglContext); + } + } + + @Override + public boolean swapBuffers() { + boolean result = false; + synchronized (NativeScreen.framebufferSwapLock) { + result = nEglSwapBuffers(eglDisplay, eglSurface); + } + return result; + } + + private native long nPlatformGetNativeWindow(String displayID); + private native long nGetEglDisplayHandle(); + private native boolean nEglInitialize(long handle); + private native boolean nEglBindApi(int v); + private native long nEglChooseConfig(long eglDisplay, int[] attribs); + private native boolean nEglMakeCurrent(long eglDisplay, long eglDrawSurface, long eglReadSurface, long eglContext); + private native long nEglCreateWindowSurface(long eglDisplay, long eglConfig, long nativeWindow); + private native long nEglCreateContext(long eglDisplay, long eglConfig); + private native boolean nEglSwapBuffers(long eglDisplay, long eglSurface); +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EGLCursor.java b/src/main/java/com/sun/glass/ui/monocle/EGLCursor.java new file mode 100644 index 0000000..9ec20fe --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EGLCursor.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.glass.ui.monocle; + +import com.sun.glass.ui.Size; + +class EGLCursor extends NativeCursor { + + private static final int CURSOR_WIDTH = 16; + private static final int CURSOR_HEIGHT = 16; + + + private native void _initEGLCursor(int cursorWidth, int cursorHeight); + private native void _setVisible(boolean visible); + private native void _setLocation(int x, int y); + private native void _setImage(byte[] cursorImage); + + EGLCursor() { + _initEGLCursor(CURSOR_WIDTH, CURSOR_HEIGHT); + } + + @Override + Size getBestSize() { + return new Size(CURSOR_WIDTH, CURSOR_HEIGHT); + } + + @Override + void setVisibility(boolean visibility) { + isVisible = visibility; + _setVisible(visibility); + } + + private void updateImage(boolean always) { + System.out.println("EGLCursor.updateImage: not implemented"); + } + + @Override + void setImage(byte[] cursorImage) { + _setImage(cursorImage); + } + + @Override + void setLocation(int x, int y) { + _setLocation(x, y); + } + + @Override + void setHotSpot(int hotspotX, int hotspotY) { + } + + @Override + void shutdown() { + } +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EGLPlatform.java b/src/main/java/com/sun/glass/ui/monocle/EGLPlatform.java new file mode 100644 index 0000000..66223ec --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EGLPlatform.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +import java.util.ArrayList; +import java.util.List; + +public class EGLPlatform extends LinuxPlatform { + + private List screens; + + /** + * Create an EGLPlatform. If a library with specific native code is needed for this platform, + * it will be downloaded now. The system property monocle.egl.lib can be used to define the + * name of the library that should be loaded. + */ + public EGLPlatform() { + String lib = System.getProperty("monocle.egl.lib"); + if (lib != null) { + long handle = LinuxSystem.getLinuxSystem().dlopen(lib, LinuxSystem.RTLD_LAZY | LinuxSystem.RTLD_GLOBAL); + if (handle == 0) { + throw new UnsatisfiedLinkError("EGLPlatform failed to load the requested library " + lib); + } + } + } + + @Override + protected NativeCursor createCursor() { + // By default, hardware cursor will be used + // Fallback to software cursor will be used in case monocle.egl.swcursor is set to true + boolean swcursor = Boolean.getBoolean("monocle.egl.swcursor"); + final NativeCursor c = useCursor ? (swcursor ? new SoftwareCursor() : new EGLCursor()) : new NullCursor(); + return logSelectedCursor(c); + } + + + @Override + protected NativeScreen createScreen() { + return new EGLScreen(0); + } + + @Override + protected synchronized List createScreens() { + if (screens == null) { + int numScreens = nGetNumberOfScreens(); + screens = new ArrayList<>(numScreens); + for (int i = 0; i < numScreens; i++) { + screens.add(new EGLScreen(i)); + } + } + return screens; + } + + @Override + public synchronized AcceleratedScreen getAcceleratedScreen(int[] attributes) throws GLException { + if (accScreen == null) { + accScreen = new EGLAcceleratedScreen(attributes); + } + return accScreen; + + } + + private native int nGetNumberOfScreens(); + +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EGLPlatformFactory.java b/src/main/java/com/sun/glass/ui/monocle/EGLPlatformFactory.java new file mode 100644 index 0000000..8d4057a --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EGLPlatformFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +public class EGLPlatformFactory extends NativePlatformFactory { + + @Override + protected boolean matches() { + return true; + } + + @Override + protected int getMajorVersion() { + return 1; + } + + @Override + protected int getMinorVersion() { + return 0; + } + + @Override + protected NativePlatform createNativePlatform() { + return new EGLPlatform(); + } + + +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EGLScreen.java b/src/main/java/com/sun/glass/ui/monocle/EGLScreen.java new file mode 100644 index 0000000..2723500 --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EGLScreen.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.glass.ui.monocle; + +import java.nio.Buffer; +import java.nio.ByteBuffer; + +public class EGLScreen implements NativeScreen { + + final int depth; + final int nativeFormat; + final int width, height; + final int offsetX, offsetY; + final int dpi; + final long handle; + final float scale; + + public EGLScreen(int idx) { + this.handle = nGetHandle(idx); + this.depth = nGetDepth(idx); + this.nativeFormat = nGetNativeFormat(idx); + this.width = nGetWidth(idx); + this.height = nGetHeight(idx); + this.offsetX = nGetOffsetX(idx); + this.offsetY = nGetOffsetY(idx); + this.dpi = nGetDpi(idx); + this.scale = nGetScale(idx); + } + + @Override + public int getDepth() { + return this.depth; + } + + @Override + public int getNativeFormat() { + return this.nativeFormat; + } + + @Override + public int getWidth() { + return this.width; + } + + @Override + public int getHeight() { + return this.height; + } + + @Override + public int getOffsetX() { + return this.offsetX; + } + + @Override + public int getOffsetY() { + return this.offsetY; + } + + @Override + public int getDPI() { + return this.dpi; + } + + @Override + public long getNativeHandle() { + return handle; + } + + @Override + public void shutdown() { + } + + @Override + public void uploadPixels(Buffer b, int x, int y, int width, int height, float alpha) { + } + + @Override + public void swapBuffers() { + } + + @Override + public ByteBuffer getScreenCapture() { + throw new UnsupportedOperationException("No screencapture on EGL platforms"); + } + + @Override + public float getScale() { + return this.scale; + } + + private native long nGetHandle(int idx); + private native int nGetDepth(int idx); + private native int nGetWidth(int idx); + private native int nGetHeight(int idx); + private native int nGetOffsetX(int idx); + private native int nGetOffsetY(int idx); + private native int nGetDpi(int idx); + private native int nGetNativeFormat(int idx); + private native float nGetScale(int idx); + +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EPDFrameBuffer.java b/src/main/java/com/sun/glass/ui/monocle/EPDFrameBuffer.java new file mode 100644 index 0000000..92334c6 --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EPDFrameBuffer.java @@ -0,0 +1,714 @@ +/* + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +import com.sun.glass.ui.monocle.EPDSystem.FbVarScreenInfo; +import com.sun.glass.ui.monocle.EPDSystem.IntStructure; +import com.sun.glass.ui.monocle.EPDSystem.MxcfbUpdateData; +import com.sun.glass.ui.monocle.EPDSystem.MxcfbWaveformModes; +import com.sun.javafx.logging.PlatformLogger; +import com.sun.javafx.logging.PlatformLogger.Level; +import com.sun.javafx.util.Logging; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.text.MessageFormat; + +/** + * Represents the standard Linux frame buffer device interface plus the custom + * extensions to that interface provided by the Electrophoretic Display + * Controller (EPDC) frame buffer driver. + *

+ * The Linux frame buffer device interface is documented in The Frame + * Buffer Device API found in the Ubuntu package called linux-doc + * (see /usr/share/doc/linux-doc/fb/api.txt.gz).

+ *

+ * The EPDC frame buffer driver extensions are documented in the i.MX + * Linux Reference Manual available on the + * NXP website (registration required). On + * the NXP home page, click Products, ARM Processors, i.MX Application + * Processors, and then i.MX 6 Processors, for example. Select the i.MX6SLL + * Product in the chart; then click the Documentation tab. Look for a download + * with a label for Linux documents, like L4.1.15_2.1.0_LINUX_DOCS, under the + * Supporting Information section. After downloading and expanding the archive, + * the reference manual is found in the doc directory as the file + * i.MX_Linux_Reference_Manual.pdf.

+ */ +class EPDFrameBuffer { + + /** + * The arithmetic right shift value to convert a bit depth to a byte depth. + */ + private static final int BITS_TO_BYTES = 3; + + /** + * The delay in milliseconds between the completion of all updates in the + * EPDC driver and when the driver powers down the EPDC and display power + * supplies. + */ + private static final int POWERDOWN_DELAY = 1_000; + + /** + * Linux system error: ENOTTY 25 Inappropriate ioctl for device. + */ + private static final int ENOTTY = 25; + + private final PlatformLogger logger = Logging.getJavaFXLogger(); + private final EPDSettings settings; + private final LinuxSystem system; + private final EPDSystem driver; + private final long fd; + + private final int xres; + private final int yres; + private final int xresVirtual; + private final int yresVirtual; + private final int xoffset; + private final int yoffset; + private final int bitsPerPixel; + private final int bytesPerPixel; + private final int byteOffset; + private final MxcfbUpdateData updateData; + private final MxcfbUpdateData syncUpdate; + + private int updateMarker; + private int lastMarker; + + /** + * Creates a new {@code EPDFrameBuffer} for the given frame buffer device. + * The geometry of the Linux frame buffer is shown below for various color + * depths and rotations on a sample system, as printed by the fbset + * command. The first three are for landscape mode, while the last three are + * for portrait. + *
{@code
+     * geometry 800 600 800 640 32 (line length: 3200)
+     * geometry 800 600 800 1280 16 (line length: 1600)
+     * geometry 800 600 800 1280 8 (line length: 800)
+     *
+     * geometry 600 800 608 896 32 (line length: 2432)
+     * geometry 600 800 608 1792 16 (line length: 1216)
+     * geometry 600 800 608 1792 8 (line length: 608)
+     * }
+ * + * @implNote {@code MonocleApplication} creates a {@code Screen} which + * requires that the width be set to {@link #xresVirtual} even though only + * the first {@link #xres} pixels of each row are visible. The EPDC driver + * supports panning only in the y-direction, so it is not possible to center + * the visible resolution horizontally when these values differ. The JavaFX + * application should be left-aligned in this case and ignore the few extra + * pixels on the right of its screen. + * + * @param fbPath the frame buffer device path, such as /dev/fb0 + * @throws IOException if an error occurs when opening the frame buffer + * device or when getting or setting the frame buffer configuration + * @throws IllegalArgumentException if the EPD settings specify an + * unsupported color depth + */ + EPDFrameBuffer(String fbPath) throws IOException { + settings = EPDSettings.newInstance(); + system = LinuxSystem.getLinuxSystem(); + driver = EPDSystem.getEPDSystem(); + fd = system.open(fbPath, LinuxSystem.O_RDWR); + if (fd == -1) { + throw new IOException(system.getErrorMessage()); + } + + /* + * Gets the current settings of the frame buffer device. + */ + var screen = new FbVarScreenInfo(); + getScreenInfo(screen); + + /* + * Changes the settings of the frame buffer from the system properties. + * + * See the section, "Format configuration," in "The Frame Buffer Device + * API" for details. Note that xoffset is always zero, and yoffset can + * be modified only by panning in the y-direction with the IOCTL call to + * LinuxSystem.FBIOPAN_DISPLAY. + */ + screen.setBitsPerPixel(screen.p, settings.bitsPerPixel); + screen.setGrayscale(screen.p, settings.grayscale); + switch (settings.bitsPerPixel) { + case Byte.SIZE: + // rgba 8/0,8/0,8/0,0/0 (set by driver when grayscale > 0) + screen.setRed(screen.p, 0, 0); + screen.setGreen(screen.p, 0, 0); + screen.setBlue(screen.p, 0, 0); + screen.setTransp(screen.p, 0, 0); + break; + case Short.SIZE: + // rgba 5/11,6/5,5/0,0/0 + screen.setRed(screen.p, 5, 11); + screen.setGreen(screen.p, 6, 5); + screen.setBlue(screen.p, 5, 0); + screen.setTransp(screen.p, 0, 0); + break; + case Integer.SIZE: + // rgba 8/16,8/8,8/0,8/24 + screen.setRed(screen.p, 8, 16); + screen.setGreen(screen.p, 8, 8); + screen.setBlue(screen.p, 8, 0); + screen.setTransp(screen.p, 8, 24); + break; + default: + String msg = MessageFormat.format("Unsupported color depth: {0} bpp", settings.bitsPerPixel); + logger.severe(msg); + throw new IllegalArgumentException(msg); + } + screen.setActivate(screen.p, EPDSystem.FB_ACTIVATE_FORCE); + screen.setRotate(screen.p, settings.rotate); + setScreenInfo(screen); + + /* + * Gets and logs the new settings of the frame buffer device. + */ + getScreenInfo(screen); + logScreenInfo(screen); + xres = screen.getXRes(screen.p); + yres = screen.getYRes(screen.p); + xresVirtual = screen.getXResVirtual(screen.p); + yresVirtual = screen.getYResVirtual(screen.p); + xoffset = screen.getOffsetX(screen.p); + yoffset = screen.getOffsetY(screen.p); + bitsPerPixel = screen.getBitsPerPixel(screen.p); + bytesPerPixel = bitsPerPixel >>> BITS_TO_BYTES; + byteOffset = (xoffset + yoffset * xresVirtual) * bytesPerPixel; + + /* + * Allocates objects for reuse to avoid creating new direct byte buffers + * outside of the Java heap on each display update. + */ + updateData = new MxcfbUpdateData(); + syncUpdate = createDefaultUpdate(xres, yres); + } + + /** + * Gets the variable screen information of the frame buffer. Run the + * fbset command as root to print the screen information. + * + * @param screen the object representing the variable screen information + * @throws IOException if an error occurs getting the information + */ + private void getScreenInfo(FbVarScreenInfo screen) throws IOException { + int rc = system.ioctl(fd, LinuxSystem.FBIOGET_VSCREENINFO, screen.p); + if (rc != 0) { + system.close(fd); + throw new IOException(system.getErrorMessage()); + } + } + + /** + * Sets the variable screen information of the frame buffer. + *

+ * "To ensure that the EPDC driver receives the initialization request, the + * {@code activate} field of the {@code fb_var_screeninfo} parameter should + * be set to {@code FB_ACTIVATE_FORCE}." [EPDC Panel Initialization, + * i.MX Linux Reference Manual]

+ *

+ * To request a change to 8-bit grayscale format, the bits per pixel must be + * set to 8 and the grayscale value must be set to one of the two valid + * grayscale format values: {@code GRAYSCALE_8BIT} or + * {@code GRAYSCALE_8BIT_INVERTED}. [Grayscale Framebuffer Selection, + * i.MX Linux Reference Manual]

+ * + * @param screen the object representing the variable screen information + * @throws IOException if an error occurs setting the information + */ + private void setScreenInfo(FbVarScreenInfo screen) throws IOException { + int rc = system.ioctl(fd, LinuxSystem.FBIOPUT_VSCREENINFO, screen.p); + if (rc != 0) { + system.close(fd); + throw new IOException(system.getErrorMessage()); + } + } + + /** + * Logs the variable screen information of the frame buffer, depending on + * the logging level. + * + * @param screen the object representing the variable screen information + */ + private void logScreenInfo(FbVarScreenInfo screen) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Frame buffer geometry: {0} {1} {2} {3} {4}", + screen.getXRes(screen.p), screen.getYRes(screen.p), + screen.getXResVirtual(screen.p), screen.getYResVirtual(screen.p), + screen.getBitsPerPixel(screen.p)); + logger.fine("Frame buffer rgba: {0}/{1},{2}/{3},{4}/{5},{6}/{7}", + screen.getRedLength(screen.p), screen.getRedOffset(screen.p), + screen.getGreenLength(screen.p), screen.getGreenOffset(screen.p), + screen.getBlueLength(screen.p), screen.getBlueOffset(screen.p), + screen.getTranspLength(screen.p), screen.getTranspOffset(screen.p)); + logger.fine("Frame buffer grayscale: {0}", screen.getGrayscale(screen.p)); + } + } + + /** + * Creates the default update data with values from the EPD system + * properties, setting all fields except for the update marker. Reusing the + * update data object avoids creating a new one for each update request. + * + * @implNote An update mode of {@link EPDSystem#UPDATE_MODE_FULL} would make + * the {@link EPDSettings#NO_WAIT} system property useless by changing all + * non-colliding updates into colliding ones, so this method sets the + * default update mode to {@link EPDSystem#UPDATE_MODE_PARTIAL}. + * + * @param width the width of the update region + * @param height the height of the update region + * @return the default update data with all fields set but the update marker + */ + private MxcfbUpdateData createDefaultUpdate(int width, int height) { + var update = new MxcfbUpdateData(); + update.setUpdateRegion(update.p, 0, 0, width, height); + update.setWaveformMode(update.p, settings.waveformMode); + update.setUpdateMode(update.p, EPDSystem.UPDATE_MODE_PARTIAL); + update.setTemp(update.p, EPDSystem.TEMP_USE_AMBIENT); + update.setFlags(update.p, settings.flags); + return update; + } + + /** + * Defines a mapping for common waveform modes. This mapping must be + * configured for the automatic waveform mode selection to function + * properly. Each of the parameters should be set to one of the following: + *
    + *
  • {@link EPDSystem#WAVEFORM_MODE_INIT}
  • + *
  • {@link EPDSystem#WAVEFORM_MODE_DU}
  • + *
  • {@link EPDSystem#WAVEFORM_MODE_GC16}
  • + *
  • {@link EPDSystem#WAVEFORM_MODE_GC4}
  • + *
  • {@link EPDSystem#WAVEFORM_MODE_A2}
  • + *
+ * + * @implNote This method fails on the Kobo Glo HD Model N437 with the error + * ENOTTY (25), "Inappropriate ioctl for device." The driver on that device + * uses an extended structure with four additional integers, changing its + * size and its corresponding request code. This method could use the + * extended structure, but the driver on the Kobo Glo HD ignores it and + * returns immediately, anyway. Furthermore, newer devices support both the + * current structure and the extended one, but define the extra fields in a + * different order. Therefore, simply use the current structure and ignore + * an error of ENOTTY, picking up the default values for any extra fields. + * + * @param init the initialization mode for clearing the screen to all white + * @param du the direct update mode for changing any gray values to either + * all black or all white + * @param gc4 the mode for 4-level (2-bit) grayscale images and text + * @param gc8 the mode for 8-level (3-bit) grayscale images and text + * @param gc16 the mode for 16-level (4-bit) grayscale images and text + * @param gc32 the mode for 32-level (5-bit) grayscale images and text + */ + private void setWaveformModes(int init, int du, int gc4, int gc8, int gc16, int gc32) { + var modes = new MxcfbWaveformModes(); + modes.setModes(modes.p, init, du, gc4, gc8, gc16, gc32); + int rc = system.ioctl(fd, driver.MXCFB_SET_WAVEFORM_MODES, modes.p); + if (rc != 0 && system.errno() != ENOTTY) { + logger.severe("Failed setting waveform modes: {0} ({1})", + system.getErrorMessage(), system.errno()); + } + } + + /** + * Sets the temperature to be used by the EPDC driver in subsequent panel + * updates. Note that this temperature setting may be overridden by setting + * the temperature in a specific update to anything other than + * {@link EPDSystem#TEMP_USE_AMBIENT}. + * + * @param temp the temperature in degrees Celsius + */ + private void setTemperature(int temp) { + int rc = driver.ioctl(fd, driver.MXCFB_SET_TEMPERATURE, temp); + if (rc != 0) { + logger.severe("Failed setting temperature to {2} degrees Celsius: {0} ({1})", + system.getErrorMessage(), system.errno(), temp); + } + } + + /** + * Selects between automatic and region update mode. In region update mode, + * updates must be submitted with an IOCTL call to + * {@link EPDSystem#MXCFB_SEND_UPDATE}. In automatic mode, updates are + * generated by the driver when it detects that pages in a frame buffer + * memory region have been modified. + *

+ * Automatic mode is available only when it has been enabled in the Linux + * kernel by the option CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE. You can find + * the configuration options used to build the kernel in a file under + * /proc or /boot, such as /proc/config.gz.

+ * + * @param mode the automatic update mode, one of: + *
    + *
  • {@link EPDSystem#AUTO_UPDATE_MODE_REGION_MODE}
  • + *
  • {@link EPDSystem#AUTO_UPDATE_MODE_AUTOMATIC_MODE}
  • + *
+ */ + private void setAutoUpdateMode(int mode) { + int rc = driver.ioctl(fd, driver.MXCFB_SET_AUTO_UPDATE_MODE, mode); + if (rc != 0) { + logger.severe("Failed setting auto-update mode to {2}: {0} ({1})", + system.getErrorMessage(), system.errno(), mode); + } + } + + /** + * Requests the entire visible region of the frame buffer to be updated to + * the display. + * + * @param updateMode the update mode, one of: + *
    + *
  • {@link EPDSystem#UPDATE_MODE_PARTIAL}
  • + *
  • {@link EPDSystem#UPDATE_MODE_FULL}
  • + *
+ * @param waveformMode the waveform mode, one of: + *
    + *
  • {@link EPDSystem#WAVEFORM_MODE_INIT}
  • + *
  • {@link EPDSystem#WAVEFORM_MODE_DU}
  • + *
  • {@link EPDSystem#WAVEFORM_MODE_GC16}
  • + *
  • {@link EPDSystem#WAVEFORM_MODE_GC4}
  • + *
  • {@link EPDSystem#WAVEFORM_MODE_A2}
  • + *
  • {@link EPDSystem#WAVEFORM_MODE_AUTO}
  • + *
+ * @param flags a bit mask composed of the following flag values: + *
    + *
  • {@link EPDSystem#EPDC_FLAG_ENABLE_INVERSION}
  • + *
  • {@link EPDSystem#EPDC_FLAG_FORCE_MONOCHROME}
  • + *
  • {@link EPDSystem#EPDC_FLAG_USE_DITHERING_Y1}
  • + *
  • {@link EPDSystem#EPDC_FLAG_USE_DITHERING_Y4}
  • + *
+ * @return the marker to identify this update in a subsequence call to + * {@link #waitForUpdateComplete} + */ + private int sendUpdate(int updateMode, int waveformMode, int flags) { + updateData.setUpdateRegion(updateData.p, 0, 0, xres, yres); + updateData.setUpdateMode(updateData.p, updateMode); + updateData.setTemp(updateData.p, EPDSystem.TEMP_USE_AMBIENT); + updateData.setFlags(updateData.p, flags); + return sendUpdate(updateData, waveformMode); + } + + /** + * Requests an update to the display, allowing for the reuse of the update + * data object. The waveform mode is reset because the update data could + * have been used in a previous update. In that case, the waveform mode may + * have been modified by the EPDC driver with the actual mode selected. The + * update marker is overwritten with the next sequential marker. + * + * @param update the data describing the update; the waveform mode and + * update marker are overwritten + * @param waveformMode the waveform mode for this update + * @return the marker to identify this update in a subsequence call to + * {@link #waitForUpdateComplete} + */ + private int sendUpdate(MxcfbUpdateData update, int waveformMode) { + /* + * The IOCTL call to MXCFB_WAIT_FOR_UPDATE_COMPLETE returns the error + * "Invalid argument (22)" when passed an update marker of zero. + */ + updateMarker++; + if (updateMarker == 0) { + updateMarker++; + } + update.setWaveformMode(update.p, waveformMode); + update.setUpdateMarker(update.p, updateMarker); + int rc = system.ioctl(fd, driver.MXCFB_SEND_UPDATE, update.p); + if (rc != 0) { + logger.severe("Failed sending update {2}: {0} ({1})", + system.getErrorMessage(), system.errno(), Integer.toUnsignedLong(updateMarker)); + } else if (logger.isLoggable(Level.FINER)) { + logger.finer("Sent update: {0} x {1}, waveform {2}, selected {3}, flags 0x{4}, marker {5}", + update.getUpdateRegionWidth(update.p), update.getUpdateRegionHeight(update.p), + waveformMode, update.getWaveformMode(update.p), + Integer.toHexString(update.getFlags(update.p)).toUpperCase(), + Integer.toUnsignedLong(updateMarker)); + } + return updateMarker; + } + + /** + * Blocks and waits for a previous update request to complete. + * + * @param marker the marker to identify a particular update, returned by + * {@link #sendUpdate(MxcfbUpdateData, int)} + */ + private void waitForUpdateComplete(int marker) { + /* + * This IOCTL call returns: 0 if the marker was not found because the + * update already completed or failed, negative (-1) with the error + * "Connection timed out (110)" if the wait timed out after 5 seconds, + * or positive if the wait occurred and completed (see + * "wait_for_completion_timeout" in "kernel/sched/completion.c"). + */ + int rc = driver.ioctl(fd, driver.MXCFB_WAIT_FOR_UPDATE_COMPLETE, marker); + if (rc < 0) { + logger.severe("Failed waiting for update {2}: {0} ({1})", + system.getErrorMessage(), system.errno(), Integer.toUnsignedLong(marker)); + } else if (rc == 0 && logger.isLoggable(Level.FINER)) { + logger.finer("Update completed before wait: marker {0}", + Integer.toUnsignedLong(marker)); + } + } + + /** + * Sets the delay between the completion of all updates in the driver and + * when the driver should power down the EPDC and display power supplies. To + * disable powering down entirely, use the delay value + * {@link EPDSystem#FB_POWERDOWN_DISABLE}. + * + * @param delay the delay in milliseconds + */ + private void setPowerdownDelay(int delay) { + int rc = driver.ioctl(fd, driver.MXCFB_SET_PWRDOWN_DELAY, delay); + if (rc != 0) { + logger.severe("Failed setting power-down delay to {2}: {0} ({1})", + system.getErrorMessage(), system.errno(), delay); + } + } + + /** + * Gets the current power-down delay from the EPDC driver. + * + * @return the delay in milliseconds + */ + private int getPowerdownDelay() { + var integer = new IntStructure(); + int rc = system.ioctl(fd, driver.MXCFB_GET_PWRDOWN_DELAY, integer.p); + if (rc != 0) { + logger.severe("Failed getting power-down delay: {0} ({1})", + system.getErrorMessage(), system.errno()); + } + return integer.get(integer.p); + } + + /** + * Selects a scheme for the flow of updates within the driver. + * + * @param scheme the update scheme, one of: + *
    + *
  • {@link EPDSystem#UPDATE_SCHEME_SNAPSHOT}
  • + *
  • {@link EPDSystem#UPDATE_SCHEME_QUEUE}
  • + *
  • {@link EPDSystem#UPDATE_SCHEME_QUEUE_AND_MERGE}
  • + *
+ */ + private void setUpdateScheme(int scheme) { + int rc = driver.ioctl(fd, driver.MXCFB_SET_UPDATE_SCHEME, scheme); + if (rc != 0) { + logger.severe("Failed setting update scheme to {2}: {0} ({1})", + system.getErrorMessage(), system.errno(), scheme); + } + } + + /** + * Initializes the EPDC frame buffer device, setting the update scheme to + * {@link EPDSystem#UPDATE_SCHEME_SNAPSHOT}. + */ + void init() { + setWaveformModes(EPDSystem.WAVEFORM_MODE_INIT, EPDSystem.WAVEFORM_MODE_DU, + EPDSystem.WAVEFORM_MODE_GC4, EPDSystem.WAVEFORM_MODE_GC16, + EPDSystem.WAVEFORM_MODE_GC16, EPDSystem.WAVEFORM_MODE_GC16); + setTemperature(EPDSystem.TEMP_USE_AMBIENT); + setAutoUpdateMode(EPDSystem.AUTO_UPDATE_MODE_REGION_MODE); + setPowerdownDelay(POWERDOWN_DELAY); + setUpdateScheme(EPDSystem.UPDATE_SCHEME_SNAPSHOT); + } + + /** + * Clears the display panel. The visible frame buffer should be cleared with + * zeros when called. This method sends two direct updates (all black + * followed by all white) to refresh the screen and clear any ghosting + * effects, and returns when both updates are complete. + *

+ * This method is not thread safe, but it is invoked only + * once from the Event Thread during initialization.

+ */ + void clear() { + lastMarker = sendUpdate(EPDSystem.UPDATE_MODE_FULL, + EPDSystem.WAVEFORM_MODE_DU, 0); + lastMarker = sendUpdate(EPDSystem.UPDATE_MODE_FULL, + EPDSystem.WAVEFORM_MODE_DU, EPDSystem.EPDC_FLAG_ENABLE_INVERSION); + waitForUpdateComplete(lastMarker); + } + + /** + * Sends the updated contents of the Linux frame buffer to the EPDC driver, + * optionally synchronizing with the driver by first waiting for the + * previous update to complete. + *

+ * This method is not thread safe, but it is invoked only + * from the JavaFX Application Thread.

+ */ + void sync() { + if (!settings.noWait) { + waitForUpdateComplete(lastMarker); + } + lastMarker = sendUpdate(syncUpdate, settings.waveformMode); + } + + /** + * Gets the number of bytes from the beginning of the frame buffer to the + * start of its visible resolution. + * + * @return the offset in bytes + */ + int getByteOffset() { + return byteOffset; + } + + /** + * Creates an off-screen byte buffer equal in resolution to the virtual + * resolution of the frame buffer, but with 32 bits per pixel. + * + * @return a 32-bit pixel buffer matching the resolution of the frame buffer + */ + ByteBuffer getOffscreenBuffer() { + /* + * In this case, a direct byte buffer outside of the normal heap is + * faster than a non-direct byte buffer on the heap. The frame rate is + * roughly 10 to 40 percent faster for a framebuffer with 8 bits per + * pixel and 40 to 60 percent faster for a framebuffer with 16 bits per + * pixel, depending on the device processor and screen size. + */ + int size = xresVirtual * yres * Integer.BYTES; + return ByteBuffer.allocateDirect(size); + } + + /** + * Creates a new mapping of the Linux frame buffer device into memory. + * + * @implNote The virtual y-resolution reported by the device driver can be + * wrong, as shown by the following example on the Kobo Glo HD Model N437 + * which reports 2,304 pixels when the correct value is 1,152 pixels + * (6,782,976 / 5,888). Therefore, this method cannot use the frame buffer + * virtual resolution to calculate its size. + * + *
{@code
+     * $ sudo fbset -i
+     *
+     * mode "1448x1072-46"
+     * # D: 80.000 MHz, H: 50.188 kHz, V: 46.385 Hz
+     * geometry 1448 1072 1472 2304 32
+     * timings 12500 16 102 4 4 28 2
+     * rgba 8/16,8/8,8/0,8/24
+     * endmode
+     *
+     * Frame buffer device information:
+     * Name        : mxc_epdc_fb
+     * Address     : 0x88000000
+     * Size        : 6782976
+     * Type        : PACKED PIXELS
+     * Visual      : TRUECOLOR
+     * XPanStep    : 1
+     * YPanStep    : 1
+     * YWrapStep   : 0
+     * LineLength  : 5888
+     * Accelerator : No
+     * }
+ * + * @return a byte buffer containing the mapping of the Linux frame buffer + * device if successful; otherwise {@code null} + */ + ByteBuffer getMappedBuffer() { + ByteBuffer buffer = null; + int size = xresVirtual * yres * bytesPerPixel; + logger.fine("Mapping frame buffer: {0} bytes", size); + long addr = system.mmap(0l, size, LinuxSystem.PROT_WRITE, LinuxSystem.MAP_SHARED, fd, 0); + if (addr == LinuxSystem.MAP_FAILED) { + logger.severe("Failed mapping {2} bytes of frame buffer: {0} ({1})", + system.getErrorMessage(), system.errno(), size); + } else { + buffer = C.getC().NewDirectByteBuffer(addr, size); + } + return buffer; + } + + /** + * Deletes the mapping of the Linux frame buffer device. + * + * @param buffer the byte buffer containing the mapping of the Linux frame + * buffer device + */ + void releaseMappedBuffer(ByteBuffer buffer) { + int size = buffer.capacity(); + logger.fine("Unmapping frame buffer: {0} bytes", size); + int rc = system.munmap(C.getC().GetDirectBufferAddress(buffer), size); + if (rc != 0) { + logger.severe("Failed unmapping {2} bytes of frame buffer: {0} ({1})", + system.getErrorMessage(), system.errno(), size); + } + } + + /** + * Closes the Linux frame buffer device. + */ + void close() { + system.close(fd); + } + + /** + * Gets the native handle to the Linux frame buffer device. + * + * @return the frame buffer device file descriptor + */ + long getNativeHandle() { + return fd; + } + + /** + * Gets the frame buffer width in pixels. See the notes for the + * {@linkplain EPDFrameBuffer#EPDFrameBuffer constructor} above. + * + * @implNote When using an 8-bit, unrotated, and uninverted frame buffer in + * the Y8 pixel format, the Kobo Clara HD Model N249 works only when this + * method returns the visible x-resolution ({@code xres}) instead of the + * normal virtual x-resolution ({@code xresVirtual}). + * + * @return the width in pixels + */ + int getWidth() { + return settings.getWidthVisible ? xres : xresVirtual; + } + + /** + * Gets the frame buffer height in pixels. + * + * @return the height in pixels + */ + int getHeight() { + return yres; + } + + /** + * Gets the frame buffer color depth in bits per pixel. + * + * @return the color depth in bits per pixel + */ + int getBitDepth() { + return bitsPerPixel; + } + + @Override + public String toString() { + return MessageFormat.format("{0}[width={1} height={2} bitDepth={3}]", + getClass().getName(), getWidth(), getHeight(), getBitDepth()); + } +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EPDInputDeviceRegistry.java b/src/main/java/com/sun/glass/ui/monocle/EPDInputDeviceRegistry.java new file mode 100644 index 0000000..bee92e1 --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EPDInputDeviceRegistry.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +import java.io.File; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +/** + * Maintains an observable set of input devices. This class is responsible for + * detecting the attached input devices and generating their input events. Run + * the following commands as root to list the properties of the keypad + * (event0) and touch screen (event1) input devices on the system: + *
{@code
+ * # udevadm info -q all -n /dev/input/event0
+ * # udevadm info -q all -n /dev/input/event1
+ * }
+ * + * @implNote {@code EPDPlatform} creates an instance of this class instead of + * {@code LinuxInputDeviceRegistry} because this class replaces two of its + * methods. + *

+ * It replaces the {@link #createDevice} method to work around bug JDK-8201568 + * by opening the device before creating its {@code LinuxInputDevice}. It also + * replaces the {@link #addDeviceInternal} method to work around older versions + * of udev, such as version 142, which do not provide the + * ID_INPUT_TOUCHSCREEN=1 property for the touch screen device. + * {@link LinuxInputDevice#isTouch} requires that property and value; otherwise + * the method returns {@code false}, and the touch screen is mistakenly assigned + * a keyboard input processor. Newer versions of udev, such as version + * 204, provide the correct property and value.

+ *

+ * Therefore, once JDK-8201568 is fixed and the old version of udev is no + * longer in use, this entire class can be removed and replaced by + * {@code LinuxInputDeviceRegistry}.

+ */ +class EPDInputDeviceRegistry extends InputDeviceRegistry { + + /** + * The file name of the keypad input device. + */ + private static final String KEYPAD_FILENAME = "event0"; + + /** + * The file name of the touch screen input device. + */ + private static final String TOUCH_FILENAME = "event1"; + + /** + * Creates a new observable set of input devices. + * + * @implNote This is a verbatim copy of the {@link LinuxInputDeviceRegistry} + * constructor. + * + * @param headless {@code true} if this environment cannot support a + * display, keyboard, and mouse; otherwise {@code false} + */ + EPDInputDeviceRegistry(boolean headless) { + if (headless) { + // Keep the registry but do not bind it to udev. + return; + } + Map deviceMap = new HashMap<>(); + UdevListener udevListener = (action, event) -> { + String subsystem = event.get("SUBSYSTEM"); + String devPath = event.get("DEVPATH"); + String devName = event.get("DEVNAME"); + if (subsystem != null && subsystem.equals("input") + && devPath != null && devName != null) { + try { + File sysPath = new File("/sys", devPath); + if (action.equals("add") + || (action.equals("change") + && !deviceMap.containsKey(sysPath))) { + File devNode = new File(devName); + LinuxInputDevice device = createDevice( + devNode, sysPath, event); + if (device != null) { + deviceMap.put(sysPath, device); + } + } else if (action.equals("remove")) { + LinuxInputDevice device = deviceMap.get(sysPath); + deviceMap.remove(sysPath); + if (device != null) { + devices.remove(device); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } + }; + Udev.getInstance().addListener(udevListener); + // Request updates for existing devices + SysFS.triggerUdevNotification("input"); + } + + /** + * Creates a Linux input device with the given properties. + * + * @implNote Works around bug + * JDK-8201568, + * "zForce touchscreen input device fails when closed and immediately + * reopened," by opening the device before creating its + * {@code LinuxInputDevice}. + * + * @param devNode the file representing the device name, such as + * /dev/input/event1 + * @param sysPath the system path to the device, such as + * /sys/devices/virtual/input/input1/event1 + * @param udevManifest the set of properties for the device + * @return the new Linux input device, or {@code null} if no processor is + * found for the device + * @throws IOException if an error occurs opening the device + */ + private LinuxInputDevice createDevice(File devNode, File sysPath, + Map udevManifest) throws IOException { + LinuxSystem system = LinuxSystem.getLinuxSystem(); + system.open(devNode.getPath(), LinuxSystem.O_RDONLY); + + var device = new LinuxInputDevice(devNode, sysPath, udevManifest); + return addDeviceInternal(device, "Linux input: " + devNode.toString()); + } + + /** + * Creates an input processor for the device which runs on a new daemon + * background thread. Run the following commands as root to display + * the events generated by the keypad (0) and touch screen (1) input devices + * when you press buttons or touch the screen: + *
{@code
+     * # input-events 0
+     * # input-events 1
+     * }
+ * + * @implNote The "mxckpd" keypad device driver does not generate EV_SYN + * events, yet the {@link LinuxInputDevice#run} method schedules an event + * for processing only after receiving the EV_SYN event terminator (see the + * {@link LinuxEventBuffer#put} method). The events from this device, + * therefore, are never delivered to the JavaFX application. The "gpio-keys" + * keypad device driver on more recent systems, though, correctly generates + * the EV_SYN event terminator. + * + * @param device the Linux input device + * @param name the device name, such as /dev/input/event0 + * @return the Linux input device, or {@code null} if no input processor is + * found for the device + */ + private LinuxInputDevice addDeviceInternal(LinuxInputDevice device, String name) { + LinuxInputProcessor processor = null; + if (name.endsWith(KEYPAD_FILENAME)) { + processor = new LinuxKeyProcessor(); + } else if (name.endsWith(TOUCH_FILENAME)) { + processor = new LinuxSimpleTouchProcessor(device); + } + if (processor == null) { + return null; + } else { + device.setInputProcessor(processor); + var thread = new Thread(device); + thread.setName(name); + thread.setDaemon(true); + thread.start(); + devices.add(device); + return device; + } + } + + @Override + public String toString() { + return MessageFormat.format("{0}[devices={1}]", getClass().getName(), devices); + } +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EPDPlatform.java b/src/main/java/com/sun/glass/ui/monocle/EPDPlatform.java new file mode 100644 index 0000000..946ecbb --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EPDPlatform.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +/** + * A native platform for a Linux system with an electrophoretic display, also + * called an e-paper display. + */ +class EPDPlatform extends LinuxPlatform { + + /** + * Creates a new Monocle EPD Platform. + */ + EPDPlatform() { + EPDSystem.getEPDSystem().loadLibrary(); + } + + @Override + protected InputDeviceRegistry createInputDeviceRegistry() { + return new EPDInputDeviceRegistry(false); + } + + @Override + protected NativeScreen createScreen() { + try { + return new EPDScreen(); + } catch (RuntimeException e) { + return new HeadlessScreen(); + } + } +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EPDPlatformFactory.java b/src/main/java/com/sun/glass/ui/monocle/EPDPlatformFactory.java new file mode 100644 index 0000000..9740c37 --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EPDPlatformFactory.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +import com.sun.javafx.logging.PlatformLogger; +import com.sun.javafx.util.Logging; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.text.MessageFormat; + +/** + * A factory object for creating the native platform on a Linux system with an + * electrophoretic display, also called an e-paper display, found on e-readers + * such as the Amazon Kindle and Rakuten Kobo. + */ +class EPDPlatformFactory extends NativePlatformFactory { + + /** + * The major version number of this platform factory. + */ + private static final int MAJOR_VERSION = 1; + + /** + * The minor version number of this platform factory. + */ + private static final int MINOR_VERSION = 0; + + /** + * The file that contains the name of the frame buffer device when CONFIG_FB + * is defined during kernel compilation. + */ + private static final String FB_FILE = "/proc/fb"; + + /** + * The name of the Mobile Extreme Convergence Electrophoretic Display + * Controller Frame Buffer device. + */ + private static final String FB_NAME = "mxc_epdc_fb"; + + private final PlatformLogger logger = Logging.getJavaFXLogger(); + + /** + * Creates a new factory object for the Monocle EPD Platform. + */ + EPDPlatformFactory() { + } + + @Override + protected boolean matches() { + @SuppressWarnings("removal") + String fbinfo = AccessController.doPrivileged((PrivilegedAction) () -> { + String line = null; + try (var reader = new BufferedReader(new FileReader(FB_FILE))) { + line = reader.readLine(); + } catch (IOException e) { + logger.severe("Failed reading " + FB_FILE, e); + } + return line; + }); + return fbinfo != null && fbinfo.contains(FB_NAME); + } + + @Override + protected NativePlatform createNativePlatform() { + return new EPDPlatform(); + } + + @Override + protected int getMajorVersion() { + return MAJOR_VERSION; + } + + @Override + protected int getMinorVersion() { + return MINOR_VERSION; + } + + @Override + public String toString() { + return MessageFormat.format("{0}[majorVersion={1} minorVersion={2} matches=\"{3} in {4}\"]", + getClass().getName(), getMajorVersion(), getMinorVersion(), FB_NAME, FB_FILE); + } +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EPDScreen.java b/src/main/java/com/sun/glass/ui/monocle/EPDScreen.java new file mode 100644 index 0000000..7c924e7 --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EPDScreen.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +import com.sun.glass.ui.Pixels; +import com.sun.javafx.logging.PlatformLogger; +import com.sun.javafx.util.Logging; +import java.io.IOException; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.text.MessageFormat; + +/** + * A native screen for an electrophoretic display, also called an e-paper + * display. This class uploads pixels directly into the Linux frame buffer if it + * is configured with a color depth of 32 bits per pixel. Otherwise, this class + * uploads pixels into a 32-bit off-screen composition buffer and converts the + * pixels to the correct format when writing them to the Linux frame buffer. + */ +class EPDScreen implements NativeScreen { + + /** + * The system property for setting the frame buffer device path. + */ + private static final String FB_PATH_KEY = "monocle.screen.fb"; + + /** + * The default value for the frame buffer device path. + */ + private static final String FB_PATH_DEFAULT = "/dev/fb0"; + + /** + * The density of this screen in pixels per inch. For now, the value is + * hard-coded to the density of a 6-inch display panel with 800 x 600 px at + * 167 ppi. + */ + private static final int DPI = 167; + + /** + * The ratio of physical pixels to logical pixels on this screen. For now, + * the value is hard-coded to a ratio of 1.0. + */ + private static final float SCALE = 1.0f; + + private final PlatformLogger logger = Logging.getJavaFXLogger(); + + private final String fbPath; + private final EPDFrameBuffer fbDevice; + private final ByteBuffer fbMapping; + private final FileChannel fbChannel; + private final Framebuffer pixels; + private final int width; + private final int height; + private final int bitDepth; + + private boolean isShutdown; + + /** + * Creates a native screen for the electrophoretic display. + * + * @throws IllegalStateException if an error occurs opening the frame buffer + */ + EPDScreen() { + @SuppressWarnings("removal") + String tmp = AccessController.doPrivileged((PrivilegedAction) () + -> System.getProperty(FB_PATH_KEY, FB_PATH_DEFAULT)); + fbPath = tmp; + try { + fbDevice = new EPDFrameBuffer(fbPath); + fbDevice.init(); + + width = fbDevice.getWidth(); + height = fbDevice.getHeight(); + bitDepth = fbDevice.getBitDepth(); + logger.fine("Native screen geometry: {0} px x {1} px x {2} bpp", + width, height, bitDepth); + + /* + * If the Linux frame buffer is configured for 32-bit color, compose + * the pixels directly into it. Otherwise, compose the pixels into + * an off-screen buffer and write them to the frame buffer when + * swapping buffers. + * + * With an LCD display, there must be space for two full screens to + * be able to write directly into the frame buffer, displaying one + * while updating the other. The Snapshot update mode of an e-paper + * display, though, allows us to reuse the same frame buffer region + * immediately after sending an update. + */ + ByteBuffer mapping = null; + if (bitDepth == Integer.SIZE) { + mapping = fbDevice.getMappedBuffer(); + } + if (mapping != null) { + fbMapping = mapping; + fbChannel = null; + } else { + Path path = FileSystems.getDefault().getPath(fbPath); + fbChannel = FileChannel.open(path, StandardOpenOption.WRITE); + fbMapping = null; + } + } catch (IOException e) { + String msg = MessageFormat.format("Failed opening frame buffer: {0}", fbPath); + logger.severe(msg, e); + throw new IllegalStateException(msg, e); + } + + /* + * Note that pixels.clearBufferContents() throws a NullPointerException + * if the last parameter of its constructor ("clear") is false. + */ + ByteBuffer buffer = fbMapping != null ? fbMapping : fbDevice.getOffscreenBuffer(); + buffer.order(ByteOrder.nativeOrder()); + pixels = new FramebufferY8(buffer, width, height, bitDepth, true); + clearScreen(); + } + + /** + * Closes the Linux frame buffer device and related resources. Called only + * from the {@link #shutdown} method, which is called only once. + */ + private void close() { + try { + if (fbChannel != null) { + fbChannel.close(); + } + } catch (IOException e) { + logger.severe("Failed closing frame buffer channel", e); + } finally { + if (fbMapping != null) { + fbDevice.releaseMappedBuffer(fbMapping); + } + fbDevice.close(); + } + } + + /** + * Writes the content of the off-screen buffer to the Linux frame buffer, if + * necessary. If the frame buffer is mapped, the content to display is + * already there, and this method does nothing. + */ + private void writeBuffer() { + if (fbChannel != null) { + try { + fbChannel.position(fbDevice.getByteOffset()); + pixels.write(fbChannel); + } catch (IOException e) { + logger.severe("Failed writing to frame buffer channel", e); + } + } + } + + /** + * Clears the screen. + */ + private void clearScreen() { + pixels.clearBufferContents(); + writeBuffer(); + fbDevice.clear(); + } + + @Override + public int getDepth() { + return bitDepth; + } + + @Override + public int getNativeFormat() { + /* + * The native pixel format must be one of either + * Pixels.Format.BYTE_BGRA_PRE when the system byte order is + * ByteOrder.LITTLE_ENDIAN, or Pixels.Format.BYTE_ARGB when the system + * byte order is ByteOrder.BIG_ENDIAN. The ARMv7-A architecture is + * little endian by default. + */ + return Pixels.Format.BYTE_BGRA_PRE; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public int getDPI() { + return DPI; + } + + @Override + public long getNativeHandle() { + return fbDevice.getNativeHandle(); + } + + @Override + public synchronized void shutdown() { + close(); + isShutdown = true; + } + + @Override + public synchronized void uploadPixels(Buffer b, int x, int y, int width, int height, float alpha) { + pixels.composePixels(b, x, y, width, height, alpha); + } + + @Override + public synchronized void swapBuffers() { + if (!isShutdown && pixels.hasReceivedData()) { + writeBuffer(); + fbDevice.sync(); + pixels.reset(); + } + } + + @Override + public synchronized ByteBuffer getScreenCapture() { + return pixels.getBuffer().asReadOnlyBuffer(); + } + + @Override + public float getScale() { + return SCALE; + } + + @Override + public String toString() { + return MessageFormat.format("{0}[width={1} height={2} depth={3} DPI={4} scale={5,number,0.0#}]", + getClass().getName(), getWidth(), getHeight(), getDepth(), getDPI(), getScale()); + } +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EPDSettings.java b/src/main/java/com/sun/glass/ui/monocle/EPDSettings.java new file mode 100644 index 0000000..5b162d0 --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EPDSettings.java @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +import com.sun.javafx.logging.PlatformLogger; +import com.sun.javafx.logging.PlatformLogger.Level; +import com.sun.javafx.util.Logging; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.HashMap; + +/** + * Provides the values of the EPD system properties. + */ +class EPDSettings { + + /** + * Sets the frame buffer color depth and pixel format: 8 for 8-bit grayscale + * in the Y8 pixel format, 16 for 16-bit color in the RGB565 pixel format, + * or 32 for 32-bit color in the ARGB32 pixel format. The default is 32. + *

+ * Using the 32-bit format allows JavaFX to render directly into the Linux + * frame buffer and avoid the step of copying and converting each pixel from + * an off-screen composition buffer.

+ * + * @implNote Corresponds to the {@code bits_per_pixel} field of + * {@code fb_var_screeninfo} in linux/fb.h. + */ + private static final String BITS_PER_PIXEL = "monocle.epd.bitsPerPixel"; + + /** + * Sets the frame buffer rotation: 0 for unrotated (UR), 1 for 90 degrees + * clockwise (CW), 2 for 180 degrees upside-down (UD), and 3 for 90 degrees + * counter-clockwise (CCW). The default is 0. + *

+ * The unrotated and upside-down settings are in landscape mode, while the + * clockwise and counter-clockwise settings are in portrait.

+ * + * @implNote Corresponds to the {@code rotate} field of + * {@code fb_var_screeninfo} in linux/fb.h. + */ + private static final String ROTATE = "monocle.epd.rotate"; + + /** + * Sets an indicator for the frame buffer grayscale value: {@code true} to + * invert the pixels of all updates when using 8-bit grayscale in the Y8 + * pixel format; otherwise {@code false}. The default is {@code false}. + *

+ * The value is ignored when the frame buffer is not set to 8-bit grayscale + * in the Y8 pixel format.

+ * + * @implNote Corresponds to the {@code GRAYSCALE_8BIT_INVERTED} constant in + * linux/mxcfb.h. + */ + private static final String Y8_INVERTED = "monocle.epd.Y8Inverted"; + + /** + * Indicates whether to wait for the previous update to complete before + * sending the next update: {@code true} to avoid waiting and send updates + * as quickly as possible; otherwise {@code false}. The default is + * {@code false}. + *

+ * The number of outstanding updates is limited by the device controller to + * either 16 or 64 concurrent non-colliding updates, depending on the model. + * A value of {@code true} may result in errors if the maximum number of + * concurrent non-colliding updates is exceeded.

+ * + * @implNote Corresponds to the IOCTL call constant + * {@code MXCFB_WAIT_FOR_UPDATE_COMPLETE} in linux/mxcfb.h. + */ + private static final String NO_WAIT = "monocle.epd.noWait"; + + /** + * Sets the waveform mode used for updates: 1 for black-and-white direct + * update (DU), 2 for 16 levels of gray (GC16), 3 for 4 levels of gray + * (GC4), 4 for pure black-and-white animation (A2), and 257 for the + * automatic selection of waveform mode based on the number of gray levels + * in the update (AUTO). The default is 257. + *

+ * Automatic selection chooses one of 1 (DU), 2 (GC16), or 3 (GC4). If the + * waveform mode is set to 2 (GC16), it may be upgraded to a compatible but + * optimized mode internal to the driver, if available.

+ * + * @implNote Corresponds to the {@code waveform_mode} field of + * {@code mxcfb_update_data} in linux/mxcfb.h. + */ + private static final String WAVEFORM_MODE = "monocle.epd.waveformMode"; + + /** + * Sets the update flag for pixel inversion: {@code true} to invert the + * pixels of each update; otherwise {@code false}. The default is + * {@code false}. + * + * @implNote Corresponds to the {@code EPDC_FLAG_ENABLE_INVERSION} constant + * in linux/mxcfb.h. + */ + private static final String FLAG_ENABLE_INVERSION = "monocle.epd.enableInversion"; + + /** + * Sets the update flag for monochrome conversion: {@code true} to convert + * the pixels of each update to pure black and white using a 50-percent + * threshold; otherwise {@code false}. The default is {@code false}. + * + * @implNote Corresponds to the {@code EPDC_FLAG_FORCE_MONOCHROME} constant + * in linux/mxcfb.h. + */ + private static final String FLAG_FORCE_MONOCHROME = "monocle.epd.forceMonochrome"; + + /** + * Sets the update flag for 1-bit dithering: {@code true} to dither each + * update in an 8-bit Y8 frame buffer to 1-bit black and white, if + * available; otherwise {@code false}. The default is {@code false}. + * + * @implNote Corresponds to the {@code EPDC_FLAG_USE_DITHERING_Y1} constant + * in linux/mxcfb.h. + */ + private static final String FLAG_USE_DITHERING_Y1 = "monocle.epd.useDitheringY1"; + + /** + * Sets the update flag for 4-bit dithering: {@code true} to dither each + * update in an 8-bit Y8 frame buffer to 4-bit grayscale, if available; + * otherwise {@code false}. The default is {@code false}. + * + * @implNote Corresponds to the {@code EPDC_FLAG_USE_DITHERING_Y4} constant + * in linux/mxcfb.h. + */ + private static final String FLAG_USE_DITHERING_Y4 = "monocle.epd.useDitheringY4"; + + /** + * Indicates whether to work around the bug found on devices, such as the + * Kobo Clara HD Model N249, which require a screen width equal to the + * visible x-resolution, instead of the normal virtual x-resolution, when + * using an 8-bit, unrotated, and uninverted frame buffer in the Y8 pixel + * format: {@code true} to work around the bug; otherwise {@code false}. The + * default is {@code false}. + */ + private static final String FIX_WIDTH_Y8UR = "monocle.epd.fixWidthY8UR"; + + private static final String[] EPD_PROPERTIES = { + BITS_PER_PIXEL, + ROTATE, + Y8_INVERTED, + NO_WAIT, + WAVEFORM_MODE, + FLAG_ENABLE_INVERSION, + FLAG_FORCE_MONOCHROME, + FLAG_USE_DITHERING_Y1, + FLAG_USE_DITHERING_Y4, + FIX_WIDTH_Y8UR + }; + + private static final int BITS_PER_PIXEL_DEFAULT = Integer.SIZE; + private static final int ROTATE_DEFAULT = EPDSystem.FB_ROTATE_UR; + private static final int WAVEFORM_MODE_DEFAULT = EPDSystem.WAVEFORM_MODE_AUTO; + + private static final int[] BITS_PER_PIXEL_PERMITTED = { + Byte.SIZE, + Short.SIZE, + Integer.SIZE + }; + + private static final int[] ROTATIONS_PERMITTED = { + EPDSystem.FB_ROTATE_UR, + EPDSystem.FB_ROTATE_CW, + EPDSystem.FB_ROTATE_UD, + EPDSystem.FB_ROTATE_CCW + }; + + private static final int[] WAVEFORM_MODES_PERMITTED = { + EPDSystem.WAVEFORM_MODE_DU, + EPDSystem.WAVEFORM_MODE_GC16, + EPDSystem.WAVEFORM_MODE_GC4, + EPDSystem.WAVEFORM_MODE_A2, + EPDSystem.WAVEFORM_MODE_AUTO + }; + + /** + * Obtains a new instance of this class with the current values of the EPD + * system properties. + * + * @return a new {@code EPDSettings} instance + */ + @SuppressWarnings("removal") + static EPDSettings newInstance() { + return AccessController.doPrivileged( + (PrivilegedAction) () -> new EPDSettings()); + } + + private final PlatformLogger logger = Logging.getJavaFXLogger(); + + private final boolean y8inverted; + private final boolean flagEnableInversion; + private final boolean flagForceMonochrome; + private final boolean flagUseDitheringY1; + private final boolean flagUseDitheringY4; + private final boolean fixWidthY8UR; + + final int bitsPerPixel; + final int rotate; + final boolean noWait; + final int waveformMode; + final int grayscale; + final int flags; + final boolean getWidthVisible; + + /** + * Creates a new EPDSettings, capturing the current values of the EPD system + * properties. + */ + private EPDSettings() { + if (logger.isLoggable(Level.FINE)) { + HashMap map = new HashMap<>(); + for (String key : EPD_PROPERTIES) { + String value = System.getProperty(key); + if (value != null) { + map.put(key, value); + } + } + logger.fine("EPD system properties: {0}", map); + } + + bitsPerPixel = getInteger(BITS_PER_PIXEL, BITS_PER_PIXEL_DEFAULT, BITS_PER_PIXEL_PERMITTED); + rotate = getInteger(ROTATE, ROTATE_DEFAULT, ROTATIONS_PERMITTED); + noWait = Boolean.getBoolean(NO_WAIT); + waveformMode = getInteger(WAVEFORM_MODE, WAVEFORM_MODE_DEFAULT, WAVEFORM_MODES_PERMITTED); + + y8inverted = Boolean.getBoolean(Y8_INVERTED); + if (bitsPerPixel == Byte.SIZE) { + if (y8inverted) { + grayscale = EPDSystem.GRAYSCALE_8BIT_INVERTED; + } else { + grayscale = EPDSystem.GRAYSCALE_8BIT; + } + } else { + grayscale = 0; + } + + flagEnableInversion = Boolean.getBoolean(FLAG_ENABLE_INVERSION); + flagForceMonochrome = Boolean.getBoolean(FLAG_FORCE_MONOCHROME); + flagUseDitheringY1 = Boolean.getBoolean(FLAG_USE_DITHERING_Y1); + flagUseDitheringY4 = Boolean.getBoolean(FLAG_USE_DITHERING_Y4); + flags = (flagEnableInversion ? EPDSystem.EPDC_FLAG_ENABLE_INVERSION : 0) + | (flagForceMonochrome ? EPDSystem.EPDC_FLAG_FORCE_MONOCHROME : 0) + | (flagUseDitheringY1 ? EPDSystem.EPDC_FLAG_USE_DITHERING_Y1 : 0) + | (flagUseDitheringY4 ? EPDSystem.EPDC_FLAG_USE_DITHERING_Y4 : 0); + + fixWidthY8UR = Boolean.getBoolean(FIX_WIDTH_Y8UR); + getWidthVisible = fixWidthY8UR && grayscale == EPDSystem.GRAYSCALE_8BIT + && rotate == EPDSystem.FB_ROTATE_UR; + } + + /** + * Gets an integer system property. + * + * @param key the property name + * @param def the default value + * @param list a list of the permitted values for the property + * @return the value provided for the property if it is equal to one of the + * permitted values; otherwise, the default value + */ + private int getInteger(String key, int def, int... list) { + int value = Integer.getInteger(key, def); + boolean found = false; + for (int i = 0; i < list.length && !found; i++) { + found = value == list[i]; + } + if (!found) { + logger.severe("Value of {0}={1} not in {2}; using default ({3})", + key, value, Arrays.toString(list), def); + value = def; + } + return value; + } + + @Override + public String toString() { + return MessageFormat.format("{0}[bitsPerPixel={1} rotate={2} " + + "noWait={3} waveformMode={4} grayscale={5} flags=0x{6} " + + "getWidthVisible={7}]", + getClass().getName(), bitsPerPixel, rotate, + noWait, waveformMode, grayscale, Integer.toHexString(flags), + getWidthVisible); + } +} diff --git a/src/main/java/com/sun/glass/ui/monocle/EPDSystem.java b/src/main/java/com/sun/glass/ui/monocle/EPDSystem.java new file mode 100644 index 0000000..cd5455d --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/EPDSystem.java @@ -0,0 +1,752 @@ +/* + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +import com.sun.glass.utils.NativeLibLoader; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.security.Permission; +import java.text.MessageFormat; + +/** + * A Java-language interface to the device API of the Electrophoretic Display + * Controller (EPDC) frame buffer driver. {@code EPDSystem} is a singleton. Its + * instance is obtained by calling the {@link EPDSystem#getEPDSystem} method. + * This class also extends {@link LinuxSystem.FbVarScreenInfo} to provide all of + * the fields in {@code fb_var_screeninfo}, defined in linux/fb.h. + */ +class EPDSystem { + + /** + * The value for {@link FbVarScreenInfo#setActivate} to ensure that the EPDC + * driver receives the initialization request. + */ + static final int FB_ACTIVATE_FORCE = 128; + + /** + * The value for {@link FbVarScreenInfo#setRotate} to set the frame buffer + * rotation to un-rotated (upright landscape mode). + */ + static final int FB_ROTATE_UR = 0; + + /** + * The value for {@link FbVarScreenInfo#setRotate} to set the frame buffer + * rotation to 90-degrees clockwise (upside-down portrait mode). + */ + static final int FB_ROTATE_CW = 1; + + /** + * The value for {@link FbVarScreenInfo#setRotate} to set the frame buffer + * rotation to 180-degrees upside-down (upside-down landscape mode). + */ + static final int FB_ROTATE_UD = 2; + + /** + * The value for {@link FbVarScreenInfo#setRotate} to set the frame buffer + * rotation to 90-degrees counter-clockwise (upright portrait mode). + */ + static final int FB_ROTATE_CCW = 3; + + /** + * The value for {@link FbVarScreenInfo#setGrayscale} to set the frame + * buffer to an 8-bit grayscale pixel format. + */ + static final int GRAYSCALE_8BIT = 0x1; + + /** + * The value for {@link FbVarScreenInfo#setGrayscale} to set the frame + * buffer to an inverted 8-bit grayscale pixel format. + */ + static final int GRAYSCALE_8BIT_INVERTED = 0x2; + + /** + * Region update mode, in which updates to the display must be submitted + * with an IOCTL call to {@link #MXCFB_SEND_UPDATE}. + */ + static final int AUTO_UPDATE_MODE_REGION_MODE = 0; + + /** + * Automatic mode, in which updates are generated automatically by the + * driver when it detects that pages in a frame buffer memory region have + * been modified. + */ + static final int AUTO_UPDATE_MODE_AUTOMATIC_MODE = 1; + + /** + * Snapshot update scheme, which processes the contents of the frame buffer + * immediately and stores the update in a memory buffer internal to the + * driver. When the IOCTL call to {@link #MXCFB_SEND_UPDATE} returns, the + * frame buffer region is free and can be modified without affecting the + * update. + */ + static final int UPDATE_SCHEME_SNAPSHOT = 0; + + /** + * Queue update scheme, which uses a work queue to handle the processing of + * updates asynchronously. When updates are submitted with an IOCTL call to + * {@link #MXCFB_SEND_UPDATE}, they are added to the queue and processed in + * order as the EPDC hardware resources become available. The frame buffer + * contents processed and displayed, therefore, may not reflect what was + * present in the frame buffer when the update was submitted. + */ + static final int UPDATE_SCHEME_QUEUE = 1; + + /** + * Queue and Merge update scheme, which adds a merging step to the Queue + * update scheme. Before an update is added to the work queue, it is + * compared with other pending updates. If a pending update matches the mode + * and flags of the current update and also overlaps the update region, it + * will be merged with the current update. After all such merges, the final + * merged update is submitted to the queue. + */ + static final int UPDATE_SCHEME_QUEUE_AND_MERGE = 2; + + /** + * Partial update mode, which applies the waveform to only the pixels that + * change in a given region. + */ + static final int UPDATE_MODE_PARTIAL = 0x0; + + /** + * Full update mode, which applies the waveform to all pixels in a given + * region. + */ + static final int UPDATE_MODE_FULL = 0x1; + + /** + * Auto waveform mode, which requests the driver to select the actual + * waveform mode automatically based on the contents of the updated region. + */ + static final int WAVEFORM_MODE_AUTO = 257; + + /** + * The temperature value that requests the driver to use the ambient + * temperature of the device. + */ + static final int TEMP_USE_AMBIENT = 0x1000; + + /** + * An update flag to enable inversion of all pixels in the updated region. + */ + static final int EPDC_FLAG_ENABLE_INVERSION = 0x01; + + /** + * An update flag to enable black-and-white posterization of all pixels in + * the updated region. + */ + static final int EPDC_FLAG_FORCE_MONOCHROME = 0x02; + + /** + * An update flag to enable dithering of an 8-bit grayscale frame buffer to + * 1-bit black and white, if supported by the driver or hardware. + */ + static final int EPDC_FLAG_USE_DITHERING_Y1 = 0x2000; + + /** + * An update flag to enable dithering of an 8-bit grayscale frame buffer to + * 4-bit grayscale, if supported by the driver or hardware. + */ + static final int EPDC_FLAG_USE_DITHERING_Y4 = 0x4000; + + /** + * The power-down delay value to disable the powering down of the EPDC and + * display power supplies. + */ + static final int FB_POWERDOWN_DISABLE = -1; + + /** + * Initialization waveform (0x0...0xF to 0xF in ~4000 ms). Clears the screen + * to all white. + *

+ * "A first exemplary drive scheme provides waveforms that may be used to + * change the display state of a pixel from any initial display state to a + * new display state of white. The first drive scheme may be referred to as + * an initialization or 'INIT' drive scheme." [United States Patent + * 9,280,955]

+ */ + static final int WAVEFORM_MODE_INIT = 0; + + /** + * Direct update waveform (0x0...0xF to 0x0 or 0xF in ~260 ms). Changes gray + * pixels to black or white. + *

+ * "A second exemplary drive scheme provides waveforms that may be used to + * change the display state of a pixel from any initial display state to a + * new display state of either white or black. The second drive scheme may + * be referred to as a 'DU' drive scheme." [United States Patent + * 9,280,955]

+ */ + static final int WAVEFORM_MODE_DU = 1; + + /** + * Gray 4-level waveform (0x0...0xF to 0x0, 0x5, 0xA, or 0xF in ~500 ms). + * Supports 2-bit grayscale images and text with lower quality. + *

+ * "A third exemplary drive scheme provides waveforms that may be used to + * change the display state of a pixel from any initial display state to a + * new display state. The initial state may be any four-bit (16 gray states) + * value. The new display state may be any two-bit (4 gray states) value. + * The third drive scheme may be referred to as a 'GC4' drive scheme." + * [United States Patent 9,280,955]

+ */ + static final int WAVEFORM_MODE_GC4 = 3; + + /** + * Gray 16-level waveform (0x0...0xF to 0x0...0xF in ~760 ms). Supports + * 4-bit grayscale images and text with high quality. + *

+ * "A fourth exemplary drive scheme provides waveforms that may be used to + * change the display state of a pixel from any initial display state to a + * new display state. The initial state may be any four-bit (16 gray states) + * value. The new display state may be any four-bit (16 gray states) value. + * The fourth drive scheme may be referred to as a 'GC16' drive scheme." + * [United States Patent 9,280,955]

+ */ + static final int WAVEFORM_MODE_GC16 = 2; + + /** + * Animation waveform (0x0 or 0xF to 0x0 or 0xF in ~120 ms). Provides a fast + * 1-bit black-and-white animation mode of up to eight frames per second. + *

+ * "A fifth exemplary drive scheme provides waveforms that may be used to + * change the display state of a pixel from an initial display state to a + * new display state. The initial state must be white or black. The new + * display state may be black or white. The fifth drive scheme may be + * referred to as an 'A2' drive scheme. An advantage of A2 waveforms is that + * they have generally short waveform periods, providing rapid display + * updates. A disadvantage of A2 waveforms is that there use may result in + * ghosting artifacts." [United States Patent 9,280,955]

+ */ + static final int WAVEFORM_MODE_A2 = 4; + + private static final Permission PERMISSION = new RuntimePermission("loadLibrary.*"); + private static final EPDSystem INSTANCE = new EPDSystem(); + + /** + * Checks for permission to load native libraries if running under a + * security manager. + */ + private static void checkPermissions() { + @SuppressWarnings("removal") + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(PERMISSION); + } + } + + /** + * Obtains the single instance of {@code EPDSystem}. Calling this method + * requires the "loadLibrary.*" {@code RuntimePermission}. The + * {@link #loadLibrary} method must be called on the EPDSystem instance + * before any system calls can be made using it. + * + * @return the {@code EPDSystem} instance + */ + static EPDSystem getEPDSystem() { + checkPermissions(); + return INSTANCE; + } + + /** + * The IOCTL request code to define a mapping for common waveform modes. + */ + final int MXCFB_SET_WAVEFORM_MODES; + + /** + * The IOCTL request code to set the temperature used by the EPDC driver in + * subsequent panel updates. + */ + final int MXCFB_SET_TEMPERATURE; + + /** + * The IOCTL request code to select between automatic and region update + * mode. + */ + final int MXCFB_SET_AUTO_UPDATE_MODE; + + /** + * The IOCTL request code to update a region of the frame buffer to the + * display. + */ + final int MXCFB_SEND_UPDATE; + + /** + * The IOCTL request code to block and wait for a previous update to + * complete. + */ + final int MXCFB_WAIT_FOR_UPDATE_COMPLETE; + + /** + * The IOCTL request code to set the delay between the completion of all + * updates in the driver and when the driver should power down the EPDC and + * display power supplies. + */ + final int MXCFB_SET_PWRDOWN_DELAY; + + /** + * The IOCTL request code to get the current power-down delay value from the + * driver. + */ + final int MXCFB_GET_PWRDOWN_DELAY; + + /** + * The IOCTL request code to select a scheme for the flow of updates within + * the driver. + */ + final int MXCFB_SET_UPDATE_SCHEME; + + private final LinuxSystem system; + + /** + * Creates the single instance of {@code EPDSystem}. + */ + private EPDSystem() { + system = LinuxSystem.getLinuxSystem(); + + MXCFB_SET_WAVEFORM_MODES = system.IOW('F', 0x2B, MxcfbWaveformModes.BYTES); + MXCFB_SET_TEMPERATURE = system.IOW('F', 0x2C, Integer.BYTES); + MXCFB_SET_AUTO_UPDATE_MODE = system.IOW('F', 0x2D, Integer.BYTES); + MXCFB_SEND_UPDATE = system.IOW('F', 0x2E, MxcfbUpdateData.BYTES); + MXCFB_WAIT_FOR_UPDATE_COMPLETE = system.IOW('F', 0x2F, Integer.BYTES); + MXCFB_SET_PWRDOWN_DELAY = system.IOW('F', 0x30, Integer.BYTES); + MXCFB_GET_PWRDOWN_DELAY = system.IOR('F', 0x31, IntStructure.BYTES); + MXCFB_SET_UPDATE_SCHEME = system.IOW('F', 0x32, Integer.BYTES); + } + + /** + * Loads the native libraries required to make system calls using this + * {@code EPDSystem} instance. This method must be called before any other + * instance methods of {@code EPDSystem}. If this method is called multiple + * times, it has no effect after the first call. + */ + void loadLibrary() { + NativeLibLoader.loadLibrary("glass_monocle_epd"); + } + + /** + * Calls the {@code ioctl} system function, passing a write integer + * parameter. This method is more convenient than passing the pointer to an + * {@code IntStructure} with {@link LinuxSystem#ioctl} and can be used when + * the request code is created by {@link LinuxSystem#IOW} for setting an + * integer value. + * + * @param fd an open file descriptor + * @param request a device-dependent request code + * @param value the integer value + * @return 0 if successful; otherwise -1 with {@code errno} set + * appropriately + */ + native int ioctl(long fd, int request, int value); + + /** + * A structure for passing the pointer to an integer in an IOCTL call. + */ + static class IntStructure extends C.Structure { + + private static final int VALUE = 0; + + private static final int NUM_INTS = 1; + private static final int BYTES = NUM_INTS * Integer.BYTES; + + private final IntBuffer data; + + IntStructure() { + b.order(ByteOrder.nativeOrder()); + data = b.asIntBuffer(); + } + + @Override + int sizeof() { + return BYTES; + } + + int get(long p) { + return data.get(VALUE); + } + + void set(long p, int value) { + data.put(VALUE, value); + } + } + + /** + * Wraps the C structure {@code mxcfb_waveform_modes}, defined in + * mxcfb.h. + */ + static class MxcfbWaveformModes extends C.Structure { + + private static final int MODE_INIT = 0; + private static final int MODE_DU = 1; + private static final int MODE_GC4 = 2; + private static final int MODE_GC8 = 3; + private static final int MODE_GC16 = 4; + private static final int MODE_GC32 = 5; + + private static final int NUM_INTS = 6; + private static final int BYTES = NUM_INTS * Integer.BYTES; + + private final IntBuffer data; + + MxcfbWaveformModes() { + b.order(ByteOrder.nativeOrder()); + data = b.asIntBuffer(); + } + + @Override + int sizeof() { + return BYTES; + } + + int getModeInit(long p) { + return data.get(MODE_INIT); + } + + int getModeDu(long p) { + return data.get(MODE_DU); + } + + int getModeGc4(long p) { + return data.get(MODE_GC4); + } + + int getModeGc8(long p) { + return data.get(MODE_GC8); + } + + int getModeGc16(long p) { + return data.get(MODE_GC16); + } + + int getModeGc32(long p) { + return data.get(MODE_GC32); + } + + void setModes(long p, int init, int du, int gc4, int gc8, int gc16, int gc32) { + data.put(MODE_INIT, init); + data.put(MODE_DU, du); + data.put(MODE_GC4, gc4); + data.put(MODE_GC8, gc8); + data.put(MODE_GC16, gc16); + data.put(MODE_GC32, gc32); + } + + @Override + public String toString() { + return MessageFormat.format( + "{0}[mode_init={1} mode_du={2} mode_gc4={3} mode_gc8={4} mode_gc16={5} mode_gc32={6}]", + getClass().getName(), getModeInit(p), getModeDu(p), getModeGc4(p), + getModeGc8(p), getModeGc16(p), getModeGc32(p)); + } + } + + /** + * Wraps the C structure {@code mxcfb_update_data}, defined in + * mxcfb.h. + */ + static class MxcfbUpdateData extends C.Structure { + + private static final int UPDATE_REGION_TOP = 0; + private static final int UPDATE_REGION_LEFT = 1; + private static final int UPDATE_REGION_WIDTH = 2; + private static final int UPDATE_REGION_HEIGHT = 3; + + private static final int WAVEFORM_MODE = 4; + private static final int UPDATE_MODE = 5; + private static final int UPDATE_MARKER = 6; + private static final int TEMP = 7; + private static final int FLAGS = 8; + + private static final int ALT_BUFFER_DATA_VIRT_ADDR = 9; + private static final int ALT_BUFFER_DATA_PHYS_ADDR = 10; + private static final int ALT_BUFFER_DATA_WIDTH = 11; + private static final int ALT_BUFFER_DATA_HEIGHT = 12; + + private static final int ALT_BUFFER_DATA_ALT_UPDATE_REGION_TOP = 13; + private static final int ALT_BUFFER_DATA_ALT_UPDATE_REGION_LEFT = 14; + private static final int ALT_BUFFER_DATA_ALT_UPDATE_REGION_WIDTH = 15; + private static final int ALT_BUFFER_DATA_ALT_UPDATE_REGION_HEIGHT = 16; + + private static final int NUM_INTS = 17; + private static final int BYTES = NUM_INTS * Integer.BYTES; + + private final IntBuffer data; + + MxcfbUpdateData() { + b.order(ByteOrder.nativeOrder()); + data = b.asIntBuffer(); + } + + @Override + int sizeof() { + return BYTES; + } + + int getUpdateRegionTop(long p) { + return data.get(UPDATE_REGION_TOP); + } + + int getUpdateRegionLeft(long p) { + return data.get(UPDATE_REGION_LEFT); + } + + int getUpdateRegionWidth(long p) { + return data.get(UPDATE_REGION_WIDTH); + } + + int getUpdateRegionHeight(long p) { + return data.get(UPDATE_REGION_HEIGHT); + } + + int getWaveformMode(long p) { + return data.get(WAVEFORM_MODE); + } + + int getUpdateMode(long p) { + return data.get(UPDATE_MODE); + } + + int getUpdateMarker(long p) { + return data.get(UPDATE_MARKER); + } + + int getTemp(long p) { + return data.get(TEMP); + } + + int getFlags(long p) { + return data.get(FLAGS); + } + + long getAltBufferDataVirtAddr(long p) { + return data.get(ALT_BUFFER_DATA_VIRT_ADDR); + } + + long getAltBufferDataPhysAddr(long p) { + return data.get(ALT_BUFFER_DATA_PHYS_ADDR); + } + + int getAltBufferDataWidth(long p) { + return data.get(ALT_BUFFER_DATA_WIDTH); + } + + int getAltBufferDataHeight(long p) { + return data.get(ALT_BUFFER_DATA_HEIGHT); + } + + int getAltBufferDataAltUpdateRegionTop(long p) { + return data.get(ALT_BUFFER_DATA_ALT_UPDATE_REGION_TOP); + } + + int getAltBufferDataAltUpdateRegionLeft(long p) { + return data.get(ALT_BUFFER_DATA_ALT_UPDATE_REGION_LEFT); + } + + int getAltBufferDataAltUpdateRegionWidth(long p) { + return data.get(ALT_BUFFER_DATA_ALT_UPDATE_REGION_WIDTH); + } + + int getAltBufferDataAltUpdateRegionHeight(long p) { + return data.get(ALT_BUFFER_DATA_ALT_UPDATE_REGION_HEIGHT); + } + + void setUpdateRegion(long p, int top, int left, int width, int height) { + data.put(UPDATE_REGION_TOP, top); + data.put(UPDATE_REGION_LEFT, left); + data.put(UPDATE_REGION_WIDTH, width); + data.put(UPDATE_REGION_HEIGHT, height); + } + + void setWaveformMode(long p, int mode) { + data.put(WAVEFORM_MODE, mode); + } + + void setUpdateMode(long p, int mode) { + data.put(UPDATE_MODE, mode); + } + + void setUpdateMarker(long p, int marker) { + data.put(UPDATE_MARKER, marker); + } + + void setTemp(long p, int temp) { + data.put(TEMP, temp); + } + + void setFlags(long p, int flags) { + data.put(FLAGS, flags); + } + + void setAltBufferData(long p, long virtAddr, long physAddr, int width, int height, + int altUpdateRegionTop, int altUpdateRegionLeft, int altUpdateRegionWidth, int altUpdateRegionHeight) { + data.put(ALT_BUFFER_DATA_VIRT_ADDR, (int) virtAddr); + data.put(ALT_BUFFER_DATA_PHYS_ADDR, (int) physAddr); + data.put(ALT_BUFFER_DATA_WIDTH, width); + data.put(ALT_BUFFER_DATA_HEIGHT, height); + data.put(ALT_BUFFER_DATA_ALT_UPDATE_REGION_TOP, altUpdateRegionTop); + data.put(ALT_BUFFER_DATA_ALT_UPDATE_REGION_LEFT, altUpdateRegionLeft); + data.put(ALT_BUFFER_DATA_ALT_UPDATE_REGION_WIDTH, altUpdateRegionWidth); + data.put(ALT_BUFFER_DATA_ALT_UPDATE_REGION_HEIGHT, altUpdateRegionHeight); + } + + @Override + public String toString() { + return MessageFormat.format( + "{0}[update_region.top={1} update_region.left={2} update_region.width={3} update_region.height={4}" + + " waveform_mode={5} update_mode={6} update_marker={7} temp={8} flags=0x{9}" + + " alt_buffer_data.virt_addr=0x{10} alt_buffer_data.phys_addr=0x{11}" + + " alt_buffer_data.width={12} alt_buffer_data.height={13}" + + " alt_buffer_data.alt_update_region.top={14} alt_buffer_data.alt_update_region.left={15}" + + " alt_buffer_data.alt_update_region.width={16} alt_buffer_data.alt_update_region.height={17}]", + getClass().getName(), + Integer.toUnsignedLong(getUpdateRegionTop(p)), + Integer.toUnsignedLong(getUpdateRegionLeft(p)), + Integer.toUnsignedLong(getUpdateRegionWidth(p)), + Integer.toUnsignedLong(getUpdateRegionHeight(p)), + Integer.toUnsignedLong(getWaveformMode(p)), + Integer.toUnsignedLong(getUpdateMode(p)), + Integer.toUnsignedLong(getUpdateMarker(p)), + getTemp(p), + Integer.toHexString(getFlags(p)), + Long.toHexString(getAltBufferDataVirtAddr(p)), + Long.toHexString(getAltBufferDataPhysAddr(p)), + Integer.toUnsignedLong(getAltBufferDataWidth(p)), + Integer.toUnsignedLong(getAltBufferDataHeight(p)), + Integer.toUnsignedLong(getAltBufferDataAltUpdateRegionTop(p)), + Integer.toUnsignedLong(getAltBufferDataAltUpdateRegionLeft(p)), + Integer.toUnsignedLong(getAltBufferDataAltUpdateRegionWidth(p)), + Integer.toUnsignedLong(getAltBufferDataAltUpdateRegionHeight(p))); + } + } + + /** + * Wraps the entire C structure {@code fb_var_screeninfo}, defined in + * linux/fb.h. + */ + static class FbVarScreenInfo extends LinuxSystem.FbVarScreenInfo { + + native int getGrayscale(long p); + + native int getRedOffset(long p); + + native int getRedLength(long p); + + native int getRedMsbRight(long p); + + native int getGreenOffset(long p); + + native int getGreenLength(long p); + + native int getGreenMsbRight(long p); + + native int getBlueOffset(long p); + + native int getBlueLength(long p); + + native int getBlueMsbRight(long p); + + native int getTranspOffset(long p); + + native int getTranspLength(long p); + + native int getTranspMsbRight(long p); + + native int getNonstd(long p); + + native int getActivate(long p); + + native int getHeight(long p); + + native int getWidth(long p); + + native int getAccelFlags(long p); + + native int getPixclock(long p); + + native int getLeftMargin(long p); + + native int getRightMargin(long p); + + native int getUpperMargin(long p); + + native int getLowerMargin(long p); + + native int getHsyncLen(long p); + + native int getVsyncLen(long p); + + native int getSync(long p); + + native int getVmode(long p); + + native int getRotate(long p); + + native void setGrayscale(long p, int grayscale); + + native void setNonstd(long p, int nonstd); + + native void setHeight(long p, int height); + + native void setWidth(long p, int width); + + native void setAccelFlags(long p, int accelFlags); + + native void setPixclock(long p, int pixclock); + + native void setLeftMargin(long p, int leftMargin); + + native void setRightMargin(long p, int rightMargin); + + native void setUpperMargin(long p, int upperMargin); + + native void setLowerMargin(long p, int lowerMargin); + + native void setHsyncLen(long p, int hsyncLen); + + native void setVsyncLen(long p, int vsyncLen); + + native void setSync(long p, int sync); + + native void setVmode(long p, int vmode); + + native void setRotate(long p, int rotate); + } + + @Override + public String toString() { + return MessageFormat.format("{0}[MXCFB_SET_WAVEFORM_MODES=0x{1} MXCFB_SET_TEMPERATURE=0x{2} " + + "MXCFB_SET_AUTO_UPDATE_MODE=0x{3} MXCFB_SEND_UPDATE=0x{4} MXCFB_WAIT_FOR_UPDATE_COMPLETE=0x{5} " + + "MXCFB_SET_PWRDOWN_DELAY=0x{6} MXCFB_GET_PWRDOWN_DELAY=0x{7} MXCFB_SET_UPDATE_SCHEME=0x{8}]", + getClass().getName(), + Integer.toHexString(MXCFB_SET_WAVEFORM_MODES), + Integer.toHexString(MXCFB_SET_TEMPERATURE), + Integer.toHexString(MXCFB_SET_AUTO_UPDATE_MODE), + Integer.toHexString(MXCFB_SEND_UPDATE), + Integer.toHexString(MXCFB_WAIT_FOR_UPDATE_COMPLETE), + Integer.toHexString(MXCFB_SET_PWRDOWN_DELAY), + Integer.toHexString(MXCFB_GET_PWRDOWN_DELAY), + Integer.toHexString(MXCFB_SET_UPDATE_SCHEME) + ); + } +} diff --git a/src/main/java/com/sun/glass/ui/monocle/FBDevScreen.java b/src/main/java/com/sun/glass/ui/monocle/FBDevScreen.java index 36a8162..d4951dd 100644 --- a/src/main/java/com/sun/glass/ui/monocle/FBDevScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/FBDevScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,9 +55,11 @@ class FBDevScreen implements NativeScreen { private final String fbDevPath; FBDevScreen() { - fbDevPath = AccessController.doPrivileged( + @SuppressWarnings("removal") + String tmp = AccessController.doPrivileged( (PrivilegedAction) () -> System.getProperty("monocle.screen.fb", "/dev/fb0")); + fbDevPath = tmp; try { linuxFB = new LinuxFrameBuffer(fbDevPath); nativeHandle = 1l; diff --git a/src/main/java/com/sun/glass/ui/monocle/FramebufferY8.java b/src/main/java/com/sun/glass/ui/monocle/FramebufferY8.java new file mode 100644 index 0000000..ef7b4dc --- /dev/null +++ b/src/main/java/com/sun/glass/ui/monocle/FramebufferY8.java @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.glass.ui.monocle; + +import com.sun.javafx.logging.PlatformLogger; +import com.sun.javafx.util.Logging; +import java.io.IOException; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.nio.channels.WritableByteChannel; +import java.text.MessageFormat; + +/** + * Provides a buffer for composing JavaFX scenes. This class is given a 32-bit + * composition buffer that is either the Linux frame buffer itself or an + * off-screen byte buffer. It can write the contents of this buffer to a target + * channel, or copy them to a buffer, in one of three pixel formats: 32-bit + * ARGB32 color, 16-bit RGB565 color, or 8-bit Y8 grayscale. + */ +class FramebufferY8 extends Framebuffer { + + /** + * The arithmetic right shift value to convert a bit depth to a byte depth. + */ + private static final int BITS_TO_BYTES = 3; + + private final PlatformLogger logger = Logging.getJavaFXLogger(); + private final ByteBuffer bb; + private final int width; + private final int height; + private final int bitDepth; + private final int byteDepth; + + private ByteBuffer lineByteBuffer; + private Buffer linePixelBuffer; + + /** + * Creates a new {@code FramebufferY8} with the given 32-bit composition + * buffer and target color depth. + * + * @param bb the 32-bit composition buffer + * @param width the width of the composition buffer in pixels + * @param height the height of the composition buffer in pixels + * @param depth the color depth of the target channel or buffer in bits per + * pixel + * @param clear {@code true} to clear the composition buffer on the first + * upload of each frame unless that upload already overwrites the entire + * buffer; otherwise {@code false} + */ + FramebufferY8(ByteBuffer bb, int width, int height, int depth, boolean clear) { + super(bb, width, height, depth, clear); + this.bb = bb; + this.width = width; + this.height = height; + this.bitDepth = depth; + this.byteDepth = depth >>> BITS_TO_BYTES; + if (byteDepth != Integer.BYTES && byteDepth != Short.BYTES && byteDepth != Byte.BYTES) { + String msg = MessageFormat.format("Unsupported color depth: {0} bpp", bitDepth); + logger.severe(msg); + throw new IllegalArgumentException(msg); + } + } + + /** + * Copies the next 32-bit ARGB32 pixel to a byte buffer with 8-bit Y8 + * pixels. Luma Y' can be calculated from gamma-corrected R'G'B' using the + * following coefficients. This method uses the coefficients from Rec. 709, + * which defines the same primaries and white point as the sRGB color space. + *
{@code
+     * Simple average:  Y' = (R' + G' + B') / 3
+     * Rec. 601 (SDTV): Y' = 0.299  * R' + 0.587  * G' + 0.114  * B'
+     * Rec. 709 (HDTV): Y' = 0.2126 * R' + 0.7152 * G' + 0.0722 * B'
+     * Rec. 2100 (HDR): Y' = 0.2627 * R' + 0.6780 * G' + 0.0593 * B'
+     * }
+ * + * @implNote Java rounds toward zero when converting a {@code float} to an + * {@code int}. The calculation of luma could be rounded to the nearest + * integer by adding 0.5 before the type conversion, but the extra operation + * seems unnecessary for a display with only 16 levels of gray. + * + * @param source the source integer buffer in ARGB32 format + * @param target the target byte buffer in Y8 format + */ + private void copyNextPixel(IntBuffer source, ByteBuffer target) { + int pixel32 = source.get(); + int r = (pixel32 >> 16) & 0xFF; + int g = (pixel32 >> 8) & 0xFF; + int b = pixel32 & 0xFF; + int y = (int) (0.2126f * r + 0.7152f * g + 0.0722f * b); + target.put((byte) y); + } + + /** + * Copies the next 32-bit ARGB32 pixel to a short buffer with 16-bit RGB565 + * pixels. This method truncates the low-order bits of each color component. + * + * @param source the source integer buffer in ARGB32 format + * @param target the target short buffer in RGB565 format + */ + private void copyNextPixel(IntBuffer source, ShortBuffer target) { + int pixel32 = source.get(); + int r = (pixel32 >> 8) & 0xF800; + int g = (pixel32 >> 5) & 0x07E0; + int b = (pixel32 >> 3) & 0x001F; + int pixel16 = r | g | b; + target.put((short) pixel16); + } + + /** + * Writes the contents of the composition buffer to the output channel, + * converting the pixel format as necessary. + * + * @param out the output channel + * @throws IOException if an error occurs writing to the channel + * @throws IllegalArgumentException if the channel has an unsupported color + * depth + */ + @Override + void write(WritableByteChannel out) throws IOException { + bb.clear(); + switch (byteDepth) { + case Byte.BYTES: { + if (lineByteBuffer == null) { + lineByteBuffer = ByteBuffer.allocate(width * Byte.BYTES); + lineByteBuffer.order(ByteOrder.nativeOrder()); + linePixelBuffer = lineByteBuffer.duplicate(); + } + IntBuffer srcPixels = bb.asIntBuffer(); + ByteBuffer byteBuffer = (ByteBuffer) linePixelBuffer; + for (int y = 0; y < height; y++) { + byteBuffer.clear(); + for (int x = 0; x < width; x++) { + copyNextPixel(srcPixels, byteBuffer); + } + lineByteBuffer.clear(); + out.write(lineByteBuffer); + } + break; + } + case Short.BYTES: { + if (lineByteBuffer == null) { + lineByteBuffer = ByteBuffer.allocate(width * Short.BYTES); + lineByteBuffer.order(ByteOrder.nativeOrder()); + linePixelBuffer = lineByteBuffer.asShortBuffer(); + } + IntBuffer srcPixels = bb.asIntBuffer(); + ShortBuffer shortBuffer = (ShortBuffer) linePixelBuffer; + for (int y = 0; y < height; y++) { + shortBuffer.clear(); + for (int x = 0; x < width; x++) { + copyNextPixel(srcPixels, shortBuffer); + } + lineByteBuffer.clear(); + out.write(lineByteBuffer); + } + break; + } + case Integer.BYTES: { + out.write(bb); + break; + } + default: + String msg = MessageFormat.format("byteDepth={0}", byteDepth); + logger.severe(msg); + throw new IllegalStateException(msg); + } + } + + /** + * Copies the contents of the composition buffer to the output buffer, + * converting the pixel format as necessary. + * + * @param out the output buffer + * @throws IllegalArgumentException if the buffer has an unsupported color + * depth + */ + @Override + void copyToBuffer(ByteBuffer out) { + bb.clear(); + switch (byteDepth) { + case Byte.BYTES: { + if (lineByteBuffer == null) { + lineByteBuffer = ByteBuffer.allocate(width * Byte.BYTES); + lineByteBuffer.order(ByteOrder.nativeOrder()); + linePixelBuffer = lineByteBuffer.duplicate(); + } + IntBuffer srcPixels = bb.asIntBuffer(); + ByteBuffer byteBuffer = (ByteBuffer) linePixelBuffer; + for (int y = 0; y < height; y++) { + byteBuffer.clear(); + for (int x = 0; x < width; x++) { + copyNextPixel(srcPixels, byteBuffer); + } + lineByteBuffer.clear(); + out.put(lineByteBuffer); + } + break; + } + case Short.BYTES: { + if (lineByteBuffer == null) { + lineByteBuffer = ByteBuffer.allocate(width * Short.BYTES); + lineByteBuffer.order(ByteOrder.nativeOrder()); + linePixelBuffer = lineByteBuffer.asShortBuffer(); + } + IntBuffer srcPixels = bb.asIntBuffer(); + ShortBuffer shortBuffer = (ShortBuffer) linePixelBuffer; + for (int y = 0; y < height; y++) { + shortBuffer.clear(); + for (int x = 0; x < width; x++) { + copyNextPixel(srcPixels, shortBuffer); + } + lineByteBuffer.clear(); + out.put(lineByteBuffer); + } + break; + } + case Integer.BYTES: { + out.put(bb); + break; + } + default: + String msg = MessageFormat.format("byteDepth={0}", byteDepth); + logger.severe(msg); + throw new IllegalStateException(msg); + } + } + + @Override + public String toString() { + return MessageFormat.format("{0}[width={1} height={2} depth={3} bb={4}]", + getClass().getName(), width, height, bitDepth, bb); + } +} diff --git a/src/main/java/com/sun/glass/ui/monocle/HeadlessPlatform.java b/src/main/java/com/sun/glass/ui/monocle/HeadlessPlatform.java index 0ff77b9..d1ff87f 100644 --- a/src/main/java/com/sun/glass/ui/monocle/HeadlessPlatform.java +++ b/src/main/java/com/sun/glass/ui/monocle/HeadlessPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ protected InputDeviceRegistry createInputDeviceRegistry() { @Override protected NativeCursor createCursor() { - return new NullCursor(); + return logSelectedCursor(new NullCursor()); } @Override diff --git a/src/main/java/com/sun/glass/ui/monocle/HeadlessScreen.java b/src/main/java/com/sun/glass/ui/monocle/HeadlessScreen.java index d055bc9..a4d4d74 100644 --- a/src/main/java/com/sun/glass/ui/monocle/HeadlessScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/HeadlessScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,7 @@ protected HeadlessScreen(int defaultWidth, this.width = defaultWidth; this.height = defaultHeight; this.depth = defaultDepth; + @SuppressWarnings("removal") String geometry = AccessController.doPrivileged((PrivilegedAction) () -> System.getProperty("headless.geometry")); if (geometry != null && geometry.indexOf('x') > 0) { try { diff --git a/src/main/java/com/sun/glass/ui/monocle/KeyInput.java b/src/main/java/com/sun/glass/ui/monocle/KeyInput.java index e66422b..3742ef9 100644 --- a/src/main/java/com/sun/glass/ui/monocle/KeyInput.java +++ b/src/main/java/com/sun/glass/ui/monocle/KeyInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,7 +85,8 @@ void setState(KeyState newState) { } else if (key == KeyEvent.VK_NUM_LOCK) { numLock = !numLock; } else if (key == KeyEvent.VK_C && newState.isControlPressed()) { - AccessController.doPrivileged((PrivilegedAction) () -> { + @SuppressWarnings("removal") + var dummy = AccessController.doPrivileged((PrivilegedAction) () -> { if ("1".equals(System.getenv("JAVAFX_DEBUG"))) { System.exit(0); } diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxArch.java b/src/main/java/com/sun/glass/ui/monocle/LinuxArch.java index 13c70d1..b4b6514 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxArch.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxArch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,14 +30,11 @@ public class LinuxArch { - private static final int bits; - - static { - bits = AccessController.doPrivileged((PrivilegedAction) () -> { - LinuxSystem system = LinuxSystem.getLinuxSystem(); - return (int) system.sysconf(LinuxSystem._SC_LONG_BIT); - }); - } + @SuppressWarnings("removal") + private static final int bits = AccessController.doPrivileged((PrivilegedAction) () -> { + LinuxSystem system = LinuxSystem.getLinuxSystem(); + return (int) system.sysconf(LinuxSystem._SC_LONG_BIT); + });; static boolean is64Bit() { return bits == 64; diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxEventBuffer.java b/src/main/java/com/sun/glass/ui/monocle/LinuxEventBuffer.java index 6a2471a..6502bd6 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxEventBuffer.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxEventBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,7 +90,7 @@ int getEventSize() { */ synchronized boolean put(ByteBuffer event) throws InterruptedException { - boolean isSync = event.getInt(eventStruct.getTypeIndex()) == 0 + boolean isSync = event.getShort(eventStruct.getTypeIndex()) == 0 && event.getInt(eventStruct.getValueIndex()) == 0; while (bb.limit() - bb.position() < event.limit()) { // Block if bb is full. This should be the diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxInputDevice.java b/src/main/java/com/sun/glass/ui/monocle/LinuxInputDevice.java index ce89628..ac2b7e2 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxInputDevice.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxInputDevice.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,12 +83,12 @@ class LinuxInputDevice implements Runnable, InputDevice { this.sysPath = sysPath; this.udevManifest = udevManifest; this.capabilities = SysFS.readCapabilities(sysPath); - this.absCaps = LinuxAbsoluteInputCapabilities.getCapabilities( - devNode, capabilities.get("abs")); fd = system.open(devNode.getPath(), LinuxSystem.O_RDONLY); if (fd == -1) { throw new IOException(system.getErrorMessage() + " on " + devNode); } + this.absCaps = LinuxAbsoluteInputCapabilities.getCapabilities( + devNode, capabilities.get("abs")); // attempt to grab the device. If the grab fails, keep going. int EVIOCGRAB = system.IOW('E', 0x90, 4); system.ioctl(fd, EVIOCGRAB, 1); diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxInputDeviceRegistry.java b/src/main/java/com/sun/glass/ui/monocle/LinuxInputDeviceRegistry.java index 7810e02..bad3ec3 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxInputDeviceRegistry.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxInputDeviceRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,6 +84,7 @@ private LinuxInputDevice createDevice(File devNode, } LinuxInputDevice addDevice(LinuxInputDevice device, String name) { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(new AllPermission()); @@ -107,6 +108,7 @@ private LinuxInputDevice addDeviceInternal(LinuxInputDevice device, String name) } void removeDevice(LinuxInputDevice device) { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(new AllPermission()); diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxMouseProcessor.java b/src/main/java/com/sun/glass/ui/monocle/LinuxMouseProcessor.java index b88dc7a..071457a 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxMouseProcessor.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxMouseProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,6 +127,10 @@ private static int mouseButtonForKeyCode(int keyCode) { return MouseEvent.BUTTON_OTHER; case LinuxInput.BTN_RIGHT: return MouseEvent.BUTTON_RIGHT; + case LinuxInput.BTN_BACK: + return MouseEvent.BUTTON_BACK; + case LinuxInput.BTN_FORWARD: + return MouseEvent.BUTTON_FORWARD; default: return -1; } diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxPlatform.java b/src/main/java/com/sun/glass/ui/monocle/LinuxPlatform.java index cc3e065..0c5ad17 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxPlatform.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,8 @@ protected InputDeviceRegistry createInputDeviceRegistry() { @Override protected NativeCursor createCursor() { - return new SoftwareCursor(); + final NativeCursor c = useCursor ? new SoftwareCursor() : new NullCursor(); + return logSelectedCursor(c); } @Override diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxPlatformFactory.java b/src/main/java/com/sun/glass/ui/monocle/LinuxPlatformFactory.java index 54456fa..040dae5 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxPlatformFactory.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxPlatformFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ class LinuxPlatformFactory extends NativePlatformFactory { @Override protected boolean matches() { + @SuppressWarnings("removal") String os = AccessController.doPrivileged( (PrivilegedAction) () -> System.getProperty("os.name")); return os != null && os.equals("Linux"); diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxSystem.java b/src/main/java/com/sun/glass/ui/monocle/LinuxSystem.java index fc72b51..b28805c 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxSystem.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,6 +57,7 @@ static LinuxSystem getLinuxSystem() { } private static void checkPermissions() { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(permission); diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxTouchProcessor.java b/src/main/java/com/sun/glass/ui/monocle/LinuxTouchProcessor.java index 06531ab..eb6f021 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxTouchProcessor.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxTouchProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ abstract class LinuxTouchProcessor implements LinuxInputProcessor { final TouchPipeline pipeline; final LinuxTouchTransform transform; + @SuppressWarnings("removal") LinuxTouchProcessor(LinuxInputDevice device) { transform = new LinuxTouchTransform(device); PrivilegedAction getFilterProperty = diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxTouchTransform.java b/src/main/java/com/sun/glass/ui/monocle/LinuxTouchTransform.java index 1a2633d..d9e6c98 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxTouchTransform.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxTouchTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ class LinuxTouchTransform { private int[] mins = new int[2]; private int[] maxs = new int[2]; + @SuppressWarnings("removal") LinuxTouchTransform(LinuxInputDevice device) { this.device = device; Arrays.fill(axes, -1); @@ -138,7 +139,8 @@ private void initTransform(int axis, int index) { } LinuxAbsoluteInputCapabilities caps = device.getAbsoluteInputCapabilities(axis); String product = device.getProduct(); - AccessController.doPrivileged((PrivilegedAction) () -> { + @SuppressWarnings("removal") + var dummy = AccessController.doPrivileged((PrivilegedAction) () -> { int minimum = Integer.getInteger( "monocle.input." + product + ".min" + axisName, caps.getMinimum()); diff --git a/src/main/java/com/sun/glass/ui/monocle/MX6Platform.java b/src/main/java/com/sun/glass/ui/monocle/MX6Platform.java index 82ea536..1d6da9f 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MX6Platform.java +++ b/src/main/java/com/sun/glass/ui/monocle/MX6Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,8 @@ class MX6Platform extends LinuxPlatform { @Override protected NativeCursor createCursor() { - return new MX6Cursor(); + final NativeCursor c = useCursor ? new MX6Cursor() : new NullCursor(); + return logSelectedCursor(c); } @Override diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java b/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java index b45422f..3dff9b0 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ import java.nio.IntBuffer; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.List; public final class MonocleApplication extends Application { @@ -110,6 +111,7 @@ private void updateDeviceFlags(InputDevice device, boolean added) { @Override protected void runLoop(Runnable launchable) { runnableProcessor.invokeLater(launchable); + @SuppressWarnings("removal") long stackSize = AccessController.doPrivileged( (PrivilegedAction) () -> Long.getLong("monocle.stackSize", 0)); @@ -153,11 +155,6 @@ public Window createWindow(Window owner, Screen screen, int styleMask) { return new MonocleWindow(owner, screen, styleMask); } - @Override - public Window createWindow(long parent) { - return new MonocleWindow(parent); - } - @Override public View createView() { return new MonocleView(); @@ -190,15 +187,18 @@ public Pixels createPixels(int width, int height, ByteBuffer data) { return new MonoclePixels(width, height, data); } + @Override + public Pixels createPixels(int width, int height, ByteBuffer data, float scalex, float scaley) { + return new MonoclePixels(width, height, data, scalex, scaley); + } + @Override public Pixels createPixels(int width, int height, IntBuffer data) { return new MonoclePixels(width, height, data); } @Override - public Pixels createPixels(int width, int height, IntBuffer data, - float scalex, float scaley) - { + public Pixels createPixels(int width, int height, IntBuffer data, float scalex, float scaley) { return new MonoclePixels(width, height, data, scalex, scaley); } @@ -219,21 +219,29 @@ protected double staticScreen_getVideoRefreshPeriod() { @Override protected Screen[] staticScreen_getScreens() { - NativeScreen ns = platform.getScreen(); - Screen screen = new Screen(1l, // dummy native pointer; - ns.getDepth(), - 0, 0, ns.getWidth(), ns.getHeight(), - 0, 0, ns.getWidth(), ns.getHeight(), - 0, 0, ns.getWidth(), ns.getHeight(), - ns.getDPI(), ns.getDPI(), - ns.getScale(), ns.getScale(), - ns.getScale(), ns.getScale()); - // Move the cursor to the middle of the screen - MouseState mouseState = new MouseState(); - mouseState.setX(ns.getWidth() / 2); - mouseState.setY(ns.getHeight() / 2); - MouseInput.getInstance().setState(mouseState, false); - return new Screen[] { screen }; + List screens = platform.getScreens(); + Screen[] answer = new Screen[screens.size()]; + int cnt = 0; + for (NativeScreen ns: screens) { + Screen screen = new Screen(ns.getNativeHandle(), + ns.getDepth(), + ns.getOffsetX(), ns.getOffsetY(), ns.getWidth(), ns.getHeight(), + ns.getOffsetX(), ns.getOffsetY(), ns.getWidth(), ns.getHeight(), + ns.getOffsetX(), ns.getOffsetY(), ns.getWidth(), ns.getHeight(), + ns.getDPI(), ns.getDPI(), + 1.f, 1.f, ns.getScale(), ns.getScale()); + answer[cnt] = screen; + // The first screen is the primaryscreen, we set the cursor to that one. + if (cnt == 0) { + // Move the cursor to the middle of the screen + MouseState mouseState = new MouseState(); + mouseState.setX(ns.getWidth() / 2); + mouseState.setY(ns.getHeight() / 2); + MouseInput.getInstance().setState(mouseState, false); + } + cnt++; + } + return answer; } @Override diff --git a/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java b/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java index bbb17ce..5c4fee0 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java @@ -37,6 +37,10 @@ final class MonoclePixels extends Pixels { super(width, height, data); } + MonoclePixels(int width, int height, ByteBuffer data, float scalex, float scaley) { + super(width, height, data, scalex, scaley); + } + MonoclePixels(int width, int height, IntBuffer data) { super(width, height, data); } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java b/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java index 6d3451f..b055e4c 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleRobot.java @@ -100,6 +100,20 @@ private static MouseState convertToMouseState(boolean press, MouseState state, M state.releaseButton(MouseEvent.BUTTON_OTHER); } break; + case BACK: + if (press) { + state.pressButton(MouseEvent.BUTTON_BACK); + } else { + state.releaseButton(MouseEvent.BUTTON_BACK); + } + break; + case FORWARD: + if (press) { + state.pressButton(MouseEvent.BUTTON_FORWARD); + } else { + state.releaseButton(MouseEvent.BUTTON_FORWARD); + } + break; default: throw new IllegalArgumentException("MouseButton: " + button + " not supported by Monocle Robot"); } @@ -214,7 +228,7 @@ public void getScreenCapture(int x, int y, int width, int height, int[] data, bo int colStop = Math.min(x + width, scrWidth); for (int row = y; row < rowStop; row++) { for (int col = x; col < colStop; col++) { - data[row * scrWidth + col] = buffer.get(row * scrWidth + col); + data[(row - y) * (colStop - x) + (col - x)] = buffer.get(row * scrWidth + col); } } } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleSettings.java b/src/main/java/com/sun/glass/ui/monocle/MonocleSettings.java index bced18f..6567638 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleSettings.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleSettings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ class MonocleSettings { + @SuppressWarnings("removal") static final MonocleSettings settings = AccessController.doPrivileged( (PrivilegedAction) () -> new MonocleSettings()); diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleTimer.java b/src/main/java/com/sun/glass/ui/monocle/MonocleTimer.java index 60ea0f0..f55cc41 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleTimer.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleTimer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,13 +26,18 @@ package com.sun.glass.ui.monocle; import com.sun.glass.ui.Timer; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; /** * Monocle implementation class for Timer. */ final class MonocleTimer extends Timer { - private static java.util.Timer timer; - private java.util.TimerTask task; + private static final String THREAD_NAME = "Monocle Timer"; + + private static ScheduledThreadPoolExecutor scheduler; + private ScheduledFuture task; MonocleTimer(final Runnable runnable) { super(runnable); @@ -47,19 +52,15 @@ static int getMaxPeriod_impl() { } @Override protected long _start(final Runnable runnable, int period) { - if (timer == null) { - timer = new java.util.Timer(true); + if (scheduler == null) { + scheduler = new ScheduledThreadPoolExecutor(1, target -> { + Thread thread = new Thread(target, THREAD_NAME); + thread.setDaemon(true); + return thread; + }); } - task = new java.util.TimerTask() { - - @Override - public void run() { - runnable.run(); - } - }; - - timer.schedule(task, 0, (long)period); + task = scheduler.scheduleAtFixedRate(runnable, 0, period, TimeUnit.MILLISECONDS); return 1; // need something non-zero to denote success. } @@ -69,9 +70,12 @@ public void run() { @Override protected void _stop(long timer) { if (task != null) { - task.cancel(); + task.cancel(false); task = null; } } + + @Override protected void _pause(long timer) {} + @Override protected void _resume(long timer) {} } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java b/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java index 385db87..b04bc4e 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,10 +55,6 @@ final class MonocleWindow extends Window { super(owner, screen, styleMask); } - MonocleWindow(long parent) { - super(parent); - } - @Override protected void _toFront(long ptr) { MonocleWindowManager.getInstance().toFront(this); @@ -112,7 +108,7 @@ protected void _setBounds(long nativeWindowPointer, if (h > 0) { //window height surpass window content height(ch) height = h; - } else if (cw > 0) { + } else if (ch > 0) { //content height changed height = ch; } else { @@ -167,11 +163,6 @@ protected long _createWindow(long NativeWindow, long NativeScreen, return id; } - @Override - protected long _createChildWindow(long parent) { - throw new UnsupportedOperationException(); - } - @Override protected boolean _close(long nativeWindowPointer) { return MonocleWindowManager.getInstance().closeWindow(this); @@ -188,6 +179,10 @@ protected boolean _setView(long nativeWindowPointer, View view) { return result; } + // empty - not needed by this implementation + @Override + protected void _updateViewSize(long ptr) {} + /** * Returns the handle used to create a rendering context in Prism */ @@ -445,13 +440,6 @@ void _notifyFocusDisabled() { ((MonocleCursor) cursor).applyCursor(); } - @Override protected int _getEmbeddedX(long ptr) { - return 0; - } - @Override protected int _getEmbeddedY(long ptr) { - return 0; - } - @Override protected void _requestInput(long ptr, String text, int type, double width, double height, double Mxx, double Mxy, double Mxz, double Mxt, diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleWindowManager.java b/src/main/java/com/sun/glass/ui/monocle/MonocleWindowManager.java index 256c824..675d458 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleWindowManager.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleWindowManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/main/java/com/sun/glass/ui/monocle/MouseInput.java b/src/main/java/com/sun/glass/ui/monocle/MouseInput.java index 6a173e8..bd3e48b 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MouseInput.java +++ b/src/main/java/com/sun/glass/ui/monocle/MouseInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,9 +89,9 @@ void setState(MouseState newState, boolean synthesized) { newState.setY(y); // Get the cached window for the old state and compute the window for // the new state - MonocleWindow oldWindow = state.getWindow(false); + MonocleWindow oldWindow = state.getWindow(false, null); boolean recalculateWindow = state.getButtonsPressed().isEmpty(); - MonocleWindow window = newState.getWindow(recalculateWindow); + MonocleWindow window = newState.getWindow(recalculateWindow, null); MonocleView view = (window == null) ? null : (MonocleView) window.getView(); // send exit event if (oldWindow != window && oldWindow != null) { @@ -105,7 +105,9 @@ void setState(MouseState newState, boolean synthesized) { MonocleView oldView = (MonocleView) oldWindow.getView(); if (oldView != null) { // send exit event - int modifiers = state.getModifiers(); // TODO: include key modifiers + KeyState keyState = new KeyState(); + KeyInput.getInstance().getState(keyState); + int modifiers = state.getModifiers() | keyState.getModifiers(); int button = state.getButton(); boolean isPopupTrigger = false; // TODO int oldX = state.getX(); @@ -145,7 +147,9 @@ void setState(MouseState newState, boolean synthesized) { int relY = y - window.getY(); // send enter event if (oldWindow != window && view != null) { - int modifiers = state.getModifiers(); // TODO: include key modifiers + KeyState keyState = new KeyState(); + KeyInput.getInstance().getState(keyState); + int modifiers = state.getModifiers() | keyState.getModifiers(); int button = state.getButton(); boolean isPopupTrigger = false; // TODO postMouseEvent(view, MouseEvent.ENTER, button, @@ -156,7 +160,9 @@ void setState(MouseState newState, boolean synthesized) { if (oldWindow != window | newAbsoluteLocation) { boolean isDrag = !state.getButtonsPressed().isEmpty(); int eventType = isDrag ? MouseEvent.DRAG : MouseEvent.MOVE; - int modifiers = state.getModifiers(); // TODO: include key modifiers + KeyState keyState = new KeyState(); + KeyInput.getInstance().getState(keyState); + int modifiers = state.getModifiers() | keyState.getModifiers(); int button = state.getButton(); boolean isPopupTrigger = false; // TODO postMouseEvent(view, eventType, button, @@ -172,11 +178,14 @@ void setState(MouseState newState, boolean synthesized) { for (int i = 0; i < buttons.size(); i++) { int button = buttons.get(i); pressState.pressButton(button); + KeyState keyState = new KeyState(); + KeyInput.getInstance().getState(keyState); + int modifiers = pressState.getModifiers() | keyState.getModifiers(); // send press event boolean isPopupTrigger = false; // TODO postMouseEvent(view, MouseEvent.DOWN, button, relX, relY, x, y, - pressState.getModifiers(), isPopupTrigger, + modifiers, isPopupTrigger, synthesized); } } @@ -190,11 +199,14 @@ void setState(MouseState newState, boolean synthesized) { for (int i = 0; i < buttons.size(); i++) { int button = buttons.get(i); releaseState.releaseButton(button); + KeyState keyState = new KeyState(); + KeyInput.getInstance().getState(keyState); + int modifiers = releaseState.getModifiers() | keyState.getModifiers(); // send release event boolean isPopupTrigger = false; // TODO postMouseEvent(view, MouseEvent.UP, button, relX, relY, x, y, - releaseState.getModifiers(), isPopupTrigger, + modifiers, isPopupTrigger, synthesized); } } @@ -208,7 +220,9 @@ void setState(MouseState newState, boolean synthesized) { default: dY = 0.0; break; } if (dY != 0.0) { - int modifiers = newState.getModifiers(); + KeyState keyState = new KeyState(); + KeyInput.getInstance().getState(keyState); + int modifiers = newState.getModifiers() | keyState.getModifiers(); RunnableProcessor.runLater(() -> { view.notifyScroll(relX, relY, x, y, 0.0, dY, modifiers, 1, 0, 0, 0, 1.0, 1.0); @@ -321,4 +335,4 @@ void notifyDragStart() { dragInProgress = true; } -} \ No newline at end of file +} diff --git a/src/main/java/com/sun/glass/ui/monocle/MouseState.java b/src/main/java/com/sun/glass/ui/monocle/MouseState.java index 2358277..86e65cf 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MouseState.java +++ b/src/main/java/com/sun/glass/ui/monocle/MouseState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,19 +78,26 @@ void releaseButton(int button) { buttonsPressed.removeInt(button); } - /** Returns the Glass window on which the coordinates of this state are located. + /** + * Returns the Glass window on which the coordinates of this state are located. * @param recalculateCache true if the cached value for the target window * should be recalculated; false if the cached * value should be used to determine the result * of this method. + * @param fallback if the original window is null, or if no window can + * be found, return the fallback window * @return the MonocleWindow at the top of the stack at the coordinates - * described by this state object. + * described by this state object, or the fallback window in case the + * current window is null or no window can be found for the supplied coordinates. */ - MonocleWindow getWindow(boolean recalculateCache) { - if (window == null || recalculateCache) { + MonocleWindow getWindow(boolean recalculateCache, MonocleWindow fallback) { + if (recalculateCache) { window = (MonocleWindow) MonocleWindowManager.getInstance().getWindowForLocation(x, y); } + if (window == null) { + window = fallback; + } return window; } @@ -115,6 +122,12 @@ int getModifiers() { case MouseEvent.BUTTON_RIGHT: modifiers |= KeyEvent.MODIFIER_BUTTON_SECONDARY; break; + case MouseEvent.BUTTON_BACK: + modifiers |= KeyEvent.MODIFIER_BUTTON_BACK; + break; + case MouseEvent.BUTTON_FORWARD: + modifiers |= KeyEvent.MODIFIER_BUTTON_FORWARD; + break; } } return modifiers; diff --git a/src/main/java/com/sun/glass/ui/monocle/NativePlatform.java b/src/main/java/com/sun/glass/ui/monocle/NativePlatform.java index 16a7cc8..122bd21 100644 --- a/src/main/java/com/sun/glass/ui/monocle/NativePlatform.java +++ b/src/main/java/com/sun/glass/ui/monocle/NativePlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,15 +25,37 @@ package com.sun.glass.ui.monocle; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import java.util.ArrayList; +import java.util.List; +import com.sun.javafx.logging.PlatformLogger; +import com.sun.javafx.logging.PlatformLogger.Level; +import com.sun.javafx.util.Logging; + /** Abstract of a platform on which JavaFX can run. */ public abstract class NativePlatform { private static InputDeviceRegistry inputDeviceRegistry; private final RunnableProcessor runnableProcessor; + private final PlatformLogger logger = Logging.getJavaFXLogger(); + private NativeCursor cursor; - private NativeScreen screen; + protected List screens; protected AcceleratedScreen accScreen; + + @SuppressWarnings("removal") + protected static final boolean useCursor = + AccessController.doPrivileged((PrivilegedAction) () -> { + final String str = + System.getProperty("monocle.cursor.enabled", "true"); + return "true".equalsIgnoreCase(str); + }); + + + protected NativePlatform() { runnableProcessor = new RunnableProcessor(); } @@ -46,8 +68,10 @@ void shutdown() { if (cursor != null) { cursor.shutdown(); } - if (screen != null) { - screen.shutdown(); + if (screens != null) { + for (NativeScreen screen: screens) { + screen.shutdown(); + } } } @@ -102,15 +126,49 @@ synchronized NativeCursor getCursor() { protected abstract NativeScreen createScreen(); /** - * Obtains the singleton NativeScreen + * Create NativeScreen instances for all + * available native screens. The default implementation of + * this method will invoke the createScreen + * method and return a list with a single screen only. + * Subclasses can override this and return a list + * with all screens. The approach to get this list is + * specific to the subclass and can be done in Java or + * in native code.

+ * The first element in the returned list is considered + * to be the primary screen. + * + * @return a list with all native screens. This list is + * never null, but it can be empty. + */ + protected synchronized List createScreens() { + if (screens == null) { + screens = new ArrayList<>(1); + screens.add(createScreen()); + } + return screens; + } + + /** + * Obtains the NativeScreen instances. This method will + * create NativeScreen instances for all native screens, + * and stores them internally. The main screen (primaryscreen) + * is returned. * - * @return the NativeScreen + * @return the primaryscreen, or null if no + * screen is found. */ synchronized NativeScreen getScreen() { - if (screen == null) { - screen = createScreen(); + if (screens == null) { + screens = createScreens(); + } + return (screens.size() == 0 ? null : screens.get(0)); + } + + synchronized List getScreens() { + if (screens == null) { + screens = createScreens(); } - return screen; + return screens; } /** @@ -129,4 +187,19 @@ public synchronized AcceleratedScreen getAcceleratedScreen(int[] attributes) return accScreen; } + + /** + * Log the name of the supplied native cursor class if required. + * + * @param cursor the native cursor in use, null is permitted + * @return the passed in cursor + */ + protected NativeCursor logSelectedCursor(final NativeCursor cursor) { + if (logger.isLoggable(Level.FINE)) { + final String name = cursor == null ? null : cursor.getClass().getSimpleName(); + logger.fine("Using native cursor: {0}", name); + } + return cursor; + } + } diff --git a/src/main/java/com/sun/glass/ui/monocle/NativePlatformFactory.java b/src/main/java/com/sun/glass/ui/monocle/NativePlatformFactory.java index be4d905..a2ac6d8 100644 --- a/src/main/java/com/sun/glass/ui/monocle/NativePlatformFactory.java +++ b/src/main/java/com/sun/glass/ui/monocle/NativePlatformFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,7 @@ public abstract class NativePlatformFactory { */ public static synchronized NativePlatform getNativePlatform() { if (platform == null) { + @SuppressWarnings("removal") String platformFactoryProperty = AccessController.doPrivileged((PrivilegedAction) () -> System.getProperty("monocle.platform", "MX6,OMAP,Dispman,Android,X11,Linux,Headless")); @@ -105,7 +106,7 @@ public static synchronized NativePlatform getNativePlatform() { throw new IllegalArgumentException("Unrecognized Monocle platform: " + factoryClassName); } - NativePlatformFactory npf = (NativePlatformFactory) clazz.newInstance(); + NativePlatformFactory npf = (NativePlatformFactory) clazz.getDeclaredConstructor().newInstance(); if (npf.matches() && npf.getMajorVersion() == majorVersion && npf.getMinorVersion() == minorVersion) { diff --git a/src/main/java/com/sun/glass/ui/monocle/NativeScreen.java b/src/main/java/com/sun/glass/ui/monocle/NativeScreen.java index 0ca6853..d5f5305 100644 --- a/src/main/java/com/sun/glass/ui/monocle/NativeScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/NativeScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,22 @@ public interface NativeScreen { */ int getHeight(); + /** + * Returns the horizontal start position of this screen relative to the total + * combined screen size. + */ + default int getOffsetX() { + return 0; + } + + /** + * Returns the vertical start position of this screen relative to the total + * combined screen size. + */ + default int getOffsetY() { + return 0; + } + /** * Returns the number of pixels per inch in the screen. */ diff --git a/src/main/java/com/sun/glass/ui/monocle/OMAPPlatform.java b/src/main/java/com/sun/glass/ui/monocle/OMAPPlatform.java index f99fc3e..6f464f4 100644 --- a/src/main/java/com/sun/glass/ui/monocle/OMAPPlatform.java +++ b/src/main/java/com/sun/glass/ui/monocle/OMAPPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,8 @@ class OMAPPlatform extends LinuxPlatform { @Override protected NativeCursor createCursor() { - return new OMAPCursor(); + final NativeCursor c = useCursor ? new OMAPCursor() : new NullCursor(); + return logSelectedCursor(c); } @Override diff --git a/src/main/java/com/sun/glass/ui/monocle/TouchInput.java b/src/main/java/com/sun/glass/ui/monocle/TouchInput.java index 653db66..0540b63 100644 --- a/src/main/java/com/sun/glass/ui/monocle/TouchInput.java +++ b/src/main/java/com/sun/glass/ui/monocle/TouchInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,7 @@ class TouchInput { * events with a delta smaller then the value of this property will be * filtered out.The value of the property is in pixels. */ + @SuppressWarnings("removal") private final int touchRadius = AccessController.doPrivileged( (PrivilegedAction) () -> Integer.getInteger( "monocle.input.touchRadius", 20) @@ -70,6 +71,7 @@ private TouchInput() { TouchPipeline getBasePipeline() { if (basePipeline == null) { basePipeline = new TouchPipeline(); + @SuppressWarnings("removal") String[] touchFilterNames = AccessController.doPrivileged( (PrivilegedAction) () -> System.getProperty( "monocle.input.touchFilters", diff --git a/src/main/java/com/sun/glass/ui/monocle/TouchPipeline.java b/src/main/java/com/sun/glass/ui/monocle/TouchPipeline.java index 6b3da8d..22aac53 100644 --- a/src/main/java/com/sun/glass/ui/monocle/TouchPipeline.java +++ b/src/main/java/com/sun/glass/ui/monocle/TouchPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,7 +73,7 @@ void addNamedFilter(String filterName) { + filterName + "TouchFilter"; } ClassLoader loader = Thread.currentThread().getContextClassLoader(); - addFilter((TouchFilter) loader.loadClass(filterName).newInstance()); + addFilter((TouchFilter) loader.loadClass(filterName).getDeclaredConstructor().newInstance()); } } catch (Exception e) { System.err.println( diff --git a/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java b/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java index b4ff676..f0e822a 100644 --- a/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,7 @@ class VNCScreen extends HeadlessScreen { super(1024, 600, 32); try { server = ServerSocketChannel.open(); + @SuppressWarnings("removal") int vncPort = AccessController.doPrivileged( (PrivilegedAction) () -> Integer.getInteger("vnc.port", 5901)); @@ -275,6 +276,7 @@ public void run() { final MouseState state = new MouseState(); state.setX(x); state.setY(y); + // These values are from RFC 6143 Section 7.5.5. if (buttons.get(0)) { state.pressButton(MouseEvent.BUTTON_LEFT); } @@ -284,6 +286,20 @@ public void run() { if (buttons.get(2)) { state.pressButton(MouseEvent.BUTTON_RIGHT); } + if (buttons.get(3)) { + state.setWheel(MouseState.WHEEL_UP); + } + if (buttons.get(4)) { + state.setWheel(MouseState.WHEEL_DOWN); + } + // TODO: Buttons from here on are not officially mentioned in the docs, can someone confirm + // on a real device? + if (buttons.get(5)) { + state.pressButton(MouseEvent.BUTTON_BACK); + } + if (buttons.get(6)) { + state.pressButton(MouseEvent.BUTTON_FORWARD); + } Platform.runLater(() -> MouseInput.getInstance().setState(state, false)); break; } diff --git a/src/main/java/com/sun/glass/ui/monocle/X.java b/src/main/java/com/sun/glass/ui/monocle/X.java index f291b1b..86ba31c 100644 --- a/src/main/java/com/sun/glass/ui/monocle/X.java +++ b/src/main/java/com/sun/glass/ui/monocle/X.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ static X getX() { } private static void checkPermissions() { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(permission); @@ -85,6 +86,10 @@ private static void checkPermissions() { static final int Button3 = 3; static final int Button4 = 4; static final int Button5 = 5; + // 4th button (aka browser backward button). + static final int Button8 = 8; + // 5th button (aka browser forward button). + static final int Button9 = 9; static final long _NET_WM_STATE_REMOVE = 0; static final long _NET_WM_STATE_ADD = 1; diff --git a/src/main/java/com/sun/glass/ui/monocle/X11AcceleratedScreen.java b/src/main/java/com/sun/glass/ui/monocle/X11AcceleratedScreen.java index 47a0253..1c92f0e 100644 --- a/src/main/java/com/sun/glass/ui/monocle/X11AcceleratedScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/X11AcceleratedScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,6 +51,7 @@ protected long platformGetNativeDisplay() { * This workaround can be removed when the bug in the drivers is fixed. */ if (nativeDisplay == null) { + @SuppressWarnings("removal") boolean doMaliWorkaround = AccessController.doPrivileged( (PrivilegedAction) () -> diff --git a/src/main/java/com/sun/glass/ui/monocle/X11InputDeviceRegistry.java b/src/main/java/com/sun/glass/ui/monocle/X11InputDeviceRegistry.java index 0ff89e6..73bcd67 100644 --- a/src/main/java/com/sun/glass/ui/monocle/X11InputDeviceRegistry.java +++ b/src/main/java/com/sun/glass/ui/monocle/X11InputDeviceRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,6 +178,8 @@ private static int buttonToGlassButton(int button) { case X.Button1: return MouseEvent.BUTTON_LEFT; case X.Button2: return MouseEvent.BUTTON_OTHER; case X.Button3: return MouseEvent.BUTTON_RIGHT; + case X.Button8: return MouseEvent.BUTTON_BACK; + case X.Button9: return MouseEvent.BUTTON_FORWARD; default: return MouseEvent.BUTTON_NONE; } } diff --git a/src/main/java/com/sun/glass/ui/monocle/X11Platform.java b/src/main/java/com/sun/glass/ui/monocle/X11Platform.java index 336fcb8..1c69e88 100644 --- a/src/main/java/com/sun/glass/ui/monocle/X11Platform.java +++ b/src/main/java/com/sun/glass/ui/monocle/X11Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ class X11Platform extends NativePlatform { private final boolean x11Input; + @SuppressWarnings("removal") X11Platform() { LinuxSystem.getLinuxSystem().loadLibrary(); x11Input = AccessController.doPrivileged((PrivilegedAction) @@ -61,10 +62,11 @@ protected InputDeviceRegistry createInputDeviceRegistry() { */ @Override protected NativeCursor createCursor() { - if (x11Input) { - return new X11Cursor(); + if (useCursor) { + final NativeCursor c = x11Input ? new X11Cursor() : new X11WarpingCursor(); + return logSelectedCursor(c); } else { - return new X11WarpingCursor(); + return logSelectedCursor(new NullCursor()); } } diff --git a/src/main/java/com/sun/glass/ui/monocle/X11PlatformFactory.java b/src/main/java/com/sun/glass/ui/monocle/X11PlatformFactory.java index 4fd3786..1c56612 100644 --- a/src/main/java/com/sun/glass/ui/monocle/X11PlatformFactory.java +++ b/src/main/java/com/sun/glass/ui/monocle/X11PlatformFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ class X11PlatformFactory extends NativePlatformFactory { @Override protected boolean matches() { + @SuppressWarnings("removal") String display = AccessController.doPrivileged( (PrivilegedAction) () -> System.getenv("DISPLAY")); return display != null; diff --git a/src/main/java/com/sun/glass/ui/monocle/X11Screen.java b/src/main/java/com/sun/glass/ui/monocle/X11Screen.java index 5010136..91eb984 100644 --- a/src/main/java/com/sun/glass/ui/monocle/X11Screen.java +++ b/src/main/java/com/sun/glass/ui/monocle/X11Screen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,6 +74,7 @@ class X11Screen implements NativeScreen { int w = xLib.WidthOfScreen(screen); int h = xLib.HeightOfScreen(screen); boolean fullScreen = true; + @SuppressWarnings("removal") String geometry = AccessController.doPrivileged((PrivilegedAction) () -> System.getProperty("x11.geometry")); From 2df649c6186d82129277b115c41aea37b685bbe9 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Sat, 10 Feb 2024 21:02:04 -0700 Subject: [PATCH 17/22] Update gradle, script and configuration --- build.gradle | 17 +++--- gradle.properties | 4 +- gradle/publish-pom.gradle | 72 +++++++++++++----------- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 53 insertions(+), 42 deletions(-) diff --git a/build.gradle b/build.gradle index 7083878..18af940 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,10 @@ // } //} -apply plugin: 'java' +plugins { + id "java" + id "maven-publish" +} // print welcome message. //apply from: rootProject.file("gradle/welcome.gradle") @@ -66,12 +69,12 @@ ext { } // java language level. -sourceCompatibility = "11" -targetCompatibility = "11" +sourceCompatibility = "17" +targetCompatibility = "17" dependencies { - compileOnly "org.openjfx:javafx-base:11.0.2:${platform}" - compileOnly "org.openjfx:javafx-graphics:11.0.2:${platform}" + implementation "org.openjfx:javafx-base:17.0.10:${platform}" + implementation "org.openjfx:javafx-graphics:17.0.10:${platform}" } // configure publish tasks. @@ -93,7 +96,7 @@ task("javadocJar", type: Jar) { from javadoc } -jar.finalizedBy createPom +jar.finalizedBy generatePomFileForMavenPublication jar.finalizedBy sourceJar jar.finalizedBy javadocJar @@ -101,7 +104,7 @@ artifacts { archives jar archives sourceJar archives javadocJar - createPom + generatePomFileForMavenPublication } compileJava { diff --git a/gradle.properties b/gradle.properties index 9082760..80d5557 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,12 @@ group = org.testfx artifact = monocle -version = 11.0.2 +version = 17.0.10 description = Headless graphics driver for JavaFX vendor = The OpenJDK Community pomName = OpenJFX Monocle -pomDependencyVersion = 11.0.2 +pomDependencyVersion = 17.0.10 url = https://github.com/TestFX/Monocle sourceUrl = https://github.com/TestFX/Monocle diff --git a/gradle/publish-pom.gradle b/gradle/publish-pom.gradle index 8554f66..7738f2d 100644 --- a/gradle/publish-pom.gradle +++ b/gradle/publish-pom.gradle @@ -15,50 +15,58 @@ * specific language governing permissions and limitations under the Licence. */ -apply plugin: 'maven' - -task createPom { - description 'Generate the artifact pom file for Maven Central' - doLast { - pom { - project { - name "${project.pomName}" - description "${project.description}" - url "https://openjfx.io/" +publishing { + publications { + maven(MavenPublication) { + pom { + name = "${project.pomName}" + description = "${project.description}" + url = "https://openjfx.io/" licenses { - license([:]) { - name "GNU General Public License, version 2, with the Classpath Exception" - url "https://github.com/TestFX/Monocle/blob/main/LICENSE" - distribution "repo" + license { + name = "GNU General Public License, version 2, with the Classpath Exception" + url = "https://github.com/TestFX/Monocle/blob/main/LICENSE" + distribution = "repo" } } scm { - url "https://github.com/TestFX/Monocle" + url = "https://github.com/TestFX/Monocle" } developers { developer { - name "The OpenJDK Community" + name = "The OpenJDK Community" } } - dependencies { - dependency { - groupId "org.openjfx" - artifactId "javafx-base" - version "${project.pomDependencyVersion}" - scope "provided" - } - dependency { - groupId "org.openjfx" - artifactId "javafx-graphics" - version "${project.pomDependencyVersion}" - scope "provided" - } - } + withXml { + asNode().appendNode('dependencies') + .appendNode('dependency') + .appendNode('groupId', 'org.openjfx') + .parent() + .appendNode('artifactId', 'javafx-base') + .parent() + .appendNode('version', "${project.pomDependencyVersion}") + .parent() + .appendNode('scope', 'provided') + .parent() + .parent() + .appendNode('dependency') + .appendNode('groupId', 'org.openjfx') + .parent() + .appendNode('artifactId', 'javafx-graphics') + .parent() + .appendNode('version', "${project.pomDependencyVersion}") + .parent() + .appendNode('scope', 'provided') + } } - }.writeTo("$buildDir/libs/${project.name}-${project.version}.pom") - } + } + } +} + +tasks.named("generatePomFileForMavenPublication") { + destination = "$buildDir/libs/${project.name}-${project.version}.pom" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bb8b2fc..3994438 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From e138561df4ed17ad3fe874b82b9bdeb579d5a7ab Mon Sep 17 00:00:00 2001 From: msoderquist Date: Sat, 10 Feb 2024 21:10:29 -0700 Subject: [PATCH 18/22] Fix build configuration --- .github/workflows/entry.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/entry.yml b/.github/workflows/entry.yml index c856c36..c8002ce 100644 --- a/.github/workflows/entry.yml +++ b/.github/workflows/entry.yml @@ -34,6 +34,6 @@ jobs: uses: ./.github/workflows/build.yml with: os: ubuntu-22.04 - jdk: 8.0.372 - openjfx: 8 + jdk: 17.0.10 + openjfx: 17 secrets: inherit From 16f86d2478e92567c1e3eadeda2f108f6c29ca75 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Sat, 10 Feb 2024 21:13:08 -0700 Subject: [PATCH 19/22] Fix build configuration --- .github/workflows/entry.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/entry.yml b/.github/workflows/entry.yml index c8002ce..7aac828 100644 --- a/.github/workflows/entry.yml +++ b/.github/workflows/entry.yml @@ -5,10 +5,10 @@ on: workflow_dispatch: pull_request: branches: - - 'master' + - 'main' push: branches: - - 'master' + - 'main' permissions: actions: read From 40721f638c4acf5c74e85884bf22737af8c327ca Mon Sep 17 00:00:00 2001 From: msoderquist Date: Sun, 11 Feb 2024 11:01:20 -0700 Subject: [PATCH 20/22] Update to JFX 21.0.2 --- .github/workflows/entry.yml | 6 ++--- build.gradle | 20 +++++++------- gradle.properties | 4 +-- gradle/wrapper/gradle-wrapper.properties | 2 +- .../ui/monocle/AndroidAcceleratedScreen.java | 6 ++--- .../glass/ui/monocle/AndroidInputDevice.java | 4 +-- .../monocle/AndroidInputDeviceRegistry.java | 6 ++++- .../ui/monocle/AndroidInputProcessor.java | 18 +++++++++++-- .../sun/glass/ui/monocle/AndroidScreen.java | 12 ++++++++- .../ui/monocle/EGLAcceleratedScreen.java | 4 +-- .../com/sun/glass/ui/monocle/GetEvent.java | 4 +-- .../java/com/sun/glass/ui/monocle/IntSet.java | 13 ++++++++- .../com/sun/glass/ui/monocle/KeyState.java | 6 ++--- .../LinuxAbsoluteInputCapabilities.java | 7 +++-- .../com/sun/glass/ui/monocle/LinuxArch.java | 4 +-- .../glass/ui/monocle/LinuxEventBuffer.java | 10 ++++++- .../glass/ui/monocle/LinuxInputDevice.java | 4 ++- .../ui/monocle/LinuxPlatformFactory.java | 10 +++---- .../LinuxStatefulMultiTouchProcessor.java | 5 ++-- .../glass/ui/monocle/LinuxTouchTransform.java | 4 +-- .../glass/ui/monocle/MonocleApplication.java | 3 ++- .../sun/glass/ui/monocle/MonoclePixels.java | 2 +- .../ui/monocle/MonocleSystemClipboard.java | 8 +++++- .../com/sun/glass/ui/monocle/MonocleView.java | 10 ++++--- .../sun/glass/ui/monocle/MonocleWindow.java | 7 ++++- .../ui/monocle/MonocleWindowManager.java | 27 +++++++++++-------- .../com/sun/glass/ui/monocle/MouseState.java | 6 ++--- .../glass/ui/monocle/RunnableProcessor.java | 4 +-- .../java/com/sun/glass/ui/monocle/SysFS.java | 6 ++--- .../sun/glass/ui/monocle/TouchPipeline.java | 4 +-- .../com/sun/glass/ui/monocle/TouchState.java | 6 ++--- .../java/com/sun/glass/ui/monocle/Udev.java | 3 ++- .../com/sun/glass/ui/monocle/VNCScreen.java | 4 +-- src/main/java/com/sun/glass/ui/monocle/X.java | 3 ++- .../com/sun/glass/ui/monocle/X11Cursor.java | 3 +-- 35 files changed, 151 insertions(+), 94 deletions(-) diff --git a/.github/workflows/entry.yml b/.github/workflows/entry.yml index 7aac828..499b6a8 100644 --- a/.github/workflows/entry.yml +++ b/.github/workflows/entry.yml @@ -1,5 +1,5 @@ --- -name: TestFX 4 CI +name: Monocle CI on: workflow_dispatch: @@ -34,6 +34,6 @@ jobs: uses: ./.github/workflows/build.yml with: os: ubuntu-22.04 - jdk: 17.0.10 - openjfx: 17 + jdk: 21.0.2 + openjfx: 21 secrets: inherit diff --git a/build.gradle b/build.gradle index 18af940..0e51e0a 100644 --- a/build.gradle +++ b/build.gradle @@ -69,12 +69,12 @@ ext { } // java language level. -sourceCompatibility = "17" -targetCompatibility = "17" +sourceCompatibility = "21" +targetCompatibility = "21" dependencies { - implementation "org.openjfx:javafx-base:17.0.10:${platform}" - implementation "org.openjfx:javafx-graphics:17.0.10:${platform}" + implementation "org.openjfx:javafx-base:21.0.2:${platform}" + implementation "org.openjfx:javafx-graphics:21.0.2:${platform}" } // configure publish tasks. @@ -82,17 +82,17 @@ apply from: rootProject.file("gradle/publish-pom.gradle") // task to create jar with source code. task("sourceJar", type: Jar) { - group "Build" - description "An archive of the source code" - classifier "sources" + group = "Build" + description = "An archive of the source code" + archiveClassifier = "sources" from sourceSets.main.allJava } // task to create jar with javadocs. task("javadocJar", type: Jar) { - group "Build" - description "An archive of the javadoc" - classifier "javadoc" + group = "Build" + description = "An archive of the javadoc" + archiveClassifier = "javadoc" from javadoc } diff --git a/gradle.properties b/gradle.properties index 80d5557..975acef 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,12 @@ group = org.testfx artifact = monocle -version = 17.0.10 +version = 21.0.2 description = Headless graphics driver for JavaFX vendor = The OpenJDK Community pomName = OpenJFX Monocle -pomDependencyVersion = 17.0.10 +pomDependencyVersion = 21.0.2 url = https://github.com/TestFX/Monocle sourceUrl = https://github.com/TestFX/Monocle diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3994438..17655d0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/com/sun/glass/ui/monocle/AndroidAcceleratedScreen.java b/src/main/java/com/sun/glass/ui/monocle/AndroidAcceleratedScreen.java index a04a781..8018621 100644 --- a/src/main/java/com/sun/glass/ui/monocle/AndroidAcceleratedScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/AndroidAcceleratedScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,6 @@ package com.sun.glass.ui.monocle; -import java.security.AccessController; -import java.security.PrivilegedAction; - /** * Provide Android implementation of AcceleratedScreen * @@ -39,6 +36,7 @@ class AndroidAcceleratedScreen extends AcceleratedScreen { super(attributes); } + @Override boolean initPlatformLibraries() { return super.initPlatformLibraries(); } diff --git a/src/main/java/com/sun/glass/ui/monocle/AndroidInputDevice.java b/src/main/java/com/sun/glass/ui/monocle/AndroidInputDevice.java index 59664b2..0ac7a65 100644 --- a/src/main/java/com/sun/glass/ui/monocle/AndroidInputDevice.java +++ b/src/main/java/com/sun/glass/ui/monocle/AndroidInputDevice.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,6 @@ package com.sun.glass.ui.monocle; -import java.io.IOException; - /** * */ diff --git a/src/main/java/com/sun/glass/ui/monocle/AndroidInputDeviceRegistry.java b/src/main/java/com/sun/glass/ui/monocle/AndroidInputDeviceRegistry.java index fccb442..133034b 100644 --- a/src/main/java/com/sun/glass/ui/monocle/AndroidInputDeviceRegistry.java +++ b/src/main/java/com/sun/glass/ui/monocle/AndroidInputDeviceRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,10 @@ public static void dispatchKeyEventFromNative(int type, int key, char[] chars, i instance.processor.dispatchKeyEvent(type, key, chars, modifiers); } + public static void dispatchMenuEventFromNative(int x, int y, int xAbs, int yAbs, boolean isKeyboardTrigger) { + instance.processor.dispatchMenuEvent(x, y, xAbs, yAbs, isKeyboardTrigger); + } + public static void gotKeyEventFromNative(int action, int linuxKey) { instance.gotKeyEvent (action, linuxKey); } diff --git a/src/main/java/com/sun/glass/ui/monocle/AndroidInputProcessor.java b/src/main/java/com/sun/glass/ui/monocle/AndroidInputProcessor.java index dee4ffd..d20167f 100644 --- a/src/main/java/com/sun/glass/ui/monocle/AndroidInputProcessor.java +++ b/src/main/java/com/sun/glass/ui/monocle/AndroidInputProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ synchronized void pushKeyEvent(KeyState keyState) { synchronized void dispatchKeyEvent(int type, int key, char[] chars, int modifiers) { Platform.runLater( () -> { - MonocleWindow window = (MonocleWindow) MonocleWindowManager.getInstance().getFocusedWindow(); + MonocleWindow window = MonocleWindowManager.getInstance().getFocusedWindow(); if (window == null) { return; } @@ -70,4 +70,18 @@ synchronized void dispatchKeyEvent(int type, int key, char[] chars, int modifier }); } + synchronized void dispatchMenuEvent(int x, int y, int xAbs, int yAbs, boolean isKeyboardTrigger) { + Platform.runLater(() -> { + MonocleWindow window = MonocleWindowManager.getInstance().getFocusedWindow(); + if (window == null) { + return; + } + MonocleView view = (MonocleView) window.getView(); + if (view == null) { + return; + } + RunnableProcessor.runLater(() -> view.notifyMenu(x, y, xAbs, yAbs, isKeyboardTrigger)); + }); + } + } diff --git a/src/main/java/com/sun/glass/ui/monocle/AndroidScreen.java b/src/main/java/com/sun/glass/ui/monocle/AndroidScreen.java index 75ac1bb..0cc8c6c 100644 --- a/src/main/java/com/sun/glass/ui/monocle/AndroidScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/AndroidScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ public class AndroidScreen implements NativeScreen { private float density = -1; + @Override public int getDepth() { return 24; } @@ -41,6 +42,7 @@ public int getDepth() { * Returns the native format of the screen, as a constant from the Pixels * class. */ + @Override public int getNativeFormat() { return Pixels.Format.BYTE_ARGB; } @@ -48,6 +50,7 @@ public int getNativeFormat() { /** * Returns the pixel width of the screen. */ + @Override public int getWidth() { int answer = (int)(_getWidth()/getScale()); return answer; @@ -56,6 +59,7 @@ public int getWidth() { /** * Returns the pixel height of the screen. */ + @Override public int getHeight() { return (int)(_getHeight()/getScale()); } @@ -63,6 +67,7 @@ public int getHeight() { /** * Returns the number of pixels per inch in the screen. */ + @Override public int getDPI() { return 100; } @@ -78,6 +83,7 @@ public float getScale () { /** * Returns a native handle for the screen. The handle is platform-specific. */ + @Override public long getNativeHandle() { long answer = _getNativeHandle(); return answer; @@ -86,6 +92,7 @@ public long getNativeHandle() { /** * Called during JavaFX shutdown to release the screen. Called only once. */ + @Override public void shutdown() { _shutdown(); } @@ -101,6 +108,7 @@ public void shutdown() { * @param alpha The alpha level to use to compose the data over existing * pixels */ + @Override public void uploadPixels(Buffer b, int x, int y, int width, int height, float alpha) { _uploadPixels (b, x, y, width, height, alpha); @@ -110,6 +118,7 @@ public void uploadPixels(Buffer b, * Called on the JavaFX application thread when pixel data for all windows * has been uploaded. */ + @Override public void swapBuffers() { _swapBuffers(); } @@ -118,6 +127,7 @@ public void swapBuffers() { * Returns a read-only ByteBuffer in the native pixel format containing the screen contents. * @return ByteBuffer a read-only ByteBuffer containing the screen contents */ + @Override public ByteBuffer getScreenCapture() { return _getScreenCapture(); } diff --git a/src/main/java/com/sun/glass/ui/monocle/EGLAcceleratedScreen.java b/src/main/java/com/sun/glass/ui/monocle/EGLAcceleratedScreen.java index b6db852..3eea128 100644 --- a/src/main/java/com/sun/glass/ui/monocle/EGLAcceleratedScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/EGLAcceleratedScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ public class EGLAcceleratedScreen extends AcceleratedScreen { * @param attributes an array of attributes that will be used by the underlying * implementation to get the best matching configuration. */ - EGLAcceleratedScreen(int[] attributes) throws GLException { + EGLAcceleratedScreen(int[] attributes) { eglWindowHandle = platformGetNativeWindow(); eglDisplay = nGetEglDisplayHandle(); nEglInitialize(eglDisplay); diff --git a/src/main/java/com/sun/glass/ui/monocle/GetEvent.java b/src/main/java/com/sun/glass/ui/monocle/GetEvent.java index 85f83ee..368344f 100644 --- a/src/main/java/com/sun/glass/ui/monocle/GetEvent.java +++ b/src/main/java/com/sun/glass/ui/monocle/GetEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ class GetEvent { } devices.add(sysPath); } else if (action.equals("remove")) { - devices.remove(devPath); + devices.remove(sysPath); } } catch (IOException | RuntimeException e) { e.printStackTrace(); diff --git a/src/main/java/com/sun/glass/ui/monocle/IntSet.java b/src/main/java/com/sun/glass/ui/monocle/IntSet.java index f108b67..794f1c4 100644 --- a/src/main/java/com/sun/glass/ui/monocle/IntSet.java +++ b/src/main/java/com/sun/glass/ui/monocle/IntSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -144,6 +144,7 @@ public boolean equals(IntSet set) { } } + @Override public boolean equals(Object o) { if (o instanceof IntSet) { return equals((IntSet) o); @@ -152,6 +153,16 @@ public boolean equals(Object o) { } } + @Override + public int hashCode() { + int h = 1; + for (int i = 0; i < size; i++) { + h = 31 * h + elements[i]; + } + return h; + } + + @Override public String toString() { StringBuffer sb = new StringBuffer("IntSet["); for (int i = 0; i < size; i++) { diff --git a/src/main/java/com/sun/glass/ui/monocle/KeyState.java b/src/main/java/com/sun/glass/ui/monocle/KeyState.java index e976555..3745f83 100644 --- a/src/main/java/com/sun/glass/ui/monocle/KeyState.java +++ b/src/main/java/com/sun/glass/ui/monocle/KeyState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,8 +77,7 @@ IntSet getKeysPressed() { /** Returns the Glass window on which this event state is located . */ MonocleWindow getWindow(boolean recalculateCache) { if (window == null || recalculateCache) { - window = (MonocleWindow) - MonocleWindowManager.getInstance().getFocusedWindow(); + window = MonocleWindowManager.getInstance().getFocusedWindow(); } return window; } @@ -111,6 +110,7 @@ boolean isControlPressed() { return (modifiers & KeyEvent.MODIFIER_CONTROL) != 0; } + @Override public String toString() { return "KeyState[modifiers=" + modifiers + ",keys=" + keysPressed + "]"; } diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxAbsoluteInputCapabilities.java b/src/main/java/com/sun/glass/ui/monocle/LinuxAbsoluteInputCapabilities.java index ee0449b..27e1e5a 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxAbsoluteInputCapabilities.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxAbsoluteInputCapabilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ class LinuxAbsoluteInputCapabilities { private LinuxAbsoluteInputCapabilities(LinuxSystem system, LinuxSystem.InputAbsInfo info, - long fd, int axis) throws IOException { + long fd, int axis) { system.ioctl(fd, system.EVIOCGABS(axis), info.p); value = LinuxSystem.InputAbsInfo.getValue(info.p); minimum = LinuxSystem.InputAbsInfo.getMinimum(info.p); @@ -81,8 +81,7 @@ static Map getCapabilities( if (fd == -1) { throw new IOException(system.getErrorMessage()); } - Map caps = - new HashMap(); + Map caps = new HashMap<>(); for (int i = 0; (i = axes.nextSetBit(i)) != -1; i++) { caps.put(i, new LinuxAbsoluteInputCapabilities(system, info, fd, i)); } diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxArch.java b/src/main/java/com/sun/glass/ui/monocle/LinuxArch.java index b4b6514..820e0c1 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxArch.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxArch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ public class LinuxArch { private static final int bits = AccessController.doPrivileged((PrivilegedAction) () -> { LinuxSystem system = LinuxSystem.getLinuxSystem(); return (int) system.sysconf(LinuxSystem._SC_LONG_BIT); - });; + }); static boolean is64Bit() { return bits == 64; diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxEventBuffer.java b/src/main/java/com/sun/glass/ui/monocle/LinuxEventBuffer.java index 6502bd6..a1bf9f6 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxEventBuffer.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxEventBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,16 +41,24 @@ interface EventStruct { } class EventStruct32Bit implements EventStruct { + @Override public int getTypeIndex() { return 8; } + @Override public int getCodeIndex() { return 10; } + @Override public int getValueIndex() { return 12; } + @Override public int getSize() { return 16; } } class EventStruct64Bit implements EventStruct { + @Override public int getTypeIndex() { return 16; } + @Override public int getCodeIndex() { return 18; } + @Override public int getValueIndex() { return 20; } + @Override public int getSize() { return 24; } } diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxInputDevice.java b/src/main/java/com/sun/glass/ui/monocle/LinuxInputDevice.java index ac2b7e2..ebbedf4 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxInputDevice.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxInputDevice.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,6 +173,7 @@ public void run() { class EventProcessor implements Runnable { boolean scheduled; + @Override public void run() { buffer.startIteration(); // Do not lock the buffer while processing events. We still want to be @@ -211,6 +212,7 @@ boolean isQuiet() { /** * @return a string describing this input device */ + @Override public String toString() { return devNode == null ? "Robot" : devNode.toString(); } diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxPlatformFactory.java b/src/main/java/com/sun/glass/ui/monocle/LinuxPlatformFactory.java index 040dae5..ec47c5f 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxPlatformFactory.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxPlatformFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,17 +25,13 @@ package com.sun.glass.ui.monocle; -import java.security.AccessController; -import java.security.PrivilegedAction; +import com.sun.javafx.PlatformUtil; class LinuxPlatformFactory extends NativePlatformFactory { @Override protected boolean matches() { - @SuppressWarnings("removal") - String os = AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("os.name")); - return os != null && os.equals("Linux"); + return PlatformUtil.isLinux(); } @Override diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxStatefulMultiTouchProcessor.java b/src/main/java/com/sun/glass/ui/monocle/LinuxStatefulMultiTouchProcessor.java index 5ce5eb5..a835e37 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxStatefulMultiTouchProcessor.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxStatefulMultiTouchProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,8 +38,7 @@ class LinuxStatefulMultiTouchProcessor extends LinuxTouchProcessor { private int currentID = ID_UNASSIGNED; private int currentSlot = 0; - private final Map slotToIDMap = - new HashMap(); + private final Map slotToIDMap = new HashMap<>(); LinuxStatefulMultiTouchProcessor(LinuxInputDevice device) { super(device); diff --git a/src/main/java/com/sun/glass/ui/monocle/LinuxTouchTransform.java b/src/main/java/com/sun/glass/ui/monocle/LinuxTouchTransform.java index d9e6c98..66bfbf4 100644 --- a/src/main/java/com/sun/glass/ui/monocle/LinuxTouchTransform.java +++ b/src/main/java/com/sun/glass/ui/monocle/LinuxTouchTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +148,7 @@ private void initTransform(int axis, int index) { "monocle.input." + product + ".max" + axisName, caps.getMaximum()); translates[index] = -minimum; - scalars[index] = ((double) (range)) / (maximum - minimum); + scalars[index] = range / (maximum - minimum); return null; }); } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java b/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java index 3dff9b0..9f7a33d 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -259,6 +259,7 @@ protected int staticTimer_getMaxPeriod() { return MonocleTimer.getMaxPeriod_impl(); } + @Override public boolean hasWindowManager() { return false; } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java b/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java index 5c4fee0..57448d7 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonoclePixels.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleSystemClipboard.java b/src/main/java/com/sun/glass/ui/monocle/MonocleSystemClipboard.java index d0e5839..d8a50ab 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleSystemClipboard.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleSystemClipboard.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,24 +39,30 @@ final class MonocleSystemClipboard extends SystemClipboard { super(Clipboard.SYSTEM); } + @Override protected boolean isOwner() { return true; } + @Override protected void pushToSystem(HashMap cacheData, int supportedActions) { } + @Override protected void pushTargetActionToSystem(int actionDone) { } + @Override protected Object popFromSystem(String mimeType) { return null; } + @Override protected int supportedSourceActionsFromSystem() { return Clipboard.ACTION_NONE; } + @Override protected String[] mimesFromSystem() { return new String[0]; } diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleView.java b/src/main/java/com/sun/glass/ui/monocle/MonocleView.java index 9281db7..84df91f 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleView.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -201,7 +201,9 @@ protected boolean _enterFullscreen(long ptr, boolean animate, boolean hideCursor) { MonocleWindowManager wm = MonocleWindowManager.getInstance(); MonocleWindow focusedWindow = wm.getFocusedWindow(); - focusedWindow.setFullScreen(true); + if (focusedWindow != null) { + focusedWindow.setFullScreen(true); + } if (hideCursor) { resetCursorVisibility = true; NativeCursor nativeCursor = @@ -216,7 +218,9 @@ protected boolean _enterFullscreen(long ptr, boolean animate, protected void _exitFullscreen(long ptr, boolean animate) { MonocleWindowManager wm = MonocleWindowManager.getInstance(); MonocleWindow focusedWindow = wm.getFocusedWindow(); - focusedWindow.setFullScreen(false); + if (focusedWindow != null) { + focusedWindow.setFullScreen(false); + } if (resetCursorVisibility) { resetCursorVisibility = false; NativeCursor nativeCursor = diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java b/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java index b04bc4e..fba8a19 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -268,6 +268,11 @@ protected boolean _maximize(long nativeWindowPointer, boolean maximize, return true; } + @Override + protected void notifyMoveToAnotherScreen(Screen screen) { + super.notifyMoveToAnotherScreen(screen); + } + void setFullScreen(boolean fullscreen) { NativeScreen screen = NativePlatformFactory.getNativePlatform().getScreen(); int x = getX(); diff --git a/src/main/java/com/sun/glass/ui/monocle/MonocleWindowManager.java b/src/main/java/com/sun/glass/ui/monocle/MonocleWindowManager.java index 675d458..ff63867 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MonocleWindowManager.java +++ b/src/main/java/com/sun/glass/ui/monocle/MonocleWindowManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,7 +97,7 @@ boolean closeWindow(MonocleWindow window) { windows.length - index - 1); windows = Arrays.copyOf(windows, windows.length - 1); } - List windowsToNotify = new ArrayList(); + List windowsToNotify = new ArrayList<>(); for (MonocleWindow otherWindow : windows) { if (otherWindow.getOwner() == window) { windowsToNotify.add(otherWindow); @@ -107,6 +107,9 @@ boolean closeWindow(MonocleWindow window) { windowsToNotify.get(i).notifyClose(); } window.notifyDestroy(); + if (focusedWindow == window) { + focusedWindow = null; + } return true; } @@ -170,16 +173,18 @@ void repaintAll() { } } - static void repaintFromNative () { - Platform.runLater(new Runnable () { - - @Override - public void run() { - Screen.notifySettingsChanged(); - instance.getFocusedWindow().setFullScreen(true); - instance.repaintAll(); - Toolkit.getToolkit().requestNextPulse(); + static void repaintFromNative(Screen screen) { + Platform.runLater(() -> { + Screen.notifySettingsChanged(); + MonocleWindow focusedWindow = instance.getFocusedWindow(); + if (focusedWindow != null) { + if (screen != null && screen.getNativeScreen() != focusedWindow.getScreen().getNativeScreen()) { + focusedWindow.notifyMoveToAnotherScreen(screen); + } + focusedWindow.setFullScreen(true); } + instance.repaintAll(); + Toolkit.getToolkit().requestNextPulse(); }); } diff --git a/src/main/java/com/sun/glass/ui/monocle/MouseState.java b/src/main/java/com/sun/glass/ui/monocle/MouseState.java index 86e65cf..3af7d36 100644 --- a/src/main/java/com/sun/glass/ui/monocle/MouseState.java +++ b/src/main/java/com/sun/glass/ui/monocle/MouseState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,8 +92,7 @@ void releaseButton(int button) { */ MonocleWindow getWindow(boolean recalculateCache, MonocleWindow fallback) { if (recalculateCache) { - window = (MonocleWindow) - MonocleWindowManager.getInstance().getWindowForLocation(x, y); + window = MonocleWindowManager.getInstance().getWindowForLocation(x, y); } if (window == null) { window = fallback; @@ -149,6 +148,7 @@ IntSet getButtonsPressed() { return buttonsPressed; } + @Override public String toString() { return "MouseState[x=" + x + ",y=" + y diff --git a/src/main/java/com/sun/glass/ui/monocle/RunnableProcessor.java b/src/main/java/com/sun/glass/ui/monocle/RunnableProcessor.java index 1298083..92154ae 100644 --- a/src/main/java/com/sun/glass/ui/monocle/RunnableProcessor.java +++ b/src/main/java/com/sun/glass/ui/monocle/RunnableProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ private static class RunLoopControl { } // our stack of nested run loops - private LinkedList activeRunLoops = new LinkedList(); + private LinkedList activeRunLoops = new LinkedList<>(); @Override public void run() { diff --git a/src/main/java/com/sun/glass/ui/monocle/SysFS.java b/src/main/java/com/sun/glass/ui/monocle/SysFS.java index 24f2acb..c6026bd 100644 --- a/src/main/java/com/sun/glass/ui/monocle/SysFS.java +++ b/src/main/java/com/sun/glass/ui/monocle/SysFS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,6 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.IntBuffer; -import java.nio.LongBuffer; import java.util.BitSet; import java.util.HashMap; import java.util.Map; @@ -45,7 +43,7 @@ class SysFS { /** Read input device capability data from sysfs */ static Map readCapabilities(File sysPath) { - Map capsMap = new HashMap(); + Map capsMap = new HashMap<>(); File[] capsFiles = new File(sysPath, "device/capabilities").listFiles(); if (capsFiles == null) { return capsMap; diff --git a/src/main/java/com/sun/glass/ui/monocle/TouchPipeline.java b/src/main/java/com/sun/glass/ui/monocle/TouchPipeline.java index 22aac53..584007b 100644 --- a/src/main/java/com/sun/glass/ui/monocle/TouchPipeline.java +++ b/src/main/java/com/sun/glass/ui/monocle/TouchPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ class TouchPipeline { private TouchInput touch = TouchInput.getInstance(); - private ArrayList filters = new ArrayList(); + private ArrayList filters = new ArrayList<>(); private TouchState flushState = new TouchState(); /** diff --git a/src/main/java/com/sun/glass/ui/monocle/TouchState.java b/src/main/java/com/sun/glass/ui/monocle/TouchState.java index 2e104d0..81200bb 100644 --- a/src/main/java/com/sun/glass/ui/monocle/TouchState.java +++ b/src/main/java/com/sun/glass/ui/monocle/TouchState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,9 +86,7 @@ MonocleWindow getWindow(boolean recalculateCache, MonocleWindow fallback) { if (primaryID >= 0) { Point p = getPointForID(primaryID); if (p != null) { - window = (MonocleWindow) - MonocleWindowManager.getInstance() - .getWindowForLocation(p.x, p.y); + window = MonocleWindowManager.getInstance().getWindowForLocation(p.x, p.y); } } } diff --git a/src/main/java/com/sun/glass/ui/monocle/Udev.java b/src/main/java/com/sun/glass/ui/monocle/Udev.java index 0200bf9..1165ab5 100644 --- a/src/main/java/com/sun/glass/ui/monocle/Udev.java +++ b/src/main/java/com/sun/glass/ui/monocle/Udev.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,6 +94,7 @@ public void run() { while (true) { Map event = readEvent(); runnableProcessor.invokeLater(new Runnable() { + @Override public void run() { String action = event.get("ACTION"); if (action != null) { diff --git a/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java b/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java index f0e822a..c0ac6a6 100644 --- a/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java +++ b/src/main/java/com/sun/glass/ui/monocle/VNCScreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ class VNCScreen extends HeadlessScreen { private ServerSocketChannel server; - private Set clients = new HashSet(); + private Set clients = new HashSet<>(); VNCScreen() { super(1024, 600, 32); diff --git a/src/main/java/com/sun/glass/ui/monocle/X.java b/src/main/java/com/sun/glass/ui/monocle/X.java index 86ba31c..62fc822 100644 --- a/src/main/java/com/sun/glass/ui/monocle/X.java +++ b/src/main/java/com/sun/glass/ui/monocle/X.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -176,6 +176,7 @@ static class XDisplay extends C.Structure { XDisplay(long p) { super(p); } + @Override native int sizeof(); } diff --git a/src/main/java/com/sun/glass/ui/monocle/X11Cursor.java b/src/main/java/com/sun/glass/ui/monocle/X11Cursor.java index 4c02d58..78d6d43 100644 --- a/src/main/java/com/sun/glass/ui/monocle/X11Cursor.java +++ b/src/main/java/com/sun/glass/ui/monocle/X11Cursor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ import com.sun.glass.ui.Size; -import java.io.IOException; import java.nio.ByteBuffer; /** Provides a native cursor for use with X11. Since X11 doesn't provide any From fbf0aaea0cff8439cd7fde8da124509184433de0 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Sun, 11 Feb 2024 11:02:11 -0700 Subject: [PATCH 21/22] Update to JFX 21.0.2 --- .github/workflows/entry.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/entry.yml b/.github/workflows/entry.yml index 499b6a8..880a530 100644 --- a/.github/workflows/entry.yml +++ b/.github/workflows/entry.yml @@ -4,8 +4,6 @@ name: Monocle CI on: workflow_dispatch: pull_request: - branches: - - 'main' push: branches: - 'main' From 8a9b04bf2e327f2c137e1a2d74e2c24659f95265 Mon Sep 17 00:00:00 2001 From: msoderquist Date: Sun, 11 Feb 2024 11:02:47 -0700 Subject: [PATCH 22/22] Update to JFX 21.0.2 --- .github/workflows/entry.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/entry.yml b/.github/workflows/entry.yml index 880a530..87ccbc0 100644 --- a/.github/workflows/entry.yml +++ b/.github/workflows/entry.yml @@ -5,8 +5,6 @@ on: workflow_dispatch: pull_request: push: - branches: - - 'main' permissions: actions: read