The Be Book Screen Saver Screen Saver Index

BScreenSaver

Derived from: none
Declared in:  be/add-ons/screen_saver/ScreenSaver.h
Library: the ScreenSaver preferences application
more...


BScreenSaver provides an interface for developers creating their own screen saver modules. Classes derived from BScreenSaver implement the functions defined here in order to draw on the screen while it's being saved, and to draw into ScreenSaver's preview screen (see "Talking to ScreenSaver" for an illustration of the preview screen).

The BScreenSaver class is abstract—it must be subclassed to be used. Furthermore, you never construct BScreenSaver (subclass) objects yourself; they're created automatically as needed by the screen saver engine.


Screen Saver Lifetime

When the screen saver engine wants to use your screen saver to save the screen, it constructs an instance of your BScreenSaver subclass (through the instantiate_screen_saver() function, as explained in "Screen Saver Add-ons"), and then calls the object's hook functions, in this order:

When the ScreenSavers preferences app loads your module, the series of calls is similar, but with these differences:

The following functions can be called at any time:

What If I Don't Want a Draw() Function?

You don't have to use the Draw()/DirectDraw() functions; they're provided as a convenience to make simple screen savers easy to write.

One approach to handling your own drawing is to spawn a drawing thread in StartSaver() and shut it down in StopSaver(). You should implement the Draw() function to notify the drawing thread when the screen is available (frame is 0). After that, you can handle drawing any way you want.

ScreenSavers' preview monitor won't work properly unless you do your drawing in the Draw() function

If you need direct access to the frame buffer, you'll have to handle synchronization with DirectConnected() yourself, because that's the only time the screen saver is holding a lock on the display for you (this is handled automatically if you use DirectDraw()).


Hook Functions

InitCheck()
Can be implemented to let the screen saver engine know if your add-on was initialized properly.

StartSaver()
Can be implemented to do things that need to be done just before the screen saver starts drawing.

StopSaver()
Can be implemented to do things that need to be done when the screen saver stops drawing.

Draw()
Can be implemented to draw the screen saver's entertaining display (to the screen, as well as in the preview displayed by the ScreenSaver preferences application).

DirectConnected()
Called when the connection to the screen has been made, when the size or format of the frame buffer changes, when the position, size, or shape of the visible part of the content area of the window changes, or when the connection to the screen is terminated.

DirectDraw()
Can be implemented to draw the screen saver's entertaining display when you need to directly access the pixels (as in a BDirectWindow).

StartConfig()
Can be implemented to display the screen saver's copyright and configuration information in the ScreenSaver preferences application.

StopConfig()
Can be implemented to handle things that need to be done just before the ScreenSaver configuration view goes away.

SupplyInfo()
Can be implemented to supply the screen saver system with information about this add-on. The system then passes the info to other screen saver add-ons (by invoking their ModulesChanged() functions).

ModulesChanged()
Can be implemented to learn about other screen saver add-ons.

SaveState()
Can be implemented to save the current state of the screen saver, allowing it to be reconstituted later.

Constructor and Destructor


BScreenSaver()

BScreenSaver(BMessage *state, image_id image)

Builds a BScreenSaver object from the state information stored in state (if any, as explained below). Freshly constructed, your screen saver isn't connected to a BView, so you can't do anything that requires one. There'll be plenty of time for that later, as described in StartSaver() and StartConfig(). To gauge the success of the construction, the screen saver engine calls InitCheck().

The state argument contains whatever items you added when SaveState() was invoked on a previous instantiation of your object—in other words, state is a record of the state of your object when it last ran. If this is the very first time your screen saver is being constructed, state will be empty, and you'll need some sensible default values. The state format is up to you—you write it, you read it, nobody else is going to touch it.

The image argument is the image (in the Kernel Kit sense) of the add-on itself. This is particularly useful if your screen saver needs to find some resources stored in the add-on. For example, imagine that your BScreenSaver subclass (SpiffySaver) has a BResources *my_rsrc member; here's how you'd retrieve the resource:

#include <kernel/OS.h>
#include <storage/Resources.h>

SpiffySaver::SpiffySaver( BMessage *info, image_id id )
{
   /* Initialization... */
   ...

   /* Find SpiffySaver's resources so we can use them later. */
   image_info the_info;
   status_t retval = get_image_info( id, &the_info );
   if( retval != B_OK ) {
      /* gripe at the user or bail out. */
   }

   my_rsrc = new BResources;
   retval = my_rsrc->SetTo( new BFile( the_info.name, O_RDONLY ) );
   if( retval != B_OK ) {
      /* gripe at the user or bail out. */
   }

   /*
   * Anything else you need in the constructor, such as
   * finding strings in your resources.
   */
   ...
}


