Closed bric3 closed 2 years ago
I'm totally experimenting with it. So I noticed the CustomTitlePane
in darklaf-platform-base
, although I'm not quite sure it works as expected.
var frame = new JFrame("FirePlace");
final JRootPane rootPane = frame.getRootPane();
if (SystemInfo.isMacOS) {
UIManager.put("MacOS.TitlePane.background", Color.PINK);
UIManager.put("MacOS.TitlePane.foreground", Color.GRAY);
UIManager.put("MacOS.TitlePane.inactiveBackground", Color.PINK.darker());
UIManager.put("MacOS.TitlePane.inactiveForeground", Color.GRAY.darker());
UIManager.put("MacOS.TitlePane.borderColor", Color.PINK);
CustomTitlePane titlePane = DecorationsHandler.getSharedInstance().createTitlePane(rootPane, JRootPane.FRAME, frame);
var layeredPane = rootPane.getLayeredPane();
layeredPane.add(titlePane, JLayeredPane.FRAME_CONTENT_LAYER);
titlePane.setVisible(true);
}
Adding doesn't seem to change a thing (I thought that the custom title bar might have been hidden by the system one.)
// allows to place swing components on the whole window
rootPane.putClientProperty("apple.awt.fullWindowContent", true);
// makes the title bar transparent
rootPane.putClientProperty("apple.awt.transparentTitleBar", true);
In comparison to the system theme detection mechanism it isn't quite as straight forward to get the custom decorations to work without actually using the laf itself. More specifically I don't think that it is possible at all in the current state. This is because DarkRootPaneUI
has to be the ui of the frames JRootPane
. I'll have to think about whether it is feasible to abstract it aways to the point where only setting the frames rootpane ui is enough.
I have somewhat extracted the necessary code for native decorations to work. Using the following version:
repositories {
maven {
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
}
}
dependencies {
// The double decorations isn't a typo. It has this name because the artifact is named "platform-decorations" and
// the branch "decorations" ;)
implementation("com.github.weisj:darklaf-platform-decorations-decorations:latest.integration")
}
You should be able to do the following then:
import com.github.weisj.darklaf.platform.decorations.ExternalLafDecorator;
...
// Everything here should happen on the swing UI thread:
ExternalLafDecorator.instance().install();
// Install you LaF.
I can't be sure that it will work as expected with every LaF e.g. any LaF that needs to have it's own implementation of RootPaneUI
present won't work (though most lafs should be fine). I haven't had the chance to test this on macOS yet, so it might not work fully for you.
Now if you wan't to change color of the titlebar you can do the following:
After installing the LaF set the appropriate properties in the UIManager
. They property names can be found here:
Cool il check it out. thanks a lot. Can these properties be adjusted on Leaf change?
As long as you change the properties before you call updatesUI
on the window hierarchy you should be fine.
Hi sorry for the delay, I got caught in various things.
So I have tried the ExternalLafDecorator
, but I'm unsure how to use it.
var frame = new JFrame("FirePlace");
frame.getRootPane().getUI(); // =>BasicNativeDecorationsRootPaneUI
When changing the colors myself the title bar don't get updated, after an updateUI
, I'm using FlatLaf from formdev.
switch (appearanceModeButton.getClientProperty(TO_APPEARANCE).toString()) {
case TO_DARK_LAF:
FlatDarculaLaf.setup();
Colors.setDarkMode(true);
appearanceModeButton.putClientProperty(TO_APPEARANCE, TO_LIGHT_LAF);
appearanceModeButton.setIcon(toLightMode);
break;
case TO_LIGHT_LAF:
FlatIntelliJLaf.setup();
Colors.setDarkMode(false);
appearanceModeButton.putClientProperty(TO_APPEARANCE, TO_DARK_LAF);
appearanceModeButton.setIcon(toDarkMode);
break;
}
+ UIManager.put("MacOS.TitlePane.borderColor", UIManager.get("TitlePane.borderColor"));
+ UIManager.put("MacOS.TitlePane.background", UIManager.get("TitlePane.background"));
+ UIManager.put("MacOS.TitlePane.foreground", UIManager.get("TitlePane.foreground"));
+ UIManager.put("MacOS.TitlePane.inactiveBackground", UIManager.get("TitlePane.inactiveBackground"));
+ UIManager.put("MacOS.TitlePane.inactiveForeground", UIManager.get(" TitlePane.inactiveForeground"));
FlatLaf.updateUI();
FlatAnimatedLafChange.hideSnapshotWithAnimation();
Also as a convenience I wonder if there's a default color that matches the light/dark system.
The following happens right in ExternalLafDecorator.instance().install();
Exception in thread "main" java.lang.IncompatibleClassChangeError: Class com.github.weisj.darklaf.platform.macos.MacOSDecorationsProvider does not implement the requested interface com.github.weisj.darklaf.platform.DecorationsProvider
at com.github.weisj.darklaf.platform.decorations.NativeDecorationsManager.initialize(NativeDecorationsManager.java:94)
at com.github.weisj.darklaf.platform.decorations.ExternalLafDecorator.install(ExternalLafDecorator.java:61)
at io.github.bric3.fireplace.FirePlaceMain$AppearanceControl.install(FirePlaceMain.java:257)
at io.github.bric3.fireplace.FirePlaceMain.setupLaF(FirePlaceMain.java:224)
at io.github.bric3.fireplace.FirePlaceMain.initUI(FirePlaceMain.java:73)
at io.github.bric3.fireplace.FirePlaceMain.main(FirePlaceMain.java:66)
I just had to do that.
implementation("com.github.weisj:darklaf-platform-preferences:latest.integration") {
exclude("com.github.weisj", "darklaf-platform-decorations")
}
implementation("com.github.weisj:darklaf-platform-decorations-decorations:latest.integration")
The current draft PR is here : https://github.com/bric3/fireplace/pull/17
The following works perfectly fine for me:
public class Test {
static boolean systemLaf = true;
private static void setLaf(String name, boolean updateUI) {
try {
UIManager.setLookAndFeel(name);
} catch (Exception e) {
e.printStackTrace();
}
if (systemLaf) {
UIManager.put("Windows.TitlePane.borderColor", Color.YELLOW);
UIManager.put("Windows.TitlePane.background", Color.CYAN);
UIManager.put("Windows.TitlePane.foreground", Color.RED);
UIManager.put("Windows.TitlePane.inactiveBackground", Color.BLUE);
UIManager.put("Windows.TitlePane.inactiveForeground", Color.ORANGE);
} else {
UIManager.put("Windows.TitlePane.borderColor", Color.YELLOW);
UIManager.put("Windows.TitlePane.background", Color.RED);
UIManager.put("Windows.TitlePane.foreground", Color.CYAN);
UIManager.put("Windows.TitlePane.inactiveBackground", Color.ORANGE);
UIManager.put("Windows.TitlePane.inactiveForeground", Color.BLUE);
}
if (updateUI) updateLaf();
}
static void updateLaf() {
for (final Window w : Window.getWindows()) {
updateLafRecursively(w);
}
}
private static void updateLafRecursively(final Window window) {
for (final Window childWindow : window.getOwnedWindows()) {
updateLafRecursively(childWindow);
}
SwingUtilities.updateComponentTreeUI(window);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
ExternalLafDecorator.instance().install();
setLaf(UIManager.getSystemLookAndFeelClassName(), false);
systemLaf = false;
JFrame frame = new JFrame("Test Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridBagLayout());
frame.getContentPane().setPreferredSize(new Dimension(400, 400));
JButton button = (JButton) frame.getContentPane().add(new JButton("I am a button!"));
button.addActionListener(e -> {
setLaf(systemLaf
? UIManager.getSystemLookAndFeelClassName()
: UIManager.getCrossPlatformLookAndFeelClassName(), true);
systemLaf = !systemLaf;
button.setText(systemLaf ? "Change to System Laf" : "Change to cross platform Laf");
button.getParent().doLayout();
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Let me quickly check whether it also works on macOS (with adjusted prooerty names of course).
It also works on macOS.
Also as a convenience I wonder if there's a default color that matches the light/dark system.
Currently it tries to "match" the colors of installed LaF (at least as good as possible without making assumptions about the LaF). Based on the colors one could try to guess whether the colors are supposed to be light or dark, but that isn't really reliable and the resulting colors will have to be adjusted to be compatible with the LaF in question to not look out of place. What did you have in mind specifically here?
What did you have in mind specifically here?
Oh your description is actually better that what I had in mind (I was suggesting tha default "color set" matching either the light / dark modes of the OS.
I don't have any windows installation, nor Linux but I'll also try to adapt your example on macOs. Thanks for sharing this!
I have added a more convenient way to customize the titlebar colors:
ExternalLafDecorator.instance().setColorProvider(new DecorationsColorProvider() {
@Override
public Color backgroundColor() {
return Color.CYAN;
}
@Override
public Color activeForegroundColor() {
return Color.ORANGE;
}
@Override
public Color inactiveForegroundColor() {
return Color.RED;
}
});
There are more colors you can customize, but these three should suffice for the most use cases.
Does the current state of the implementation work for you suffiently? If yes I would cut the next release.
Ah sorry I'm between two "fires" and forgot to report back.
So I'm not sure if I'm doing this right but I got a NPE, because there's no value for the key borderSecondary
.
Apr 05, 2022 11:33:37 AM com.formdev.flatlaf.util.LoggingFacadeImpl logSevere
SEVERE: FlatLaf: Failed to setup look and feel 'com.formdev.flatlaf.FlatIntelliJLaf'.
java.lang.NullPointerException
at java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011)
at java.base/java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1006)
at java.base/java.util.Properties.put(Properties.java:1301)
at com.github.weisj.darklaf.platform.decorations.ExternalLafDecorator.putOrCopy(ExternalLafDecorator.java:89)
at com.github.weisj.darklaf.platform.decorations.ExternalLafDecorator.installExtraProperties(ExternalLafDecorator.java:99)
at com.github.weisj.darklaf.platform.decorations.ExternalLafDecorator.lambda$new$0(ExternalLafDecorator.java:47)
at java.desktop/java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:343)
at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:335)
at java.desktop/javax.swing.event.SwingPropertyChangeSupport.firePropertyChange(SwingPropertyChangeSupport.java:93)
at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:268)
at java.desktop/javax.swing.UIManager.setLookAndFeel(UIManager.java:602)
at com.formdev.flatlaf.FlatLaf.setup(FlatLaf.java:117)
at com.formdev.flatlaf.FlatIntelliJLaf.setup(FlatIntelliJLaf.java:39)
at io.github.bric3.fireplace.FirePlaceMain$AppearanceControl.lambda$new$0(FirePlaceMain.java:225)
at io.github.bric3.fireplace.FirePlaceMain$AppearanceControl.lambda$new$1(FirePlaceMain.java:240)
at com.github.weisj.darklaf.platform.preferences.SystemPreferencesManager.lambda$onPreferenceChange$0(SystemPreferencesManager.java:55)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at com.github.weisj.darklaf.platform.preferences.SystemPreferencesManager.onPreferenceChange(SystemPreferencesManager.java:54)
at com.github.weisj.darklaf.platform.preferences.SystemPreferencesManager.enableReporting(SystemPreferencesManager.java:100)
at io.github.bric3.fireplace.FirePlaceMain$AppearanceControl.install(FirePlaceMain.java:262)
at io.github.bric3.fireplace.FirePlaceMain.setupLaF(FirePlaceMain.java:203)
at io.github.bric3.fireplace.FirePlaceMain.initUI(FirePlaceMain.java:74)
at io.github.bric3.fireplace.FirePlaceMain.main(FirePlaceMain.java:67)
ExternalLafDecorator.instance().install();
ExternalLafDecorator.instance().setColorProvider(new DecorationsColorProvider() {
@Override
public Color backgroundColor() {
return UIManager.getColor("TitlePane.background");
}
@Override
public Color activeForegroundColor() {
return UIManager.getColor("TitlePane.foreground");
}
@Override
public Color inactiveForegroundColor() {
return UIManager.getColor(" TitlePane.inactiveForeground");
}
});
So I think the code should protect itself against null values, returned by the color provider.
Thank you very much for your patience !
Also I'm not sure about how to change the window title color. (It is set like this new JFrame("FirePlace")
)
Shouldn't be orange with this code ?
@Override
public Color activeForegroundColor() {
return Color.ORANGE;
}
So I think the code should protect itself against null values, returned by the color provider.
I can fallback to the default colors if null
is returned. However it probably will look somewhat out of place.
Also I'm not sure about how to change the window title color. (It is set like this new JFrame("FirePlace"))
On macOS there actually isn't any way to change the color of the window title as it is painted by the OS. I have added to option to switch between light/dark title text by implementing DecorationsColorProvider::isDark
.
This looks way better, thanks. I noted two things
I have my own color theme setting, however the setting has to be inverted, I think the isDark
name could be renamed to something more speaking when reading the code isSystemWindowTitleDark
@Override
public boolean isDark() {
return !Colors.isDarkMode();
}
The Window title is not the right color when I first start the application, once the LaF changes it works as expected though. I'll investigate.
It's a nitpick, but why not propose a default implementation for this method.
On point 1 and 2
After looking at the code, I noticed this line
Actually affects this one.
So when my implementation
@Override
public boolean isDark() {
return !Colors.isDarkMode();
}
returns true
from isDark
, I actually get a dark text, and vice versa when returning false
.
Also I noticed these logs (running JDK 17), not sure it is related though.
2022-04-05 15:04:04.733 java[69308:1421889] Bad JNI lookup accessibilityHitTest
2022-04-05 15:04:04.734 java[69308:1421889] (
0 libawt_lwawt.dylib 0x0000000102ed720d -[CommonComponentAccessibility accessibilityHitTest:] + 173
1 libawt_lwawt.dylib 0x0000000102e920a0 -[AWTView accessibilityHitTest:] + 176
2 AppKit 0x00007ff81e780eca -[NSWindow(NSWindowAccessibility) accessibilityHitTest:] + 302
3 AppKit 0x00007ff81e31531b -[NSApplication(NSApplicationAccessibility) accessibilityHitTest:] + 285
4 AppKit 0x00007ff81e2e4cec CopyElementAtPosition + 136
5 HIServices 0x00007ff820f3979e _AXXMIGCopyElementAtPosition + 393
6 HIServices 0x00007ff820f5b084 _XCopyElementAtPosition + 355
7 HIServices 0x00007ff820f189b9 mshMIGPerform + 182
8 CoreFoundation 0x00007ff81b4c0294 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
9 CoreFoundation 0x00007ff81b4c0174 __CFRunLoopDoSource1 + 619
10 CoreFoundation 0x00007ff81b4be7db __CFRunLoopRun + 2415
11 CoreFoundation 0x00007ff81b4bd7ac CFRunLoopRunSpecific + 562
12 HIToolbox 0x00007ff824144ce6 RunCurrentEventLoopInMode + 292
13 HIToolbox 0x00007ff824144913 ReceiveNextEventCommon + 283
14 HIToolbox 0x00007ff8241447e5 _BlockUntilNextEventMatchingListInModeWithFilter + 70
15 AppKit 0x00007ff81dee453d _DPSNextEvent + 927
16 AppKit 0x00007ff81dee2bfa -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1394
17 libosxapp.dylib 0x00000001023234aa -[NSApplicationAWT nextEventMatchingMask:untilDate:inMode:dequeue:] + 122
18 AppKit 0x00007ff81ded52a9 -[NSApplication run] + 586
19 libosxapp.dylib 0x0000000102323275 +[NSApplicationAWT runAWTLoopWithApp:] + 165
20 libawt_lwawt.dylib 0x0000000102ef7140 +[AWTStarter starter:headless:] + 496
21 libosxapp.dylib 0x0000000102324f5f +[ThreadUtilities invokeBlockCopy:] + 15
22 Foundation 0x00007ff81c333857 __NSThreadPerformPerform + 179
23 CoreFoundation 0x00007ff81b4bfaeb __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
24 CoreFoundation 0x00007ff81b4bfa53 __CFRunLoopDoSource0 + 180
25 CoreFoundation 0x00007ff81b4bf7cd __CFRunLoopDoSources0 + 242
26 CoreFoundation 0x00007ff81b4be1e8 __CFRunLoopRun + 892
27 CoreFoundation 0x00007ff81b4bd7ac CFRunLoopRunSpecific + 562
28 libjli.dylib 0x0000000101ef0132 CreateExecutionEnvironment + 386
29 libjli.dylib 0x0000000101eebc96 JLI_Launch + 1366
30 java 0x0000000101dc3c0a main + 394
31 dyld 0x000000011196351e start + 462
)
Exception in thread "AppKit Thread" java.lang.NoSuchMethodError: accessibilityHitTest
Also I noticed these logs (running JDK 17), not sure it is related though. ...
I don't think this is related. At least I don't see anything which might cause it as the native portion of the implementation doesn't interface with accessibilityHitTest
.
- I have my own color theme setting, however the setting has to be inverted, I think the isDark name could be renamed to something more speaking when reading the code isSystemWindowTitleDark
I have changed the api to make it clearer on how to change the title color. You can now specify windowTitleColor
as either LIGHT
, DARK
or CUSTOM
, wheras CUSTOM
will force the color returned by ::activeForegroundColor
to be used and LIGHT/DARK
repsectively use the native colors (or use sane defaults based on ::activeForegroundColor
on Windows). Let me know if this API is easier to reason about.
As for point 2: The beginning of the first video is directly after application startup right? In the second video it breaks after checking "Sync appearance". I suspect there might be some bad interplay between system theme detection and the decorations. Is https://github.com/bric3/fireplace/pull/17 an up-to date version reproducing this behaviour?
On each video I restarted the app. But I agree there's something fishy, when the sync is re-enabled.
Is https://github.com/bric3/fireplace/pull/17 an up-to date version reproducing this behaviour?
Yes, however it is based on the snapshot earlier today : https://oss.sonatype.org/content/repositories/snapshots/com/github/weisj/darklaf-platform-decorations/3.0.0-SNAPSHOT/darklaf-platform-decorations-3.0.0-20220405.121934-75.jar
The API is nicer with the latest change, however the title color is still weird. Wether it syncs with the OS or from settings.
I'll push the latest commit.
Hi there,
With the very latest snapshots (3.0.0-20220406.014333-77), I tried to install/uninstall the ExternalLafDecorator
yet the title bar changes are is jumpy.
That made be realize there's a thin black border when the ExternalLafDecorator
is active, in some occasions, and toggling the to dark theme, then light theme again makes this border disappear.
Also I'm not sure about the buttons when inactive, they are not visible, or not even there. This seems to happen when os synchronization is active new SystemPreferencesManager().enableReporting(true)
And even for the out of color title, this seems related to when system reporting is active.
Also I noticed these logs (running JDK 17), not sure it is related though. ...
I don't think this is related. At least I don't see anything which might cause it as the native portion of the implementation doesn't interface with
accessibilityHitTest
.
This seem to be related to these issues (running corretto 17.0.2.8.1)
Hi there,
With the very latest snapshots (3.0.0-20220406.014333-77), I tried to install/uninstall the
ExternalLafDecorator
yet the title bar changes are is jumpy.
Could you elaborate what you mean by "jumpy".
That made be realize there's a thin black border when the
ExternalLafDecorator
is active, in some occasions, and toggling the to dark theme, then light theme again makes this border disappear.
I suppose the dark border is coupled to the color of the window title. If it is light (which is achieved by switching the window to dark mode) the border also becomes dark. If this is bothering you, you can use TitleColor.CUSTOM
to force the window to be in light theme (i.e. it has a light border).
Also I'm not sure about the buttons when inactive, they are not visible, or not even there. This seems to happen when os synchronization is active
new SystemPreferencesManager().enableReporting(true)
What do you mean by inactive? Inactive as in ExternalLafDecorator
is uninstalled or inactive as in the window isn't the active window?
And even for the out of color title, this seems related to when system reporting is active.
Does it behave correctly without system reporting enabled (except maybe the first time)?
With the very latest snapshots (3.0.0-20220406.014333-77), I tried to install/uninstall the
ExternalLafDecorator
yet the title bar changes are is jumpy.Could you elaborate what you mean by "jumpy".
Sorry I should have dropped a god example and a video.
https://user-images.githubusercontent.com/803621/162060035-9776464f-d923-4e1b-9424-d71164adc321.mov
The sync checkbox action is basically calling this method, and in this experience I tried to install custom decorations when os reporting is off and vice versa.
void toggleSync(boolean sync) {
try {
manager.enableReporting(sync);
+ if (sync) {
+ ExternalLafDecorator.instance().uninstall();
+ } else {
+ ExternalLafDecorator.instance().install();
+ }
} catch (Exception e) {
e.printStackTrace();
}
}
Note this code change is only for this experiment. All other remarks are based on code like this
Ok after having the time to dig it a bit I noticed an issue in my preference detector, it seems that in some specific circumstances my darkMode boolean got inverted, I've changed that and this fixes the three issues mentioned above (the darker border, the inactive buttons, and the window title.
Thanks for your "insistance" on this, I was able to nail the thing.
So for me everything looks good now, thank you very much !!!
Maybe one thing that might be worth documenting is that installing the platform decorations make these properties ignored, it is expected since it is no the same UI component.
final JRootPane rootPane = frame.getRootPane();
if (SystemInfo.isMacOS) {
// allows to place swing components on the whole window
rootPane.putClientProperty("apple.awt.fullWindowContent", true);
// makes the title bar transparent
rootPane.putClientProperty("apple.awt.transparentTitleBar", true);
}
In a previous experiment I used these to have some UI components in the title bar.
https://user-images.githubusercontent.com/803621/162071344-5f84128f-2f90-4b3b-bf88-ba8d4ca45d4e.mov
But here as you see the color of window title is not updated
Could you elaborate what you mean by "jumpy".
Sorry I should have dropped a god example and a video.
Screen.Recording.2022-04-06.at.21.54.40.mov The sync checkbox action is basically calling this method, and in this experience I tried to install custom decorations when os reporting is off and vice versa.
void toggleSync(boolean sync) { try { manager.enableReporting(sync); + if (sync) { + ExternalLafDecorator.instance().uninstall(); + } else { + ExternalLafDecorator.instance().install(); + } } catch (Exception e) { e.printStackTrace(); } }
This is expected behaviour when installing/uninstalling the decorations. Due to the nature that it changes the underlying window the "jumps" are somewhat inevitable.
Ok after having the time to dig it a bit I noticed an issue in my preference detector, it seems that in some specific circumstances my darkMode boolean got inverted, I've changed that and this fixes the three issues mentioned above (the darker border, the inactive buttons, and the window title. ... So for me everything looks good now, thank you very much !!!
Thats great to hear :)
Maybe one thing that might be worth documenting is that installing the platform decorations make these properties ignored, it is expected since it is no the same UI component.
I think I can reasonably replicate the behaviour of those two properties.
Maybe one thing that might be worth documenting is that installing the platform decorations make these properties ignored, it is expected since it is no the same UI component.
I think I can reasonably replicate the behaviour of those two properties.
That would be nice to have a proper API for that. So it's possible to benefit from both worlds.
With the latest snapshot using the properties should be possible (I hope).
Edit: Due to failing CI I suppose there is a regression and it won’t work as expected at all.
That's curious the Linux and Windows failures seem unrelated.
CustomTitleBarTest > checkTitleBarColored() FAILED
org.opentest4j.AssertionFailedError: Expected java.awt.Color[r=255,g=0,b=0], but got java.awt.Color[r=242,g=242,b=242]. Allowed tolerance is 60. Title color not equal.
MemoryTest > frameGetsGarbageCollectedComplexContent() FAILED
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
Windows:
DemoTest > runningDemosDoesNotThrow() FAILED
FontTest > initializationError FAILED
MemoryTest > initializationError FAILED
TooltipTest > initializationError FAILED
Caused by:
java.lang.IllegalArgumentException: Width (170) and height (0) cannot be <= 0
at java.desktop/java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1016)
Should be fixed now
Excellent ! it works really well !
I just noted a simple issue upon first launch, the orange border does not seem to be correctly rendered / visible at the beginning of the app, however when toggling stuff it comes back. That's not a big issue though.
https://user-images.githubusercontent.com/803621/162460575-6e0a4f3e-1365-4534-b365-ab2e2ceef8db.mov
Really awesome work !
Does it appear if you force the whole window to be repainted? This might be a situation where the titlebar doesn't yet know that it is visible when painting (i.e. try to call SwingUtilities.invokeLater(() -> frame.repaint())
after installing the laf).
Actually I'm installing the laf and decorations before creating the JFrame, and before frame.setVisible(true)
.
I'll investigate.
So I just discovered the DecorationsColorProvider
isn't called if UIManager::setLookAndFeel()
or if the look and feel is com.apple.laf.AquaLookAndFeel
. I was expecting this wasn't called if updateUI isn't called.
So once I got this using nimbus this gave this, it seems the border is painted over.
As for my app I still don't quite get what going on. It seems that on bootstrap the border is painted first, then the other component are painted over. And once I click on the buttons, the border is painted on the top.
https://user-images.githubusercontent.com/803621/162544196-e0d781ec-db90-4624-b40c-19949213b310.mov
I'm not sure this a bug per se but a behavior I'm not familiar with.
I've cooked have simple reproducer. Basically when the components are added to the frame they cover the border, but when refreshing the LaF, the border stays on top.
I realised that the correct behaviour should be that no border is painted at all in this case (specifying that the titlebar ist transparent should make it non-visible). Latest snapshot resolve the issue.
Works for me, on my side there's nothing against publishing v3 :)
Quick question, if this is possible to get the height of the title bar or the button location. If I want to place a menu on the left to the titlebar buttons (close, minimize, expand), or if I want to put something under. At this time I'm settings my borders with magic numbers that I found by guess.
I think I can expose the bounds of the buttons somehow. I’ll probably also add an easy way to hide the title as well (without setting the title to ""
, which would cripple accessibility), as otherwise one has to respect that one too which might be difficult.
Nice, although don't block the V3 for that it can wait. I mean if you're keen on releasing V3 sooner rather than later.
I scheduled the release of V3 for this weekend so I had some time on my hands. You can check the bound of the title buttons using ExternalLafDecorator.instance().decorationsManager().titlePaneLayout(frame).windowButtonRect()
. Also you can hide the title of the window by setting rootPane.putClientProperty(DecorationsConstants.KEY_HIDE_TITLE, true)
Cool!
I just gave these a try
Hiding window title, it does work ✅
But the property is inverted DecorationsConstants.KEY_HIDE_TITLE to false
will hide the title.
Getting the button rectangle ✅
I was wondering if I could get them before the window is shown, in order to do layout before. But it doesn't seem possible.
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at com.github.weisj.darklaf.platform.macos.ui.MacOSTitlePane.windowHandle(MacOSTitlePane.java:203)
at com.github.weisj.darklaf.platform.macos.MacOSDecorationsProvider.titlePaneLayoutInfo(MacOSDecorationsProvider.java:69)
at com.github.weisj.darklaf.platform.decorations.NativeDecorationsManager.titlePaneLayoutInfo(NativeDecorationsManager.java:123)
at com.github.weisj.darklaf.platform.decorations.NativeDecorationsManager.titlePaneLayoutInfo(NativeDecorationsManager.java:127)
at io.github.bric3.fireplace.AppearanceControl.getWindowButtonsRect(AppearanceControl.java:88)
at io.github.bric3.fireplace.FirePlaceMain.lambda$initUI$10(FirePlaceMain.java:163)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
...
After setting the frame visible there's no issue. But this happesn really fast so that seem ok. Maybe throwing a IllegalStateEx
could suggest a dev to use that API after the frame is visible.
- Hiding window title, it does work ✅ But the property is inverted
DecorationsConstants.KEY_HIDE_TITLE to false
will hide the title.
Fixed
After setting the frame visible there's no issue. But this happesn really fast so that seem ok. Maybe throwing a
IllegalStateEx
could suggest a dev to use that API after the frame is visible.
An exception is now thrown with a more descriptive error message. You can actually force it to succeed by calling frame.addNotify()
before calling it if you really need it before the window is visible. But I would go for something like this
class TitleBarSpace extends JComponent {
public Dimension getPreferredSize() {
ExternalLafDecorator.instance().decorationsManager().titlePaneLayout(frame).windowButtonRect().getSize();
}
public Dimension getMinimumSize() {
return getPreferredSize();
}
public Dimension getPreferredSize() {
return getPreferredSize();
}
}
and using it as a spacer in e.g. a `BorderLayout
or BoxLayout
.
Interesting. I'll give it a try.
That works, however the location (x
in particular for my case) of the rectangle must taken into account. I suppose on Linux or Windows the button rectangle is on the other side, which require a different handling.
You are right. I overlooked that fact :D I‘ll release the next version later today
Hi sorry this is not really a feature request but a usage question.
I would like to be able to control the color of the main window title bar color. And I'm not quite sure how to do it, as I have to dived in the code yet.
For reference the application is using LaF from other project (so it doesn't rely on
LafManager
). At this time the application is relying onThemePreferencesHandler.getSharedInstance()
to synchronize with OS dark mode. But I'd like to allow the user to control the appearance if they wish so.The thing is that I can switch the LaF, but the window decoration keeps the current system appearance, while I would like to assign a color to this window title bar to match the current LaF.
I have noticed the
LafManager.setDecorationsEnabled(enabled);
API but as I said I avoid LafManager as it initializes a lot of stuff the application don't need.I've noticed that
LafManager
is actually invokingBit from there I'm not quite sure how to proceed. Thank you in advance for the bits.
By the way in https://github.com/weisJ/darklaf/issues/310 we've discussed about version 3 snapshot, but I'm not yet relying on it yet as it's a snapshot.