Setting window icons

This allows the developer to set window icons using the Settings object. These are then used as the window and alt-tab icons in three places:


  • SettingsDialog
  • JME display window
  • JOGL display window



    Note that I have coded some of it using reflection so that it continues to compile and run under JRE < 1.6 (just with the standard Java icon instead).



    Patch against current SVN (6757):



    [patch]

    Index: src/jogl2/com/jme3/system/jogl/JoglDisplay.java

    ===================================================================

    — src/jogl2/com/jme3/system/jogl/JoglDisplay.java (revision 6016)

    +++ src/jogl2/com/jme3/system/jogl/JoglDisplay.java (revision )

    @@ -41,6 +41,9 @@

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

    import java.lang.reflect.InvocationTargetException;

    +import java.lang.reflect.Method;

    +import java.util.Arrays;

    +import java.util.List;

    import java.util.concurrent.atomic.AtomicBoolean;

    import java.util.logging.Level;

    import java.util.logging.Logger;

    @@ -235,6 +238,15 @@

    frame.setResizable(false);

    frame.setFocusable(true);


  •    if (settings.getIcons() != null) {<br />
    
  •        try {<br />
    
  •            Method setIconImages = frame.getClass().getMethod(&quot;setIconImages&quot;, List.class);<br />
    
  •            setIconImages.invoke(frame, Arrays.asList(settings.getIcons()));<br />
    
  •        } catch (Exception e) {<br />
    
  •            e.printStackTrace();<br />
    
  •        }<br />
    
  •    }<br />
    

+

canvas.setSize(settings.getWidth(), settings.getHeight());

// only add canvas after frame is visible

contentPane.add(canvas, BorderLayout.CENTER);

Index: src/jogl/com/jme3/system/jogl/JoglDisplay.java

===================================================================

— src/jogl/com/jme3/system/jogl/JoglDisplay.java (revision 5910)

+++ src/jogl/com/jme3/system/jogl/JoglDisplay.java (revision )

@@ -42,6 +42,9 @@

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import java.lang.reflect.InvocationTargetException;

+import java.lang.reflect.Method;

+import java.util.Arrays;

+import java.util.List;

import java.util.concurrent.atomic.AtomicBoolean;

import java.util.logging.Level;

import java.util.logging.Logger;

@@ -94,6 +97,15 @@

frame.setResizable(false);

frame.setFocusable(true);


  •    if (settings.getIcons() != null) {<br />
    
  •        try {<br />
    
  •            Method setIconImages = frame.getClass().getMethod(&quot;setIconImages&quot;, List.class);<br />
    
  •            setIconImages.invoke(frame, Arrays.asList(settings.getIcons()));<br />
    
  •        } catch (Exception e) {<br />
    
  •            e.printStackTrace();<br />
    
  •        }<br />
    
  •    }<br />
    

+

// only add canvas after frame is visible

contentPane.add(canvas, BorderLayout.CENTER);

frame.pack();

Index: src/core/com/jme3/system/AppSettings.java

===================================================================

— src/core/com/jme3/system/AppSettings.java (revision 6709)

+++ src/core/com/jme3/system/AppSettings.java (revision )

@@ -31,6 +31,7 @@

*/

package com.jme3.system;



+import java.awt.image.BufferedImage;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

@@ -68,6 +69,7 @@

defaults.put("UseInput", true);

defaults.put("VSync", false);

defaults.put("FrameRate", -1);

  •    defaults.put(&quot;Icons&quot;, null);<br />
    

// disable these settings to benchmark speed
// defaults.put("VSync", true);
@@ -261,6 +263,23 @@
putBoolean("VSync", value);
}

+ /**
+ * Sets the application icons to be used, with the most preferred first.
+ * For Windows you should supply at least one 16x16 icon and one 32x32. The former is used for the title/task bar,
+ * the latter for the alt-tab icon.
+ * Linux (and similar platforms) expect one 32x32 icon.
+ * Mac OS X should be supplied one 128x128 icon.
+ * <br/>
+ * The icon is used for the settings window, and the LWJGL render window. Not currently supported for JOGL.
+ * Note that a bug in Java 6 (bug ID 6445278, currently hidden but available in Google cache) currently prevents
+ * the icon working for alt-tab on the settings dialog in Windows.
+ *
+ * @param value An array of BufferedImages to use as icons.
+ */
+ public void setIcons(BufferedImage[] value) {
+ put("Icons", value);
+ }
+
public int getFrameRate() {
return getInteger("FrameRate");
}
@@ -321,6 +340,10 @@
return getString("AudioRenderer");
}

+ public BufferedImage[] getIcons() {
+ return (BufferedImage[]) get("Icons");
+ }
+
public void setSettingsDialogImage(String path) {
settingsDialogImage = path;
}
Index: src/desktop/com/jme3/app/SettingsDialog.java
===================================================================
--- src/desktop/com/jme3/app/SettingsDialog.java (revision 6709)
+++ src/desktop/com/jme3/app/SettingsDialog.java (revision )
@@ -44,11 +44,13 @@
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
+import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
@@ -247,6 +249,8 @@
}
});

