/** Copyright 2007-2014 Haiku, Inc. All rights reserved.* Distributed under the terms of the MIT License.** Authors:* Niels Sascha Reedijk, niels.reedijk@gmail.com* John Scipione, jscipione@gmail.com** Corresponds to:* headers/os/app/Handler.h hrev47355* src/kits/app/Handler.cpp hrev47355*//*!\file Handler.h\ingroup app\ingroup libbe\brief Provides the BHandler class.*////// Globals //////*!\def B_OBSERVE_WHAT_CHANGE\brief Internal.\since BeOS R5*//*!\def B_OBSERVE_ORIGINAL_WHAT\brief Constant for a message data field in observer messages.If you have called one of the flavors of BHandler::StartWachting(), andyou receive a notification, sometimes there can be send a BMessage to gowith that notification. The message you receive is a copy of that message,but with the what constant set to \c B_OBSERVER_NOTICE_CHANGE. The original\c what constant of the transmitted data message is stored behind thelabel defined by this constant.\since BeOS R5*//*!\var B_OBSERVER_OBSERVE_ALL\brief Parameter to BHandler::StartWatching().\note Specifying this parameter as the \a what value, leads to the sameresults as calling BHandler::StartWatchingAll().\since BeOS R5*////// BHandler //////*!\class BHandler\ingroup app\ingroup libbe\brief Handles messages that are passed on by a BLooper.The BHandler class implements two important pieces of functionality. Itprovides the foundations for <b>handling messages</b>, and it serves as a<b>state machine</b> that sends out notifications of the state changes.The most common use of this class is to <b>handle messages</b>. Handlerscan be tied to loopers, which are the objects that send and receivemessages. As soon as a message is received, the looper passes through itslist of associated handlers and tries them in a certain order until themessage is handled, or the options are exhausted.You should know that a looper is a subclass of a handler, and as such,loopers can be self-contained and do not need additional handlers. In manycases, this construction will suffice. You will simply subclass the looper,override its MessageReceived() hook and handle the messages you receive. Insome cases, you might opt in for a more ingenious construction. Areal-world example is the interface kit. Within that kit, the windows arerepresented by a BLooper, and all the views and controls in that kit arederived from BHandler. If you put a control in a window, then whenevermessages such as clicks are received, the window loops the handlers untilthere is a handler that is at the screen position the click was in. It isnot unlikely that you will some day want to use this functionality of theAPI.If your handler is limited to a certain type of messages, you can set afilter that the looper will apply to your message before passing it on toyour overridden MessageReceived() method. The BMessageFilter class providesthe framework for the flexible filtering options, and using AddFilter() youcan apply filters to this handler. Note that a filter object should only beapplied to one handler. They cannot be shared.For more information on the handling chain, have a look at thedocumentation of the BLooper class.Using BHandler as a <b>state machine</b> is a second area of functionality.Since handlers process messages, and perform actions associated with those,they are the center of keeping track on the current state of things withinan application. If you want to synchronize these states between differentparts of your application, you could perform this manually by sendingmessages to the interested components, or you can use the more flexibleapproach with observers.Observers watch a certain state. A handler can track one or more differentstates. Each state is represented by a four byte constant - just like the\c what property of a message. Using the StartWatching() methods, you canregister observers both within your team, and in other applications. As anargument of that method, you can supply the state you want to watch, or youcan register an observer using StartWatchingAll() to watch all the statesthe handler tracks. When the handler needs to emit a state change, you canuse SendNotices(). You can specify the exact state change, and some datathat you want to be send to the observers. This data is in the form of thevery flexible BMessage, as such you are almost free to pass anything youwant.Whenever SendNotices() is called, all interested observers will receive amessage of the \a B_OBSERVER_NOTICE_CHANGE type. Please note that theconstant that is associated with the state itself is not transmitted. Ifyou require this information, consider using the message that is passedon to describe the state change.BHandler is a part of the chain in the eloquent messaging structure. For aproper understanding of all its facets, have a look at the \ref app_messaging"messaging overview".\since BeOS R3*//*!\fn BHandler::BHandler(const char* name)\brief Construct a new handler with a \a name.The newly constructed handler is not associated with a looper until youexplicitly request this to happen. To associate this handler with a looper,use BLooper::AddHandler().\since BeOS R3*//*!\fn BHandler::~BHandler()\brief Free the filters of this handler, as well as the list of observers.This method does not remove the handler from the looper to which thishandler is associated. You should do this yourself, usingBLooper::RemoveHandler().\warning This constructor does no type check whatsoever. Since you can passany BMessage, you should - if you are not sure about the exact type -use the Instantiate() method, which does check the type.\since BeOS R3*//*!\fn BArchivable* BHandler::Instantiate(BMessage* data)\brief Static method to instantiate a handler from an archived message.\return A pointer to the instantiated handler, or \c NULL if the \a datais not a valid archived BHandler object.\see BHandler(BMessage* data)\since BeOS R3*////// Archiving //////*!\name ArchivingBHandler inherits the BArchivable class, and as such implements support forarchiving and unarchiving handlers.*///! @{/*!\fn BHandler::BHandler(BMessage* data)\brief Construct a handler from an archived message.This \a data has to be created using the BHandler::Archive() method.Note that only the name is stored. The filters, the associated looper andthe observers are not stored, and should be manually added when you areusing this object.\since BeOS R3*//*!\fn status_t BHandler::Archive(BMessage* data, bool deep) const\brief Archive a handler to a messageCurrently, only the name is archived. The filters, the associated looperand the observers are not stored.\param data The message to archive the object in.\param deep This parameter is ignored, as BHandler does not have children.\return A status code.\retval B_OK Archiving succeeded.\retval B_BAD_VALUE The \a data parameter is not a valid message.\see BHandler::Instantiate(BMessage* data)\since BeOS R3*///! @}///// The guts of BHandler //////*!\name Core Handler Functionality*///! @{/*!\fn void BHandler::MessageReceived(BMessage* message)\brief Handle \a message that has been received by the associated looper.This method is reimplemented by subclasses. If the messages that havebeen received by a looper pass through the filters, then they end up inthe MessageReceived() methods.The example below shows a very common way to handle \a message. Usually,this involves parsing the BMessage::what constant and then perform anaction based on that.\codevoidShowImageApp::MessageReceived(BMessage *message){switch (message->what) {case MSG_FILE_OPEN:fOpenPanel->Show();break;case B_CANCEL:// File open panel was closed,// start checking count of open windows.StartPulse();break;default:// We do not handle this message, pass it on to the base class.BApplication::MessageReceived(message);break;}}\endcodeIf your handler cannot process this \a message, you should pass it onto the base class. Eventually, it will reach the base implementation,which will reply with \c B_MESSAGE_NOT_UNDERSTOOD.\attention If you want to keep or manipulate the \a message, have alook at BLooper::DetachCurrentMessage() to receive ownershipof the \a message.\param message The message that needs to be handled.\since BeOS R3*//*!\fn BLooper* BHandler::Looper() const\brief Return a pointer to the looper that this handler is associated with.\return If the handler is not yet associated with a looper, it will return\c NULL.\see BLooper::AddHandler()\see LockLooper()\since BeOS R3*//*!\fn void BHandler::SetName(const char *name)\brief Set or change the name of this handler.\see Name()\since BeOS R3*//*!\fn const char* BHandler::Name() const\brief Return the name of this handler.\see SetName()\since BeOS R3*//*!\fn void BHandler::SetNextHandler(BHandler* handler)\brief Set the next handler in the chain that the message is passed on toif this \a handler cannot process it.This method has three requirements:-# This \a handler should belong to a looper.-# The looper needs to be locked. See LockLooper().-# The \a handler that you pass must be associated with the same looper.Failure to meet any of these requirements will result in your applicationcrashing.By default, the handlers are chained in order that they were associated toa looper with BLooper::AddHander().\see NextHandler()\since BeOS R3*//*!\fn BHandler* BHandler::NextHandler() const\brief Return the next hander in the chain to which the message is passedon.\see SetNextHandler()\since BeOS R3*///! @}///// Message Filtering //////*!\name Message Filtering*///! @{/*!\fn void BHandler::AddFilter(BMessageFilter *filter)\brief Add \a filter as a prerequisite to this handler.If the handler is associated with a looper, this looper needs to be lockedin order for this operation to succeed.Note that the filter is not copied, rather a pointer to the \a filter isstored. As such, you need to make sure that the \a filter object exists aslong as it is added to this handler.\see RemoveFilter()\see SetFilterList()\since BeOS R3*//*!\fn bool BHandler::RemoveFilter(BMessageFilter* filter)\brief Remove \a filter from the filter list.If the handler is associated with a looper, this looper needs to be lockedin order for this operation to succeed.Note that the \a filter is not deleted, merely removed from the list. Youneed to take care of the memory yourself.\return \c true if the \a filter was in the filter list and is removed,\c false if the \a filter was not found in the filter list.\see AddFilter()\see FilterList()\since BeOS R3*//*!\fn void BHandler::SetFilterList(BList* filters)\brief Set the internal list of filters to \a filters.If the handler is associated with a looper, this looper needs to be lockedin order for this operation to succeed.The internal list will be replaced with the new list of \a filters. All theexisting filters will be \b deleted.\see AddFilter(), FilterList()\since BeOS R3*//*!\fn BList* BHandler::FilterList()\brief Return a pointer to the list of filters.\return A pointer to the list of filters. Do not manipulate the list offilters directly, but use the methods provided by this class, inorder to maintain internal consistency.\see AddFilter()\see RemoveFilter()\see SetFilterList().\since BeOS R3*///! @}///// Locking //////*!\name LockingThis class provides some utility functions to lock the looper associatedwith this handler.*///! @{/*!\fn bool BHandler::LockLooper()\brief Lock the looper associated with this handler.\return \c true if the looper is locked, \c false if there was an erroracquiring the lock.\see LockLooperWithTimeout()\see UnlockLooper()\since BeOS R4*//*!\fn status_t BHandler::LockLooperWithTimeout(bigtime_t timeout)\brief Lock the looper associated with this handler, with a time out value.\param timeout The time to wait for acquiring the lock in microseconds. Youmay also use \c B_INFINITE_TIMEOUT, in which this method will waitas long as it takes to acquire the lock.\return A status code.\retval B_OK Locking succeeded.\retval B_BAD_VALUE This handler is not associated with a looper (anymore).\retval B_TIMED_OUT The time specified in \a timeout has passed withoutlocking the looper.\see LockLooper()\see UnlockLooper()\since BeOS R4*//*!\fn void BHandler::UnlockLooper()\brief Unlock the looper.\since BeOS R4*///! @}///// Scripting ///////*!\name Scripting*///! @{/*!\fn BHandler* BHandler::ResolveSpecifier(BMessage* message, int32 index,BMessage* specifier, int32 what, const char* property)\brief Determine the proper handler for a scripting message.\param message The scripting message to determine the handler.\param index The index of the specifier.\param specifier The message which contains the specifier.\param what The 'what' field of the specifier message.\param property The name of the target property.\return A pointer to the proper BHandler for the given scriptingmessage.\since BeOS R3*//*!\fn status_t BHandler::GetSupportedSuites(BMessage* data)\brief Reports the suites of messages and specifiers that derived classesunderstand.\since BeOS R3*///! @}///// Observing //////*!\name ObservingHandlers can function as state machines, which emit messages to observerswhen the state changes. Use the following methods to subscribe to thesenotifications.Note that there is a semantic difference between the two StartWatching()methods. The overloaded method that accepts a BHandler, expects asargument an \a observer that watches this handler. The method thataccepts a BMessenger, expects a \a target that emits the state changesto this handler.*///! @{/*!\fn status_t BHandler::StartWatching(BMessenger target, uint32 what)\brief Subscribe this handler to watch a specific state change of a\a target.Use this method to subscribe messengers to watch state changes in thishandler, this also means that observers from other teams can besubscribed.\code// Handler B watches Handler ABHandler A, B;BMessenger messengerA(&A)B.StartWatching(messengerA, kNetworkConnection);\endcode\param target The messenger from which the notifications would be received.\param what The state that needs to be watched.\return During the call of this method, a notification will be transmittedusing the \a target. If this works, then this method will return\c B_OK.\see StartWatchingAll(BMessenger), StopWatching(BMessenger, uint32)\since BeOS R5*//*!\fn status_t BHandler::StartWatchingAll(BMessenger target)\brief Subscribe this handler to watch a \a target for all events.This method performs the same task as StartWatching(BMessenger, uint32),but it will subscribe to all the state changes the \a target knows.\see StartWatching(BMessenger, uint32), StopWatchingAll(BMessenger)\since BeOS R5*//*!\fn status_t BHandler::StopWatching(BMessenger target, uint32 what)\brief Unsubscribe this handler from watching a specific state.This method will unsubscribe this handler from watching a specific eventin a \a target.\see StartWatching(BMessenger, uint32)\since BeOS R5*//*!\fn status_t BHandler::StopWatchingAll(BMessenger target)\brief Unsubscribe this handler from watching all states.This method will unsubscribe the \a target from watching all state changes.\see StartWatchingAll(BMessenger)\since BeOS R5*//*!\fn status_t BHandler::StartWatching(BHandler* observer, uint32 what)\brief Subscribe an \a observer for a specific state change of this handler.Use this method to subscribe observers to watch this handler. State changesof this handler that match the \a what argument, will be sent.\code// Handler B wants to observe Handler ABHandler A, B;A.StartWatching(&B, kNetworkConnection);\endcodeSince pointers to handlers can onlyexist in the local namespace, have a look atStartWatching(BMessenger, uint32) for inter-team watching.\param observer The observer for this handler.\param what The state that needs to be watched.\return During the call of this method, a notification will be transmittedusing the \a observer. If this works, then this method will return\c B_OK.\see StartWatchingAll(BHandler*), StopWatching(BHandler*, uint32)\since BeOS R5*//*!\fn status_t BHandler::StartWatchingAll(BHandler* observer)\brief Subscribe an \a observer for a all state changes.This method performs the same task as StartWatching(BHandler, uint32),but it will subscribe the \a observer to all the state changes this handlertracks.\see StartWatching(BHandler*, uint32), StopWatchingAll(BHandler*)\since BeOS R5*//*!\fn status_t BHandler::StopWatching(BHandler* handler, uint32 what)\brief Unsubscribe an observer from watching a specific state.This method will unsubscribe the \a handler from watching a specific event.\see StartWatching(BHandler*, uint32)\since BeOS R5*//*!\fn status_t BHandler::StopWatchingAll(BHandler* handler)\brief Unsubscribe an observer from watching all states.This method will unsubscribe the \a handler from watching all state changes.\see StartWatchingAll(BHandler*)\since BeOS R5*///! @}///// State changes //////*!\name Emitting State ChangesIf your handler functions as a state machine, and it has observers (whichsubscribed using the StartWatching() method), you can emit these statechanges.*///! @{/*!\fn void BHandler::SendNotices(uint32 what, const BMessage* notice)\brief Emit a state change to the observers.The actual state (specified by \a what) will not be transmitted. This ismerely for internal bookkeeping. It is not entirely unimaginable that youstill want to inform the observers of what actually took place. You canuse the \a msg to transmit this, and any other data you want. Note thatthe message will be copied and slightly altered: the \c what member of themessage will be \c B_OBSERVER_NOTICE_CHANGE, and the \c what constant youspecified will be stored in the #B_OBSERVE_ORIGINAL_WHAT label.\param what The identifier of the state.\param notice Any data associated with the state change. You retainownership of this data, so make sure you dispose it when you aredone.\since BeOS R5*//*!\fn bool BHandler::IsWatched() const\brief Check if there are any observers watching this handler.\since BeOS R5*///! @}