BApplication

Derived from: public BLooper

Declared in: be/app/Application.h

Library: libbe.so

[method summary]

The BApplication class defines an object that represents and serves the entire application. Every Be application must have one (and only one) BApplication object. It's usually the first object the application constructs and the last one it deletes.

The BApplication object has these primary responsibilities:


Derived Classes

BApplication typically serves as the base class for a derived class that specializes it and extends it in ways that are appropriate for a particular application. It declares (and inherits declarations for) a number of hook functions that you can implement in a derived class to augment and fine-tune what it does.

For example, your application might implement a RefsReceived() function to open a document and display it in a window or a ReadyToRun() function to finish initializing the application after it has been launched and has started to receive messages. These two functions, like a handful of others, are called in response to system messages that have applicationwide import. All of these messages and the hook functions that respond to them are discussed in the next section.

If you expect your application to get messages from remote sources, or its main thread to get messages from other threads in the application, you should also implement a MessageReceived() function to sort through them as they arrive.

A derived class is also a good place to record the global properties of your application and to define functions that give other objects access to those properties.


Application Messages

The BApplication object runs the main message loop where it receives application messages--system messages that concern the application as a whole. For these messages, the BApplication object acts as both looper (receiving and dispatching the message) and handler (responding to the message).

All seven application messages report events. Two of them notify the application of a change in its status:

Two of the messages are requests that the application typically makes of itself:

Other application messages report information from remote sources:

The system is the source of one repeated message:

All application messages are received by the BApplication object in the main thread. The object dispatches them all to itself; it doesn't delegate them to any other handler. The following chart lists the hook functions that are called to initiate the application's response to system messages and the base class where each function is declared:

Message type Hook function Class
B_READY_TO_RUN ReadyToRun() BApplication
B_APP_ACTIVATED AppActivated() BApplication
B_QUIT_REQUESTED QuitRequested() BLooper
B_ABOUT_REQUESTED AboutRequested() BApplication
B_ARGV_RECEIVED ArgvReceived() BApplication
B_REFS_RECEIVED RefsReceived() BApplication
B_PULSE Pulse() BApplication

QuitRequested() is first declared in the BLooper class. BApplication reinterprets it--and reimplements it--to mean a request to quit the whole application, not just one of its threads.

Only three application messages--B_APP_ACTIVATED, B_ARGV_RECEIVED, and B_REFS_RECEIVED--contain any data; the rest are empty. See "Application Messages" in the Message Protocols appendix for details on the content of these messages.


Constructing the Object and Running the Message Loop

The BApplication object must be constructed before the application can begin running or put a user interface on-screen. Other objects in other kits depend on the BApplication object and its connection to the Application Server. In particular, you can't construct BWindow objects in the Interface Kit until the BApplication object is in place.

Simply constructing the BApplication object forms the connection to the server. The connection is severed when you quit the application and delete the object.

be_app

The BApplication constructor assigns the new object to a global variable, be_app. be_app is declared in Application.h and can be used throughout the code you write (or, more accurately, all code that directly or indirectly includes Application.h).

The be_app variable is typed as a pointer to an instance of the BApplication class. If you use a derived class instead--as most applications do--you have to cast the be_app variable when you call a function that's implemented by the derived class.

   ((MyApplication *)be_app)->DoSomethingSpecial();

Casting isn't required to call functions defined in the BApplication class (or in the BHandler and BLooper classes it inherits from), nor is it required for virtual functions defined in a derived class but declared by BApplication (or by the classes it inherits from).

main()

Because of its pivotal role, the BApplication object is one of the first objects, if not the very first object, the application creates. It's typically created in the main() function.

After constructing the BApplication object (and the other objects that your application initially needs), you tell it to begin running the message loop by calling its Run() function. Like the Run() function defined in the BLooper class, BApplication's Run() initiates a message loop and begins processing messages. However, unlike the BLooper function, it doesn't spawn a thread; rather, it takes over the main application thread. Because it runs the loop in the same thread in which it was called, Run() doesn't return until the application is told to quit.

