hide random home http://www.be.com/documentation/be_book/app/Looper.html (Amiga Plus Extra No. 5/97, 05/1997)


The Application Kit: BLooper

Derived from: public BHandler

Declared in: <app/Looper.h>


Overview

A BLooper object runs a message loop in a thread that it spawns for that purpose. It's a simple way to create a thread with a message interface.

Various classes in the Be software kits derive from BLooper in order to associate threads with significant entities in the application and to set up message loops with special handling for system messages. In the Application Kit, the BApplication object runs a message loop in the application's main thread. (Unlike other BLoopers, the BApplication object doesn't spawn a separate thread, but takes over the thread in which the application was launched.) In the Interface Kit, each BWindow object runs a loop to handle messages that report activity in the user interface.


Running the Loop

Constructing a BLooper object gets it ready to work, but doesn't actually begin the message loop. Its Run() function must be called to spawn the thread and initiate the loop. Some derived classes may choose to call Run() within the class constructor,

   MyLooper::MyLooper(const char *name, long priority)
           : BLooper(name, priority)
   {
       . . .
       Run();
   }

so that simply constructing the object yields a fully functioning message loop. Other classes may need to keep object initialization separate from loop initiation. (The BApplication and BWindow classes maintain this separation. An application must explicitly call Run() after constructing the BApplication object; a BWindow calls Run() for you just before putting the window on-screen for the first time.)


Receiving and Dispatching Messages

You can deliver messages to a BLooper's thread by posting them directly (calling its PostMessage() function) or by sending them through a proxy object (calling a BMessenger's SendMessage() function or the SendReply() function of a BMessage object). In addition, drag-and-drop operations deliver messages to the threads of the destination windows.

No matter how they get there, all messages are delivered to a port owned by the BLooper object. The BLooper transfers arriving messages from the port to a queue (a BMessageQueue object) as soon as it can. The port doesn't offer much flexibility as a data container and its capacity is fixed (typically 100 slots); the queue is more flexible and has unlimited capacity.

The BLooper takes messages from the queue one at a time, in the order that they arrive, and calls DispatchMessage() for each one. DispatchMessage() hands the message to a BHandler object; the BHandler kicks off the thread's specific response to the message.

Posting or sending a message to a thread initiates activity within that thread, beginning with the DispatchMessage() function. Since DispatchMessage() immediately transfers responsibility for incoming messages to BHandler objects, BHandlers determine what happens in the BLooper's thread. Everything that the thread does, it does through BHandlers responding to messages. The BLooper merely runs the posting and dispatching mechanism.

The BLooper object is locked when DispatchMessage() is called; it stays locked until the thread has finished responding to the message.


Targeted and Preferred Handlers

When a message is posted or sent to a thread, a target BHandler can be named for it. The target is specified when PostMessage() is called or when the BMessenger proxy that will send the message is constructed. Messages that aren't targeted to a specific object are entrusted to the BLooper's preferred handler--the object that was last set as the default handler for the thread. The preferred handler can change from time to time depending on circumstances. (For example, a BWindow sets its preferred handler to match its current focus view.)

Because the BLooper class inherits from BHandler, a BLooper can be named as the target for messages it dispatches; a BLooper object can play both roles--the dispatcher role of running the message loop and the handler role of responding to messages. In fact, a BLooper is its own default preferred handler (technically, it's the handler of choice when there's no specific target and the preferred handler is NULL, but it amounts to the same thing).

For it to successfully handle messages you define, you must derive a class from BLooper and implement a MessageReceived() function that can respond to the messages it dispatches to itself. However, the BLooper class can also be used without change, as it's defined in the kit--as long as all messages are targeted to another handler, or another object is designated as its preferred handler.


Eligible Handlers

A BLooper keeps a list of the BHandler objects that are eligible for the messages it dispatches. AddHandler() places a BHandler in the list, and RemoveHandler() removes it. (The BLooper is an automatic member of the list; it cannot be removed from its own list or added to the list of another BLooper.)

