<body><div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
                                        <div><span style="font-size: 13.3333px">Hi Christoph, hi all.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">Let me add some more details about my reasoning behind Morphic-mt.1761.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">First of all, let me explain the "code smells" that I found in the changeset:</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">1. Relying on the overly specific entry point Browser class >> #browseMethodFull.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">2. Adapting HierarchyBrowser probably because of the first smell, breaking existing behavior.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">3. Implicitly adding (and thus "simulating") a dynamic variable via set-and-ensure.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">***</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">I noticed that the role of a "requestor" is participating in the "Reuse windows" preference. I am familiar with this role in the sense that model-view communication (e.g. PluggableListMorph to Browser) uses it to some extent. So, instead of being focused on who should not see that preference (i.e. hacking global state), it makes sense to design its intentions more clearly. In my opinion, that's the better object-oriented design. It's more robust.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">Now, a safe way to pass a requestor along is as message argument. See Morph >> #mouseLeave: and EventHandler >> #mouseLeave:fromMorph: as an example. However, this role might emerge only later in the design process. Then you have the problem of old code relying on the existing interface. What then? A dynamically scoped variable might help.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">Yet, dynamic scope can be challenging to maintain. Especially when having the notion of an ever-running image (object memory), which is highly state-based, dynamic scope can be easily messed up. Any object could choose to reset (and rely on) the scope for its own purpose. That's dangerous. Faulty behavior might become difficult to trace and understand without the right tools. Even with the right tools, the underlying design might have become accidentally more complex than it needs to be.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">In Morphic, we have the dynamically scoped ActiveWorld(Variable), ActiveHand(Variable), and ActiveEvent(Variable) to support scenarios where one of those basic objects is not available in a messages send. For examples, browse senders of #currentEvent or #currentWorld. Unfortunately, we have to take care that only well-defined places reset this scope. Such managing of global contracts can be quite effortful. ... The user interrupt (i.e. CMD+Dot) comes to mind. It must work; the system must stay responsive.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">Let's treat the use of a dynamic variable as "forward scope." There is another way. A way that avoids the risks of not knowing what might happen within that scope through sends to come. Instead, we can take a look at thisContext, which allows reasoning about the current scope "backwards" and "at rest."</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">Is a query over thisContext always a solution to a missing argument in the message send? Surely not. We are lucky enough to benefit from some inherent properties of the Morphic design:</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">1. Single UI process</span></div><div><span style="font-size: 13.3333px">2. Little use of deferred UI messages; no use of other async UI request via promises etc.</span></div><div><span style="font-size: 13.3333px">3. Clear user model through morph composition; whole-parts hierarchy visible in pixels</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">To sum up my intentions behind Morphic-mt.1761, I looked for a way to implement the role of a "requestor" for the "Reuse windows" preference as concise (!) as possible -- at a single place to reduce the cost of future maintenance. After pondering the pros and cons of "global state", "dynamic forward scope", and "resting backward scope" in Morphic, I decided to apply meta programming to look into thisContext to figure out the current "requestor." Given that the solution is at a single place (!), I think that future adjustments will remain manageable.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">If - at some point - Morphic's properties would change and hence not allow the current approach, I would keep looking for a way to clearly implement the role of a "requestor." At worst, the "reuse windows" preference might just not be supported under some circumstances. I would never risk hacking the entire system just for some edge case.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">Yet, I stay confident. We will find a way. If it would mean to re-design #openInWorld: to always supply a requestor, we should do it, maybe by adding #openInWorld:from:. And clearly mark the missing requestor as "discouraged" because you would loose certain effects (or preferences). Well, this takes time and patience.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">Until then, let's just keep this little piece of meta-programming to look up thisContext in SystemWindow >> #anyOpenWindowLikeMeIn:. Maybe add an extra flag to emphasize it a little bit more. To be able to quickly find it once we have a better solution for it.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">***</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">TL;DR: For the Squeak system, dynamic scope is only a little bit better than relying on global state. At best, all required information are in the message arguments. The next better thing is receiver state (i.e. instVars). After that, it gets tricky. Remember that singletons (e.g. SystemWindow class >> #topWindow) are global state, too.</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">Happy squeaking! :-)</span></div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">Best,</span></div><div><span style="font-size: 13.3333px">Marcel</span></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;'>
                        <p style='color: #AAAAAA; margin-top: 10px;'>Am 01.05.2021 19:10:25 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.de>:</p><div style='font-family:Arial,Helvetica,sans-serif'>

