8371370: [macOS] Crash after main stage with modal dialog is moved to full screen#2098
8371370: [macOS] Crash after main stage with modal dialog is moved to full screen#2098jperedadnr wants to merge 3 commits into
Conversation
… from entering full screen mode, manage style mask, window behavior and standard window buttons state,
|
👋 Welcome back jpereda! A progress list of the required criteria for merging this PR into |
|
❗ This change is not yet ready to be integrated. |
There was a problem hiding this comment.
Pull request overview
Fixes macOS Glass window state handling around fullscreen transitions, particularly when a modal dialog disables the main stage, to avoid crashes and prevent non-resizable windows from entering fullscreen.
Changes:
- Defers fullscreen collection behavior enabling to the point when a window becomes resizable, preventing non-resizable ownerless windows from entering fullscreen.
- Tracks/restores miniaturizable/resizable style-mask bits more carefully during enable/disable transitions.
- Reapplies style-mask, collection behavior, and standard button enabled states on fullscreen exit.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| modules/javafx.graphics/src/main/native-glass/mac/GlassWindow.m | Adjusts enabled/disabled handling to preserve/restore miniaturizable/resizable style bits and standard button enabled states. |
| modules/javafx.graphics/src/main/native-glass/mac/GlassWindow+Overrides.m | Restores style mask, collection behavior, and button states when exiting fullscreen; adds a failure-to-exit handler. |
| modules/javafx.graphics/src/main/native-glass/mac/GlassWindow+Java.m | Updates resizable toggling to manage fullscreen eligibility via collection behavior and to defer style changes until fullscreen exit completes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Webrevs
|
|
/reviewers 2 |
|
@andy-goryachev-oracle |
|
This will need a lot of testing in various modes to ensure no regressions or unintended changes in behavior. I did a fair bit of testing with an preliminary patch last year, but will need to refamiliarize myself with it. @beldenfox Would you have time to take a look at this as well? |
|
As a sanity check, I submitted a headful test run to our CI and all existing tests passed. |
|
I will take a look at this. At some point I will also run the tests in PR #1789 which cover more ground than the existing system tests. |
|
This PR is causing some of the tests in PR #1789 to fail. I think the tests are timing out while trying to put UNDECORATED stages into fullscreen mode. This is another murky area in the spec. The description of setResizable() states that turning the flag off doesn't prevent API calls from changing the window size. Historically it seems we've interpreted that to mean that non-resizable stages can be maximized and enter fullscreen mode. There's code on the macOS side to handle the fullscreen case (setResizableForFullscreen:). That assumption has made its way into the tests. The tests in #1789 are FullScreenTest and StageAttributesTest (testFullScreenStage and testFullScreenStageBeforeShow). The timeouts seem to be preventing proper cleanup so I'm also seeing some bogus failures after the first one. |
| if (!self->owner && !isPopupOrUtility) { | ||
| NSWindowCollectionBehavior behavior = [self->nsWindow collectionBehavior]; | ||
| behavior |= NSWindowCollectionBehaviorFullScreenPrimary; | ||
| [self->nsWindow setCollectionBehavior: behavior]; |
There was a problem hiding this comment.
This is minor but I've never understood the coding conventions in the Mac glass code. I have no idea why there's all the references to self and why no one uses property notation. In any other codebase this line would just be
nsWindow.collectionBehavior = behavior;
I wouldn't change anything in this PR since it does follow the prevailing conventions but I urge anyone writing new code to at least drop all the self references.
|
About Undecorated windows: Currently (before this PR), you can indeed have: and even: and on macOS the window will enter full screen mode, as a regular decorated window, and be resized, even if it is marked as non resizable. With this PR, that is no longer the case. The JavaFX definition of Undecorated does mention it supports fullscreen mode, and for non-resizable windows, it mentions that it can be resized programmatically, but it doesn't specify if it can enter fullscreen mode. However:
With this PR, I tried to follow those macOS conventions, (so now neither undecorated nor non-resizable windows can't enter full screen on macOS), but I do realize that it implies some inconsistencies for the Undecorated stages. The question I have: do we want to follow this path (keep macOS conventions) and deal with the required changes for undecorated windows? Or do we keep it as it was, allowing undecorated windows entering full screen mode? |
We need to keep current behavior for this. Preventing undecorated windows from programmatically entering full screen would be a regression in behavior. |
|
Right, that makes sense. I've updated the PR, restoring the behavior for undecorated screens. I've also checked the tests under #1789 and all pass now. |
|
@jperedadnr This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply issue a |
|
/keepalive |
|
@jperedadnr The pull request is being re-evaluated and the inactivity timeout has been reset. |
|
I've updated the original bug report with some additional information. There are two separate systems trying to save and restore the NSWindowStyleMaskResizable flag, one for when the window is disabled and re-enabled and another for entering and existing fullscreen. This is fragile since it only works if things happen in a very specific order. I don't think this bug can be truly fixed until these two save/restore mechanisms are either unified into one mechanism or removed. I vote for removing them and added some notes to the bug report on how I think that would work. In this bug the OS is providing a round-about way of entering fullscreen mode while the window is disabled. To prevent that this PR is dynamically adding and removing the fullscreen collection behavior. That's a good idea but needs to be followed up with some additional code to bullet-proof any calls to toggleFullScreen. If the collection behavior isn't set when we call toggleFullScreen Glass will enter the fullscreen exiting loop and never leave it. We need to ensure that never happens. In the past a client has always been able to call Stage.setFullScreen(true) to put a stage into fullscreen mode regardless of StageStyle and even if it has been made non-resizable using Stage.setResizable. To keep that behavior we need to ensure that Stage.setFullScreen always adds the fullscreen collection behavior to the NSWindow the same way it always adds the NSWindowStyleMaskResizable. Personally I think we should do a localized fix to avoid the crash; when restoring the styleMask avoid altering the NSWindowStyleMaskFullScreen bit. Then we can do a separate PR to remove the two save/restore systems that are fighting over the Resizable style mask bit. And then another PR to add and remove the full screen collection behavior dynamically. |
This PR adds a fix to prevent a crash on macOS after exiting full screen mode when a modal dialog is showing (https://bugs.openjdk.org/browse/JDK-8371370).
At the same time, it prevents non-resizable windows from entering full screen mode (https://bugs.openjdk.org/browse/JDK-8379315), given that the changes for both issues were interrelated.
While no tests have been added, manual tests have been run, checking that the style mask, the window behavior and the standard window buttons state, remained consistent in different scenarios.
Also, according to https://developer.apple.com/documentation/appkit/nswindow/showsresizeindicator, the
showsResizeIndicatorproperty has been removed.Progress
Issue
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/2098/head:pull/2098$ git checkout pull/2098Update a local copy of the PR:
$ git checkout pull/2098$ git pull https://git.openjdk.org/jfx.git pull/2098/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 2098View PR using the GUI difftool:
$ git pr show -t 2098Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/2098.diff
Using Webrev
Link to Webrev Comment