blob: 9d3482af2a06a0ecb37430e245c28215779ff4a1 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkEventSink.h"
11#include "SkTagList.h"
12#include "SkThread.h"
13
14#include "SkGlobals.h"
15#include "SkThread.h"
16#include "SkTime.h"
17
18#define SK_EventSink_GlobalsTag SkSetFourByteTag('e', 'v', 's', 'k')
19
20class SkEventSink_Globals : public SkGlobals::Rec {
21public:
22 SkMutex fSinkMutex;
23 SkEventSinkID fNextSinkID;
24 SkEventSink* fSinkHead;
25};
26
27static SkGlobals::Rec* create_globals()
28{
29 SkEventSink_Globals* rec = new SkEventSink_Globals;
30 rec->fNextSinkID = 0;
31 rec->fSinkHead = NULL;
32 return rec;
33}
34
35SkEventSink::SkEventSink() : fTagHead(NULL)
36{
37 SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
38
39 globals.fSinkMutex.acquire();
40
41 fID = ++globals.fNextSinkID;
42 fNextSink = globals.fSinkHead;
43 globals.fSinkHead = this;
44
45 globals.fSinkMutex.release();
46}
47
48SkEventSink::~SkEventSink()
49{
50 SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
51
52 if (fTagHead)
53 SkTagList::DeleteAll(fTagHead);
54
55 globals.fSinkMutex.acquire();
56
57 SkEventSink* sink = globals.fSinkHead;
58 SkEventSink* prev = NULL;
59
60 for (;;)
61 {
62 SkEventSink* next = sink->fNextSink;
63 if (sink == this)
64 {
65 if (prev)
66 prev->fNextSink = next;
67 else
68 globals.fSinkHead = next;
69 break;
70 }
71 prev = sink;
72 sink = next;
73 }
74 globals.fSinkMutex.release();
75}
76
77bool SkEventSink::doEvent(const SkEvent& evt)
78{
79 return this->onEvent(evt);
80}
81
82bool SkEventSink::doQuery(SkEvent* evt)
83{
84 SkASSERT(evt);
85 return this->onQuery(evt);
86}
87
88bool SkEventSink::onEvent(const SkEvent&)
89{
90 return false;
91}
92
93bool SkEventSink::onQuery(SkEvent*)
94{
95 return false;
96}
97
98///////////////////////////////////////////////////////////////////////////////
99
100SkTagList* SkEventSink::findTagList(U8CPU tag) const
101{
102 return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL;
103}
104
105void SkEventSink::addTagList(SkTagList* rec)
106{
107 SkASSERT(rec);
108 SkASSERT(fTagHead == NULL || SkTagList::Find(fTagHead, rec->fTag) == NULL);
109
110 rec->fNext = fTagHead;
111 fTagHead = rec;
112}
113
114void SkEventSink::removeTagList(U8CPU tag)
115{
116 if (fTagHead)
117 SkTagList::DeleteTag(&fTagHead, tag);
118}
119
120///////////////////////////////////////////////////////////////////////////////
121
122struct SkListenersTagList : SkTagList {
123 SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
124 {
125 fExtra16 = SkToU16(count);
126 fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
127 }
128 virtual ~SkListenersTagList()
129 {
130 sk_free(fIDs);
131 }
132
133 int countListners() const { return fExtra16; }
134
135 int find(SkEventSinkID id) const
136 {
137 const SkEventSinkID* idptr = fIDs;
138 for (int i = fExtra16 - 1; i >= 0; --i)
139 if (idptr[i] == id)
140 return i;
141 return -1;
142 }
143
144 SkEventSinkID* fIDs;
145};
146
147void SkEventSink::addListenerID(SkEventSinkID id)
148{
149 if (id == 0)
150 return;
151
152 SkListenersTagList* prev = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
153 int count = 0;
154
155 if (prev)
156 {
157 if (prev->find(id) >= 0)
158 return;
159 count = prev->countListners();
160 }
161
162 SkListenersTagList* next = SkNEW_ARGS(SkListenersTagList, (count + 1));
163
164 if (prev)
165 {
166 memcpy(next->fIDs, prev->fIDs, count * sizeof(SkEventSinkID));
167 this->removeTagList(kListeners_SkTagList);
168 }
169 next->fIDs[count] = id;
170 this->addTagList(next);
171}
172
173void SkEventSink::copyListeners(const SkEventSink& sink)
174{
175 SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList);
176 if (sinkList == NULL)
177 return;
178 SkASSERT(sinkList->countListners() > 0);
179 const SkEventSinkID* iter = sinkList->fIDs;
180 const SkEventSinkID* stop = iter + sinkList->countListners();
181 while (iter < stop)
182 addListenerID(*iter++);
183}
184
185void SkEventSink::removeListenerID(SkEventSinkID id)
186{
187 if (id == 0)
188 return;
189
190 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
191
192 if (list == NULL)
193 return;
194
195 int index = list->find(id);
196 if (index >= 0)
197 {
198 int count = list->countListners();
199 SkASSERT(count > 0);
200 if (count == 1)
201 this->removeTagList(kListeners_SkTagList);
202 else
203 {
204 // overwrite without resize/reallocating our struct (for speed)
205 list->fIDs[index] = list->fIDs[count - 1];
206 list->fExtra16 = SkToU16(count - 1);
207 }
208 }
209}
210
211bool SkEventSink::hasListeners() const
212{
213 return this->findTagList(kListeners_SkTagList) != NULL;
214}
215
reed@google.com87fac4a2011-08-04 13:50:17 +0000216void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
reed@google.com87fac4a2011-08-04 13:50:17 +0000218 if (list) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 SkASSERT(list->countListners() > 0);
220 const SkEventSinkID* iter = list->fIDs;
221 const SkEventSinkID* stop = iter + list->countListners();
reed@google.com87fac4a2011-08-04 13:50:17 +0000222 while (iter < stop) {
223 SkEvent* copy = SkNEW_ARGS(SkEvent, (evt));
224 copy->setTargetID(*iter++)->postDelay(delay);
225 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 }
227}
228
229///////////////////////////////////////////////////////////////////////////////
230
reed@google.com87fac4a2011-08-04 13:50:17 +0000231SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt) {
232 SkEvent::Proc proc = evt.getTargetProc();
233 if (proc) {
234 return proc(evt) ? kHandled_EventResult : kNotHandled_EventResult;
235 }
236
237 SkEventSink* sink = SkEventSink::FindSink(evt.getTargetID());
238 if (sink) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
240 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241
reed@google.com87fac4a2011-08-04 13:50:17 +0000242 return kSinkNotFound_EventResult;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243}
244
245SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
246{
247 if (sinkID == 0)
248 return 0;
249
250 SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
251 SkAutoMutexAcquire ac(globals.fSinkMutex);
252 SkEventSink* sink = globals.fSinkHead;
253
254 while (sink)
255 {
256 if (sink->getSinkID() == sinkID)
257 return sink;
258 sink = sink->fNextSink;
259 }
260 return NULL;
261}
262
263////////////////////////////////////////////////////////////////////////////////////////
264////////////////////////////////////////////////////////////////////////////////////////
265
266#if 0 // experimental, not tested
267
268#include "SkThread.h"
269#include "SkTDict.h"
270
271#define kMinStringBufferSize 128
272static SkMutex gNamedSinkMutex;
273static SkTDict<SkEventSinkID> gNamedSinkIDs(kMinStringBufferSize);
274
275/** Register a name/id pair with the system. If the name already exists,
276 replace its ID with the new id. This pair will persist until UnregisterNamedSink()
277 is called.
278*/
279void SkEventSink::RegisterNamedSinkID(const char name[], SkEventSinkID id)
280{
281 if (id && name && *name)
282 {
283 SkAutoMutexAcquire ac(gNamedSinkMutex);
284 gNamedSinkIDs.set(name, id);
285 }
286}
287
288/** Return the id that matches the specified name (from a previous call to
289 RegisterNamedSinkID(). If no match is found, return 0
290*/
291SkEventSinkID SkEventSink::FindNamedSinkID(const char name[])
292{
293 SkEventSinkID id = 0;
294
295 if (name && *name)
296 {
297 SkAutoMutexAcquire ac(gNamedSinkMutex);
298 (void)gNamedSinkIDs.find(name, &id);
299 }
300 return id;
301}
302
303/** Remove all name/id pairs from the system. This is call internally
304 on shutdown, to ensure no memory leaks. It should not be called
305 before shutdown.
306*/
307void SkEventSink::RemoveAllNamedSinkIDs()
308{
309 SkAutoMutexAcquire ac(gNamedSinkMutex);
310 (void)gNamedSinkIDs.reset();
311}
312#endif