# $Id: events.py.in,v 1.9 2003/10/06 02:08:01 mackstann Exp $

import types
import kahakai

kahakaiInst = kahakai.Kahakai.Instance()
screen = kahakaiInst.script_current_screen

if isinstance(kahakaiInst, str):
    print "Error!  What should be a kahakai instance is in fact a string,"
    print "which is weird. You most likely have an error in your userconfig."

_modifiers = dict([(comp.first, comp.second)
                   for comp in kahakai.getXModifiers(screen.display)])

# Define some alias, will use this so the keynames are case insensitive
# (which is not the case for X keyname, like Return != return)

alias = {
# you can add some aliases here
# do not remove the following line !!!
# GENERATED ALIAS TABLE GOES HERE
# GENERATED ALIAS TABLE GOES HERE
}

for mod in ['MoveResizeMask']:
    _modifiers[mod] = getattr(kahakai, mod)

def warn(s):
    print "*** Warning: %s" % s

class Modifiers(object):
    def __init__(self, mods=0, nmods=0):
        self.mod  = mods
        self.nmod = nmods

    def fromString(s):
        if s in _modifiers:
            return Modifiers(_modifiers[s])
        else:
            warn("Unknown modifier %s" % s)
            return Modifiers()

    def normalize(obj):
        if isinstance(obj, Modifiers):
            return obj
        elif isinstance(obj, str):
            return Modifiers.fromString(obj)
        elif isinstance(obj, int):
            return Modifiers(mods=obj)
        elif isinstance(obj, types.NoneType):
            return Modifiers()
        else:
            warn("Wrong type for a modifier: %s with type %s."%(obj, type(obj)))
            return Modifiers()
        
    def __add__(self, other):
        if isinstance(other, str):
            if other in _modifiers:                
                return self + Modifiers(_modifiers[other])
            else:
                warn("Unknown modifier %s" % other)
        elif isinstance(other, Modifiers):
            return Modifiers(self.mod  | other.mod,
                             self.nmod | other.nmod)
        elif isinstance(other, int):
            return Modifiers(self.mod | other,
                             self.nmod)
        else:
            raise ValueError, "Can't add Modifiers and %s objects" % type(other)

    def __sub__(self, other):
        return self + (-Modifiers.normalize(other))

    def __repr__(self):
        return '<Modifiers: mods = %s, nmods = %s>' % (self.mod, self.nmod)

    def __neg__(self):
        return Modifiers(self.nmod, self.mod)

    fromString = staticmethod(fromString)
    normalize  = staticmethod(normalize)

# Define some common modifiers
Ctrl   = Modifiers.fromString('Control_L')
Alt    = Modifiers.fromString('Alt_L')
Shift  = Modifiers.fromString('Shift_L')
Super  = Modifiers.fromString('Super_L')

MoveResizeMask  = Modifiers.fromString('MoveResizeMask')

if 'Mode_switch' in _modifiers:
    AltGr  = Modifiers.fromString('Mode_switch')
else:
    AltGr  = Modifiers()	

C, A, S, W = Ctrl, Alt, Shift, Super

class ActionEvent(object):
    delayBreaks = []

    def __init__(self, delay=0.0):
        self.delay = delay

    def set(self, action):
        # Decompose delay into second and micro second
        action.delay.tv_sec  = int(self.delay)
        action.delay.tv_usec = (self.delay - int(self.delay)) * 1e6

        action.delay_breaks = kahakai.Vector_int()
        for delayBreak in self.delayBreaks:
            action.delay_breaks.append(delayBreak)

class _Default: pass

