From b414b06c84aa5ea9551decb013bee1b72ee4bcf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Sat, 19 Aug 2023 19:46:36 +0200 Subject: [PATCH 01/11] Added new colorize Icon method to colorize using replacing method instead multiplying values. --- .../codereview/list/ReviewListCellRenderer.kt | 2 +- .../core-ui/src/ui/icons/CoreIconManager.kt | 2 +- platform/core-ui/src/util/IconUtil.kt | 36 +++++++++++++++---- .../wm/impl/welcomeScreen/FlatWelcomeFrame.kt | 2 +- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/list/ReviewListCellRenderer.kt b/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/list/ReviewListCellRenderer.kt index ed83e49bfdfb9..b6eb1e8918b60 100644 --- a/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/list/ReviewListCellRenderer.kt +++ b/platform/collaboration-tools/src/com/intellij/collaboration/ui/codereview/list/ReviewListCellRenderer.kt @@ -143,7 +143,7 @@ class ReviewListCellRenderer(private val presenter: (T) -> ReviewListItemPres val color = tag.color if (color != null) { //TODO: need a separate untinted icon to color properly - label.icon = IconUtil.colorize(DvcsImplIcons.BranchLabel, color) + label.icon = IconUtil.colorizeTint(DvcsImplIcons.BranchLabel, color) } else { label.icon = DvcsImplIcons.BranchLabel diff --git a/platform/core-ui/src/ui/icons/CoreIconManager.kt b/platform/core-ui/src/ui/icons/CoreIconManager.kt index bf72732cb1fa9..75966a4450cde 100644 --- a/platform/core-ui/src/ui/icons/CoreIconManager.kt +++ b/platform/core-ui/src/ui/icons/CoreIconManager.kt @@ -167,7 +167,7 @@ class CoreIconManager : IconManager, CoreAwareIconManager { override fun createOffsetIcon(icon: Icon): Icon = OffsetIcon(icon) - override fun colorize(g: Graphics2D, source: Icon, color: Color): Icon = IconUtil.colorize(g, source, color) + override fun colorize(g: Graphics2D, source: Icon, color: Color): Icon = IconUtil.colorizeTint(g, source, color) override fun createLayered(vararg icons: Icon): Icon = LayeredIcon.layeredIcon(icons) diff --git a/platform/core-ui/src/util/IconUtil.kt b/platform/core-ui/src/util/IconUtil.kt index 96d6713e6a48c..fcd3d70dcc3e9 100644 --- a/platform/core-ui/src/util/IconUtil.kt +++ b/platform/core-ui/src/util/IconUtil.kt @@ -499,14 +499,24 @@ object IconUtil { @JvmOverloads @JvmStatic - fun colorize(source: Icon, color: Color, keepGray: Boolean = false): Icon { - return filterIcon(icon = source, filterSupplier = { ColorFilter(color, keepGray) }) + fun colorizeTint(source: Icon, color: Color, keepGray: Boolean = false): Icon { + return filterIcon(icon = source, filterSupplier = { ColorMultiplyFilter(color, keepGray) }) } @JvmOverloads @JvmStatic - fun colorize(g: Graphics2D?, source: Icon, color: Color, keepGray: Boolean = false): Icon { - return filterIcon(g = g, source = source, filter = ColorFilter(color, keepGray)) + fun colorizeTint(g: Graphics2D?, source: Icon, color: Color, keepGray: Boolean = false): Icon { + return filterIcon(g = g, source = source, filter = ColorMultiplyFilter(color, keepGray)) + } + + @JvmStatic + fun colorizeReplace(source: Icon, color: Color): Icon { + return filterIcon(icon = source, filterSupplier = { ColorReplaceFilter(color) }) + } + + @JvmStatic + fun colorizeReplace(g: Graphics2D?, source: Icon, color: Color): Icon { + return filterIcon(g = g, source = source, filter = ColorReplaceFilter(color)) } @JvmStatic @@ -627,7 +637,7 @@ class CropIcon internal constructor(val sourceIcon: Icon, val crop: Rectangle) : override fun hashCode(): Int = Objects.hash(sourceIcon, crop) } -private class ColorFilter(color: Color, private val keepGray: Boolean) : RGBImageFilter() { +private class ColorMultiplyFilter(color: Color, private val keepGray: Boolean) : RGBImageFilter() { private val base = Color.RGBtoHSB(color.red, color.green, color.blue, null) override fun filterRGB(x: Int, y: Int, rgba: Int): Int { @@ -641,6 +651,20 @@ private class ColorFilter(color: Color, private val keepGray: Boolean) : RGBImag } } +private class ColorReplaceFilter(color: Color) : RGBImageFilter() { + private val base = Color.RGBtoHSB(color.red, color.green, color.blue, null) + + override fun filterRGB(x: Int, y: Int, rgba: Int): Int { + val r = rgba shr 16 and 0xff + val g = rgba shr 8 and 0xff + val b = rgba and 0xff + val hsb = FloatArray(3) + Color.RGBtoHSB(r, g, b, hsb) + val rgb = Color.HSBtoRGB(base[0], base[1], base[2]) + return rgba and -0x1000000 or (rgb and 0xffffff) + } +} + private class DesaturationFilter : RGBImageFilter() { override fun filterRGB(x: Int, y: Int, rgba: Int): Int { val r = rgba shr 16 and 0xff @@ -709,7 +733,7 @@ private fun scaleByIcon(icon: Icon?, ancestor: Component?, defaultIcon: Icon, si } } -private fun filterIcon(g: Graphics2D?, source: Icon, filter: ColorFilter): Icon { +private fun filterIcon(g: Graphics2D?, source: Icon, filter: RGBImageFilter): Icon { val src = if (g == null) { ImageUtil.createImage(source.iconWidth, source.iconHeight, BufferedImage.TYPE_INT_ARGB) } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt index 10bf6e6856060..d85997567d78e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.kt @@ -474,7 +474,7 @@ open class FlatWelcomeFrame @JvmOverloads constructor( var icon = presentation.icon if (icon == null || icon.iconHeight != JBUIScale.scale(16) || icon.iconWidth != JBUIScale.scale(16)) { icon = if (icon == null) JBUIScale.scaleIcon(EmptyIcon.create(16)) else IconUtil.scale(icon, null, 16f / icon.iconWidth) - icon = IconUtil.colorize(icon, JBColor(0x6e6e6e, 0xafb1b3)) + icon = IconUtil.colorizeTint(icon, JBColor(0x6e6e6e, 0xafb1b3)) } action = ActionGroupPanelWrapper.wrapGroups(action, this) val link = ActionLink(text, icon, action, null, ActionPlaces.WELCOME_SCREEN) From 0ad048111db0cb28c7d89542eea9afadeabe19e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Sat, 19 Aug 2023 20:06:35 +0200 Subject: [PATCH 02/11] Divided logic to separate Windows and linux. NEW Linux frame title buttons with extracted icons. --- .../CustomFrameTitleButtons.kt | 164 ++++++++++-------- .../LinuxLookAndFeel.kt | 38 ++++ .../ResizableCustomFrameTitleButtons.kt | 57 ------ .../frameTitleButtons/FrameTitleButtons.kt | 28 +++ .../LinuxFrameTitleButtons.kt | 138 +++++++++++++++ .../WindowsFrameTitleButtons.kt | 95 ++++++++++ .../header/DialogHeader.kt | 1 + .../header/FrameHeader.kt | 3 +- 8 files changed, 393 insertions(+), 131 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt delete mode 100644 platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/ResizableCustomFrameTitleButtons.kt create mode 100644 platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/FrameTitleButtons.kt create mode 100644 platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt create mode 100644 platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt index 2d0c3634837e4..03ec4916c2406 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt @@ -1,33 +1,43 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations -import com.intellij.icons.AllIcons import com.intellij.ide.ui.UISettings +import com.intellij.openapi.util.SystemInfo +import com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons.FrameTitleButtons +import com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons.LinuxFrameTitleButtons +import com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons.WindowsFrameTitleButtons import com.intellij.openapi.wm.impl.customFrameDecorations.style.ComponentStyle import com.intellij.openapi.wm.impl.customFrameDecorations.style.ComponentStyleState -import com.intellij.openapi.wm.impl.customFrameDecorations.style.HOVER_KEY import com.intellij.openapi.wm.impl.customFrameDecorations.style.StyleManager import com.intellij.ui.scale.JBUIScale import com.intellij.util.ui.JBUI.Borders import com.intellij.util.ui.JBUI.CurrentTheme -import java.awt.Color import java.awt.Dimension import java.awt.FlowLayout -import java.awt.Graphics -import javax.accessibility.AccessibleContext import javax.swing.* -import javax.swing.plaf.ButtonUI -import javax.swing.plaf.basic.BasicButtonUI -internal open class CustomFrameTitleButtons(myCloseAction: Action) { + +internal open class CustomFrameTitleButtons(private val myCloseAction: Action, + private val myRestoreAction: Action? = null, + private val myIconifyAction: Action? = null, + private val myMaximizeAction: Action? = null +) { companion object { - fun create(closeAction: Action): CustomFrameTitleButtons { - val darculaTitleButtons = CustomFrameTitleButtons(closeAction) + fun create(myCloseAction: Action, + myRestoreAction: Action? = null, + myIconifyAction: Action? = null, + myMaximizeAction: Action? = null): CustomFrameTitleButtons { + val darculaTitleButtons = CustomFrameTitleButtons(myCloseAction, myRestoreAction, myIconifyAction, myMaximizeAction) darculaTitleButtons.createChildren() return darculaTitleButtons } } + private val buttons: FrameTitleButtons = if (SystemInfo.isWindows) + WindowsFrameTitleButtons(myCloseAction, myRestoreAction, myIconifyAction, myMaximizeAction) + else + LinuxFrameTitleButtons(myCloseAction, myRestoreAction, myIconifyAction, myMaximizeAction) + private val baseStyle = ComponentStyle.ComponentStyleBuilder { isOpaque = false border = Borders.empty() @@ -41,32 +51,9 @@ internal open class CustomFrameTitleButtons(myCloseAction: Action) { } } - private val closeStyleBuilder: ComponentStyle.ComponentStyleBuilder = ComponentStyle.ComponentStyleBuilder { - isOpaque = false - border = Borders.empty() - icon = AllIcons.Windows.CloseActive - }.apply { - style(ComponentStyleState.HOVERED) { - isOpaque = true - background = Color(0xe81123) - icon = AllIcons.Windows.CloseHover - } - style(ComponentStyleState.PRESSED) { - isOpaque = true - background = Color(0xf1707a) - icon = AllIcons.Windows.CloseHover - } - } - private val activeCloseStyle = closeStyleBuilder.build() - - private val inactiveCloseStyle = closeStyleBuilder - .updateDefault { - icon = AllIcons.Windows.CloseInactive - }.build() private val panel = TitleButtonsPanel() - val closeButton: JButton = createButton("Close", myCloseAction) internal var isCompactMode: Boolean set(value) { @@ -78,19 +65,51 @@ internal open class CustomFrameTitleButtons(myCloseAction: Action) { var isSelected: Boolean = false set(value) { - if(field != value) { + if (field != value) { field = value updateStyles() } } protected open fun updateStyles() { - StyleManager.applyStyle(closeButton, if(isSelected) activeCloseStyle else inactiveCloseStyle) + StyleManager.applyStyle( + buttons.closeButton, + getStyle( + if (isSelected) buttons.closeIcon else buttons.closeInactiveIcon, + buttons.closeHoverIcon + ) + ) + buttons.restoreButton?.let { + StyleManager.applyStyle( + it, + getStyle( + if (isSelected) buttons.restoreIcon else buttons.restoreInactiveIcon, + buttons.restoreIcon + ) + ) + } + buttons.maximizeButton?.let { + StyleManager.applyStyle( + it, + getStyle( + if (isSelected) buttons.maximizeIcon else buttons.maximizeInactiveIcon, + buttons.maximizeIcon + ) + ) + } + buttons.minimizeButton?.let { + StyleManager.applyStyle( + it, + getStyle( + if (isSelected) buttons.minimizeIcon else buttons.minimizeInactiveIcon, + buttons.minimizeIcon + ) + ) + } } protected fun createChildren() { fillButtonPane() - addCloseButton() updateVisibility() updateStyles() } @@ -98,20 +117,38 @@ internal open class CustomFrameTitleButtons(myCloseAction: Action) { fun getView(): JComponent = panel protected open fun fillButtonPane() { + if (SystemInfo.isLinux) { + var linuxButtonsLayout = LinuxLookAndFeel.getHeaderLayout() + if (!linuxButtonsLayout.contains("close")) { + linuxButtonsLayout = linuxButtonsLayout.plus("close") + } + for (item in linuxButtonsLayout) { + when (item) { + "minimize" -> buttons.minimizeButton?.let { panel.addComponent(it) } + "maximize" -> { + buttons.maximizeButton?.let { panel.addComponent(it) } + buttons.restoreButton?.let { panel.addComponent(it) } + } + "close" -> panel.addComponent(buttons.closeButton) + } + } + val emptyComponent: Box = Box.createHorizontalBox() // Margin right + panel.addComponent(emptyComponent) + } else { + buttons.minimizeButton?.let { panel.addComponent(it) } + buttons.maximizeButton?.let { panel.addComponent(it) } + buttons.restoreButton?.let { panel.addComponent(it) } + panel.addComponent(buttons.closeButton) + } } open fun updateVisibility() { + buttons.minimizeButton?.isVisible = myIconifyAction?.isEnabled ?: false + buttons.restoreButton?.isVisible = myRestoreAction?.isEnabled ?: false + buttons.maximizeButton?.isVisible = myMaximizeAction?.isEnabled ?: false } - private fun addCloseButton() { - addComponent(closeButton) - } - - protected fun addComponent(component: JComponent) { - panel.addComponent(component) - } - - protected fun getStyle(icon: Icon, hoverIcon : Icon): ComponentStyle { + protected fun getStyle(icon: Icon, hoverIcon: Icon): ComponentStyle { val clone = baseStyle.clone() clone.updateDefault { this.icon = icon @@ -127,32 +164,6 @@ internal open class CustomFrameTitleButtons(myCloseAction: Action) { return clone.build() } - protected fun createButton(accessibleName: String, action: Action): JButton { - val button = object : JButton(){ - init { - super.setUI(HoveredButtonUI()) - } - - override fun setUI(ui: ButtonUI?) { - } - } - button.action = action - button.isFocusable = false - button.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName) - button.text = null - return button - } -} -private class HoveredButtonUI : BasicButtonUI() { - override fun paint(g: Graphics, c: JComponent) { - getHoverColor(c)?.let { - g.color = it - g.fillRect(0, 0, c.width, c.height) - } - super.paint(g, c) - } - - private fun getHoverColor(c: JComponent): Color? = c.getClientProperty(HOVER_KEY) as? Color } private class TitleButtonsPanel : JPanel(FlowLayout(FlowLayout.LEADING, 0, 0)) { @@ -177,10 +188,19 @@ private class TitleButtonsPanel : JPanel(FlowLayout(FlowLayout.LEADING, 0, 0)) { private fun JComponent.setScaledPreferredSize() { val size = CurrentTheme.TitlePane.buttonPreferredSize(UISettings.defFontScale).clone() as Dimension + // TODO isCompactMode siempre es false, parece un bug if (isCompactMode) { size.height = JBUIScale.scale(30) } - preferredSize = Dimension(size.width, size.height) + if (SystemInfo.isLinux) { + if (this !is Box) { + preferredSize = Dimension(36, 36) + } else { + preferredSize = Dimension(2, size.height) // Margin right + } + } else { + preferredSize = Dimension(size.width, size.height) + } } override fun updateUI() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt new file mode 100644 index 0000000000000..7f1476efd828f --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt @@ -0,0 +1,38 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.openapi.wm.impl.customFrameDecorations + +import java.io.BufferedReader +import java.io.InputStreamReader + +class LinuxLookAndFeel { + companion object { + fun getIconTheme(): String? { + return getDconfEntry("/org/gnome/desktop/interface/icon-theme") + } + + fun getHeaderLayout(): List { + // Next line returns something like appmenu:minimize,maximize,close + var elementsString = getDconfEntry("/org/gnome/desktop/wm/preferences/button-layout") + elementsString = elementsString?.drop(1)?.dropLast(1) + val elements = elementsString?.split(":", ",") + return elements ?: emptyList() + } + + private fun getDconfEntry(key: String): String? { + return execute("dconf read $key") + } + + private fun execute(command: String): String? { + val processBuilder = ProcessBuilder(command.split(" ")) + processBuilder.redirectErrorStream(true) + + val process = processBuilder.start() + val reader = BufferedReader(InputStreamReader(process.inputStream)) + + val line: String? = reader.readLine() // Leer la primera línea + val exitCode = process.waitFor() + + return line + } + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/ResizableCustomFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/ResizableCustomFrameTitleButtons.kt deleted file mode 100644 index 5dd3606a582ee..0000000000000 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/ResizableCustomFrameTitleButtons.kt +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.openapi.wm.impl.customFrameDecorations - -import com.intellij.icons.AllIcons -import com.intellij.openapi.wm.impl.customFrameDecorations.style.StyleManager -import javax.swing.Action - -internal class ResizableCustomFrameTitleButtons(closeAction: Action, - private val myRestoreAction: Action, - private val myIconifyAction: Action, - private val myMaximizeAction: Action -) : CustomFrameTitleButtons(closeAction) { - companion object { - private val restoreIcon = AllIcons.Windows.Restore - private val restoreInactiveIcon = AllIcons.Windows.RestoreInactive - - private val maximizeIcon = AllIcons.Windows.Maximize - private val maximizeInactiveIcon = AllIcons.Windows.MaximizeInactive - - private val minimizeIcon = AllIcons.Windows.Minimize - private val minimizeInactiveIcon = AllIcons.Windows.MinimizeInactive - - fun create(myCloseAction: Action, - myRestoreAction: Action, - myIconifyAction: Action, - myMaximizeAction: Action): ResizableCustomFrameTitleButtons { - val darculaTitleButtons = ResizableCustomFrameTitleButtons(myCloseAction, myRestoreAction, myIconifyAction, myMaximizeAction) - darculaTitleButtons.createChildren() - return darculaTitleButtons - } - } - - private val restoreButton = createButton("Restore", myRestoreAction) - private val maximizeButton = createButton("Maximize", myMaximizeAction) - private val minimizeButton = createButton("Iconify", myIconifyAction) - - override fun fillButtonPane() { - super.fillButtonPane() - addComponent(minimizeButton) - addComponent(maximizeButton) - addComponent(restoreButton) - } - - override fun updateVisibility() { - super.updateVisibility() - minimizeButton.isVisible = myIconifyAction.isEnabled - restoreButton.isVisible = myRestoreAction.isEnabled - maximizeButton.isVisible = myMaximizeAction.isEnabled - } - - override fun updateStyles() { - super.updateStyles() - StyleManager.applyStyle(restoreButton, getStyle(if (isSelected) restoreIcon else restoreInactiveIcon, restoreIcon)) - StyleManager.applyStyle(maximizeButton, getStyle(if (isSelected) maximizeIcon else maximizeInactiveIcon, maximizeIcon)) - StyleManager.applyStyle(minimizeButton, getStyle(if (isSelected) minimizeIcon else minimizeInactiveIcon, minimizeIcon)) - } -} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/FrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/FrameTitleButtons.kt new file mode 100644 index 0000000000000..8c35fcc0b919c --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/FrameTitleButtons.kt @@ -0,0 +1,28 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons + +import javax.swing.Action +import javax.swing.Icon +import javax.swing.JButton + +interface FrameTitleButtons { + val closeButton: JButton + val restoreButton: JButton? + val maximizeButton: JButton? + val minimizeButton: JButton? + + val restoreIcon: Icon + val restoreInactiveIcon: Icon + + val maximizeIcon: Icon + val maximizeInactiveIcon: Icon + + val minimizeIcon: Icon + val minimizeInactiveIcon: Icon + + val closeIcon: Icon + val closeInactiveIcon: Icon + val closeHoverIcon: Icon + + fun createButton(accessibleName: String, action: Action): JButton +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt new file mode 100644 index 0000000000000..13067a1140d65 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt @@ -0,0 +1,138 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons + +import com.intellij.icons.AllIcons +import com.intellij.openapi.wm.impl.customFrameDecorations.LinuxLookAndFeel +import com.intellij.openapi.wm.impl.customFrameDecorations.style.HOVER_KEY +import com.intellij.ui.IconManager +import com.intellij.ui.JBColor +import com.intellij.util.IconUtil +import java.awt.Color +import java.awt.Graphics +import java.awt.Graphics2D +import java.awt.RenderingHints +import javax.accessibility.AccessibleContext +import javax.swing.Action +import javax.swing.Icon +import javax.swing.JButton +import javax.swing.JComponent +import javax.swing.plaf.ButtonUI +import javax.swing.plaf.basic.BasicButtonUI + +class LinuxFrameTitleButtons( + myCloseAction: Action, + myRestoreAction: Action? = null, + myIconifyAction: Action? = null, + myMaximizeAction: Action? = null) : FrameTitleButtons { + override val closeButton: JButton = createButton("Close", myCloseAction) + override val restoreButton: JButton? = myRestoreAction?.let { createButton("Restore", it) } + override val maximizeButton: JButton? = myMaximizeAction?.let { createButton("Maximize", it) } + override val minimizeButton: JButton? = myIconifyAction?.let { createButton("Iconify", it) } + + val restore = loadLinuxIcon("window-restore-symbolic.svg") + override val restoreIcon = restore + override val restoreInactiveIcon = restore + + val maximize = loadLinuxIcon("window-maximize-symbolic") + override val maximizeIcon = maximize + override val maximizeInactiveIcon = maximize + + val minimize = loadLinuxIcon("window-minimize-symbolic.svg") + override val minimizeIcon = minimize + override val minimizeInactiveIcon = minimize + + val close = loadLinuxIcon("window-close-symbolic.svg") + override val closeIcon = close + override val closeInactiveIcon = close + override val closeHoverIcon = close + + override fun createButton(accessibleName: String, action: Action): JButton { + val button = object : JButton() { + init { + super.setUI(HoveredCircleButtonUI()) + } + + override fun setUI(ui: ButtonUI?) { + } + } + button.action = action + button.isFocusable = false + button.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName) + button.text = null + //button.preferredSize = Dimension(5, 5) + + println("====================================") + println("====================================") + println("====================================") + println("====================================") + println(LinuxLookAndFeel.getIconTheme()) + println(LinuxLookAndFeel.getHeaderLayout()) + println("====================================") + println("====================================") + println("====================================") + println("====================================") + + return button + } + + + private fun loadLinuxIcon(iconName: String): Icon { + val themeAdwaita = "Adwaita/scalable/ui/" // Adwaita + val themeYaru = "Yaru/scalable/ui/" // Yaru + val themePapirus = "Papirus/symbolic/actions/" // Papirus + var icon = IconManager.getInstance().getIcon("file:/usr/share/icons/$themePapirus$iconName", + AllIcons::class.java.classLoader) + icon = IconUtil.colorizeReplace(icon, JBColor(0x6c7080, 0xcfd1d8)) + return icon + } +} + + +private class HoveredCircleButtonUI : BasicButtonUI() { + private val circleDiameter = 24 + override fun paint(g: Graphics, c: JComponent) { + g.color = Color(0x434343) + getHoverColor(c)?.let { + g.color = Color(0x4e4e4e) + //g.fillRect(0, 0, c.width, c.height) + } + if (g is Graphics2D) { + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) + g.fillRoundRect((c.width / 2) - (circleDiameter / 2), (c.height / 2) - (circleDiameter / 2), circleDiameter, circleDiameter, c.width, c.height) + } + super.paint(g, c) + } + + private fun getHoverColor(c: JComponent): Color? = c.getClientProperty(HOVER_KEY) as? Color +} + +/* +private class Dconf { + + fun getIconTheme(): String? { + return getDconfEntry("/org/gnome/desktop/interface/icon-theme") + } + + fun getHeaderLayout(): String? { + // Next line returns something like appmenu:minimize,maximize,close + return getDconfEntry("/org/gnome/desktop/wm/preferences/button-layout") + } + + private fun getDconfEntry(key: String): String? { + return execute("dconf read $key") + } + + private fun execute(command: String): String? { + val processBuilder = ProcessBuilder(command.split(" ")) + processBuilder.redirectErrorStream(true) + + val process = processBuilder.start() + val reader = BufferedReader(InputStreamReader(process.inputStream)) + + val line: String? = reader.readLine() // Leer la primera línea + val exitCode = process.waitFor() + + return line + } + +}*/ diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt new file mode 100644 index 0000000000000..6f785bc0a6410 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt @@ -0,0 +1,95 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons + +import com.intellij.icons.AllIcons +import com.intellij.openapi.wm.impl.customFrameDecorations.style.ComponentStyle +import com.intellij.openapi.wm.impl.customFrameDecorations.style.ComponentStyleState +import com.intellij.openapi.wm.impl.customFrameDecorations.style.HOVER_KEY +import com.intellij.ui.JBColor +import com.intellij.util.IconUtil +import com.intellij.util.ui.JBUI +import java.awt.Color +import java.awt.Graphics +import javax.accessibility.AccessibleContext +import javax.swing.Action +import javax.swing.JButton +import javax.swing.JComponent +import javax.swing.plaf.ButtonUI +import javax.swing.plaf.basic.BasicButtonUI + +class WindowsFrameTitleButtons( + myCloseAction: Action, + myRestoreAction: Action? = null, + myIconifyAction: Action? = null, + myMaximizeAction: Action? = null) : FrameTitleButtons { + override val closeButton: JButton = createButton("Close", myCloseAction) + override val restoreButton: JButton? = myRestoreAction?.let { createButton("Restore", it) } + override val maximizeButton: JButton? = myMaximizeAction?.let { createButton("Maximize", it) } + override val minimizeButton: JButton? = myIconifyAction?.let { createButton("Iconify", it) } + + override val restoreIcon = AllIcons.Windows.Restore + override val restoreInactiveIcon = AllIcons.Windows.RestoreInactive + + override val maximizeIcon = AllIcons.Windows.Maximize + override val maximizeInactiveIcon = AllIcons.Windows.MaximizeInactive + + override val minimizeIcon = AllIcons.Windows.Minimize + override val minimizeInactiveIcon = AllIcons.Windows.MinimizeInactive + + + override val closeIcon = AllIcons.Windows.CloseActive + override val closeInactiveIcon = AllIcons.Windows.CloseInactive + override val closeHoverIcon = IconUtil.colorizeReplace(AllIcons.Windows.CloseActive, JBColor(0xffffff, 0xffffff)) + + /*private val closeStyleBuilder: ComponentStyle.ComponentStyleBuilder = ComponentStyle.ComponentStyleBuilder { + isOpaque = true + border = JBUI.Borders.empty() + icon = AllIcons.Windows.CloseActive + }*//*.apply { + style(ComponentStyleState.HOVERED) { + isOpaque = true + background = Color(0xe81123) + icon = AllIcons.Windows.CloseHover + } + style(ComponentStyleState.PRESSED) { + isOpaque = true + background = Color(0xf1707a) + icon = AllIcons.Windows.CloseHover + } + }*/ + /*override val activeCloseStyle = closeStyleBuilder.build() + + override val inactiveCloseStyle = closeStyleBuilder + .updateDefault { + icon = AllIcons.Windows.CloseInactive + }.build()*/ + + override fun createButton(accessibleName: String, action: Action): JButton { + val button = object : JButton() { + init { + super.setUI(if (accessibleName == "Close") HoveredButtonUI(Color(0xe81123)) else HoveredButtonUI()) + } + + override fun setUI(ui: ButtonUI?) { + } + } + button.action = action + button.isFocusable = false + button.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName) + button.text = null + return button + } +} + + +private class HoveredButtonUI(private val customBackgroundColor: Color? = null) : BasicButtonUI() { + override fun paint(g: Graphics, c: JComponent) { + getHoverColor(c)?.let { + g.color = customBackgroundColor ?: it + g.fillRect(0, 0, c.width, c.height) + } + super.paint(g, c) + } + + private fun getHoverColor(c: JComponent): Color? = c.getClientProperty(HOVER_KEY) as? Color +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt index 1e34b86592507..2a73e59f3de11 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt @@ -88,6 +88,7 @@ internal class DialogHeader(window: Window) : CustomHeader(window) { } private fun createButtonsPane(): CustomFrameTitleButtons? { + //return null // TODO Arreglar return if (IdeRootPane.hideNativeLinuxTitle) CustomFrameTitleButtons.create(createCloseAction(this)) else null } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt index de091b4ead83c..b2ce294c84144 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/FrameHeader.kt @@ -7,7 +7,6 @@ import com.intellij.ide.IdeBundle import com.intellij.idea.ActionsBundle import com.intellij.openapi.wm.impl.IdeRootPane import com.intellij.openapi.wm.impl.customFrameDecorations.CustomFrameTitleButtons -import com.intellij.openapi.wm.impl.customFrameDecorations.ResizableCustomFrameTitleButtons import com.intellij.util.ui.JBFont import java.awt.Font import java.awt.Frame @@ -98,7 +97,7 @@ internal open class FrameHeader(protected val frame: JFrame) : CustomHeader(fram private fun createButtonsPane(): CustomFrameTitleButtons? { if (IdeRootPane.hideNativeLinuxTitle) { - return ResizableCustomFrameTitleButtons.create(closeAction, restoreAction, iconifyAction, maximizeAction) + return CustomFrameTitleButtons.create(closeAction, restoreAction, iconifyAction, maximizeAction) } return null } From b6a5cff90e4499a496820d2a1e7e44beb3dbd203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Sat, 19 Aug 2023 20:09:37 +0200 Subject: [PATCH 03/11] Cleaning --- .../LinuxFrameTitleButtons.kt | 30 ------------------- .../WindowsFrameTitleButtons.kt | 23 -------------- 2 files changed, 53 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt index 13067a1140d65..5868d17a0d916 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt @@ -106,33 +106,3 @@ private class HoveredCircleButtonUI : BasicButtonUI() { private fun getHoverColor(c: JComponent): Color? = c.getClientProperty(HOVER_KEY) as? Color } -/* -private class Dconf { - - fun getIconTheme(): String? { - return getDconfEntry("/org/gnome/desktop/interface/icon-theme") - } - - fun getHeaderLayout(): String? { - // Next line returns something like appmenu:minimize,maximize,close - return getDconfEntry("/org/gnome/desktop/wm/preferences/button-layout") - } - - private fun getDconfEntry(key: String): String? { - return execute("dconf read $key") - } - - private fun execute(command: String): String? { - val processBuilder = ProcessBuilder(command.split(" ")) - processBuilder.redirectErrorStream(true) - - val process = processBuilder.start() - val reader = BufferedReader(InputStreamReader(process.inputStream)) - - val line: String? = reader.readLine() // Leer la primera línea - val exitCode = process.waitFor() - - return line - } - -}*/ diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt index 6f785bc0a6410..86dffe21f83f3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt @@ -41,29 +41,6 @@ class WindowsFrameTitleButtons( override val closeInactiveIcon = AllIcons.Windows.CloseInactive override val closeHoverIcon = IconUtil.colorizeReplace(AllIcons.Windows.CloseActive, JBColor(0xffffff, 0xffffff)) - /*private val closeStyleBuilder: ComponentStyle.ComponentStyleBuilder = ComponentStyle.ComponentStyleBuilder { - isOpaque = true - border = JBUI.Borders.empty() - icon = AllIcons.Windows.CloseActive - }*//*.apply { - style(ComponentStyleState.HOVERED) { - isOpaque = true - background = Color(0xe81123) - icon = AllIcons.Windows.CloseHover - } - style(ComponentStyleState.PRESSED) { - isOpaque = true - background = Color(0xf1707a) - icon = AllIcons.Windows.CloseHover - } - }*/ - /*override val activeCloseStyle = closeStyleBuilder.build() - - override val inactiveCloseStyle = closeStyleBuilder - .updateDefault { - icon = AllIcons.Windows.CloseInactive - }.build()*/ - override fun createButton(accessibleName: String, action: Action): JButton { val button = object : JButton() { init { From 74bf4115b549772e78fa35466ed8d4d46c759183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Sun, 20 Aug 2023 18:52:26 +0200 Subject: [PATCH 04/11] Find any icon WIP inheritance. Apply exact sizes and background color from adwaita. WIP listenIconThemeChanges from dbus --- .../CustomFrameTitleButtons.kt | 4 +- .../LinuxLookAndFeel.kt | 49 +++++++++++++++++-- .../LinuxFrameTitleButtons.kt | 18 ++++--- .../header/DialogHeader.kt | 1 - 4 files changed, 60 insertions(+), 12 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt index 03ec4916c2406..71f1a6678204b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt @@ -194,9 +194,9 @@ private class TitleButtonsPanel : JPanel(FlowLayout(FlowLayout.LEADING, 0, 0)) { } if (SystemInfo.isLinux) { if (this !is Box) { - preferredSize = Dimension(36, 36) + preferredSize = Dimension(38, size.height) } else { - preferredSize = Dimension(2, size.height) // Margin right + preferredSize = Dimension(1, size.height) // Margin right } } else { preferredSize = Dimension(size.width, size.height) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt index 7f1476efd828f..68d963f118512 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt @@ -3,11 +3,19 @@ package com.intellij.openapi.wm.impl.customFrameDecorations import java.io.BufferedReader import java.io.InputStreamReader +import kotlin.concurrent.thread + class LinuxLookAndFeel { companion object { + fun findIconAbsolutePath(iconName: String): String? { + val iconTheme = getIconTheme() ?: return null + val command = "find /usr/share/icons/$iconTheme -type f -name $iconName" + return execute(command) + } + fun getIconTheme(): String? { - return getDconfEntry("/org/gnome/desktop/interface/icon-theme") + return getDconfEntry("/org/gnome/desktop/interface/icon-theme")?.drop(1)?.dropLast(1) } fun getHeaderLayout(): List { @@ -29,10 +37,45 @@ class LinuxLookAndFeel { val process = processBuilder.start() val reader = BufferedReader(InputStreamReader(process.inputStream)) - val line: String? = reader.readLine() // Leer la primera línea - val exitCode = process.waitFor() + val line: String? = reader.readLine() + process.waitFor() return line } + + private fun listenIconThemeChanges() { + thread(start = true) { + val processBuilder = ProcessBuilder(listOf("dbus-monitor", "member='Notify'")) + processBuilder.redirectErrorStream(true) + + val process = processBuilder.start() + val reader = BufferedReader(InputStreamReader(process.inputStream)) + + + Runtime.getRuntime().addShutdownHook(Thread { + reader.close() + process.destroy() + }) + + var line: String + + while (true) { + line = reader.readLine() + if (line.contains("/org/gnome/desktop/interface/icon-theme")) { + println("Theme changed!!!") + subscribers.forEach {it()} + } + } + } + } + + private val subscribers = mutableListOf<() -> Unit>() + fun onIconThemeChanges(callback: () -> Unit) { + subscribers.add(callback) + } + + init { + //listenIconThemeChanges() + } } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt index 5868d17a0d916..4b3660720e446 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt @@ -3,6 +3,7 @@ package com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons import com.intellij.icons.AllIcons import com.intellij.openapi.wm.impl.customFrameDecorations.LinuxLookAndFeel +import com.intellij.openapi.wm.impl.customFrameDecorations.LinuxLookAndFeel.Companion.findIconAbsolutePath import com.intellij.openapi.wm.impl.customFrameDecorations.style.HOVER_KEY import com.intellij.ui.IconManager import com.intellij.ui.JBColor @@ -33,7 +34,7 @@ class LinuxFrameTitleButtons( override val restoreIcon = restore override val restoreInactiveIcon = restore - val maximize = loadLinuxIcon("window-maximize-symbolic") + val maximize = loadLinuxIcon("window-maximize-symbolic.svg") override val maximizeIcon = maximize override val maximizeInactiveIcon = maximize @@ -59,7 +60,6 @@ class LinuxFrameTitleButtons( button.isFocusable = false button.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName) button.text = null - //button.preferredSize = Dimension(5, 5) println("====================================") println("====================================") @@ -77,10 +77,13 @@ class LinuxFrameTitleButtons( private fun loadLinuxIcon(iconName: String): Icon { + /*val iconThemeName = LinuxLookAndFeel.getIconTheme() + find /usr/share/icons -type f -name "window-maximize-symbolic.svg" val themeAdwaita = "Adwaita/scalable/ui/" // Adwaita val themeYaru = "Yaru/scalable/ui/" // Yaru - val themePapirus = "Papirus/symbolic/actions/" // Papirus - var icon = IconManager.getInstance().getIcon("file:/usr/share/icons/$themePapirus$iconName", + val themePapirus = "Papirus/symbolic/actions/" // Papirus*/ + val iconPath = findIconAbsolutePath(iconName) + var icon = IconManager.getInstance().getIcon("file:$iconPath", AllIcons::class.java.classLoader) icon = IconUtil.colorizeReplace(icon, JBColor(0x6c7080, 0xcfd1d8)) return icon @@ -89,11 +92,14 @@ class LinuxFrameTitleButtons( private class HoveredCircleButtonUI : BasicButtonUI() { + // Adwaita background circle: + // - light theme: rgba(0, 0, 0, 0.08) -> 20.40 + // - dark theme: rgba(255, 255, 255, 0.1) -> 25.5 private val circleDiameter = 24 override fun paint(g: Graphics, c: JComponent) { - g.color = Color(0x434343) + g.color = JBColor(Color(0f, 0f, 0f, 0.1f), Color(1f, 1f, 1f, 0.08f)) getHoverColor(c)?.let { - g.color = Color(0x4e4e4e) + g.color = JBColor(Color(0f, 0f, 0f, 0.1f + 0.05f), Color(1f, 1f, 1f, 0.08f + 0.05f)) //g.fillRect(0, 0, c.width, c.height) } if (g is Graphics2D) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt index 2a73e59f3de11..1e34b86592507 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/DialogHeader.kt @@ -88,7 +88,6 @@ internal class DialogHeader(window: Window) : CustomHeader(window) { } private fun createButtonsPane(): CustomFrameTitleButtons? { - //return null // TODO Arreglar return if (IdeRootPane.hideNativeLinuxTitle) CustomFrameTitleButtons.create(createCloseAction(this)) else null } } \ No newline at end of file From c32270afde3faefc9405fcfaa729b0e2820ef42f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Tue, 22 Aug 2023 19:16:08 +0200 Subject: [PATCH 05/11] Buttons background adapts correctly to current theme --- .../LinuxFrameTitleButtons.kt | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt index 4b3660720e446..8af475b11b23c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt @@ -2,6 +2,7 @@ package com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons import com.intellij.icons.AllIcons +import com.intellij.ide.ui.LafManager import com.intellij.openapi.wm.impl.customFrameDecorations.LinuxLookAndFeel import com.intellij.openapi.wm.impl.customFrameDecorations.LinuxLookAndFeel.Companion.findIconAbsolutePath import com.intellij.openapi.wm.impl.customFrameDecorations.style.HOVER_KEY @@ -91,17 +92,28 @@ class LinuxFrameTitleButtons( } +// Can not use JBColor because title frame can use a dark background in Light theme +@Suppress("UseJBColor") private class HoveredCircleButtonUI : BasicButtonUI() { + private val circleDiameter = 24 + // Adwaita background circle: // - light theme: rgba(0, 0, 0, 0.08) -> 20.40 // - dark theme: rgba(255, 255, 255, 0.1) -> 25.5 - private val circleDiameter = 24 + private val circleLightBackground = Color(1f, 1f, 1f, 0.08f) + private val circleDarkBackground = Color(0f, 0f, 0f, 0.1f) + override fun paint(g: Graphics, c: JComponent) { - g.color = JBColor(Color(0f, 0f, 0f, 0.1f), Color(1f, 1f, 1f, 0.08f)) + val isLightBackground = with(LafManager.getInstance().currentLookAndFeel.name) { + this == "Light with Light Header" || this == "IntelliJ Light" + } + val backgroundColor = if (isLightBackground) circleDarkBackground else circleLightBackground + + g.color = backgroundColor getHoverColor(c)?.let { - g.color = JBColor(Color(0f, 0f, 0f, 0.1f + 0.05f), Color(1f, 1f, 1f, 0.08f + 0.05f)) - //g.fillRect(0, 0, c.width, c.height) + g.color = alterAlpha(backgroundColor, 0.05f) } + if (g is Graphics2D) { g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) g.fillRoundRect((c.width / 2) - (circleDiameter / 2), (c.height / 2) - (circleDiameter / 2), circleDiameter, circleDiameter, c.width, c.height) @@ -110,5 +122,9 @@ private class HoveredCircleButtonUI : BasicButtonUI() { } private fun getHoverColor(c: JComponent): Color? = c.getClientProperty(HOVER_KEY) as? Color + + private fun alterAlpha(color: Color, amount: Float): Color { + return Color(color.red, color.green, color.blue, (((color.alpha.toFloat() / 256f) + amount) * 256).toInt()) + } } From 015527576cd44ead8db88035162ef79c0fefe556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Thu, 24 Aug 2023 19:40:47 +0200 Subject: [PATCH 06/11] Added ide.linux.mimic.system.theme registry key. More refactoring: separate windows and linux custom code --- .../CustomFrameTitleButtons.kt | 58 +++++------------ .../LinuxLookAndFeel.kt | 13 ++++ .../frameTitleButtons/FrameTitleButtons.kt | 4 ++ .../LinuxFrameTitleButtons.kt | 65 ++++++++----------- .../WindowsFrameTitleButtons.kt | 16 ++++- .../util/resources/misc/registry.properties | 4 ++ 6 files changed, 77 insertions(+), 83 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt index 71f1a6678204b..00caa4bcfa25f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt @@ -3,6 +3,7 @@ package com.intellij.openapi.wm.impl.customFrameDecorations import com.intellij.ide.ui.UISettings import com.intellij.openapi.util.SystemInfo +import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons.FrameTitleButtons import com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons.LinuxFrameTitleButtons import com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons.WindowsFrameTitleButtons @@ -14,7 +15,10 @@ import com.intellij.util.ui.JBUI.Borders import com.intellij.util.ui.JBUI.CurrentTheme import java.awt.Dimension import java.awt.FlowLayout -import javax.swing.* +import javax.swing.Action +import javax.swing.Icon +import javax.swing.JComponent +import javax.swing.JPanel internal open class CustomFrameTitleButtons(private val myCloseAction: Action, @@ -33,7 +37,9 @@ internal open class CustomFrameTitleButtons(private val myCloseAction: Action, } } - private val buttons: FrameTitleButtons = if (SystemInfo.isWindows) + private val isLinuxThemingEnabled = Registry.`is`("ide.linux.mimic.system.theme", false) + + private val buttons: FrameTitleButtons = if (SystemInfo.isWindows || !isLinuxThemingEnabled) WindowsFrameTitleButtons(myCloseAction, myRestoreAction, myIconifyAction, myMaximizeAction) else LinuxFrameTitleButtons(myCloseAction, myRestoreAction, myIconifyAction, myMaximizeAction) @@ -52,7 +58,9 @@ internal open class CustomFrameTitleButtons(private val myCloseAction: Action, } - private val panel = TitleButtonsPanel() + private val panel = TitleButtonsPanel(buttons) + + fun getView(): JComponent = panel internal var isCompactMode: Boolean @@ -109,39 +117,11 @@ internal open class CustomFrameTitleButtons(private val myCloseAction: Action, } protected fun createChildren() { - fillButtonPane() + buttons.fillButtonPane(panel) updateVisibility() updateStyles() } - fun getView(): JComponent = panel - - protected open fun fillButtonPane() { - if (SystemInfo.isLinux) { - var linuxButtonsLayout = LinuxLookAndFeel.getHeaderLayout() - if (!linuxButtonsLayout.contains("close")) { - linuxButtonsLayout = linuxButtonsLayout.plus("close") - } - for (item in linuxButtonsLayout) { - when (item) { - "minimize" -> buttons.minimizeButton?.let { panel.addComponent(it) } - "maximize" -> { - buttons.maximizeButton?.let { panel.addComponent(it) } - buttons.restoreButton?.let { panel.addComponent(it) } - } - "close" -> panel.addComponent(buttons.closeButton) - } - } - val emptyComponent: Box = Box.createHorizontalBox() // Margin right - panel.addComponent(emptyComponent) - } else { - buttons.minimizeButton?.let { panel.addComponent(it) } - buttons.maximizeButton?.let { panel.addComponent(it) } - buttons.restoreButton?.let { panel.addComponent(it) } - panel.addComponent(buttons.closeButton) - } - } - open fun updateVisibility() { buttons.minimizeButton?.isVisible = myIconifyAction?.isEnabled ?: false buttons.restoreButton?.isVisible = myRestoreAction?.isEnabled ?: false @@ -166,7 +146,7 @@ internal open class CustomFrameTitleButtons(private val myCloseAction: Action, } -private class TitleButtonsPanel : JPanel(FlowLayout(FlowLayout.LEADING, 0, 0)) { +class TitleButtonsPanel(val buttons: FrameTitleButtons) : JPanel(FlowLayout(FlowLayout.LEADING, 0, 0)) { var isCompactMode = false set(value) { field = value @@ -188,19 +168,11 @@ private class TitleButtonsPanel : JPanel(FlowLayout(FlowLayout.LEADING, 0, 0)) { private fun JComponent.setScaledPreferredSize() { val size = CurrentTheme.TitlePane.buttonPreferredSize(UISettings.defFontScale).clone() as Dimension - // TODO isCompactMode siempre es false, parece un bug + // TODO isCompactMode is always false if (isCompactMode) { size.height = JBUIScale.scale(30) } - if (SystemInfo.isLinux) { - if (this !is Box) { - preferredSize = Dimension(38, size.height) - } else { - preferredSize = Dimension(1, size.height) // Margin right - } - } else { - preferredSize = Dimension(size.width, size.height) - } + preferredSize = buttons.setScaledPreferredSize(size) } override fun updateUI() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt index 68d963f118512..a45365525de9a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt @@ -1,13 +1,26 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations +import com.intellij.icons.AllIcons +import com.intellij.ui.IconManager +import com.intellij.ui.JBColor +import com.intellij.util.IconUtil import java.io.BufferedReader import java.io.InputStreamReader +import javax.swing.Icon import kotlin.concurrent.thread class LinuxLookAndFeel { companion object { + fun getLinuxIcon(iconName: String): Icon { + val iconPath = findIconAbsolutePath(iconName) + var icon = IconManager.getInstance().getIcon("file:$iconPath", + AllIcons::class.java.classLoader) + icon = IconUtil.colorizeReplace(icon, JBColor(0x6c7080, 0xcfd1d8)) + return icon + } + fun findIconAbsolutePath(iconName: String): String? { val iconTheme = getIconTheme() ?: return null val command = "find /usr/share/icons/$iconTheme -type f -name $iconName" diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/FrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/FrameTitleButtons.kt index 8c35fcc0b919c..bb57c504ec47e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/FrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/FrameTitleButtons.kt @@ -1,6 +1,8 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons +import com.intellij.openapi.wm.impl.customFrameDecorations.TitleButtonsPanel +import java.awt.Dimension import javax.swing.Action import javax.swing.Icon import javax.swing.JButton @@ -25,4 +27,6 @@ interface FrameTitleButtons { val closeHoverIcon: Icon fun createButton(accessibleName: String, action: Action): JButton + fun fillButtonPane(panel: TitleButtonsPanel) + fun setScaledPreferredSize(size: Dimension): Dimension } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt index 8af475b11b23c..acaec8a48abdc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt @@ -1,26 +1,20 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons -import com.intellij.icons.AllIcons import com.intellij.ide.ui.LafManager import com.intellij.openapi.wm.impl.customFrameDecorations.LinuxLookAndFeel -import com.intellij.openapi.wm.impl.customFrameDecorations.LinuxLookAndFeel.Companion.findIconAbsolutePath +import com.intellij.openapi.wm.impl.customFrameDecorations.TitleButtonsPanel import com.intellij.openapi.wm.impl.customFrameDecorations.style.HOVER_KEY -import com.intellij.ui.IconManager -import com.intellij.ui.JBColor -import com.intellij.util.IconUtil -import java.awt.Color -import java.awt.Graphics -import java.awt.Graphics2D -import java.awt.RenderingHints +import com.intellij.util.ui.JBUI +import java.awt.* import javax.accessibility.AccessibleContext import javax.swing.Action -import javax.swing.Icon import javax.swing.JButton import javax.swing.JComponent import javax.swing.plaf.ButtonUI import javax.swing.plaf.basic.BasicButtonUI + class LinuxFrameTitleButtons( myCloseAction: Action, myRestoreAction: Action? = null, @@ -31,19 +25,19 @@ class LinuxFrameTitleButtons( override val maximizeButton: JButton? = myMaximizeAction?.let { createButton("Maximize", it) } override val minimizeButton: JButton? = myIconifyAction?.let { createButton("Iconify", it) } - val restore = loadLinuxIcon("window-restore-symbolic.svg") + val restore = LinuxLookAndFeel.getLinuxIcon("window-restore-symbolic.svg") override val restoreIcon = restore override val restoreInactiveIcon = restore - val maximize = loadLinuxIcon("window-maximize-symbolic.svg") + val maximize = LinuxLookAndFeel.getLinuxIcon("window-maximize-symbolic.svg") override val maximizeIcon = maximize override val maximizeInactiveIcon = maximize - val minimize = loadLinuxIcon("window-minimize-symbolic.svg") + val minimize = LinuxLookAndFeel.getLinuxIcon("window-minimize-symbolic.svg") override val minimizeIcon = minimize override val minimizeInactiveIcon = minimize - val close = loadLinuxIcon("window-close-symbolic.svg") + val close = LinuxLookAndFeel.getLinuxIcon("window-close-symbolic.svg") override val closeIcon = close override val closeInactiveIcon = close override val closeHoverIcon = close @@ -61,33 +55,30 @@ class LinuxFrameTitleButtons( button.isFocusable = false button.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName) button.text = null - - println("====================================") - println("====================================") - println("====================================") - println("====================================") - println(LinuxLookAndFeel.getIconTheme()) - println(LinuxLookAndFeel.getHeaderLayout()) - println("====================================") - println("====================================") - println("====================================") - println("====================================") - return button } + override fun fillButtonPane(panel: TitleButtonsPanel) { + var linuxButtonsLayout = LinuxLookAndFeel.getHeaderLayout() + if (!linuxButtonsLayout.contains("close")) { + linuxButtonsLayout = linuxButtonsLayout.plus("close") + } + for (item in linuxButtonsLayout) { + when (item) { + "minimize" -> this.minimizeButton?.let { panel.addComponent(it) } + "maximize" -> { + this.maximizeButton?.let { panel.addComponent(it) } + this.restoreButton?.let { panel.addComponent(it) } + } + "close" -> panel.addComponent(this.closeButton) + } + } + panel.border = JBUI.Borders.emptyRight(1) + } + - private fun loadLinuxIcon(iconName: String): Icon { - /*val iconThemeName = LinuxLookAndFeel.getIconTheme() - find /usr/share/icons -type f -name "window-maximize-symbolic.svg" - val themeAdwaita = "Adwaita/scalable/ui/" // Adwaita - val themeYaru = "Yaru/scalable/ui/" // Yaru - val themePapirus = "Papirus/symbolic/actions/" // Papirus*/ - val iconPath = findIconAbsolutePath(iconName) - var icon = IconManager.getInstance().getIcon("file:$iconPath", - AllIcons::class.java.classLoader) - icon = IconUtil.colorizeReplace(icon, JBColor(0x6c7080, 0xcfd1d8)) - return icon + override fun setScaledPreferredSize(size: Dimension): Dimension { + return Dimension(38, size.height) } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt index 86dffe21f83f3..94e3120984761 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/WindowsFrameTitleButtons.kt @@ -2,13 +2,12 @@ package com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons import com.intellij.icons.AllIcons -import com.intellij.openapi.wm.impl.customFrameDecorations.style.ComponentStyle -import com.intellij.openapi.wm.impl.customFrameDecorations.style.ComponentStyleState +import com.intellij.openapi.wm.impl.customFrameDecorations.TitleButtonsPanel import com.intellij.openapi.wm.impl.customFrameDecorations.style.HOVER_KEY import com.intellij.ui.JBColor import com.intellij.util.IconUtil -import com.intellij.util.ui.JBUI import java.awt.Color +import java.awt.Dimension import java.awt.Graphics import javax.accessibility.AccessibleContext import javax.swing.Action @@ -56,6 +55,17 @@ class WindowsFrameTitleButtons( button.text = null return button } + + override fun fillButtonPane(panel: TitleButtonsPanel) { + this.minimizeButton?.let { panel.addComponent(it) } + this.maximizeButton?.let { panel.addComponent(it) } + this.restoreButton?.let { panel.addComponent(it) } + panel.addComponent(this.closeButton) + } + + override fun setScaledPreferredSize(size: Dimension): Dimension { + return Dimension(size.width, size.height) + } } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 8be3b9c5ba35c..a903dc742d9fc 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -1930,6 +1930,10 @@ ide.linux.use.undecorated.border=true ide.linux.use.undecorated.border.description=Enables undecorated border for windows, see Window.undecorated.border theme property ide.linux.use.undecorated.border.restartRequired=true +ide.linux.mimic.system.theme=false +ide.linux.mimic.system.theme.description=Mimics linux look and feel +ide.linux.mimic.system.theme.restartRequired=true + ide.tree.large.model.allowed=false ide.tree.large.model.allowed.description=Allows to use FixedHeightLayoutCache if setLargeModel(true) From 13e2c3032873fe33fa4335e85cb0225263f95e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Thu, 24 Aug 2023 20:12:58 +0200 Subject: [PATCH 07/11] Update listening icon theme changes --- .../wm/impl/customFrameDecorations/LinuxLookAndFeel.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt index a45365525de9a..07e1fb862c751 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt @@ -56,7 +56,10 @@ class LinuxLookAndFeel { return line } + private var isListeningIconThemeChanges = false private fun listenIconThemeChanges() { + if (isListeningIconThemeChanges) return + isListeningIconThemeChanges = true thread(start = true) { val processBuilder = ProcessBuilder(listOf("dbus-monitor", "member='Notify'")) processBuilder.redirectErrorStream(true) @@ -84,11 +87,8 @@ class LinuxLookAndFeel { private val subscribers = mutableListOf<() -> Unit>() fun onIconThemeChanges(callback: () -> Unit) { + listenIconThemeChanges() subscribers.add(callback) } - - init { - //listenIconThemeChanges() - } } } \ No newline at end of file From 6f8b8bf5d522daf6f48f1ac796d56c8d182544f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Sat, 26 Aug 2023 19:45:16 +0200 Subject: [PATCH 08/11] Find inherit themes when no icons found. Prefer 16x16 icons. Use windows icons if no icons found --- .../LinuxLookAndFeel.kt | 62 +++++++++++++++++-- .../LinuxFrameTitleButtons.kt | 11 ++-- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt index 07e1fb862c751..e635f2ba2e1b9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt @@ -6,6 +6,7 @@ import com.intellij.ui.IconManager import com.intellij.ui.JBColor import com.intellij.util.IconUtil import java.io.BufferedReader +import java.io.File import java.io.InputStreamReader import javax.swing.Icon import kotlin.concurrent.thread @@ -13,21 +14,70 @@ import kotlin.concurrent.thread class LinuxLookAndFeel { companion object { - fun getLinuxIcon(iconName: String): Icon { + val linuxIconPath = "/usr/share/icons" + fun getLinuxIcon(iconName: String): Icon? { val iconPath = findIconAbsolutePath(iconName) + if (iconPath.isNullOrEmpty()) + return null + var icon = IconManager.getInstance().getIcon("file:$iconPath", AllIcons::class.java.classLoader) icon = IconUtil.colorizeReplace(icon, JBColor(0x6c7080, 0xcfd1d8)) return icon } - fun findIconAbsolutePath(iconName: String): String? { - val iconTheme = getIconTheme() ?: return null - val command = "find /usr/share/icons/$iconTheme -type f -name $iconName" - return execute(command) + fun findIconAbsolutePath(iconName: String, useOtherTheme: String? = null, recursiveDepth: Int = 0): String? { + val themeName = useOtherTheme ?: getCurrentIconTheme() ?: return null + + val themePath = "$linuxIconPath/$themeName" + + // Prefer first find in 16x16 subfolder + var iconPath = execute("find $themePath/16x16 -type f -name $iconName") + if (isValidIconPath(iconPath)) + return iconPath + + // If no icons found, found anywhere + iconPath = execute("find $themePath -type f -name $iconName") + if (isValidIconPath(iconPath)) + return iconPath + + + if (recursiveDepth > 10) return null + + // If no icon found, then find icons in theme inheritance + for (inheritIconTheme in getInheritedIconThemes(themeName)) { + iconPath = findIconAbsolutePath(iconName, inheritIconTheme, recursiveDepth + 1) + if (isValidIconPath(iconPath)) + return iconPath + } + + return null + } + + private fun isValidIconPath(iconPath: String?): Boolean { + return !iconPath.isNullOrEmpty() && iconPath.startsWith(linuxIconPath) + } + + fun getInheritedIconThemes(themeName: String): List { + try{ + val themePath = "$linuxIconPath/$themeName" + val themeConfigFile = File("$themePath/index.theme") + val inheritanceString = "Inherits=" + if (themeConfigFile.exists()) { + val lines = themeConfigFile.readLines() + for (line in lines) { + if (line.startsWith(inheritanceString)) { + return line.substringAfter(inheritanceString).split(",").map{it.trim()} + } + } + } + return listOf() + } catch (error: Exception) { + return listOf() + } } - fun getIconTheme(): String? { + fun getCurrentIconTheme(): String? { return getDconfEntry("/org/gnome/desktop/interface/icon-theme")?.drop(1)?.dropLast(1) } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt index acaec8a48abdc..c41175d182d0e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt @@ -1,6 +1,7 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons +import com.intellij.icons.AllIcons import com.intellij.ide.ui.LafManager import com.intellij.openapi.wm.impl.customFrameDecorations.LinuxLookAndFeel import com.intellij.openapi.wm.impl.customFrameDecorations.TitleButtonsPanel @@ -25,19 +26,21 @@ class LinuxFrameTitleButtons( override val maximizeButton: JButton? = myMaximizeAction?.let { createButton("Maximize", it) } override val minimizeButton: JButton? = myIconifyAction?.let { createButton("Iconify", it) } - val restore = LinuxLookAndFeel.getLinuxIcon("window-restore-symbolic.svg") + + + val restore = LinuxLookAndFeel.getLinuxIcon("window-restore-symbolic.svg") ?: AllIcons.Windows.Restore override val restoreIcon = restore override val restoreInactiveIcon = restore - val maximize = LinuxLookAndFeel.getLinuxIcon("window-maximize-symbolic.svg") + val maximize = LinuxLookAndFeel.getLinuxIcon("window-maximize-symbolic.svg") ?: AllIcons.Windows.Maximize override val maximizeIcon = maximize override val maximizeInactiveIcon = maximize - val minimize = LinuxLookAndFeel.getLinuxIcon("window-minimize-symbolic.svg") + val minimize = LinuxLookAndFeel.getLinuxIcon("window-minimize-symbolic.svg") ?: AllIcons.Windows.Minimize override val minimizeIcon = minimize override val minimizeInactiveIcon = minimize - val close = LinuxLookAndFeel.getLinuxIcon("window-close-symbolic.svg") + val close = LinuxLookAndFeel.getLinuxIcon("window-close-symbolic.svg") ?: AllIcons.Windows.CloseActive override val closeIcon = close override val closeInactiveIcon = close override val closeHoverIcon = close From 5437b5be954f961719d62bc6a373fc497a456b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Sat, 23 Sep 2023 16:32:18 +0200 Subject: [PATCH 09/11] KDE approaching --- .../CustomFrameTitleButtons.kt | 12 ++- .../LinuxLookAndFeel.kt | 93 ++++++++++++++----- .../LinuxFrameTitleButtons.kt | 51 +++++++--- 3 files changed, 119 insertions(+), 37 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt index 00caa4bcfa25f..44404d5c5d42f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/CustomFrameTitleButtons.kt @@ -4,6 +4,7 @@ package com.intellij.openapi.wm.impl.customFrameDecorations import com.intellij.ide.ui.UISettings import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.registry.Registry +import com.intellij.openapi.wm.impl.X11UiUtil import com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons.FrameTitleButtons import com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons.LinuxFrameTitleButtons import com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons.WindowsFrameTitleButtons @@ -39,10 +40,15 @@ internal open class CustomFrameTitleButtons(private val myCloseAction: Action, private val isLinuxThemingEnabled = Registry.`is`("ide.linux.mimic.system.theme", false) - private val buttons: FrameTitleButtons = if (SystemInfo.isWindows || !isLinuxThemingEnabled) - WindowsFrameTitleButtons(myCloseAction, myRestoreAction, myIconifyAction, myMaximizeAction) - else + private val buttons: FrameTitleButtons = if ( + SystemInfo.isLinux && + (SystemInfo.isGNOME || SystemInfo.isKDE) && + isLinuxThemingEnabled && + !X11UiUtil.isWSL() + ) LinuxFrameTitleButtons(myCloseAction, myRestoreAction, myIconifyAction, myMaximizeAction) + else + WindowsFrameTitleButtons(myCloseAction, myRestoreAction, myIconifyAction, myMaximizeAction) private val baseStyle = ComponentStyle.ComponentStyleBuilder { isOpaque = false diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt index e635f2ba2e1b9..1081b1d463bb3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt @@ -2,6 +2,7 @@ package com.intellij.openapi.wm.impl.customFrameDecorations import com.intellij.icons.AllIcons +import com.intellij.openapi.util.SystemInfo import com.intellij.ui.IconManager import com.intellij.ui.JBColor import com.intellij.util.IconUtil @@ -15,11 +16,30 @@ import kotlin.concurrent.thread class LinuxLookAndFeel { companion object { val linuxIconPath = "/usr/share/icons" - fun getLinuxIcon(iconName: String): Icon? { - val iconPath = findIconAbsolutePath(iconName) - if (iconPath.isNullOrEmpty()) - return null + fun getLinuxIcon(name: WindowToolbarIcons): Icon? { + val iconName: String + var iconPath: String? = null + if (SystemInfo.isGNOME) { + iconName = when (name) { + WindowToolbarIcons.CLOSE -> "window-close-symbolic.svg" + WindowToolbarIcons.MAXIMIZE -> "window-maximize-symbolic.svg" + WindowToolbarIcons.RESTORE -> "window-restore-symbolic.svg" + WindowToolbarIcons.MINIMIZE -> "window-minimize-symbolic.svg" + } + iconPath = findIconAbsolutePath(iconName) + } + else if (SystemInfo.isKDE) { + iconName = when (name) { + WindowToolbarIcons.CLOSE -> "close-normal.svg" + WindowToolbarIcons.MAXIMIZE -> "maximize-normal.svg" + WindowToolbarIcons.RESTORE -> "maximized-normal.svg" + WindowToolbarIcons.MINIMIZE -> "minimize-normal.svg" + } + iconPath = "\$HOME/.config/gtk-3.0/assets/$iconName" + } + + if (iconPath.isNullOrEmpty()) return null var icon = IconManager.getInstance().getIcon("file:$iconPath", AllIcons::class.java.classLoader) icon = IconUtil.colorizeReplace(icon, JBColor(0x6c7080, 0xcfd1d8)) @@ -59,7 +79,7 @@ class LinuxLookAndFeel { } fun getInheritedIconThemes(themeName: String): List { - try{ + try { val themePath = "$linuxIconPath/$themeName" val themeConfigFile = File("$themePath/index.theme") val inheritanceString = "Inherits=" @@ -67,26 +87,47 @@ class LinuxLookAndFeel { val lines = themeConfigFile.readLines() for (line in lines) { if (line.startsWith(inheritanceString)) { - return line.substringAfter(inheritanceString).split(",").map{it.trim()} + return line.substringAfter(inheritanceString).split(",").map { it.trim() } } } } return listOf() - } catch (error: Exception) { + } + catch (exception: Exception) { return listOf() } } fun getCurrentIconTheme(): String? { - return getDconfEntry("/org/gnome/desktop/interface/icon-theme")?.drop(1)?.dropLast(1) + return getDconfEntry("/org/gnome/desktop/interface/icon-theme")?.drop(1)?.dropLast(1) // Remove double quotes } fun getHeaderLayout(): List { - // Next line returns something like appmenu:minimize,maximize,close - var elementsString = getDconfEntry("/org/gnome/desktop/wm/preferences/button-layout") - elementsString = elementsString?.drop(1)?.dropLast(1) - val elements = elementsString?.split(":", ",") - return elements ?: emptyList() + try { + if (SystemInfo.isGNOME) { + // Next line returns something like appmenu:minimize,maximize,close + var elementsString = getDconfEntry("/org/gnome/desktop/wm/preferences/button-layout") + elementsString = elementsString?.drop(1)?.dropLast(1) // Remove double quotes + return elementsString?.split(":", ",") ?: emptyList() + } + else if (SystemInfo.isKDE) { + val gtk3ConfigFile = File("\$HOME/.config/gtk-3.0/settings.ini") + val paramName = "gtk-decoration-layout=" + if (gtk3ConfigFile.exists()) { + val lines = gtk3ConfigFile.readLines() + for (line in lines) { + if (line.startsWith(paramName)) { + // Next line returns something like icon:minimize,maximize,close + return line.substringAfter(paramName).split(":", ",").map { it.trim() } + } + } + } + } + } + catch (exception: Exception) { + exception.printStackTrace() + } + return emptyList() } private fun getDconfEntry(key: String): String? { @@ -94,16 +135,22 @@ class LinuxLookAndFeel { } private fun execute(command: String): String? { - val processBuilder = ProcessBuilder(command.split(" ")) - processBuilder.redirectErrorStream(true) + try { + val processBuilder = ProcessBuilder(command.split(" ")) + processBuilder.redirectErrorStream(true) - val process = processBuilder.start() - val reader = BufferedReader(InputStreamReader(process.inputStream)) + val process = processBuilder.start() + val reader = BufferedReader(InputStreamReader(process.inputStream)) - val line: String? = reader.readLine() - process.waitFor() + val line: String? = reader.readLine() + process.waitFor() - return line + return line + } + catch (exception: Exception) { + exception.printStackTrace() + } + return null } private var isListeningIconThemeChanges = false @@ -129,7 +176,7 @@ class LinuxLookAndFeel { line = reader.readLine() if (line.contains("/org/gnome/desktop/interface/icon-theme")) { println("Theme changed!!!") - subscribers.forEach {it()} + subscribers.forEach { it() } } } } @@ -141,4 +188,8 @@ class LinuxLookAndFeel { subscribers.add(callback) } } +} + +enum class WindowToolbarIcons { + MAXIMIZE, MINIMIZE, RESTORE, CLOSE } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt index c41175d182d0e..e2e35da827837 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt @@ -3,8 +3,10 @@ package com.intellij.openapi.wm.impl.customFrameDecorations.frameTitleButtons import com.intellij.icons.AllIcons import com.intellij.ide.ui.LafManager +import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.wm.impl.customFrameDecorations.LinuxLookAndFeel import com.intellij.openapi.wm.impl.customFrameDecorations.TitleButtonsPanel +import com.intellij.openapi.wm.impl.customFrameDecorations.WindowToolbarIcons import com.intellij.openapi.wm.impl.customFrameDecorations.style.HOVER_KEY import com.intellij.util.ui.JBUI import java.awt.* @@ -28,19 +30,19 @@ class LinuxFrameTitleButtons( - val restore = LinuxLookAndFeel.getLinuxIcon("window-restore-symbolic.svg") ?: AllIcons.Windows.Restore + val restore = LinuxLookAndFeel.getLinuxIcon(WindowToolbarIcons.RESTORE) ?: AllIcons.Windows.Restore override val restoreIcon = restore override val restoreInactiveIcon = restore - val maximize = LinuxLookAndFeel.getLinuxIcon("window-maximize-symbolic.svg") ?: AllIcons.Windows.Maximize + val maximize = LinuxLookAndFeel.getLinuxIcon(WindowToolbarIcons.MAXIMIZE) ?: AllIcons.Windows.Maximize override val maximizeIcon = maximize override val maximizeInactiveIcon = maximize - val minimize = LinuxLookAndFeel.getLinuxIcon("window-minimize-symbolic.svg") ?: AllIcons.Windows.Minimize + val minimize = LinuxLookAndFeel.getLinuxIcon(WindowToolbarIcons.MINIMIZE) ?: AllIcons.Windows.Minimize override val minimizeIcon = minimize override val minimizeInactiveIcon = minimize - val close = LinuxLookAndFeel.getLinuxIcon("window-close-symbolic.svg") ?: AllIcons.Windows.CloseActive + val close = LinuxLookAndFeel.getLinuxIcon(WindowToolbarIcons.CLOSE) ?: AllIcons.Windows.CloseActive override val closeIcon = close override val closeInactiveIcon = close override val closeHoverIcon = close @@ -48,7 +50,7 @@ class LinuxFrameTitleButtons( override fun createButton(accessibleName: String, action: Action): JButton { val button = object : JButton() { init { - super.setUI(HoveredCircleButtonUI()) + super.setUI(HoveredCircleButtonUI(accessibleName)) } override fun setUI(ui: ButtonUI?) { @@ -63,6 +65,9 @@ class LinuxFrameTitleButtons( override fun fillButtonPane(panel: TitleButtonsPanel) { var linuxButtonsLayout = LinuxLookAndFeel.getHeaderLayout() + if (linuxButtonsLayout.isEmpty()) { + linuxButtonsLayout = listOf("minimize", "maximize", "close") + } if (!linuxButtonsLayout.contains("close")) { linuxButtonsLayout = linuxButtonsLayout.plus("close") } @@ -88,26 +93,46 @@ class LinuxFrameTitleButtons( // Can not use JBColor because title frame can use a dark background in Light theme @Suppress("UseJBColor") -private class HoveredCircleButtonUI : BasicButtonUI() { +private class HoveredCircleButtonUI(val accessibleName: String) : BasicButtonUI() { private val circleDiameter = 24 - // Adwaita background circle: + // Adwaita GTK background circle: // - light theme: rgba(0, 0, 0, 0.08) -> 20.40 // - dark theme: rgba(255, 255, 255, 0.1) -> 25.5 private val circleLightBackground = Color(1f, 1f, 1f, 0.08f) private val circleDarkBackground = Color(0f, 0f, 0f, 0.1f) + // Breeze KDE background circle + private val circleTransparent = Color(0f, 0f, 0f, 0f) + private val circleRedHover = Color(1f, 0.572f, 0.638f, 1f) + private val circleDarkHover = Color(0.114f, 0.129f, 0.144f, 1f) + private val circleLightHover = Color(0.989f, 0.989f, 0.989f, 1f) + override fun paint(g: Graphics, c: JComponent) { - val isLightBackground = with(LafManager.getInstance().currentLookAndFeel.name) { + val isLightBackground = with(LafManager.getInstance().currentUIThemeLookAndFeel.name) { this == "Light with Light Header" || this == "IntelliJ Light" } - val backgroundColor = if (isLightBackground) circleDarkBackground else circleLightBackground + if (SystemInfo.isKDE) { + g.color = circleTransparent + getHoverColor(c)?.let { + g.color = if (accessibleName == "Close") { + circleRedHover + } else { + if (isLightBackground) { + circleDarkHover + } else { + circleLightHover + } + } + } + } else { + val backgroundColor = if (isLightBackground) circleDarkBackground else circleLightBackground - g.color = backgroundColor - getHoverColor(c)?.let { - g.color = alterAlpha(backgroundColor, 0.05f) + g.color = backgroundColor + getHoverColor(c)?.let { + g.color = alterAlpha(backgroundColor, 0.05f) + } } - if (g is Graphics2D) { g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) g.fillRoundRect((c.width / 2) - (circleDiameter / 2), (c.height / 2) - (circleDiameter / 2), circleDiameter, circleDiameter, c.width, c.height) From 118e51a2d92968957b52405af78151385d318589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Mon, 25 Sep 2023 23:20:55 +0200 Subject: [PATCH 10/11] Fix $HOME env variable read --- .../LinuxLookAndFeel.kt | 40 ++----------------- .../LinuxFrameTitleButtons.kt | 4 +- 2 files changed, 6 insertions(+), 38 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt index 1081b1d463bb3..7380d4fdf3bba 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/LinuxLookAndFeel.kt @@ -16,6 +16,7 @@ import kotlin.concurrent.thread class LinuxLookAndFeel { companion object { val linuxIconPath = "/usr/share/icons" + val linuxHomePath = System.getenv("HOME") fun getLinuxIcon(name: WindowToolbarIcons): Icon? { val iconName: String var iconPath: String? = null @@ -35,7 +36,7 @@ class LinuxLookAndFeel { WindowToolbarIcons.RESTORE -> "maximized-normal.svg" WindowToolbarIcons.MINIMIZE -> "minimize-normal.svg" } - iconPath = "\$HOME/.config/gtk-3.0/assets/$iconName" + iconPath = "$linuxHomePath/.config/gtk-3.0/assets/$iconName" } @@ -111,7 +112,7 @@ class LinuxLookAndFeel { return elementsString?.split(":", ",") ?: emptyList() } else if (SystemInfo.isKDE) { - val gtk3ConfigFile = File("\$HOME/.config/gtk-3.0/settings.ini") + val gtk3ConfigFile = File("$linuxHomePath/.config/gtk-3.0/settings.ini") val paramName = "gtk-decoration-layout=" if (gtk3ConfigFile.exists()) { val lines = gtk3ConfigFile.readLines() @@ -152,41 +153,6 @@ class LinuxLookAndFeel { } return null } - - private var isListeningIconThemeChanges = false - private fun listenIconThemeChanges() { - if (isListeningIconThemeChanges) return - isListeningIconThemeChanges = true - thread(start = true) { - val processBuilder = ProcessBuilder(listOf("dbus-monitor", "member='Notify'")) - processBuilder.redirectErrorStream(true) - - val process = processBuilder.start() - val reader = BufferedReader(InputStreamReader(process.inputStream)) - - - Runtime.getRuntime().addShutdownHook(Thread { - reader.close() - process.destroy() - }) - - var line: String - - while (true) { - line = reader.readLine() - if (line.contains("/org/gnome/desktop/interface/icon-theme")) { - println("Theme changed!!!") - subscribers.forEach { it() } - } - } - } - } - - private val subscribers = mutableListOf<() -> Unit>() - fun onIconThemeChanges(callback: () -> Unit) { - listenIconThemeChanges() - subscribers.add(callback) - } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt index e2e35da827837..4c24eb144abbc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/frameTitleButtons/LinuxFrameTitleButtons.kt @@ -29,7 +29,6 @@ class LinuxFrameTitleButtons( override val minimizeButton: JButton? = myIconifyAction?.let { createButton("Iconify", it) } - val restore = LinuxLookAndFeel.getLinuxIcon(WindowToolbarIcons.RESTORE) ?: AllIcons.Windows.Restore override val restoreIcon = restore override val restoreInactiveIcon = restore @@ -86,6 +85,9 @@ class LinuxFrameTitleButtons( override fun setScaledPreferredSize(size: Dimension): Dimension { + if (SystemInfo.isKDE) { + return Dimension(24, size.height) + } return Dimension(38, size.height) } } From 78dbc52bdc03ff8188816619dcd0f367db7d1cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20Garc=C3=ADa=20Torres?= Date: Wed, 8 Nov 2023 21:58:39 +0100 Subject: [PATCH 11/11] Update branch --- platform/core-ui/src/util/IconUtil.kt | 12 ++++++++---- .../PresentationAssistantQuickSettingsButton.kt | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/platform/core-ui/src/util/IconUtil.kt b/platform/core-ui/src/util/IconUtil.kt index 17e09a85a55a2..43f2084ffbb3f 100644 --- a/platform/core-ui/src/util/IconUtil.kt +++ b/platform/core-ui/src/util/IconUtil.kt @@ -441,23 +441,27 @@ object IconUtil { @JvmOverloads @JvmStatic fun colorizeTint(source: Icon, color: Color, keepGray: Boolean = false): Icon { - return filterIcon(icon = source, filterSupplier = { ColorMultiplyFilter(color, keepGray) }) + return filterIcon(icon = source, filterSupplier = object : RgbImageFilterSupplier { + override fun getFilter() = ColorMultiplyFilter(color = color, keepGray = keepGray) + }) } @JvmOverloads @JvmStatic fun colorizeTint(g: Graphics2D?, source: Icon, color: Color, keepGray: Boolean = false): Icon { - return filterIcon(g = g, source = source, filter = ColorMultiplyFilter(color, keepGray)) + return filterIcon(g = g, source = source, filter = ColorMultiplyFilter(color = color, keepGray = keepGray)) } @JvmStatic fun colorizeReplace(source: Icon, color: Color): Icon { - return filterIcon(icon = source, filterSupplier = { ColorReplaceFilter(color) }) + return filterIcon(icon = source, filterSupplier = object : RgbImageFilterSupplier { + override fun getFilter() = ColorReplaceFilter(color = color) + }) } @JvmStatic fun colorizeReplace(g: Graphics2D?, source: Icon, color: Color): Icon { - return filterIcon(g = g, source = source, filter = ColorReplaceFilter(color)) + return filterIcon(g = g, source = source, filter = ColorReplaceFilter(color = color)) } @JvmStatic diff --git a/platform/platform-impl/src/com/intellij/platform/ide/impl/presentationAssistant/PresentationAssistantQuickSettingsButton.kt b/platform/platform-impl/src/com/intellij/platform/ide/impl/presentationAssistant/PresentationAssistantQuickSettingsButton.kt index 1a391aa59d37f..f6f19128fd59a 100644 --- a/platform/platform-impl/src/com/intellij/platform/ide/impl/presentationAssistant/PresentationAssistantQuickSettingsButton.kt +++ b/platform/platform-impl/src/com/intellij/platform/ide/impl/presentationAssistant/PresentationAssistantQuickSettingsButton.kt @@ -27,7 +27,7 @@ import javax.swing.SwingConstants internal class PresentationAssistantQuickSettingsButton(private val project: Project, private val appearance: ActionInfoPopupGroup.Appearance, private val shownStateRequestCountChanged: (Int) -> Unit): - JBLabel(IconUtil.colorize(AllIcons.Actions.PresentationAssistantSettings, appearance.theme.keymapLabel)), Disposable, DataContext { + JBLabel(IconUtil.colorizeTint(AllIcons.Actions.PresentationAssistantSettings, appearance.theme.keymapLabel)), Disposable, DataContext { private var popup: JBPopup? = null private var hideAlarm = Alarm()