On Thu, 19 Jun 2025 08:47:08 GMT, Johan Vos <[email protected]> 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