michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef SkEvent_DEFINED michael@0: #define SkEvent_DEFINED michael@0: michael@0: #include "SkDOM.h" michael@0: #include "SkMetaData.h" michael@0: #include "SkString.h" michael@0: michael@0: /** Unique 32bit id used to identify an instance of SkEventSink. When events are michael@0: posted, they are posted to a specific sinkID. When it is time to dispatch the michael@0: event, the sinkID is used to find the specific SkEventSink object. If it is found, michael@0: its doEvent() method is called with the event. michael@0: */ michael@0: typedef uint32_t SkEventSinkID; michael@0: michael@0: /** michael@0: * \class SkEvent michael@0: * michael@0: * When an event is dispatched from the event queue, it is either sent to michael@0: * the eventsink matching the target ID (if not 0), or the target proc is michael@0: * called (if not NULL). michael@0: */ michael@0: class SkEvent { michael@0: public: michael@0: /** michael@0: * Function pointer that takes an event, returns true if it "handled" it. michael@0: */ michael@0: typedef bool (*Proc)(const SkEvent& evt); michael@0: michael@0: SkEvent(); michael@0: explicit SkEvent(const SkString& type, SkEventSinkID = 0); michael@0: explicit SkEvent(const char type[], SkEventSinkID = 0); michael@0: SkEvent(const SkEvent& src); michael@0: ~SkEvent(); michael@0: michael@0: /** Copy the event's type into the specified SkString parameter */ michael@0: void getType(SkString* str) const; michael@0: michael@0: /** Returns true if the event's type matches exactly the specified type (case sensitive) */ michael@0: bool isType(const SkString& str) const; michael@0: michael@0: /** Returns true if the event's type matches exactly the specified type (case sensitive) */ michael@0: bool isType(const char type[], size_t len = 0) const; michael@0: michael@0: /** michael@0: * Set the event's type to the specified string. michael@0: */ michael@0: void setType(const SkString&); michael@0: michael@0: /** michael@0: * Set the event's type to the specified string. michael@0: */ michael@0: void setType(const char type[], size_t len = 0); michael@0: michael@0: /** michael@0: * Return the target ID, or 0 if there is none. michael@0: * michael@0: * When an event is dispatched from the event queue, it is either sent to michael@0: * the eventsink matching the targetID (if not 0), or the target proc is michael@0: * called (if not NULL). michael@0: */ michael@0: SkEventSinkID getTargetID() const { return fTargetID; } michael@0: michael@0: /** michael@0: * Set the target ID for this event. 0 means none. Calling this will michael@0: * automatically clear the targetProc to null. michael@0: * michael@0: * When an event is dispatched from the event queue, it is either sent to michael@0: * the eventsink matching the targetID (if not 0), or the target proc is michael@0: * called (if not NULL). michael@0: */ michael@0: SkEvent* setTargetID(SkEventSinkID targetID) { michael@0: fTargetProc = NULL; michael@0: fTargetID = targetID; michael@0: return this; michael@0: } michael@0: michael@0: /** michael@0: * Return the target proc, or NULL if it has none. michael@0: * michael@0: * When an event is dispatched from the event queue, it is either sent to michael@0: * the eventsink matching the targetID (if not 0), or the target proc is michael@0: * called (if not NULL). michael@0: */ michael@0: Proc getTargetProc() const { return fTargetProc; } michael@0: michael@0: /** michael@0: * Set the target ID for this event. NULL means none. Calling this will michael@0: * automatically clear the targetID to 0. michael@0: * michael@0: * When an event is dispatched from the event queue, it is either sent to michael@0: * the eventsink matching the targetID (if not 0), or the target proc is michael@0: * called (if not NULL). michael@0: */ michael@0: SkEvent* setTargetProc(Proc proc) { michael@0: fTargetID = 0; michael@0: fTargetProc = proc; michael@0: return this; michael@0: } michael@0: michael@0: /** michael@0: * Return the event's unnamed 32bit field. Default value is 0 michael@0: */ michael@0: uint32_t getFast32() const { return f32; } michael@0: michael@0: /** michael@0: * Set the event's unnamed 32bit field. michael@0: */ michael@0: void setFast32(uint32_t x) { f32 = x; } michael@0: michael@0: /** Return true if the event contains the named 32bit field, and return the field michael@0: in value (if value is non-null). If there is no matching named field, return false michael@0: and ignore the value parameter. michael@0: */ michael@0: bool findS32(const char name[], int32_t* value = NULL) const { return fMeta.findS32(name, value); } michael@0: /** Return true if the event contains the named SkScalar field, and return the field michael@0: in value (if value is non-null). If there is no matching named field, return false michael@0: and ignore the value parameter. michael@0: */ michael@0: bool findScalar(const char name[], SkScalar* value = NULL) const { return fMeta.findScalar(name, value); } michael@0: /** Return true if the event contains the named SkScalar field, and return the fields michael@0: in value[] (if value is non-null), and return the number of SkScalars in count (if count is non-null). michael@0: If there is no matching named field, return false and ignore the value and count parameters. michael@0: */ michael@0: const SkScalar* findScalars(const char name[], int* count, SkScalar values[] = NULL) const { return fMeta.findScalars(name, count, values); } michael@0: /** Return the value of the named string field, or if no matching named field exists, return null. michael@0: */ michael@0: const char* findString(const char name[]) const { return fMeta.findString(name); } michael@0: /** Return true if the event contains the named pointer field, and return the field michael@0: in value (if value is non-null). If there is no matching named field, return false michael@0: and ignore the value parameter. michael@0: */ michael@0: bool findPtr(const char name[], void** value) const { return fMeta.findPtr(name, value); } michael@0: bool findBool(const char name[], bool* value) const { return fMeta.findBool(name, value); } michael@0: const void* findData(const char name[], size_t* byteCount = NULL) const { michael@0: return fMeta.findData(name, byteCount); michael@0: } michael@0: michael@0: /** Returns true if ethe event contains the named 32bit field, and if it equals the specified value */ michael@0: bool hasS32(const char name[], int32_t value) const { return fMeta.hasS32(name, value); } michael@0: /** Returns true if ethe event contains the named SkScalar field, and if it equals the specified value */ michael@0: bool hasScalar(const char name[], SkScalar value) const { return fMeta.hasScalar(name, value); } michael@0: /** Returns true if ethe event contains the named string field, and if it equals (using strcmp) the specified value */ michael@0: bool hasString(const char name[], const char value[]) const { return fMeta.hasString(name, value); } michael@0: /** Returns true if ethe event contains the named pointer field, and if it equals the specified value */ michael@0: bool hasPtr(const char name[], void* value) const { return fMeta.hasPtr(name, value); } michael@0: bool hasBool(const char name[], bool value) const { return fMeta.hasBool(name, value); } michael@0: bool hasData(const char name[], const void* data, size_t byteCount) const { michael@0: return fMeta.hasData(name, data, byteCount); michael@0: } michael@0: michael@0: /** Add/replace the named 32bit field to the event. In XML use the subelement */ michael@0: void setS32(const char name[], int32_t value) { fMeta.setS32(name, value); } michael@0: /** Add/replace the named SkScalar field to the event. In XML use the subelement */ michael@0: void setScalar(const char name[], SkScalar value) { fMeta.setScalar(name, value); } michael@0: /** Add/replace the named SkScalar[] field to the event. */ michael@0: SkScalar* setScalars(const char name[], int count, const SkScalar values[] = NULL) { return fMeta.setScalars(name, count, values); } michael@0: /** Add/replace the named string field to the event. In XML use the subelement postDelay(0); michael@0: } michael@0: michael@0: /** michael@0: * Post to the event queue using the event's targetID or target-proc and michael@0: * the specifed millisecond delay. michael@0: * michael@0: * The event must be dynamically allocated, as ownership is transferred to michael@0: * the event queue. It cannot be allocated on the stack or in a global. michael@0: */ michael@0: void postDelay(SkMSec delay); michael@0: michael@0: /** michael@0: * Post to the event queue using the event's targetID or target-proc. michael@0: * The event will be delivered no sooner than the specified millisecond michael@0: * time, as measured by SkTime::GetMSecs(). michael@0: * michael@0: * The event must be dynamically allocated, as ownership is transferred to michael@0: * the event queue. It cannot be allocated on the stack or in a global. michael@0: */ michael@0: void postTime(SkMSec time); michael@0: michael@0: /////////////////////////////////////////////// michael@0: /** Porting layer must call these functions **/ michael@0: /////////////////////////////////////////////// michael@0: michael@0: /** Global initialization function for the SkEvent system. Should be called exactly michael@0: once before any other event method is called, and should be called after the michael@0: call to SkGraphics::Init(). michael@0: */ michael@0: static void Init(); michael@0: /** Global cleanup function for the SkEvent system. Should be called exactly once after michael@0: all event methods have been called, and should be called before calling SkGraphics::Term(). michael@0: */ michael@0: static void Term(); michael@0: michael@0: /** Call this to process one event from the queue. If it returns true, there are more events michael@0: to process. michael@0: */ michael@0: static bool ProcessEvent(); michael@0: /** Call this whenever the requested timer has expired (requested by a call to SetQueueTimer). michael@0: It will post any delayed events whose time as "expired" onto the event queue. michael@0: It may also call SignalQueueTimer() and SignalNonEmptyQueue(). michael@0: */ michael@0: static void ServiceQueueTimer(); michael@0: michael@0: /** Return the number of queued events. note that this value may be obsolete michael@0: upon return, since another thread may have called ProcessEvent() or michael@0: Post() after the count was made. michael@0: */ michael@0: static int CountEventsOnQueue(); michael@0: michael@0: //////////////////////////////////////////////////// michael@0: /** Porting layer must implement these functions **/ michael@0: //////////////////////////////////////////////////// michael@0: michael@0: /** Called whenever an SkEvent is posted to an empty queue, so that the OS michael@0: can be told to later call Dequeue(). michael@0: */ michael@0: static void SignalNonEmptyQueue(); michael@0: /** Called whenever the delay until the next delayed event changes. If zero is michael@0: passed, then there are no more queued delay events. michael@0: */ michael@0: static void SignalQueueTimer(SkMSec delay); michael@0: michael@0: #if defined(SK_BUILD_FOR_WIN) michael@0: static bool WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); michael@0: #endif michael@0: michael@0: private: michael@0: SkMetaData fMeta; michael@0: mutable char* fType; // may be characters with low bit set to know that it is not a pointer michael@0: uint32_t f32; michael@0: michael@0: // 'there can be only one' (non-zero) between target-id and target-proc michael@0: SkEventSinkID fTargetID; michael@0: Proc fTargetProc; michael@0: michael@0: // these are for our implementation of the event queue michael@0: SkMSec fTime; michael@0: SkEvent* fNextEvent; // either in the delay or normal event queue michael@0: michael@0: void initialize(const char* type, size_t typeLen, SkEventSinkID); michael@0: michael@0: static bool Enqueue(SkEvent* evt); michael@0: static SkMSec EnqueueTime(SkEvent* evt, SkMSec time); michael@0: static SkEvent* Dequeue(); michael@0: static bool QHasEvents(); michael@0: }; michael@0: michael@0: #endif