1 /* libs/graphics/views/SkEventSink.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include "SkEventSink.h"
19 #include "SkTagList.h"
20 #include "SkThread.h"
21
22 #include "SkGlobals.h"
23 #include "SkThread.h"
24 #include "SkTime.h"
25
26 #define SK_EventSink_GlobalsTag SkSetFourByteTag('e', 'v', 's', 'k')
27
28 class SkEventSink_Globals : public SkGlobals::Rec {
29 public:
30 SkMutex fSinkMutex;
31 SkEventSinkID fNextSinkID;
32 SkEventSink* fSinkHead;
33 };
34
create_globals()35 static SkGlobals::Rec* create_globals()
36 {
37 SkEventSink_Globals* rec = new SkEventSink_Globals;
38 rec->fNextSinkID = 0;
39 rec->fSinkHead = NULL;
40 return rec;
41 }
42
SkEventSink()43 SkEventSink::SkEventSink() : fTagHead(NULL)
44 {
45 SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
46
47 globals.fSinkMutex.acquire();
48
49 fID = ++globals.fNextSinkID;
50 fNextSink = globals.fSinkHead;
51 globals.fSinkHead = this;
52
53 globals.fSinkMutex.release();
54 }
55
~SkEventSink()56 SkEventSink::~SkEventSink()
57 {
58 SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
59
60 if (fTagHead)
61 SkTagList::DeleteAll(fTagHead);
62
63 globals.fSinkMutex.acquire();
64
65 SkEventSink* sink = globals.fSinkHead;
66 SkEventSink* prev = NULL;
67
68 for (;;)
69 {
70 SkEventSink* next = sink->fNextSink;
71 if (sink == this)
72 {
73 if (prev)
74 prev->fNextSink = next;
75 else
76 globals.fSinkHead = next;
77 break;
78 }
79 prev = sink;
80 sink = next;
81 }
82 globals.fSinkMutex.release();
83 }
84
doEvent(const SkEvent & evt)85 bool SkEventSink::doEvent(const SkEvent& evt)
86 {
87 return this->onEvent(evt);
88 }
89
doQuery(SkEvent * evt)90 bool SkEventSink::doQuery(SkEvent* evt)
91 {
92 SkASSERT(evt);
93 return this->onQuery(evt);
94 }
95
onEvent(const SkEvent &)96 bool SkEventSink::onEvent(const SkEvent&)
97 {
98 return false;
99 }
100
onQuery(SkEvent *)101 bool SkEventSink::onQuery(SkEvent*)
102 {
103 return false;
104 }
105
106 ///////////////////////////////////////////////////////////////////////////////
107
findTagList(U8CPU tag) const108 SkTagList* SkEventSink::findTagList(U8CPU tag) const
109 {
110 return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL;
111 }
112
addTagList(SkTagList * rec)113 void SkEventSink::addTagList(SkTagList* rec)
114 {
115 SkASSERT(rec);
116 SkASSERT(fTagHead == NULL || SkTagList::Find(fTagHead, rec->fTag) == NULL);
117
118 rec->fNext = fTagHead;
119 fTagHead = rec;
120 }
121
removeTagList(U8CPU tag)122 void SkEventSink::removeTagList(U8CPU tag)
123 {
124 if (fTagHead)
125 SkTagList::DeleteTag(&fTagHead, tag);
126 }
127
128 ///////////////////////////////////////////////////////////////////////////////
129
130 struct SkListenersTagList : SkTagList {
SkListenersTagListSkListenersTagList131 SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
132 {
133 fExtra16 = SkToU16(count);
134 fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
135 }
~SkListenersTagListSkListenersTagList136 virtual ~SkListenersTagList()
137 {
138 sk_free(fIDs);
139 }
140
countListnersSkListenersTagList141 int countListners() const { return fExtra16; }
142
findSkListenersTagList143 int find(SkEventSinkID id) const
144 {
145 const SkEventSinkID* idptr = fIDs;
146 for (int i = fExtra16 - 1; i >= 0; --i)
147 if (idptr[i] == id)
148 return i;
149 return -1;
150 }
151
152 SkEventSinkID* fIDs;
153 };
154
addListenerID(SkEventSinkID id)155 void SkEventSink::addListenerID(SkEventSinkID id)
156 {
157 if (id == 0)
158 return;
159
160 SkListenersTagList* prev = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
161 int count = 0;
162
163 if (prev)
164 {
165 if (prev->find(id) >= 0)
166 return;
167 count = prev->countListners();
168 }
169
170 SkListenersTagList* next = SkNEW_ARGS(SkListenersTagList, (count + 1));
171
172 if (prev)
173 {
174 memcpy(next->fIDs, prev->fIDs, count * sizeof(SkEventSinkID));
175 this->removeTagList(kListeners_SkTagList);
176 }
177 next->fIDs[count] = id;
178 this->addTagList(next);
179 }
180
copyListeners(const SkEventSink & sink)181 void SkEventSink::copyListeners(const SkEventSink& sink)
182 {
183 SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList);
184 if (sinkList == NULL)
185 return;
186 SkASSERT(sinkList->countListners() > 0);
187 const SkEventSinkID* iter = sinkList->fIDs;
188 const SkEventSinkID* stop = iter + sinkList->countListners();
189 while (iter < stop)
190 addListenerID(*iter++);
191 }
192
removeListenerID(SkEventSinkID id)193 void SkEventSink::removeListenerID(SkEventSinkID id)
194 {
195 if (id == 0)
196 return;
197
198 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
199
200 if (list == NULL)
201 return;
202
203 int index = list->find(id);
204 if (index >= 0)
205 {
206 int count = list->countListners();
207 SkASSERT(count > 0);
208 if (count == 1)
209 this->removeTagList(kListeners_SkTagList);
210 else
211 {
212 // overwrite without resize/reallocating our struct (for speed)
213 list->fIDs[index] = list->fIDs[count - 1];
214 list->fExtra16 = SkToU16(count - 1);
215 }
216 }
217 }
218
hasListeners() const219 bool SkEventSink::hasListeners() const
220 {
221 return this->findTagList(kListeners_SkTagList) != NULL;
222 }
223
postToListeners(const SkEvent & evt,SkMSec delay)224 void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay)
225 {
226 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
227 if (list)
228 {
229 SkASSERT(list->countListners() > 0);
230 const SkEventSinkID* iter = list->fIDs;
231 const SkEventSinkID* stop = iter + list->countListners();
232 while (iter < stop)
233 (SkNEW_ARGS(SkEvent, (evt)))->post(*iter++, delay);
234 }
235 }
236
237 ///////////////////////////////////////////////////////////////////////////////
238
DoEvent(const SkEvent & evt,SkEventSinkID sinkID)239 SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt, SkEventSinkID sinkID)
240 {
241 SkEventSink* sink = SkEventSink::FindSink(sinkID);
242
243 if (sink)
244 {
245 #ifdef SK_DEBUG
246 if (evt.isDebugTrace())
247 {
248 SkString etype;
249 evt.getType(&etype);
250 SkDebugf("SkEventTrace: dispatching event <%s> to 0x%x", etype.c_str(), sinkID);
251 const char* idStr = evt.findString("id");
252 if (idStr)
253 SkDebugf(" (%s)", idStr);
254 SkDebugf("\n");
255 }
256 #endif
257 return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
258 }
259 else
260 {
261 #ifdef SK_DEBUG
262 if (sinkID)
263 SkDebugf("DoEvent: Can't find sink for ID(%x)\n", sinkID);
264 else
265 SkDebugf("Event sent to 0 sinkID\n");
266
267 if (evt.isDebugTrace())
268 {
269 SkString etype;
270 evt.getType(&etype);
271 SkDebugf("SkEventTrace: eventsink not found <%s> for 0x%x\n", etype.c_str(), sinkID);
272 }
273 #endif
274 return kSinkNotFound_EventResult;
275 }
276 }
277
FindSink(SkEventSinkID sinkID)278 SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
279 {
280 if (sinkID == 0)
281 return 0;
282
283 SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
284 SkAutoMutexAcquire ac(globals.fSinkMutex);
285 SkEventSink* sink = globals.fSinkHead;
286
287 while (sink)
288 {
289 if (sink->getSinkID() == sinkID)
290 return sink;
291 sink = sink->fNextSink;
292 }
293 return NULL;
294 }
295
296 ////////////////////////////////////////////////////////////////////////////////////////
297 ////////////////////////////////////////////////////////////////////////////////////////
298
299 #if 0 // experimental, not tested
300
301 #include "SkThread.h"
302 #include "SkTDict.h"
303
304 #define kMinStringBufferSize 128
305 static SkMutex gNamedSinkMutex;
306 static SkTDict<SkEventSinkID> gNamedSinkIDs(kMinStringBufferSize);
307
308 /** Register a name/id pair with the system. If the name already exists,
309 replace its ID with the new id. This pair will persist until UnregisterNamedSink()
310 is called.
311 */
312 void SkEventSink::RegisterNamedSinkID(const char name[], SkEventSinkID id)
313 {
314 if (id && name && *name)
315 {
316 SkAutoMutexAcquire ac(gNamedSinkMutex);
317 gNamedSinkIDs.set(name, id);
318 }
319 }
320
321 /** Return the id that matches the specified name (from a previous call to
322 RegisterNamedSinkID(). If no match is found, return 0
323 */
324 SkEventSinkID SkEventSink::FindNamedSinkID(const char name[])
325 {
326 SkEventSinkID id = 0;
327
328 if (name && *name)
329 {
330 SkAutoMutexAcquire ac(gNamedSinkMutex);
331 (void)gNamedSinkIDs.find(name, &id);
332 }
333 return id;
334 }
335
336 /** Remove all name/id pairs from the system. This is call internally
337 on shutdown, to ensure no memory leaks. It should not be called
338 before shutdown.
339 */
340 void SkEventSink::RemoveAllNamedSinkIDs()
341 {
342 SkAutoMutexAcquire ac(gNamedSinkMutex);
343 (void)gNamedSinkIDs.reset();
344 }
345 #endif
346