A BHandler can be associated with only one BLooper at a time; it can't get messages dispatched by any BLooper except the one it's currently affiliated with. However, this eligibility constraint is imposed not by DispatchMessage(), but by the BMessenger constructor when a target BHandler is named for the messages it will send and by PostMessage() when a BHandler is proposed as the target of a message posted to the BLooper.

The BLooper reveals the membership of its handlers list through its HandlerAt() function. A BHandler's Looper() function reveals which BLooper it currently belongs to.


Hook Functions

DispatchMessage() Passes incoming messages to a BHandler; can be overridden to change the way certain messages or classes of messages are dispatched.
QuitRequested() Can be implemented to decide whether a request to terminate the message loop and destroy the BLooper should be honored or not.


Constructor and Destructor


BLooper()


      BLooper(const char *name = NULL,
         int32 priority = B_NORMAL_PRIORITY, 
         int32 portCapacity = 
               B_LOOPER_PORT_DEFAULT_CAPACITY) 
      BLooper(BMessage *archive) 

Assigns the BLooper object a name and sets up the port at which it will receive messages and the message queue where messages will reside until they're dispatched. However, you must call Run() to spawn the thread that the BLooper will oversee; the constructor doesn't do it.Run() creates the thread at the specified priority level and begins the message loop.

The priority determines how much attention the thread will receive from the scheduler and, consequently, how much CPU time it will get relative to other threads. It's best to choose one of the discrete priority levels defined in kernel/OS.h; intermediate priorities are possible but not recommended. The defined priorities, from lowest to highest, are:

B_LOW_PRIORITY For threads running in the background that shouldn't interrupt other threads.
B_NORMAL_PRIORITY For all ordinary threads, including the main thread.
B_DISPLAY_PRIORITY For threads associated with objects in the user interface, including window threads.
B_URGENT_DISPLAY_PRIORITY For interface threads that deserve more attention than ordinary windows.
B_REAL_TIME_DISPLAY_PRIORITY For threads that animate the on-screen display.
B_URGENT_PRIORITY For threads performing time-critical computations.
B_REAL_TIME_PRIORITY For threads controlling real-time processes that need unfettered access to the CPUs.

Some derived classes may want to call Run() in the constructor, so that the object is set in motion at the time it's created.

A BLooper is constructed in a locked state and must be locked when Run() is called. Run() unlocks the BLooper to begin message processing, but locks it again for each dispatched message.

BLooper objects should always be dynamically allocated (with new), never statically allocated on the stack.

See also: Run(), BHandler::SetName()


~BLooper()


      virtual ~BLooper(void)

Gets rid of the BLooper's port and all its contents, frees the message queue and all pending messages, stops the message loop, and destroys the thread in which it ran. BHandlers that have been added to the BLooper are not deleted, but BMessageFilter objects added as common filters are, as is the BList object that contains them.

With the exception of the BApplication object, BLoopers should be destroyed by calling the Quit() function (or QuitRequested()), not by using the delete operator.

See also: Quit()


Static Functions


Instantiate()


      static BLooper *Instantiate(BMessage *archive) 

Returns a new BLooper object, allocated by new and created with the version of the constructor that takes a BMessage archive. However, if the archive message doesn't contain data for a BLooper object, this function returns NULL.

See also: BArchivable::Instantiate(), instantiate_object(), Archive()


LooperForThread()


      static BLooper *LooperForThread(thread_id thread)

Returns the BLooper object that runs a message loop in the specified thread, or NULL if the thread doesn't belong to a BLooper.

