Reading OpenVPN Status Data with Python (1 of 3)

I’m doing a 3 part series on using wxPython and PyWin32 to capture output from a running OpenVPN session.

I use OpenVPN to connect to PCs at work. I noticed that our current method of launching OpenVPN was in a console window so that one could monitor the program’s output. If the user happened to close said window, it would end the VPN session. I thought this was dumb, so I decided that I would try wrapping the interface using wxPython in such a way that I can minimize it to the system tray and bring it back up on demand to check the output if I was having an issue. If you want to follow along, then you’ll need the following:

Got all those? Ok. Let’s continue. To begin, create a folder to hold your scripts. We’ll actually need a couple to do this right.

First, we’re going to create a system tray icon.

Step 1: Pick an icon (I used one from the Tamarin set)

Step 2: Once you have the icon, we’ll use a wxPython utility called img2py that will convert the icon or picture into a python file. It can be found in your Python folder after you’ve installed wxPython: \\path\to\Python25\Lib\site-packages\wx-2.8-msw-unicode\wx\tools (adjust as necessary for your system)

Step 3: Move the icon file to the directory in step 2 and open a command window by clicking Start, Run, and type cmd. Navigate to the directory above (using the cd command) and run the following: python img2py.py -i myIcon.ico icon.py

Step 4: Once that’s done, copy the icon.py file to the the folder you created to hold your scripts. This will be coupled with some code that handles the iconization and right-click menus.

Now we’ll create the logic needed for the system tray icon to respond to mouse events. I found some code in the wxPython Demo that did most of what I did. So I copied it and modified it slightly to fit my needs. You can see the end result below:

import wx
from vpnIcon import getIcon

class VPNIconCtrl(wx.TaskBarIcon):
    TBMENU_RESTORE = wx.NewId()
    TBMENU_CLOSE   = wx.NewId()
    TBMENU_CHANGE  = wx.NewId()
        
    def __init__(self, frame):
        wx.TaskBarIcon.__init__(self)
        self.frame = frame        

        # Set the image
        tbIcon = getIcon()

        # Give the icon a tooltip
        self.SetIcon(tbIcon, "VPN Status")
        self.imgidx = 1
        
        # bind some events
        self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarActivate)
        self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=self.TBMENU_RESTORE)
        self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE)        

    def CreatePopupMenu(self):
        """
        This method is called by the base class when it needs to popup
        the menu for the default EVT_RIGHT_DOWN event.  Just create
        the menu how you want it and return it from this function,
        the base class takes care of the rest.
        """
        menu = wx.Menu()
        menu.Append(self.TBMENU_RESTORE, "View Status")
        menu.AppendSeparator()
        menu.Append(self.TBMENU_CLOSE, "Close Program")
        
        return menu

    def OnTaskBarActivate(self, evt):
        if self.frame.IsIconized():
            self.frame.Iconize(False)
        if not self.frame.IsShown():
            self.frame.Show(True)
        self.frame.Raise()

    def OnTaskBarClose(self, evt):
        self.Destroy()
        self.frame.Close()

Next time, we’ll go over the win32 code you’ll need to know and in the final piece, we’ll create the GUI and put the rest of the pieces together.