package org.limewire.ui.swing.dock; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import javax.swing.Icon; import javax.swing.JPanel; import org.limewire.service.ErrorService; import org.limewire.ui.swing.util.MacOSXUtils; import org.limewire.util.OSUtils; /** * A utility class to modify the Dock Icon and request * for user attention. */ public class Dock { private static final boolean HAS_DOCK; static { boolean hasDock = false; if (OSUtils.isMacOSX()) { try { System.loadLibrary("Dock"); hasDock = true; } catch (UnsatisfiedLinkError err) { ErrorService.error(err); } } HAS_DOCK = hasDock; } /** * These constants specify the level of severity of a user * attention request and are used by * {@link Dock#requestUserAttention(com.limegroup.gnutella.gui.Dock.AttentionType)} * and {@link Dock#cancelUserAttentionRequest(int)}. * * See the documentation for NSApplication and its Constants for * more information. */ public static enum AttentionType { /** * The Dock Icon will bounce until either the application * becomes active or the request is canceled. */ CRITICAL(0), /** * The Dock Icon will bounce for one second. The request, * though, remains active until either the application * becomes active or the request is canceled. * * NOTE: The Dock Icon will bounce like {@link #CRITICAL} * endlessly until either the application becomes active or * the request is canceled. */ INFORMATIONAL(10); private final int type; private AttentionType(int type) { this.type = type; } } /** * The width of the Dock Icon (128px). */ public static final int ICON_WIDTH = 128; /** * The height of the Dock Icon (128px). */ public static final int ICON_HEIGHT = 128; private Dock() { } /** * Returns the Lock the Dock is using to synchronize * access to this class. */ public static Object getDockLock() { return Dock.class; } /** * Replaces the current Dock Icon with the given Icon. * * @param icon The new Icon to be used in the Dock */ public synchronized static void setDockTileImage(Icon icon) { paintIcon(icon, false); } /** * Overlays the current Dock icon with the given Icon. * * @param icon The new overlay Icon */ public synchronized static void setDockTileOverlayImage(Icon icon) { paintIcon(icon, true); } /** * Paints the Icon, extracts the pixel data and passes it to * the native code which draws the Icon in the Dock. * * @param icon The new Icon * @param overlay Whether it's an overlay or replacement Icon */ private synchronized static void paintIcon(Icon icon, boolean overlay) { if (!HAS_DOCK) { return; } if (icon == null) { throw new NullPointerException("Icon is null"); } // We'll store the pixel in this Array and pass it // to the native methods later int[] pixel = new int[ICON_WIDTH * ICON_HEIGHT]; // We draw the Icon in this BufferedImage BufferedImage image = new BufferedImage(ICON_WIDTH, ICON_HEIGHT, BufferedImage.TYPE_INT_ARGB); // Setup a fake Component Component panel = new JPanel(); Dimension iconSize = new Dimension(ICON_WIDTH, ICON_HEIGHT); panel.setSize(iconSize); panel.setPreferredSize(iconSize); panel.setMinimumSize(iconSize); panel.setMaximumSize(iconSize); // Initialize the Image with the current pixel (zeros) image.setRGB(0, 0, ICON_WIDTH, ICON_HEIGHT, pixel, 0, ICON_WIDTH); // Create a Graphics Object and paint the Icon on it Graphics2D g = image.createGraphics(); try { icon.paintIcon(panel, g, 0, 0); } finally { g.dispose(); } // Get the pixel! image.getRGB(0, 0, ICON_WIDTH, ICON_HEIGHT, pixel, 0, ICON_WIDTH); // And draw the Icon! DrawDockTileImage(pixel, overlay, MacOSXUtils.getAppDir()); } /** * Restores the Dock Icon to its original state. */ public synchronized static void restoreDockTileImage() { if (HAS_DOCK) { RestoreApplicationDockTileImage(MacOSXUtils.getAppDir()); } } /** * Starts a user attention request. Calling this method has no * effect if the application is already active. The value returned * by this method can be used to manually cancel an attention * request. * * @param requestType The type of the attention request * @return request identifier */ public synchronized static int requestUserAttention(AttentionType requestType) { if (HAS_DOCK) { return RequestUserAttention(requestType.type); } return -1; } /** * Cancels a previous user attention request. A request is also canceled * automatically by user activation of the application. * * @param request The return value from a previous call to * {@link #requestUserAttention(com.limegroup.gnutella.gui.Dock.AttentionType)} */ public synchronized static void cancelUserAttentionRequest(int request) { if (HAS_DOCK) { CancelUserAttentionRequest(request); } } /** * Draws the Dock Tile Image. * * OverlayApplicationDockTileImage(CGImageRef) * SetApplicationDockTileImage(CGImageRef) */ private static final native void DrawDockTileImage(int[] icon, boolean overlay, String appDir); /** * Restores the Dock Tile Image. */ private static final native void RestoreApplicationDockTileImage(String appDir); /** * Starts an user attention request. */ private static final native int RequestUserAttention(int requestType); /** * Cancels an user attention request manually. */ private static final native void CancelUserAttentionRequest(int request); }