The Source for Java Technology Collaboration
User: Password:



   

Introducing JDesktop Integration Components, Part 2 Introducing JDesktop Integration Components, Part 2

by Joshua Marinacci
11/01/2004


Contents
What is the SaverBeans SDK?
A Simple Example
A Custom Screensaver
Adapting an Existing Program
Further Work
Conclusion
Resources

"Write once, run anywhere." This has been the mantra of Java developers since day one. The philosophy has given us great flexibility and power, but always with trade-offs. Certain types of programming have effectively been off-limits to Java developers because of the speed requirements or access to native services. Now, finally, things are looking better. JIT virtual machines and Moore's Law have taken care of the speed improvements and the new JDesktop Integration Components finally let Java developers write programs that tie closely to the native operating system. Part one of this series covered the desktop, file, browser, and system tray components. In this article, we will explore an entirely new area, the SaverBeans SDK, which lets us write screen savers entirely in Java. We will go from a simple example to adapting a particle simulator with user-supplied configuration.

What is the SaverBeans SDK?

A screensaver seems like a simple thing: just fill the screen with a pretty animation and you're done. Sadly, nothing in the world of computers is that simple. A screensaver must be packaged in a certain way for the host operating system to recognize it and launch it at the correct time. And, of course, every operating system has its own way of doing this. Since JDIC was already doing such a great job of unifying disparate platform-specific APIs, it was only logical to tackle this one as well. The SaverBeans SDK is an incubator project that provides a cross-platform API for accessing the screen, along with a packager tool to produce platform-specific executables. SaverBeans doesn't come with any screensavers, but there is a secondary project where various java.net citizens have posted their own creations.

In this article, you will learn how to build a simple countdown screensaver; what to download, how to create your classes, and how to package it all up. You will also see how to take an existing program and convert it into a screensaver, including user configuration.

I should mention at this point that SaverBeans supports Windows, Linux, and Solaris, but not the Mac. The SaverBeans API uses native code underneath to do its magic, and no one has written a hook into the OS X screensaver API yet. If you know a little bit about native OS X programming, then please join the JDIC project and help out.

A Simple Example

Now that we have all of that out of the way, let's go make some screensavers. For the first one I've chosen something simple: a Christmas countdown timer. Every time you activate the screensaver, your computer will display the time left until Christmas morning, with the millisecond accuracy that anxious eight-year-olds demand.

First of all, you will need to download the SDK from the SaverBeans project page. This .zip file includes both the SDK itself and a sample screensaver you can compile and run. The native libraries have already been compiled so you won't need any native tools or C compilers to get started. You will need Ant and a recent JDK, though: 1.4 for Windows and 1.5 for Linux (due to some animation problems with 1.4 for Linux). Unzip this file and you will have a directory containing the main .jars, plus a second .zip file, saverbeans-startup.zip, which contains the sample screensaver.

I will only cover the Windows instructions here, but the documentation contains similar instructions for Linux. The only major difference is where you put the resulting screensaver executable.

Unzip the file and go into saverbeans-startup, and then copy the build.properties.sample file to build.properties. Edit the properties file and change the saverbeans.path property to point to where you have the saverbeans-ant.jar file (usually ..). Now type ant dist, which compiles the code, moves your program resources to platform directories (currently one each for Windows, Solaris, and Linux), then builds a custom executable (a .scr file, under Windows) that launches the screensaver class files. Copy the contents of dist/bouncingline-win32 to your C:/windows/system32 directory. Now head to the display properties control panel, and select the bouncingline screensaver. If all goes well, you will see a small preview in the mini-window of a bouncing line, as seen in Figure 1.

Figure 1. Bouncinglines preview
Figure 1. Bouncinglines preview

A Custom Screensaver

Now let's make our own! Here's the beginning:

package org.joshy.screensavers;

import org.jdesktop.jdic.screensaver.*;
import org.joda.time.*;
import java.awt.*;
import java.io.*;

public class XmasCountdown extends SimpleScreensaver {
    DateTime xmas;
    Duration old_dur;
    boolean first;
    
