diff --git a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java index 98b65669eda..faa52b83130 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java @@ -133,6 +133,22 @@ default boolean enableCustomChrome() return OSType.getOSType() == OSType.Windows; } + @Range( + min = 10, + max = 100 + ) + @ConfigItem( + keyName = "uiWindowOpacity", + name = "Window opacity", + description = "Set the windows opacity.", + position = 16, + section = windowSettings + ) + default int windowOpacity() + { + return 100; + } + @ConfigItem( keyName = "gameAlwaysOnTop", name = "Always on top", diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java index f28a29fec9c..8eff248e553 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java @@ -1114,6 +1114,12 @@ private void updateFrameConfig(boolean updateResizable) return; } + if (frame.getGraphicsConfiguration().isTranslucencyCapable() && + frame.getGraphicsConfiguration().getDevice().getFullScreenWindow() == null) + { + frame.setOpacity(((float) config.windowOpacity()) / 100.0f); + } + if (config.usernameInTitle() && (client instanceof Client)) { final Player player = ((Client) client).getLocalPlayer(); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ContainableFrame.java b/runelite-client/src/main/java/net/runelite/client/ui/ContainableFrame.java index 42a0f3a158b..c95b9648de8 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ContainableFrame.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ContainableFrame.java @@ -27,6 +27,7 @@ import com.formdev.flatlaf.ui.FlatNativeWindowsLibrary; import java.awt.Dimension; import java.awt.Frame; +import java.awt.IllegalComponentStateException; import java.awt.Insets; import java.awt.Rectangle; import java.awt.geom.AffineTransform; @@ -52,6 +53,7 @@ public enum Mode private boolean rightSideSuction; private boolean boundsOpSet; private boolean scaleMinSize = false; + private boolean overrideUndecorated; @Override @SuppressWarnings("deprecation") @@ -259,4 +261,30 @@ void updateContainsInScreen() FlatNativeWindowsLibrary.setContainInScreen(this, containedInScreen == Mode.ALWAYS); } } + + @Override + public void setOpacity(float opacity) + { + // JDK-6993784 requires the frame to be undecorated to apply opacity, but in practice it works on Windows regardless. + // Temporarily pretend to be an undecorated frame to satisfy Frame.setOpacity(). + overrideUndecorated = true; + try + { + super.setOpacity(opacity); + } + catch (IllegalComponentStateException | UnsupportedOperationException | IllegalArgumentException ex) + { + log.warn("unable to set opacity {}", opacity, ex); + } + finally + { + overrideUndecorated = false; + } + } + + @Override + public boolean isUndecorated() + { + return overrideUndecorated || super.isUndecorated(); + } }