#!/usr/bin/env python

import fluxspace
import os.path
import os
import re
import sys

reApplet = re.compile('^[ \t]*([0-9]+)[ \t]+([a-z]+)[ \t]+([^ \t].*)[ \t]*$')
reCommandArg = re.compile('[ \t]*([^ \t"]+)|"([^"]*)"')

supportedActions = ['manage', 'run']

helper = fluxspace.FluxletHelper('runner')

def GetArgs(command):
    args = []
    s = command
    m = reCommandArg.search(s)
    while m is not None:
        arg = m.group(1)
        pos = m.end(1)
        if arg is None:
            arg = m.group(2)
            pos = m.end(2)
        args.append(os.path.expanduser(arg))
        m = reCommandArg.search(s, pos+1)
    return args

class Applet:
    def __init__(self, helper, action, command):
        self.helper  = helper
        self.action  = action
        args = GetArgs(command)
        self.command = args[0]
        self.args    = args
        self.pid     = 0
    def Start(self):
        self.helper.Trace('Start %s %s' % (self.command, self.args))
        self.helper.Trace('pid=%d' % self.pid)
        if self.pid == 0 or self.action == 'run':
            self.pid = os.fork()
            if self.pid == 0:
                try:
                    os.execvp(self.command, self.args)
                except:
                    self.helper.Message(2, 'Unable to start "%s"' % self.command)
                    sys.exit(1)
    def Stop(self):
        if self.pid != 0 and self.action == 'manage':
            self.helper.Trace('Stop %d (%s %s)' % (self.pid, self.command, self.args))
            os.system('kill %d' % (self.pid))
            self.pid = 0
    def Restart(self):
        self.Stop()
        self.Start()

class AppletManager:
    def __init__(self, helper):
        self.helper = helper
        self.workspaceApplets = {}
    def AddApplet(self, key, action, command):
        if not self.workspaceApplets.has_key(key):
            self.workspaceApplets[key] = []
        self.helper.Trace('Register workspace "%s" applet "%s"' % (key, command))
        self.workspaceApplets[key].append(Applet(self.helper, action, command))
    def ClearApplets(self, key):
        if self.workspaceApplets.has_key(key):
            self.workspaceApplets[key] = []
        self.helper.Trace('Clear workspace "%s" applets' % key)
    def StartApplets(self, key):
        self.helper.Trace('Start workspace "%s" applets' % key)
        if self.workspaceApplets.has_key(key):
            for applet in self.workspaceApplets[key]:
                applet.Start()
    def StopApplets(self, key):
        self.helper.Trace('Stop workspace "%s" applets' % key)
        if self.workspaceApplets.has_key(key):
            for applet in self.workspaceApplets[key]:
                applet.Stop()

class Handler:
    def __init__(self, appletManager):
        helper.Trace('Event handler created')
        self.appletManager = appletManager
    def Initialize(self):
        self.prevWorkspace = -1
        helper.Trace('Initialize')
    def WorkspaceIn(self, n):
        helper.Trace('WorkspaceIn %d' % n)
        if self.prevWorkspace >= 0:
            self.appletManager.StopApplets('%d' % self.prevWorkspace)
        else:
            self.appletManager.StartApplets('all')
        self.appletManager.StartApplets('%d' % n)
    def WorkspaceOut(self, n):
        helper.Trace('WorkspaceOut %d' % n)
        self.prevWorkspace = n
    def WindowMap(self, w):
        helper.Trace('WindowMap 0x%08x' % w)
    def WindowUnmap(self, w):
        helper.Trace('WindowUnmap 0x%08x' % w)

def fluxlet_main(config):
    appletManager = AppletManager(helper)
    programs = config.getElementsByTagName('program')
    if len(programs) == 0:
        return
    for program in programs:
        key = program.getAttribute('workspace')
        if not key:
            key = 'all'
        action = program.getAttribute('action')
        if not action:
            action = 'manage'
        command = program.getAttribute('command')
        if command:
            appletManager.AddApplet(key, action, command)
        else:
            helper.Message(1, 'Program with missing command skipped')
    helper.AddHandler(Handler(appletManager))


syntax highlighted by Code2HTML, v. 0.9.1