    public void init() {
        xmas = new DateTime(2004,12,25,5,40,0,0);
        DateTime now = new DateTime();
        old_dur = new Duration(DurationType.getDayHourType(),
                               now,xmas);
        first = true;
    }

The SaverBeans API is quite simple. Just subclass the SimpleScreensaver class in the org.jdesktop.jdic.screensaver package, and then override two methods. In the first method, init(), I have used a special DateTime class from the Joda project. Joda is a set of date and time utilities that replace the default Date and Calendar classes in Java. I chose to use Joda because it makes calculating the distance between two dates much easier than the standard Calendar class. In the init method, I created a timestamp for Christmas at 5:40 in the morning, which is about the time I used to get up as a child. I've also stored the initial distance between now and Christmas in a Duration object, old_dur. The Boolean, first, tells the paint method that it has just been initialized so that it knows to redraw the entire screen. The paint method is below:

public void paint(Graphics g) {
    DateTime now = new DateTime();
    Duration dur =
        new Duration(DurationType.getDayHourType(),
                     now,xmas);
    
    // get the screen size and clear the screen
    Component c = getContext().getComponent();
    int w = c.getWidth();
    int h = c.getHeight();
    
    ((Graphics2D)g).setRenderingHint(
        RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    Font font = new Font("SansSerif",Font.PLAIN,50);
    g.setFont(font);
    
    // draw the header text
    g.setColor(Color.green);
    if(first) { g.drawString("Countdown to Christmas",10,50); }
                
    drawText(g,"Days: ", dur.getDays(), 
        old_dur.getDays(),150);
    drawText(g,"Hours: ", dur.getHours(), 
        old_dur.getHours(),200);
    drawText(g,"Minutes: ", dur.getMinutes(), 
        old_dur.getMinutes(),250);
    drawText(g,"Seconds: ", dur.getSeconds(), 
        old_dur.getSeconds(),300);
    drawText(g,"MilliSeconds: ", dur.getMillis(), 
        old_dur.getMillis(),350);
    
    old_dur = dur;
    first = false;
}

I'll go through this step by step. The first two lines calculate the distance between the current time and Christmas. Next, it pulls out a reference to the drawing component via the context and calculates the width and height of the screen. After that it turns on anti-aliasing, sets up a large font, and then draws the title "Countdown to Christmas" in green. The title is only drawn on the first pass so that we don't have to erase and redraw it each time. The rest of the paint method draws each part of the time until Christmas on its own line in red using the drawText method. Finally we update the old_dur and first variables for the next time paint() is called.

To get this class running as a screensaver, we have to tell Ant about our new class and .jar. Start by modifying the screensaver and screensaver.class properties at the top of the build.xml file.

If you need extra .jars for your screensaver, like mine does, then things get a bit tricker. Due to a limitation in the launching system, a SaverBeans screensaver cannot specify a complete classpath. Instead, it hands Java the name of a .jar from which to load the main class. I modified the manifest of my main .jar to automatically include the support .jars, like this:

Manifest-Version: 1.0
Main-Class: org.joshy.screensaver.XmasCountdown
Class-Path: joda-time-0.95.jar

To get this manifest into the .jar, I modified the jar task in the dist target like this:

<jar destfile="${build}/jar/${screensaver}.jar"
        manifest="src/conf/MANIFEST.MF">
    <fileset dir="${build}/share" />
</jar>;

There is only one last thing to do. Each screensaver has a config file, stored in the src/conf directory. I copied the default one into xmascountdown.xml and changed the .jars and classes to match the new screensaver.

<?xml version="1.0" encoding="UTF-8"?>

<screensaver name="xmascount" 
    _label="Countdown to Christmas">
    
    <command arg="-root"/>
    <command arg="-jar xmascount.jar"/>
    <command arg="-cp joda-time-0.95.jar;xmascount.jar"/>
    <command 
    arg="-class org.joshy.screensavers.XmasCountdown"/>
    <file id="jdkhome" _label="Java Home (blank=auto)" 
    arg="-jdkhome %" />

    <_description> This screensaver counts down,
    with great precision, the amount of time left until
    the magic day, defined as just a hair after
    midnight Christmas Eve. </_description>

</screensaver>

Some of the elements may look a little strange, like the _description, for example. That is because this is actually the configuration file for XScreenSaver, the gold standard of Unix screensaver programs. Under Linux and Solaris, this file is used directly to launch the program and create a settings screen. Since Windows just uses .scr executables, SaverBeans will parse this and generate a settings screen internally. Though this part is a bit complicated, for the most part, you can set it up once and forget about it.

Now run ant clean dist again and your new screensaver will be placed in the dist/xmascount-win32 directory. Copy the contents (xmascountdown.scr and the three .jar files) to C:/windows/system32 and your screensaver is ready to go. It should look something like Figure 2.

Figure 2. Countdown To Christmas Screensaver
Figure 2. Countdown To Christmas Screensaver

Pages: 1, 2

Next Page » 

Related Articles

Java Sketchbook: Getting Started With Scripting
Programs that expose themselves to programming by the user are few and far between--an Emacs Lisp macro here, an AppleScript-able Mac app there. It's a pity, since scriptability gives users great power. With Java, embedding JavaScript as a scripting language is pretty easy. Joshua Marinacci shows how it can be done.

View all java.net Articles.

 Feed java.net RSS Feeds