Home > Software engineering >  How to handle a WM_ENDSESSION in tkinter?
How to handle a WM_ENDSESSION in tkinter?

Time:08-28

I'm having trouble figuring out how to receive the WM_ENDSESSION window manager message in Tkinter, that is supposed to be sent to the top-level window during system shutdown. I am aware of everything that comes with trying to run extra code during shutdown, however in my case it'll only be a simple file flush down to disk and close, so that my program has a chance to save it's state.

My simple test code:

import tkinter as tk

def on_close(*args):
    print("User closed the window")

# I want this to run during shutdown
def on_shutdown(*args):
    print("User is shutting down their PC")

root = tk.Tk()
root.protocol("WM_DELETE_WINDOW", on_close)
root.mainloop()

A code example, or at least a pointer towards which functions or methods to use, would be appreciated.

CodePudding user response:

I would suggest using a message spying too like "Spy " (spyxx.exe) to check which messages are actually sent to your window.

In some places it is suggested that wireshark can also do this, but I have not found concrete evidence for that.

CodePudding user response:

Tk gives your program "a chance to save it's state" with the aptly named WM_SAVE_YOURSELF protocol. It is hooked up to WM_QUERYENDSESSION on Windows. The return value seems to be ignored so you cannot prevent WM_ENDSESSION from being dispatched, and therefore it shouldn't be used for long blocking work, so it really depends on how much you have to write if things will get weird or interrupted.

Hook up your callback with root.protocol("WM_SAVE_YOURSELF", on_close) and let me know if that works!

CodePudding user response:

As you, I found out (with respect for the issue) tk.Tk().protocol is pretty useless and your desired behavior is a wish since 1999. In the link is a patch you could try out.

I think the easiest way to go for you will be SetConsoleCtrlHandler:

This function provides a similar notification for console application and services that WM_QUERYENDSESSION provides for graphical applications with a message pump. You could also use this function from a graphical application, but there is no guarantee it would arrive before the notification from WM_QUERYENDSESSION.

You could find an exampel on StackOverflow or go with Pywin32. The disadvantage over the message approach is that you can't delay the shutdown further more. But the User would have this option anyway, after the timeout of 5 seconds is expired and you would have with SetConsoleHandler the same amount of time.

A word of caution, flushing a bigger amount of data is explicitly discouraged:

Avoid disk flushes, for example, those initiated through calling FlushFileBuffers API. Flushing causes the disk stack to delete its caches and is supposed to force the hard drive to write out data in its RAM buffers. Typically, this operation is very costly and does not guarantee data consistency since the hard drives often ignore the request.

...

It is recommended that applications save their data and state frequently; for example, automatically save data between save operations

In addition there is an example with tkinter and pywin32 that handles WM_ENDSESSION, if you intrested.

  • Related