KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > SystemTray


1 /*
2  * Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved. Use is
3  * subject to license terms.
4  */

5
6 package java.awt;
7
8 import java.util.Vector JavaDoc;
9 import java.awt.peer.SystemTrayPeer;
10 import java.beans.PropertyChangeListener JavaDoc;
11 import java.beans.PropertyChangeSupport JavaDoc;
12 import sun.awt.AppContext;
13 import sun.awt.SunToolkit;
14 import sun.awt.HeadlessToolkit;
15 import sun.security.util.SecurityConstants;
16
17 /**
18  * The <code>SystemTray</code> class represents the system tray for a
19  * desktop. On Microsoft Windows it is referred to as the "Taskbar
20  * Status Area", on Gnome it is referred to as the "Notification
21  * Area", on KDE it is referred to as the "System Tray". The system
22  * tray is shared by all applications running on the desktop.
23  *
24  * <p> On some platforms the system tray may not be present or may not
25  * be supported, in this case {@link SystemTray#getSystemTray()}
26  * throws {@link UnsupportedOperationException}. To detect whether the
27  * system tray is supported, use {@link SystemTray#isSupported}.
28  *
29  * <p>The <code>SystemTray</code> may contain one or more {@link
30  * TrayIcon TrayIcons}, which are added to the tray using the {@link
31  * #add} method, and removed when no longer needed, using the
32  * {@link #remove}. <code>TrayIcon</code> consists of an
33  * image, a popup menu and a set of associated listeners. Please see
34  * the {@link TrayIcon} class for details.
35  *
36  * <p>Every Java application has a single <code>SystemTray</code>
37  * instance that allows the app to interface with the system tray of
38  * the desktop while the app is running. The <code>SystemTray</code>
39  * instance can be obtained from the {@link #getSystemTray} method.
40  * An application may not create its own instance of
41  * <code>SystemTray</code>.
42  *
43  * <p>The following code snippet demonstrates how to access
44  * and customize the system tray:
45  * <code>
46  * <pre>
47  * {@link TrayIcon} trayIcon = null;
48  * if (SystemTray.isSupported()) {
49  * // get the SystemTray instance
50  * SystemTray tray = SystemTray.{@link #getSystemTray};
51  * // load an image
52  * {@link java.awt.Image} image = {@link java.awt.Toolkit#getImage(String) Toolkit.getDefaultToolkit.getImage}(...);
53  * // create a action listener to listen for default action executed on the tray icon
54  * {@link java.awt.event.ActionListener} listener = new {@link java.awt.event.ActionListener ActionListener}() {
55  * public void {@link java.awt.event.ActionListener#actionPerformed actionPerformed}({@link java.awt.event.ActionEvent} e) {
56  * // execute default action of the application
57  * // ...
58  * }
59  * };
60  * // create a popup menu
61  * {@link java.awt.PopupMenu} popup = new {@link java.awt.PopupMenu#PopupMenu PopupMenu}();
62  * // create menu item for the default action
63  * MenuItem defaultItem = new MenuItem(...);
64  * defaultItem.addActionListener(listener);
65  * popup.add(defaultItem);
66  * /// ... add other items
67  * // construct a TrayIcon
68  * trayIcon = new {@link TrayIcon#TrayIcon(java.awt.Image, String, java.awt.PopupMenu) TrayIcon}(image, "Tray Demo", popup);
69  * // set the TrayIcon properties
70  * trayIcon.{@link TrayIcon#addActionListener(java.awt.event.ActionListener) addActionListener}(listener);
71  * // ...
72  * // add the tray image
73  * try {
74  * tray.{@link SystemTray#add(TrayIcon) add}(trayIcon);
75  * } catch (AWTException e) {
76  * System.err.println(e);
77  * }
78  * // ...
79  * } else {
80  * // disable tray option in your application or
81  * // perform other actions
82  * ...
83  * }
84  * // ...
85  * // some time later
86  * // the application state has changed - update the image
87  * if (trayIcon != null) {
88  * trayIcon.{@link TrayIcon#setImage(java.awt.Image) setImage}(updatedImage);
89  * }
90  * // ...
91  * </pre>
92  * </code>
93  *
94  * @since 1.6
95  * @see TrayIcon
96  *
97  * @author Bino George
98  * @author Denis Mikhalkin
99  * @author Sharon Zakhour
100  * @author Anton Tarasov
101  */

