PySnarl を使ってみる

SnarlというGrowlWindows 版とでもいうようなソフトがあるのだが、PySnarlという、SnarlPython binding を見つけたので、以前書いたネットワークの接続状況をシステムトレイに表示するスクリプトに組み込んでみた。
10秒ごとにチェックし、ネットワークが切断されてたり、接続されたりしたタイミングで Snarl を使って Notiy する。なかなか良い。
ちなみに Python Win32 Extension, wxPython, dnspython が必要。

#!/usr/bin/env python

import wx
import dns.resolver
import sys
from PySnarl import SnarlMessage

ID_ICON_TIMER = wx.NewId()
INTERVAL = 10000                # in msec
DNS_TIMEOUT = 5                 # in sec

class MyTaskBarIcon(wx.TaskBarIcon):
    def __init__(self, frame):
        wx.TaskBarIcon.__init__(self)
        self.frame = frame

    def CreatePopupMenu(self):
        return self._create_menu()

    def OnClose(self, _):
        self.frame.Close(1)

    def _create_menu(self):
        menu = wx.Menu()
        id = wx.NewId()
        menu.Append(id, "Exit")
        wx.EVT_MENU(self, id, self.OnClose)
        return menu


class TaskBarApp(wx.Frame):
    def __init__(self, parent, id, title):
        style = wx.FRAME_NO_TASKBAR | wx.NO_FULL_REPAINT_ON_RESIZE
        wx.Frame.__init__(self, parent, -1, title, size = (1, 1),
                          style = style)

        self.Bind(wx.EVT_CLOSE, self.OnClose)

        self.timer = wx.Timer(self, ID_ICON_TIMER)
        self.Bind(wx.EVT_TIMER, self.CheckConnection, self.timer, ID_ICON_TIMER)
        self.timer.Start(INTERVAL)

        self.resolver = dns.resolver.get_default_resolver()
        self.resolver.lifetime = DNS_TIMEOUT

        self.tbicon = MyTaskBarIcon(self)

        self.is_connected = False
        self.snarl = None

        self.Show(True)
        self.CheckConnection(None)

    def CheckConnection(self, _):
        image = wx.EmptyImage(16, 16)
        text = 'Network '
        try:
            self.resolver.query("www.google.com")
            image.SetData('\x11\xff\x11' * 256)
            text += 'Connected'
            is_connected = True
        except dns.resolver.Timeout:
            image.SetData('\xff\x11\x11' * 256)
            text += 'Disconnected'
            is_connected = False
        
        bmp = image.ConvertToBitmap()
        bmp.SetMask(wx.Mask(bmp, wx.WHITE))

        icon = wx.EmptyIcon()
        icon.CopyFromBitmap(bmp)
        self.tbicon.SetIcon(icon, text)

        if is_connected != self.is_connected:
            if self.snarl is not None:
                self.snarl.hide()
            self.snarl = SnarlMessage(text)
            self.snarl.show()
        self.is_connected = is_connected

    def OnClose(self, _):
        self.tbicon.Destroy()
        self.Destroy()


class MyApp(wx.App):
    def OnInit(self):
        frame = TaskBarApp(None, -1, ' ')
        frame.Center(wx.BOTH)
        frame.Show(False)
        return True

def main(argv=None):
    if argv is None:
        argv = sys.argv
    app = MyApp(0)
    app.MainLoop()

if __name__ == '__main__':
    main()