mirror of
https://github.com/chylex/IntelliJ-Pin-Undocked-Tool-Windows.git
synced 2025-05-06 19:34:04 +02:00
Stop IntelliJ from hiding Undocked tool windows when they lose focus
This commit is contained in:
parent
96c63d6b06
commit
7ec831c0c3
src/main/kotlin/com/chylex/intellij/pinundockedtoolwindows
@ -0,0 +1,21 @@
|
||||
package com.chylex.intellij.pinundockedtoolwindows
|
||||
|
||||
import com.chylex.intellij.pinundockedtoolwindows.patch.ToolWindowPatcher
|
||||
import com.intellij.ide.plugins.DynamicPluginListener
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
|
||||
|
||||
const val PLUGIN_ID = "com.chylex.intellij.pinundockedtoolwindows"
|
||||
|
||||
class DynamicPluginListener : DynamicPluginListener {
|
||||
override fun pluginLoaded(pluginDescriptor: IdeaPluginDescriptor) {
|
||||
if (pluginDescriptor.pluginId.idString == PLUGIN_ID) {
|
||||
ToolWindowPatcher.apply()
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforePluginUnload(pluginDescriptor: IdeaPluginDescriptor, isUpdate: Boolean) {
|
||||
if (pluginDescriptor.pluginId.idString == PLUGIN_ID) {
|
||||
ToolWindowPatcher.revert()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.chylex.intellij.pinundockedtoolwindows
|
||||
|
||||
import com.chylex.intellij.pinundockedtoolwindows.patch.ToolWindowPatcher
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.startup.ProjectActivity
|
||||
|
||||
class ProjectActivityListener : ProjectActivity {
|
||||
override suspend fun execute(project: Project) {
|
||||
ApplicationManager.getApplication().invokeLater(ToolWindowPatcher::apply)
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.chylex.intellij.pinundockedtoolwindows.patch
|
||||
|
||||
import com.intellij.openapi.wm.IdeFocusManager
|
||||
import com.intellij.openapi.wm.ToolWindowManager
|
||||
import com.intellij.openapi.wm.ToolWindowType
|
||||
import com.intellij.openapi.wm.impl.ToolWindowManagerImpl
|
||||
import com.intellij.toolWindow.InternalDecoratorImpl
|
||||
import com.intellij.ui.ClientProperty
|
||||
import java.awt.AWTEvent
|
||||
import java.awt.Component
|
||||
import java.awt.event.AWTEventListener
|
||||
import java.awt.event.FocusEvent
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class PatchedAwtFocusListener(internal val original: AWTEventListener) : AWTEventListener {
|
||||
override fun eventDispatched(event: AWTEvent?) {
|
||||
if (event is FocusEvent && event.id == FocusEvent.FOCUS_LOST && shouldIgnoreFocusLostEvent(event.component)) {
|
||||
return
|
||||
}
|
||||
|
||||
original.eventDispatched(event)
|
||||
}
|
||||
|
||||
private fun shouldIgnoreFocusLostEvent(currentlyFocused: Component?): Boolean {
|
||||
val project = IdeFocusManager.getGlobalInstance().lastFocusedFrame?.project ?: return false
|
||||
if (project.isDisposed || project.isDefault) {
|
||||
return false
|
||||
}
|
||||
|
||||
val toolWindowManager = ToolWindowManager.getInstance(project)
|
||||
val toolWindowId = getToolWindowIdForComponent(currentlyFocused) ?: return false
|
||||
val toolWindow = toolWindowManager.getToolWindow(toolWindowId) ?: return false
|
||||
|
||||
return toolWindow.type == ToolWindowType.SLIDING
|
||||
}
|
||||
|
||||
private fun getToolWindowIdForComponent(component: Component?): String? {
|
||||
var c = component
|
||||
while (c != null) {
|
||||
if (c is InternalDecoratorImpl) {
|
||||
return c.toolWindowId
|
||||
}
|
||||
c = ClientProperty.get(c, ToolWindowManagerImpl.PARENT_COMPONENT) ?: c.parent
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.chylex.intellij.pinundockedtoolwindows.patch
|
||||
|
||||
import java.awt.AWTEvent
|
||||
import java.awt.Toolkit
|
||||
import java.awt.event.AWTEventListenerProxy
|
||||
|
||||
object ToolWindowPatcher {
|
||||
private const val EVENT_MASK = AWTEvent.FOCUS_EVENT_MASK or AWTEvent.WINDOW_FOCUS_EVENT_MASK
|
||||
|
||||
private var activePatch: ActivePatch? = null
|
||||
|
||||
private data class ActivePatch(val listener: PatchedAwtFocusListener, val eventMask: Long)
|
||||
|
||||
fun apply() {
|
||||
if (activePatch != null) {
|
||||
return
|
||||
}
|
||||
|
||||
val toolkit = Toolkit.getDefaultToolkit()
|
||||
for (listenerProxy in toolkit.getAWTEventListeners(EVENT_MASK)) {
|
||||
if (listenerProxy is AWTEventListenerProxy) {
|
||||
val listener = listenerProxy.listener
|
||||
if (listener.javaClass.name == "com.intellij.openapi.wm.impl.ToolWindowManagerImpl\$ToolWindowManagerAppLevelHelper\$MyListener") {
|
||||
val patch = ActivePatch(PatchedAwtFocusListener(listener), listenerProxy.eventMask)
|
||||
toolkit.removeAWTEventListener(listener)
|
||||
toolkit.addAWTEventListener(patch.listener, patch.eventMask)
|
||||
activePatch = patch
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun revert() {
|
||||
val patch = activePatch
|
||||
if (patch != null) {
|
||||
val toolkit = Toolkit.getDefaultToolkit()
|
||||
toolkit.removeAWTEventListener(patch.listener)
|
||||
toolkit.addAWTEventListener(patch.listener.original, patch.eventMask)
|
||||
activePatch = null
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user