The main() function of a Be application typically looks something like this:

   #include <app/Application.h>
   
   main()
   {
       . . .
       new BApplication("application/x-vnd.ORA-app5");
       . . .
       be_app->Run();
       delete be_app;
   }

The string passed to the constructor ("application/x-vnd.ORA-app5") sets the application's signature. This is just a precautionary measure. It's more common (and much better) to set the signature at compile time as an attribute and resource. If there is a compile-time signature, it's used and the one passed to the constructor is ignored.

The main() function shown above doesn't allow for the usual command-line arguments, argc and argv. It would be possible to have main() parse the argv array, but these arguments are also packaged in a B_ARGV_RECEIVED message that the application gets immediately after Run() is called. Instead of handling them within main(), applications generally implement an ArgvReceived() function to do the job. This function can also handle command-line arguments that are passed to the application after it has been launched; it can be called at any time while the application is running.

Configuration Messages Received on Launch

When an application is launched, it may be passed messages that affect how it configures itself. These are the first messages that the BApplication object receives after Run() is called.

For example, when the user double-clicks a document icon to launch an application, the Tracker passes the application a B_REFS_RECEIVED message with information about the document. When launched from the command line, the application gets a B_ARGV_RECEIVED message listing the command-line arguments. When launched by the BRoster object, it might receive an arbitrary set of configuration messages.

After all the messages passed on-launch have been received and responded to, the application gets a B_READY_TO_RUN message and its ReadyToRun() hook function is called. This is the appropriate place to finish initializing the application before it begins running in earnest. It's the application's last chance to present the user with its initial user interface. For example, if a document has not already been opened in response to an on-launch B_REFS_RECEIVED message, ReadyToRun() could be implemented to place a window with an empty document on-screen.

ReadyToRun() is always called to mark the transition from the initial period when the application is being launched to the period when it's up and running--even if it's launched without any configuration messages. The IsLaunching() function can let you know which period the application is in.

Quitting

