This PR is a new take on a highly requested feature: JavaFX controls in the 
header bar (see also #594 for an earlier iteration).

This is a feature with many possible ways to skin the cat, and it has taken 
quite a bit of effort to come up with a good user model. In contrast to the 
previous iteration, the focus has shifted from providing an entirely 
undecorated window to providing a window with a user-configurable header bar.

The customizable header bar is a new layout container: 
`javafx.scene.layout.HeaderBar`. It has three areas that accept child nodes: 
leading, center, and trailing.  `HeaderBar` also automatically adjusts for the 
placement of the default window buttons (minimize, maximize, close) on the left 
or right side of the window.

The customizable header bar is combined with a new `EXTENDED` stage style, 
which extends the client area into the header bar area. The new extended stage 
style is supported on Windows, macOS, and Linux. For platforms that don't 
support this stage style, it automatically downgrades to `DECORATED`.

This is how it looks like on each of the three operating systems:

![extendedwindow](https://github.com/user-attachments/assets/9d798af6-09f4-4337-8210-6eae91079d3a)

The window buttons (minimize, maximize, close) are provided by JavaFX, not by 
the application developer. This makes it easier to get basic window 
functionality without recreating the entirety of the window controls for all 
platforms.

## Usage
This is a minimal example that uses a custom header bar with a `TextField` in 
the center area. `HeaderBar` is usually placed in the top area of a 
`BorderPane` root container:

public class MyApp extends Application {
    @Override
    public void start(Stage stage) {
        var headerBar = new HeaderBar();
        headerBar.setCenter(new TextField());

        var root = new BorderPane();
        root.setTop(headerBar);

        stage.setScene(new Scene(root));
        stage.initStyle(StageStyle.EXTENDED);
        stage.show();
    }
}

To learn more about the details of the API, refer to the documentation of 
`StageStyle.EXTENDED` and `HeaderBar`.

## Platform integration
The implementation varies per platform, and ranges from pretty easy to quite 
involved:
1. **macOS**: The window buttons are provided by macOS, we just leave an empty 
area where the window buttons will appear. The client area is extended to cover 
the entire window by setting the `NSWindowStyleMaskFullSizeContentView` flag. A 
click-and-drag operation is initiated with `performWindowDragWithEvent`.

For both Windows and Linux, there is no practical way to draw custom content 
into the system-provided title bar, and it is also not an option to overlay the 
system-provided window buttons on top of a custom window. Both implementations 
therefore hide the system title bar, and draw a JavaFX recreation of the system 
window buttons into an overlay layer on top of the window. Since there is no 
title bar, the entire window is available for JavaFX.

2. **Windows**: We get a "barebones" window by handling `WM_NCCALCSIZE` to 
extend the client area, and `WM_NCHITTEST` to get click-and-drag and snap 
layouts. The system-provided resize border around the window, shadows under the 
window, and window animations are retained (this differentiates it from an 
`UNDECORATED` window).
3. **Linux**: Since GTK really doesn't want to share rendering with JavaFX, we 
can't use `GtkHeaderBar` to get the default window buttons. In contrast to 
Windows, which has only one look-and-feel, Linux has many. We ship two versions 
of window buttons: one that looks Gnome-like, and one that looks KDE-like. 
JavaFX then chooses the version that fits best.
Making matters more complicated, an undecorated GTK window has no 
system-provided resize border. We therefore need to introduce a virtual resize 
border around the inside of the window, and handle click-and-drag and resizing 
with `gtk_window_begin_move_drag()` and `gtk_window_begin_resize_drag()`, 
respectively.

## Final thoughts
This feature is quite complex, and it introduces APIs that are hard to change 
after introduction (like the `HeaderBar` layout container). We should consider 
making this a [preview feature](https://github.com/openjdk/jfx/pull/1359).

-------------

Commit messages:
 - WIP

Changes: https://git.openjdk.org/jfx/pull/1605/files
  Webrev: https://webrevs.openjdk.org/?repo=jfx&pr=1605&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8313424
  Stats: 4463 lines in 60 files changed: 3977 ins; 408 del; 78 mod
  Patch: https://git.openjdk.org/jfx/pull/1605.diff
  Fetch: git fetch https://git.openjdk.org/jfx.git pull/1605/head:pull/1605

PR: https://git.openjdk.org/jfx/pull/1605

Reply via email to