This function is useful in lower-level code to find whether the code is excecuting in a BLooper's thread and might possibly, therefore, be tying up the message loop and interferring with the responsiveness of the BLooper. For example:

   BLooper *looper;
   if ( looper = LooperForThread(find_thread(NULL) )
       . . .


Member Functions


AddCommonFilter() see SetCommonFilterList()


AddHandler(), RemoveHandler(), HandlerAt(), CountHandlers(), IndexOf()


      void AddHandler(BHandler *handler)

      bool RemoveHandler(BHandler *handler)

      BHandler *HandlerAt(int32 index) const

      int32 CountHandlers(void) const

      int32 IndexOf(BHandler *handler) const

AddHandler() adds handler to the BLooper's list of BHandler objects, and RemoveHandler() removes it. Only BHandlers that have been added to the list are eligible to respond to the messages the BLooper dispatches. (However, this constraint is imposed not by DispatchMessage(), but by PostMessage() and the BMessenger constructor.)

AddHandler() fails if the handler already belongs to a BLooper; a BHandler can belong to no more than one BLooper at a time. It can change its affiliation from time to time, but must be removed from one BLooper before it can be added to another. RemoveHandler() returns true if it succeeds in removing the BHandler from the BLooper, and false if not or if the handler doesn't belong to the BLooper in the first place.

AddHandler() also calls the handler's SetNextHandler() function to assign it the BLooper as its default next handler. RemoveHandler() calls the same function to set the handler's next handler to NULL.

HandlerAt() returns the BHandler object currently located at index in the BLooper's list of eligible handlers, or NULL if the index is out of range. Indices begin at 0 and there are no gaps in the list. CountHandlers() returns the number of objects currently in the list; the count should always be at least 1, since the list automatically includes the BLooper itself. IndexOf() returns the index of the specified handler, or B_ERROR if that object isn't in the list.

For any of these functions to work, the BLooper must be locked.

See also: BHandler::Looper(), BHandler::SetNextHandler(), PostMessage(), the BMessenger class


Archive()


      virtual status_t Archive(BMessage *archive, bool deep = true) const

Archives the BLooper by recording the priority of its thread and the capacity of its port in the BMessage archive passed as an argument.

See also: BArchivable::Archive(), Instantiate() static function


CommonFilterList() see SetCommonFilterList()


CountHandlers() see AddHandler()


CurrentMessage()


      BMessage *CurrentMessage(void) const

Returns a pointer to the message that the BLooper's thread is currently processing, or NULL if it's currently between messages.

You won't always need this function, since the current message is also passed as an argument to BHandler's MessageReceived() hook function. However, the hook functions that respond to system messages (such as MouseDown() and ScreenChanged()) are typically passed only part of the information contained in the current BMessage, not the entire object. In such a case, you will have to call CurrentMessage() to get complete information about the instruction or event the BMessage object reports.

For example, a KeyDown() function (declared in the BView class of the Interface Kit) might check whether the Control key was pressed at the time of the key-down event as follows:

   void MyView::KeyDown(const char *bytes, int32 numBytes)
   {
       BMessage *message = Window()->CurrentMessage();
       if ( message->FindLong("modifiers") & B_CONTROL_KEY ) {
           . . .
       }
       . . .
   }

See also: BHandler::MessageReceived(), DetachCurrentMessage()


DetachCurrentMessage()


      BMessage *DetachCurrentMessage(void)

Detaches the current message (the message the BLooper's thread is currently processing) from the message loop and returns it, or returns NULL if the BLooper is between messages. Detaching the message means that:

Since the message won't be deleted automatically, you have time to reply to it later. However, if the thread that initiated the message is blocked waiting for a reply, you should send one (or get rid of the BMessage) without much delay. If a reply hasn't already been sent by the time the message is deleted, the BMessage destructor sends back a default B_NO_REPLY message to indicate that a real reply won't be forthcoming. But if the message isn't deleted and a reply isn't sent, the initiating thread may continue to block. (BMessage's IsSourceWaiting() function will let you know whether the message source is waiting for a reply.)

Detaching a message is useful only when you want to stretch out your response to it beyond the end of the message cycle, perhaps passing responsibility for it to another thread while the BLooper's thread continues to get and respond to other messages.

See also: BHandler::MessageReceived(), BMessage::WasDelivered(), CurrentMessage()


DispatchMessage()


      virtual void DispatchMessage(BMessage *message, BHandler *target)

Dispatches messages as they're received by the BLooper's thread. Precisely how they're dispatched depends on the message and the designated target BHandler. The BWindow and BApplication classes that derive from BLooper implement their own versions of this function to provide for special dispatching of system messages. Each class defines its own set of such messages.

The target may be the BHandler object that was named when the message was posted, the handler that was specified when the BMessenger was constructed, the current preferred handler, the handler that was designated as the target for a reply message, or (for a BWindow) the BView where the message was dropped. It might be the BLooper itself, acting as a specific target or in its capacity as the default preferred handler. For system messages the target may be NULL; if so, the dispatcher must figure out a target for the message based on the contents of the BMessage object.

DispatchMessage() is the first stop in the message-handling mechanism. The BLooper's thread calls it automatically as it reads messages from the queue--you never call it yourself.

BLooper's version of DispatchMessage() dispatches B_QUIT_REQUESTED messages by calling its own QuitRequested() function, but only if the message is targeted to the BLooper itself. All other messages are forwarded to the target's MessageReceived() function. The BApplication and BWindow classes add other kinds of message-specific dispatching.

You can override this function to dispatch the messages that your own application defines or recognizes. Of course, you can also just wait for these messages to fall through to MessageReceived()--the choice is yours. If you do override DispatchMessage(), you should:

For example:

   void MyLooper::DispatchMessage(BMessage *msg, BHandler *target)
   {
       switch ( msg->what ) {
       case MY_MESSAGE1:
           . . .
           break; 
       case MY_MESSAGE2:
           . . .
           break; 
       default:
           inherited::DispatchMessage(msg, target);
           break;
       }
   }

Don't delete the messages you handle when you're through with them; they're deleted for you.

The system locks the BLooper before calling DispatchMessage() and keeps it locked for the duration of the thread's response to the message (until DispatchMessage() returns).

See also: the BMessage class, BHandler::MessageReceived(), QuitRequested()


HandlerAt() see AddHandler()


IndexOf() see AddHandler()


IsLocked() see LockingThread()


Lock(), LockWithTimeout(), Unlock()


      bool Lock(void)

      status_t LockWithTimeout(bigtime_t timeout)

      void Unlock(void)

These functions provide a mechanism for locking data associated with the BLooper, so that a thread can't alter the data while another thread is in the middle of doing something that depends on it. Only one thread can have the BLooper locked at any given time. Lock() blocks until it can lock the object, then returns true. If the calling thread already has the object locked, it returns true immediately. If another thread has the BLooper locked, it waits until that thread releases the lock and it can acquire it; it then returns true. It returns false only if the BLooper can't be locked at all--for example, if it was destroyed by another thread.

LockWithTimeout() is an alternative to Lock() that permits you to limit how long it should block waiting for the lock. The timeout is specified in microseconds. If it can't acquire the lock before the time limit expires, it returns B_TIMED_OUT. If the timeout is 0, it doesn't block but returns immediately with or without the lock. If the timeout is B_INFINITE_TIMEOUT, it blocks without limit, just as Lock() does.

If it locks the BLooper (or if the calling thread already has it locked), LockWithTimeout() returns B_OK. In addition to B_TIMED_OUT, it may also return B_BAD_VALUE if the BLooper has been deleted, is invalid, or was improperly allocated. Each of these failures would cause Lock() to return false.

Note that if Lock() returns 0 (false), it has failed to lock the BLooper, but if LockWithTimeout() returns 0 (B_OK), it has succeeded.

Unlock() releases the lock previously obtained by Lock() or LockWithTimeout(). Only the locking thread should call Unlock(). This is the natural result if it's called in the same section of code to balance a previous Lock() or LockWithTimeout() call, as follows:

   if ( myLooper->Lock() ) {
       myLooper->DoSomethingCritical();
       . . .
       myLooper->Unlock();
   }

Calls to Lock() (or LockWithTimeout()) and Unlock() can be nested. For example, the function that's called within the brace of the lock in the example above can itself call Lock() and Unlock():

   status_t MyLooperClass::DoSomethingCritical(void)
   {
       if ( Lock() ) {
           . . .
           Unlock();
           return B_OK;
       }
       return B_ERROR;
   }

If the locking functions are called more than once from the same thread, it will take an equal number of Unlock() calls from that thread to unlock the BLooper. Only when Unlock() has released the lock at the base level will another thread be permitted to lock the BLooper.

Locking is the basic mechanism for operating safely in a multithreaded environment. It's especially important for the kit classes derived from BLooper--BApplication and BWindow.

However, it's generally not necessary to lock a BLooper when calling functions defined in the class itself or in a derived class. The BLooper is locked for you when:

Moreover, BApplication and BWindow functions are implemented to call Lock() and Unlock() when necessary. Functions you define in classes derived from BLooper (or from BApplication and BWindow) should also call Lock() (or LockWithTimeout()) and Unlock(). In addition, you should employ the locking mechanism when calling functions of a class that's closely associated with a BLooper--for example, when calling functions of a BView that's attached to a BWindow.

Although locking is important and useful, you shouldn't be too cavalier about it. While you hold a BLooper's lock, no other thread can acquire it. If another thread calls a function that tries to lock, the thread will hang until you unlock. Each thread should hold the lock as briefly as possible.

See also: LockingThread(), BMessenger::LockTarget(), the BLocker class in the Support Kit


LockingThread(), IsLocked(), CountLocks(), CountLockRequests(), Sem()


      thread_id LockingThread(void) const

      bool IsLocked(void) const

      int32 CountLocks(void) const

      int32 CountLockRequests(void) const

      sem_id Sem(void) const

These functions may be useful while debugging a BLooper.

LockingThread() returns the thread that currently has the BLooper locked, or -1 if the BLooper isn't locked.

IsLocked() returns true if the calling thread currently has the BLooper locked (if it's the locking thread) and false if not (if some other thread is the locking thread or the BLooper isn't locked).

CountLocks() returns the number of times the locking thread has locked the BLooper--the number of Lock() (or LockWithTimeout()) calls that have not yet been balanced by matching Unlock() calls.

CountLockRequests() returns the number of threads currently trying to lock the BLooper. The count includes the thread that currently has the lock plus all threads currently waiting to acquire it.

Sem() returns the sem_id for the semaphore that the BLooper uses to implement the locking mechanism.

See also: Lock()


MessageReceived()


      virtual void MessageReceived(BMessage *message)

Simply calls the inherited function. For the current release, the BLooper implementation of this function does nothing of importance.

See also: BHandler::MessageReceived()


MessageQueue()


      BMessageQueue *MessageQueue(void) const

Returns the queue that holds messages delivered to the BLooper's thread. You rarely need to examine the message queue directly; it's made available so you can cheat fate by looking ahead.

See also: the BMessageQueue class


PostMessage()


      status_t PostMessage(BMessage *message, BHandler *handler, 
         BHandler *replyHandler = NULL)
      status_t PostMessage(uint32 command, BHandler *handler, 
         BHandler *replyHandler = NULL)
      status_t PostMessage(BMessage *message)
      status_t PostMessage(uint32 command)

Delivers a message to the BLooper, just as constructing a BMessenger and calling SendMessage() would.

If a target handler object is named for the message, it will be passed as the designated handler to DispatchMessage(). DispatchMessage() will, in turn, call an appropriate function of the handler to respond to the message. However, if the target BHandler isn't associated with the BLooper (if the handler's Looper() function returns NULL or some other BLooper object), the posting fails. A BHandler must be associated with a BLooper before it can be the target for dispatched messages; it can't get messages from any other BLooper except the one to which it belongs. For example, BViews in the Interface Kit can receive messages only from the BWindows to which they're attached.

