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 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 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 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 85 bool SkEventSink::doEvent(const SkEvent& evt) 86 { 87 return this->onEvent(evt); 88 } 89 90 bool SkEventSink::doQuery(SkEvent* evt) 91 { 92 SkASSERT(evt); 93 return this->onQuery(evt); 94 } 95 96 bool SkEventSink::onEvent(const SkEvent&) 97 { 98 return false; 99 } 100 101 bool SkEventSink::onQuery(SkEvent*) 102 { 103 return false; 104 } 105 106 /////////////////////////////////////////////////////////////////////////////// 107 108 SkTagList* SkEventSink::findTagList(U8CPU tag) const 109 { 110 return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL; 111 } 112 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 122 void SkEventSink::removeTagList(U8CPU tag) 123 { 124 if (fTagHead) 125 SkTagList::DeleteTag(&fTagHead, tag); 126 } 127 128 /////////////////////////////////////////////////////////////////////////////// 129 130 struct SkListenersTagList : SkTagList { 131 SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList) 132 { 133 fExtra16 = SkToU16(count); 134 fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID)); 135 } 136 virtual ~SkListenersTagList() 137 { 138 sk_free(fIDs); 139 } 140 141 int countListners() const { return fExtra16; } 142 143 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 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 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 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 219 bool SkEventSink::hasListeners() const 220 { 221 return this->findTagList(kListeners_SkTagList) != NULL; 222 } 223 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 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 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