The main message loop terminates and Run() returns when Quit() is called. Because Run() doesn't spawn a thread, Quit() merely breaks the loop; it doesn't kill the thread or destroy the object (unlike BLooper's version of the function).

Quit() is usually called indirectly, as a byproduct of a B_QUIT_REQUESTED message posted to the BApplication object. The application is notified of the message through a QuitRequested() function call; it calls Quit() if QuitRequested() returns true.

When Run() returns, the application is well down the path of terminating itself. main() simply deletes be_app, cleans up anything else that might need attention, and exits.

Construction and Restricted Launch Behavior

Applications with restricted launch behavior (B_EXCLUSIVE_LAUNCH and B_SINGLE_LAUNCH) may be launched anyway in violation of those restrictions. When this happens, the BApplication constructor causes the application to exit immediately.

Applications should be prepared for their main() functions to be executed in this abortive manner and guard against any undesired consequences.


Locking

You sometimes have to coordinate access to the BApplication object, since a single object serves the entire application and different parts of the application (windows, in particular) will be running in other threads. Locking ensures that one thread won't change the state of the application while another thread is changing the same aspect (or even just trying to examine it).

The BApplication object is locked automatically while the main thread is responding to a message, but it may have to be explicitly locked at other times.

This class inherits the locking mechanism--the Lock(), Unlock(), and other functions--from BLooper. See that class for details.


Hook Functions

AboutRequested()
Can be implemented to present the user with a window containing information about the application.

AppActivated()
Can be implemented to do whatever is necessary when the application becomes the active application, or when it loses that status.

ArgvReceived()
Can be implemented to parse the array of command-line arguments (or a similar array of argument strings).

Pulse()
Can be implemented to do something over and over again. Pulse() is called repeatedly at roughly regular intervals in the absence of any other activity in the main thread.

Quit()
Can be implemented to do whatever is necessary to clean up after the application.

ReadyToRun()
Can be implemented to set up the application's running environment. This function is called after all messages the application receives on-launch have been responded to.

RefsReceived()
Can be implemented to respond to a message that contains references to files and directories. Typically, the references are to documents that the application is being asked to open.


Constructor and Destructor


BApplication()

      BApplication(const char *signature) 
      BApplication(BMessage *archive) 

Establishes a connection to the Application Server, assigns signature as the application identifier if one hasn't already been set, and initializes the applicationwide variable be_app to point to the new object.

The signature that's passed becomes the application identifier only if a signature hasn't been set as a resource or file-system attribute. It's preferable to assign the signature at compile time, since that enables the system to associate the signature with the application even when it's not running.

Every application must have one and only one BApplication object, typically an instance of a derived class. It's usually the first object that the application creates.

If the application has launch restrictions (either B_SINGLE_LAUNCH or B_EXCLUSIVE_LAUNCH), and the application is already running, the constructor will abort without doing anything.

Like other BHandlers, the BApplication object is archivable and can be reconstructed from a BMessage archive.


~BApplication()

      virtual ~BApplication()

Closes the application's windows, if it has any, without giving them a chance to disagree, kills the window threads, frees the BWindow objects and the BViews they contain, and severs the application's connection to the Application Server.

You can delete the BApplication object only after Run() has exited the main message loop. In the normal course of events, all the application's windows will already have been closed and freed by then.

See also: the BWindow class in the Interface Kit, QuitRequested()


Static Functions


Instantiate()

      static BApplication *Instantiate(BMessage *archive) 

Returns a new BApplication object, allocated by new and created with the version of the constructor that takes a BMessage archive.

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


Member Functions


AboutRequested()

      virtual void AboutRequested(void)

Implemented by derived classes to put a window on-screen that provides the user with information about the application. The window typically displays copyright data, the version number, license restrictions, the names of the application's authors, a simple description of what the application is for, and similar information.

This function is called when the user operates an About... menu item and a B_ABOUT_REQUESTED message is delivered to the BApplication object as a result.

To set up the menu item, assign it a model message with B_ABOUT_REQUESTED as the command constant and the BApplication object as the target, as follows:

   BMenuItem *item;
   item = new BMenuItem("About application name" B_UTF8_ELLIPSIS,
                                new BMessage(B_ABOUT_REQUESTED));
   item->SetTarget(be_app);
   menu->AddItem(item);

See also: the BMenu class in the Interface Kit


AppActivated()

      virtual void AppActivated(bool active)

Implemented by derived classes to take note when the application becomes--or ceases to be--the active application. The application has just attained that status if the active flag is true, and just lost it if the flag is false. The active application is the one that owns the current active window.

This function is called only when the change in active application is a consequence of a window being activated. It will be called when an application is launched (provided that the application puts a window on-screen). However, it's always called after ReadyToRun(), not before.

See also: BWindow::WindowActivated() in the Interface Kit, "B_APP_ACTIVATED" in the Message Protocols appendix


Archive()

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

Calls the inherited version of Archive(), then adds the application signature to the BMessage archive.

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


ArgvReceived()

      virtual void ArgvReceived(int32 argc, char **argv)

Implemented by derived classes to respond to a B_ARGV_RECEIVED message that passes the application an array of argument strings, typically arguments typed on the command line. argv is a pointer to the strings and argc is the number of strings in the array. These parameters are identical to those traditionally associated with the main() function.

When an application is launched from the command line, the command-line arguments are both passed to main() and packaged in a B_ARGV_RECEIVED message that's sent to the application on-launch (before ReadyToRun() is called). When BRoster's Launch() function is passed argc and argv parameters, they're similarly bundled in an on-launch message.

An application might also get B_ARGV_RECEIVED messages after it's launched. For example, imagine a graphics program called "Splotch" that can handle multiple documents and is therefore restricted so that it can't be launched more than once (it's a B_SINGLE_LAUNCH or a B_EXCLUSIVE_LAUNCH application). If the user types

   $ Splotch myArtwork

in a shell, it launches the application and passes it an on-launch B_ARGV_RECEIVED message with the strings "Splotch" and "myArtwork". Then, if the user types

   $ Splotch yourArtwork

the running application is again informed with a B_ARGV_RECEIVED message. In both cases, the BApplication object dispatches the message by calling this function.

To open either of the artwork files, the Splotch application will need to translate the document pathname into a file reference. It can do this most easily by calling get_ref_for_path(), defined in the Storage Kit.

See also: RefsReceived(), "B_ARGV_RECEIVED" in the Message Protocols appendix


CountWindows()

      int32 CountWindows(void) const

Returns the number of windows belonging to the application. The count includes only windows that the application explicitly created. It omits, for example, the private windows used by BBitmap objects.

See also: the BWindow class in the Interface Kit


DispatchMessage()

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

Augments the BLooper function to dispatch system messages by calling a specific hook function. The set of system messages that the BApplication object receives and the hook functions that it calls to respond to them are listed under "Application Messages" in the overview.

Other messages--those defined by the application rather than the Application Kit--are forwarded to the target BHandler's MessageReceived() function. Note that the target is ignored for most system messages.

DispatchMessage() locks the BApplication object and keeps it locked until the main thread has finished responding to the message.

See also: BLooper::DispatchMessage(), BHandler::MessageReceived()


GetAppInfo()

      status_t GetAppInfo(app_info *theInfo) const

Writes information about the application into the app_info structure referred to by theInfo. The structure contains the application signature, the identifier for its main thread, a reference to its executable file in the file system, and other information.

This function is the equivalent to the identically named BRoster function--or, more accurately, to BRoster's GetRunningAppInfo()--except that it provides information only about the current application. The following code

   app_info info;
   if ( be_app->GetAppInfo(&info) == B_OK )
       . . .

is a shorthand for:

   app_info info;
   if ( be_roster->GetRunningAppInfo(be_app->Team(), &info) == B_OK )
       . . .

GetAppInfo() returns B_OK if successful, and an error code if not.

See the BRoster function for the error codes and for a description of the information contained in an app_info structure.

See also: BRoster::GetAppInfo()


HideCursor(), ShowCursor(), ObscureCursor(), IsCursorHidden()

      void HideCursor(void)
      void ShowCursor(void)
      void ObscureCursor(void)
      bool IsCursorHidden(void) const

HideCursor() removes the cursor from the screen. ShowCursor() restores it. ObscureCursor() hides the cursor until the user moves the mouse. IsCursorHidden() returns false if the cursor is hidden (but not obscured), and true if it's visible. It's not our place to question these things.

See also: SetCursor()


IsLaunching()

      bool IsLaunching(void) const

Returns true if the application is in the process of launching--of getting itself ready to run--and false once the ReadyToRun() function has been called.

IsLaunching() can be called while responding to a message to find out whether the message was received on-launch (to help the application configure itself) or after-launch as an ordinary message.

See also: ReadyToRun()


MessageReceived()

      virtual void MessageReceived(BMessage *message)

Augments the BHandler version of MessageReceived() to handle scripting requests delivered to the BApplication object.

See also: BHandler::MessageReceived()


ObscureCursor() see HideCursor()


Pulse()

      virtual void Pulse(void)

If your app's pulse rate is set, it will receive a B_PULSE message automatically and regularly (ostensibly, once every pulse-rate microseconds). The message invokes the Pulse() function. By default, pulsing is disabled--the pulse rate is set to 0; you can enable it by calling the SetPulseRate() function.

You can implement Pulse() to do whatever you want, but note that the precision of pulse event timing is not guaranteed.

The default version of this function is empty.

See also: BWindow::Pulse() in the Interface Kit, SetPulseRate()


Quit()

      virtual void Quit(void)

Kills the application by terminating the message loop and causing Run() to return. You rarely call this function directly; it's called for you when the application receives a B_QUIT_REQUESTED message and QuitRequested() returns true to allow the application to shut down.

BApplication's Quit() differs from the BLooper function it overrides in four important respects:

Before shutting down, the BApplication object responds to every message it received prior to the Quit() call.

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


QuitRequested()

      virtual bool QuitRequested(void)

Overrides the BLooper function to decide whether the application should really quit when requested to do so.

BApplication's implementation of this function tries to get the permission of the application's windows before agreeing to quit. It works its way through the list of BWindow objects that belong to the application and forwards the QuitRequested() call to each one. If a BWindow agrees to quit (its QuitRequested() function returns true), the BWindow version of Quit() is called to destroy the window. If the window refuses to quit (its QuitRequested() function returns false), the attempt to destroy the window fails and no other windows are asked to quit.

If it's successful in terminating all the application's windows (or if the application didn't have any windows to begin with), this function returns true to indicate that the application may quit; if not, it returns false.

An application can replace this window-by-window test of whether the application should quit, or augment it by adding a more global test. It might, for example, put a modal window on-screen that gives the user the opportunity to save documents, terminate on-going operations, or cancel the quit request.

This hook function is called for you when the main thread receives a B_QUIT_REQUESTED message; you never call it yourself. However, you do have to post the B_QUIT_REQUESTED message. Typically, the application's main menu has an item labeled "Quit." When the user invokes the item, it should post a B_QUIT_REQUESTED message directly to the BApplication object.

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


ReadyToRun()

      virtual void ReadyToRun(void)

Implemented by derived classes to complete the initialization of the application. This is a hook function that's called after all messages that the application receives on-launch have been handled. It's called in response to a B_READY_TO_RUN message that's posted immediately after the last on-launch message. If the application isn't launched with any messages, B_READY_TO_RUN is the first message it receives.

This function is the application's last opportunity to put its initial user interface on-screen. If the application hasn't yet displayed a window to the user (for example, if it hasn't opened a document in response to an on-launch B_REFS_RECEIVED or B_ARGV_RECEIVED message), it should do so in ReadyToRun().

The default version of ReadyToRun() is empty.

See also: Run(), IsLaunching()


RefsReceived()

      virtual void RefsReceived(BMessage *message)

Implemented by derived classes to do something with file system entries that have been referred to the application in a message. The message has B_REFS_RECEIVED as its what data member and a single data field named "refs" that contains one or more entry_ref (B_REF_TYPE) items.

Typically, the entry refs are for documents that the application is requested to open. For example, when the user double-clicks a document icon in a Tracker window, the Tracker sends a B_REFS_RECEIVED message to the application that owns the document. The BApplication object dispatches the message by passing it to this function.

There are a number of things you can do with the entry_ref taken from the message. For example, you might create a BEntry object for it and inquire whether it refers to a file:

   BEntry entry(&ref);
   if ( entry.IsFile() )
       . . .

If you're sure it's a file reference, you might create a BFile object and open it. For example:

   void MyApplication::RefsReceived(BMessage *message)
   {
       uint32 type;
       int32 count;
       entry_ref ref;
       . . .
       message->GetInfo("refs", &type, &count);
       if ( type != B_REF_TYPE )
           return;
       for ( long i = --count; i >= 0; i-- ) {
           if ( message->FindRef("refs", i, &ref) == B_OK ) {
               BFile file;
               if ( file.SetTo(&ref, B_READ_WRITE) == B_OK )
                   . . .
           }
       }
       . . .
   }

B_REFS_RECEIVED messages can be received both on-launch (while the application is configuring itself) or after-launch (as ordinary messages received while the application is running).

See also: the BEntry class in the Storage Kit, ArgvReceived(), ReadyToRun(), IsLaunching(), "B_REFS_RECEIVED" in the Message Protocols appendix


ResolveSpecifier()

      virtual BHandler *ResolveSpecifier(BMessage *message, int32 index, 
         BMessage *specifier, int32 command, const char *property)

Resolves specifiers for the "Name" and "Window" properties. See "Scripting Support" in the class overview and the "Scripting" section of this chapter for more information.

See also: BHandler::ResolveSpecifier()


Run()

      virtual thread_id Run(void)

Runs a message loop in the application's main thread. This function must be called from main() to start the application running. The loop is terminated and Run() returns when Quit() is called, or (potentially) when a QUIT_REQUESTED message is received. It returns the identifier for the main thread (not that it's of much use once the application has stopped running).

This function overrides BLooper's Run() function. Unlike that function, it doesn't spawn a thread for the message loop or return immediately.

See also: BLooper::Run(), ReadyToRun(), QuitRequested()


SetCursor()

      void SetCursor(const void *cursor)

Sets the cursor image to the bitmap specified in cursor. Each application has control over its own cursor and can set and reset it as often as necessary. The cursor on-screen will have the shape specified in cursor as long as the application remains the active application. If it loses that status and then regains it, its current cursor is automatically restored.

The first four bytes of cursor data is a preamble that gives information about the image, as follows:

Image data follows these four bytes. Pixel values are specified from left to right in rows starting at the top of the image and working downward. First comes data specifying the color value of each pixel in the image. In a one-bit-per-pixel image, 1 means black and 0 means white.

Following the color data is a mask that indicates which pixels in the image square are transparent and which are opaque. Transparent pixels are marked 0; they let whatever is underneath that part of the cursor bitmap show through. Opaque pixels are marked 1.

The Application Kit defines two standard cursor images. Each is represented by a constant that you can pass to SetCursor():

B_HAND_CURSOR The hand image that's seen when the computer is first turned on. This is the default cursor.
B_I_BEAM_CURSOR The standard I-beam image for selecting text.

See also: HideCursor()


SetPulseRate()

      void SetPulseRate(bigtime_t microseconds)

Sets how often Pulse() is called (how often B_PULSE messages are posted). The interval set should be a multiple of 100,000 microseconds (0.1 second); differences less than 100,000 microseconds will not be noticeable. A finer granularity can't be guaranteed.

The default pulse rate is 0, which disables the pulsing mechanism. Setting a different rate enables it.

See also: Pulse()


ShowCursor() see HideCursor()


WindowAt()

      BWindow *WindowAt(int32 index) const

Returns the BWindow object recorded in the list of the application's windows at index, or NULL if index is out of range. Indices begin at 0 and there are no gaps in the list. Windows aren't listed in any particular order (such as the order they appear on-screen), so the value of index has no ulterior meaning. The window list excludes the private windows used by BBitmaps and other objects, but it doesn't distinguish main windows that display documents from palettes, panels, and other supporting windows.

This function can be used to iterate through the window list:

   BWindow *window;
   int32 i = 0;
   
   while ( window = be_app->WindowAt(i++) ) {
       if ( window->Lock() ) {
           . . . 
           window->Unlock();
       }
   }

This works as long as windows aren't being created or deleted while the list index is being incremented. Locking the BApplication object doesn't lock the window list.

It's best for an application to maintain its own window list, one that arranges windows in a logical order and can be locked while it's being read.

See also: CountWindows()


Scripting Support

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


The Name Property

Message Specifiers Meaning
B_GET_PROPERTY B_DIRECT_SPECIFIER Returns the name of the application's main thread.


The Window Property

Message Specifiers Meaning
B_COUNT_PROPERTIES B_DIRECT_SPECIFIER Returns the number of windows owned by the application as reported by CountWindows().
any others B_NAME_SPECIFIER,
B_INDEX_SPECIFIER,
B_REVERSE_INDEX_SPECIFIER
Directs the scripting message to the specified window, first popping the current specifier off the specifier stack.






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

Copyright © 1998 Be, Inc. All rights reserved.

Last modified December 11, 1998.