On 18 Jan 2014, at 12:09, b...@openinworld.com wrote:

PharoLauncher is currently leaking AnnouncementSubscriptions when its window closes.  I'm not sure with Spec how to ensure actions are performed when the window is closed, but I have been able to achieve this with the following modification [1] which is...
-----
  WindowModel>>windowIsClosing
      isClosedHolder value: true
      self model windowIsClosing  "<----proposed modification"
-----

I investigated with a halt in SpecWindow>>close to trace through and discover that it calls...
SpecWindow(StandardWindow)>>delete, which in my non-fullscreen-case calls...
SpecWindow(SystemWindow)>>delete, which "model windowIsClosing" calls...
MorphicWindowAdaptor>>windowIsClosing, which "self model windowIsClosing" calls...
WindowModel>>windowIsClosing, which does only "isClosedHolder value: true"

That last line happens to hold aPharoLauncher in its 'model' instance variable, so with the above proposal I can implement PharoLauncher>>windowIsClosing to unregister the announcer.
Any problem expected with that modification?

[1] https://pharo.fogbugz.com/f/cases/12677

cheers -ben

Benjamin wrote:
I think i would be more elegant that the model register to the isClosedHolder changes :)

Ben

Hi Ben,

I've gave that a go and had some success, but it raised an architectural question I ask near the end.  I've documented my investigation here in case it is of use to others new to Spec or the Spec documentation being developed.

So references to i-var 'isClosedHolder' indicate this operates through #whenClosedDo:
which has three senders:
* InspectorNavigator>>initialize
* SpecDebugger>>initialize
* SpecPreDebugWindow>>initialize
All of which use the pattern...
    self whenWindowChanged: [ :w | w whenClosedDo: [ "do stuff" ] ].

I understand this I inserted the following breakpoints...
InspectorNavigator>>initialize
    ...
    self haltOnce. self whenWindowChanged:  [ :w | "outerBlock" self halt. w whenClosedDo:
            [ "innerBlock" self halt. self inspector close  ] ].

After enabling haltOnce and doing "1 inspect"...

Trace Part 1.
The first breakpoint (haltOnce) occurs in InspectorNavigator(ComposableModel)>>whenWindowChanged:
At this point before the window is created, the i-var 'window' holds "NewValueHolder [ nil ]". 
A few steps later it registers "outerBlock" on i-var 'window' for announcement ValueChanged .
It is interesting that the action is registered before the window is opened/exists.

Trace Part 2.
After a <proceed>, the "outerBlock" breakpoint occurs.
Down(or up?) the stack InspectorNavigator(ComposableModel)>>openWithSpecLayout:
does "window value: (WindowModel new model: self)"
so that a few steps up NewValueHolder>>valueChanged: effectively announces ValueChanged on i-var 'window'  .
such that WindowModel>>whenClosedDo:
executes to register the "innerBlock" on WindowModel's i-var 'isClosedHolder' for announcement ValueChanged.
The inspector then appears.

Trace Part 3.
When the close button on the inspector is clicked, the "innerBlock" breakpoint occurs.
Down the stack WindowModel>>windowIsClosing
does "isClosedHolder value: true"
so that a few steps up NewValueHolder>>valueChanged: announces ValueChanged on i-var 'isClosedHolder'
such that "self inspector close" is executed.

Armed with that understanding I found the following worked fine...
    PharoLauncher>>initialize
        super initialize.
        self whenWindowChanged: [ :w | w whenClosedDo: [ self releaseSubscriptions ] ].
with support from
    PharoLauncher>>releaseSubscriptions
        imagesModel releaseSubscriptions 
    PhLTitledTreeModel>>releaseSubscriptions
        self repository unsubscribe: self.

Where PharoLauncher and PhLTitledTreeModel are both subclassed from ComposableModel, and PhLTitledTreeModel is composed into PharoLauncher by the i-var 'imagesModel'.

However I could not help make the comparison of the simplicity of:
    PharoLauncher>>windowIsClosing
       self releaseSubscriptons
which is 1 stack level in the debugger away from WindowModel>>windowIsClosing and took about an hour to track down and understand...

versus isClosedHolder:
which has 22 stack levels for both Trace Part 1 and Trace Part 2 from the two levels of redirection with Announcements and taken many hours of play to get to my current point of understanding.

So what is gained in elegance from doing it the isClosedHolder way?

I thought that maybe... since all these components are meant to be composable, PhLTitledTreeModel should be self-contained about about releasing its subscriptions, by registering on isClosedHolder itself at the point where the subscription-of-concern is created. Otherwise relying on its owner PharoLauncher to call PhLTitledTreeModel >>releaseSubscriptions means if PhLTitledTreeModel is composed elsewhere in ClassX, then the onus is on ClassX to do the same thing. I had hoped that adding the last line here would work...
    PhLTitledTreeModel>>repository: aRepository
        repositoryHolder value: aRepository.
        self repository whenChangedSend: #refresh to: self.  "<--subscription-of-concern"
        self refresh.
        self whenWindowChanged: [ :w | w whenClosedDo: [ self repository unsubscribe: self ] ]. "<--added line"

since that would be quite elegant!  However it doesn't work since tracing through I find that the PhLTitledTreeModel i-var 'window' never changes from nil.  To work it seems like PhLTitledTreeModel i-var 'window' should be the same WindowModel as its owner PharoLauncher's i-var 'window'. 

So the question this leads up to is...
    Should child ComposableModels all reference the same WindowModel as their owner?

To my naive view (and direct need here) it makes intuitive sense that they should.  I envisage the case in a dockable UI where ComposableModels might be dragged out from being a subpane to having a window of their own, where you would want the call to #releaseSubscriptions to be independent of the owner.

Thanks for your patience on that long writeup.  I hope its clear - otherwise maybe we could communicate on IM or screenshare.
cheers -ben

Reply via email to