jfx icon indicating copy to clipboard operation
jfx copied to clipboard

8313424: JavaFX controls in the title bar

Open beldenfox opened this issue 1 year ago • 30 comments

This proof-of-concept PR introduces the COMBINED StageStyle which extends the JavaFX Scene to share the title bar space with the platform decorations. Currently this only works for Mac and Windows.

There’s a very simple demo app in tests/manual/stage/CombinedStage.java.

If you take an existing app and switch the stage style to COMBINED the size you set for the Stage will now include the title bar. Compared to DECORATED the title bar will be shifted downward to overlap the Scene. The application can use the read-write titleBarHeight property to set the height of the title bar area. The platform uses this value to position the window decorations and handle title bar clicks. The platform exports the read-only properties leftTitleBarInset and rightTitleBarInset to indicate how far the application should inset content in the title bar area to avoid overlapping the platform controls.

I tried to use existing platform API’s to achieve the title bar/Scene integration so the platform still draws window drop shadows and resize handles. I also wanted to make click-dragging in the title bar area transparent to JavaFX i.e. clicking in an empty area of the title bar initiates a drag without creating a JavaFX event (see the hitTest code).

A few observations:

  • In this PR the platform draws the title bar background so the user sees appropriate visuals for active and inactive windows. To set this up in JavaFX you need to turn off backgrounds for every Node that might overlap the title bar. It would probably be easier to draw the background inside JavaFX if we have access to the correct platform colors.

  • Click-to-drag in the title bar area is difficult to set up since layout controls like HBox and VBox prevent clicks from reaching lower nodes. An app can create Box subclasses which allow click-through but controls like Toolbar have skins which create boxes under the hood which will still block clicks.

  • On Windows 10 the platform buttons draw under the JavaFX content and there’s no way to control their colors or positions. It would probably be easier to remove them and use JavaFX controls.

  • On the Mac there’s a lot of value in re-using the platform “stoplight” controls. They have a fair amount of behavior associated with them that would be hard to reproduce and which varies across OS versions.

Still investigating this on Linux.


Progress

  • [ ] Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • [x] Change must not contain extraneous whitespace
  • [x] Commit message must refer to an issue

Issue

  • JDK-8313424: JavaFX controls in the title bar (Enhancement - P4)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1192/head:pull/1192
$ git checkout pull/1192

Update a local copy of the PR:
$ git checkout pull/1192
$ git pull https://git.openjdk.org/jfx.git pull/1192/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 1192

View PR using the GUI difftool:
$ git pr show -t 1192

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1192.diff

beldenfox avatar Aug 01 '23 15:08 beldenfox

:wave: Welcome back beldenfox! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

bridgekeeper[bot] avatar Aug 01 '23 15:08 bridgekeeper[bot]

This is an interesting feature. But as you also mentioned it is a bit cumbersome to setup. While testing I also figured out that the application icon on the left is missing. And if you setup your UI wrong, you don't see the minimize, maximize and close button anymore.

I also don't know yet if this can be improved so it is less error prone. One idea I had is that some kind of title bar node must be explicitly set. This node can deal with all the special cases and layout itself correctly in without removing any decoration or consume a drag event.

Maran23 avatar Aug 03 '23 15:08 Maran23

The Win10 API for customizing the title bar is so limited that a standard approach is to remove the platform title bar and build a new one from scratch, buttons and all. If you look closely at the apps Microsoft ships with Win10 you'll see they all draw the buttons a little differently. Implementing the title bar in JavaFX has other benefits like allowing the controls to be styled using CSS.

The Mac also has some quirks in the way it draws title bar backgrounds. My take-away from this exercise is that it's good to re-use the Mac stoplight buttons and beyond that we should create our own title bars inside JavaFX.

beldenfox avatar Aug 03 '23 18:08 beldenfox

Is it similar on what I did on #1022 ?

It's very possible on Linux. In fact, the entire modern gnome decoration is done this way.

