Search code examples
sublimetext3sublime-text-plugin

SublimeText3 Plugin - Listen on Application or Window close events


In developing plugins for SublimeText we have the ability to listen on events by extending the EventListener or ViewEventListener classes.

Working with the API, is it possible to perform an action right before the application closes or before a window is closed?

I tried looking at all fired window commands by using on_window_command(window, command_name, args), but there seem to be no interceptable window commands involved when the application is closed.

I also tried listening on on_pre_close(view). This gets fired when the application closes once for each tab, but I could not determine from that method if only one view is closed or also the whole window.

Am I missing something obvious or is it not possible to listen to the closing of the application or an application window?


Solution

  • Based on your desire to take an action right before a window closes or Sublime exits, the short answer to your question is that it's not possible to do either in a reliable way. It is however possible to know about either of those things at some point after it happens, though for the case of Sublime quitting this is generally less interesting because by the time you're in a position to know, it's too late for you to do anything in response.

    The on_close and on_pre_close events are view events; that is they trigger when a tab is being closed (or about to be closed). Tabs can be closed for a variety of reasons, so it's not feasible to use that event solely to detect when the window is closing.

    In particular, when the hot_exit setting is turned on (which it is by default), quitting Sublime or closing a window that has an associated sublime-project or sublime-workspace file will cause the state of all windows (or the project/workspace window, depending on your action) to be persisted into the session or workspace file without closing any views. So in that sense you would only ever get these events when someone was actually closing a file.

    One method for determining that Sublime is about to close (or that a window is about to close) is using on_window_command as you noted in your question, but this is not reliable.

    The exit command is triggered when you tell Sublime to terminate, so you can intercept that with on_window_command to know when it's happening, but only in some cases.

    For example, the following plugin listens for the exit command and rewrites it to block Sublime from terminating:

    import sublime
    import sublime_plugin
    
    
    class TestListener(sublime_plugin.EventListener):
        def on_window_command(self, window, command, args):
            if command == "exit":
                print("I think not!")
                return ("noop")
    

    If you bind a key to the exit command, that key will quit Sublime and be intercepted by the plugin, but choosing File > Exit or File > Quit terminates Sublime without triggering the plugin. It also doesn't trigger anything when you close the last window on Linux or Windows (which implicitly quits Sublime; on MacOS Sublime keeps running even with no windows present). So on the whole, this is not a reliable method.

    Similarly you can also listen for the close_window command to detect when a window is closing. However in that case the command only triggers when you use the key binding or the menu entry, but not when you use the button in the window caption to close the window (since that's effectively not triggering a command in Sublime).

    So in both cases it's technically possible to catch either event just before it happens, but only in certain specific circumstances, which is less than ideal for anything you need to rely on.

    That said, it's possible to detect either of these items after they've occurred, although the potential utility of that may not be what you want, particularly since you're interested in knowing beforehand in this case.

    It's possible to watch for the plugin_host to terminate from outside of Sublime, which would let you know when Sublime has terminated. On Linux and MacOS you could write a plugin that forks the plugin_host and then watches to see when the parent goes away. On Windows you would need to spawn an external process of some sort instead as Python on windows doesn't support fork() as far as I'm aware.

    It's also technically possible to detect when a window has closed (after the fact) by polling the list of windows from sublime.windows() on an ongoing basis to see if the size of the list changes or the window.id() of one of the windows has changed (which would indicate a window closing and a new one being added).

    This would let you know that the window went away after it was closed, but the polling interval you use would determine how long after you find out about it; there may also be performance concerns for frequent polling intervals as well.