Receive and process messages in a separate thread. More...
Inherits BHandler.
Inherited by BApplication, BMediaRoster, and BWindow.
Public Member Functions | |
BLooper (const char *name=NULL, int32 priority=B_NORMAL_PRIORITY, int32 portCapacity=B_LOOPER_PORT_DEFAULT_CAPACITY) | |
Construct a new BLooper with a priority and an capacity. | |
virtual | ~BLooper () |
Destruct the looper. | |
virtual status_t | Perform (perform_code d, void *arg) |
Internal method. | |
Message Mechanics | |
status_t | PostMessage (uint32 command) |
Post a message with the command as what identifier to this looper. | |
status_t | PostMessage (BMessage *message) |
Post a message to this looper. | |
status_t | PostMessage (uint32 command, BHandler *handler, BHandler *replyTo=NULL) |
Sends a message with command what identifier to the handler associated with this looper. A response may be sent to the replyTo handler asynchronously. | |
status_t | PostMessage (BMessage *message, BHandler *handler, BHandler *replyTo=NULL) |
Send a message to the handler associated with this looper. A response may be sent to the replyTo handler asynchronously. | |
Message Processing | |
virtual void | DispatchMessage (BMessage *message, BHandler *handler) |
Dispatch a message to a handler. Override if there are messages that you want to catch before they are sent to the handlers. | |
virtual void | MessageReceived (BMessage *message) |
Process a message received by the internal handler of this looper. | |
BMessage * | CurrentMessage () const |
Retrieve the current message. | |
BMessage * | DetachCurrentMessage () |
Get ownership of the message currently being processed. | |
void | DispatchExternalMessage (BMessage *message, BHandler *handler, bool &_detached) |
Internal method to support single-threaded GUI toolkits. | |
BMessageQueue * | MessageQueue () const |
Get a pointer to the internal message queue of this looper. | |
bool | IsMessageWaiting () const |
Check if there is a message waiting. | |
Handler Management | |
void | AddHandler (BHandler *handler) |
Associate a handler to this looper. | |
bool | RemoveHandler (BHandler *handler) |
Disassociate a handler from this looper. | |
int32 | CountHandlers () const |
Get the number of handlers associated with this looper. | |
BHandler * | HandlerAt (int32 index) const |
Get the handler at an index of the list of associated handlers. | |
int32 | IndexOf (BHandler *handler) const |
Get the index of the handler that is in the associated handler list. | |
BHandler * | PreferredHandler () const |
Get the preferred handler. | |
void | SetPreferredHandler (BHandler *handler) |
Set a preferred handler. | |
Loop Debugging | |
These methods may aid you in debugging problems when they occur, but do not use these in actual production code. These methods are unreliable because they are not thread-safe, and as such are only useful in specific debugging situations. Handle with care. | |
thread_id | LockingThread () const |
Return the thread id of the thread that currently holds the lock. | |
int32 | CountLocks () const |
Return the number of recursive locks that are currently being held on this looper. | |
int32 | CountLockRequests () const |
Return the number of pending locks. | |
sem_id | Sem () const |
Return the id of the semaphore that is used to lock this looper. | |
Scripting | |
virtual BHandler * | ResolveSpecifier (BMessage *message, int32 index, BMessage *specifier, int32 what, const char *property) |
Determine the proper handler for a scripting message. | |
virtual status_t | GetSupportedSuites (BMessage *data) |
Reports the suites of messages and specifiers that derived classes understand. | |
Looper Message Filters | |
Note that filters added with these methods will be applied to all associated handlers. Have a look at the filtering methods of the BHandler class to see how filters can be applied to the inherited handler of this looper specifically. | |
virtual void | AddCommonFilter (BMessageFilter *filter) |
Add a common filter to the list of filters that are applied to all incoming messages. | |
virtual bool | RemoveCommonFilter (BMessageFilter *filter) |
Remove a filter from the common message filter list. | |
virtual void | SetCommonFilterList (BList *filters) |
Set a new list of filters that need to be applied to all incoming messages. | |
BList * | CommonFilterList () const |
Return a list of filters applied to all incoming messages. | |
Public Member Functions inherited from BHandler | |
BHandler (const char *name=NULL) | |
Construct a new handler with a name. | |
virtual | ~BHandler () |
Free the filters of this handler, as well as the list of observers. | |
virtual status_t | Perform (perform_code d, void *arg) |
Perform some action (Internal method defined for binary compatibility purposes). | |
BHandler (BMessage *data) | |
Construct a handler from an archived message. | |
BLooper * | Looper () const |
Return a pointer to the looper that this handler is associated with. | |
void | SetName (const char *name) |
Set or change the name of this handler. | |
const char * | Name () const |
Return the name of this handler. | |
virtual void | SetNextHandler (BHandler *handler) |
Set the next handler in the chain that the message is passed on to if this handler cannot process it. | |
BHandler * | NextHandler () const |
Return the next hander in the chain to which the message is passed on. | |
virtual void | AddFilter (BMessageFilter *filter) |
Add filter as a prerequisite to this handler. | |
virtual bool | RemoveFilter (BMessageFilter *filter) |
Remove filter from the filter list. | |
virtual void | SetFilterList (BList *filters) |
Set the internal list of filters to filters. | |
BList * | FilterList () |
Return a pointer to the list of filters. | |
bool | LockLooper () |
Lock the looper associated with this handler. | |
status_t | LockLooperWithTimeout (bigtime_t timeout) |
Lock the looper associated with this handler, with a time out value. | |
void | UnlockLooper () |
Unlock the looper. | |
status_t | StartWatching (BMessenger target, uint32 what) |
Subscribe this handler to watch a specific state change of a target. | |
status_t | StartWatchingAll (BMessenger target) |
Subscribe this handler to watch a target for all events. | |
status_t | StopWatching (BMessenger target, uint32 what) |
Unsubscribe this handler from watching a specific state. | |
status_t | StopWatchingAll (BMessenger target) |
Unsubscribe this handler from watching all states. | |
status_t | StartWatching (BHandler *observer, uint32 what) |
Subscribe an observer for a specific state change of this handler. | |
status_t | StartWatchingAll (BHandler *observer) |
Subscribe an observer for a all state changes. | |
status_t | StopWatching (BHandler *observer, uint32 what) |
Unsubscribe an observer from watching a specific state. | |
status_t | StopWatchingAll (BHandler *observer) |
Unsubscribe an observer from watching all states. | |
virtual void | SendNotices (uint32 what, const BMessage *notice=NULL) |
Emit a state change to the observers. | |
bool | IsWatched () const |
Check if there are any observers watching this handler. | |
Public Member Functions inherited from BArchivable | |
BArchivable () | |
Constructor. Does nothing. | |
BArchivable (BMessage *from) | |
Constructor. Does important behind-the-scenes work in the unarchiving process. | |
virtual | ~BArchivable () |
Destructor. Does nothing. | |
virtual status_t | AllArchived (BMessage *archive) const |
Method relating to the use of BArchiver . | |
virtual status_t | AllUnarchived (const BMessage *archive) |
Method relating to the use of BUnarchiver . | |
virtual status_t | Archive (BMessage *into, bool deep=true) const |
Archive the object into a BMessage. | |
virtual status_t | Perform (perform_code d, void *arg) |
Perform some action (Internal method defined for binary compatibility purposes). | |
Protected Member Functions | |
BMessage * | MessageFromPort (bigtime_t=B_INFINITE_TIMEOUT) |
Hook method to retrieve a message from the looper's port. | |
Archiving | |
BLooper (BMessage *data) | |
Construct a looper from an archived message. | |
virtual status_t | Archive (BMessage *data, bool deep=true) const |
Archive a looper to a message. | |
static BArchivable * | Instantiate (BMessage *data) |
Static method to instantiate a looper from an archived message. | |
Loop Control | |
virtual thread_id | Run () |
Start the event loop. | |
void | Loop () |
Run the event loop in the current thread. | |
virtual void | Quit () |
Hook method that is called after a B_QUIT_REQUESTED message. | |
virtual bool | QuitRequested () |
Hook method that is called during a B_QUIT_REQUESTED message. | |
bool | Lock () |
Lock the looper. | |
void | Unlock () |
Unlock a locked looper. | |
bool | IsLocked () const |
Check if a looper is locked. | |
status_t | LockWithTimeout (bigtime_t timeout) |
Lock a looper with a timeout. | |
thread_id | Thread () const |
Return the thread id of the internal message looper thread. | |
team_id | Team () const |
Return the team id in which this looper exists. | |
static BLooper * | LooperForThread (thread_id thread) |
Static method to retrieve a BLooper for a specified thread. | |
Additional Inherited Members | |
Static Public Member Functions inherited from BHandler | |
static BArchivable * | Instantiate (BMessage *data) |
Static method to instantiate a handler from an archived message. | |
Static Public Member Functions inherited from BArchivable | |
static BArchivable * | Instantiate (BMessage *archive) |
Static member to restore objects from messages. | |
Receive and process messages in a separate thread.
When an object of this class is created, the message loop can be started with Run(). This spawns the thread that receives messages and processes messages. Messages are actually passed on to handlers that are associated with this looper. By default there is always one handler available: the looper itself. To 'quit' a looper, you should pass a B_QUIT_REQUESTED
message using one of the message post functions. When a looper receives such a request, it will delete itself. As such, looper should always be created on the heap (with new
), and never on the stack.
Posting messages can be done using the various PostMessage() methods. Whenever a message is posted, it will be added through to the message queue. It is possible to apply filters (see AddCommonFilter()) to filter out any messages that correspond with certain criteria. The method will copy the contents of the message and this copy is processed, so make sure you delete the original messages in case you create them on the heap. The handler for the message is chosen using the following criteria:
Because a looper usually is used in multiple threads, you should make sure you Lock() and Unlock() it during most operations. Locking calls can be recursive (so multiple locks can come from a single thread), but make sure you pair every Lock() with an Unlock() call. Failing to do so will inevitably cause a deadlock.
Because a looper provides a separate thread, and the inherited handler is usually a default handler, you will most often use this class by subclassing it. For example, you are likely to subclass BWindow (which is derived from BLooper) to customize your window and handle the messages sent to that window. You can override Run() in case you want to perform additional tasks before (or right after) starting the message loop. You can override QuitRequested() if you want to decline quitting in certain circumstances. You can override Quit() in case you want to perform additional procedures during closing time. You can also override DispatchMessage() if you want to do something with all incoming messages before they are dispatched to a handler.
BLooper is one of the major base classes of the Haiku application programmers interface. Closely related classes are BMessage, BHandler and BMessenger. It is used in the interface kit, for example by the BWindow class, which makes sure every window runs it its own thread.
BLooper is a part of the chain in the eloquent messaging structure. For a proper understanding of all its facets, have a look at the messaging overview.
BLooper::BLooper | ( | const char * | name = NULL , |
int32 | priority = B_NORMAL_PRIORITY , |
||
int32 | portCapacity = B_LOOPER_PORT_DEFAULT_CAPACITY |
||
) |
Construct a new BLooper with a priority and an capacity.
The new looper is, by default, not running yet. If you have set up everything properly, you may call Run().
delete
themselves in the Quit() method.name | The name of the looper. |
priority | The priority of the message thread of this looper. The default priority should be good enough for most tasks. Also, some derived versions of BLooper will use a specialized priority. So it is advised to leave this setting at the default, unless you know why you would like another setting. |
portCapacity | Loopers use ports to send and receive messages (see the kernel kit). Ports have a maximum capacity; if there are so many messages queued that the port is full, all other incoming messages are dropped. There are situations where the size of the port should be different from the default. This might be when your looper receives a lot of messages, or if the message handling thread runs at a lower priority than normal, which would decrease the processing speed. Finding a suitable value for these custom scenarios would be done by testing. |
|
virtual |
BLooper::BLooper | ( | BMessage * | data | ) |
Construct a looper from an archived message.
The data message has to be constructed by a BLooper::Archive() call. Note that the data that is restored, is merely the port capacity and the name of the looper/handler. Other data, such as filters, is not archived by the default archiver.
|
virtual |
Add a common filter to the list of filters that are applied to all incoming messages.
Filters can only be applied once, so they cannot be shared between loopers, a handler and a looper or between two handlers.
The filter is not copied; rather a pointer is stored. Keep the filter alive as long as it is used by a looper.
void BLooper::AddHandler | ( | BHandler * | handler | ) |
Associate a handler to this looper.
The handler will be associated to this looper. By default, the handler in this looper will be chained to the supplied handler.
handler | The handler to associate with this looper. If the handler is already associated to another looper, the operation will fail silently. Check beforehand if you cannot be sure that the handler is unassociated. |
Archive a looper to a message.
Currently, only the name and the port capacity are archived. Any other data, such as the filters, is not stored.
data | The message to archive the object in. |
deep | This parameter is ignored, as BLooper does not have children. |
B_OK | Archiving succeeded. |
B_BAD_VALUE | The data parameter is not a valid message. |
Reimplemented from BHandler.
Reimplemented in BWindow, BApplication, BDirectWindow, and BAlert.
BList * BLooper::CommonFilterList | ( | ) | const |
Return a list of filters applied to all incoming messages.
NULL
if such a list has not yet been created. Please note that you should use the internal list management functions to manipulate the internal filter list, in order to maintain internal consistency.int32 BLooper::CountHandlers | ( | ) | const |
int32 BLooper::CountLockRequests | ( | ) | const |
Return the number of pending locks.
int32 BLooper::CountLocks | ( | ) | const |
Return the number of recursive locks that are currently being held on this looper.
BMessage * BLooper::CurrentMessage | ( | ) | const |
Retrieve the current message.
NULL
pointer or an invalid pointer.BMessage * BLooper::DetachCurrentMessage | ( | ) |
Get ownership of the message currently being processed.
Retrieve the current message and gain ownership of it. This means that the message will not be deleted as soon as the looper is done processing it. You can then use it for different purposes.
NULL
pointer.Internal method to support single-threaded GUI toolkits.
Dispatch a message to a handler. Override if there are messages that you want to catch before they are sent to the handlers.
This method is called by the message looping thread to dispatch a message to handler. If you implement the BLooper class and your looper receives messages that absolutely have to be processed by the looper instead of any of the handlers, override this method. For example, the default implementation catches B_QUIT_REQUESTED messages before they are sent to the handlers, so that the looper will quit at those messages.
You are discouraged from using this method to filter out any messages you do not want to process. For this, there is a more generic method using the BMessageFilter class. If you want to skip messages with certain patterns, have a look at the AddCommonFilter() and SetCommonFilterList() methods.
If you do override this method, please remember to call the DispatchMessage() method of the parent class.
Reimplemented in BApplication, BDirectWindow, BAlert, and BWindow.
Reports the suites of messages and specifiers that derived classes understand.
Reimplemented from BHandler.
Reimplemented in BApplication, BDirectWindow, BAlert, and BWindow.
Get the handler at an index of the list of associated handlers.
NULL
if the index is out of range.Get the index of the handler that is in the associated handler list.
|
static |
Static method to instantiate a looper from an archived message.
NULL
if the data is not a valid archived BLooper object.bool BLooper::IsLocked | ( | ) | const |
Check if a looper is locked.
true
if the looper is locked, false
if the looper is not locked, or the looper has been deleted.bool BLooper::IsMessageWaiting | ( | ) | const |
Check if there is a message waiting.
true
if there are still messages to be processed, false
if there is no message waiting. bool BLooper::Lock | ( | ) |
Lock the looper.
For most operations involving the internal data of the looper, you need to hold the lock. Each looper implements a global lock, which you can use to perform operations on internal data in a thread-safe manner.
Do not forget to pair each Lock() request with an Unlock() request. Lock() requests can be stacked, which means that recursively locking a looper from a thread that actually holds the lock, will not cause a deadlock. See BLocker for more information on locking internals.
true
if the locking request succeeded, false
if the locking request could not be completed. There are a variety of reasons for this to happen, for example when the looper is destroyed.Referenced by BAutolock::Lock().
thread_id BLooper::LockingThread | ( | ) | const |
Return the thread id of the thread that currently holds the lock.
Lock a looper with a timeout.
This method locks the looper like Lock(), but if the locking request does not succeed within the provided timeout, the method will return.
timeout | The maximum time to wait for the lock request to succeed. |
B_OK | The lock is acquired. |
B_BAD_VALUE | The looper has been destroyed. |
other errors | There was an error acquiring the lock. |
thread_id BLooper::Loop | ( | ) |
Run the event loop in the current thread.
This method runs the event loop in an already existing thread. It blocks until the looper stops looping. This can be used to turn an existing thread into a BLooper.
Make sure the looper is not yet running before you call this method.
|
static |
Static method to retrieve a BLooper for a specified thread.
Hook method to retrieve a message from the looper's port.
The default implementation is called by the internal message looping thread and retrieves the next message from the port that belongs to this looper.
If you use a looper in a context where it might receive messages from other sources, you can override this method in order to insert these methods into the message processing. Note that any messages that are returned by this method will be deleted by this looper, so make sure you have ownership of the message. If you override this method, remember to call the base implementation every now and then, in order to retrieve the messages arriving at the default port.
BMessageQueue * BLooper::MessageQueue | ( | ) | const |
Get a pointer to the internal message queue of this looper.
You can use this pointer to manipulate the message queue. Note that the message that is being processed is already detached from this queue.
|
virtual |
Process a message received by the internal handler of this looper.
Reimplemented from BHandler::MessageReceived();
Reimplemented from BHandler.
Reimplemented in BApplication, BDirectWindow, BAlert, and BWindow.
|
virtual |
Internal method.
Reimplemented from BHandler.
Reimplemented in BDirectWindow, BWindow, BApplication, and BAlert.
Post a message to this looper.
Posting a message puts it in the message queue. The message passes through the default handler chain.
The message is copied, and as such, you should make sure you will not leak it. The best way to send messages is like this:
message | The message you would like to pass to this method. |
B_OK | The operation succeeded, and the message is sent to the port. |
B_ERROR | There was a general operation error. |
B_BAD_VALUE | This looper is not yet running and therefore cannot receive messages. |
Send a message to the handler associated with this looper. A response may be sent to the replyTo handler asynchronously.
The target handler should be associated with this looper. This method bypasses the default message queue.
The message is copied, and as such, you should make sure you will not leak it. The best way to send messages is like this:
message | The message you want to pass. |
handler | The handler you would like to pass this message to. |
replyTo | If you would like to request a reply, pass the handler to which this reply should be directed to. If you pass NULL , you will not receive a reply. |
B_OK | The operation succeeded, and the message is sent to the port. |
B_ERROR | There was a general operation error. |
B_BAD_VALUE | This looper is not yet running and therefore cannot receive messages. |
B_MISMATCHED_VALUES | The handler is not associated with this looper. |
Post a message with the command as what
identifier to this looper.
Posting a message puts it in the message queue. The message passes through the default handler chain.
command | The what identifier of the message to be sent. |
B_OK | The operation succeeded, and the message is sent to the port. |
B_ERROR | There was a general operation error. |
B_BAD_VALUE | This looper is not yet running and therefore cannot receive messages. |
Sends a message with command what
identifier to the handler associated with this looper. A response may be sent to the replyTo handler asynchronously.
The target handler should be associated with this looper. This method bypasses the default message queue.
command | The value you want as the message's what identifier. |
handler | The handler you would like to pass this message to. |
replyTo | If you would like to request a reply, pass the handler to which this reply should be directed to. If you pass NULL , you will not receive a reply. |
B_OK | The operation succeeded, and the message is sent to the port. |
B_ERROR | There was a general operation error. |
B_BAD_VALUE | This looper is not yet running and therefore cannot receive messages. |
B_MISMATCHED_VALUES | The handler is not associated with this looper. |
BHandler * BLooper::PreferredHandler | ( | ) | const |
Get the preferred handler.
NULL
if none is set.
|
virtual |
Hook method that is called after a B_QUIT_REQUESTED
message.
If you want to quit and delete the looper, you should post a B_QUIT_REQUESTED
message. This will first call the hook method QuitRequested(), which can be overridden in child classes in case there are conditions that would prevent the looper to be quit. If you really know what you are doing, and you definitely want to quit this looper, you may call this method, but only after performing a Lock() operation.
Override this method if your subclass needs to perform specific clean-up tasks. Remember to call the base class implementation when you're done.
Reimplemented in BApplication, BDirectWindow, BAlert, and BWindow.
|
virtual |
Hook method that is called during a B_QUIT_REQUESTED
message.
This hook function is called by the looper thread when a B_QUIT_REQUESTED
is received. The default implementation always accepts the message, but if your subclass needs a special condition to be met before actually accepting a quit message, you can test for that condition in this hook method. A good example is a window (which is a derivative of BLooper), which contains a modified document. The condition may be that a modal dialog requesting a path of action is closed.
true
if the looper can be quit and destroyed, false
if this method does not accept the quit message and continue processing messages.Reimplemented in BApplication, BAlert, and BWindow.
|
virtual |
Remove a filter from the common message filter list.
Note that this will not free the memory used by the filter, so you should dispose of it yourself.
bool BLooper::RemoveHandler | ( | BHandler * | handler | ) |
Disassociate a handler from this looper.
If the handler is disassociated, it can be reassociated to another looper.
true
if the handler has been removed from this looper, false
The handler was invalid or the handler was not associated to this looper.
|
virtual |
Determine the proper handler for a scripting message.
message | The scripting message to determine the handler. |
index | The index of the specifier. |
specifier | The message which contains the specifier. |
what | The 'what' field of the specifier message. |
property | The name of the target property. |
Reimplemented from BHandler.
Reimplemented in BApplication, BAlert, BDirectWindow, and BWindow.
|
virtual |
Start the event loop.
After the looper has been constructed, it needs to be started using this method. A thread will be spawned, which will receive messages.
Make sure the looper is not yet running before you call this method.
Reimplemented in BApplication, and BWindow.
sem_id BLooper::Sem | ( | ) | const |
Return the id of the semaphore that is used to lock this looper.
|
virtual |
Set a new list of filters that need to be applied to all incoming messages.
You are responsible for validating that all the items in the list of filters are actual filters. The old list is discarded; all the filters are destroyed.
Note that filters can only be applied to one looper or handler. If any of the filters is already associated with another one, this call will fail.
void BLooper::SetPreferredHandler | ( | BHandler * | handler | ) |
Set a preferred handler.
If messages are posted to this looper using one of the PostMessage() methods without a specific BHandler argument, the messages will be handled by the looper itself (since a looper is a subclass of BHandler, this is perfectly possible). If you want to override that behavior, you should set a preferred handler. This handler will be called if incoming messages do not ask to be directly passed on to a specific handler.
handler | The preferred handler you want undesignated messages to be handled by. If you want to unset the preferred handler, pass NULL . If the supplied handler is not associated with this looper, this call will fail silently and the current preferred handler will be unset. |
team_id BLooper::Team | ( | ) | const |
Return the team id in which this looper exists.
thread_id BLooper::Thread | ( | ) | const |
Return the thread id of the internal message looper thread.
If the looper is not yet running, this method will return 0.
void BLooper::Unlock | ( | ) |
Unlock a locked looper.
Use this method paired with Lock() calls, to release a lock. Make sure that this method is only called on a locked looper.
Referenced by BAutolock::Unlock().