Do not delete the argument message when you're done with. It doesn't belong to you.
| Class Overview |
BHandler(const char* name = NULL);
BHandler(BMessage* archive);
Initializes the BHandler
by assigning it a name
and registering it with the messaging system. BHandler
s can also
be reconstructed from a BMessage
archive
.
virtual void MessageReceived(BMessage* message);
Implemented by derived classes to respond to messages that are received by
the BHandler
. The default
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()
.
A typical MessageReceived()
implementation distinguishes
between messages by looking at its command constant (i.e. the
what
field). For example:
voidMyHandler
::MessageReceived
(BMessage
*message
) { switch (message
->what
) { caseCOMMAND_ONE
:HandleCommandOne
(); break; caseCOMMAND_TWO
:HandleCommandTwo
(); break; ... default:baseClass
::MessageReceived
(message
); break; ... } }
It's essential that all unhandled messages are passed to the base class
implementation of |
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.
Do not delete the argument message when you're done with. It doesn't belong to you.
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_tMyHandler
::GetSupportedSuites
(BMessage*message
) {message
->AddString
("suites", "suite/vnd.Me-my_handler"));BPropertyInfo
prop_info
(prop_list
);message
->AddFlat
("messages",prop_info
); returnBHandler
::GetSupportedSuites
(message
); }
The value returned by GetSupportedSuites()
is added
to message
in the int32
be:error
field.
BHandler
's version
of this function adds the universal suite "suite/vnd.Be-handler"
to message
then returns B_OK
.
bool LockLooper();
status_t LockLooperWithTimeout(bigtime_t timeout);
void UnlockLooper();
These are "smart" versions of BLooper
's locking functions
(BLooper::Lock()
et.
al.). The difference between the versions is that these functions retrieve
the handler's looper and lock it (or unlock it) in a pseudo-atomic
operation, thus avoiding a race condition. Anytime you're tempted to write
code such as this:
/* DON'T DO THIS */ if (myHandler
->Looper
()->Lock
()) { ...myHandler
->Looper()
->Unlock
(); }
Don't do it. Instead, do this:
/* DO THIS INSTEAD */ if (myHandler
->LockLooper
()) { ...myHandler
->UnlockLooper
(); }
Except for an additional return value in
LockLooperWithTimeout()
, these functions are
identical to their BLooper
analogues. See
BLooper::Lock()
for details.
LockLooper()
returns true
if
it was able to lock the looper, or if it's already locked by the calling
thread, and false
otherwise. If the handler changes
loopers during the call, false
is returned.
LockLooperWithTimeout()
returns:
Return Code | Description |
---|---|
| The looper was successfully locked. |
| The call timed out without locking the looper. |
| This handler's looper is invalid. |
| The handler switched loopers during the call. |
BLooper* Looper() const;
Returns the BLooper
object that the BHandler
has been added to. The
function returns NULL
if the object hasn't been added
to a BLooper
. A
BHandler
can be associated with only one BLooper
at a time.
Note that a BLooper
object automatically adds itself (as a handler) to itself (as a looper),
and a BWindow
automatically adds its child views. To explicitly add a handler to a
looper, you call BLooper::AddHandler()
.
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 targetted property.
ResolveSpecifier()
returns a pointer to the next
BHandler
that should look at the message. To
identify the BHandler
, it tries these methods, in
order:
If the
specifier
identifies a
BHandler
belonging to another BLooper
, it should send the
message
to the BLooper
and return
NULL
. The message will be handled in the message loop
of the other BLooper
;
it won't be further processed in this one. For example, a
BHandler
that kept a list of proxies might use code
like the following:
if ( (strcmp
(property
, "Proxy") == 0) && (what
==B_INDEX_SPECIFIER
) ) { int32i
; 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
); returnNULL
; } } . . . } . . . }
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 the specifier
picks out another
BHandler
object belonging to the same BLooper
,
ResolveSpecifier()
can return that
BHandler
. For example:
if (proxy
) {message
->PopSpecifier
(); if (proxy
->Looper
() !=Looper
() ) {proxy
->Looper
()->PostMessage
(message
,proxy
); returnNULL
; } else { returnproxy
; } }
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 it can resolve all remaining
specifiers and recognizes the message as one that the
BHandler
itself can handle, it should return the
BHandler
(this
). For example:
if ( (strcmp
(property
, "Value") == 0) && (message
->what
==B_GET_PROPERTY
) ) returnthis
;
This confirms the BHandler
as the message target.
ResolveSpecifier()
won't be called again, so it's
not necessary to call PopSpecifier()
before returning.
If it doesn't recognize the
property or can't resolve the specifier, it should call (and return the
value returned by) the inherited version of
ResolveSpecifier()
.
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 "Suite" for
the supported suites, "Messenger" for the
BHandler
, or the BHandler
's
"InternalName" (the same name that its
Name()
function returns). In all three 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.
virtual void SetFilterList(BList* list);
BList* FilterList() 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() 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 th
Interface Kit
void SetNextHandler(BHandler* handler);
BHandler* NextHandler() const;
SetNextHandler()
reorders the objects in the
handler chain so that handler
follows this
BHandler
. This BHandler
and
handler
must already be part of the same chain,
and the BLooper
they belong to must be locked. The order of objects in the handler chain
affects the way in-coming messages are handled (as explained in
"Inheritance and the Handler Chain".
By default handlers are placed in the order that they're added (through
BLooper::AddHandler()
).
NextHandler()
returns this object's next handler.
If this object is at the end of the chain, it returns
NULL
.
virtual void SendNotices(uint32 what,
const BMessage
* msg = 0);
Sends a
B_OBSERVER_NOTICE_CHANGE
message to each BHandler
object (or "observer")
that's observing this handler (the "notifier"). To observe
a notifier, the observer calls
StartWatching()
.
The what
argument describes the type of change
that's prompting this notification; only those observers that have
registered to be notified about what (or that are watching all changes)
are sent notifications.
The
B_OBSERVER_NOTICE_CHANGE
messages that are
sent are copied from msg
with the what argument
added as the be:old_what
field. Note that
msg
's original what
field is clobbered.
status_t StartWatching(BMessenger watcher,
uint32 what);
status_t StartWatching(BHandler* watcher,
uint32 what);
status_t StartWatchingAll(BMessenger watcher);
status_t StartWatchingAll(BHandler* watcher);
status_t StopWatching(BMessenger watcher,
uint32 what);
status_t StopWatching(BHandler* watcher,
uint32 what);
status_t StopWatchingAll(BMessenger watcher);
status_t StopWatchingAll(BHandler* watcher);
The BHandler
class provides the concept of a
notifier. Notifiers maintain one or more
states that other entities might want to monitor changes to. These states
are identified by a 32-bit what
code. Another entity
a BHandler
or a BMessenger
can watch for
changes notifiers' states. These are called observers.
StartWatching()
registers the BMessenger
or
BHandler
specified by watcher
to be notified whenever the state specified by what
changes. StartWatchingAll()
registers the
specified BMessenger
or
BHandler
to be notified when any of the notifer's
states change.
StartWatching()
works by sending a message to the
BHandler
you want to observe, with a BMessenger
back to the
observer, so both must be attached to a looper at the time
StartWatching()
is called.
The forms of StartWatching()
and
StartWatchingAll()
that accept a
BHandler
can be used to observe a handler that's not
yet attached to a looper. However, these only work if the observer and
notifier are both in the same looper.
StopWatching()
ceases monitoring of the state
what
. StopWatchingAll()
, by
some odd coincidence, stops all monitoring by the
BHandler
or BMessenger
specified by
watcher
.
Return Code | Description |
---|---|
| No error. |
|
The specified |
Field | Type code | Description |
---|---|---|
_name | B_STRING_TYPE | The object's name (see
SetName() ). |
BHandler
records its own name.
Message | Specifiers | Reply Type |
---|---|---|
B_GET_PROPERTY | B_DIRECT_SPECIFIER | B_STRING_TYPE |
Returns the handler's name.
Message | Specifiers | Reply Type |
---|---|---|
B_GET_PROPERTY | B_DIRECT_SPECIFIER | B_MESSENGER_TYPE |
Returns a BMessenger
for the handler.