On Friday, June 19, 2020 at 8:33:43 PM UTC-5, Félix wrote:
>
> I'm doing preliminary tests with the "close" method in order to support 
> multiple Leo files in leoInteg.
>

This is an excellent question. I think you understand the overall situation 
quite well.

I wrote a preliminary answer without realizing you had added the addendum. 
I don't see the addendum in my email, presumably because your edit didn't 
trigger another email. In future, please reply to yourself, rather than 
doing a major edit.


> def closeFile(self, p_paramUnused):
> '''Closes a leo file. A file can then be opened with "openFile"'''
> print("Trying to close opened file " + str(self.commander.changed))
> if self.commander:
> if self.commander.changed:
> return self.sendLeoBridgePackage('closed', False)
> else:
> self.commander.close()
> return self.sendLeoBridgePackage('closed', True)
> return self.sendLeoBridgePackage() # Just send empty as 'did nothing'
>
> After going through the second branch and actually calling the .close() 
> method on the controller that was made with the leoBridge, since I didnt 
> change anything else to support a 'closed' commander, I expected the 
> leoInteg view to fatally crash because all subsequent calls to 
> 'getChildren' etc. would obviously fail because the commander was closed. 
>
> Surprising thing is : There is no crash and I can seemingly do any 
> browsing and editing as I could before the .close() call...
>
> I suspect it's me who's not understanding what the self.commander.close 
> method is actually expected to do, or maybe I should be calling something 
> like "self.commander.file.close()" or something like that... Or maybe that 
> just lowered an "opened" flag somewhere and all objects are still valid 
> pointers until python does garbage collecting... i dunno :/
>
> If anyone can shed some light on this it would be greatly appreciated! :)
>

See below. 

*EDIT / ADDENDUM WHILE STEPPING THROUGH WITH THE DEBUGGER*
> First it goes through this: 
>
> @g.commander_command('close-window')
> def close(self, event=None, new_c=None):
> """Close the Leo window, prompting to save it if it has been changed."""
> g.app.closeLeoWindow(self.frame, new_c=new_c)
>
>
Yes. This is the code that corresponds to c.close(). The decorator injects 
this method into to all open commanders! 

and then it goes through this without problems ... 
> def closeLeoWindow(self, frame, new_c=None, finish_quit=True):
> """
> Attempt to close a Leo window.
>
> Return False if the user veto's the close.
>
> finish_quit - usually True, close Leo when last file closes, but
> False when closing an already-open-elsewhere file
> during initial load, so UI remains for files
> further along the command line.
> """
> c = frame.c
> if 'shutdown' in g.app.debug:
> g.trace(f"changed: {c.changed} {c.shortFileName()}")
> c.endEditing() # Commit any open edits.
> if c.promptingForClose:
> # There is already a dialog open asking what to do.
> return False
> g.app.recentFilesManager.writeRecentFilesFile(c)
> # Make sure .leoRecentFiles.txt is written.
> if c.changed:
> c.promptingForClose = True
> veto = frame.promptForSave()
> c.promptingForClose = False
> if veto: return False
> g.app.setLog(None) # no log until we reactive a window.
> g.doHook("close-frame", c=c)
> #
> # Save the window state for *all* open files.
> g.app.saveWindowState(c)
> g.app.saveEditorDockState(c)
> g.app.commander_cacher.commit()
> # store cache, but don't close it.
> # This may remove frame from the window list.
> if frame in g.app.windowList:
> g.app.destroyWindow(frame)
> g.app.windowList.remove(frame)
> else:
> # #69.
> g.app.forgetOpenFile(fn=c.fileName(), force=True)
> if g.app.windowList:
> c2 = new_c or g.app.windowList[0].c
> g.app.selectLeoWindow(c2)
> elif finish_quit and not g.app.unitTesting:
> g.app.finishQuit()
> return True # The window has been closed.
>
>
Exactly.

Again, since I've got no gui and the commander I'm closing was opened 
> through leoBridge, I guess I should just then 'pop' the commander from the 
> array I was keeping it in, and consider it "closed" and its 'ressources' 
> will be freed eventually? ( as this reference seems to indicate? 
> https://stackoverflow.com/questions/49065803/python-delete-objects-and-free-up-space
>  )
>

The key fragment in g.app.closeWindow is:

if frame in g.app.windowList:
    g.app.destroyWindow(frame)
    g.app.windowList.remove(frame)
else:
    # #69.
    g.app.forgetOpenFile(fn=c.fileName(), force=True)

g.app.destroyWindow is:

def destroyWindow(self, frame):
    """Destroy all ivars in a Leo frame."""
    if 'shutdown' in g.app.debug:
        g.pr(f"destroyWindow:  {frame.c.shortFileName()}")
    if g.app.externalFilesController:
        g.app.externalFilesController.destroy_frame(frame)
    if frame in g.app.windowList:
        # g.pr('destroyWindow', (g.app.windowList)
        g.app.forgetOpenFile(frame.c.fileName())
    # force the window to go away now.
    # Important: this also destroys all the objects of the commander.
    frame.destroySelf()

*However*, the bridge uses a nullFrame, and nullFrame.destroySelf is a 
do-nothing.

So I conclude that the commander is *not* destroyed immediately. Otoh, the 
(null) frame *is* removed from g.app.windowList, so there is one less 
reference to the commander. It's possible that the gc could remove the 
commander later.

*Summary*

I think you understand the situation quite well.

c.close does the following:

- Prompts for save if the commander has changed.
- Clears c.frame from g.app.windowList.
- (Supposedly) completely destroys c.frame and c. But this doesn't happen 
when using a nullFrame.

My advice is not to worry about whether c has been garbage collected. You 
can safely access c if and *only *if c.frame exists in g.app.windowList. 
However, there is no guarantee that this advice is correct.

HTH. 

Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/leo-editor/4286a47d-9ce3-49e2-95df-20b194fb142bo%40googlegroups.com.

Reply via email to