--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/awt/SystemTray.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,496 @@
+/*
+ * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.awt;
+
+import java.util.Vector;
+import java.awt.peer.SystemTrayPeer;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import sun.awt.AppContext;
+import sun.awt.SunToolkit;
+import sun.awt.HeadlessToolkit;
+import sun.security.util.SecurityConstants;
+
+/**
+ * The <code>SystemTray</code> class represents the system tray for a
+ * desktop. On Microsoft Windows it is referred to as the "Taskbar
+ * Status Area", on Gnome it is referred to as the "Notification
+ * Area", on KDE it is referred to as the "System Tray". The system
+ * tray is shared by all applications running on the desktop.
+ *
+ * <p> On some platforms the system tray may not be present or may not
+ * be supported, in this case {@link SystemTray#getSystemTray()}
+ * throws {@link UnsupportedOperationException}. To detect whether the
+ * system tray is supported, use {@link SystemTray#isSupported}.
+ *
+ * <p>The <code>SystemTray</code> may contain one or more {@link
+ * TrayIcon TrayIcons}, which are added to the tray using the {@link
+ * #add} method, and removed when no longer needed, using the
+ * {@link #remove}. <code>TrayIcon</code> consists of an
+ * image, a popup menu and a set of associated listeners. Please see
+ * the {@link TrayIcon} class for details.
+ *
+ * <p>Every Java application has a single <code>SystemTray</code>
+ * instance that allows the app to interface with the system tray of
+ * the desktop while the app is running. The <code>SystemTray</code>
+ * instance can be obtained from the {@link #getSystemTray} method.
+ * An application may not create its own instance of
+ * <code>SystemTray</code>.
+ *
+ * <p>The following code snippet demonstrates how to access
+ * and customize the system tray:
+ * <code>
+ * <pre>
+ * {@link TrayIcon} trayIcon = null;
+ * if (SystemTray.isSupported()) {
+ * // get the SystemTray instance
+ * SystemTray tray = SystemTray.{@link #getSystemTray};
+ * // load an image
+ * {@link java.awt.Image} image = {@link java.awt.Toolkit#getImage(String) Toolkit.getDefaultToolkit().getImage}(...);
+ * // create a action listener to listen for default action executed on the tray icon
+ * {@link java.awt.event.ActionListener} listener = new {@link java.awt.event.ActionListener ActionListener}() {
+ * public void {@link java.awt.event.ActionListener#actionPerformed actionPerformed}({@link java.awt.event.ActionEvent} e) {
+ * // execute default action of the application
+ * // ...
+ * }
+ * };
+ * // create a popup menu
+ * {@link java.awt.PopupMenu} popup = new {@link java.awt.PopupMenu#PopupMenu PopupMenu}();
+ * // create menu item for the default action
+ * MenuItem defaultItem = new MenuItem(...);
+ * defaultItem.addActionListener(listener);
+ * popup.add(defaultItem);
+ * /// ... add other items
+ * // construct a TrayIcon
+ * trayIcon = new {@link TrayIcon#TrayIcon(java.awt.Image, String, java.awt.PopupMenu) TrayIcon}(image, "Tray Demo", popup);
+ * // set the TrayIcon properties
+ * trayIcon.{@link TrayIcon#addActionListener(java.awt.event.ActionListener) addActionListener}(listener);
+ * // ...
+ * // add the tray image
+ * try {
+ * tray.{@link SystemTray#add(TrayIcon) add}(trayIcon);
+ * } catch (AWTException e) {
+ * System.err.println(e);
+ * }
+ * // ...
+ * } else {
+ * // disable tray option in your application or
+ * // perform other actions
+ * ...
+ * }
+ * // ...
+ * // some time later
+ * // the application state has changed - update the image
+ * if (trayIcon != null) {
+ * trayIcon.{@link TrayIcon#setImage(java.awt.Image) setImage}(updatedImage);
+ * }
+ * // ...
+ * </pre>
+ * </code>
+ *
+ * @since 1.6
+ * @see TrayIcon
+ *
+ * @author Bino George
+ * @author Denis Mikhalkin
+ * @author Sharon Zakhour
+ * @author Anton Tarasov
+ */
+public class SystemTray {
+ private static SystemTray systemTray;
+ private int currentIconID = 0; // each TrayIcon added gets a unique ID
+
+ transient private SystemTrayPeer peer;
+
+ /**
+ * Private <code>SystemTray</code> constructor.
+ *
+ */
+ private SystemTray() {
+ addNotify();
+ }
+
+ /**
+ * Gets the <code>SystemTray</code> instance that represents the
+ * desktop's tray area. This always returns the same instance per
+ * application. On some platforms the system tray may not be
+ * supported. You may use the {@link #isSupported} method to
+ * check if the system tray is supported.
+ *
+ * <p>If a SecurityManager is installed, the AWTPermission
+ * {@code accessSystemTray} must be granted in order to get the
+ * {@code SystemTray} instance. Otherwise this method will throw a
+ * SecurityException.
+ *
+ * @return the <code>SystemTray</code> instance that represents
+ * the desktop's tray area
+ * @throws UnsupportedOperationException if the system tray isn't
+ * supported by the current platform
+ * @throws HeadlessException if
+ * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
+ * @throws SecurityException if {@code accessSystemTray} permission
+ * is not granted
+ * @see #add(TrayIcon)
+ * @see TrayIcon
+ * @see #isSupported
+ * @see SecurityManager#checkPermission
+ * @see AWTPermission
+ */
+ public static SystemTray getSystemTray() {
+ checkSystemTrayAllowed();
+ if (GraphicsEnvironment.isHeadless()) {
+ throw new HeadlessException();
+ }
+
+ initializeSystemTrayIfNeeded();
+
+ if (!isSupported()) {
+ throw new UnsupportedOperationException(
+ "The system tray is not supported on the current platform.");
+ }
+
+ return systemTray;
+ }
+
+ /**
+ * Returns whether the system tray is supported on the current
+ * platform. In addition to displaying the tray icon, minimal
+ * system tray support includes either a popup menu (see {@link
+ * TrayIcon#setPopupMenu(PopupMenu)}) or an action event (see
+ * {@link TrayIcon#addActionListener(ActionListener)}).
+ *
+ * <p>Developers should not assume that all of the system tray
+ * functionality is supported. To guarantee that the tray icon's
+ * default action is always accessible, add the default action to
+ * both the action listener and the popup menu. See the {@link
+ * SystemTray example} for an example of how to do this.
+ *
+ * <p><b>Note</b>: When implementing <code>SystemTray</code> and
+ * <code>TrayIcon</code> it is <em>strongly recommended</em> that
+ * you assign different gestures to the popup menu and an action
+ * event. Overloading a gesture for both purposes is confusing
+ * and may prevent the user from accessing one or the other.
+ *
+ * @see #getSystemTray
+ * @return <code>false</code> if no system tray access is supported; this
+ * method returns <code>true</code> if the minimal system tray access is
+ * supported but does not guarantee that all system tray
+ * functionality is supported for the current platform
+ */
+ public static boolean isSupported() {
+ initializeSystemTrayIfNeeded();
+
+ if (Toolkit.getDefaultToolkit() instanceof SunToolkit) {
+
+ return ((SunToolkit)Toolkit.getDefaultToolkit()).isTraySupported();
+
+ } else if (Toolkit.getDefaultToolkit() instanceof HeadlessToolkit) {
+
+ return ((HeadlessToolkit)Toolkit.getDefaultToolkit()).isTraySupported();
+ }
+ return false;
+ }
+
+ /**
+ * Adds a <code>TrayIcon</code> to the <code>SystemTray</code>.
+ * The tray icon becomes visible in the system tray once it is
+ * added. The order in which icons are displayed in a tray is not
+ * specified - it is platform and implementation-dependent.
+ *
+ * <p> All icons added by the application are automatically
+ * removed from the <code>SystemTray</code> upon application exit
+ * and also when the desktop system tray becomes unavailable.
+ *
+ * @param trayIcon the <code>TrayIcon</code> to be added
+ * @throws NullPointerException if <code>trayIcon</code> is
+ * <code>null</code>
+ * @throws IllegalArgumentException if the same instance of
+ * a <code>TrayIcon</code> is added more than once
+ * @throws AWTException if the desktop system tray is missing
+ * @see #remove(TrayIcon)
+ * @see #getSystemTray
+ * @see TrayIcon
+ * @see java.awt.Image
+ */
+ public void add(TrayIcon trayIcon) throws AWTException {
+ if (trayIcon == null) {
+ throw new NullPointerException("adding null TrayIcon");
+ }
+ TrayIcon[] oldArray = null, newArray = null;
+ Vector<TrayIcon> icons = null;
+ synchronized (this) {
+ oldArray = systemTray.getTrayIcons();
+ icons = (Vector<TrayIcon>)AppContext.getAppContext().get(TrayIcon.class);
+ if (icons == null) {
+ icons = new Vector<TrayIcon>(3);
+ AppContext.getAppContext().put(TrayIcon.class, icons);
+
+ } else if (icons.contains(trayIcon)) {
+ throw new IllegalArgumentException("adding TrayIcon that is already added");
+ }
+ icons.add(trayIcon);
+ newArray = systemTray.getTrayIcons();
+
+ trayIcon.setID(++currentIconID);
+ }
+ try {
+ trayIcon.addNotify();
+ } catch (AWTException e) {
+ icons.remove(trayIcon);
+ throw e;
+ }
+ firePropertyChange("trayIcons", oldArray, newArray);
+ }
+
+ /**
+ * Removes the specified <code>TrayIcon</code> from the
+ * <code>SystemTray</code>.
+ *
+ * <p> All icons added by the application are automatically
+ * removed from the <code>SystemTray</code> upon application exit
+ * and also when the desktop system tray becomes unavailable.
+ *
+ * <p> If <code>trayIcon</code> is <code>null</code> or was not
+ * added to the system tray, no exception is thrown and no action
+ * is performed.
+ *
+ * @param trayIcon the <code>TrayIcon</code> to be removed
+ * @see #add(TrayIcon)
+ * @see TrayIcon
+ */
+ public void remove(TrayIcon trayIcon) {
+ if (trayIcon == null) {
+ return;
+ }
+ TrayIcon[] oldArray = null, newArray = null;
+ synchronized (this) {
+ oldArray = systemTray.getTrayIcons();
+ Vector<TrayIcon> icons = (Vector<TrayIcon>)AppContext.getAppContext().get(TrayIcon.class);
+ // TrayIcon with no peer is not contained in the array.
+ if (icons == null || !icons.remove(trayIcon)) {
+ return;
+ }
+ trayIcon.removeNotify();
+ newArray = systemTray.getTrayIcons();
+ }
+ firePropertyChange("trayIcons", oldArray, newArray);
+ }
+
+ /**
+ * Returns an array of all icons added to the tray by this
+ * application. You can't access the icons added by another
+ * application. Some browsers partition applets in different
+ * code bases into separate contexts, and establish walls between
+ * these contexts. In such a scenario, only the tray icons added
+ * from this context will be returned.
+ *
+ * <p> The returned array is a copy of the actual array and may be
+ * modified in any way without affecting the system tray. To
+ * remove a <code>TrayIcon</code> from the
+ * <code>SystemTray</code>, use the {@link
+ * #remove(TrayIcon)} method.
+ *
+ * @return an array of all tray icons added to this tray, or an
+ * empty array if none has been added
+ * @see #add(TrayIcon)
+ * @see TrayIcon
+ */
+ public TrayIcon[] getTrayIcons() {
+ Vector<TrayIcon> icons = (Vector<TrayIcon>)AppContext.getAppContext().get(TrayIcon.class);
+ if (icons != null) {
+ return (TrayIcon[])icons.toArray(new TrayIcon[icons.size()]);
+ }
+ return new TrayIcon[0];
+ }
+
+ /**
+ * Returns the size, in pixels, of the space that a tray icon will
+ * occupy in the system tray. Developers may use this methods to
+ * acquire the preferred size for the image property of a tray icon
+ * before it is created. For convenience, there is a similar
+ * method {@link TrayIcon#getSize} in the <code>TrayIcon</code> class.
+ *
+ * @return the default size of a tray icon, in pixels
+ * @see TrayIcon#setImageAutoSize(boolean)
+ * @see java.awt.Image
+ * @see TrayIcon#getSize()
+ */
+ public Dimension getTrayIconSize() {
+ return peer.getTrayIconSize();
+ }
+
+ /**
+ * Adds a {@code PropertyChangeListener} to the list of listeners for the
+ * specific property. The following properties are currently supported:
+ * <p> </p>
+ * <table border=1 summary="SystemTray properties">
+ * <tr>
+ * <th>Property</th>
+ * <th>Description</th>
+ * </tr>
+ * <tr>
+ * <td>{@code trayIcons}</td>
+ * <td>The {@code SystemTray}'s array of {@code TrayIcon} objects.
+ * The array is accessed via the {@link #getTrayIcons} method.<br>
+ * This property is changed when a tray icon is added to (or removed
+ * from) the system tray.<br> For example, this property is changed
+ * when the system tray becomes unavailable on the desktop<br>
+ * and the tray icons are automatically removed.</td>
+ * </tr>
+ * <tr>
+ * <td>{@code systemTray}</td>
+ * <td>This property contains {@code SystemTray} instance when the system tray
+ * is available or <code>null</code> otherwise.<br> This property is changed
+ * when the system tray becomes available or unavailable on the desktop.<br>
+ * The property is accessed by the {@link #getSystemTray} method.</td>
+ * </tr>
+ * </table>
+ * <p> </p>
+ * The {@code listener} listens to property changes only in this context.
+ * <p>
+ * If {@code listener} is {@code null}, no exception is thrown
+ * and no action is performed.
+ *
+ * @param propertyName the specified property
+ * @param listener the property change listener to be added
+ *
+ * @see #removePropertyChangeListener
+ * @see #getPropertyChangeListeners
+ */
+ public synchronized void addPropertyChangeListener(String propertyName,
+ PropertyChangeListener listener)
+ {
+ if (listener == null) {
+ return;
+ }
+ getCurrentChangeSupport().addPropertyChangeListener(propertyName, listener);
+ }
+
+ /**
+ * Removes a {@code PropertyChangeListener} from the listener list
+ * for a specific property.
+ * <p>
+ * The {@code PropertyChangeListener} must be from this context.
+ * <p>
+ * If {@code propertyName} or {@code listener} is {@code null} or invalid,
+ * no exception is thrown and no action is taken.
+ *
+ * @param propertyName the specified property
+ * @param listener the PropertyChangeListener to be removed
+ *
+ * @see #addPropertyChangeListener
+ * @see #getPropertyChangeListeners
+ */
+ public synchronized void removePropertyChangeListener(String propertyName,
+ PropertyChangeListener listener)
+ {
+ if (listener == null) {
+ return;
+ }
+ getCurrentChangeSupport().removePropertyChangeListener(propertyName, listener);
+ }
+
+ /**
+ * Returns an array of all the listeners that have been associated
+ * with the named property.
+ * <p>
+ * Only the listeners in this context are returned.
+ *
+ * @param propertyName the specified property
+ * @return all of the {@code PropertyChangeListener}s associated with
+ * the named property; if no such listeners have been added or
+ * if {@code propertyName} is {@code null} or invalid, an empty
+ * array is returned
+ *
+ * @see #addPropertyChangeListener
+ * @see #removePropertyChangeListener
+ */
+ public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
+ return getCurrentChangeSupport().getPropertyChangeListeners(propertyName);
+ }
+
+
+ // ***************************************************************
+ // ***************************************************************
+
+
+ /**
+ * Support for reporting bound property changes for Object properties.
+ * This method can be called when a bound property has changed and it will
+ * send the appropriate PropertyChangeEvent to any registered
+ * PropertyChangeListeners.
+ *
+ * @param propertyName the property whose value has changed
+ * @param oldValue the property's previous value
+ * @param newValue the property's new value
+ */
+ private void firePropertyChange(String propertyName,
+ Object oldValue, Object newValue)
+ {
+ if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
+ return;
+ }
+ getCurrentChangeSupport().firePropertyChange(propertyName, oldValue, newValue);
+ }
+
+ /**
+ * Returns the current PropertyChangeSupport instance for the
+ * calling thread's context.
+ *
+ * @return this thread's context's PropertyChangeSupport
+ */
+ private synchronized PropertyChangeSupport getCurrentChangeSupport() {
+ PropertyChangeSupport changeSupport =
+ (PropertyChangeSupport)AppContext.getAppContext().get(SystemTray.class);
+
+ if (changeSupport == null) {
+ changeSupport = new PropertyChangeSupport(this);
+ AppContext.getAppContext().put(SystemTray.class, changeSupport);
+ }
+ return changeSupport;
+ }
+
+ synchronized void addNotify() {
+ if (peer == null) {
+ peer = ((SunToolkit)Toolkit.getDefaultToolkit()).createSystemTray(this);
+ }
+ }
+
+ static void checkSystemTrayAllowed() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkPermission(SecurityConstants.ACCESS_SYSTEM_TRAY_PERMISSION);
+ }
+ }
+
+ private static void initializeSystemTrayIfNeeded() {
+ synchronized (SystemTray.class) {
+ if (systemTray == null) {
+ systemTray = new SystemTray();
+ }
+ }
+ }
+}