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