Skip to content

Commit d1f0296

Browse files
authored
Merge pull request #2473 from digma-ai/improve-jcef-reload
shorten delay and reload per project
2 parents 9141557 + 3efce8a commit d1f0296

File tree

11 files changed

+312
-90
lines changed

11 files changed

+312
-90
lines changed

ide-common/src/main/kotlin/org/digma/intellij/plugin/reload/ReloadAction.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import org.digma.intellij.plugin.errorreporting.ErrorReporter
1010
class ReloadAction : AnAction() {
1111
override fun actionPerformed(p0: AnActionEvent) {
1212
try {
13-
service<ReloadService>().reload(0)
13+
service<ReloadService>().reloadAllProjects()
1414
} catch (e: Throwable) {
1515
ErrorReporter.getInstance().reportError("ReloadAction.actionPerformed", e)
1616
}

ide-common/src/main/kotlin/org/digma/intellij/plugin/reload/ReloadObserver.kt

Lines changed: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ import com.intellij.openapi.Disposable
44
import com.intellij.openapi.components.Service
55
import com.intellij.openapi.components.service
66
import com.intellij.openapi.diagnostic.Logger
7+
import com.intellij.openapi.project.Project
78
import com.intellij.openapi.util.Disposer
89
import com.intellij.openapi.util.SystemInfo
910
import kotlinx.coroutines.CancellationException
1011
import kotlinx.coroutines.CoroutineScope
1112
import kotlinx.coroutines.delay
1213
import kotlinx.coroutines.isActive
1314
import kotlinx.coroutines.launch
15+
import kotlinx.datetime.Clock
16+
import org.digma.intellij.plugin.common.isProjectValid
1417
import org.digma.intellij.plugin.errorreporting.ErrorReporter
1518
import org.digma.intellij.plugin.log.Log
1619
import java.awt.Component
@@ -20,7 +23,7 @@ import java.beans.PropertyChangeListener
2023
import java.util.Queue
2124
import java.util.concurrent.ConcurrentLinkedQueue
2225
import javax.swing.JComponent
23-
import javax.swing.JPanel
26+
import kotlin.time.Duration.Companion.seconds
2427

2528

2629
/**
@@ -43,7 +46,7 @@ class ReloadObserver(cs: CoroutineScope) {
4346
try {
4447
val event = propertyChangedEvents.poll()
4548
if (event == null) {
46-
delay(2000)
49+
delay(1000)
4750
} else {
4851
checkChangesAndReload(event)
4952
}
@@ -58,7 +61,18 @@ class ReloadObserver(cs: CoroutineScope) {
5861
}
5962

6063

61-
fun register(jcefWrapperPanel: JPanel, jcefUiComponent: JComponent, parentDisposable: Disposable) {
64+
companion object {
65+
private fun buildGraphicsDeviceList(): List<String> {
66+
return GraphicsEnvironment.getLocalGraphicsEnvironment().screenDevices.map { it.iDstring }
67+
}
68+
69+
private fun deviceListEquals(list1: List<String>, list2: List<String>): Boolean {
70+
return list1.size == list2.size && list1.containsAll(list2)
71+
}
72+
}
73+
74+
75+
fun register(project: Project, appName: String, jcefUiComponent: JComponent, parentDisposable: Disposable) {
6276

6377
if (GraphicsEnvironment.isHeadless()) {
6478
Log.log(logger::trace, "GraphicsEnvironment is headless, not registering components")
@@ -71,7 +85,7 @@ class ReloadObserver(cs: CoroutineScope) {
7185
}
7286

7387
val jcefPropertyChangeListener =
74-
MyPropertyChangeListener(jcefUiComponent, "${jcefWrapperPanel.javaClass.simpleName}.jcefUiComponent")
88+
MyPropertyChangeListener(project, jcefUiComponent, "$appName.jcefUiComponent")
7589
jcefUiComponent.addPropertyChangeListener(jcefPropertyChangeListener)
7690

7791
Disposer.register(parentDisposable) {
@@ -84,53 +98,90 @@ class ReloadObserver(cs: CoroutineScope) {
8498
private suspend fun checkChangesAndReload(event: Pair<ComponentDetails, PropertyChangeEvent>) {
8599
try {
86100

87-
Log.log(logger::trace, "checking graphics changes for component {}", event.first.componentName)
88-
89101
val componentDetails = event.first
90102
val component = componentDetails.component
103+
val componentName = componentDetails.componentName
104+
val project = componentDetails.project
105+
106+
Log.log(logger::trace, "checking graphics changes for component {} in project {}", componentName, project.name)
107+
108+
109+
if (!isProjectValid(project)) {
110+
Log.log(
111+
logger::trace,
112+
"skipping checking graphics changes for component {} in project {} because project is invalid",
113+
componentName,
114+
project.name
115+
)
116+
return
117+
}
91118

92119
val currentDisplayMode = component.graphicsConfiguration?.device?.displayMode
93120
val currentGraphicsDevice = component.graphicsConfiguration?.device?.iDstring
94121
if (currentGraphicsDevice != componentDetails.graphicDevice) {
95122
Log.log(
96123
logger::trace,
97-
"component {} moved to another graphics device, oldValue:{},newValue:{}",
98-
componentDetails.componentName,
124+
"component {} in project {} moved to another graphics device, oldValue:{},newValue:{}",
125+
componentName,
126+
project.name,
99127
componentDetails.graphicDevice,
100128
currentGraphicsDevice
101129
)
102130

103131
componentDetails.graphicDevice = currentGraphicsDevice
104132
componentDetails.displayMode = currentDisplayMode
105133

106-
delay(1000)
134+
//it may take the GraphicsEnvironment some time to refresh the screen devices. it depends on native OS calls timing,
135+
// it may take the OS some seconds to notify the GraphicsEnvironment about changes.
136+
//if we don't catch the change we may miss a reload when it's needed.
137+
//so wait for some seconds to try to detect the change. if there is no change no harm will be done and this
138+
// coroutine will just finish doing nothing
139+
var currentGraphicsDeviceList = buildGraphicsDeviceList()
140+
val endWait = Clock.System.now() + 3.seconds
141+
while (deviceListEquals(currentGraphicsDeviceList, componentDetails.graphicsDeviceList) &&
142+
Clock.System.now() < endWait
143+
) {
144+
Log.log(logger::trace, "waiting for device list to refresh for component {} in project {}", componentName, project.name)
145+
delay(100)
146+
currentGraphicsDeviceList = buildGraphicsDeviceList()
147+
}
107148

108-
val currentGraphicsDeviceNumber = GraphicsEnvironment.getLocalGraphicsEnvironment().screenDevices.size
109-
if (currentGraphicsDeviceNumber != componentDetails.graphicsDeviceNumber) {
149+
if (!deviceListEquals(currentGraphicsDeviceList, componentDetails.graphicsDeviceList)) {
110150
Log.log(
111151
logger::trace,
112-
"graphics device number has changed for component {} ,oldValue:{},newValue:{}",
113-
componentDetails.componentName,
114-
componentDetails.graphicsDeviceNumber,
115-
currentGraphicsDeviceNumber
152+
"graphics device list has changed for component {} in project {},oldValue:{},newValue:{}",
153+
componentName,
154+
project.name,
155+
componentDetails.graphicsDeviceList,
156+
currentGraphicsDeviceList
116157
)
117-
componentDetails.graphicsDeviceNumber = currentGraphicsDeviceNumber
158+
componentDetails.graphicsDeviceList = currentGraphicsDeviceList
118159

119-
service<ReloadService>().reload()
160+
service<ReloadService>().reload(project)
161+
} else {
162+
Log.log(
163+
logger::trace,
164+
"graphics device list has NOT changed for component {} in project {},oldValue:{},newValue:{}",
165+
componentName,
166+
project.name,
167+
componentDetails.graphicsDeviceList,
168+
currentGraphicsDeviceList
169+
)
120170
}
121171
} else if (currentDisplayMode != componentDetails.displayMode) {
122172
Log.log(
123173
logger::trace,
124-
"component {} display mode has changed, oldValue:{},newValue:{}",
125-
componentDetails.componentName,
174+
"component {} in project {} display mode has changed, oldValue:{},newValue:{}",
175+
componentName,
176+
project.name,
126177
componentDetails.displayMode,
127178
currentDisplayMode
128179
)
129180
componentDetails.displayMode = currentDisplayMode
130181

131-
service<ReloadService>().reload()
182+
service<ReloadService>().reload(project)
132183
} else {
133-
Log.log(logger::trace, "no graphics changes for component {}", componentDetails.componentName)
184+
Log.log(logger::trace, "no graphics changes for component {} in project {}", componentName, project.name)
134185
}
135186

136187
} catch (e: Throwable) {
@@ -139,24 +190,36 @@ class ReloadObserver(cs: CoroutineScope) {
139190
}
140191

141192

142-
private class ComponentDetails(val component: Component, val componentName: String) {
193+
private class ComponentDetails(val project: Project, val component: Component, val componentName: String) {
143194
var graphicDevice = component.graphicsConfiguration?.device?.iDstring
144195
var displayMode = component.graphicsConfiguration?.device?.displayMode
145-
var graphicsDeviceNumber = GraphicsEnvironment.getLocalGraphicsEnvironment().screenDevices.size
196+
var graphicsDeviceList = buildGraphicsDeviceList()
197+
198+
199+
override fun toString(): String {
200+
return "ComponentDetails(project=${project.name}, " +
201+
"component=${component::class.java.simpleName}, " +
202+
"componentName='$componentName', " +
203+
"graphicDevice=$graphicDevice, " +
204+
"displayMode=$displayMode, " +
205+
"graphicsDeviceList=$graphicsDeviceList)"
206+
}
207+
146208
}
147209

148210

149211
private inner class MyPropertyChangeListener(
212+
project: Project,
150213
component: Component,
151214
private val componentName: String,
152215
) :
153216
PropertyChangeListener {
154217

155-
private val componentDetails = ComponentDetails(component, componentName)
218+
private val componentDetails = ComponentDetails(project, component, componentName)
156219

157220
override fun propertyChange(evt: PropertyChangeEvent) {
158221
if (evt.propertyName == "graphicsConfiguration") {
159-
Log.log(logger::trace, "got PropertyChangeEvent for {}, {}", componentName, evt)
222+
Log.log(logger::trace, "got PropertyChangeEvent for {}, event {}, component details {}", componentName, evt, componentDetails)
160223
//putting the events in a queue ensures we process them in the order they arrive.
161224
//just launching a coroutine here does not guarantee order and may cause wrong decisions
162225
//about reloading

0 commit comments

Comments
 (0)