<div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000">
                                        
                                        
                                            
                                        
                                        
                                        <div>Hmm... this feature has quite an impact on Morph creation time and the overall memory footprint, right? Did you benchmark that somehow?</div><div><br></div><div>From a first impression, I would say:</div><div><br></div><div>-1 to keeping track of the #<span style="font-family: Arial, Helvetica, sans-serif;font-size: 13.3333px">creatorStack because compiled methods can outdate in a long-running image</span></div><div>+1 to keeping track of the #<span style="font-family: Arial, Helvetica, sans-serif;font-size: 13.3333px">officialCreator because that could help setting a breakpoint at the right place</span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13.3333px"><br></span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13.3333px">Still ... w</span><span style="font-size: 10pt">hat 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?</span></div><div><br></div><div>Maybe there could be a way to keep track of morph creation explicitely?</div><div><br></div><div>Morph keepTrackOfCreationDuring: someBlock.</div><div><br></div><div>Even with a preference, adding such a thing to Morph >> #initialize requires actual benchmarks to asses the performance and memory overhead.</div><div><br></div><div>Just my two cents. :-)</div><div><br></div><div>Best,</div><div>Marcel</div><div class="mb_sig"></div>
                                        
                                        <blockquote class="history_container" type="cite" style="border-left-style: solid;border-width: 1px;margin-top: 20px;margin-left: 0px;padding-left: 10px;min-width: 500px">
                        <p style="color: #AAAAAA; margin-top: 10px;">Am 23.09.2019 16:47:29 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.de>:</p><div style="font-family:Arial,Helvetica,sans-serif">
<meta content="text/html; charset=UTF-8">
<style type="text/css" style="">
<!--
p
        {margin-top:0;
        margin-bottom:0}
-->
</style>
<div dir="ltr">
<div id="x_divtagdefaultwrapper" dir="ltr" style="font-size: 12pt;color: #000000;font-family: Calibri,Helvetica,sans-serif">
<p>How do you like that?</p>
<p><img size="29554" id="x_img206000" tabindex="0" style="max-width:99.9%" src="cid:b635a64a-7981-444c-af79-70188915420b"></img><br>
</p>
<p>Can you notice a real performance impact when activating the preference? What is on Raspi?</p>
<p><br>
</p>
<p>Best,</p>
<p>Christoph</p>
<div id="x_Signature">
<div name="x_divtagdefaultwrapper" style="font-family: Calibri,Arial,Helvetica,sans-serif;font-size: ;margin: 0">
<div><span style="font-size: 10pt;color: #808080"></span></div>
</div>
</div>
</div>
<hr tabindex="-1" style="display:inline-block; width:98%">
<div id="x_divRplyFwdMsg" dir="ltr"><span style="font-family: Calibri, sans-serif;color: #000000"><b>Von:</b> Squeak-dev <squeak-dev-bounces@lists.squeakfoundation.org> im Auftrag von commits@source.squeak.org <commits@source.squeak.org><br>
<b>Gesendet:</b> Montag, 23. September 2019 16:44:39<br>
<b>An:</b> squeak-dev@lists.squeakfoundation.org<br>
<b>Betreff:</b> [squeak-dev] The Inbox: Morphic-ct.1540.mcz</span>
<div> </div>
</div>
</div>
<span style="font-size: 10pt"><span style="font-size: 10pt">
<div class="PlainText">A new version of Morphic was added to project The Inbox:<br>
<a href="http://source.squeak.org/inbox/Morphic-ct.1540.mcz">http://source.squeak.org/inbox/Morphic-ct.1540.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: Morphic-ct.1540<br>
Author: ct<br>
Time: 23 September 2019, 4:44:32.818523 pm<br>
UUID: 064f7940-90ea-1646-a6f5-6c0a82c06e91<br>
Ancestors: Morphic-mt.1539<br>
<br>
Proposal: Remember & explore provenance of any morph.<br>
<br>
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.<br>
<br>
=============== Diff against Morphic-mt.1539 ===============<br>
<br>
Item was changed:<br>
  Object subclass: #Morph<br>
         instanceVariableNames: 'bounds owner submorphs fullBounds color extension'<br>
