History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/SystemTray.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/awt/SystemTray.java+504−0
@@ -0,0 +1,504 @@
1+/*
2+ * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.awt;
27+
28+import java.util.Vector;
29+import java.awt.peer.SystemTrayPeer;
30+import java.beans.PropertyChangeListener;
31+import java.beans.PropertyChangeSupport;
32+import sun.awt.AppContext;
33+import sun.awt.SunToolkit;
34+import sun.awt.HeadlessToolkit;
35+import sun.security.util.SecurityConstants;
36+
37+/**
38+ * The <code>SystemTray</code> class represents the system tray for a
39+ * desktop. On Microsoft Windows it is referred to as the "Taskbar
40+ * Status Area", on Gnome it is referred to as the "Notification
41+ * Area", on KDE it is referred to as the "System Tray". The system
42+ * tray is shared by all applications running on the desktop.
43+ *
44+ * <p> On some platforms the system tray may not be present or may not
45+ * be supported, in this case {@link SystemTray#getSystemTray()}
46+ * throws {@link UnsupportedOperationException}. To detect whether the
47+ * system tray is supported, use {@link SystemTray#isSupported}.
48+ *
49+ * <p>The <code>SystemTray</code> may contain one or more {@link
50+ * TrayIcon TrayIcons}, which are added to the tray using the {@link
51+ * #add} method, and removed when no longer needed, using the
52+ * {@link #remove}. <code>TrayIcon</code> consists of an
53+ * image, a popup menu and a set of associated listeners. Please see
54+ * the {@link TrayIcon} class for details.
55+ *
56+ * <p>Every Java application has a single <code>SystemTray</code>
57+ * instance that allows the app to interface with the system tray of
58+ * the desktop while the app is running. The <code>SystemTray</code>
59+ * instance can be obtained from the {@link #getSystemTray} method.
60+ * An application may not create its own instance of
61+ * <code>SystemTray</code>.
62+ *
63+ * <p>The following code snippet demonstrates how to access
64+ * and customize the system tray:
65+ * <code>
66+ * <pre>
67+ * {@link TrayIcon} trayIcon = null;
68+ * if (SystemTray.isSupported()) {
69+ * // get the SystemTray instance
70+ * SystemTray tray = SystemTray.{@link #getSystemTray};
71+ * // load an image
72+ * {@link java.awt.Image} image = {@link java.awt.Toolkit#getImage(String) Toolkit.getDefaultToolkit().getImage}(...);
73+ * // create a action listener to listen for default action executed on the tray icon
74+ * {@link java.awt.event.ActionListener} listener = new {@link java.awt.event.ActionListener ActionListener}() {
75+ * public void {@link java.awt.event.ActionListener#actionPerformed actionPerformed}({@link java.awt.event.ActionEvent} e) {
76+ * // execute default action of the application
77+ * // ...
78+ * }
79+ * };
80+ * // create a popup menu
81+ * {@link java.awt.PopupMenu} popup = new {@link java.awt.PopupMenu#PopupMenu PopupMenu}();
82+ * // create menu item for the default action
83+ * MenuItem defaultItem = new MenuItem(...);
84+ * defaultItem.addActionListener(listener);
85+ * popup.add(defaultItem);
86+ * /// ... add other items
87+ * // construct a TrayIcon
88+ * trayIcon = new {@link TrayIcon#TrayIcon(java.awt.Image, String, java.awt.PopupMenu) TrayIcon}(image, "Tray Demo", popup);
89+ * // set the TrayIcon properties
90+ * trayIcon.{@link TrayIcon#addActionListener(java.awt.event.ActionListener) addActionListener}(listener);
91+ * // ...
92+ * // add the tray image
93+ * try {
94+ * tray.{@link SystemTray#add(TrayIcon) add}(trayIcon);
95+ * } catch (AWTException e) {
96+ * System.err.println(e);
97+ * }
98+ * // ...
99+ * } else {
100+ * // disable tray option in your application or
101+ * // perform other actions
102+ * ...
103+ * }
104+ * // ...
105+ * // some time later
106+ * // the application state has changed - update the image
107+ * if (trayIcon != null) {
108+ * trayIcon.{@link TrayIcon#setImage(java.awt.Image) setImage}(updatedImage);
109+ * }
110+ * // ...
111+ * </pre>
112+ * </code>
113+ *
114+ * @since 1.6
115+ * @see TrayIcon
116+ *
117+ * @author Bino George
118+ * @author Denis Mikhalkin
119+ * @author Sharon Zakhour
120+ * @author Anton Tarasov
121+ */
122+public class SystemTray {
123+ private static SystemTray systemTray;
124+ private int currentIconID = 0; // each TrayIcon added gets a unique ID
125+
126+ transient private SystemTrayPeer peer;
127+
128+ private static final TrayIcon[] EMPTY_TRAY_ARRAY = new TrayIcon[0];
129+
130+ /**
131+ * Private <code>SystemTray</code> constructor.
132+ *
133+ */
134+ private SystemTray() {
135+ addNotify();
136+ }
137+
138+ /**
139+ * Gets the <code>SystemTray</code> instance that represents the
140+ * desktop's tray area. This always returns the same instance per
141+ * application. On some platforms the system tray may not be
142+ * supported. You may use the {@link #isSupported} method to
143+ * check if the system tray is supported.
144+ *
145+ * <p>If a SecurityManager is installed, the AWTPermission
146+ * {@code accessSystemTray} must be granted in order to get the
147+ * {@code SystemTray} instance. Otherwise this method will throw a
148+ * SecurityException.
149+ *
150+ * @return the <code>SystemTray</code> instance that represents
151+ * the desktop's tray area
152+ * @throws UnsupportedOperationException if the system tray isn't
153+ * supported by the current platform
154+ * @throws HeadlessException if
155+ * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
156+ * @throws SecurityException if {@code accessSystemTray} permission
157+ * is not granted
158+ * @see #add(TrayIcon)
159+ * @see TrayIcon
160+ * @see #isSupported
161+ * @see SecurityManager#checkPermission
162+ * @see AWTPermission
163+ */
164+ public static SystemTray getSystemTray() {
165+ checkSystemTrayAllowed();
166+ if (GraphicsEnvironment.isHeadless()) {
167+ throw new HeadlessException();
168+ }
169+
170+ initializeSystemTrayIfNeeded();
171+
172+ if (!isSupported()) {
173+ throw new UnsupportedOperationException(
174+ "The system tray is not supported on the current platform.");
175+ }
176+
177+ return systemTray;
178+ }
179+
180+ /**
181+ * Returns whether the system tray is supported on the current
182+ * platform. In addition to displaying the tray icon, minimal
183+ * system tray support includes either a popup menu (see {@link
184+ * TrayIcon#setPopupMenu(PopupMenu)}) or an action event (see
185+ * {@link TrayIcon#addActionListener(ActionListener)}).
186+ *
187+ * <p>Developers should not assume that all of the system tray
188+ * functionality is supported. To guarantee that the tray icon's
189+ * default action is always accessible, add the default action to
190+ * both the action listener and the popup menu. See the {@link
191+ * SystemTray example} for an example of how to do this.
192+ *
193+ * <p><b>Note</b>: When implementing <code>SystemTray</code> and
194+ * <code>TrayIcon</code> it is <em>strongly recommended</em> that
195+ * you assign different gestures to the popup menu and an action
196+ * event. Overloading a gesture for both purposes is confusing
197+ * and may prevent the user from accessing one or the other.
198+ *
199+ * @see #getSystemTray
200+ * @return <code>false</code> if no system tray access is supported; this
201+ * method returns <code>true</code> if the minimal system tray access is
202+ * supported but does not guarantee that all system tray
203+ * functionality is supported for the current platform
204+ */
205+ public static boolean isSupported() {
206+ Toolkit toolkit = Toolkit.getDefaultToolkit();
207+ if (toolkit instanceof SunToolkit) {
208+ // connecting tray to native resource
209+ initializeSystemTrayIfNeeded();
210+ return ((SunToolkit)toolkit).isTraySupported();
211+ } else if (toolkit instanceof HeadlessToolkit) {
212+ // skip initialization as the init routine
213+ // throws HeadlessException
214+ return ((HeadlessToolkit)toolkit).isTraySupported();
215+ } else {
216+ return false;
217+ }
218+ }
219+
220+ /**
221+ * Adds a <code>TrayIcon</code> to the <code>SystemTray</code>.
222+ * The tray icon becomes visible in the system tray once it is
223+ * added. The order in which icons are displayed in a tray is not
224+ * specified - it is platform and implementation-dependent.
225+ *
226+ * <p> All icons added by the application are automatically
227+ * removed from the <code>SystemTray</code> upon application exit
228+ * and also when the desktop system tray becomes unavailable.
229+ *
230+ * @param trayIcon the <code>TrayIcon</code> to be added
231+ * @throws NullPointerException if <code>trayIcon</code> is
232+ * <code>null</code>
233+ * @throws IllegalArgumentException if the same instance of
234+ * a <code>TrayIcon</code> is added more than once
235+ * @throws AWTException if the desktop system tray is missing
236+ * @see #remove(TrayIcon)
237+ * @see #getSystemTray
238+ * @see TrayIcon
239+ * @see java.awt.Image
240+ */
241+ public void add(TrayIcon trayIcon) throws AWTException {
242+ if (trayIcon == null) {
243+ throw new NullPointerException("adding null TrayIcon");
244+ }
245+ TrayIcon[] oldArray = null, newArray = null;
246+ Vector<TrayIcon> icons = null;
247+ synchronized (this) {
248+ oldArray = systemTray.getTrayIcons();
249+ icons = (Vector<TrayIcon>)AppContext.getAppContext().get(TrayIcon.class);
250+ if (icons == null) {
251+ icons = new Vector<TrayIcon>(3);
252+ AppContext.getAppContext().put(TrayIcon.class, icons);
253+
254+ } else if (icons.contains(trayIcon)) {
255+ throw new IllegalArgumentException("adding TrayIcon that is already added");
256+ }
257+ icons.add(trayIcon);
258+ newArray = systemTray.getTrayIcons();
259+
260+ trayIcon.setID(++currentIconID);
261+ }
262+ try {
263+ trayIcon.addNotify();
264+ } catch (AWTException e) {
265+ icons.remove(trayIcon);
266+ throw e;
267+ }
268+ firePropertyChange("trayIcons", oldArray, newArray);
269+ }
270+
271+ /**
272+ * Removes the specified <code>TrayIcon</code> from the
273+ * <code>SystemTray</code>.
274+ *
275+ * <p> All icons added by the application are automatically
276+ * removed from the <code>SystemTray</code> upon application exit
277+ * and also when the desktop system tray becomes unavailable.
278+ *
279+ * <p> If <code>trayIcon</code> is <code>null</code> or was not
280+ * added to the system tray, no exception is thrown and no action
281+ * is performed.
282+ *
283+ * @param trayIcon the <code>TrayIcon</code> to be removed
284+ * @see #add(TrayIcon)
285+ * @see TrayIcon
286+ */
287+ public void remove(TrayIcon trayIcon) {
288+ if (trayIcon == null) {
289+ return;
290+ }
291+ TrayIcon[] oldArray = null, newArray = null;
292+ synchronized (this) {
293+ oldArray = systemTray.getTrayIcons();
294+ Vector<TrayIcon> icons = (Vector<TrayIcon>)AppContext.getAppContext().get(TrayIcon.class);
295+ // TrayIcon with no peer is not contained in the array.
296+ if (icons == null || !icons.remove(trayIcon)) {
297+ return;
298+ }
299+ trayIcon.removeNotify();
300+ newArray = systemTray.getTrayIcons();
301+ }
302+ firePropertyChange("trayIcons", oldArray, newArray);
303+ }
304+
305+ /**
306+ * Returns an array of all icons added to the tray by this
307+ * application. You can't access the icons added by another
308+ * application. Some browsers partition applets in different
309+ * code bases into separate contexts, and establish walls between
310+ * these contexts. In such a scenario, only the tray icons added
311+ * from this context will be returned.
312+ *
313+ * <p> The returned array is a copy of the actual array and may be
314+ * modified in any way without affecting the system tray. To
315+ * remove a <code>TrayIcon</code> from the
316+ * <code>SystemTray</code>, use the {@link
317+ * #remove(TrayIcon)} method.
318+ *
319+ * @return an array of all tray icons added to this tray, or an
320+ * empty array if none has been added
321+ * @see #add(TrayIcon)
322+ * @see TrayIcon
323+ */
324+ public TrayIcon[] getTrayIcons() {
325+ Vector<TrayIcon> icons = (Vector<TrayIcon>)AppContext.getAppContext().get(TrayIcon.class);
326+ if (icons != null) {
327+ return (TrayIcon[])icons.toArray(new TrayIcon[icons.size()]);
328+ }
329+ return EMPTY_TRAY_ARRAY;
330+ }
331+
332+ /**
333+ * Returns the size, in pixels, of the space that a tray icon will
334+ * occupy in the system tray. Developers may use this methods to
335+ * acquire the preferred size for the image property of a tray icon
336+ * before it is created. For convenience, there is a similar
337+ * method {@link TrayIcon#getSize} in the <code>TrayIcon</code> class.
338+ *
339+ * @return the default size of a tray icon, in pixels
340+ * @see TrayIcon#setImageAutoSize(boolean)
341+ * @see java.awt.Image
342+ * @see TrayIcon#getSize()
343+ */
344+ public Dimension getTrayIconSize() {
345+ return peer.getTrayIconSize();
346+ }
347+
348+ /**
349+ * Adds a {@code PropertyChangeListener} to the list of listeners for the
350+ * specific property. The following properties are currently supported:
351+ * <p> </p>
352+ * <table border=1 summary="SystemTray properties">
353+ * <tr>
354+ * <th>Property</th>
355+ * <th>Description</th>
356+ * </tr>
357+ * <tr>
358+ * <td>{@code trayIcons}</td>
359+ * <td>The {@code SystemTray}'s array of {@code TrayIcon} objects.
360+ * The array is accessed via the {@link #getTrayIcons} method.<br>
361+ * This property is changed when a tray icon is added to (or removed
362+ * from) the system tray.<br> For example, this property is changed
363+ * when the system tray becomes unavailable on the desktop<br>
364+ * and the tray icons are automatically removed.</td>
365+ * </tr>
366+ * <tr>
367+ * <td>{@code systemTray}</td>
368+ * <td>This property contains {@code SystemTray} instance when the system tray
369+ * is available or <code>null</code> otherwise.<br> This property is changed
370+ * when the system tray becomes available or unavailable on the desktop.<br>
371+ * The property is accessed by the {@link #getSystemTray} method.</td>
372+ * </tr>
373+ * </table>
374+ * <p> </p>
375+ * The {@code listener} listens to property changes only in this context.
376+ * <p>
377+ * If {@code listener} is {@code null}, no exception is thrown
378+ * and no action is performed.
379+ *
380+ * @param propertyName the specified property
381+ * @param listener the property change listener to be added
382+ *
383+ * @see #removePropertyChangeListener
384+ * @see #getPropertyChangeListeners
385+ */
386+ public synchronized void addPropertyChangeListener(String propertyName,
387+ PropertyChangeListener listener)
388+ {
389+ if (listener == null) {
390+ return;
391+ }
392+ getCurrentChangeSupport().addPropertyChangeListener(propertyName, listener);
393+ }
394+
395+ /**
396+ * Removes a {@code PropertyChangeListener} from the listener list
397+ * for a specific property.
398+ * <p>
399+ * The {@code PropertyChangeListener} must be from this context.
400+ * <p>
401+ * If {@code propertyName} or {@code listener} is {@code null} or invalid,
402+ * no exception is thrown and no action is taken.
403+ *
404+ * @param propertyName the specified property
405+ * @param listener the PropertyChangeListener to be removed
406+ *
407+ * @see #addPropertyChangeListener
408+ * @see #getPropertyChangeListeners
409+ */
410+ public synchronized void removePropertyChangeListener(String propertyName,
411+ PropertyChangeListener listener)
412+ {
413+ if (listener == null) {
414+ return;
415+ }
416+ getCurrentChangeSupport().removePropertyChangeListener(propertyName, listener);
417+ }
418+
419+ /**
420+ * Returns an array of all the listeners that have been associated
421+ * with the named property.
422+ * <p>
423+ * Only the listeners in this context are returned.
424+ *
425+ * @param propertyName the specified property
426+ * @return all of the {@code PropertyChangeListener}s associated with
427+ * the named property; if no such listeners have been added or
428+ * if {@code propertyName} is {@code null} or invalid, an empty
429+ * array is returned
430+ *
431+ * @see #addPropertyChangeListener
432+ * @see #removePropertyChangeListener
433+ */
434+ public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
435+ return getCurrentChangeSupport().getPropertyChangeListeners(propertyName);
436+ }
437+
438+
439+ // ***************************************************************
440+ // ***************************************************************
441+
442+
443+ /**
444+ * Support for reporting bound property changes for Object properties.
445+ * This method can be called when a bound property has changed and it will
446+ * send the appropriate PropertyChangeEvent to any registered
447+ * PropertyChangeListeners.
448+ *
449+ * @param propertyName the property whose value has changed
450+ * @param oldValue the property's previous value
451+ * @param newValue the property's new value
452+ */
453+ private void firePropertyChange(String propertyName,
454+ Object oldValue, Object newValue)
455+ {
456+ if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
457+ return;
458+ }
459+ getCurrentChangeSupport().firePropertyChange(propertyName, oldValue, newValue);
460+ }
461+
462+ /**
463+ * Returns the current PropertyChangeSupport instance for the
464+ * calling thread's context.
465+ *
466+ * @return this thread's context's PropertyChangeSupport
467+ */
468+ private synchronized PropertyChangeSupport getCurrentChangeSupport() {
469+ PropertyChangeSupport changeSupport =
470+ (PropertyChangeSupport)AppContext.getAppContext().get(SystemTray.class);
471+
472+ if (changeSupport == null) {
473+ changeSupport = new PropertyChangeSupport(this);
474+ AppContext.getAppContext().put(SystemTray.class, changeSupport);
475+ }
476+ return changeSupport;
477+ }
478+
479+ synchronized void addNotify() {
480+ if (peer == null) {
481+ Toolkit toolkit = Toolkit.getDefaultToolkit();
482+ if (toolkit instanceof SunToolkit) {
483+ peer = ((SunToolkit)Toolkit.getDefaultToolkit()).createSystemTray(this);
484+ } else if (toolkit instanceof HeadlessToolkit) {
485+ peer = ((HeadlessToolkit)Toolkit.getDefaultToolkit()).createSystemTray(this);
486+ }
487+ }
488+ }
489+
490+ static void checkSystemTrayAllowed() {
491+ SecurityManager security = System.getSecurityManager();
492+ if (security != null) {
493+ security.checkPermission(SecurityConstants.AWT.ACCESS_SYSTEM_TRAY_PERMISSION);
494+ }
495+ }
496+
497+ private static void initializeSystemTrayIfNeeded() {
498+ synchronized (SystemTray.class) {
499+ if (systemTray == null) {
500+ systemTray = new SystemTray();
501+ }
502+ }
503+ }
504+}