How to create a background inactivity timer in tkinter python program?

155 Views Asked by At

I'm trying to figure out how to start a python program, have the initial tkinter window hidden and to put an icon in the system tray on Windows. I want to be able to set an inactivity timer (using 10 seconds for testing) and when the time has been reached to display an image using the tkinter window in full screen. The behavior would mimic a screen saver. If the image window is triple clicked, it should disappear, the icon should be added back to the system tray and the inactivity timer would be checking in the background every second until it reaches the threshold again and the process repeats.

I've been able to accomplish the showing and hiding of the window and the system tray icon behavior, however I can't seem to get the inactivity timer behavior working. If I use the after method, it only does the inactivity timer when it is displayed. It doesn't work when I want it to (when the tkinter is withdrawn).

How can I get the timer to work when the tkinter is not active?

from tkinter import *
from ctypes import Structure, windll, c_uint, sizeof, byref
import time
import pystray
from PIL import Image, ImageTk

class LASTINPUTINFO(Structure):
    _fields_ = [
        ('cbSize', c_uint),
        ('dwTime', c_uint),
    ]

def get_idle_duration():
    lastInputInfo = LASTINPUTINFO()
    lastInputInfo.cbSize = sizeof(lastInputInfo)
    windll.user32.GetLastInputInfo(byref(lastInputInfo))
    millis = windll.kernel32.GetTickCount() - lastInputInfo.dwTime
    return millis / 1000.0

class FS_Display:
    def __init__(self):
        self.root = Tk()
        self.root.title("FS Display")
        #self.root.state = True
        #self.root.attributes("-fullscreen", False)
        #self.root.bind("<Double-1>", self.exit)#resume_fullscreen)
        self.root.bind("<Triple-1>", self.end_fullscreen)
        #self.root.bind("<F11>", self.resume_fullscreen)
        self.root.bind("<Escape>", self.end_fullscreen)#.end_fullscreen)
        self.root.protocol('WM_DELETE_WINDOW', self.end_fullscreen)
        self.end_fullscreen()

    def end_fullscreen(self, event=None):
        #self.root.attributes("-fullscreen", False)
        self.root.withdraw()
        self.image = Image.open("favicon.png")
        self.menu = (pystray.MenuItem('Quit', self.quit), pystray.MenuItem('Show', self.show_fullscreen))
        self.icon = pystray.Icon("name", self.image, "FS Display", self.menu)
        self.icon.run()

    def show_fullscreen(self, event=None):
        self.root.attributes("-fullscreen", True)
        self.icon.stop()
        self.root.deiconify()

    def quit(self, event=None):
        self.icon.stop()
        self.root.destroy()

    def idle_check(self, event=None):
        GetLastInputInfo = int(get_idle_duration())
        print(GetLastInputInfo)
        if GetLastInputInfo == 10:
            self.show_fullscreen()
        self.root.after(1000, self.idle_check)

if __name__ == '__main__':
    fs = FS_Display()
    main_image = Image.open("D:black_background.png")
    photo = ImageTk.PhotoImage(main_image)
    Label(fs.root, image=photo).pack()
    fs.root.after(1000, fs.idle_check)
    fs.root.mainloop()
0

There are 0 best solutions below