If the handler is NULL, the designated handler will be the BLooper's preferred handler at the time DispatchMessage() is called.

For the versions of PostMessage() that take a single argument and don't allow you to designate a handler, the handler will be the BLooper object. These shorthand functions may not be supported in the future. It's better programming practice to name the BLooper explicitly as the target handler.

Replies to the posted message will be delivered to the replyHandler BHandler. Like the target handler, this object must belong to a BLooper (not necessarily this BLooper) or be a BLooper itself. If a replyHandler isn't specified, replies will be delivered to the BApplication object.

The caller retains ownership of the posted message; it's safe to delete it when PostMessage() returns.

If a command is passed rather than a message, PostMessage() creates a BMessage object, initializes its what data member to command, and posts it. This simply saves you the step of constructing a BMessage when it won't contain any data. For example, this code

   myWindow->PostMessage(command, handler);

is equivalent to:

   BMessage message(command);
   myWindow->PostMessage(&message, handler);

PostMessage() returns B_OK if successful, B_MISMATCHED_VALUES if the posting fails because the proposed target BHandler doesn't belong to the BLooper, and B_ERROR, B_BAD_PORT_ID, or some other error if it fails because the BLooper is invalid or corrupted.

See also: BHandler::Looper(), DispatchMessage()


PreferredHandler() see SetPreferredHandler()


