-
Notifications
You must be signed in to change notification settings - Fork 473
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8313424: JavaFX controls in the title bar #1605
base: master
Are you sure you want to change the base?
Conversation
👋 Welcome back mstrauss! A progress list of the required criteria for merging this PR into |
❗ This change is not yet ready to be integrated. |
Webrevs
|
/reviewers 2 reviewers |
@mstr2 has indicated that a compatibility and specification (CSR) request is needed for this pull request. @mstr2 please create a CSR request for issue JDK-8313424 with the correct fix version. This pull request cannot be integrated until the CSR request is approved. |
Hey, I'm glad to see this PR, but do you have any ideas for continuing to provide |
Very nice. I'll test on Linux and report back. |
The only difference between the two would be whether the default window buttons are provided. I don't see how a window without default window buttons would be more useful. Even heavily stylized apps like Spotify use window buttons that feel at home on the OS, that doesn't take away from a consistent look and feel. |
A few points observed on Linux:
Added later: Nice cleanup on |
I suggest we convert this PR to Draft and first discuss this in the mailing list. There are so many issues with the proposal that need to be ironed first: CSS support, height limitation (what happens when the app or CSS places too large of the component?), user-defined color/accents/transparency on Windows, to name just a few. This change also may add a significant maintenance burden to the platform, for what I feel is a very small payout. What do you think? |
This has already been discussed at various points in time, and was always received positively. The previous implementation is one of the most-upvoted feature proposals since OpenJFX moved to GitHub.
What about these things? I don't understand the question, but let me try to give some answers nontheless:
Popular demand says otherwise. |
Popular demand is good, but I would like to hear from the tech leads and the maintainers. |
To clarify about height: do all the platforms support arbitrary height? What if size set by the app/CSS exceeds the height supported by the platform? About platform preferences: will it support all the attributes of the window decorations provided by the platform? |
@tsayao Thanks for the comments. I'll have a look at the bugs that you found.
I know that dragging on interactive controls is a thing on Linux, but I don't think that we should be doing that. JavaFX applications are multi-platform apps, which means that their behavior should be consistent across platforms. Stealing mouse interactions on interactive controls is not a thing on Windows and macOS, and this has the potential to cause problems for application developers. If you want, you can declare any node in the header bar to be draggable on all platforms with
I'll have to look into that, but in general an
While that sounds useful at first, I don't think it carries its own weight. Many platforms use different styling for windows that are focused vs. windows that are not. This not only includes the header bar, but many other parts of the user interface as well. I don't think that we should be adding what would essentially be ad-hoc pseudo-classes only to HeaderBar. In addition to that, it is extremely easy for an application to do this by adding a listener to We should definitely not do pseudo-classes for light vs. dark mode. The correct way to solve this problem is with media queries (prefers-color-scheme). |
Mailing list message from quizynox at gmail.com on openjfx-dev: Hello, Thank you so much for your effort! I'm really glad this hasn't been Every modern platform supports this feature: Electron, Tauri, Wails, Qt, Unfortunately, the current UNDECORATED stage implementation lacks two That's why the implementation should be handled on the native side, which It's indeed a complex feature. For that reason, I believe the ??, 22 ???. 2024??. ? 03:24, Michael Strau? <mstrauss at openjdk.org>: -------------- next part -------------- |
Continuing on window attributes. I would like to know what is and is not supported by platform, by feature. For example: Windows
Did I miss anything? |
For the HeaderBar, I would like to see the explanation of different layout options, including the cases when all the information does not fit the window width. Which parts are contracted? How is overflow handled? |
May be I am late to the party, but I would suggest to discuss the JEP first. I would like to see the summary by platform by feature, I would like to see details of the layout, and the description if and how the proposed design responds to user preferences changes dynamically. I would also like to see alternatives. Perhaps the app developers has all the tools already (for example, creating an overlay transparent scene on top of the platform title bar?), or maybe this functionality should be rather implemented in a library. Lastly, there is a concern of adding a huge maintenance burden on the platform. Next time the major OS vendor changes the L&F or adds something to the window decorations, we are on the hook for supporting that. I am not even qualified to access the impact of this feature in the Linux world. There are so many frameworks and opinions - how do you propose to handle that? Is it going to be supported on Wayland? |
Gtk does work on Mac and Windows, maybe we can see how it handles it's HeaderBar, for reference. |
Another aspect is whether this should be a conditional feature. |
I'll eagerly invite you to dissect this PR for its merits, its pros and cons. However, your questions lead me to conclude that you haven't really looked at what I'm proposing. Half of your questions are answered just by looking at the documentation for Let me try to explain
Since there is no non-client title bar, all questions regarding the appearance or accessibility of the |
There is, however, one problem in RTL mode on Win11: Can you check please? edit: even when the hover background is active, clicking on the button does not close the window, and double click maximizes the window. Here is the recording: video1943689320.mp4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first batch of comments up until and including HeaderBar.
to be continued...
buildSrc/win.gradle
Outdated
"/DELAYLOAD:user32.dll", "/DELAYLOAD:urlmon.dll", "/DELAYLOAD:winmm.dll", "/DELAYLOAD:shell32.dll", | ||
"/DELAYLOAD:Uiautomationcore.dll", "/DELAYLOAD:dwmapi.dll"]).flatten() | ||
"/DELAYLOAD:Uiautomationcore.dll", "/DELAYLOAD:dwmapi.dll", "/DELAYLOAD:uxtheme.dll"]).flatten() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor suggestion: placing each entry on separate line might simplify maintenance and reduce merge conflicts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried that, but this will add another 14 lines to the script. I'm inclined to not change it at this point.
modules/javafx.graphics/src/main/java/com/sun/glass/ui/WindowControlsOverlay.java
Show resolved
Hide resolved
modules/javafx.graphics/src/main/java/com/sun/glass/ui/WindowControlsOverlay.java
Show resolved
Hide resolved
modules/javafx.graphics/src/main/java/com/sun/glass/ui/win/WinWindow.java
Show resolved
Hide resolved
modules/javafx.graphics/src/main/java/com/sun/javafx/tk/quantum/ViewScene.java
Show resolved
Hide resolved
modules/javafx.graphics/src/main/java/javafx/application/ConditionalFeature.java
Show resolved
Hide resolved
* All children will be resized to their preferred widths and extend the height of the {@code HeaderBar}. | ||
* {@code HeaderBar} honors the minimum, preferred, and maximum sizes of its children. If the child's | ||
* resizable range prevents it from be resized to fit within its position, it will be vertically centered | ||
* relative to the available space; this alignment can be customized with a layout constraint. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if the components are too large to fit, will clipping occur? should this behavior be mentioned?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The components can't be too large to fit:
{@code HeaderBar} honors the minimum, preferred, and maximum sizes of its children.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to know what happens when the layout is over-constrained. For example, consider the layout to have the leading, the center, and the trailing nodes set, and the leading one has minWidth set to 10_000. What happens?
Will the center and the trailing nodes be shown or clipped? will the layout attempt to squeeze all three to fit the available space?
Can I get this answer from the javadoc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added another sentence to the javadocs of HeaderBar
:
* All children will be resized to their preferred widths and extend the height of the {@code HeaderBar}.
* {@code HeaderBar} honors the minimum, preferred, and maximum sizes of its children. As a consequence,
* its computed minimum size is sufficient to accommodate all of its children.
Does that help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is probably ok - I am curious what @kevinrushforth might think.
it might be either obvious that the window will cut off the HB if it is wider than the window width, or it should be explicitly mentioned (there is probably enough text to go through to kind of understand the behavior in the case of over-constrained HB, or the dev can just try it).
modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderBar.java
Outdated
Show resolved
Hide resolved
Thanks for discovering this, there was a problem with mirrored coordinates in RTL windows. Should be fixed now. |
Yes, the overlay is resizable and will always stretch the entire window. As you point out, there's no practical significance, as overlays are not part of the scene graph and applications will never be able to interact with them. |
The main problem with this approach is that it presupposes that the drawing is only done in GTK callbacks. But that's not how JavaFX interacts with GTK, so I think it will probably not work. I haven't found a way to simultaneously use the current JavaFX rendering approach and mix in GTK widgets on the same surface. |
Yeah, didn't work. In theory it should work with Wayland and a subsurface, like libdecor does. X11 has the concept of multiple stacked Windows, in theory it's possible, I just don't know how to sync it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
second batch of comments
modules/javafx.graphics/src/main/java/javafx/application/ConditionalFeature.java
Show resolved
Hide resolved
modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderBar.java
Outdated
Show resolved
Hide resolved
* All children will be resized to their preferred widths and extend the height of the {@code HeaderBar}. | ||
* {@code HeaderBar} honors the minimum, preferred, and maximum sizes of its children. If the child's | ||
* resizable range prevents it from be resized to fit within its position, it will be vertically centered | ||
* relative to the available space; this alignment can be customized with a layout constraint. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to know what happens when the layout is over-constrained. For example, consider the layout to have the leading, the center, and the trailing nodes set, and the leading one has minWidth set to 10_000. What happens?
Will the center and the trailing nodes be shown or clipped? will the layout attempt to squeeze all three to fit the available space?
Can I get this answer from the javadoc?
modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderBar.java
Show resolved
Hide resolved
modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderBar.java
Show resolved
Hide resolved
modules/javafx.graphics/src/main/native-glass/mac/GlassViewDelegate.m
Outdated
Show resolved
Hide resolved
modules/javafx.graphics/src/main/resources/com/sun/glass/ui/gtk/WindowDecorationGnome.css
Show resolved
Hide resolved
} | ||
|
||
.close-button > .glyph { | ||
-fx-shape: "m 8.1464844,8.1464844 a 0.5,0.5 0 0 0 0,0.7070312 L 11.292969,12 8.1464844,15.146484 a 0.5,0.5 0 0 0 0,0.707032 0.5,0.5 0 0 0 0.7070312,0 L 12,12.707031 l 3.146484,3.146485 a 0.5,0.5 0 0 0 0.707032,0 0.5,0.5 0 0 0 0,-0.707032 L 12.707031,12 15.853516,8.8535156 a 0.5,0.5 0 0 0 0,-0.7070312 0.5,0.5 0 0 0 -0.707032,0 L 12,11.292969 8.8535156,8.1464844 a 0.5,0.5 0 0 0 -0.7070312,0 z"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: we could probably minimize the path by rounding to 2 or 3 decimal points
(same comment for all .css changes)
} | ||
|
||
.maximize-button.restore > .glyph { | ||
-fx-shape: "m 7.6491699,2.5192871 q 0,-0.3444824 -0.1369629,-0.6495361 Q 7.3752441,1.5646973 7.1407471,1.338501 6.90625,1.1123047 6.5970459,0.98156738 6.2878418,0.85083008 5.9475098,0.85083008 H 1.7722168 Q 1.838623,0.65991211 1.9589844,0.50219727 2.0793457,0.34448242 2.2370605,0.23242188 2.3947754,0.12036133 2.5836182,0.06018066 2.7724609,0 2.9758301,0 H 5.9475098 Q 6.4746094,0 6.9394531,0.20129395 7.4042969,0.40258789 7.7508545,0.74707031 8.0974121,1.0915527 8.2987061,1.5563965 8.5,2.0212402 8.5,2.5483398 V 5.5241699 Q 8.5,5.7275391 8.4398193,5.9163818 8.3796387,6.1052246 8.2675781,6.2629395 8.1555176,6.4206543 7.9978027,6.5410156 7.8400879,6.661377 7.6491699,6.7277832 Z M 1.253418,8.5 Q 1.0043945,8.5 0.77612305,8.3983154 0.54785156,8.2966309 0.37561035,8.1243896 0.20336914,7.9521484 0.10168457,7.723877 0,7.4956055 0,7.246582 V 2.9550781 Q 0,2.7019043 0.10168457,2.475708 0.20336914,2.2495117 0.37561035,2.0772705 0.54785156,1.9050293 0.77404785,1.8033447 1.0002441,1.7016602 1.253418,1.7016602 h 4.2915039 q 0.2531738,0 0.4814453,0.1016845 0.2282715,0.1016846 0.3984375,0.2718506 0.170166,0.170166 0.2718506,0.3984375 0.1016845,0.2282715 0.1016845,0.4814453 V 7.246582 q 0,0.2531739 -0.1016845,0.4793701 Q 6.5949707,7.9521484 6.4227295,8.1243896 6.2504883,8.2966309 6.024292,8.3983154 5.7980957,8.5 5.5449219,8.5 Z M 5.5241699,7.6491699 q 0.087158,0 0.1639405,-0.033203 0.076782,-0.033203 0.1369628,-0.091309 0.060181,-0.058105 0.093384,-0.1348877 0.033203,-0.076782 0.033203,-0.1639404 v -4.25 q 0,-0.087158 -0.033203,-0.1660156 Q 5.8852539,2.730957 5.8271484,2.6728516 5.769043,2.6147461 5.6901855,2.581543 5.6113281,2.5483398 5.5241699,2.5483398 h -4.25 q -0.087158,0 -0.1639404,0.033203 -0.076782,0.033203 -0.1348877,0.093384 -0.0581055,0.060181 -0.0913086,0.1369628 -0.0332031,0.076782 -0.0332031,0.1639405 v 4.25 q 0,0.087158 0.0332031,0.1639404 0.0332031,0.076782 0.0913086,0.1348877 0.0581055,0.058105 0.1348877,0.091309 0.076782,0.033203 0.1639404,0.033203 z"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... especially here
modules/javafx.graphics/src/test/java/test/javafx/scene/layout/HeaderBarTest.java
Show resolved
Hide resolved
please link your JEP from this PR |
I like the idea of having different subsurfaces for JavaFX client-side rendering and window decorations. We'd need a working Wayland backend, though... |
@@ -275,30 +234,25 @@ void alignmentOfCenterChild_resizable_withNonEmptyLeadingAndTrailingChild(String | |||
"BOTTOM_CENTER, 450, 40, 100, 50", | |||
"BOTTOM_RIGHT, 740, 40, 100, 50" | |||
}) | |||
void alignmentOfCenterChild_notResizable_withNonEmptyLeadingAndTrailingChild(String arg) { | |||
String[] args = arg.split(","); | |||
void alignmentOfCenterChild_notResizable_withNonEmptyLeadingAndTrailingChild( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor suggestion:
long test names do not help much (and actually may cause problems, see https://bugs.openjdk.org/browse/JDK-8334497)
also rather inconvenient to see in the logs, or IDEs. You can use comments for human-readability and short(er) method names.
@andy-goryachev-oracle Can you mark conversations resolved if you think the issue has been discussed appropriately? This would help to organize all of the remaining points. |
we are hitting the a github design problem here - as you correctly expect, the originator should, in theory, be able to mark conversation as resolved, but the only person who could is the PR submitter. I started to use thumbsUp emoji to mark resolved/accepted answers, and I can go through and do the remaining ones, or mark the points that have not been answered yet (those exist). Any other suggestions? |
This is, indeed, a limitation of GitHub.
I can't think of a better approach. |
*/ | ||
public final class WindowControlsOverlay extends Region { | ||
|
||
private static final CssMetaData<WindowControlsOverlay, HorizontalDirection> BUTTON_PLACEMENT_METADATA = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, check out StyleablePropertyFactory
. It can be used if one doesn't do lazy initialization, or if one doesn't need e.g. IntegerProperties
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kudos for tackling this and doing such a thorough job. I'll try to look over the Windows code in the next couple of weeks.
@@ -1143,6 +1143,13 @@ - (BOOL)suppressMouseEnterExitOnMouseDown | |||
return YES; | |||
} | |||
|
|||
- (void)performWindowDrag | |||
{ | |||
if (lastEvent != nil) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is correct code but it would be more bullet-proof if you used NSApp.currentEvent
rather than lastEvent
. I'm fine either way.
[window->nsWindow setTitleVisibility:NSWindowTitleHidden]; | ||
[window->nsWindow setTitlebarAppearsTransparent:YES]; | ||
[window->nsWindow setToolbar:[NSToolbar new]]; | ||
[window->nsWindow setToolbarStyle:NSWindowToolbarStyleUnifiedCompact]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The presence of an empty toolbar is confusing fullscreen mode. My attempt at a fix was to add a few lines in GlassWindow+Overrides.m. In windowWillEnterFullScreen
I added:
if (nsWindow.toolbar != nil) {
nsWindow.toolbar.visible = NO;
}
I made the toolbar visible again in windowDidExitFullScreen
. I tried doing this in windowWillExitFullScreen
but it didn't work.
These delegate methods are all you need to tweak. There's still a bunch of code strewn about related to non-native fullscreen handling but it's all unused cruft.
View.EventHandler eventHandler = view != null ? view.getEventHandler() : null; | ||
if (eventHandler != null && eventHandler.pickDragAreaNode(wx, wy) != null) { | ||
if (clickCount == 2) { | ||
maximize(!isMaximized()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The title bar double-click behavior is user-configurable. Unfortunately the only way to get this right is to query for an undocumented but widely-known preference.
NSString* action = [NSUserDefaults.standardUserDefaults stringForKey: @"AppleActionOnDoubleClick"];
if ([action isEqualToString: @"Minimize"]) {
[window performMiniaturize: nil];
}
else if ([action isEqualToString: @"Maximize"]) {
[window performZoom: nil];
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion!
GLASS_ASSERT_MAIN_JAVA_THREAD(env); | ||
GLASS_POOL_ENTER; | ||
{ | ||
NSString* preferredLanguage = [[NSLocale preferredLanguages] objectAtIndex:0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there some reason you're not using the NSWindow.windowTitlebarLayoutDirection
property?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It just doesn't seem to work. NSWindow.windowTitlebarLayoutDirection
always returns NSUserInterfaceLayoutDirectionLeftToRight
, even when my system layout direction clearly is right-to-left. I haven't been able to find out why that is.
# Conflicts: # modules/javafx.graphics/src/test/addExports
@@ -56,6 +56,7 @@ | |||
--add-opens javafx.graphics/javafx.scene.layout=ALL-UNNAMED | |||
--add-opens javafx.graphics/javafx.scene.paint=ALL-UNNAMED | |||
--add-opens javafx.graphics/javafx.stage=ALL-UNNAMED | |||
--add-opens java.desktop/javax.imageio=ALL-UNNAMED |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this change seems unrelated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WindowControlsOverlayTest.activePseudoClassCorrespondsToStageFocusedProperty()
requires opens javafx.stage
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the question is about java.desktop/javax.imageio
not javafx.graphics/javafx.stage
or am I missing something?
Implementation of
EXTENDED
stage style.Progress
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1605/head:pull/1605
$ git checkout pull/1605
Update a local copy of the PR:
$ git checkout pull/1605
$ git pull https://git.openjdk.org/jfx.git pull/1605/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1605
View PR using the GUI difftool:
$ git pr show -t 1605
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1605.diff
Using Webrev
Link to Webrev Comment