import wx import threading import SimpleXMLRPCServer import wx.lib.newevent import wx.lib.fancytext as fancytext NewMessageEvent, EVT_NEW_MESSAGE = wx.lib.newevent.NewEvent() class StaticFancyText(wx.StaticBitmap): def __init__(self, window, id, text, *args, **kargs): args = list(args) kargs.setdefault('name', 'staticFancyText') if 'background' in kargs: background = kargs.pop('background') elif args: background = args.pop(0) else: background = wx.Brush(window.GetBackgroundColour(), wx.SOLID) bmp = fancytext.RenderToBitmap(text, background, enclose = 1) wx.StaticBitmap.__init__(self, window, id, bmp, *args, **kargs) class MessageWindow(wx.Frame): def __init__(self, title, msg): wx.Frame.__init__(self, None, -1, size=(350, 50), style = wx.STAY_ON_TOP | wx.FRAME_TOOL_WINDOW | wx.FULL_REPAINT_ON_RESIZE) self.Bind(wx.EVT_MOTION, self.OnMotion) self.hiding = False #self.sizer = wx.BoxSizer(wx.VERTICAL) #print title, msg self.title = StaticFancyText(self, -1, str('%s' % title)) self.body = StaticFancyText(self, -1, str('%s' % msg)) #self.title = wx.StaticText(self, -1, str(title), (3, 3)) #self.body = wx.StaticText(self, -1, str(msg), (3, 15)) #b = 10 #self.sizer.Add(self.title, 1, wx.EXPAND | wx.ALL, b) #self.sizer.Add(self.body, 1, wx.EXPAND | wx.ALL, b) #self.SetSizer(self.sizer) #self.title.SetForegroundColour((255, 255, 255)) #self.body.SetForegroundColour((255, 255, 255)) #font = self.title.GetFont() #font.SetWeight(wx.FONTWEIGHT_BOLD) #self.title.SetFont(font) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.title, 0, wx.ALL|wx.ADJUST_MINSIZE, 2) sizer.Add(self.body, 0, wx.ALL|wx.ADJUST_MINSIZE, 2) self.SetAutoLayout(True) self.SetSizer(sizer) sizer.Fit(self) sizer.SetSizeHints(self) self.Layout() #self.SetAutoLayout(True) #self.sizer.SetSizeHints(self) def MakeTransparent(self, amount): return # never gunna work on linux hwnd = self.GetHandle() try: import ctypes _winlib = ctypes.windll.user32 style = _winlib.GetWindowLongA(hwnd, 0xffffffecL) style |= 0x00080000 _winlib.SetWindowLongA(hwnd, 0xffffffecL, style) _winlib.SetLayeredWindowAttributes(hwnd, 0, amount, 2) except ImportError: import win32api, win32con, winxpgui _winlib = win32api.LoadLibrary("user32") pSetLayeredWindowAttributes = win32api.GetProcAddress( _winlib, "SetLayeredWindowAttributes") if pSetLayeredWindowAttributes == None: return exstyle = win32api.GetWindowLong(hwnd, win32con.GWL_EXSTYLE) if 0 == (exstyle & 0x80000): win32api.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, exstyle | 0x80000) winxpgui.SetLayeredWindowAttributes(hwnd, 0, amount, 2) def OnMotion(self, event): self.hiding = True self.normalsize = self.GetSize() self.SetSize((2, self.normalsize.height)) self.timer = threading.Timer(1.0, self.UnHide) self.timer.start() event.Skip() def UnHide(self): self.SetSize(self.normalsize) self.hiding = False self.Refresh() class MyApp(wx.App): def OnInit(self): self.tbicon = wx.TaskBarIcon() icon = wx.Icon('python.ico', wx.BITMAP_TYPE_ICO) self.tbicon.SetIcon(icon, '') self.tbicon.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarLeftDClick) self.Bind(EVT_NEW_MESSAGE, self.OnNewMessage) self.windows = [] self.maxwindows = 10 self.maxalpha = 240 self.minalpha = 100 server = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 8008)) server.register_function(self.notify) self.rpcserver = server self.rpcthread = threading.Thread(target = server.serve_forever) self.rpcthread.start() return True def OnNewMessage(self, evt): win = self.NewMessage(evt.title, evt.msg) def notify(self, title, msg): #self.notifyicon.show_balloon(title, msg, 1, NIIF_NONE) evt = NewMessageEvent(msg=msg, title=title) wx.PostEvent(self, evt) return True def OnTaskBarLeftDClick(self, event): win = self.NewMessage('test', 'test') def NewMessage(self, title, msg): win = MessageWindow(title, msg) if len(self.windows) > self.maxwindows: oldwin = self.windows.pop() oldwin.Destroy() self.windows.insert(0, win) win.Show(True) self.UpdateWindows() thread = threading.Timer(60, self.PopMessage) thread.start() win.popthread = thread return win def PopMessage(self): oldwind = self.windows.pop() oldwind.Destroy() self.UpdateWindows() def UpdateWindows(self): alphad = (self.maxalpha - self.minalpha) / self.maxwindows top = 0 for idx, win in enumerate(self.windows): win.SetPosition((0, top)) win.MakeTransparent(self.maxalpha - (idx * alphad)) size = win.GetSize() top += size.height def main(): app = MyApp(0) app.MainLoop() if __name__ == '__main__': main()