On Thu, 19 Jun 2025 08:47:08 GMT, Johan Vos <j...@openjdk.org> wrote:
>> After spending a year in the sandbox repository, the Headless Platform is >> now ready to be reviewed in the main repository. >> >> ### the Headless Platform >> The Headless Platform is a top-level com.sun.glass.ui platform that replaces >> the second-level Monocle-Headless subplatform, that is part of the top-level >> Monocle platform. >> The platform can be used like any other platform, especially for running >> headless JavaFX applications, or for running tests (e.g. on CI systems) >> >> ### changes >> The code for the Headless Platform is in a new package >> com.sun.glass.ui.headless in the javafx.graphics module, and it does not >> require a code change in other packages. >> This PR adds a simple change in the `build.gradle` file, to make the >> Headless Platform the standard when running headless tests (instead of using >> Monocle/Headless) >> >> ### enable the Headless Platform >> Setting the system property `glass.platform` to `Headless` will select the >> Headless Platform instead of the default one (either gtk, mac or win). >> >> ### testing >> `gradlew --info -PHEADLESS_TEST=true -PFULL_TEST=true :systemTests:cleanTest >> :systemTests:test` >> runs all the system tests, apart from the robot tests. There are 2 failing >> tests, but there are valid reasons for those to fail. >> >> ### robot tests >> Most of the robot tests are working on headless as well. add `-PUSE_ROBOT` >> to test those. > > Johan Vos has updated the pull request incrementally with one additional > commit since the last revision: > > Fix missing ; My testing shows that the headless platform works as expected. Some general comments: 1. All files need a copyright header. 2. Very long lines can benefit from a few line breaks. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessApplication.java line 23: > 21: private final HeadlessWindowManager windowManager = new > HeadlessWindowManager(); > 22: private Screen[] screens = null; > 23: private HeadlessCursor cursor; This field is not used in this class, other than assigning a value. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessApplication.java line 29: > 27: private final int MULTICLICK_MAX_X = 20; > 28: private final int MULTICLICK_MAX_Y = 20; > 29: private final long MULTICLICK_TIME = 500; These fields should be `static`. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessApplication.java line 173: > 171: > 172: @Override > 173: protected CommonDialogs.FileChooserResult > staticCommonDialogs_showFileChooser(Window owner, String folder, String > filename, String title, int type, boolean multipleMode, > CommonDialogs.ExtensionFilter[] extensionFilters, int defaultFilterIndex) { This is an extremely long line... modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessPlatformFactory.java line 52: > 50: } > 51: > 52: class HeadlessSystemClipboard extends SystemClipboard { This class can be `static`. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessPlatformFactory.java line 92: > 90: } > 91: > 92: class HeadlessDnDClipboard extends SystemClipboard { This class can be `static`. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessRobot.java line 63: > 61: view.notifyKey(KeyEvent.TYPED, 0, keyval, mods); > 62: } > 63: Minor: empty line modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessRobot.java line 213: > 211: HeadlessView view = (HeadlessView)activeWindow.getView(); > 212: int modifiers = 0; > 213: view.notifyMouse(MouseEvent.ENTER, MouseEvent.BUTTON_NONE, > (int)mouseX-wx, (int)mouseY-wy, (int)mouseX, (int)mouseY, modifiers, true, > true); Minor: spacing around operators modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessRobot.java line 219: > 217: int owx = oldWindow.getX(); > 218: int owy = oldWindow.getY(); > 219: oldView.notifyMouse(MouseEvent.EXIT, > MouseEvent.BUTTON_NONE, (int)mouseX-owx, (int)mouseY-owy, (int)mouseX, > (int)mouseY, modifiers, true, true); Minor: spacing around operators modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessRobot.java line 277: > 275: modifiers |= KeyEvent.MODIFIER_BUTTON_FORWARD; > 276: break; > 277: } Using an expression can help increase readibility and correctness: Suggestion: modifiers |= switch (buttons[i]) { case NONE -> KeyEvent.MODIFIER_NONE; case PRIMARY -> KeyEvent.MODIFIER_BUTTON_PRIMARY; case MIDDLE -> KeyEvent.MODIFIER_BUTTON_MIDDLE; case SECONDARY -> KeyEvent.MODIFIER_BUTTON_SECONDARY; case BACK -> KeyEvent.MODIFIER_BUTTON_BACK; case FORWARD -> KeyEvent.MODIFIER_BUTTON_FORWARD; }; modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessRobot.java line 293: > 291: if (button == MouseButton.BACK) return MouseEvent.BUTTON_BACK; > 292: if (button == MouseButton.FORWARD) return > MouseEvent.BUTTON_FORWARD; > 293: return MouseEvent.BUTTON_NONE; Use an expression to get compile-time exhaustiveness checks: Suggestion: return switch (button) { case NONE -> MouseEvent.BUTTON_NONE; case PRIMARY -> MouseEvent.BUTTON_LEFT; case MIDDLE -> MouseEvent.BUTTON_OTHER; case SECONDARY -> MouseEvent.BUTTON_RIGHT; case BACK -> MouseEvent.BUTTON_BACK; case FORWARD -> MouseEvent.BUTTON_FORWARD; }; modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessRobot.java line 390: > 388: if (this.specialKeys.keyShift) answer = answer | > KeyEvent.MODIFIER_SHIFT; > 389: if (this.specialKeys.keyCommand) answer = answer | > KeyEvent.MODIFIER_COMMAND; > 390: if (this.specialKeys.keyAlt) answer = answer | > KeyEvent.MODIFIER_ALT; You can remove four utterances of the word "answer" by using the `|=` operator. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessTimer.java line 11: > 9: > 10: private static ScheduledThreadPoolExecutor scheduler; > 11: private ScheduledFuture task; You can use the parameterized type `ScheduledFuture<?>`. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessView.java line 16: > 14: private Pixels pixels; > 15: > 16: private boolean imeEnabled; The following fields are not read, but only assigned to in this class: * `capabilities` * `x` * `y` * `imeEnabled` The field `parentPtr` is neither assigned nor read. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessView.java line 46: > 44: @Override > 45: protected void _setParent(long ptr, long parentPtr) { > 46: parentPtr = parentPtr; You're assigning a variable to itself. But even if you qualify `this.parentPtr`, the assignment seems pointless. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessView.java line 79: > 77: } > 78: > 79: Pixels getPixels() { This method is never used. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessWindow.java line 36: > 34: private float alpha; > 35: private Pixels icon; > 36: private Cursor cursor; The following fields are never used, other than assigning a value: * `ptr` * `resizable` * `visible` * `isFocusable` * `enabled` * `closed` * `bg_r`, `bg_g`, `bg_b` * `alpha` * `icon` * `cursor` modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessWindow.java line 106: > 104: this.originalY = this.y; > 105: newX = 0; > 106: newY = 0; `newX` and `newY` already have the value 0. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessWindow.java line 259: > 257: > 258: @Override > 259: protected void _requestInput(long ptr, String text, int type, double > width, double height, double Mxx, double Mxy, double Mxz, double Mxt, double > Myx, double Myy, double Myz, double Myt, double Mzx, double Mzy, double Mzz, > double Mzt) { Another very long line. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessWindow.java line 268: > 266: } > 267: > 268: boolean setFullscreen(boolean full) { None of the two callers use the return value of this method. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessWindow.java line 294: > 292: private void notifyResizeAndMove(int x, int y, int width, int > height) { > 293: HeadlessView view = (HeadlessView) getView(); > 294: // if (getWidth() != width || getHeight() != height) { Why is this code commented out? modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessWindow.java line 306: > 304: > 305: public Color getColor(int lx, int ly) { > 306: int mx = lx;// + getX(); Why is this code commented out? modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessWindow.java line 350: > 348: int val = intBuffer.get(i * pixels.getWidth() + j); > 349: if (val != 0) { > 350: } The `if` statement has an empty body. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/HeadlessWindowManager.java line 22: > 20: } > 21: > 22: private HeadlessWindow getFocusedWindow() { This private method is never used. modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/NestedRunnableProcessor.java line 20: > 18: } > 19: > 20: void invokeLater(final Runnable r) { The following methods are never used: * `invokeLater` * `runLater` * `invokeAndWait` * `stopProcessing` modules/javafx.graphics/src/main/java/com/sun/glass/ui/headless/NestedRunnableProcessor.java line 61: > 59: } catch (Throwable e) { > 60: e.printStackTrace(); > 61: Application.reportException(e); Why do you print the exception, _and_ send it to `Application.reportException()`? The latter already sends it to the uncaught exception handler, where it is printed by default. ------------- PR Review: https://git.openjdk.org/jfx/pull/1836#pullrequestreview-2944117528 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157728622 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157728091 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157718050 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157730230 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157730745 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157714682 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157722605 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157722822 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157714269 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157714007 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157716281 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157732726 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157735148 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157734090 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157735700 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157726326 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157726799 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157722231 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157727769 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157719923 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157720058 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157720342 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157737328 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157736712 PR Review Comment: https://git.openjdk.org/jfx/pull/1836#discussion_r2157721837