VM interface changes for splash-screen support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hey all,
So it seems AWT in 1.6 will include support for splash-screens.
This will require a little (optional) VM support, so here's a proposal
and some prototype code for this I'd like feedback on.

This is done by either:
1) Giving the VM a command line option and filename (JPEG/GIF/PNG is
supported)
2) Including such an image in a JAR and using an option in the manifest.
(In the case of both, the former has precedence.)

The idea is that the splashscreen should be loaded and shown as quickly
as possible. Once the first AWT window is opened by the app, the
splashscreen is closed. But once user code is running the program can
update the splashscreen prior to that, using a new SplashScreen class.

* For VM implementors:
Ok, so I've got a proposal for how to do this. For the VM part, 
see splashscreen.h. There are two native functions to call:
 int cp_awt_splashscreen_load_file( char *filename );
 int cp_awt_splashscreen_load_data( char *url, char *imagedata );

Corresponding to loading from the command line and from a jar,
respectively. These methods should load the file, create a frameless
window, display it, and return as fast as they can, using the
native toolkit instead of java.

Strictly speaking we only need one function, but since the 
command-line option takes precedence we can use that to show
the splash earlier. On failure, the VM can display a message
or silently ignore it. 

* For peer implementors:
A new ClasspathToolkit method:
public abstract SplashWindow getSplashWindow();

The public SplashScreen class is implemented on top
of our SplashWindow class. This is more or less an ordinary
Window. But more on this later, first the native side of things:

The native methods above set a global variable (cp_splashscreen) which
is a struct splashscreenhandle
{
  void *nativeWindowHandle;
  void *nativeImageHandle;
}
If set (the variable is null if no splashscreen is available
or if loading failed), the structure should be populated with
platform-specific values for the window handle and image data.
On X/GTK/Qt, this should be understood to mean XIDs for the
window and a pixmap, respectively. NOT a toolkit-specific
structure (See below). On Windows (athough we don't have peers 
for that yet) it'd be a HWND and HBITMAP, and so on.

The reason why we want to use X structures here is this:
We cannot know from the start which set of peers the user
is using, and therefore we don't know which peers will want
to create the SplashWindow instance. 

The idea here is that the native splashscreen code should be compiled 
to use the default toolkit (or none). If the user has chosen a
different toolkit at runtime, the thing should still work.

Q and A..

Q: What does the peer need to do, then? 
A: Implement getSplashWindow. What this should do, is retrive
the cp_splashscreen structure and use the X handles to wrap it 
in the native toolit (e.g. gdk_window_foreign_new on GTK). This 
object should then be wrapped with a WindowPeer from which a
SplashWindow implementation can be created. (This is a lot less
code than it sounds like)

Q: What does the VM need to do, then?
A: Nothing. But if it wants splashscreens it should. Call
cp_awt_splashscreen_load_file or cp_awt_splashscreen_load_data,
and do so as soon as it can (after parsing the command line and reading
the jar manifest, respectively).

Q: Native toolkit?! But what about JNode/IKVM/Other pure-java peers?
A: In those cases the VM is already loaded, or will need to be. In which
case displaying a splash-screen during VM loading is rather pointless.
However, a pure-java implementation which the VM can show at some point
of its choice is simple to do, and should be done.

/Sven
/******** PROTOTYPE CODE ***************/

/* SplashScreen.java -- 
   Copyright (C) 2006 Free Software Foundation

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

package java.awt;

import gnu.java.awt.ClasspathToolkit;
import gnu.java.awt.SplashWindow;

public final class SplashScreen
{
  private static SplashScreen splash;

  /**
   * Get the native splashscreen object.
   */
  static
  {
    SplashWindow win = ((ClasspathToolkit)Toolkit.getDefaultToolkit())
      .getSplashWindow();
    if( win != null )
      splash = new SplashScreen( win );
  }

  public static SplashScreen getSplashScreen()
  {
    return splash;
  }

  /**
   * The SplashScreen window.
   */
  private SplashWindow win;

  /**
   * Constructor used by the static code above.
   */
  private SplashScreen(SplashWindow win)
  {
    this.win = win;
  }

  public void close()
  {
    if( win == null ) 
      throw new IllegalStateException("SplashScreen instance closed.");
    win.hide();
    win.dispose();
    win = null;
  }

  public Graphics2D createGraphics()
  {
    if( win == null ) 
      throw new IllegalStateException("SplashScreen instance closed.");
    return win.createGraphics();
  }

  public Rectangle getBounds()
  {
    if( win == null ) 
      throw new IllegalStateException("SplashScreen instance closed.");
    return win.getBounds();
  }

  public URL getImageURL()
  {
    if( win == null ) 
      throw new IllegalStateException("SplashScreen instance closed.");
    return win.getImageURL();
  }

  public Dimension getSize()
  {
    if( win == null ) 
      throw new IllegalStateException("SplashScreen instance closed.");

    return win.getSize();
  }

  public boolean isVisible()
  {
    if( win == null ) 
      throw new IllegalStateException("SplashScreen instance closed.");
    return win.isVisible();
  }

  public void setImageURL(URL imageURL)
  {
    if( win == null ) 
      throw new IllegalStateException("SplashScreen instance closed.");
    win.setImageURL( imageURL );
  }

  public void update()
  {
    if( win == null ) 
      throw new IllegalStateException("SplashScreen instance closed.");
    win.update();
  }
}
/******** PROTOTYPE CODE ***************/