There are three functions to be used:

  • gtk_window_begin_move_drag: It tells the window manager that a window drag operation has started, so it (the window manager) handles from there. You don't actually declare where the titlebar is, it can be done from anywhere - you just don't have access to move the window outside of screen bounds with regular window move operations - but with this way, the window manager is doing it, so it's secure (and it's allowed outside of the screen, otherwise it will block when the side of the window touches the end of the screen);
  • gtk_window_begin_resize_drag: It works similarly, but for handing window resize;
  • gdk_window_set_shadow_width: The window manager does not draw the shadows, you just use this function to tell it's insets and drawn it youself.

tsayao avatar Sep 03 '23 17:09 tsayao

@tsayao I'm taking a different approach. With #1022 you are taking an undecorated window and manually implementing all the decorations including the drop shadow and resize corners. None of that is necessary on Windows and Mac since those platforms have supported and much simpler ways of merging the JavaFX content with the title bar.

On Linux I've done some prototyping trying to get GTK to do as much of the work as possible (I really don't want to draw the drop shadows). I'm experimenting with adding a hidden Header Bar to the GTK window. This removes the title bar and forces GTK to take over drawing all of the window decorations. But that investigation is still rough and I haven't worked on it for a while.

beldenfox avatar Sep 03 '23 20:09 beldenfox

@beldenfox Humm, I'm interested :)

I only use Linux, but I'm guessing (by looking at your code) that on Windows and Mac you just define the top area (height) where you will put the tittlebar, but you still set the contents yourself.

If you mean this gtk headerbar - I think it'll get you into trouble because it's just a gtk control that integrates on the gtk layout system and we draw directly on the window (this is not possible on gtk4 - so we'll have to rethink this anyway).

tsayao avatar Sep 03 '23 21:09 tsayao

@beldenfox Did some experimenting:

Screencast from 03-09-2023 20:04:49.webm

tsayao avatar Sep 03 '23 22:09 tsayao

I think it should not allow the window to be resized will less height than the titlebar.

I was wrong about the shadow, it is drawn.

tsayao avatar Sep 04 '23 00:09 tsayao

I did a patch below for quick testing:

Include_Gtk_Glass_Backend.zip

tsayao avatar Sep 04 '23 00:09 tsayao

I have been dealing with this stuff since years, I've leaned JNI for that only and this is the result. A lot of time to implement the hit-tests, and I don't feel happy yet, I will improve that so with less that 10 lines of code you can set your own title bar fully functional and set your own hit spots.

image

image

image

image

image

image

xdsswar avatar Sep 04 '23 04:09 xdsswar

There's the case where a user might want to have rounded corners and shadows. How does mac and windows handle this? In the case of Linux I think we would drawn the shadows on the java side and then gdk_window_set_shadow_width() to let the window manager know it's side, so it does not use the sticky behavior on the shadow.

tsayao avatar Sep 12 '23 11:09 tsayao

There's the case where a user might want to have rounded corners and shadows. How does mac and windows handle this? In the case of Linux I think we would drawn the shadows on the java side and then gdk_window_set_shadow_width() to let the window manager know it's side, so it does not use the sticky behavior on the shadow.

I just implemented a window solution, in my case I can set the rounded corners(on w10, for w11 is by default) but not a shadow, I leave that handled by the OS. I havent tried mac os yet, but I will.

xdsswar avatar Sep 12 '23 21:09 xdsswar

I know the effect, and in Swing, it's like this (window 11 and open jdk 17): JFrame jFrame = new JFrame();jFrame.setSize(100, 100);jFrame.setUndecorated(true);jFrame.setVisible(true); I am very looking forward to the 'set undecorated (true)' feature similar to Swing. Additionally, I would like to add drag layout windows and drag border scaling windows. Because I encountered a difficult problem to solve in the program,When the mouse zooms in and out on the left and top of the window, the following code will cause flickering. If there were new features, I wouldn't need to write such complex code anymore...... CustomWindow.txt WindowMouseEventTest.txt TestWindowLaunch.txt

https://github.com/openjdk/jfx/assets/67951198/0d9f4b5a-4781-47dc-9d07-e949902dad95

If unable to play online, please download

SingleKey avatar Oct 26 '23 17:10 SingleKey

There's the case where a user might want to have rounded corners and shadows. How does mac and windows handle this?

I'm not sure if you're asking about my COMBINED code or the work that @xdsswar did. On Windows and Mac the COMBINED code still uses the drop shadows and resize handles provided by the operating system. It also picks up whatever corner style is native to the OS (rounded on Mac and Win 11, square on Win 10).

I did do some prototyping of this on Ubuntu 22 using GTK 3.0. The only way I found to remove the window manager's title bar was to add a Gtk HeaderBar to the window and then hide it. That got me a square window with drop shadows and resize handles. But painting and mouse events broke.

JavaFX draws directly to the top-level GDK window. Once a HeaderBar is added GTK expands the top-level GDK window to include the shadow area and draws the shadows manually. This means a) JavaFX and GTK are both trying to draw to the GDK window and b) the GDK mouse coordinates that JavaFX sees are off by the shadow amount.