class KeyEvent(ActionEvent):

    def __init__(self, a, b=_Default, replay=False, delay=0):
        ActionEvent.__init__(self, delay)
        # we can be called with either ("keyname"), or (modifiers, "keyname"),
        # so at this point we don't know which is which, thus the generic
        # names `a' and `b'

        # and here we determine which is which
        if b is _Default:
            # We are just called with a keyname
            modifiers, keyName = Modifiers(), a
        else:
            # We are called with modifier, keyname
            modifiers, keyName = a, b

        modifiers = Modifiers.normalize(modifiers)

        if not keyName:
            self.keySym = 0
        else:
            self.keySym = self._parseKey(keyName)
            
        self.nmod, self.mod = modifiers.nmod, modifiers.mod
        self.replay = replay

    def _parseKey(self, keyName):
        if isinstance(keyName, (int, long)): # Keycode
            return keyName

        if len(keyName) == 1:
            keyName = keyName.lower()

        keyName = alias.get(keyName.lower(), keyName)
 
        keySym = kahakai.XStringToKeysym(keyName)
		
        if keySym == kahakai.NoSymbol and len(keyName) > 1:
            keySym = kahakai.XStringToKeysym(keyName.capitalize())

            if keySym == kahakai.NoSymbol:
                print "** Warning: %s not a valid key name" % keyName
                return None

        return keySym

        
    def set(self, action):
        if not self.keySym: return False

        ActionEvent.set(self, action)
        
        action.type   = self.type
        action.replay = self.replay
        action.detail = self.keySym
        action.nmod, action.mod = self.nmod, self.mod

        return True

    def bindToCommand(self, screen, command):
        action = kahakai.Action()
        _objects.append(action)
        if not self.set(action): return        
        action.command = command

        for actionList in screen.config.awinacts, screen.config.rootacts:
            actionList.append(action)

class KeyPress(KeyEvent):
    type = kahakai.KeyPress

class KeyRelease(KeyEvent):
    type = kahakai.KeyRelease

class SimpleActionEvent(ActionEvent):
    def __init__(self, modifiers=Modifiers(), delay=0):
        ActionEvent.__init__(self, delay)
            
        modifiers = Modifiers.normalize(modifiers)
        
        self.nmod, self.mod = modifiers.nmod, modifiers.mod

    def set(self, action):
        ActionEvent.set(self, action)
        
        action.type   = self.type
        action.detail = 0
        action.nmod, action.mod = self.nmod, self.mod
        
        return True

class EnterNotify(SimpleActionEvent):
    type = kahakai.EnterNotify
    delayBreaks = kahakai.LeaveNotify,

class LeaveNotify(SimpleActionEvent):
    type = kahakai.LeaveNotify
    delayBreaks = kahakai.EnterNotify,

class MapRequest(SimpleActionEvent):
    type = kahakai.MapRequest

class MouseEvent(ActionEvent):
    def __init__(self, a, b=None, replay=False, delay=0):
        # see KeyEvent for notes about arguments a and b
        ActionEvent.__init__(self, delay);

        if b is None: 
            # We are just called with a buttonName
            modifiers, buttonName = Modifiers(), a
        else:
            # We are called modifier, buttonName
            modifiers, buttonName = a, b

        modifiers = Modifiers.normalize(modifiers)
        
        self.detail = self._parseButton(buttonName)
        self.nmod, self.mod = modifiers.nmod, modifiers.mod
        self.replay = replay

    def set(self, action):
        if not self.detail: return False

        ActionEvent.set(self, action)
        
        action.type   = self.type
        action.detail = self.detail
        action.replay = self.replay
        action.nmod, action.mod = self.nmod, self.mod

        return True
    
    def _parseButton(self, buttonName):
        buttons = {
            'anybutton': 0,
            'button1': kahakai.Button1,
            'button2': kahakai.Button2,
            'button3': kahakai.Button3,
            'button4': kahakai.Button4,
            'button5': kahakai.Button5,
            }

        if buttonName.lower() in buttons:
            return buttons[buttonName.lower()]
        elif buttonName.startswith('button'):
            return int(buttonName[len('button'):])
        else:
            warn("Unknown button: %s" % buttonName)

class ButtonPress(MouseEvent):
    type = kahakai.ButtonPress

class DoubleClick(MouseEvent):
    type = kahakai.DoubleClick

class ButtonRelease(MouseEvent):
    type = kahakai.ButtonRelease