/* SplashWindow.java -- 
   Copyright (C) 2006 Free Software Foundation

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

package gnu.java.awt;

import java.awt.peer.ComponentPeer;
import java.awt.Rectangle;
import java.awt.Component;
import java.awt.Image;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Window;
import java.net.URL;

public abstract class SplashWindow extends Window
{
  private URL imageURL;
  private Image image;
  private Image overlay;
  private int w, h;

  public SplashWindow( ComponentPeer peer, URL imageURL, Image img )
  {
    this.peer = peer;
    // splashscreens are visible by the time the object is created.
    this.visible = true; 
    setAlwaysOnTop( true ); // (they already should be)

    this.imageURL = imageURL;
    this.image = img;
    createOverlay();
  }

  private void createOverlay()
  {
    w = image.getWidth( null );
    h = image.getHeight( null );
    overlay = createImage( w, h );
    Graphics g = overlay.getGraphics();
    g.setColor(0, 0, 0, 0); // fill transparent
    g.fillRect(0, 0, w, h);
  }

  public Graphics2D createGraphics()
  {
    Graphics g = overlay.getGraphics();
    g.setColor(0, 0, 0, 0); // fill transparent
    g.fillRect(0, 0, w, h);
    return (Graphics2D)g;
  }

  public void paint( Graphics g )
  {
    g.drawImage( image, 0, 0, null );
    g.drawImage( overlay, 0, 0, null );
  }

  public URL getImageURL()
  {
    return imageURL;
  }

  public void setImageURL(URL imageURL)
  {
    // Load the image
    Image newImage = Toolkit.getDefaultToolkit().createImage( imageURL );

    // Center on screen
    int w = newImage.getWidth( null );
    int h = newImage.getHeight( null );

    Rectangle screenBounds = GraphicsEnvironment.getLocalGraphicsEnvironment().
      getDefaultScreenDevice().getDefaultConfiguration().getBounds();
    
    Rectangle windowBounds = new Rectangle();
    windowBounds.x = screenBounds.x + ((screenBounds.width - w) >> 1);
    windowBounds.y = screenBounds.y + ((screenBounds.height - h) >> 1);
    windowBounds.width = w;
    windowBounds.height = h;
    setBounds( windowBounds );

    this.imageURL = imageURL;
    createOverlay();
  }

  public void update()
  {
    repaint();
  }
}
#ifndef __SPLASHSCREEN_H__
#define __SPLASHSCREEN_H__

struct splashscreenhandle
{
  void *nativeWindowHandle;
  void *nativeImageHandle;
};

/**
 * Global variable
 */
extern struct splashscreenhandle cp_splashscreen;

/**
 * Loads the splashscreen from a file.
 * filename is a null-terminated string 
 * The return value is zero on success, nonzero otherwise.
 */
int cp_awt_splashscreen_load_file( char *filename );

/**
 * Loads an image from data. The data can and should be freed by the VM
 * afterwards. The image URL is only for passing on to the interface,
 * it is not used by the code.
 *
 * url is a null-terminated utf-8 string 
 * imagedata is a pointer to the image file data.
 * The return value is zero on success, nonzero otherwise.
 */
int cp_awt_splashscreen_load_data( char *url, void *imagedata );

#endif 

[Index of Archives]     [Linux Kernel]     [Linux Cryptography]     [Fedora]     [Fedora Directory]     [Red Hat Development]

  Powered by Linux