Home | History | Annotate | Download | only in views
      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