fix(jetbrains): let worktree toolbar inherit theme

This commit is contained in:
kirillk
2026-08-14 13:20:51 -04:00
parent 1ebc4a88bc
commit 66819e69a0
4 changed files with 24 additions and 27 deletions
@@ -24,7 +24,6 @@ import ai.kilocode.client.diff.ensureDiffEditorKind
import ai.kilocode.client.plugin.KiloBundle
import ai.kilocode.client.session.SessionActivityKind
import ai.kilocode.client.ui.UiStyle
import ai.kilocode.client.util.bindTheme
import ai.kilocode.client.ui.list.ActiveList
import ai.kilocode.client.ui.list.ActiveListBadge
import ai.kilocode.client.ui.list.ActiveListConfig
@@ -108,7 +107,6 @@ class AgentManagerPanel(
list.installPopup(group)
sync()
bindModel()
bindTheme(this, this)
controller.onSelect = { key ->
// Focus the list so the freshly created worktree renders as an active selection rather
// than the inactive highlight it would get while focus stays on the toolbar.
@@ -13,7 +13,6 @@ import ai.kilocode.client.session.history.HistoryTime
import ai.kilocode.client.session.history.LocalHistoryItem
import ai.kilocode.client.plugin.KiloPluginSettings
import ai.kilocode.client.telemetry.Telemetry
import ai.kilocode.client.util.bindTheme
import ai.kilocode.client.ui.list.ActiveList
import ai.kilocode.client.ui.list.ActiveListBadge
import ai.kilocode.client.ui.list.ActiveListConfig
@@ -116,7 +115,9 @@ class WorktreeSessionEditorPanel(
Disposer.register(parent, this)
isOpaque = true
toolbar.targetComponent = this
toolbar.component.background = activeListToolWindowBackground()
// Keep the toolbar transparent so it shows its themed parent background and tracks
// Look-and-Feel changes automatically, instead of caching a color that goes stale.
toolbar.component.isOpaque = false
toolbar.updateActionsImmediately()
list.installPopup(group)
splitter.firstComponent = list
@@ -141,7 +142,6 @@ class WorktreeSessionEditorPanel(
}
}
bindStatus()
bindTheme(this, this)
sync()
}
@@ -1,21 +0,0 @@
package ai.kilocode.client.util
import com.intellij.ide.ui.LafManagerListener
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import javax.swing.JComponent
import javax.swing.SwingUtilities
/**
* Refresh [roots] on Look-and-Feel changes. The subscription is tied to [parent], so it is removed
* when the owning component is disposed. Replaces the copy/pasted `LafManagerListener` blocks that
* each panel used to carry.
*/
internal fun bindTheme(parent: Disposable, vararg roots: JComponent) {
val bus = ApplicationManager.getApplication().messageBus.connect(parent)
bus.subscribe(LafManagerListener.TOPIC, LafManagerListener {
ApplicationManager.getApplication().invokeLater {
roots.forEach { SwingUtilities.updateComponentTreeUI(it) }
}
})
}
@@ -36,6 +36,7 @@ import com.intellij.ui.SearchTextField
import com.intellij.ui.components.JBList
import com.intellij.ui.components.JBScrollPane
import com.intellij.util.ui.UIUtil
import java.awt.Color
import java.awt.Container
import java.awt.Point
import java.awt.event.ActionEvent
@@ -46,6 +47,7 @@ import javax.swing.JButton
import javax.swing.JComponent
import javax.swing.KeyStroke
import javax.swing.SwingUtilities
import javax.swing.UIManager
@Suppress("UnstableApiUsage")
class WorktreeSessionEditorPanelTest : BasePlatformTestCase() {
@@ -110,7 +112,7 @@ class WorktreeSessionEditorPanelTest : BasePlatformTestCase() {
assertEquals(activeListToolWindowBackground(), edt { scroll.background })
assertEquals(activeListToolWindowBackground(), edt { scroll.viewport.background })
assertEquals(activeListToolWindowBackground(), edt { (scroll.viewport.view as JComponent).background })
assertEquals(activeListToolWindowBackground(), edt { toolbar.background })
assertFalse(edt { toolbar.isOpaque })
assertEquals(activeListToolWindowBackground(), edt { toolbarPanel.background })
assertEquals(activeListToolWindowBackground(), edt { header.background })
assertEquals(0, edt { scroll.border.getBorderInsets(scroll).left })
@@ -119,6 +121,24 @@ class WorktreeSessionEditorPanelTest : BasePlatformTestCase() {
assertTrue(edt { header.border.getBorderInsets(header).bottom > 0 })
}
fun `test toolbar background tracks the theme automatically`() {
val button = edt { components(panel).filterIsInstance<ActionButton>().single { it.presentation.text == "New session" } }
val toolbar = edt { button.parent as JComponent }
val toolbarPanel = edt { toolbar.parent as JComponent }
val old = UIManager.get("ToolWindow.background")
val next = Color(17, 34, 51)
try {
// The toolbar is transparent, so its themed background comes from the parent and follows
// the theme's ToolWindow.background live -- no listener or manual assignment required.
assertFalse(edt { toolbar.isOpaque })
edt { UIManager.put("ToolWindow.background", next) }
assertEquals(next, edt { toolbarPanel.background })
} finally {
UIManager.put("ToolWindow.background", old)
}
}
fun `test expand collapse hides session list and edit toolbar but keeps header actions`() {
edt {
val splitter = UIUtil.findComponentOfType(panel, OnePixelSplitter::class.java)!!