Screen Saver: BScreenSaver

Screen Saver Table of Contents | Screen Saver Index

# BScreenSaver

Derived from: none

Declared in: be/add-ons/screen_saver/ScreenSaver.h

Library: the

###### Summary

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:

- `InitCheck()`; if this returns a value other than `B_OK`, your object is deleted (and the add-on is unloaded).

- `StartSaver()` is called just before your screen saver starts drawing. You implement it to perform any pre-drawing setup.

- `DirectConnected()` is called as soon as your module is in control of the screen, and then periodically whenever the display changes. It's also called when you're about to lose control of the screen.

- `DirectDraw()` draws to the screen by drawing directly to the frame buffer (in the manner of a BDirectWindow). It's called every `TickSize()` microseconds while your saver is in control.

- `Draw()` also draws to the screen, although not directly to the frame buffer. It's also called once every `TickSize()` microseconds. Typically, you implement `DirectDraw()` or `Draw()`, but not both. If you do implement both, `DirectDraw()` is called first.

- `StopSaver()` is called when the screen no longer needs to be saved, and just before the screen is restored to its former glory.

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

- Just after the `StartSaver()` call, you get a `StartConfig()` call that lets you set up ScreenSavers' configuration view.

- All drawing is done through `Draw()`—You don't get `DirectConnected()` or `DirectDraw()` calls.

- `StopConfig()`, called just after `StopSaver()`, lets you clean up the configuration view.

The following functions can be called at any time:

- `SupplyInfo()

  `
- `ModulesChanged()

  `
- `SaveState()

  `

#### 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).

`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.

### DirectDraw() 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();
                   }
               }
           }
       }

Screen Saver Table of Contents | Screen Saver Index

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

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