#!/usr/bin/env python # Module : traypopup.py # Synopsis : Windows System tray icon. # Programmer : Takayuki Shimizukawa # Date : 25 November 2008 # Python ver : 2.4 tested. # win32 ver : import time import logging logger = logging.getLogger('trayicon') from contribs.SysTrayIcon import win32api, win32con, win32gui, win32gui_struct import win32event, timer import log # for logger setup. import utils class Screen(object): def __init__(self): pass def GetWorkingArea(self): return win32api.GetSystemMetrics(win32con.SM_CXFULLSCREEN),\ win32api.GetSystemMetrics(win32con.SM_CYFULLSCREEN) + \ win32api.GetSystemMetrics(win32con.SM_CYCAPTION) screen = Screen() class PopupTimer(object): def __init__(self, wait=3000, delay=500, interval=10): self.wait = wait self.delay = delay self.interval = interval self.estimate = 0 self.rate = 0 self.killed = False self.event = win32event.CreateEvent(None, 0, 0, None) self.timer = timer.set_timer(interval, self.increment) def increment(self, id, dt): if self.killed: timer.kill_timer(id) return self.estimate += self.interval est = self.estimate delay = self.delay * 1.0 wait = self.wait if est < delay: self.rate = est / delay * 100 elif delay <= est < delay + wait: self.rate = delay / delay * 100 elif delay + wait <= est < delay*2 + wait: self.rate = (delay*2 + wait - est) / delay * 100 else: self.kill() win32event.SetEvent(self.event) def __del__(self): self.kill() def kill(self): self.killed = True win32gui.PostQuitMessage(0) # Terminate the app. #win32???.DeleteEvent(self.event) def __bool__(self): return not self.killed class TrayPopup(object): def __init__(self, window_class_name=None,): self.on_quit = None message_map = {win32con.WM_DESTROY: self.destroy, win32con.WM_COMMAND: self.command,} self._message_map = message_map # window class window_class = win32gui.WNDCLASS() self.hinst = window_class.hInstance = win32gui.GetModuleHandle(None) window_class.lpszClassName = window_class_name or 'TrayPopupPy' window_class.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW window_class.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW) window_class.hbrBackground = win32con.COLOR_WINDOW window_class.lpfnWndProc = self.message_proc classAtom = win32gui.RegisterClass(window_class) # window #style = win32con.WS_POPUP | win32con.WS_BORDER style = win32con.WS_OVERLAPPED #styleEx = win32con.WS_EX_TOPMOST # for top-most styleEx = win32con.WS_EX_TOOLWINDOW # for hide from taskbar sizex = sizey = 192 desktopsize = screen.GetWorkingArea() posx = desktopsize[0] - sizex posy = desktopsize[1] - sizey hwnd = win32gui.CreateWindowEx(styleEx, classAtom, window_class.lpszClassName, style, posx, posy, sizex, sizey, 0, 0, self.hinst, None) win32gui.UpdateWindow(hwnd) # instance vars self.hwnd = hwnd self.window_class = window_class self.classAtom = classAtom self.size = (sizex, sizey) self.pos = (posx, posy) self.timer = None def get_pos(self, rate=100): desktopsize = screen.GetWorkingArea() x = desktopsize[0] - (self.size[0]) y = desktopsize[1] - (self.size[1] * rate / 100) return int(x),int(y) @property def is_show(self): return self.timer def show(self, timer=1000): if self.is_show: return self.timer = PopupTimer() def _ticktimer(self, self2, msg, wp, lp): if not self.is_show: return pos = self.get_pos(self.timer.rate) p2 = win32gui.GetWindowRect(self.hwnd) if pos != tuple(p2[:2]): win32gui.SetWindowPos(self.hwnd, 0, pos[0], pos[1], 0, 0, win32con.SWP_NOSIZE | win32con.SWP_NOZORDER | win32con.SWP_SHOWWINDOW) def message_proc(self, hwnd, msg, wparam, lparam): logger.debug('msg: %s', str(utils.WM_MAP.get(msg, msg))) if msg in self._message_map: return self._message_map[msg](self, msg, wparam, lparam) return win32gui.DefWindowProc(hwnd, msg, wparam, lparam) def destroy(self, hwnd, msg, wparam, lparam): if self.on_quit: self.on_quit(self) win32gui.PostQuitMessage(0) # Terminate the app. #win32gui.UnregisterClass(self.window_class.lpszClassName, self.hinst) def command(self, hwnd, msg, wparam, lparam): pass #id = win32gui.LOWORD(wparam) #self.execute_menu_option(id) if __name__ == '__main__': tp = TrayPopup() tp.show() t = tp.timer # Timers are message based - so we need # To run a message loop while waiting for our timers # to expire. while 1: # We can't simply give a timeout of 30 seconds, as # we may continouusly be recieving other input messages, # and therefore never expire. rc = win32event.MsgWaitForMultipleObjects( (t.event,), # list of objects 0, # wait all 500, # timeout win32event.QS_ALLEVENTS, # type of input ) if rc == win32event.WAIT_OBJECT_0: # Event signalled. tp._ticktimer(0,0,0,0) elif rc == win32event.WAIT_OBJECT_0+1: # Message waiting. if win32gui.PumpWaitingMessages(): # receive WM_QUIT message. break else: # no messages, no events. pass