BHandler

Derived from: public BArchivable

Declared in: be/app/Handler.h

Library: libbe.so


Overview

[method summary]

A BHandler object responds to messages that are handed to it by a BLooper. The BLooper tells the BHandler about a message by invoking the BHandler's MessageReceived() function.


The Handler List

To be eligible to get messages from a BLooper, a BHandler must be in the BLooper's list of eligible handlers (as explained in the BLooper class). The list of eligible handlers is ordered; if the "first" handler doesn't want to respond to a message that it has received, it simply calls the inherited version of MessageReceived() and the message will automatically be handed to the object's "next" handler. (System messages are not handed down the list.) The BLooper that all these BHandlers belong to is always the last the last handler in the list (BLooper inherits from BHandler).

A BHandler's next handler assignment can be changed through SetNextHandler().


Targets

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.


Filtering

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.


Hook Functions

MessageReceived()
Implemented to handle received messages.


Constructor and Destructor


BHandler()

      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.


~BHandler()

      virtual ~BHandler()

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 Functions


Instantiate()

      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()


Member Functions


AddFilter() see SetFilterList()


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


FilterList() see SetFilterList()


GetSupportedSuites()

      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 either a B_GET_PROPERTIES scripting message for the "Suites" property or a B_GET_SUPPORTED_SUITES message.

Each derived class should add the names of the suites it implements to the "suites" array of message. Each item in the array is a MIME string with the "suite" supertype. In addition, the class should add corresponding flattened BPropertyInfo objects in the "messages" array. A typical implementation of GetSupportedSuites() looks like:

   status_t MyHandler::GetSupportedSuites(BMessage *message)
   {
      message->AddString("suites", "suite/vnd.Me-my_handler"));
      BPropertyInfo prop_info(prop_list);
      message->AddFlat("messages", &prop_info);
      return BHandler::GetSupportedSuites(message);
   }

The value returned by GetSupportedSuites() is added to message in the int32 "error" field. BHandler's version of this function adds the universal suite "suite/vnd.Be-handler" to message then returns B_OK.


LockLooper(), LockLooperWithTimeout(), UnlockLooper()

      bool LockLooper(void) 
      status_t LockLooperWithTimeout(bigtime_t timeout) 
      void UnlockLooper(void) 

Locks or unlocks the looper associated with the object. This avoids a possible race condition in the following:

   window = view->Window();
   if (window->Lock()) {
      ...
      window->Unlock();
   }

The code above assumes the BHandler is still associated with the BLooper when Lock() is called, although that might not be true. In these cases, use LockLooper() and UnlockLooper() instead:

   if (view->LockLooper()) {
      ...
      view->UnlockLooper();
   }

LockLooper() returns true if it successfully locks the BLooper (or if it already has it locked), and false if it was unsuccessful. If the BLooper changed between the start and end of the call, LockLooper() returns false.

LockLooperWithTimeout() lets you set a timeout during which the associated BLooper will block while waiting for the lock. If the timeout is 0, the function doesn't block, instead returning immediately with or without the lock. If the timeout is B_INFINITE_TIMEOUT, it blocks without limit, just as LockLooper() does.

LockLooperWithTimeout() returns B_OK if it successfully locks the BLooper (or if it already has it locked), B_TIMED_OUT if it times out, B_BAD_VALUE if the BLooper is invalid, or B_MISMATCHED_VALUES if the associated BLooper changed between the start and end of the call (i.e. the race condition cited above).

See also: BLooper::Lock()


LockLooperWithTimeout() see LockLooper()


Looper()

      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


MessageReceived()

      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:
           BHandler::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()


Name() see SetName()


NextHandler() see SetNextHandler()


ResolveSpecifier()

      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 scripting message. 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 the current specifier (or more, if necessary) and return the object that should either 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 first argument, message, points to the scripting message under consideration. The current specifier is passed in specifier; it will be at index index in the specifier array of message. Finally, what contains the what data member of specifier while property contains the name of the targeted property.

If the current BHandler is able to handle the scripting message, it should return a pointer to itself (this). If a BHandler in another BLooper is the target, it should send the message to the BLooper and return NULL. This causes the current BLooper to stop further processing of the message. Otherwise, the function should return a pointer to the BHandler that should handle the message, if no specifiers remain, or look at the next specifier, if any exist. Often, ResolveSpecifier() calls PopSpecifier() before returning so the next BHandler won't examine the same specifier.

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.

For more information about this function and scripting in general, see the "Scripting" section near the beginning of this chapter.

See also: BMessage::AddSpecifier(), BMessage::GetCurrentSpecifier()


SetFilterList(), FilterList(), AddFilter(), RemoveFilter()

      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


SetName(), Name()

      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


SetNextHandler(), NextHandler()

      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. For example, the handler chain for BViews works up the view hierarchy and stops at 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()


UnlockLooper() see LockLooper()


Scripting Support

The BHandler class implements the suite called "suite/vnd.Be-handler" consisting of the following messages:


The InternalName Property

Message Specifiers Meaning
B_GET_PROPERTY B_DIRECT_SPECIFIER Returns the name of the BHandler.


The Messenger Property

Message Specifiers Meaning
B_GET_PROPERTY B_DIRECT_SPECIFIER Returns a BMessenger that targets the BHandler.


The Suites Property

Message Specifiers Meaning
B_GET_PROPERTY B_DIRECT_SPECIFIER Returns an array of the suites supported by the object.






The Be Book, in lovely HTML, for BeOS Release 4.

Copyright © 1998 Be, Inc. All rights reserved.

Last modified December 23, 1998.