The solution I prototyped was to ensure JavaFX is not drawing to the top-level GDK window. Instead I installed a GtkEventBox which provides its own GDK window for JavaFX to use. But I just got that working before moving on to other stuff.

beldenfox avatar Nov 03 '23 03:11 beldenfox

I discovered recently that mixing Gtk and JavaFX painting on the same platform window is a no-go, specially for Wayland. X11 is being replaced by Wayland, so I don't think we should add something that won't work in the future.

X11 embeds a platform window inside another window, so it might be possible. On Wayland this is not the case - there are Subsurfaces, but those are mainly targeted to video players.

The GtkEventBox won't work in the future either with Gtk4 or Wayland (I did a lot of experiments with those recently o jfx-sandbox).

I did attach a "demo" of this working on a previous comment using gtk_window_begin_resize_drag and gtk_window_begin_move_drag, but it does not involve using decorations - those would have to be drawn by JavaFX.

tsayao avatar Nov 03 '23 10:11 tsayao

I have to make time to install MacOS and linux and try something there. Also need to learn the libs used

xdsswar avatar Nov 04 '23 01:11 xdsswar

My code here https://github.com/xdsswar/shared-fx-jni-src

xdsswar avatar Dec 09 '23 00:12 xdsswar

My code here ...

@xdsswar We are unable to evaluate your code as long as it is in an independent GitHub project. If you would like to contribute it to JavaFX on OpenJDK, including making it available to those who are working on this potential feature, you need to sign the Oracle Contributor Agreement (OCA), as indicated in the CONTRIBUTING guidelines. Then make your code available in a personal fork of this (openjdk/jfx) repo, so that it is can be used and contributed under the terms of the OCA.

kevinrushforth avatar Dec 09 '23 15:12 kevinrushforth

@beldenfox This pull request has been inactive for more than 8 weeks and will be automatically closed if another 8 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

bridgekeeper[bot] avatar Feb 03 '24 18:02 bridgekeeper[bot]

No delete yet.

xdsswar avatar Feb 04 '24 03:02 xdsswar

I'm not sure what to do with this PR. The breakdown is this:

Mac: The easiest platform since the OS "stoplight" controls look the same in all windows. The only thing we need to do is position them correctly and ensure they behave well when we transition in and out of fullscreen mode.

Linux: Don't want to go there. To extend the Scene into the title bar area using GTK 3 we would also have to take over drawing every other element of the window including the drop shadow as well as take over all the resize handle interactions. This sounds like a maintenance nightmare.

Windows: A useful Windows 10 solution would involve re-implementing the title bar controls either in Java or with native calls. In Windows 11 we can use the AppWindowTitleBar class for an OS-supported solution but if we want developers to exercise control over the colors used to draw the buttons we'll need to expose a fair number of properties that are platform-specific.