Quit()


      virtual void Quit(void)

Closes down the BLooper, if it's locked. This function fails if the BLooper isn't locked.

If Run() hasn't been called yet, Quit() just deletes the BLooper object. But if Run() has been called, it exits the message loop, frees the message queue, kills the thread, and then deletes the BLooper object.

When Quit() is called from the BLooper's thread, all this happens immediately. Any pending messages are ignored and destroyed. Because the thread dies, Quit() doesn't return.

However, when called from another thread, Quit() waits until all previously posted messages (all messages already in the queue) work their way through the message loop and are handled. It then destroys the BLooper and returns only after the loop, queue, thread, and object no longer exist.

Quit() therefore terminates the BLooper synchronously; when it returns, you know that everything has been destroyed. To quit the BLooper asynchronously, you can post a B_QUIT_REQUESTED message to the thread (that is, a BMessage with B_QUIT_REQUESTED as its what data member). PostMessage() places the message in the queue and returns immediately.

When it gets a B_QUIT_REQUESTED message, the BLooper calls the QuitRequested() virtual function. If QuitRequested() returns true, as it does by default, it then calls Quit().

See also: QuitRequested()


QuitRequested()


      virtual bool QuitRequested(void)

Implemented by derived classes to determine whether the BLooper should quit when requested to do so. The BLooper calls this function to respond to B_QUIT_REQUESTED messages. If it returns true, the BLooper calls Quit() to exit the message loop, kill the thread, and delete itself. If it returns false, the request is denied and no further action is taken.

