source: trunk/src/testing/dim/eventManager.py @ 4

Revision 4, 7.0 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1############################################################################
2#
3# DIM - A Direct Interaction Manager for SAGE
4# Copyright (C) 2007 Electronic Visualization Laboratory,
5# University of Illinois at Chicago
6#
7# All rights reserved.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions are met:
11#
12#  * Redistributions of source code must retain the above copyright
13#    notice, this list of conditions and the following disclaimer.
14#  * Redistributions in binary form must reproduce the above
15#    copyright notice, this list of conditions and the following disclaimer
16#    in the documentation and/or other materials provided with the distribution.
17#  * Neither the name of the University of Illinois at Chicago nor
18#    the names of its contributors may be used to endorse or promote
19#    products derived from this software without specific prior written permission.
20#
21# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32#
33# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
34#
35# Author: Ratko Jagodic
36#       
37############################################################################
38
39
40
41from threading import RLock
42from globals import *
43import traceback as tb
44import sys
45from events import *
46
47
48
49class EventManager:
50    """ receives all the events and then forwards them to
51        all the event handlers that want them
52    """
53
54    def __init__(self):
55        self.evtLock = RLock()
56        self.__evtHandlers = {}   # keyed by eventId, value=list of callbacks
57
58        # add other handlers
59        #self.__addHandlers()
60
61
62    def addHandlers(self):
63        """ you can add evtHandlers here manually """
64
65
66    def __onDisplayInfo(self, evt):
67        di = evt.displayInfo
68        for display in di.getAllDisplays():
69            self.__importHandlerPlugin("wall").makeNew(display.getId())  # one for each display
70
71
72    def __importHandlerPlugin(self, name):
73        plugin = __import__("overlays."+name, globals(), locals(), [name])
74        return plugin
75       
76
77    def register(self, eventId, callback):
78        """ register the evtHandler to receive events of eventId """
79        if eventId not in self.__evtHandlers:
80            self.__evtHandlers[eventId] = []
81        self.__evtHandlers[eventId].append( callback )
82
83
84    def unregister(self, callbackHash):
85        """ unregisters the evtHandler from the specified events """
86        for eventId, callback in callbackHash.iteritems():
87            try:
88                self.__evtHandlers[eventId].remove(callback)
89            except:
90                continue
91           
92
93    def postEvent(self, event):
94        """ thread safe """
95        self.evtLock.acquire()
96       
97        # handle differently depending on whether
98        # it's a device event or a generic event
99        if event.eventId in self.__evtHandlers:
100            if event.eventType == DEVICE_EVENT:
101                self.__sendToSingleEvtHandler(event)
102            else:
103                if event.eventType == EVT_DISPLAY_INFO:
104                    self.__onDisplayInfo(event)   # create objects that are display dependent
105                   
106                self.__sendToMultipleEvtHandler(event)
107           
108        self.evtLock.release()
109
110
111    def getCallbackAtPos(self, event):
112        """ returns the callback function for the specified event at pos x,y
113            Or None if no suitable evtHandler was found at that position
114            Considers z ordering
115        """
116        currentCandidate = None  # the candidate based on the z value
117        lastZ = BOTTOM_Z
118        x, y, eventId, displayId = event.x, event.y, event.eventId, event.device.displayId
119       
120       
121        if eventId in self.__evtHandlers:
122            for callback in self.__evtHandlers[eventId]:
123                evtHandler = callback.im_self
124                if evtHandler.displayId == displayId and \
125                       evtHandler.z < lastZ and \
126                       evtHandler.bounds.isIn(x,y):
127                    currentCandidate = callback
128                    lastZ = evtHandler.z
129
130        # check if the handler is already captured
131        if currentCandidate and currentCandidate.im_self.captured:
132            return None
133       
134        return currentCandidate
135               
136
137    def __sendToSingleEvtHandler(self, event):
138        """ forward the event to a handler that is at the position
139            of the event and wants the current event
140        """
141        eventId = event.eventId
142        device = event.device
143       
144        # if the event goes to a specific evtHandler, no need to search for one
145        if event.toEvtHandler:
146            callback = event.toEvtHandler.getCallback(eventId)
147        else:
148            callback = self.getCallbackAtPos(event)
149               
150            # this is here to generate EVT_ENTERED_WINDOW and EVT_LEFT_WINDOW
151            if eventId == EVT_MOVE or eventId == EVT_MOVE_SPECIAL:
152                if callback != device.lastMoveCallback:   # window changed
153                    if device.lastMoveCallback:
154                        evtId = EVT_LEFT_WINDOW
155                        if device.specialDevice: evtId = EVT_LEFT_WINDOW_SPECIAL
156                        self.__sendEvent(WindowLeftEvent(device),
157                                         device.lastMoveCallback.im_self.getCallback(evtId))
158                    if callback:
159                        evtId = EVT_ENTERED_WINDOW
160                        if device.specialDevice: evtId = EVT_ENTERED_WINDOW_SPECIAL
161                        self.__sendEvent(WindowEnteredEvent(device),
162                                         callback.im_self.getCallback(evtId))
163                    device.lastMoveCallback = callback
164                   
165        # send the original event
166        self.__sendEvent(event, callback)
167       
168
169    def __sendToMultipleEvtHandler(self, event):
170        """ forward to all the evtHandlers registered for this eventId """
171        for callback in self.__evtHandlers[event.eventId]:
172            self.__sendEvent(event, callback)
173
174
175    def __sendEvent(self, event, callback):
176        """ executes callback with event as a parameter """
177        if callback:
178            try:
179                callback(event)
180            except AttributeError:   # if the object doesn't exist anymore, remove its callback
181                tb.print_exc()
182                self.__evtHandlers[event.eventId].remove(callback)
Note: See TracBrowser for help on using the repository browser.