1
1
package shark
2
2
3
+ import androidx.compose.desktop.AppWindow
4
+ import androidx.compose.desktop.WindowEvents
3
5
import androidx.compose.foundation.ExperimentalFoundationApi
4
6
import androidx.compose.foundation.layout.Row
5
7
import androidx.compose.material.MaterialTheme
@@ -10,9 +12,27 @@ import androidx.compose.runtime.mutableStateOf
10
12
import androidx.compose.runtime.remember
11
13
import androidx.compose.runtime.setValue
12
14
import androidx.compose.ui.input.key.ExperimentalKeyInput
15
+ import androidx.compose.ui.input.key.Key
16
+ import androidx.compose.ui.input.key.Key.Companion
17
+ import androidx.compose.ui.input.key.plus
18
+ import androidx.compose.ui.unit.IntSize
19
+ import androidx.compose.ui.window.KeyStroke
20
+ import androidx.compose.ui.window.Menu
21
+ import androidx.compose.ui.window.MenuBar
22
+ import androidx.compose.ui.window.MenuItem
13
23
import backstack.Backstack
14
24
import shark.SharkScreen.HeapObjectTree
15
25
import shark.SharkScreen.Home
26
+ import shark.adb.showAdbDumpHeapWindow
27
+ import java.awt.FileDialog
28
+ import java.awt.Frame
29
+ import java.awt.KeyboardFocusManager
30
+ import java.awt.Toolkit
31
+ import java.awt.event.KeyEvent
32
+ import java.awt.image.BufferedImage
33
+ import java.io.File
34
+ import java.util.concurrent.Executors
35
+ import javax.swing.SwingUtilities
16
36
17
37
@OptIn(
18
38
ExperimentalKeyInput ::class ,
@@ -55,3 +75,111 @@ fun HeapGraphWindow(
55
75
}
56
76
}
57
77
}
78
+
79
+ @OptIn(ExperimentalKeyInput ::class )
80
+ fun showHeapGraphWindow (
81
+ windowIcon : BufferedImage ,
82
+ heapDumpFile : File ,
83
+ onWindowShown : () -> Unit = {}
84
+ ) {
85
+ val loadingState = HeapDumpLoadingState (heapDumpFile, Executors .newSingleThreadExecutor())
86
+ loadingState.load()
87
+
88
+ SwingUtilities .invokeLater {
89
+ val screenSize = Toolkit .getDefaultToolkit().screenSize
90
+
91
+ lateinit var appWindow: AppWindow
92
+ appWindow = AppWindow (
93
+ title = " ${heapDumpFile.name} - SharkApp" ,
94
+ size = IntSize ((screenSize.width * 0.8f ).toInt(), (screenSize.height * 0.8f ).toInt()),
95
+ centered = true ,
96
+ icon = windowIcon,
97
+ events = WindowEvents (onClose = {
98
+ loadingState.loadedGraph.value?.close()
99
+ loadingState.ioExecutor.shutdown()
100
+ }),
101
+ menuBar = MenuBar (
102
+ Menu (
103
+ name = " File" ,
104
+ MenuItem (
105
+ name = " Open Heap Dump" ,
106
+ onClick = {
107
+ showSelectHeapDumpFileWindow(onHprofFileSelected = { selectedFile ->
108
+ showHeapGraphWindow(windowIcon, selectedFile)
109
+ })
110
+ },
111
+ shortcut = KeyStroke (Key .O )
112
+ ),
113
+ MenuItem (
114
+ name = " Dump Heap with adb" ,
115
+ onClick = { showAdbDumpHeapWindow(windowIcon) },
116
+ shortcut = KeyStroke (Key .D )
117
+ ),
118
+ MenuItem (
119
+ name = " Close Heap Dump" ,
120
+ onClick = {
121
+ appWindow.close()
122
+ },
123
+ shortcut = KeyStroke (Key .W )
124
+ )
125
+ ),
126
+ )
127
+ )
128
+
129
+ val pressedKeys = PressedKeys ()
130
+
131
+ KeyboardFocusManager .getCurrentKeyboardFocusManager().addKeyEventDispatcher { keyEvent ->
132
+ when (keyEvent.id) {
133
+ KeyEvent .KEY_PRESSED -> {
134
+ when (keyEvent.keyCode) {
135
+ KeyEvent .VK_ALT -> pressedKeys.alt = true
136
+ KeyEvent .VK_META -> pressedKeys.meta = true
137
+ KeyEvent .VK_CONTROL -> pressedKeys.ctrl = true
138
+ KeyEvent .VK_SHIFT -> pressedKeys.shift = true
139
+ }
140
+ }
141
+ KeyEvent .KEY_RELEASED -> {
142
+ when (keyEvent.keyCode) {
143
+ KeyEvent .VK_ALT -> pressedKeys.alt = false
144
+ KeyEvent .VK_META -> pressedKeys.meta = false
145
+ KeyEvent .VK_CONTROL -> pressedKeys.ctrl = false
146
+ KeyEvent .VK_SHIFT -> pressedKeys.shift = false
147
+ }
148
+ }
149
+ }
150
+ false
151
+ }
152
+
153
+ val navigator = ScreenNavigator <SharkScreen >(
154
+ Home (),
155
+ recentsEquals = { screen1, screen2 -> screen1.title == screen2.title })
156
+ appWindow.keyboard.apply {
157
+ setShortcut(Key .AltLeft + Key (KeyEvent .VK_LEFT ), navigator::goBack)
158
+ setShortcut(Key .AltRight + Key (KeyEvent .VK_LEFT ), navigator::goBack)
159
+ setShortcut(Key .AltLeft + Key (KeyEvent .VK_RIGHT ), navigator::goForward)
160
+ setShortcut(Key .AltLeft + Key (KeyEvent .VK_RIGHT ), navigator::goForward)
161
+ }
162
+ appWindow.show {
163
+ HeapGraphWindow (navigator, loadingState, pressedKeys)
164
+ }
165
+
166
+ onWindowShown()
167
+ }
168
+ }
169
+
170
+ class PressedKeys {
171
+ var alt = false
172
+ var ctrl = false
173
+ var meta = false
174
+ var shift = false
175
+ }
176
+
177
+ fun showSelectHeapDumpFileWindow (onHprofFileSelected : (File ) -> Unit ) {
178
+ val fileDialog = FileDialog (null as Frame ? , " Select hprof file" )
179
+ fileDialog.isVisible = true
180
+
181
+ if (fileDialog.file != null && fileDialog.file.endsWith(" .hprof" )) {
182
+ val heapDumpFile = File (fileDialog.directory, fileDialog.file)
183
+ onHprofFileSelected(heapDumpFile)
184
+ }
185
+ }
0 commit comments