Hmm... this feature has quite an impact on Morph creation time and the overall memory footprint, right? Did you benchmark that somehow?
From a first impression, I would say:
-1 to keeping track of the #creatorStack because compiled methods can outdate in a long-running image +1 to keeping track of the #officialCreator because that could help setting a breakpoint at the right place
Still ... what if we would use PasteUpMorph >> addedMorph:? How would those stacks look like? What's the user requirements here? Something in the world or more a debugging tool at the level of halos?
Maybe there could be a way to keep track of morph creation explicitely?
Morph keepTrackOfCreationDuring: someBlock.
Even with a preference, adding such a thing to Morph >> #initialize requires actual benchmarks to asses the performance and memory overhead.
Just my two cents. :-)
Best, Marcel Am 23.09.2019 16:47:29 schrieb Thiede, Christoph christoph.thiede@student.hpi.uni-potsdam.de: How do you like that?
Can you notice a real performance impact when activating the preference? What is on Raspi?
Best, Christoph Von: Squeak-dev squeak-dev-bounces@lists.squeakfoundation.org im Auftrag von commits@source.squeak.org commits@source.squeak.org Gesendet: Montag, 23. September 2019 16:44:39 An: squeak-dev@lists.squeakfoundation.org Betreff: [squeak-dev] The Inbox: Morphic-ct.1540.mcz A new version of Morphic was added to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1540.mcz [http://source.squeak.org/inbox/Morphic-ct.1540.mcz]
==================== Summary ====================
Name: Morphic-ct.1540 Author: ct Time: 23 September 2019, 4:44:32.818523 pm UUID: 064f7940-90ea-1646-a6f5-6c0a82c06e91 Ancestors: Morphic-mt.1539
Proposal: Remember & explore provenance of any morph.
Sure, this is a performance regression (that's why it's turned off by default), but when you are debugging, I could tell you of so many cases in which this can be a useful utility. Looking at #browseCreatorMethod, we can also use this to allow beginners for quickly browsing the <example> method that created a morph.
=============== Diff against Morphic-mt.1539 ===============
Item was changed: Object subclass: #Morph instanceVariableNames: 'bounds owner submorphs fullBounds color extension' + classVariableNames: 'HaloForAll IndicateKeyboardFocus MetaMenuForAll PreferredCornerRadius RememberProvenance UseSoftDropShadow' - classVariableNames: 'HaloForAll IndicateKeyboardFocus MetaMenuForAll PreferredCornerRadius UseSoftDropShadow' poolDictionaries: '' category: 'Morphic-Kernel'! !Morph commentStamp: 'klc 3/14/2017 11:30' prior: 0! A Morph (from the Greek "shape" or "form") is an interactive graphical object. General information on the Morphic system can be found at http://wiki.squeak.org/squeak/30 [http://wiki.squeak.org/squeak/30]. Morphs exist in a tree, rooted at a World (generally a PasteUpMorph). The morphs owned by a morph are its submorphs. Morphs are drawn recursively; if a Morph has no owner it never gets drawn. To hide a Morph and its submorphs, set its #visible property to false using the #visible: method. The World (screen) coordinate system is used for most coordinates, but can be changed if there is a TransformMorph somewhere in the owner chain. My instance variables have accessor methods (e.g., #bounds, #bounds:). Most users should use the accessor methods instead of using the instance variables directly. Structure: instance var Type Description bounds Rectangle A Rectangle indicating my position and a size that will enclose me. owner Morph My parent Morph, or nil for the top-level Morph, which is a or nil world, typically a PasteUpMorph. submorphs Array My child Morphs. fullBounds Rectangle A Rectangle minimally enclosing me and my submorphs. color Color My primary color. Subclasses can use this in different ways. extension MorphExtension Allows extra properties to be stored without adding a or nil storage burden to all morphs. By default, Morphs do not position their submorphs. Morphs may position their submorphs directly or use a LayoutPolicy to automatically control their submorph positioning. Although Morph has some support for BorderStyle, most users should use BorderedMorph if they want borders.!
Item was added: + ----- Method: Morph class>>rememberProvenance (in category 'preferences') ----- + rememberProvenance + + <preference: 'Remember provenance of each morph' + categoryList: #(Morphic) + description: 'If enabled, each morph will contain a debug item to view its creator stack. This allows you to explore its provenance later. May affect performance.' + type: #Boolean> + ^ RememberProvenance ifNil: [false]!
Item was added: + ----- Method: Morph class>>rememberProvenance: (in category 'preferences') ----- + rememberProvenance: aBoolean + + RememberProvenance := aBoolean.!
Item was added: + ----- Method: Morph>>browseCreatorMethod (in category 'debug and other') ----- + browseCreatorMethod + + ^ (self valueOfProperty: #officialCreator) browse!
Item was changed: ----- Method: Morph>>buildDebugMenu: (in category 'debug and other') ----- buildDebugMenu: aHand "Answer a debugging menu for the receiver. The hand argument is seemingly historical and plays no role presently" | aMenu aPlayer | aMenu := MenuMorph new defaultTarget: self. aMenu addStayUpItem. (self hasProperty: #errorOnDraw) ifTrue: [aMenu add: 'start drawing again' translated action: #resumeAfterDrawError. aMenu addLine]. (self hasProperty: #errorOnStep) ifTrue: [aMenu add: 'start stepping again' translated action: #resumeAfterStepError. aMenu addLine]. aMenu add: 'inspect morph' translated action: #inspectInMorphic:. aMenu add: 'inspect owner chain' translated action: #inspectOwnerChain. Smalltalk isMorphic ifFalse: [aMenu add: 'inspect morph (in MVC)' translated action: #inspect]. self isMorphicModel ifTrue: [aMenu add: 'inspect model' translated target: self model action: #inspect; add: 'explore model' translated target: self model action: #explore]. (aPlayer := self player) ifNotNil: [aMenu add: 'inspect player' translated target: aPlayer action: #inspect]. aMenu add: 'explore morph' translated target: self selector: #exploreInMorphic:. aMenu addLine. aPlayer ifNotNil: [ aMenu add: 'viewer for Player' translated target: self player action: #beViewed. aMenu balloonTextForLastItem: 'Opens a viewer on my Player -- this is the same thing you get if you click on the cyan "View" halo handle' translated ]. aMenu add: 'viewer for Morph' translated target: self action: #viewMorphDirectly. aMenu balloonTextForLastItem: 'Opens a Viewer on this Morph, rather than on its Player' translated. aMenu addLine. aPlayer ifNotNil: [aPlayer class isUniClass ifTrue: [ aMenu add: 'browse player class' translated target: aPlayer selector: #haveFullProtocolBrowsedShowingSelector: argumentList: #(nil)]]. aMenu add: 'browse morph class' translated target: self selector: #browseHierarchy. + self isMorphicModel - (self isMorphicModel) ifTrue: [aMenu add: 'browse model class' target: self model selector: #browseHierarchy]. + (self valueOfProperty: #officialCreator ifAbsent: [nil]) ifNotNil: [ + aMenu add: 'browse creator method' action: #browseCreatorMethod]. + (self hasProperty: #creatorStack) ifTrue: [ + aMenu add: 'explore creator stack' action: #exploreCreatorStack]. aMenu addLine. self addViewingItemsTo: aMenu. aMenu add: 'make own subclass' translated action: #subclassMorph; add: 'save morph in file' translated action: #saveOnFile; addLine; add: 'call #tempCommand' translated action: #tempCommand; add: 'define #tempCommand' translated action: #defineTempCommand; addLine; add: 'control-menu...' translated target: self selector: #invokeMetaMenu:; add: 'edit balloon help' translated action: #editBalloonHelpText. ^ aMenu!
Item was added: + ----- Method: Morph>>exploreCreatorStack (in category 'debug and other') ----- + exploreCreatorStack + + ^ (self valueOfProperty: #creatorStack) explore!
Item was changed: ----- Method: Morph>>initialize (in category 'initialization') ----- initialize "initialize the state of the receiver" owner := nil. submorphs := Array empty. bounds := self defaultBounds. + color := self defaultColor. + self class rememberProvenance ifTrue: [ + | creatorStack | + creatorStack := thisContext home stack collect: #method. + self setProperty: #creatorStack toValue: creatorStack. + creatorStack + detect: [:method | method hasPragma: #example] + ifFound: [:method | self setProperty: #officialCreator toValue: method]].! - color := self defaultColor!