+ safeSetIconImages(Arrays.asList(source.getIcons()));
+
setTitle("Select Display Settings");

// The panels...
@@ -348,6 +352,25 @@
pack();
}

+ /* Access JDialog.setIconImages by reflection in case we're running on JRE < 1.6 */
+ private void safeSetIconImages(List<? extends Image> icons) {
+ try {
+ // Due to Java bug 6445278, we try to set icon on our shared owner frame first.
+ // Otherwise, our alt-tab icon will be the Java default under Windows.
+ Window owner = getOwner();
+ if (owner != null) {
+ Method setIconImages = owner.getClass().getMethod("setIconImages", List.class);
+ setIconImages.invoke(owner, icons);
+ return;
+ }
+
+ Method setIconImages = getClass().getMethod("setIconImages", List.class);
+ setIconImages.invoke(this, icons);
+ } catch (Exception e) {
+ return;
+ }
+ }
+
/**
* <code>verifyAndSaveCurrentSelection</code> first verifies that the
* display mode is valid for this system, and then saves the current
Index: src/lwjgl-ogl/com/jme3/system/lwjgl/LwjglDisplay.java
===================================================================
--- src/lwjgl-ogl/com/jme3/system/lwjgl/LwjglDisplay.java (revision 6602)
+++ src/lwjgl-ogl/com/jme3/system/lwjgl/LwjglDisplay.java (revision )
@@ -37,6 +37,10 @@
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import com.jme3.system.AppSettings;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -107,6 +111,9 @@
if (displayMode != null)
Display.setDisplayMode(displayMode);

+ if (settings.getIcons() != null)
+ Display.setIcon(imagesToByteBuffers(settings.getIcons()));
+
Display.setFullscreen(settings.isFullscreen());
Display.setVSyncEnabled(settings.isVSync());

@@ -133,6 +140,43 @@
}
}

+ private ByteBuffer[] imagesToByteBuffers(BufferedImage[] images) {
+ ByteBuffer[] out = new ByteBuffer[images.length];
+ for (int i = 0; i < images.length; i++) {
+ out = imageToByteBuffer(images);
+ }
+ return out;
+ }
+
+ private ByteBuffer imageToByteBuffer(BufferedImage image) {
+ if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) {
+ BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics2D g = convertedImage.createGraphics();
+ double width = image.getWidth() * (double) 1;
+ double height = image.getHeight() * (double) 1;
+ g.drawImage(image, (int) ((convertedImage.getWidth() - width) / 2),
+ (int) ((convertedImage.getHeight() - height) / 2),
+ (int) (width), (int) (height), null);
+ g.dispose();
+ image = convertedImage;
+ }
+
+ byte[] imageBuffer = new byte[image.getWidth() * image.getHeight() * 4];
+ int counter = 0;
+ for (int i = 0; i < image.getHeight(); i++) {
+ for (int j = 0; j < image.getWidth(); j++) {
+ int colorSpace = image.getRGB(j, i);
+ imageBuffer[counter + 0] = (byte) ((colorSpace << 8) >> 24);
+ imageBuffer[counter + 1] = (byte) ((colorSpace << 16) >> 24);
+ imageBuffer[counter + 2] = (byte) ((colorSpace << 24) >> 24);
+ imageBuffer[counter + 3] = (byte) (colorSpace >> 24);
+ counter += 4;
+ }
+ }
+ return ByteBuffer.wrap(imageBuffer);
+ }
+
+
public void create(boolean waitFor){
if (created.get()){
logger.warning("create() called when display is already created!");
[/patch]

Example usage:

[java]
try {
settings.setIcons(new BufferedImage[]{
ImageIO.read(getClass().getResourceAsStream("/res/misc/icon256.png")),
ImageIO.read(getClass().getResourceAsStream("/res/misc/icon128.png")),
ImageIO.read(getClass().getResourceAsStream("/res/misc/icon32.png")),
ImageIO.read(getClass().getResourceAsStream("/res/misc/icon16.png"))
});
}
catch (IOException e) {
log.log(java.util.logging.Level.WARNING, "Unable to load program icons", e);
}
[/java]
1 Like

Thanks! Also for making the effort to keep it 1.5 compatible :slight_smile:

Oops, these lines can be removed from the patch, since I worked around the bug by setting the icon on the (invisible) owner frame instead:



[patch]

  • * Note that a bug in Java 6 (bug ID 6445278, currently hidden but available in Google cache) currently prevents<br />
    
  • * the icon working for alt-tab on the settings dialog in Windows.<br />
    

[/patch]

Committed in revision 6781

http://code.google.com/p/jmonkeyengine/source/detail?r=6781



Thanks for this contribution