102 public class SystemTray {
103     private static SystemTray JavaDoc systemTray;
104     private int currentIconID = 0; // each TrayIcon added gets a unique ID
105

106     transient private SystemTrayPeer peer;
107
108     /**
109      * Private <code>SystemTray</code> constructor.
110      *
111      */

112     private SystemTray() {
113         addNotify();
114     }
115
116     /**
117      * Gets the <code>SystemTray</code> instance that represents the
118      * desktop's tray area. This always returns the same instance per
119      * application. On some platforms the system tray may not be
120      * supported. You may use the {@link #isSupported} method to
121      * check if the system tray is supported.
122      *
123      * <p>If a SecurityManager is installed, the AWTPermission
124      * {@code accessSystemTray} must be granted in order to get the
125      * {@code SystemTray} instance. Otherwise this method will throw a
126      * SecurityException.
127      *
128      * @return the <code>SystemTray</code> instance that represents
129      * the desktop's tray area
130      * @throws UnsupportedOperationException if the system tray isn't
131      * supported by the current platform
132      * @throws HeadlessException if
133      * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
134      * @throws SecurityException if {@code accessSystemTray} permission
135      * is not granted
136      * @see #add(TrayIcon)
137      * @see TrayIcon
138      * @see #isSupported
139      * @see SecurityManager#checkPermission
140      * @see AWTPermission
141      */

142     public static SystemTray JavaDoc getSystemTray() {
143         checkSystemTrayAllowed();
144         if (GraphicsEnvironment.isHeadless()) {
145             throw new HeadlessException JavaDoc();
146         }
147
148         initializeSystemTrayIfNeeded();
149
150         if (!isSupported()) {
151             throw new UnsupportedOperationException JavaDoc(
152                 "The system tray is not supported on the current platform.");
153         }
154
155         return systemTray;
156     }
157
158     /**
159      * Returns whether the system tray is supported on the current
160      * platform. In addition to displaying the tray icon, minimal
161      * system tray support includes either a popup menu (see {@link
162      * TrayIcon#setPopupMenu(PopupMenu)}) or an action event (see
163      * {@link TrayIcon#addActionListener(ActionListener)}).
164      *
165      * <p>Developers should not assume that all of the system tray
166      * functionality is supported. To guarantee that the tray icon's
167      * default action is always accessible, add the default action to
168      * both the action listener and the popup menu. See the {@link
169      * SystemTray example} for an example of how to do this.
170      *
171      * <p><b>Note</b>: When implementing <code>SystemTray</code> and
172      * <code>TrayIcon</code> it is <em>strongly recommended</em> that
173      * you assign different gestures to the popup menu and an action
174      * event. Overloading a gesture for both purposes is confusing
175      * and may prevent the user from accessing one or the other.
176      *
177      * @see #getSystemTray
178      * @return <code>false</code> if no system tray access is supported; this
179      * method returns <code>true</code> if the minimal system tray access is
180      * supported but does not guarantee that all system tray
181      * functionality is supported for the current platform
182      */

183     public static boolean isSupported() {
184         initializeSystemTrayIfNeeded();
185
186         if (Toolkit.getDefaultToolkit() instanceof SunToolkit) {
187
188             return ((SunToolkit)Toolkit.getDefaultToolkit()).isTraySupported();
189
190         } else if (Toolkit.getDefaultToolkit() instanceof HeadlessToolkit) {
191
192             return ((HeadlessToolkit)Toolkit.getDefaultToolkit()).isTraySupported();
193         }
194         return false;
195     }
196
197     /**
198      * Adds a <code>TrayIcon</code> to the <code>SystemTray</code>.
199      * The tray icon becomes visible in the system tray once it is
200      * added. The order in which icons are displayed in a tray is not
201      * specified - it is platform and implementation-dependent.
202      *
203      * <p> All icons added by the application are automatically
204      * removed from the <code>SystemTray</code> upon application exit
205      * and also when the desktop system tray becomes unavailable.
206      *
207      * @param trayIcon the <code>TrayIcon</code> to be added
208      * @throws NullPointerException if <code>trayIcon</code> is
209      * <code>null</code>
210      * @throws IllegalArgumentException if the same instance of
211      * a <code>TrayIcon</code> is added more than once
212      * @throws AWTException if the desktop system tray is missing
213      * @see #remove(TrayIcon)
214      * @see #getSystemTray
215      * @see TrayIcon
216      * @see java.awt.Image
217      */

218     public void add(TrayIcon JavaDoc trayIcon) throws AWTException JavaDoc {
219         if (trayIcon == null) {
220             throw new NullPointerException JavaDoc("adding null TrayIcon");
221         }
222         TrayIcon JavaDoc[] oldArray = null, newArray = null;
223         Vector JavaDoc<TrayIcon JavaDoc> icons = null;
224         synchronized (this) {
225             oldArray = systemTray.getTrayIcons();
226             icons = (Vector JavaDoc<TrayIcon JavaDoc>)AppContext.getAppContext().get(TrayIcon JavaDoc.class);
227             if (icons == null) {
228                 icons = new Vector JavaDoc<TrayIcon JavaDoc>(3);
229                 AppContext.getAppContext().put(TrayIcon JavaDoc.class, icons);
230                 
231             } else if (icons.contains(trayIcon)) {
232                 throw new IllegalArgumentException JavaDoc("adding TrayIcon that is already added");
233             }
234             icons.add(trayIcon);
235             newArray = systemTray.getTrayIcons();
236
237             trayIcon.setID(++currentIconID);
238         }
239         try {
240             trayIcon.addNotify();
241         } catch (AWTException JavaDoc e) {
242             icons.remove(trayIcon);
243             throw e;
244         }
245         firePropertyChange("trayIcons", oldArray, newArray);
246     }
247
248     /**
249      * Removes the specified <code>TrayIcon</code> from the
250      * <code>SystemTray</code>.
251      *
252      * <p> All icons added by the application are automatically
253      * removed from the <code>SystemTray</code> upon application exit
254      * and also when the desktop system tray becomes unavailable.
255      *
256      * <p> If <code>trayIcon</code> is <code>null</code> or was not
257      * added to the system tray, no exception is thrown and no action
258      * is performed.
259      *
260      * @param trayIcon the <code>TrayIcon</code> to be removed
261      * @see #add(TrayIcon)
262      * @see TrayIcon
263      */

264     public void remove(TrayIcon JavaDoc trayIcon) {
265         if (trayIcon == null) {
266             return;
267         }
268         TrayIcon JavaDoc[] oldArray = null, newArray = null;
269         synchronized (this) {
270             oldArray = systemTray.getTrayIcons();
271             Vector JavaDoc<TrayIcon JavaDoc> icons = (Vector JavaDoc<TrayIcon JavaDoc>)AppContext.getAppContext().get(TrayIcon JavaDoc.class);
272             // TrayIcon with no peer is not contained in the array.
273
if (icons == null || !icons.remove(trayIcon)) {
274                 return;
275             }
276             trayIcon.removeNotify();
277             newArray = systemTray.getTrayIcons();
278         }
279         firePropertyChange("trayIcons", oldArray, newArray);
280     }
281
282     /**
283      * Returns an array of all icons added to the tray by this
284      * application. You can't access the icons added by another
285      * application. Some browsers partition applets in different
286      * code bases into separate contexts, and establish walls between
287      * these contexts. In such a scenario, only the tray icons added
288      * from this context will be returned.
289      *
290      * <p> The returned array is a copy of the actual array and may be
291      * modified in any way without affecting the system tray. To
292      * remove a <code>TrayIcon</code> from the
293      * <code>SystemTray</code>, use the {@link
294      * #remove(TrayIcon)} method.
295      *
296      * @return an array of all tray icons added to this tray, or an
297      * empty array if none has been added
298      * @see #add(TrayIcon)
299      * @see TrayIcon
300      */

301     public TrayIcon JavaDoc[] getTrayIcons() {
302         Vector JavaDoc<TrayIcon JavaDoc> icons = (Vector JavaDoc<TrayIcon JavaDoc>)AppContext.getAppContext().get(TrayIcon JavaDoc.class);
303         if (icons != null) {
304             return (TrayIcon JavaDoc[])icons.toArray(new TrayIcon JavaDoc[icons.size()]);
305         }
306         return new TrayIcon JavaDoc[0];
307     }
308
309     /**
310      * Returns the size, in pixels, of the space that a tray icon will
311      * occupy in the system tray. Developers may use this methods to
312      * acquire the preferred size for the image property of a tray icon
313      * before it is created. For convenience, there is a similar
314      * method {@link TrayIcon#getSize} in the <code>TrayIcon</code> class.
315      *
316      * @return the default size of a tray icon, in pixels
317      * @see TrayIcon#setImageAutoSize(boolean)
318      * @see java.awt.Image
319      * @see TrayIcon#getSize()
320      */

321     public Dimension JavaDoc getTrayIconSize() {
322         return peer.getTrayIconSize();
323     }
324
325     /**
326      * Adds a {@code PropertyChangeListener} to the listener list for a
327      * specific property. Currently supported property:
328      * <ul>
329      * <li>{@code trayIcons}<p>
330      * <p>
331      * This {@code SystemTray}'s array of {@code TrayIcon}s.
332      * The array is accessed via {@link SystemTray#getTrayIcons}.<br>
333      * This property is changed when a {@code TrayIcon} is added to
334      * (or removed from) the {@code SystemTray}.<br> For example, this property
335      * is changed when the native {@code SystemTray} becomes unavailable on the
336      * desktop<br> and the {@code TrayIcon}s are automatically removed.</li>
337      * </ul>
338      * <p>
339      * The {@code listener} listens to property changes only in this context.
340      * <p>
341      * If {@code listener} is {@code null}, no exception is thrown
342      * and no action is performed.
343      *
344      * @param propertyName the specified property
345      * @param listener the property change listener to be added
346      *
347      * @see #removePropertyChangeListener
348      * @see #getPropertyChangeListeners
349      */

350     public synchronized void addPropertyChangeListener(String JavaDoc propertyName,
351                                                        PropertyChangeListener JavaDoc listener)
352     {
353         if (listener == null) {
354             return;
355         }
356         getCurrentChangeSupport().addPropertyChangeListener(propertyName, listener);
357     }
358
359     /**
360      * Removes a {@code PropertyChangeListener} from the listener list
361      * for a specific property.
362      * <p>
363      * The {@code PropertyChangeListener} must be from this context.
364      * <p>
365      * If {@code propertyName} or {@code listener} is {@code null} or invalid,
366      * no exception is thrown and no action is taken.
367      *
368      * @param propertyName the specified property
369      * @param listener the PropertyChangeListener to be removed
370      *
371      * @see #addPropertyChangeListener
372      * @see #getPropertyChangeListeners
373      */

374     public synchronized void removePropertyChangeListener(String JavaDoc propertyName,
375                                                           PropertyChangeListener JavaDoc listener)
376     {
377         if (listener == null) {
378             return;
379         }
380         getCurrentChangeSupport().removePropertyChangeListener(propertyName, listener);
381     }
382
383     /**
384      * Returns an array of all the listeners that have been associated
385      * with the named property.
386      * <p>
387      * Only the listeners in this context are returned.
388      *
389      * @param propertyName the specified property
390      * @return all of the {@code PropertyChangeListener}s associated with
391      * the named property; if no such listeners have been added or
392      * if {@code propertyName} is {@code null} or invalid, an empty
393      * array is returned
394      *
395      * @see #addPropertyChangeListener
396      * @see #removePropertyChangeListener
397      */

398     public synchronized PropertyChangeListener JavaDoc[] getPropertyChangeListeners(String JavaDoc propertyName) {
399         return getCurrentChangeSupport().getPropertyChangeListeners(propertyName);
400     }
401
402
403     // ***************************************************************
404
// ***************************************************************
405

406
407     /**
408      * Support for reporting bound property changes for Object properties.
409      * This method can be called when a bound property has changed and it will
410      * send the appropriate PropertyChangeEvent to any registered
411      * PropertyChangeListeners.
412      *
413      * @param propertyName the property whose value has changed
414      * @param oldValue the property's previous value
415      * @param newValue the property's new value
416      */

417     private void firePropertyChange(String JavaDoc propertyName,
418                                     Object JavaDoc oldValue, Object JavaDoc newValue)
419     {
420         if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
421             return;
422         }
423         getCurrentChangeSupport().firePropertyChange(propertyName, oldValue, newValue);
424     }
425
426     /**
427      * Returns the current PropertyChangeSupport instance for the
428      * calling thread's context.
429      *
430      * @return this thread's context's PropertyChangeSupport
431      */

432     private synchronized PropertyChangeSupport JavaDoc getCurrentChangeSupport() {
433         PropertyChangeSupport JavaDoc changeSupport =
434             (PropertyChangeSupport JavaDoc)AppContext.getAppContext().get(SystemTray JavaDoc.class);
435
436         if (changeSupport == null) {
437             changeSupport = new PropertyChangeSupport JavaDoc(this);
438             AppContext.getAppContext().put(SystemTray JavaDoc.class, changeSupport);
439         }
440         return changeSupport;
441     }
442
443     synchronized void addNotify() {
444         if (peer == null) {
445             peer = ((SunToolkit)Toolkit.getDefaultToolkit()).createSystemTray(this);
446         }
447     }
448
449     static void checkSystemTrayAllowed() {
450         SecurityManager JavaDoc security = System.getSecurityManager();
451         if (security != null) {
452             security.checkPermission(SecurityConstants.ACCESS_SYSTEM_TRAY_PERMISSION);
453         }
454     }
455
456     private static void initializeSystemTrayIfNeeded() {
457         synchronized (SystemTray JavaDoc.class) {
458             if (systemTray == null) {
459                 systemTray = new SystemTray JavaDoc();
460             }
461         }
462     }
463 }
464
Popular Tags