+        classVariableNames: 'HaloForAll IndicateKeyboardFocus MetaMenuForAll PreferredCornerRadius RememberProvenance UseSoftDropShadow'<br>
-        classVariableNames: 'HaloForAll IndicateKeyboardFocus MetaMenuForAll PreferredCornerRadius UseSoftDropShadow'<br>
         poolDictionaries: ''<br>
         category: 'Morphic-Kernel'!<br>
  <br>
  !Morph commentStamp: 'klc 3/14/2017 11:30' prior: 0!<br>
  A Morph (from the Greek "shape" or "form") is an interactive graphical object. General information on the Morphic system can be found at
<a href="http://wiki.squeak.org/squeak/30">http://wiki.squeak.org/squeak/30</a>. <br>
  <br>
  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. <br>
  <br>
  The World (screen) coordinate system is used for most coordinates, but can be changed if there is a TransformMorph somewhere in the owner chain.
<br>
  <br>
  My instance variables have accessor methods (e.g., #bounds, #bounds:). Most users should use the accessor methods instead of using the instance variables directly.<br>
  <br>
  Structure:<br>
  instance var   Type                     Description <br>
  bounds                         Rectangle                A Rectangle indicating my position and a size that will enclose                                                                  me.
<br>
  owner                  Morph             My parent Morph, or nil for the top-level Morph, which is a<br>
                                 or nil                  world, typically a PasteUpMorph.<br>
  submorphs              Array                    My child Morphs. <br>
  fullBounds             Rectangle                A Rectangle minimally enclosing me and my submorphs.
<br>
  color                  Color                    My primary color. Subclasses can use this in different ways.
<br>
  extension              MorphExtension Allows extra properties to be stored without adding a<br>
                                 or nil                           storage burden to all morphs.
<br>
  <br>
  By default, Morphs do not position their submorphs. Morphs may position their submorphs directly or use a LayoutPolicy to automatically control their submorph positioning.<br>
  <br>
  Although Morph has some support for BorderStyle, most users should use BorderedMorph if they want borders.!<br>
<br>
Item was added:<br>
+ ----- Method: Morph class>>rememberProvenance (in category 'preferences') -----<br>
+ rememberProvenance<br>
+ <br>
+        <preference: 'Remember provenance of each morph'<br>
+                categoryList: #(Morphic)<br>
+                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.'<br>
+                type: #Boolean><br>
+        ^ RememberProvenance ifNil: [false]!<br>
<br>
Item was added:<br>
+ ----- Method: Morph class>>rememberProvenance: (in category 'preferences') -----<br>
+ rememberProvenance: aBoolean<br>
+ <br>
+        RememberProvenance := aBoolean.!<br>
<br>
Item was added:<br>
+ ----- Method: Morph>>browseCreatorMethod (in category 'debug and other') -----<br>
+ browseCreatorMethod<br>
+ <br>
+        ^ (self valueOfProperty: #officialCreator) browse!<br>
<br>
Item was changed:<br>
  ----- Method: Morph>>buildDebugMenu: (in category 'debug and other') -----<br>
  buildDebugMenu: aHand<br>
         "Answer a debugging menu for the receiver.  The hand argument is seemingly historical and plays no role presently"<br>
  <br>
         | aMenu aPlayer |<br>
         aMenu := MenuMorph new defaultTarget: self.<br>
         aMenu addStayUpItem.<br>
         (self hasProperty: #errorOnDraw) ifTrue:<br>
                 [aMenu add: 'start drawing again' translated action: #resumeAfterDrawError.<br>
                 aMenu addLine].<br>
         (self hasProperty: #errorOnStep) ifTrue:<br>
                 [aMenu add: 'start stepping again' translated action: #resumeAfterStepError.<br>
                 aMenu addLine].<br>
  <br>
         aMenu add: 'inspect morph' translated action: #inspectInMorphic:.<br>
         aMenu add: 'inspect owner chain' translated action: #inspectOwnerChain.<br>
         Smalltalk isMorphic ifFalse:<br>
                 [aMenu add: 'inspect morph (in MVC)' translated action: #inspect].<br>
  <br>
         self isMorphicModel ifTrue:<br>
                 [aMenu add: 'inspect model' translated target: self model action: #inspect;<br>
                         add: 'explore model' translated target: self model action: #explore].<br>
         (aPlayer := self player) ifNotNil:<br>
                 [aMenu add: 'inspect player' translated target: aPlayer action: #inspect].<br>
  <br>
       aMenu add: 'explore morph' translated target: self selector: #exploreInMorphic:.<br>
  <br>
         aMenu addLine.<br>
         aPlayer ifNotNil:<br>
                 [ aMenu add: 'viewer for Player' translated target: self player action: #beViewed.<br>
         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 ].<br>
  <br>
         aMenu add: 'viewer for Morph' translated target: self action: #viewMorphDirectly.<br>
         aMenu balloonTextForLastItem: 'Opens a Viewer on this Morph, rather than on its Player' translated.<br>
         aMenu addLine.<br>
  <br>
         aPlayer ifNotNil:<br>
                 [aPlayer class isUniClass ifTrue: [<br>
                         aMenu add: 'browse player class' translated target: aPlayer selector: #haveFullProtocolBrowsedShowingSelector: argumentList: #(nil)]].<br>
         aMenu add: 'browse morph class' translated target: self selector: #browseHierarchy.<br>
+        self isMorphicModel<br>
-        (self isMorphicModel)<br>
                 ifTrue: [aMenu<br>
                                 add: 'browse model class'<br>
                                 target: self model<br>
                                 selector: #browseHierarchy].<br>
+        (self valueOfProperty: #officialCreator ifAbsent: [nil]) ifNotNil: [<br>
+                aMenu add: 'browse creator method' action: #browseCreatorMethod].<br>
+        (self hasProperty: #creatorStack) ifTrue: [<br>
+                aMenu add: 'explore creator stack' action: #exploreCreatorStack].<br>
         aMenu addLine.<br>
  <br>
         self addViewingItemsTo: aMenu.<br>
         aMenu <br>
                 add: 'make own subclass' translated action: #subclassMorph;<br>
                 add: 'save morph in file' translated  action: #saveOnFile;<br>
                 addLine;<br>
                 add: 'call #tempCommand' translated action: #tempCommand;<br>
                 add: 'define #tempCommand' translated action: #defineTempCommand;<br>
                 addLine;<br>
  <br>
                 add: 'control-menu...' translated target: self selector: #invokeMetaMenu:;<br>
                 add: 'edit balloon help' translated action: #editBalloonHelpText.<br>
  <br>
         ^ aMenu!<br>
<br>
Item was added:<br>
+ ----- Method: Morph>>exploreCreatorStack (in category 'debug and other') -----<br>
+ exploreCreatorStack<br>
+ <br>
+        ^ (self valueOfProperty: #creatorStack) explore!<br>
<br>
Item was changed:<br>
  ----- Method: Morph>>initialize (in category 'initialization') -----<br>
  initialize<br>
         "initialize the state of the receiver"<br>
         owner := nil.<br>
         submorphs := Array empty.<br>
         bounds := self defaultBounds.<br>
+        color := self defaultColor.<br>
+        self class rememberProvenance ifTrue: [<br>
+                | creatorStack |<br>
+                creatorStack := thisContext home stack collect: #method.<br>
+                self setProperty: #creatorStack toValue: creatorStack.<br>
+                creatorStack<br>
+                        detect: [:method | method hasPragma: #example]<br>
+                        ifFound: [:method | self setProperty: #officialCreator toValue: method]].!<br>
-        color := self defaultColor!<br>
<br>
<br>
</div>
</span></span>
</div></blockquote></div>