Comments (47)
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.
from darklaf.
You are right. I overlooked that fact :D I‘ll release the next version later today
from darklaf.
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.
from darklaf.
Does the current state of the implementation work for you suffiently? If yes I would cut the next release.
from darklaf.
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.
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();
}
}
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 !!!
from darklaf.
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.
Screen.Recording.2022-04-08.at.16.36.03.mov
Really awesome work !
from darklaf.
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.
from darklaf.
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);
}
from darklaf.
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);
from darklaf.
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.
from darklaf.
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:
- For Windows: https://github.com/weisJ/darklaf/blob/decorations/windows/src/main/resources/com/github/weisj/darklaf/platform/windows/windows_decorations.properties
- For macOS: https://github.com/weisJ/darklaf/blob/decorations/macos/src/main/resources/com/github/weisj/darklaf/platform/macos/macos_decorations.properties
from darklaf.
Cool il check it out. thanks a lot.
Can these properties be adjusted on Leaf change?
from darklaf.
As long as you change the properties before you call updatesUI
on the window hierarchy you should be fine.
from darklaf.
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")
from darklaf.
The current draft PR is here : bric3/fireplace#17
from darklaf.
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?
from darklaf.
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!
from darklaf.
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 !
from darklaf.
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;
}
from darklaf.
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
.
from darklaf.
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 codeisSystemWindowTitleDark
@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.
video showcasing the issue with system wide color change
Screen.Recording.2022-04-05.at.15.07.11.mov
video showcasing the issue with interface toggle
Screen.Recording.2022-04-05.at.15.11.26.mov
-
It's a nitpick, but why not propose a default implementation for this method.
from darklaf.
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
.
from darklaf.
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
from darklaf.
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.
from darklaf.
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 bric3/fireplace#17 an up-to date version reproducing this behaviour?
from darklaf.
On each video I restarted the app. But I agree there's something fishy, when the sync is re-enabled.
Is bric3/fireplace#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
from darklaf.
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.
from darklaf.
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.
from darklaf.
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)
from darklaf.
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)?
from darklaf.
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.
Screen.Recording.2022-04-06.at.23.08.15.mov
But here as you see the color of window title is not updated
from darklaf.
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.
from darklaf.
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.
from darklaf.
That's curious the Linux and Windows failures seem unrelated.
- macos:
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.
- Linux:
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)
from darklaf.
Should be fixed now
from darklaf.
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).
from darklaf.
Actually I'm installing the laf and decorations before creating the JFrame, and before frame.setVisible(true)
.
I'll investigate.
from darklaf.
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.
Screen.Recording.2022-04-09.at.00.52.59.mov
I'm not sure this a bug per se but a behavior I'm not familiar with.
from darklaf.
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.
Single class reproducer code
import com.github.weisj.darklaf.platform.decorations.DecorationsColorProvider;
import com.github.weisj.darklaf.platform.decorations.ExternalLafDecorator;
import com.github.weisj.darklaf.platform.preferences.SystemPreferencesManager;
import com.github.weisj.darklaf.theme.spec.ColorToneRule;
import javax.swing.*;
import java.awt.*;
public class BorderMain {
private static final SystemPreferencesManager manager = new SystemPreferencesManager();
public static final Runnable SYNC_THEME_CHANGER = () -> {
dark = manager.getPreferredThemeStyle().getColorToneRule() == ColorToneRule.DARK;
setLaF();
updateUI();
};
private static void setLaF() {
try {
UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
} catch (UnsupportedLookAndFeelException e) {
throw new RuntimeException(e);
}
}
static {
manager.addListener(style -> SYNC_THEME_CHANGER.run());
}
private static boolean dark = false;
public static void main(String[] args) {
System.setProperty("apple.awt.application.name", "Border");
System.setProperty("apple.awt.application.appearance", "system");
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Border");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(1000, 600));
frame.getContentPane().add(getComp());
var rootPane = frame.getRootPane();
rootPane.putClientProperty("apple.awt.fullWindowContent", true);
rootPane.putClientProperty("apple.awt.transparentTitleBar", true);
ExternalLafDecorator.instance().install();
ExternalLafDecorator.instance().setColorProvider(new DecorationsColorProvider() {
@Override
public Color backgroundColor() {
return dark ? Color.BLACK : Color.WHITE;
}
@Override
public Color activeForegroundColor() {
return UIManager.getColor("TitlePane.foreground");
}
@Override
public Color inactiveForegroundColor() {
return Color.RED;
}
@Override
public TitleColor windowTitleColor() {
return dark ? TitleColor.LIGHT : TitleColor.DARK;
}
});
SYNC_THEME_CHANGER.run();
manager.enableReporting(true);
frame.setVisible(true);
});
}
private static JComponent getComp() {
var topPanel = new JPanel(new BorderLayout());
var textField = new JTextField("");
textField.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.BLUE, 1),
BorderFactory.createEmptyBorder(30, 5, 5, 5)
));
textField.setEditable(false);
textField.setBackground(Color.PINK);
topPanel.add(textField, BorderLayout.CENTER);
topPanel.setBackground(Color.DARK_GRAY);
var control = getAppearanceControls();
control.setBorder(BorderFactory.createLineBorder(Color.PINK, 1));
control.setBackground(Color.GRAY);
topPanel.add(control, BorderLayout.EAST);
var content = new JPanel(new BorderLayout());
content.setBackground(Color.GRAY);
var panel = new JPanel(new BorderLayout());
panel.add(topPanel, BorderLayout.NORTH);
panel.add(content, BorderLayout.CENTER);
return panel;
}
static JComponent getAppearanceControls() {
var appearanceModeButton = new JCheckBox("L/D");
{
appearanceModeButton.addActionListener(e -> {
dark = !dark;
setLaF();
updateUI();
});
appearanceModeButton.setEnabled(false);
appearanceModeButton.setVisible(true);
}
var syncAppearanceButton = new JCheckBox("Sync appearance");
{
syncAppearanceButton.addActionListener(e -> {
manager.enableReporting(syncAppearanceButton.isSelected());
appearanceModeButton.setEnabled(!syncAppearanceButton.isSelected());
SYNC_THEME_CHANGER.run();
});
syncAppearanceButton.setSelected(true);
syncAppearanceButton.setVisible(true);
}
var appearanceControlsPanel = new JPanel(new FlowLayout());
appearanceControlsPanel.add(appearanceModeButton);
appearanceControlsPanel.add(syncAppearanceButton);
return appearanceControlsPanel;
}
public static void updateUI() {
for (var window : Window.getWindows()) {
SwingUtilities.updateComponentTreeUI(window);
}
}
}
from darklaf.
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.
from darklaf.
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.
from darklaf.
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.
from darklaf.
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)
from darklaf.
Cool!
I just gave these a try
-
Hiding window title, it does work ✅
But the property is invertedDecorationsConstants.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.
from darklaf.
- Hiding window title, it does work
✅
But the property is invertedDecorationsConstants.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 ``BorderLayoutor
BoxLayout`.
from darklaf.
Interesting. I'll give it a try.
from darklaf.
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.
from darklaf.
Related Issues (20)
- SAXException with Icons HOT 4
- Message "Couldn't get HWND of window" in the log HOT 3
- Maximize and Restore not working in 3.0.0 HOT 5
- Wiki Demo links not working. HOT 1
- temp files not deleted on Windows HOT 2
- Stackoverflow when setting the border of a spinner editor to an UIResource border
- Advice on how to contribute, Darklaf theme broken in JMeter 5.3, 5.4, 5.5 HOT 4
- JTree has some renderer bug HOT 3
- Event registered on EditorComponent for JComboBox will be cleared when new theme applied. HOT 3
- On a windows 10 computer,cannot open filechooser HOT 2
- JTabFrame custom PanelPopup buttons disappear after changing LaF settings HOT 1
- [Feature Request] JTabFrame disallow changing Alignment of the tabs.
- Buttons are "raised" in latest.integration (compared to 3.0.2)
- Can't build project on mac m1, 13.12.1 HOT 1
- Replace UIDefaultsWithResourceBundleCache with delegation
- [Feature Request] Allow confirm dialog on closing for ClosableTabbedPane without overwriting removeTabAt method
- [Bug] Exception when running on Windows Java 17 HOT 7
- [Bug] Opacity slider of JColorChooser has no effect
- [Feature Request] Apply color pipette with left-mouse click HOT 1
- [Bug] Wrong IconButton positioning in v3.0.3 HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from darklaf.