<div id="divtagdefaultwrapper" style="font-size: 12pt;color: #000000;font-family: Calibri,Helvetica,sans-serif" dir="ltr">
<p>Hi Marcel,</p>
<p><br>
</p>
<p>thanks for your review, I will notify you if I identify any regressions. :-)</p>
<p><br>
</p>
<p>But your metaprogramming approach from <span>Morphic-mt.1761</span> ... To be honest, I cannot really say that I would like it. Such magic can be very hard to debug, explore, extend, etc. IMHO, in Smalltalk, we can do better. :-) Instead, I believe an explicit
 method that to turn off #reuseWindows temporarily would be a better option. If #<span>browseMethodFull is used too frequently, maybe we could wrap it into a new selector #browseMethodFullNew?</span></p>
<p><span><br>
</span></p>
<p><span>Looking at the current solution, I would even prefer a (kind of global) variable that temporarily holds a Model/Browser instance that does not want to reused - for instance:</span></p>
<p><span></span></p>
<div>----- Method: SystemWindow>>anyOpenWindowLikeMeIn: (in category 'open/close') -----</div>
<div>anyOpenWindowLikeMeIn: aPasteUpMorph</div>
<div><span style="font-size: 12pt">
<div>| requestor |</div>
</span></div>
<div><span style="font-size: 12pt">self class reuseWindows ifFalse: [ ^ Array empty ].</span><br>
</div>
<div>requestor := Model currentRequestorNotToBeReused.</div>
<div>...</div>
<div><br>
</div>
<div>Best,</div>
<div>Christoph</div>
<p></p>
<div id="Signature">
<div id="divtagdefaultwrapper" dir="ltr" style="font-size: 12pt;color: rgb(0, 0, 0);font-family: Calibri, Helvetica, sans-serif, EmojiFont, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols">
<div name="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>
</div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="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 Taeumel, Marcel<br>
<b>Gesendet:</b> Montag, 26. April 2021 10:03:32<br>
<b>An:</b> squeak-dev<br>
<b>Betreff:</b> Re: [squeak-dev] The Trunk: Morphic-eem.1719.mcz</span>
<div> </div>
</div>
<div>
<div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
Hi Christoph,
<div class="mb_sig"></div>
<div><br>
</div>
<div>I somewhat integrated your proposed changes into Trunk. :-)</div>
<div><br>
</div>
<div>Browser >> #representsSameBrowseeAs:</div>
<div>SearchBar >> #smartSearch:in:</div>
<div>SystemWindow >> #anyOpenWindowLikeMeIn:</div>
<div><br>
</div>
<div>Note that a tool's buttons can typically be used to duplicate the tool if desired. Thus, it is not an option to just remove the "hierarchy" button, for example, if it interferes with the "re-use windows" preference -- which you proposed. Also, by just
 hacking into #browseMethodFull for Browser, you omit all the other possible paths that might interfere with that preference. Well, preference settings might have other side effects, yet, if one would want to do that (e.g., in tests), you must put it into the
 ensure context:</div>
<div><span style="white-space: pre;"></span><br>
</div>
<div>
<div><span style="font-size: 13.3333px">^ [</span><span style="font-size: 10pt">systemWindow reuseWindows: false. </span>super browseMethodFull]</div>
<div><span style="font-size: 13.3333px"><span style="white-space:pre"></span>ensure: [systemWindow reuseWindows: previous]</span></div>
</div>
<div><br>
</div>
<div>Anyway -- instead -- I added the constraint that the requesting window should not be considered as a re-use candidate. With our current tool architecture, I had to resort to meta programming (i.e. context checking). I hope that you won't notice any performance
 glitches.</div>
<div><br>
</div>
<div>(Took be about 1.5 hours.)</div>
<div><br>
</div>
<div>Best,</div>
<div>Marcel</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 25.04.2021 22:36:47 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.de>:</p>
<div style="font-family:Arial,Helvetica,sans-serif">
<div id="divtagdefaultwrapper" style="font-size: 12pt;color: #000000;font-family: Calibri,Helvetica,sans-serif" dir="ltr">
<p>Hi all,</p>
<p><br>
</p>
<p>please find the attached changeset which fixes the regression of the smart search bar not honoring the #reuseWindows preference. Also, I added a proper implementation of #reuseWindows for browsers. Please review and/or merge! :-)</p>
<p><br>
</p>
<p>Best,</p>
<p>Christoph</p>
<p><br>
</p>
<p>PS: What is packages@lists.squeakfoundation.org and why is it being cc'ed in this conversation?</p>
<div id="Signature">
<div id="divtagdefaultwrapper" dir="ltr" style="font-size: 12pt;color: rgb(0, 0, 0);font-family: Calibri, Helvetica, sans-serif, EmojiFont, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols">
<div name="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>
</div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="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 Chris Muller <asqueaker@gmail.com><br>
<b>Gesendet:</b> Freitag, 5. Februar 2021 22:19:13<br>
<b>An:</b> The general-purpose Squeak developers list<br>
<b>Cc:</b> packages@lists.squeakfoundation.org<br>
<b>Betreff:</b> Re: [squeak-dev] The Trunk: Morphic-eem.1719.mcz</span>
<div> </div>
</div>
<div>
<div dir="ltr">Hi Christoph!
<div><br>
</div>
<div>I thought this feature seemed reminiscent of Reuse Windows as well.  The method to hook in each Model subclass (as needed) is #representsSameBrowseeAs:.  Looking at that, you can see that simply making your code pane temporarily dirty, an additional window
 will be spawned.  I mention that because Reuse Windows is fantastic and I hate to see your experience with it ruined over something so trivial.  :)</div>