~BScreenSaver()

virtual ~BScreenSaver()

Destroys your screen saver; this is what happens when the user wants to get back to digital content creation. By the time the destructor is called, you won't be drawing on the screen anymore, and StopConfig() and StopSaver() will already have been called.


Member Functions


Draw() , DirectDraw()

virtual void Draw(BView *view, int32 frame)
virtual void DirectDraw(int32 frame)

These are the hook functions that draw to the screen. For "normal" drawing, you override Draw(); if you want to bang the bits directly (such as you would in a BDirectWindow), you should use DirectDraw(). In general, you should only implement one function or the other. If you implement both functions, they'll both be called. DirectDraw() will always be called before Draw() if you implement both of them.

Draw() is called once every TickSize() microseconds. view is the view to draw into; frame is a frame counter that starts at 0 and is incremented each time Draw() is called. The view starts with a view color of B_TRANSPARENT_32_BIT, which means the desktop will be showing through it. If you don't want to see the Desktop (maybe your add-on draws some nice line patterns that look best on a black background), you should clear the view on the first frame (frame == 0).

An easy way to clear the view is to set the view color in StartSaver() using BView::SetViewColor().

DirectDraw()'s protocol (and calling frequency) is the same as for Draw(), but, since it draws directly to the screen, DirectDraw() lacks a view parameter. See DirectConnected() for more direct drawing information.

The longer you spend in your Draw()/DirectDraw() function, the longer the user will have to wait to un-save their system, and that'll annoy everyone. Do your drawing and get out as quickly as possible.


DirectConnected()

virtual void DirectConnected(direct_buffer_info *info)

Hook function that's called when direct window access is enabled or suspended, or when the state of the display that you'll be (direct) drawing on changes. The info argument describes the display state; see the BDirectWindow class (in the Game Kit) for more information about the direct_buffer_info structure.

Unlike BDirectWindow::DirectConnected(), you don't need to worry about synchronizing with your drawing thread; the screen saver engine handles that for you.

Your DirectConnected() code should be as short as possible, because what it does can affect the performance of the entire system. DirectConnected() should only handle the immediate task of dealing with changes in the direct drawing context, and shouldn't normally do any actual drawing—that's what DirectDraw() is for.

DirectConnected() should only return when it can guarantee that the request specified by info will be strictly obeyed.

The structure pointed to by info goes away after DirectConnected() returns, so you should cache the information that interests you.


Direct  see Draw()


InitCheck()

virtual status_t InitCheck(void)

Hook function that the screen saver engine uses to assess the success of your object's construction. Your version of InitCheck() should return B_OK if the object constructed itself properly, and B_ERROR if there was a problem. The default InitCheck() returns B_OK.

InitCheck() is called after the constructor, but before the object has been asked to provide any services. Use it to examine the runtime environment, and let the screen saver engine know if you don't like what's going on. For example, if your screen saver requires hardware-accelerated OpenGL, this would be the place to report an error if the hardware can't be found.


LoopOffCount() see SetLoop()
LoopOnCount() see SetLoop()
ModulesChanged() see SupplyInfo()


SaveState()

virtual status_t SaveState(BMessage *state) const

Implement this hook function to save the current state of your screen saver so it can be reconstituted the next time your object is constructed. You save the state into the state message, which will be passed to your object's constructor.

If your version of SaveState() returns anything other than B_OK, the screen saver engine will ignore anything you've put into the state message.

SaveState() can be called at any time, and is not guarenteed to be called from StopSaver(); your saver can't depend on it to handle updates to variables being controlled from the configuration view. You should handle these directly (and immediately) so the user can see their changes happening.


SetLoop() , LoopOnCount() , LoopOffCount()

void SetLoop(int32 on_count, int32 off_count)
int32 LoopOnCount(void) const
int32 LoopOffCount(void) const

These functions are used for controlling animation loop cycles. For some screen savers, it makes sense to draw repeatedly, and then to sleep. For example, a saver to draw ink-blot patterns could draw pixels every frame until enough of them are on the screen, and then spend some time sleeping before clearing the screen and starting over.

Use SetLoop() to implement a screen saver that uses a cycle like this. Your Draw() and/or DirectDraw() method will be called for on_count frames (and the frame count will always be 0 to on_count - 1), and then the saver engine will sleep (for TickSize() microseconds) for off_count frames.

For example, if you SetLoop( 10, 5 ), your saver will draw on frames 0 to 9, and then sleep for the TickSize() microseconds 5 times.

