Audio/AudioControl: Lots of fixes
[audiocontrol.git] / Events.py
1 """Event handling and generation.
2
3 The Event module manages event generation. Events are created by
4 EventSource instances. Each event source is associated with a file
5 handle. This handle will be poll()'ed and the eventsource will be
6 called, as sonn as input is available."""
7
8 import select, Logger, Node, Actions
9
10 class Event(object):
11
12     def __init__(self, context, code):
13         self.context = context
14         self.code = code
15
16     def __getitem__(self, index):
17         rerturn (self.context, self.code)[index]
18
19     def __cmp__(self, other):
20         return cmp(self.context, other.context) or cmp(self.code, other.code)
21
22     def __hash__(self):
23         return hash(self.context) ^ hash(self.code)
24
25     def __str__(self):
26         return repr((self.context, self.code))
27
28
29 class ControlEvent(Event):
30
31     def __init__(self, context, code, value):
32         Event.__init__(self, context, code)
33         self.value = value
34
35     def __str__(self):
36         return repr((self.context, self.code, self.value))
37
38
39 class EventSource(Node.Node):
40
41     def __init__(self, fd, context):
42         Node.Node.__init__(self)
43         self._fd = fd
44         self._context = context
45
46     def fd(self):
47         return self._fd
48
49     def context(self):
50         return self._context
51
52     def fileno(self):
53         return self._fd.fileno()
54
55     def readEvents(self):
56         raise NotImplementedError
57
58
59 class Dispatcher(Node.Node):
60
61     _sources = Node.NodeMap()
62
63     def __init__(self, keylist):
64         Node.Node.__init__(self)
65         self._sources = {}
66         self._callbacks = []
67         self._keylist = keylist
68         self._poller = select.poll()
69         self._event = None
70         self._interval = None
71         self._idleCallback = None
72
73     def registerSource(self, eventSource):
74         self._sources[eventSource.fileno()] = eventSource
75         self._poller.register(eventSource.fileno(),select.POLLIN)
76
77     def unregisterSource(self, eventSource):
78         del self._sources[eventSource.fileno()]
79         self._poller.unregister(eventSource.fileno())
80
81     def registerCallback(self,cb):
82         self._callbacks.append(cb)
83
84     def unregisterCallback(self,cb):
85         self._callbacks.remove(cb)
86
87     def currentEvent(self):
88         return self._event
89
90     def setIdleCallback(self, cb, interval):
91         self._interval = interval
92         self._idleCallback = cb
93
94     def unsetIdleCallback(self):
95         self._interval = None
96         self._idleCallback = None
97
98     def emit(self, event):
99         binding = self._keylist.lookup(event)
100         if binding is not None:
101             self._event = event
102             binding.execute()
103             self._event = None
104             
105     def run(self):
106         while 1:
107             for cb in self._callbacks : cb()
108             try:
109                 pollEvents = self._poller.poll(self._interval)
110             except select.error, v:
111                 if v[0]==4 : continue
112                 else       : raise
113             if not pollEvents and self._idleCallback:
114                 self._idleCallback()
115             for fd, pollEvent in pollEvents:
116                 if pollEvent != select.POLLIN : return
117                 for event in  self._sources[fd].readEvents():
118                     Logger.log('dispatcher', 'event: ' + str(event))
119                     self.emit(event)
120
121 class EmitEvent(Actions.Action):
122
123     def __init__(self, name, dispatcher, event):
124         Actions.Action.__init__(self, name)
125         self._dispatcher = dispatcher
126         self._event = event
127
128     def __call__(self, binding):
129         self._dispatcher.emit(self._event)