<div><br>
</div>
<div>You do also have the green duplicate halo.  People are happy to use "non-standard" UI features in other IDE's, but there seems to be an aversion to people using halos in Squeak.  I could be wrong about that, but I find the duplicate halo useful quite often.</div>
<div><br>
</div>
<div> - Chris</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Thu, Feb 4, 2021 at 7:14 PM Thiede, Christoph <<a href="mailto:Christoph.Thiede@student.hpi.uni-potsdam.de" target="_blank">Christoph.Thiede@student.hpi.uni-potsdam.de</a>> wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex;border-left: 1px solid rgb(204,204,204);padding-left: 1ex;min-width: 500px">
<div>
<div dir="ltr">
<div id="gmail-m_9093067954458625683gmail-m_6432014879716207574gmail-m_6310697106371890450x_divtagdefaultwrapper" dir="ltr" style="font-size: 12pt;color: rgb(0,0,0);font-family: Calibri,Helvetica,sans-serif">
<p>Hi Eliot,</p>
<p><br>
</p>
<p>could you please honor the "<span>SystemWindow reuseWindows" here? I have turned that preference off in my image because I actually use to accept a class name multiple times in the search bar in order to open multiple windows - for instance, to view different
 protocols of the same class side-by-side. It would be great if this would work soon again ... :-)</span></p>
<p><span><br>
</span></p>
<p><span>Best,</span></p>
<p><span>Christoph</span></p>
<div id="gmail-m_9093067954458625683gmail-m_6432014879716207574gmail-m_6310697106371890450x_Signature">
<div id="gmail-m_9093067954458625683gmail-m_6432014879716207574gmail-m_6310697106371890450x_divtagdefaultwrapper" dir="ltr" style="font-size: 12pt;color: rgb(0,0,0);font-family: Calibri,Helvetica,sans-serif,EmojiFont,"Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols">
<div name="x_divtagdefaultwrapper">
<div><span style="font-size: 10pt;color: #808080"></span></div>
</div>
</div>
</div>
</div>
<hr style="display:inline-block;width:98%">
<div id="gmail-m_9093067954458625683gmail-m_6432014879716207574gmail-m_6310697106371890450x_divRplyFwdMsg" dir="ltr">
<span style="font-family: Calibri, sans-serif;color: #000000"><b>Von:</b> Squeak-dev <<a href="mailto:squeak-dev-bounces@lists.squeakfoundation.org" target="_blank">squeak-dev-bounces@lists.squeakfoundation.org</a>> im Auftrag von
<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a> <<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>><br>
<b>Gesendet:</b> Donnerstag, 4. Februar 2021 03:38:15<br>
<b>An:</b> <a href="mailto:squeak-dev@lists.squeakfoundation.org" target="_blank">
squeak-dev@lists.squeakfoundation.org</a>; <a href="mailto:packages@lists.squeakfoundation.org" target="_blank">
packages@lists.squeakfoundation.org</a><br>
<b>Betreff:</b> [squeak-dev] The Trunk: Morphic-eem.1719.mcz</span>
<div> </div>
</div>
</div>
<span style="font-size: 10pt"><span style="font-size: 10pt">
<div>Eliot Miranda uploaded a new version of Morphic to project The Trunk:<br>
<a href="http://source.squeak.org/trunk/Morphic-eem.1719.mcz" target="_blank">http://source.squeak.org/trunk/Morphic-eem.1719.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: Morphic-eem.1719<br>
Author: eem<br>
Time: 3 February 2021, 6:38:11.11355 pm<br>
UUID: ffb981b1-7c53-4fbe-b6f4-4c8f27c79f5a<br>
Ancestors: Morphic-mt.1718<br>
<br>
Make SearchBar>>#smartSearch:in: search existing browsers for a class name being searched for, bringing the first such browser to the front and selecting the class.  This allows one to find classes in browsers either when one has very many, or when one is using
 multi-window browsers containing many many classes.<br>