The LoopOnCount() function returns the current number of drawing frames (the on_count).

The LoopOffCount() function returns the current number of sleep frames (the off_count).


SetTickSize() , TickSize()

void SetTickSize(bigtime_t size)
bigtime_t TickSize(void) const

SetTickSize() sets the drawing frequency to size microseconds. This lets you control how often your Draw() and/or DirectDraw() function is called. The default tick size is 50000 (50 milliseconds).

Setting the tick size to 0 causes Draw()/DirectDraw() to be called with almost no delay; in reality, there will be some variable delay depending on scheduling latency. This is actually a good thing because it gives other threads a chance to run, and also lets the screen saver stay responsive when the user wants to get back to work.

If you set tick size to 0, do not call snooze(), snooze_until(), sleep() or anything that could block indefinitely. This sort of misbehavior will cause users to delete your screen saver immediately because nobody appreciates a locked up system. If you do need some sort of delay, call SetTickSize() before you return from drawing and reset it to 0 during the next frame.

TickSize() returns the drawing frequency in microseconds.


StartConfig() , StopConfig()

virtual void StartConfig(BView *configView)
virtual void StopConfig(void)

Your StartConfig() function is called when the ScreenSaver preference is about to display your module's configuration view. Any controls that you need to create to let the user fine-tune your module should be added to configView. Remember to set the targets of any controls that you add; a good way to do this is to add a custom BView and SetTarget() your controls to that custom view in the view's AttachedToWindow() function.

Don't draw your screen saver's funky display inside configView; it's for displaying information about your module, and controls for fiddling with its settings. StartSaver() will be called (with its preview argument set to true) to give you a chance to show off.

StopConfig() is called when the configuration view of the ScreenSaver prefs is about to vanish.


StartSaver() , StopSaver()

virtual status_t StartSaver(BView *view, bool preview)
virtual void StopSaver(void)

An invocation of StartSaver() means that the screen saver engine is about to start saving the screen (if preview is false), or that ScreenSavers is about to display the module in its preview monitor (if preview is true).

In your implementation of StartSaver(), you can't add children to the view, and you can't draw on the screen yet. Wait for calls to Draw() or DirectDraw() for that. The view will become visible after StartSaver() returns.

StartSaver() gives you an opportunity to set up your saver because it tells you exactly how large an area you'll be saving via the view argument. You can also use view to figure out your color space (indirectly, by creating a BScreen with view–>Window() in the constructor).

Return B_OK if all is well, or B_ERROR if you're not prepared to draw on the screen. Screen savers with no preview should return B_ERROR when asked to provide one:

status_t SpiffySaver::StartSaver( BView *view, bool preview )
{
   /* SpiffySaver has no preview... it's not THAT spiffy. */
   if( preview ) return B_ERROR;
   
   ...

   return B_OK;
}

StopSaver() is called when the screen saver is done displaying. It's called after the very last call to Draw() or DirectDraw().


StopConfig() see StartConfig()
StopSaver()  see StartSaver()


SupplyInfo() , ModulesChanged()

virtual void SupplyInfo(BMessage *info) const
virtual void ModulesChanged(const BMessage *info)

These functions aren't currently used by the screen saver system.

These functions are used for communication between screen saver modules.

The screen saver engine calls SupplyInfo() when it wants you to supply information about your screen saver. Stuff any information you want other modules to know about into the info message. The message is then passed to other screen saver modules through their ModulesChanged() functions.

The ModulesChanged() hook function is called whenever the list of known screen saver modules changes. The info BMessage contains an embedded BMessage for every valid module. Each embedded BMessage is named after its module's add-on, and contains the information that's returned by the module's SupplyInfo() implementation.

As an example—although not a very useful one—here we print the name and contents of each embedded message:

void SpiffySaver::ModulesChanged( const BMessage *info )
{
   int32 num_addons = info->CountNames( B_MESSAGE_TYPE );

   for( int idx = 0; idx < num_addons; idx ++ ) {
      status_t retval;
      type_code found_type;
      char *name;
      
      retval = info->GetInfo( B_MESSAGE_TYPE, idx,
                              &name, &found_type );
      if( retval == B_OK ) {
            BMessage msg;
            retval = info->GetMessage( name, &msg );

            if( retval == B_OK ) {
               printf( "A module named "%s" sent this info:n", name );
            msg.PrintToStream();
            }
      }
   }
}


The Be Book Screen Saver Screen Saver Index

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

Copyright © 2000 Be, Inc. All rights reserved..