BLooper's default implementation of QuitRequested() always returns true.

A request to quit that's delivered to the BApplication object is, in fact, a request to quit the entire application, not just one thread. BApplication therefore overrides QuitRequested() to pass the request on to each window thread before shutting down.

For BWindow objects in the Interface Kit, a request to quit might come from the user clicking the window's close button (a quit-requested event for the window), from the user's decision to quit the application (a quit-requested event for the application), from a Close menu item, or from some other occurrence that forces the window to close.

Classes derived from BWindow typically implement QuitRequested() to give the user a chance to save documents before the window is destroyed, or to cancel the request.

If a BWindow represents the last window the application has open (or the last one that gives the user access to menus and the ability to continue doing work), closing the window is tantamount to quitting the application. In this case, QuitRequested() should make sure the application quits by passing the request along to the BApplication object. For example

   bool MyWindow::QuitRequested()
   {
       . . .
       if ( myDocuments <= 1 )
           be_app->PostMessage(B_QUIT_REQUESTED, be_app);
       return true;
   }

After asking the application to quit, QuitRequested() returns true to immediately dispose of the window. If it returns false, BApplication's version of the function will again request the window to quit.

If you call QuitRequested() from your own code, be sure to also provide the code that calls Quit():

   if ( myLooper->QuitRequested() )
       myLooper->Quit();

See also: BApplication::QuitRequested(), Quit()


RemoveCommonFilter() see SetCommonFilterList()


Run()


      virtual thread_id Run(void)