Going forward with this PR I will remove the Win10 support and focus on Win11 (in part because I don't even have a Win10 system to test with anymore).

beldenfox avatar Feb 05 '24 18:02 beldenfox

I Understand that Mac and Windows will drawn the window controls over the window rendered content - Linux, at least Gnome/Gtk approach is different, the user would have to make their own controls (Gtk provides a Headerbar control).

This would be difficult since the user could be using other desktop environment with a different window manager or a different theme that would have different sizes.

We could have a default JavaFX Control on Linux that is part of the Scene.

tsayao avatar Feb 05 '24 18:02 tsayao

This is insane. You bring a feature but it brings a lot of work to maintain it, bugs, etc. I did some jni that help me on window 10 and 11. It works well as you see on top msgs, but I dont feel its good yet.

xdsswar avatar Feb 05 '24 23:02 xdsswar

The main issue I have is that to get the Window hwnd I need to show the stage before, and when so, some times there is a flicker due to the new winproc I need in order to draw my own window titlebar using javafx while keeping the native features such as the snap layout in w11 and the native tooltips, also the corner preferences and resize, drag.

xdsswar avatar Feb 05 '24 23:02 xdsswar

I Understand that Mac and Windows will drawn the window controls over the window rendered content

The Mac will but Windows will not. Now that I've looked into a bit more I see that Windows 11 doesn't improve matters. So we either have to avoid drawing over the platform controls OR they need to be removed and re-implemented in JavaFX.

I'm also experimenting with turning on the translucency effects provided on both Windows and Mac and those effects also rely on JavaFX controls not drawing background fills.

beldenfox avatar Feb 07 '24 00:02 beldenfox

I Understand that Mac and Windows will drawn the window controls over the window rendered content

The Mac will but Windows will not. Now that I've looked into a bit more I see that Windows 11 doesn't improve matters. So we either have to avoid drawing over the platform controls OR they need to be removed and re-implemented in JavaFX.

I'm also experimenting with turning on the translucency effects provided on both Windows and Mac and those effects also rely on JavaFX controls not drawing background fills.

Thats what I do for Windows, I draw my own javafx titlebar with control, and some sort of 2 way communication between javafx and native side to handle the native behaviour.

xdsswar avatar Feb 07 '24 03:02 xdsswar

I think I will end building my own custom javafx build at this point for my needs , or idk, build a javafx.decoration module wich will be allowed to access the private javafx api. I code for window 30% of the time and rest for cloud stuff, but I like a custom caption bar, 100% css styleable for my desktop apps.

xdsswar avatar Feb 07 '24 04:02 xdsswar

I Understand that Mac and Windows will drawn the window controls over the window rendered content

The Mac will but Windows will not. Now that I've looked into a bit more I see that Windows 11 doesn't improve matters. So we either have to avoid drawing over the platform controls OR they need to be removed and re-implemented in JavaFX.

I'm also experimenting with turning on the translucency effects provided on both Windows and Mac and those effects also rely on JavaFX controls not drawing background fills.

Maybe we can introduce some kind of header wrapper you need to use for the header. This component handles everything for you, regarding positioning so that the Windows native controls are not overlapped? I mean we should probably somewhat start with the minimum viable product here, before thinking about every cornercase one may have. I think for most of us, it is enough do draw something into the titlebar, e.g hamburger menu, nothing crazy.

Maran23 avatar Feb 07 '24 08:02 Maran23

❗ This change is not yet ready to be integrated. See the Progress checklist in the description for automated requirements.

openjdk[bot] avatar Mar 13 '24 20:03 openjdk[bot]

@beldenfox This pull request has been inactive for more than 8 weeks and will be automatically closed if another 8 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

bridgekeeper[bot] avatar May 09 '24 01:05 bridgekeeper[bot]