<br>
=============== Diff against Morphic-mt.1718 ===============<br>
<br>
Item was added:<br>
+ ----- Method: Browser>>displayClass: (in category '*Morphic-Menus-DockingBar-accessing') -----<br>
+ displayClass: aClass<br>
+        "Assuming the receiver has answered true to isDisplayingClass:, come to the front and select the given class."<br>
+        | index |<br>
+        index := self multiWindowIndexForClassName: aClass.<br>
+        index  ~= 0 ifTrue:<br>
+                [multiWindowState selectWindowIndex: index].<br>
+        self selectClass: aClass!<br>
<br>
Item was added:<br>
+ ----- Method: Browser>>isDisplayingClass: (in category '*Morphic-Menus-DockingBar-accessing') -----<br>
+ isDisplayingClass: aClass<br>
+        | className |<br>
+        className := aClass name.<br>
+        (self multiWindowIndexForClassName: className) ~= 0 ifTrue: [^true].<br>
+        ^selectedClassName = className!<br>
<br>
Item was added:<br>
+ ----- Method: Browser>>multiWindowIndexForClassName: (in category '*Morphic-Menus-DockingBar-accessing') -----<br>
+ multiWindowIndexForClassName: className<br>
+        "Answer the index of a browser displaying className in multiWindowState, if any.<br>
+         Otherwise answer zero."<br>
+        multiWindowState ifNil: [^0].<br>
+        multiWindowState models withIndexDo:<br>
+                [:browser :index|<br>
+                browser selectedClassName = className ifTrue: [^index]].<br>
+        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: SearchBar>>smartSearch:in: (in category 'searching') -----<br>
  smartSearch: text in: morph<br>
         "Take the user input and perform an appropriate search"<br>
         | input newContents |<br>
         self removeResultsWidget.<br>
         input := text asString ifEmpty:[^self].<br>
         self class useSmartSearch ifFalse: [^ ToolSet default browseMessageNames: input].<br>
  <br>
+        (Symbol findInterned: input) ifNotNil:<br>
+                [:symbol| input := symbol].<br>
         "If it is a global or a full class name, browse that class."<br>
+        (Smalltalk bindingOf: input) ifNotNil:<br>
+                [:assoc| | class |<br>
+                class := (assoc value isBehavior ifTrue:[assoc value] ifFalse:[assoc value class]) theNonMetaClass.<br>
+                Project current world submorphs do:<br>
+                        [:windowMorph|<br>
+                         (windowMorph isSystemWindow<br>
+                          and: [(windowMorph model isKindOf: Browser)<br>
+                          and: [windowMorph model isDisplayingClass: class]]) ifTrue:<br>
+                                [windowMorph beKeyWindow.<br>
+                                 ^windowMorph model displayClass: class]].<br>
+                ^ToolSet browse: class selector: nil].<br>
-        (Smalltalk bindingOf: input) ifNotNil:[:assoc| | global |<br>
-                global := assoc value.<br>
-                ^ToolSet browse: (global isBehavior ifTrue:[global] ifFalse:[global class]) selector: nil].<br>
         <br>
         "If it is a symbol and there are implementors of it, browse those implementors."<br>
         Symbol hasInterned: input ifTrue: [:selector |<br>
                 (SystemNavigation new allImplementorsOf: selector) ifNotEmpty:[:list|<br>
                         ^SystemNavigation new<br>
                                 browseMessageList: list<br>
                                 name: 'Implementors of ' , input]].<br>
  <br>
         "If it starts uppercase, browse classes if any. Otherwise, just search for messages."<br>
+        input first isUppercase ifTrue:<br>
+                [(UIManager default classFromPattern: input withCaption: '')<br>
+                        ifNotNil:[:aClass| ^ToolSet browse: aClass selector: nil].<br>
+                newContents := input, ' -- not found.'.<br>
+                self searchTerm: newContents.<br>
+                self selection: (input size+1 to: newContents size).<br>
+                self currentHand newKeyboardFocus: morph textMorph.<br>
+                ^ self].<br>
+ <br>
+        "Default to browse message names..."<br>
+        ToolSet default browseMessageNames: input!<br>
-        input first isUppercase<br>
-                ifTrue: [<br>
-                        (UIManager default classFromPattern: input withCaption: '')<br>
-                                ifNotNil:[:aClass| ^ToolSet browse: aClass selector: nil]<br>
-                                ifNil: [<br>
-                                        newContents := input, ' -- not found.'.<br>
-                                        self searchTerm: newContents.<br>
-                                        self selection: (input size+1 to: newContents size).<br>
-                                        self currentHand newKeyboardFocus: morph textMorph.<br>
-                                        ^ self]]<br>
-                ifFalse: [<br>
-                        ToolSet default browseMessageNames: input].!<br>
<br>
<br>
</div>
</span></span></div>
<br>
</blockquote>
</div>
</div>
</div>
</blockquote>
</div>
</div>
</div></blockquote>
                                        </div></body>