UX: avoid round trip to GDB until thread node is expanded
...by assuming a thread has always a child. This is not strictly
true, but speeds up the UI significantly for multi-threaded
applications since usually user is debugging one, two threads
and this avoids fetching stack for all threads unless absolutely
necessary.
"
jv:vdb - Visual / VM Debugger
Copyright (C) 2015-now Jan Vrany
Copyright (C) 2020 LabWare
This software is licensed under 'Creative Commons Attribution-NonCommercial 4.0 International License'
You may find a full license text in LICENSE.txt or at http://creativecommons.org/licenses/by-nc/4.0/
"
"{ Package: 'jv:vdb' }"
"{ NameSpace: Smalltalk }"
VDBAbstractPresenter subclass:#VDBThreadPresenter
instanceVariableNames:'thread name'
classVariableNames:''
poolDictionaries:''
category:'VDB-Presentation'
!
!VDBThreadPresenter class methodsFor:'documentation'!
copyright
"
jv:vdb - Visual / VM Debugger
Copyright (C) 2015-now Jan Vrany
Copyright (C) 2020 LabWare
This software is licensed under 'Creative Commons Attribution-NonCommercial 4.0 International License'
You may find a full license text in LICENSE.txt or at http://creativecommons.org/licenses/by-nc/4.0/
"
! !
!VDBThreadPresenter class methodsFor:'menu specs'!
contextMenu
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:VDBThreadPresenter andSelector:#contextMenu
(Menu new fromLiteralArrayEncoding:(VDBThreadPresenter contextMenu)) startUp
"
<resource: #menu>
^
#(Menu (
(MenuItem
enabled: canCopyBacktrace
label: 'Copy Backtrace To Clipboard'
itemValue: doCopyBacktraceToClipboard
isVisible: true
)
) nil
nil
)
! !
!VDBThreadPresenter methodsFor:'accessing'!
icon
thread isRunning ifTrue:[ ^ VDBIconLibrary threadRunning16x16 ].
thread isStopped ifTrue:[ ^ VDBIconLibrary threadStopped16x16 ].
thread isTerminated ifTrue:[ ^ VDBIconLibrary threadTerminated16x16 ].
^ nil
"Created: / 22-09-2014 / 22:00:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
label
name isNil ifTrue:[
thread isRunning ifFalse:[
name := '"' , thread name , '"'
]
].
^ 'Thread %1 [%2] %3' bindWith: (thread id printStringRadix: 10 size: 2 fill: Character space) with: thread status with: name ? ''
"Created: / 22-09-2014 / 00:14:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 12-07-2017 / 14:23:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 27-11-2020 / 13:44:36 / Jan Vrany <jan.vrany@labware.com>"
!
subject
"Return an instance of GDB object that this presenter displays."
^ thread
"Modified: / 05-02-2018 / 13:08:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
thread
^ thread
! !
!VDBThreadPresenter methodsFor:'initialization'!
setThread: aGDBThread
thread := aGDBThread.
"Created: / 21-09-2014 / 23:39:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 12-07-2017 / 14:21:06 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!VDBThreadPresenter methodsFor:'menu actions'!
doCopyBacktraceToClipboard
| backtrace |
backtrace := String streamContents:[:s|
thread stack
do: [:frame | frame dumpOn: s ]
separatedBy: [ s cr; nextPutAll: '--'; cr ]
].
self doCopy: backtrace
"Modified: / 09-08-2020 / 07:15:42 / Jan Vrany <jan.vrany@labware.com>"
! !
!VDBThreadPresenter methodsFor:'menu queries'!
canCopyBacktrace
^ [ thread isStopped ]
"Modified: / 09-08-2020 / 07:01:35 / Jan Vrany <jan.vrany@labware.com>"
! !
!VDBThreadPresenter methodsFor:'protocol-accessing'!
fetchChildren
"should compute the list of children via the model.
Be aware, that the somewhat stupid 'optimization' of how the model is fetched may lead to
a O(n*log n) or even O(n^2) behavior here.
*** to optimize: redefine by subClass"
thread isDead ifTrue:[ ^ #() ].
thread isRunning ifTrue:[ ^ #() ].
^ thread stack collect:[ :f | VDBFramePresenter new setFrame: f; parent: self ]
"Created: / 21-09-2014 / 23:42:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 30-09-2014 / 00:04:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!VDBThreadPresenter methodsFor:'protocol-queries'!
hasChildren
"/ Here we assume a thread has at least one frame.
"/ This is NOT true is certain corner cases, however,
"/ unconditionally answering `true` here avoids round-trip
"/ to GDB until thread node is actually "expanded".
^ true
"Created: / 10-12-2020 / 00:05:41 / Jan Vrany <jan.vrany@labware.com>"
"Modified (comment): / 10-12-2020 / 20:17:56 / Jan Vrany <jan.vrany@labware.com>"
! !
!VDBThreadPresenter methodsFor:'testing'!
isThreadPresenter
^ true
"Created: / 21-09-2014 / 23:54:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!VDBThreadPresenter class methodsFor:'documentation'!
version_HG
^ '$Changeset: <not expanded> $'
! !