retool SkEvent to own its target ID or target proc



git-svn-id: http://skia.googlecode.com/svn/trunk@2041 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/views/SkEvent.h b/include/views/SkEvent.h
index 71a2a72..b3a07e9 100644
--- a/include/views/SkEvent.h
+++ b/include/views/SkEvent.h
@@ -21,71 +21,111 @@
 */
 typedef uint32_t SkEventSinkID;
 
-/** \class SkEvent
-
-    SkEvents are used to communicate type-safe information to SkEventSinks.
-    SkEventSinks (including SkViews) each have a unique ID, which is stored
-    in an event. This ID is used to target the event once it has been "posted".
-*/
+/**
+ *  \class SkEvent
+ *
+ *  When an event is dispatched from the event queue, it is either sent to
+ *  the eventsink matching the target ID (if not 0), or the target proc is
+ *  called (if not NULL).
+ */
 class SkEvent {
 public:
-    /** Default construct, creating an empty event.
-    */
+    /**
+     *  Function pointer that takes an event, returns true if it "handled" it.
+     */
+    typedef bool (*Proc)(const SkEvent& evt);
+
     SkEvent();
-    /** Construct a new event with the specified type.
-    */
-    explicit SkEvent(const SkString& type);
-    /** Construct a new event with the specified type.
-    */
-    explicit SkEvent(const char type[]);
-    /** Construct a new event by copying the fields from the src event.
-    */
+    explicit SkEvent(const SkString& type, SkEventSinkID = 0);
+    explicit SkEvent(const char type[], SkEventSinkID = 0);
     SkEvent(const SkEvent& src);
     ~SkEvent();
 
     /** Copy the event's type into the specified SkString parameter */
-    void    getType(SkString* str) const;
+    void getType(SkString* str) const;
+
     /** Returns true if the event's type matches exactly the specified type (case sensitive) */
-    bool    isType(const SkString& str) const;
+    bool isType(const SkString& str) const;
+
     /** Returns true if the event's type matches exactly the specified type (case sensitive) */
-    bool    isType(const char type[], size_t len = 0) const;
-    /** Set the event's type to the specified string.
-        In XML, use the "type" attribute.
-    */
-    void    setType(const SkString&);
-    /** Set the event's type to the specified string.
-        In XML, use the "type" attribute.
-    */
-    void    setType(const char type[], size_t len = 0);
+    bool isType(const char type[], size_t len = 0) const;
+
+    /**
+     *  Set the event's type to the specified string.
+     */
+    void setType(const SkString&);
+
+    /**
+     *  Set the event's type to the specified string.
+     */
+    void setType(const char type[], size_t len = 0);
 
     /**
      *  Return the target ID, or 0 if there is none.
+     *
+     *  When an event is dispatched from the event queue, it is either sent to
+     *  the eventsink matching the targetID (if not 0), or the target proc is
+     *  called (if not NULL).
      */
     SkEventSinkID getTargetID() const { return fTargetID; }
 
     /**
-     *  Set the target ID for this event. 0 means none. Can be specified when
-     *  the event is posted or sent.
+     *  Set the target ID for this event. 0 means none. Calling this will
+     *  automatically clear the targetProc to null.
+     *
+     *  When an event is dispatched from the event queue, it is either sent to
+     *  the eventsink matching the targetID (if not 0), or the target proc is
+     *  called (if not NULL).
      */
-    void setTargetID(SkEventSinkID targetID) { fTargetID = targetID; }
+    SkEvent* setTargetID(SkEventSinkID targetID) {
+        fTargetProc = NULL;
+        fTargetID = targetID;
+        return this;
+    }
 
-    /** Return the event's unnamed 32bit field. Default value is 0 */
+    /**
+     *  Return the target proc, or NULL if it has none.
+     *
+     *  When an event is dispatched from the event queue, it is either sent to
+     *  the eventsink matching the targetID (if not 0), or the target proc is
+     *  called (if not NULL).
+     */
+    Proc getTargetProc() const { return fTargetProc; }
+
+    /**
+     *  Set the target ID for this event. NULL means none. Calling this will
+     *  automatically clear the targetID to 0.
+     *
+     *  When an event is dispatched from the event queue, it is either sent to
+     *  the eventsink matching the targetID (if not 0), or the target proc is
+     *  called (if not NULL).
+     */
+    SkEvent* setTargetProc(Proc proc) {
+        fTargetID = 0;
+        fTargetProc = proc;
+        return this;
+    }
+    
+    /**
+     *  Return the event's unnamed 32bit field. Default value is 0
+     */
     uint32_t getFast32() const { return f32; }
-    /** Set the event's unnamed 32bit field. In XML, use
-        the subelement <data fast32=... />
-    */
-    void    setFast32(uint32_t x) { f32 = x; }
+
+    /**
+     *  Set the event's unnamed 32bit field.
+     */
+    void setFast32(uint32_t x) { f32 = x; }
 
     /** Return true if the event contains the named 32bit field, and return the field
         in value (if value is non-null). If there is no matching named field, return false
         and ignore the value parameter.
     */
-    bool    findS32(const char name[], int32_t* value = NULL) const { return fMeta.findS32(name, value); }
+    bool findS32(const char name[], int32_t* value = NULL) const { return fMeta.findS32(name, value); }
     /** Return true if the event contains the named SkScalar field, and return the field
         in value (if value is non-null). If there is no matching named field, return false
         and ignore the value parameter.
     */
-    bool    findScalar(const char name[], SkScalar* value = NULL) const { return fMeta.findScalar(name, value); }
+    bool findScalar(const char name[], SkScalar* value = NULL) const { return fMeta.findScalar(name, value); }
     /** Return true if the event contains the named SkScalar field, and return the fields
         in value[] (if value is non-null), and return the number of SkScalars in count (if count is non-null).
         If there is no matching named field, return false and ignore the value and count parameters.
@@ -98,112 +138,82 @@
         in value (if value is non-null). If there is no matching named field, return false
         and ignore the value parameter.
     */
-    bool    findPtr(const char name[], void** value) const { return fMeta.findPtr(name, value); }
-    bool    findBool(const char name[], bool* value) const { return fMeta.findBool(name, value); }
+    bool findPtr(const char name[], void** value) const { return fMeta.findPtr(name, value); }
+    bool findBool(const char name[], bool* value) const { return fMeta.findBool(name, value); }
     const void* findData(const char name[], size_t* byteCount = NULL) const {
         return fMeta.findData(name, byteCount);
     }
 
     /** Returns true if ethe event contains the named 32bit field, and if it equals the specified value */
-    bool    hasS32(const char name[], int32_t value) const { return fMeta.hasS32(name, value); }
+    bool hasS32(const char name[], int32_t value) const { return fMeta.hasS32(name, value); }
     /** Returns true if ethe event contains the named SkScalar field, and if it equals the specified value */
-    bool    hasScalar(const char name[], SkScalar value) const { return fMeta.hasScalar(name, value); }
+    bool hasScalar(const char name[], SkScalar value) const { return fMeta.hasScalar(name, value); }
     /** Returns true if ethe event contains the named string field, and if it equals (using strcmp) the specified value */
-    bool    hasString(const char name[], const char value[]) const { return fMeta.hasString(name, value); }
+    bool hasString(const char name[], const char value[]) const { return fMeta.hasString(name, value); }
     /** Returns true if ethe event contains the named pointer field, and if it equals the specified value */
-    bool    hasPtr(const char name[], void* value) const { return fMeta.hasPtr(name, value); }
-    bool    hasBool(const char name[], bool value) const { return fMeta.hasBool(name, value); }
+    bool hasPtr(const char name[], void* value) const { return fMeta.hasPtr(name, value); }
+    bool hasBool(const char name[], bool value) const { return fMeta.hasBool(name, value); }
     bool hasData(const char name[], const void* data, size_t byteCount) const {
         return fMeta.hasData(name, data, byteCount);
     }
 
     /** Add/replace the named 32bit field to the event. In XML use the subelement <data name=... s32=... /> */
-    void    setS32(const char name[], int32_t value) { fMeta.setS32(name, value); }
+    void setS32(const char name[], int32_t value) { fMeta.setS32(name, value); }
     /** Add/replace the named SkScalar field to the event. In XML use the subelement <data name=... scalar=... /> */
-    void    setScalar(const char name[], SkScalar value) { fMeta.setScalar(name, value); }
+    void setScalar(const char name[], SkScalar value) { fMeta.setScalar(name, value); }
     /** Add/replace the named SkScalar[] field to the event. */
     SkScalar* setScalars(const char name[], int count, const SkScalar values[] = NULL) { return fMeta.setScalars(name, count, values); }
     /** Add/replace the named string field to the event. In XML use the subelement <data name=... string=... */
-    void    setString(const char name[], const SkString& value) { fMeta.setString(name, value.c_str()); }
+    void setString(const char name[], const SkString& value) { fMeta.setString(name, value.c_str()); }
     /** Add/replace the named string field to the event. In XML use the subelement <data name=... string=... */
-    void    setString(const char name[], const char value[]) { fMeta.setString(name, value); }
+    void setString(const char name[], const char value[]) { fMeta.setString(name, value); }
     /** Add/replace the named pointer field to the event. There is no XML equivalent for this call */
-    void    setPtr(const char name[], void* value) { fMeta.setPtr(name, value); }
-    void    setBool(const char name[], bool value) { fMeta.setBool(name, value); }
+    void setPtr(const char name[], void* value) { fMeta.setPtr(name, value); }
+    void setBool(const char name[], bool value) { fMeta.setBool(name, value); }
     void setData(const char name[], const void* data, size_t byteCount) {
         fMeta.setData(name, data, byteCount);
     }
 
     /** Return the underlying metadata object */
-    SkMetaData&         getMetaData() { return fMeta; }
+    SkMetaData& getMetaData() { return fMeta; }
     /** Return the underlying metadata object */
-    const SkMetaData&   getMetaData() const { return fMeta; }
-
-    void tron() { SkDEBUGCODE(fDebugTrace = true;) }
-    void troff() { SkDEBUGCODE(fDebugTrace = false;) }
-    bool isDebugTrace() const
-    {
-#ifdef SK_DEBUG
-        return fDebugTrace;
-#else
-        return false;
-#endif
-    }
+    const SkMetaData& getMetaData() const { return fMeta; }
 
     /** Call this to initialize the event from the specified XML node */
-    void    inflate(const SkDOM&, const SkDOM::Node*);
+    void inflate(const SkDOM&, const SkDOM::Node*);
 
     SkDEBUGCODE(void dump(const char title[] = NULL);)
 
-    /** Post the specified event to the event queue, targeting the specified eventsink, with an optional
-        delay. The event must be dynamically allocated for this. It cannot be a global or on the stack.
-        After this call, ownership is transfered to the system, so the caller must not retain
-        the event's ptr. Returns false if the event could not be posted (which means it will have been deleted).
-    */
-    static bool Post(SkEvent* evt, SkEventSinkID targetID, SkMSec delay = 0);
-    /** Post the specified event to the event queue, targeting the specified eventsink, to be delivered on/after the
-        specified millisecond time. The event must be dynamically allocated for this. It cannot be a global or on the stack.
-        After this call, ownership is transfered to the system, so the caller must not retain
-        the event's ptr. Returns false if the event could not be posted (which means it will have been deleted).
-    */
-    static bool PostTime(SkEvent* evt, SkEventSinkID targetID, SkMSec time);
+    ///////////////////////////////////////////////////////////////////////////
 
     /**
-     *  Post to the event queue using the event's targetID. If this is 0, then
-     *  false is returned and the event is deleted, otherwise true is returned
-     *  and ownership of the event passes to the event queue.
+     *  Post to the event queue using the event's targetID or target-proc.
+     *
+     *  The event must be dynamically allocated, as ownership is transferred to
+     *  the event queue. It cannot be allocated on the stack or in a global.
      */
-    bool post() {
+    void post() {
         return this->postDelay(0);
     }
     
     /**
-     *  Post to the event queue using the event's targetID and the specifed
-     *  millisecond delay. If the event's targetID is 0, then false is returned
-     *  and the event is deleted, otherwise true is returned and ownership of
-     *  the event passes to the event queue.
+     *  Post to the event queue using the event's targetID or target-proc and
+     *  the specifed millisecond delay.
+     *
+     *  The event must be dynamically allocated, as ownership is transferred to
+     *  the event queue. It cannot be allocated on the stack or in a global.
      */
-    bool postDelay(SkMSec delay);
+    void postDelay(SkMSec delay);
     
     /**
-     *  Post to the event queue using the event's targetID and the specifed
-     *  millisecond time. If the event's targetID is 0, then false is returned
-     *  and the event is deleted, otherwise true is returned and ownership of
-     *  the event passes to the event queue.
+     *  Post to the event queue using the event's targetID or target-proc.
+     *  The event will be delivered no sooner than the specified millisecond
+     *  time, as measured by SkTime::GetMSecs().
+     *
+     *  The event must be dynamically allocated, as ownership is transferred to
+     *  the event queue. It cannot be allocated on the stack or in a global.
      */
-    bool postTime(SkMSec time);
-    
-    /** Helper method for calling SkEvent::PostTime(this, ...), where the caller specifies a delay.
-        The real "time" will be computed automatically by sampling the clock and adding its value
-        to delay.
-    */
-    bool post(SkEventSinkID sinkID, SkMSec delay = 0) {
-        return SkEvent::Post(this, sinkID, delay);
-    }
-
-    void postTime(SkEventSinkID sinkID, SkMSec time) {
-        SkEvent::PostTime(this, sinkID, time);
-    }
+    void postTime(SkMSec time);
 
     ///////////////////////////////////////////////
     /** Porting layer must call these functions **/
@@ -213,21 +223,21 @@
         once before any other event method is called, and should be called after the
         call to SkGraphics::Init().
     */
-    static void     Init();
+    static void Init();
     /** Global cleanup function for the SkEvent system. Should be called exactly once after
         all event methods have been called, and should be called before calling SkGraphics::Term().
     */
-    static void     Term();
+    static void Term();
 
     /** Call this to process one event from the queue. If it returns true, there are more events
         to process.
     */
-    static bool     ProcessEvent();
+    static bool ProcessEvent();
     /** Call this whenever the requested timer has expired (requested by a call to SetQueueTimer).
         It will post any delayed events whose time as "expired" onto the event queue.
         It may also call SignalQueueTimer() and SignalNonEmptyQueue().
     */
-    static void     ServiceQueueTimer();
+    static void ServiceQueueTimer();
 
     /** Return the number of queued events. note that this value may be obsolete
         upon return, since another thread may have called ProcessEvent() or
@@ -264,17 +274,20 @@
     SkMetaData      fMeta;
     mutable char*   fType;  // may be characters with low bit set to know that it is not a pointer
     uint32_t        f32;
+
+    // 'there can be only one' (non-zero) between target-id and target-proc
     SkEventSinkID   fTargetID;
-    SkDEBUGCODE(bool fDebugTrace;)
+    Proc            fTargetProc;
 
     // these are for our implementation of the event queue
     SkMSec          fTime;
     SkEvent*        fNextEvent; // either in the delay or normal event queue
-    void initialize(const char* type, size_t typeLen);
+
+    void initialize(const char* type, size_t typeLen, SkEventSinkID);
 
     static bool Enqueue(SkEvent* evt);
     static SkMSec EnqueueTime(SkEvent* evt, SkMSec time);
-    static SkEvent* Dequeue(SkEventSinkID* targetID);
+    static SkEvent* Dequeue();
     static bool     QHasEvents();
 };
 
diff --git a/include/views/SkEventSink.h b/include/views/SkEventSink.h
index 6ba4dfa..69981fa 100644
--- a/include/views/SkEventSink.h
+++ b/include/views/SkEventSink.h
@@ -24,53 +24,66 @@
             SkEventSink();
     virtual ~SkEventSink();
 
-    /** Returns this eventsink's unique ID. Use this to post SkEvents to
-        this eventsink.
-    */
+    /**
+     *  Returns this eventsink's unique ID. Use this to post SkEvents to
+     *  this eventsink.
+     */
     SkEventSinkID getSinkID() const { return fID; }
 
-    /** Call this to pass an event to this object for processing. Returns true if the
-        event was handled.
-    */
+    /**
+     *  Call this to pass an event to this object for processing. Returns true if the
+     *  event was handled.
+     */
     bool doEvent(const SkEvent&);
+
     /** Returns true if the sink (or one of its subclasses) understands the event as a query.
         If so, the sink may modify the event to communicate its "answer".
     */
     bool doQuery(SkEvent* query);
 
-    /** Add sinkID to the list of listeners, to receive events from calls to sendToListeners()
-        and postToListeners(). If sinkID already exists in the listener list, no change is made.
-    */
-    void    addListenerID(SkEventSinkID sinkID);
-    /** Copy listeners from one event sink to another, typically from parent to child.
-        @param from the event sink to copy the listeners from
-    */
+    /**
+     *  Add sinkID to the list of listeners, to receive events from calls to sendToListeners()
+     *  and postToListeners(). If sinkID already exists in the listener list, no change is made.
+     */
+    void addListenerID(SkEventSinkID sinkID);
+
+    /**
+     *  Copy listeners from one event sink to another, typically from parent to child.
+     *  @param from the event sink to copy the listeners from
+     */
     void copyListeners(const SkEventSink& from);
-    /** Remove sinkID from the list of listeners. If sinkID does not appear in the list,
-        no change is made.
-    */
-    void    removeListenerID(SkEventSinkID);
-    /** Returns true if there are 1 or more listeners attached to this eventsink
-    */
-    bool    hasListeners() const;
-    /** Posts a copy of evt to each of the eventsinks in the lisener list.
-    */
-    void    postToListeners(const SkEvent& evt, SkMSec delay = 0);
+
+    /**
+     *  Remove sinkID from the list of listeners. If sinkID does not appear in the list,
+     *  no change is made.
+     */
+    void removeListenerID(SkEventSinkID);
+
+    /**
+     *  Returns true if there are 1 or more listeners attached to this eventsink
+     */
+    bool hasListeners() const;
+
+    /**
+     *  Posts a copy of evt to each of the eventsinks in the lisener list.
+     *  This ignores the targetID and target proc in evt.
+     */
+    void postToListeners(const SkEvent& evt, SkMSec delay = 0);
 
     enum EventResult {
         kHandled_EventResult,       //!< the eventsink returned true from its doEvent method
         kNotHandled_EventResult,    //!< the eventsink returned false from its doEvent method
         kSinkNotFound_EventResult   //!< no matching eventsink was found for the event's getSink().
     };
-    /** DoEvent handles searching for an eventsink object that matches the targetID.
-        If one is found, it calls the sink's doEvent method, returning
-        either kHandled_EventResult or kNotHandled_EventResult. If no matching
-        eventsink is found, kSinkNotFound_EventResult is returned.
-    */
-    static EventResult DoEvent(const SkEvent&, SkEventSinkID targetID);
 
-    /** Returns the matching eventsink, or null if not found
-    */
+    /**
+     *  DoEvent handles dispatching the event to its target ID or proc.
+     */
+    static EventResult DoEvent(const SkEvent&);
+
+    /**
+     *  Returns the matching eventsink, or null if not found
+     */
     static SkEventSink* FindSink(SkEventSinkID);
 
 protected:
diff --git a/include/views/SkOSMenu.h b/include/views/SkOSMenu.h
index 2dbc1a5..54c7dbe 100644
--- a/include/views/SkOSMenu.h
+++ b/include/views/SkOSMenu.h
@@ -64,7 +64,9 @@
         
         //Post event associated with the menu item to target, any changes to the
         //associated event must be made prior to calling this method.
-        void postEvent() const { (new SkEvent(*(fEvent)))->post(fTarget); }
+        void postEvent() const {
+            (new SkEvent(*(fEvent)))->setTargetID(fTarget)->post();
+        }
         
         //Helper functions for predefined types
         void postEventWithBool(bool value) const; //For Switch
diff --git a/include/views/SkView.h b/include/views/SkView.h
index acac745..5cb6e4a 100644
--- a/include/views/SkView.h
+++ b/include/views/SkView.h
@@ -162,10 +162,6 @@
      */
     SkView* sendQueryToParents(SkEvent*);
 
-    /** Depricated helper function. Just call event->post(sinkID, delay);
-    */
-    bool    postEvent(SkEvent* evt, SkEventSinkID sinkID, SkMSec delay) { return evt->post(sinkID, delay); }
-
     //  View hierarchy management
 
     /** Return the view's parent, or null if it has none. This does not affect the parent's reference count. */
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 0d70f66..92004f9 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -156,8 +156,7 @@
 static const char view_inval_msg[] = "view-inval-msg";
 
 void SampleWindow::postInvalDelay() {
-    SkEvent* evt = new SkEvent(view_inval_msg);
-    evt->post(this->getSinkID(), 1);
+    (new SkEvent(view_inval_msg, this->getSinkID()))->postDelay(1);
 }
 
 static bool isInvalEvent(const SkEvent& evt) {
@@ -1002,8 +1001,7 @@
 
 void SampleWindow::postAnimatingEvent() {
     if (fAnimating) {
-        SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
-        evt->post(this->getSinkID(), ANIMATING_DELAY);
+        (new SkEvent(ANIMATING_EVENTTYPE, this->getSinkID()))->postDelay(ANIMATING_DELAY);
     }
 }
 
@@ -1416,6 +1414,7 @@
     if (NULL == view) {
         view = create_overview(fSamples.count(), fSamples.begin());
     }
+    
     view->setVisibleP(true);
     view->setClipToBounds(false);
     this->attachChildToFront(view)->unref();
diff --git a/samplecode/SampleGM.cpp b/samplecode/SampleGM.cpp
index 7319af8..2d172af 100644
--- a/samplecode/SampleGM.cpp
+++ b/samplecode/SampleGM.cpp
@@ -96,7 +96,7 @@
     
 private:
     void postNextGM() {
-        (new SkEvent("next-gm"))->post(this->getSinkID(), 1500);
+        (new SkEvent("next-gm", this->getSinkID()))->postDelay(1500);
     }
 
     typedef SampleView INHERITED;
diff --git a/samplecode/SamplePicture.cpp b/samplecode/SamplePicture.cpp
index d0ec092..d2c9d65 100644
--- a/samplecode/SamplePicture.cpp
+++ b/samplecode/SamplePicture.cpp
@@ -173,7 +173,7 @@
     #define INVAL_ALL_TYPE  "inval-all"
     
     void delayInval(SkMSec delay) {
-        (new SkEvent(INVAL_ALL_TYPE))->post(this->getSinkID(), delay);
+        (new SkEvent(INVAL_ALL_TYPE, this->getSinkID()))->postDelay(delay);
     }
     
     virtual bool onEvent(const SkEvent& evt) {
diff --git a/samplecode/SampleXfermodesBlur.cpp b/samplecode/SampleXfermodesBlur.cpp
index c1aaf98..f0dcf31 100644
--- a/samplecode/SampleXfermodesBlur.cpp
+++ b/samplecode/SampleXfermodesBlur.cpp
@@ -95,6 +95,30 @@
     virtual void onDrawContent(SkCanvas* canvas) {
         canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
 
+        if (false) {
+            SkPaint paint;
+            paint.setAntiAlias(true);
+            paint.setTextSize(50);
+            paint.setTypeface(SkTypeface::CreateFromName("Arial Unicode MS", SkTypeface::kNormal));
+            SkSafeUnref(paint.getTypeface());
+            char buffer[10];
+            size_t len = SkUTF8_FromUnichar(0x8500, buffer);
+            canvas->drawText(buffer, len, 40, 40, paint);
+            return;
+        }
+        if (true) {
+            SkPaint paint;
+            paint.setAntiAlias(true);
+            
+            SkRect r0 = { 0, 0, 10.5f, 20 };
+            SkRect r1 = { 10.5f, 10, 20, 30 };
+            paint.setColor(SK_ColorRED);
+            canvas->drawRect(r0, paint);
+            paint.setColor(SK_ColorBLUE);
+            canvas->drawRect(r1, paint);
+            return;
+        }
+
         const struct {
             SkXfermode::Mode  fMode;
             const char*         fLabel;
diff --git a/src/animator/SkAnimateMaker.cpp b/src/animator/SkAnimateMaker.cpp
index ce4ddfd..414e728 100644
--- a/src/animator/SkAnimateMaker.cpp
+++ b/src/animator/SkAnimateMaker.cpp
@@ -121,9 +121,11 @@
 
 void SkAnimateMaker::delayEnable(SkApply* apply, SkMSec time) {
     int index = fDelayed.find(apply);
-    if (index < 0)
+    if (index < 0) {
         *fDelayed.append() = apply;
-    (new SkEvent(SK_EventType_Delay))->postTime(fAnimator->getSinkID(), time);
+    }
+    
+    (new SkEvent(SK_EventType_Delay, fAnimator->getSinkID()))->postTime(time);
 }
 
 void SkAnimateMaker::deleteMembers() {
diff --git a/src/animator/SkAnimator.cpp b/src/animator/SkAnimator.cpp
index 9b5b061..a8f23fe 100644
--- a/src/animator/SkAnimator.cpp
+++ b/src/animator/SkAnimator.cpp
@@ -479,7 +479,7 @@
 #else
     SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
 #endif
-    SkEvent::Post(evt, sinkID);
+    evt->setTargetID(sinkID)->post();
 }
 
 void SkAnimator::onEventPostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time)
@@ -493,7 +493,7 @@
 #else
     SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
 #endif
-    SkEvent::PostTime(evt, sinkID, time);
+    evt->setTargetID(sinkID)->postTime(time);
 }
 
 void SkAnimator::reset() {
diff --git a/src/utils/mac/SkOSWindow_Mac.cpp b/src/utils/mac/SkOSWindow_Mac.cpp
index 5731a4d..2940cbd 100644
--- a/src/utils/mac/SkOSWindow_Mac.cpp
+++ b/src/utils/mac/SkOSWindow_Mac.cpp
@@ -204,8 +204,7 @@
 
 void SkOSWindow::onHandleInval(const SkIRect& r)
 {
-    SkEvent* evt = new SkEvent("inval-imageview");
-    evt->post(this->getSinkID());
+    (new SkEvent("inval-imageview", this->getSinkID()))->post();
 }
 
 bool SkOSWindow::onEvent(const SkEvent& evt) {
diff --git a/src/views/SkEvent.cpp b/src/views/SkEvent.cpp
index d330636..c7ac638 100644
--- a/src/views/SkEvent.cpp
+++ b/src/views/SkEvent.cpp
@@ -9,21 +9,22 @@
 
 #include "SkEvent.h"
 
-void SkEvent::initialize(const char* type, size_t typeLen) {
+void SkEvent::initialize(const char* type, size_t typeLen,
+                         SkEventSinkID targetID) {
     fType = NULL;
     setType(type, typeLen);
     f32 = 0;
+    fTargetID = targetID;
+    fTargetProc = NULL;
 #ifdef SK_DEBUG
-    fTargetID = 0;
     fTime = 0;
     fNextEvent = NULL;
 #endif
-    SkDEBUGCODE(fDebugTrace = false;)
 }
 
 SkEvent::SkEvent()
 {
-    initialize("", 0);
+    initialize("", 0, 0);
 }
 
 SkEvent::SkEvent(const SkEvent& src)
@@ -33,15 +34,15 @@
         setType(src.fType);
 }
 
-SkEvent::SkEvent(const SkString& type)
+SkEvent::SkEvent(const SkString& type, SkEventSinkID targetID)
 {
-    initialize(type.c_str(), type.size());
+    initialize(type.c_str(), type.size(), targetID);
 }
 
-SkEvent::SkEvent(const char type[])
+SkEvent::SkEvent(const char type[], SkEventSinkID targetID)
 {
     SkASSERT(type);
-    initialize(type, strlen(type));
+    initialize(type, strlen(type), targetID);
 }
 
 SkEvent::~SkEvent()
@@ -288,90 +289,50 @@
     return rec;
 }
 
-bool SkEvent::Post(SkEvent* evt, SkEventSinkID sinkID, SkMSec delay)
-{
-    if (delay)
-        return SkEvent::PostTime(evt, sinkID, SkTime::GetMSecs() + delay);
+///////////////////////////////////////////////////////////////////////////////
 
-    SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
-
-    evt->fTargetID = sinkID;
-
-#ifdef SK_TRACE_EVENTS
-    {
-        SkString    str("SkEvent::Post(");
-        str.append(evt->getType());
-        str.append(", 0x");
-        str.appendHex(sinkID);
-        str.append(", ");
-        str.appendS32(delay);
-        str.append(")");
-        event_log(str.c_str());
-    }
-#endif
-
-    globals.fEventMutex.acquire();
-    bool wasEmpty = SkEvent::Enqueue(evt);
-    globals.fEventMutex.release();
-
-    // call outside of us holding the mutex
-    if (wasEmpty)
-        SkEvent::SignalNonEmptyQueue();
-    return true;
-}
-
-#if defined(SK_SIMULATE_FAILED_MALLOC) && defined(SK_FIND_MEMORY_LEAKS)
-SkMSec gMaxDrawTime;
-#endif
-
-bool SkEvent::PostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time)
-{
-#if defined(SK_SIMULATE_FAILED_MALLOC) && defined(SK_FIND_MEMORY_LEAKS)
-    gMaxDrawTime = time;
-#endif
-    SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
-
-    evt->fTargetID = sinkID;
-
-#ifdef SK_TRACE_EVENTS
-    {
-        SkString    str("SkEvent::Post(");
-        str.append(evt->getType());
-        str.append(", 0x");
-        str.appendHex(sinkID);
-        str.append(", ");
-        str.appendS32(time);
-        str.append(")");
-        event_log(str.c_str());
-    }
-#endif
-
-    globals.fEventMutex.acquire();
-    SkMSec queueDelay = SkEvent::EnqueueTime(evt, time);
-    globals.fEventMutex.release();
-
-    // call outside of us holding the mutex
-    if ((int32_t)queueDelay != ~0)
-        SkEvent::SignalQueueTimer(queueDelay);
-    return true;
-}
-
-bool SkEvent::postDelay(SkMSec delay) {
-    return SkEvent::Post(this, this->getTargetID(), delay);
-}
-
-bool SkEvent::postTime(SkMSec time) {
-    SkEventSinkID target = this->getTargetID();
-    if (target) {
-        return SkEvent::PostTime(this, target, time);
-    } else {
+void SkEvent::postDelay(SkMSec delay) {
+    if (!fTargetID && !fTargetProc) {
         delete this;
-        return false;
+        return;
+    }
+    
+    if (delay) {
+        this->postTime(SkTime::GetMSecs() + delay);
+        return;
+    }
+
+    SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+    globals.fEventMutex.acquire();
+    bool wasEmpty = SkEvent::Enqueue(this);
+    globals.fEventMutex.release();
+    
+    // call outside of us holding the mutex
+    if (wasEmpty) {
+        SkEvent::SignalNonEmptyQueue();
     }
 }
 
-bool SkEvent::Enqueue(SkEvent* evt)
-{
+void SkEvent::postTime(SkMSec time) {
+    if (!fTargetID && !fTargetProc) {
+        delete this;
+        return;
+    }
+
+    SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+    
+    globals.fEventMutex.acquire();
+    SkMSec queueDelay = SkEvent::EnqueueTime(this, time);
+    globals.fEventMutex.release();
+    
+    // call outside of us holding the mutex
+    if ((int32_t)queueDelay != ~0) {
+        SkEvent::SignalQueueTimer(queueDelay);
+    }
+}
+
+bool SkEvent::Enqueue(SkEvent* evt) {
     SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
     //  gEventMutex acquired by caller
 
@@ -387,37 +348,29 @@
     evt->fNextEvent = NULL;
 
     SkDEBUGCODE(++globals.fEventCounter);
-//  SkDebugf("Enqueue: count=%d\n", gEventCounter);
 
     return wasEmpty;
 }
 
-SkEvent* SkEvent::Dequeue(SkEventSinkID* sinkID)
-{
+SkEvent* SkEvent::Dequeue() {
     SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
     globals.fEventMutex.acquire();
 
     SkEvent* evt = globals.fEventQHead;
-    if (evt)
-    {
+    if (evt) {
         SkDEBUGCODE(--globals.fEventCounter);
 
-        if (sinkID)
-            *sinkID = evt->fTargetID;
-
         globals.fEventQHead = evt->fNextEvent;
-        if (globals.fEventQHead == NULL)
+        if (globals.fEventQHead == NULL) {
             globals.fEventQTail = NULL;
+        }
     }
     globals.fEventMutex.release();
 
-//  SkDebugf("Dequeue: count=%d\n", gEventCounter);
-
     return evt;
 }
 
-bool SkEvent::QHasEvents()
-{
+bool SkEvent::QHasEvents() {
     SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
 
     // this is not thread accurate, need a semaphore for that
@@ -428,60 +381,49 @@
     static int gDelayDepth;
 #endif
 
-SkMSec SkEvent::EnqueueTime(SkEvent* evt, SkMSec time)
-{
-#ifdef SK_TRACE_EVENTS
-    SkDebugf("enqueue-delay %s %d (%d)", evt->getType(), time, gDelayDepth);
-    const char* idStr = evt->findString("id");
-    if (idStr)
-        SkDebugf(" (%s)", idStr);
-    SkDebugf("\n");
-    ++gDelayDepth;
-#endif
-
+SkMSec SkEvent::EnqueueTime(SkEvent* evt, SkMSec time) {
     SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
     //  gEventMutex acquired by caller
 
     SkEvent* curr = globals.fDelayQHead;
     SkEvent* prev = NULL;
 
-    while (curr)
-    {
-        if (SkMSec_LT(time, curr->fTime))
+    while (curr) {
+        if (SkMSec_LT(time, curr->fTime)) {
             break;
+        }
         prev = curr;
         curr = curr->fNextEvent;
     }
 
     evt->fTime = time;
     evt->fNextEvent = curr;
-    if (prev == NULL)
+    if (prev == NULL) {
         globals.fDelayQHead = evt;
-    else
+    } else {
         prev->fNextEvent = evt;
+    }
 
     SkMSec delay = globals.fDelayQHead->fTime - SkTime::GetMSecs();
-    if ((int32_t)delay <= 0)
+    if ((int32_t)delay <= 0) {
         delay = 1;
+    }
     return delay;
 }
 
-//////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
 
 #include "SkEventSink.h"
 
-bool SkEvent::ProcessEvent()
-{
-    SkEventSinkID   sinkID;
-    SkEvent*        evt = SkEvent::Dequeue(&sinkID);
+bool SkEvent::ProcessEvent() {
+    SkEvent*                evt = SkEvent::Dequeue();
     SkAutoTDelete<SkEvent>  autoDelete(evt);
-    bool            again = false;
+    bool                    again = false;
 
     EVENT_LOGN("ProcessEvent", (int32_t)evt);
 
-    if (evt)
-    {
-        (void)SkEventSink::DoEvent(*evt, sinkID);
+    if (evt) {
+        (void)SkEventSink::DoEvent(*evt);
         again = SkEvent::QHasEvents();
     }
     return again;
diff --git a/src/views/SkEventSink.cpp b/src/views/SkEventSink.cpp
index 3c3aa5d..9d3482a 100644
--- a/src/views/SkEventSink.cpp
+++ b/src/views/SkEventSink.cpp
@@ -213,58 +213,33 @@
     return this->findTagList(kListeners_SkTagList) != NULL;
 }
 
-void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay)
-{
+void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay) {
     SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
-    if (list)
-    {
+    if (list) {
         SkASSERT(list->countListners() > 0);
         const SkEventSinkID* iter = list->fIDs;
         const SkEventSinkID* stop = iter + list->countListners();
-        while (iter < stop)
-            (SkNEW_ARGS(SkEvent, (evt)))->post(*iter++, delay);
+        while (iter < stop) {
+            SkEvent* copy = SkNEW_ARGS(SkEvent, (evt));
+            copy->setTargetID(*iter++)->postDelay(delay);
+        }
     }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt, SkEventSinkID sinkID)
-{
-    SkEventSink* sink = SkEventSink::FindSink(sinkID);
-
-    if (sink)
-    {
-#ifdef SK_DEBUG
-        if (evt.isDebugTrace())
-        {
-            SkString    etype;
-            evt.getType(&etype);
-            SkDebugf("SkEventTrace: dispatching event <%s> to 0x%x", etype.c_str(), sinkID);
-            const char* idStr = evt.findString("id");
-            if (idStr)
-                SkDebugf(" (%s)", idStr);
-            SkDebugf("\n");
-        }
-#endif
+SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt) {
+    SkEvent::Proc proc = evt.getTargetProc();
+    if (proc) {
+        return proc(evt) ? kHandled_EventResult : kNotHandled_EventResult;
+    }
+        
+    SkEventSink* sink = SkEventSink::FindSink(evt.getTargetID());
+    if (sink) {
         return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
     }
-    else
-    {
-#ifdef SK_DEBUG
-        if (sinkID)
-            SkDebugf("DoEvent: Can't find sink for ID(%x)\n", sinkID);
-        else
-            SkDebugf("Event sent to 0 sinkID\n");
 
-        if (evt.isDebugTrace())
-        {
-            SkString    etype;
-            evt.getType(&etype);
-            SkDebugf("SkEventTrace: eventsink not found <%s> for 0x%x\n", etype.c_str(), sinkID);
-        }
-#endif
-        return kSinkNotFound_EventResult;
-    }
+    return kSinkNotFound_EventResult;
 }
 
 SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)