The BApplication
class, the most important
BLooper
subclass, bends the above description in one of two ways:
A
BApplication
takes over the main thread, it doesn't spawn a new one.You do have to delete
be_app
; you can't justQuit()
it.
A BLooper
object creates a "message loop"
that receives messages that are sent or posted to the
BLooper
. The message loop runs in a separate thread
that's spawned (and told to run) when the BLooper
receives a Run()
call. If you're
creating your own BLooper
, you can invoke Run()
from within the
constructor.
You tell the loop to stop by sending the BLooper
a
B_QUIT_REQUESTED
message, which invokes the object's
Quit()
function. You can also call Quit()
directly, but
you have to Lock()
the object
first (BLooper
locking is explained later). Quit()
deletes the
BLooper
for you.
The BApplication
class, the most important
BLooper
subclass, bends the above description in one of two ways:
A BApplication
takes over the main thread, it doesn't spawn a new one.
You do have to delete be_app
; you can't just Quit()
it.
You can deliver messages to a BLooper
's thread by…
Posting them directly by calling BLooper
's PostMessage()
function.
Sending them through
BMessenger
's
SendMessage()
or
BMessage
's
SendReply()
function.
As messages arrive, they're added to the BLooper
's
BMessageQueue
object. The
BLooper
takes messages from the queue in the order that they arrived, and calls
DispatchMessage()
for each one.
DispatchMessage()
locks the
BLooper
and then hands the message to a
BHandler
object by invoking the handler's
MessageReceived()
function. But which BHandler
does the
BLooper
hand the message to? Here's the path:
If an incoming message targets a specific
BHandler
,
and if that BHandler
is one of the BLooper
's eligible handlers (as set through the
AddHandler()
function), the BLooper
uses that
BHandler
. (See the
BMessage
and
BMessenger
classes
for instructions on how to target a BHandler
.)
Otherwise it hands the message to its preferred handler, as set through
SetPreferredHandler()
.
If no preferred handler is set, the BLooper
itself
handles the message (its own implementation of MessageReceived()
is invoked).
After the handler is finished (when its MessageReceived()
returns), the BMessage
is automatically
deleted and the BLooper
is unlocked.
Access to many BLooper
functions (and some BHandler
functions) is
proteced by a lock. To invoke a lock-protected functions (or groups of
functions), you must first call Lock()
, and then
call Unlock()
when you're done. The lock is scoped to the calling thread: Lock()
/Unlock()
calls can
be nested within the thread. Keep in mind that each Lock()
must balanced
by an Unlock()
.
The BLooper
constructor automatically locks the
object. It's unlocked when Run()
is invoked.
This means that the Run()
function and
any other lock-protected functions that you call before you call Run()
must be called
from the thread that constructed the BLooper
.
Because they delete themselves when told to quit,
BLooper
s can't be allocated on the stack; you have
to construct them with new
.