Closed rkeen-siemens closed 2 years ago
As I'm using NetBeans at work on Windows with menu integrated into title bar, I began to wonder how difficult it would be. As a quick experiment I came up with this:
FlatLaf#getSupportsWindowDecorations
to always return trueDemoFrame.java
enforce menu entries for the title bar feature to be availableFlatLafDemo.java
set JFrame.setDefaultLookAndFeelDecorated
With that I get this window on Ubuntu Linux:
Window interactions work as expected, it does not match the configure GTK Theme, but that is to be expected by client side decorations. I don't understand why getSupportsWindowDecorations
is so complicated, as the theme obviously can handle window decoration quite fine. Even more window decorations from LAF are only used if switched on by asking JFrame
to actually use the support.
The biggest headache will probably be enabling the dynamic switch between OS window decorations and LAF window decorations as the JFrame does not "know" how it was created.
@DevCharly what do you think?
Thanks, @matthiasblaesing. This looks great and seems to work well with the minor exception (in Gnome 3 on CentOS at least) that dragging to maximize/restore and snap to other windows and the edge of the screen does not seem to work. It would be nice to support the standard system interactions like these (including similar ones with other window managers). Other methods to maximize and snap (double click, max/min/restore buttons, keyboard) do seem to work, so it's still quite usable.
Tried this on Linux and it works better than expected. The windows even have shadows 😄 Window resizing had some problems and unified window title bar did not work correctly, but these issues are now fixed.
I've changed FlatLaf.getSupportsWindowDecorations()
to allow custom window decorations on Linux.
To enable them in your app use e.g.:
if( SystemInfo.isLinux ) {
// enable custom window decorations
JFrame.setDefaultLookAndFeelDecorated( true );
JDialog.setDefaultLookAndFeelDecorated( true );
}
...with the minor exception (in Gnome 3 on CentOS at least) that dragging to maximize/restore and snap to other windows and the edge of the screen does not seem to work.
That's the downside of enabling custom window decorations.
It would be nice to support the standard system interactions like these (including similar ones with other window managers).
On Windows 10/11, there was the same problem and the only way to solve it was to implement some C++ code that interacts directly with Windows API, which was complex and time consuming.
Similar would be necessary for Linux using X11 API. Currently, I don't have the time to do this.
Also there is OpenJDK Project Wakefield, which will support Wayland display server in the future. So it would be a waste of time to implement something now for X11, and later throw it away and implement same for Wayland...
@DevCharly, thanks for the quick update. When I entered this issue I was expecting an explanation of why this would be too difficult to implement, but I'm pleasantly surprised.
Siemens would like to see the drag and snap behavior implemented using the X11 API and would be willing to pay for its development (subject to timing and cost). @DevCharly (or other interested parties), do you have an estimate on when this could be released and what would be a reasonable amount to pay for the development and testing? If there's a better forum for this type of request, I'd be happy to repost this request there.
If someone want to have a look at this. This is what I tried (feel free to use if it leads to improvements in FlatLaf):
XUngrabPointer
like this: interface X11Ext extends X11 {
X11Ext INSTANCE = Native.load("X11", X11Ext.class);
int XUngrabPointer(Display display, NativeLong time);
}
private static void move_resize(int x, int y) throws HeadlessException {
System.out.printf("%d x %d%n", x, y);
Display display = X11Ext.INSTANCE.XOpenDisplay(null);
Window w = new X11Ext.Window(windowsId);
X11Ext.XEvent event = new X11Ext.XEvent();
event.type = X11Ext.ClientMessage;
event.setType(XClientMessageEvent.class);
event.xclient.type = X11Ext.ClientMessage;
event.xclient.serial = new NativeLong(0);
event.xclient.send_event = 1;
event.xclient.message_type = X11Ext.INSTANCE.XInternAtom(display, "_NET_WM_MOVERESIZE", false);
event.xclient.display = display;
event.xclient.window = w;
event.xclient.format = 32;
event.xclient.data.setType(NativeLong[].class);
event.xclient.data.l[0] = new NativeLong(x);
event.xclient.data.l[1] = new NativeLong(y);
event.xclient.data.l[2] = new NativeLong(10);
event.xclient.data.l[3] = new NativeLong(0);
event.xclient.data.l[4] = new NativeLong(0);
System.out.println(X11Ext.INSTANCE.XUngrabPointer(display, new NativeLong(0)));
System.out.println(X11Ext.INSTANCE.XUngrabKeyboard(display, new NativeLong(0)));
System.out.println(X11Ext.INSTANCE.XSendEvent(display, X11Ext.INSTANCE.XDefaultRootWindow(display), 0, new NativeLong(SubstructureNotifyMask|X11.SubstructureRedirectMask), event));
System.out.println(X11Ext.INSTANCE.XFlush(display));
System.out.println(X11Ext.INSTANCE.XCloseDisplay(display));
System.out.println("Done");
}
Theoretically changing the third data element to 8 should make this a mouse move, that did not work for me though.
@rkeen-siemens thanks for the offer. I'm willing to work on it. Please contact me via Email: https://www.formdev.com/company/
Is the "drag and snap behavior" the only functionality that you to want? I've compared native windows with FlatLaf decorated windows and there are some more differences:
Shift
key while resizing to snap the window to the edges of the screen and other windows does not work@matthiasblaesing many thanks for the code. I tried it.
Works for me even using 8
(using mouse screen coordinates for x and y).
Found out that _NET_WM_MOVERESIZE
message can be also used for resizing to get snapping when holding down Shift
key.
https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm45381394031168
BTW is this API available on all Linux distros (that support X11)?
Any idea how to show that window popup menu via API?
Since the above code uses JNA and depending FlatLaf library on JNA is not an option (like to keep it dependency free), I want to translate the code into C/C++ and build a small .so
library that is shipped inside of flatlaf.jar
(similar to Windows DLLs inside of flatlaf.jar
).
@DevCharly to my understanding implementors should check the atom list returned by querying the property _NET_SUPPORTED of the root window.
I'm not sure if going though direct X11 calls is the preferred way or if it would be better to use gdk. If I remember correctly, both OpenJFX and Swing/AWT are both build on top of gtk and gtk has support for wayland and X11. The drawback is, that you'd have to check if the function is called identically between the supported gtk versions. A runtime lookup of the function symbol might work correctly, if the function call names differ.
For the popup - sorry, no idea.
As reference this is the GDK function I referenced: https://docs.gtk.org/gdk3/method.Window.begin_move_drag.html And yes, gtk4 changes this: https://docs.gtk.org/gdk4/method.Toplevel.begin_move.html
@DevCharly, thanks for the offer. I'm assuming we will want the other behaviors as well. I'll contact you via email in the next couple days with more details.
I tested it on Manjaro KDE with X11 and it looks okay:
The problems listed by @DevCharly are all present on KDE Plasma, and the additional one is that window shadow disappeared.
@DevCharly, I sent you an email last week with details on my earlier request for updates. Perhaps you have been busy, but I'm wondering if the message was lost in transit. I'll post my request here as well in case you didn't receive it or others are interested in the work.
Siemens would like to see the drag and snap behavior implemented when window decorations are enabled in Linux.
The following are already available and should be maintained:
The following should be available as they are currently for native windows (i.e. with window decorations disabled and without the need to hold down a modifier key such as Super before performing the action).
This assumes support is not OS or desktop environment specific (i.e. it should work in GNOME 3 on CentOS and KDE Plasma on Ubuntu). If there are any known issues in the existing implementation or new scope that are platform specific, please provide details of the limitations.
We'd like to have this available in a publicly released version of FlatLaf no later than 30 June 2022. We are happy to test with pre-release versions or build from a branch if needed.
Ideally, this would be available in the version bundled in NetBeans 14 at the end of May. If that is not possible, we have our own fork of the NetBeans platform so as long as you can provide instructions for us to update it there that would be acceptable as well.
These custom window decorations on Linux are awesome! Thank you!
But I noticed I'm not getting any window shadows when running on Mint 20.3. Not sure what's different than the other distros where the window shadows work.
Finally, a PR is now available to improve FlatLaf window decorations on Linux: #579 😄
The window decorations (including the embedded menu bar and title bar options) would be great to have on linux as well as Windows.