Derived from: public BArchivable
Declared in: be/app/Handler.h
Library: libbe.so
BHandlers are the objects that respond to messages received in message loops. The class declares a hook function--MessageReceived()--that derived classes must implement to handle expected messages. BLooper's DispatchMessage() function calls MessageReceived() to pass incoming messages from the BLooper to the BHandler.
All messages are entrusted to BHandler objects--even system messages, which are dispatched by calling a message-specific function, not MessageReceived(). These specific functions are declared in classes derived from BHandler--especially BWindow and BView in the Interface Kit and BLooper and BApplication in this kit. For example, the BApplication class declares a ReadyToRun() function to respond to B_READY_TO_RUN messages, and the BView class declares a KeyDown() function to respond to B_KEY_DOWN messages.
All messages that aren't matched to a specific hook function--messages defined by applications rather than the kits--are dispatched by calling MessageReceived().
To be eligible to get messages from a BLooper, a BHandler must be in the BLooper's circle of handlers. At any given time, a BHandler can belong to only one BLooper. BLooper's AddHandler() function is the agent for forming looper-handler associations; a BHandler's Looper() function identifies the BLooper it's currently associated with.
BHandlers that belong to the same BLooper can be chained together in a linked list. The default behavior for MessageReceived() is simply to pass the message to the next handler in the chain. However, system messages are not passed from handler to handler.
When a BHandler is assigned to a BLooper, the BLooper becomes its default next handler. That assignment can be changed by SetNextHandler().
You can designate a target BHandler for most messages. The designation is made when calling BLooper's PostMessage() function or when constructing the BMessenger object that will send the message. Messages that a user drags and drops are targeted to the object (a BView) that controls the part of the window where the message was dropped. The messaging mechanism eventually passes the target BHandler to DispatchMessage(), so that the message can be delivered to its designated destination.
Messages can be filtered before they're dispatched--that is, you can define a function that will look at the message before the target BHandler's hook function is called. The filter function is associated with a BMessageFilter object, which records the criteria for calling the function.
Filters that should apply only to messages targeted to a particular BHandler are assigned to the BHandler by SetFilterList() or AddFilter(). Filters that might apply to any message a BLooper dispatches, regardless of its target, are assigned by the parallel BLooper functions, SetCommonFilterList() and AddCommonFilter(). See those functions and the BMessageFilter class for details.
All BHandler objects respond to the following scripting messages:
Property name: | "Messenger" for a BMessenger object that targets the BHandler | |
Specifiers: | B_DIRECT_SPECIFIER | |
Messages: | B_GET_PROPERTY only | |
Data type: | A BMessenger object (B_MESSENGER_TYPE) | |
Since any object that can respond to any message at all can respond to these requests, there's no need for a suite name; it's the universal suite.
See Scripting , and especially The Universal Suite , for more information.
MessageReceived() | Implemented to handle received messages. |
BHandler(const char *name = NULL) BHandler(BMessage *archive)
Initializes the BHandler by assigning it a name and registering it with the messaging system. Because BHandlers are archivable objects, they can also be reconstructed from a BMessage archive.
virtual ~BHandler(void)
Removes the BHandler's registration, frees the memory allocated for its name, and gets rid of any BMessageFilters assigned to the BHandler and the BList object that holds them.
static BHandler *Instantiate(BMessage *archive)
Returns a new BHandler object, allocated by new and created with the version of the constructor that takes a BMessage archive. However, if the archive doesn't contain data for a BHandler of some kind, this function returns NULL.
See also: BArchivable::Instantiate(), instantiate_object(), Archive()
virtual status_t Archive(BMessage *archive, bool deep = true) const
Archives the BHandler by writing its name, if any, to the BMessage archive.
See also: BArchivable::Archive(), Instantiate() static function
virtual status_t GetSupportedSuites(BMessage *message)
Implemented by derived classes to report the suites of messages and specifiers they understand. This function is called in response to a B_GET_SUPPORTED_SUITES BMessage delivered to the BHandler.
A suite is identified by a MIME subtype for the type suite. For example, a BView object identifies the set of messages it can handle by "suite/vnd.Beview" and a BControl identifies its set by "suite/vnd.Becontrol".
The message that's passed as an argument will eventually be sent as a reply to the B_GET_SUPPORTED_SUITES request. Each derived class should place the names of all suites it implements in the message, then pass the message to its base class. The suite names should be placed in a data field named "suites" as B_STRING_TYPE items. For example:
status_t MyHandler::GetSupportedSuites(BMessage *message) { status_t err; err = message->AddString("suites", "suite/vnd.Me-my_handler"); if ( err ) return err; return inherited::GetSupportedSuites(message); }
The return value is added to the message as a B_INT32_TYPE value in a field named "error". BHandler's version of the function simply returns B_OK.
See also: Suites
BLooper *Looper(void) const
Returns the BLooper object that the BHandler is associated with, or NULL if it's not associated with any BLooper. A BHandler must be associated with a BLooper before the BLooper can call upon it to handle messages it dispatches. (However, strictly speaking, this restriction is imposed when the message is posted or when the BMessenger that will send it is constructed, rather than when it's dispatched.)
BLooper objects are automatically associated with themselves; they can act as handlers only for messages that they receive in their own message loops. All other BHandlers must be explicitly tied to a particular BLooper by calling that BLooper's AddHandler() function. A BHandler can be associated with only one BLooper at a time.
In the Interface Kit, when a BView is added to a window's view hierarchy, it's also added as a BHandler to the BWindow object.
See also: BLooper::AddHandler(), BLooper::PostMessage(), the BMessenger constructor
virtual void MessageReceived(BMessage *message)
Implemented by derived classes to respond to messages that are dispatched to the BHandler. The default (BHandler) implementation of this function responds only to scripting requests. It passes all other messages to the next handler by calling that object's version of MessageReceived().
You must implement MessageReceived() to handle the variety of messages that might be dispatched to the BHandler. It can distinguish between messages by the value recorded in the what data member of the BMessage object. For example:
void MyHandler::MessageReceived(BMessage *message) { switch ( message->what ) { case COMMAND_ONE: . . . break; case COMMAND_TWO: . . . break; case COMMAND_THREE: . . . break; default: inherited::MessageReceived(message); break; . . . } }
When defining a version of MessageReceived(), you must incorporate the inherited version as well, as shown in the example above. This ensures that:
If the message comes to the end of the line--if it's not recognized and there is no next handler--the BHandler version of this function sends a B_MESSAGE_NOT_UNDERSTOOD reply to notify the message source.
See also: SetNextHandler(), BLooper::PostMessage(), BLooper::DispatchMessage(), GetSupportedSuites()
virtual BHandler *ResolveSpecifier(BMessage *message, int32 index, BMessage *specifier, int32 what, const char *property)
Implemented by derived classes to determine the proper handler for a BMessage that has specifiers. The message is targeted to the BHandler, but the specifiers may indicate that it should be assigned to another object. It's the job of ResolveSpecifier() to examine at least one specifier, more if necessary, and return the object that should handle the message or look at the next specifier. This function is called before the message is dispatched and before any filtering functions are called.
The BMessage that is about to be dispatched is passed to ResolveSpecifier() as the first argument, message. The next two arguments detail the specifier that is next in line to be resolved (the current specifier)--index is its position in the "specifiers" field in the BMessage and specifier is the specifier message itself. The final two arguments extract information from the specifier--what is its what data member and property is the property name in the specifier message.
The what argument will let you know whether you need to look inside the specifier for more information and what information to look for. For example, if what is B_NAME_SPECIFIER, the specifier BMessage should have a name in a field called "name". If it's B_RANGE_SPECIFIER, it should have "index" and "range" fields. See AddSpecifier() in the BMessage class for a discussion of specifier contents.
ResolveSpecifier() has four options:
if ( (strcmp(property, "Proxy") == 0) && (what == B_INDEX_SPECIFIER) ) { int32 i; if ( specifier->FindInt32("index", &i) == B_OK ) { MyProxy *proxy = (MyProxy *)proxyList->ItemAt(i); if ( proxy ) { message->PopSpecifier(); if ( proxy->Looper() != Looper() ) { proxy->Looper()->PostMessage(message, proxy); return NULL; } } . . . } . . . }
Since this function resolved the specifier at index, it calls PopSpecifier() to decrement the index before forwarding the message. Otherwise, the next handler would try to resolve the same specifier. |
if ( proxy ) { message->PopSpecifier(); if ( proxy->Looper() != Looper() ) { proxy->Looper()->PostMessage(message, proxy); return NULL; } else { return proxy; } }
This, in effect, puts the returned object in the BHandler's place as the designated handler for the message. The BLooper will give the returned handler a chance to respond to the message or resolve the next specifier.
| ||
Again, PopSpecifier() should be called so that an attempt isn't made to resolve the same specifier twice. |
if ( (strcmp(property, "Value") == 0) && (message->what == B_GET_PROPERTY) ) return this;
This confirms the BHandler as the message target. ResolveSpecifier() won't be called again, so it's not necessary to call PopSpecifier() before returning. |
return inherited:ResolveSpecifier(message, index, specifier, what, property);
The BApplication object takes the first path when it resolves a specifier for a "Window" property; it sends the message to the specified BWindow and returns NULL. A BWindow follows the second path when it resolves a specifier for a "View" property; it returns the specified BView. Thus, a message initially targeted to the BApplication object can find its way to a BView.
BHandler's version of ResolveSpecifier() recognizes a B_GET_PROPERTY message with a direct specifier requesting a "Messenger" for the BHandler or the BHandler's "InternalName" (the same name that its Name() function returns). In both cases, it assigns the BHandler (this) as the object responsible for the message.
For all other specifiers and messages, it sends a B_MESSAGE_NOT_UNDERSTOOD reply and returns NULL. The reply message has an "error" field with B_SCRIPT_SYNTAX as the error and a "message" field with a longer textual explanation of the error.
See also: BMessage::AddSpecifier(), BMessage::GetCurrentSpecifier()
virtual void SetFilterList(BList *list) BList *FilterList(void) const virtual void AddFilter(BMessageFilter *filter) virtual bool RemoveFilter(BMessageFilter *filter)
These functions manage a list of BMessageFilter objects associated with the BHandler.
SetFilterList() assigns the BHandler a new list of filters; the list must contain pointers to instances of the BMessageFilter class or to instances of classes that derive from BMessageFilter. The new list replaces any list of filters previously assigned. All objects in the previous list are deleted, as is the BList that contains them. If list is NULL, the current list is removed without a replacement. FilterList() returns the current list of filters.
AddFilter() adds a filter to the end of the BHandler's list of filters. It creates the BList object if it doesn't already exist. By default, BHandlers don't maintain a BList of filters until one is assigned or the first BMessageFilter is added. RemoveFilter() removes a filter from the list without deleting it. It returns true if successful, and false if it can't find the specified filter in the list (or the list doesn't exist). It leaves the BList in place even after removing the last filter.
For SetFilterList(), AddFilter(), and RemoveFilter() to work, the BHandler must be assigned to a BLooper object and the BLooper must be locked.
See also: BLooper::SetCommonFilterList(), BLooper::Lock(), the BMessageFilter class
void SetName(const char *string) const char *Name(void) const
These functions set and return the name that identifies the BHandler. The name is originally set by the constructor. SetName() assigns the BHandler a new name, and Name() returns the current name. The string returned by Name() belongs to the BHandler object; it shouldn't be altered or freed.
See also: the BHandler constructor, BView::FindView() in the Interface Kit
void SetNextHandler(BHandler *handler) BHandler *NextHandler(void) const
These functions set and return the BHandler object that's linked to this BHandler. By default, the MessageReceived() function passes any messages that a BHandler can't understand to its next handler.
When a BHandler object is added to a BLooper (by BLooper's AddHandler() function), the BLooper becomes its next handler by default. BLoopers don't have a next handler.
However, when a BView object is added to a view hierarchy (by AddChild()), the Interface Kit assigns the BView's parent as its next handler--unless the parent is the window's top view, in which case the BWindow object becomes its next handler. The handler chain for BViews is therefore BView to BView, up the view hierarchy, to the BWindow object.
SetNextHandler() can alter any of these default assignments. For it to work, the BHandler must belong to a BLooper object, its prospective next handler must belong to the same BLooper, and the BLooper must be locked.
See also: MessageReceived(), BLooper::AddHandler()
The Be Book, in lovely HTML, for the BeOS Preview Release.
Copyright © 1997 Be, Inc. All rights reserved.
Be is a registered trademark; BeOS, BeBox, BeWare, GeekPort, the Be logo, and the BeOS logo are trademarks of Be, Inc.
Last modified September 18, 1997.