Spawns a thread at the priority level that was specified when the BLooper was constructed and begins running a message loop in that thread. If successful, this function returns the thread identifier. If unsuccessful, it returns B_NO_MORE_THREADS or B_NO_MEMORY to indicate why.

Run() expects the BLooper to be locked when it's called--and to be locked just once. Since a BLooper is locked on construction, you should not lock it again before calling Run(). Run() will unlock the BLooper, but make sure that it's locked while the thread responds to each dispatched message.

A BLooper can be run only once. If called a second time, Run() returns B_ERROR, but doesn't disrupt the message loop already running. < Currently, it drops into the debugger so you can correct the error. >

The message loop is terminated when Quit() is called, or (potentially) when a B_QUIT_REQUESTED message is received. This also kills the thread and deletes the BLooper object.

See also: the BLooper constructor, the BApplication class, Quit()


SetCommonFilterList(), CommonFilterList(), AddCommonFilter(), RemoveCommonFilter()


      virtual void SetCommonFilterList(BList *list)

      BList *CommonFilterList(void) const

      virtual void AddCommonFilter(BMessageFilter *filter)

      virtual void RemoveCommonFilter(BMessageFilter *filter)

These functions manage a list of filters that can apply to any message the BLooper receives, regardless of its target BHandler. They complement a similar set of functions defined in the BHandler class. When a filter is associated with a BHandler, it applies only to messages targeted to that BHandler. When it's associated with a BLooper as a common filter, it applies to all messages that the BLooper dispatches, regardless of the target.

In addition to the list of common filters, a BLooper can maintain a filter list in its role as a BHandler. These filters apply only if the BLooper is the target of the message (see SetFilterList() in the BHandler class.)

SetCommonFilterList() assigns the BLooper a new list of common filters; the list must contain pointers to instances of the BMessageFilter class or instances of classes that derive from BMessageFilter. The new list replaces any list of common filters previously assigned. All objects in the previous list are deleted, as is the BList itself. If list is NULL, the current list is removed without a replacement. CommonFilterList() returns the current list of common filters.

AddCommonFilter() adds a filter to the end of the list of common filters. It creates the BList object if it doesn't already exist. By default, BLoopers don't keep a BList of common filters until one is assigned or AddCommonFilter() is called for the first time. RemoveCommonFilter() removes a filter from the list without freeing 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 SetCommonFilterList(), AddCommonFilter(), and RemoveCommonFilter() to work, the BLooper must be locked.

See also: BHandler::SetFilterList(), Lock(), BMessageFilter


SetPreferredHandler(), PreferredHandler()


      void SetPreferredHandler(void) const

      BHandler *PreferredHandler(BHandler *handler) 

These functions set and return the BLooper's preferred handler--the BHandler object that should handle messages not specifically targetted to another BHandler.

To designate the current preferred handler--whatever object that may be--as the target of a message, pass NULL for the target handler to PostMessage() or to the BMessenger constructor.

Posting or sending messages to the preferred handler can be useful. For example, in the Interface Kit, BWindow objects name the current focus view as the preferred handler. This makes it possible for other objects--such as BMenuItems and BButtons--to target messages to the BView that's currently in focus, without knowing what view that might be. For example, by posting its messages to the window's preferred handler, a Cut menu item can make sure that it always acts on whatever view contains the current selection. See the chapter on the Interface Kit for information on windows, views, and the role of the focus view.

By default, BLoopers don't have a preferred handler; until one is set, PreferredHandler() returns NULL. Note however, that messages targeted to the preferred handler are dispatched to the BLooper whenever the preferred handler is NULL. In other words, the BLooper acts as default preferred handler, even though the default is formally NULL.

See also: BControl::SetTarget() and BMenuItem::SetTarget() in the Interface Kit, PostMessage()


Thread(), Team()


      thread_id Thread(void) const

      team_id Team(void) const 

These functions identify the thread that runs the message loop and the team to which it belongs. Thread() returns B_ERROR if Run() hasn't yet been called to spawn the thread and begin the loop. Team() always returns the application's team_id.


Unlock() see Lock()






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 June 30, 1997.