View Javadoc
1   /*
2    * Copyright (c) 2005, 2012, 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.awt.event.*;
29  import java.awt.peer.TrayIconPeer;
30  import sun.awt.AppContext;
31  import sun.awt.SunToolkit;
32  import sun.awt.AWTAccessor;
33  import sun.awt.HeadlessToolkit;
34  import java.util.EventObject;
35  import java.security.AccessControlContext;
36  import java.security.AccessController;
37  
38  /**
39   * A <code>TrayIcon</code> object represents a tray icon that can be
40   * added to the {@link SystemTray system tray}. A
41   * <code>TrayIcon</code> can have a tooltip (text), an image, a popup
42   * menu, and a set of listeners associated with it.
43   *
44   * <p>A <code>TrayIcon</code> can generate various {@link MouseEvent
45   * MouseEvents} and supports adding corresponding listeners to receive
46   * notification of these events.  <code>TrayIcon</code> processes some
47   * of the events by itself.  For example, by default, when the
48   * right-mouse click is performed on the <code>TrayIcon</code> it
49   * displays the specified popup menu.  When the mouse hovers
50   * over the <code>TrayIcon</code> the tooltip is displayed.
51   *
52   * <p><strong>Note:</strong> When the <code>MouseEvent</code> is
53   * dispatched to its registered listeners its <code>component</code>
54   * property will be set to <code>null</code>.  (See {@link
55   * java.awt.event.ComponentEvent#getComponent}) The
56   * <code>source</code> property will be set to this
57   * <code>TrayIcon</code>. (See {@link
58   * java.util.EventObject#getSource})
59   *
60   * <p><b>Note:</b> A well-behaved {@link TrayIcon} implementation
61   * will assign different gestures to showing a popup menu and
62   * selecting a tray icon.
63   *
64   * <p>A <code>TrayIcon</code> can generate an {@link ActionEvent
65   * ActionEvent}.  On some platforms, this occurs when the user selects
66   * the tray icon using either the mouse or keyboard.
67   *
68   * <p>If a SecurityManager is installed, the AWTPermission
69   * {@code accessSystemTray} must be granted in order to create
70   * a {@code TrayIcon}. Otherwise the constructor will throw a
71   * SecurityException.
72   *
73   * <p> See the {@link SystemTray} class overview for an example on how
74   * to use the <code>TrayIcon</code> API.
75   *
76   * @since 1.6
77   * @see SystemTray#add
78   * @see java.awt.event.ComponentEvent#getComponent
79   * @see java.util.EventObject#getSource
80   *
81   * @author Bino George
82   * @author Denis Mikhalkin
83   * @author Sharon Zakhour
84   * @author Anton Tarasov
85   */
86  public class TrayIcon {
87  
88      private Image image;
89      private String tooltip;
90      private PopupMenu popup;
91      private boolean autosize;
92      private int id;
93      private String actionCommand;
94  
95      transient private TrayIconPeer peer;
96  
97      transient MouseListener mouseListener;
98      transient MouseMotionListener mouseMotionListener;
99      transient ActionListener actionListener;
100 
101     /*
102      * The tray icon's AccessControlContext.
103      *
104      * Unlike the acc in Component, this field is made final
105      * because TrayIcon is not serializable.
106      */
107     private final AccessControlContext acc = AccessController.getContext();
108 
109     /*
110      * Returns the acc this tray icon was constructed with.
111      */
112     final AccessControlContext getAccessControlContext() {
113         if (acc == null) {
114             throw new SecurityException("TrayIcon is missing AccessControlContext");
115         }
116         return acc;
117     }
118 
119     static {
120         Toolkit.loadLibraries();
121         if (!GraphicsEnvironment.isHeadless()) {
122             initIDs();
123         }
124 
125         AWTAccessor.setTrayIconAccessor(
126             new AWTAccessor.TrayIconAccessor() {
127                 public void addNotify(TrayIcon trayIcon) throws AWTException {
128                     trayIcon.addNotify();
129                 }
130                 public void removeNotify(TrayIcon trayIcon) {
131                     trayIcon.removeNotify();
132                 }
133             });
134     }
135 
136     private TrayIcon()
137       throws UnsupportedOperationException, HeadlessException, SecurityException
138     {
139         SystemTray.checkSystemTrayAllowed();
140         if (GraphicsEnvironment.isHeadless()) {
141             throw new HeadlessException();
142         }
143         if (!SystemTray.isSupported()) {
144             throw new UnsupportedOperationException();
145         }
146         SunToolkit.insertTargetMapping(this, AppContext.getAppContext());
147     }
148 
149     /**
150      * Creates a <code>TrayIcon</code> with the specified image.
151      *
152      * @param image the <code>Image</code> to be used
153      * @throws IllegalArgumentException if <code>image</code> is
154      * <code>null</code>
155      * @throws UnsupportedOperationException if the system tray isn't
156      * supported by the current platform
157      * @throws HeadlessException if
158      * {@code GraphicsEnvironment.isHeadless()} returns {@code true}
159      * @throws SecurityException if {@code accessSystemTray} permission
160      * is not granted
161      * @see SystemTray#add(TrayIcon)
162      * @see TrayIcon#TrayIcon(Image, String, PopupMenu)
163      * @see TrayIcon#TrayIcon(Image, String)
164      * @see SecurityManager#checkPermission
165      * @see AWTPermission
166      */
167     public TrayIcon(Image image) {
168         this();
169         if (image == null) {
170             throw new IllegalArgumentException("creating TrayIcon with null Image");
171         }
172         setImage(image);
173     }
174 
175     /**
176      * Creates a <code>TrayIcon</code> with the specified image and
177      * tooltip text.
178      *
179      * @param image the <code>Image</code> to be used
180      * @param tooltip the string to be used as tooltip text; if the
181      * value is <code>null</code> no tooltip is shown
182      * @throws IllegalArgumentException if <code>image</code> is
183      * <code>null</code>
184      * @throws UnsupportedOperationException if the system tray isn't
185      * supported by the current platform
186      * @throws HeadlessException if
187      * {@code GraphicsEnvironment.isHeadless()} returns {@code true}
188      * @throws SecurityException if {@code accessSystemTray} permission
189      * is not granted
190      * @see SystemTray#add(TrayIcon)
191      * @see TrayIcon#TrayIcon(Image)
192      * @see TrayIcon#TrayIcon(Image, String, PopupMenu)
193      * @see SecurityManager#checkPermission
194      * @see AWTPermission
195      */
196     public TrayIcon(Image image, String tooltip) {
197         this(image);
198         setToolTip(tooltip);
199     }
200 
201     /**
202      * Creates a <code>TrayIcon</code> with the specified image,
203      * tooltip and popup menu.
204      *
205      * @param image the <code>Image</code> to be used
206      * @param tooltip the string to be used as tooltip text; if the
207      * value is <code>null</code> no tooltip is shown
208      * @param popup the menu to be used for the tray icon's popup
209      * menu; if the value is <code>null</code> no popup menu is shown
210      * @throws IllegalArgumentException if <code>image</code> is <code>null</code>
211      * @throws UnsupportedOperationException if the system tray isn't
212      * supported by the current platform
213      * @throws HeadlessException if
214      * {@code GraphicsEnvironment.isHeadless()} returns {@code true}
215      * @throws SecurityException if {@code accessSystemTray} permission
216      * is not granted
217      * @see SystemTray#add(TrayIcon)
218      * @see TrayIcon#TrayIcon(Image, String)
219      * @see TrayIcon#TrayIcon(Image)
220      * @see PopupMenu
221      * @see MouseListener
222      * @see #addMouseListener(MouseListener)
223      * @see SecurityManager#checkPermission
224      * @see AWTPermission
225      */
226     public TrayIcon(Image image, String tooltip, PopupMenu popup) {
227         this(image, tooltip);
228         setPopupMenu(popup);
229     }
230 
231     /**
232      * Sets the image for this <code>TrayIcon</code>.  The previous
233      * tray icon image is discarded without calling the {@link
234      * java.awt.Image#flush} method &#151; you will need to call it
235      * manually.
236      *
237      * <p> If the image represents an animated image, it will be
238      * animated automatically.
239      *
240      * <p> See the {@link #setImageAutoSize(boolean)} property for
241      * details on the size of the displayed image.
242      *
243      * <p> Calling this method with the same image that is currently
244      * being used has no effect.
245      *
246      * @throws NullPointerException if <code>image</code> is <code>null</code>
247      * @param image the non-null <code>Image</code> to be used
248      * @see #getImage
249      * @see Image
250      * @see SystemTray#add(TrayIcon)
251      * @see TrayIcon#TrayIcon(Image, String)
252      */
253     public void setImage(Image image) {
254         if (image == null) {
255             throw new NullPointerException("setting null Image");
256         }
257         this.image = image;
258 
259         TrayIconPeer peer = this.peer;
260         if (peer != null) {
261             peer.updateImage();
262         }
263     }
264 
265     /**
266      * Returns the current image used for this <code>TrayIcon</code>.
267      *
268      * @return the image
269      * @see #setImage(Image)
270      * @see Image
271      */
272     public Image getImage() {
273         return image;
274     }
275 
276     /**
277      * Sets the popup menu for this <code>TrayIcon</code>.  If
278      * <code>popup</code> is <code>null</code>, no popup menu will be
279      * associated with this <code>TrayIcon</code>.
280      *
281      * <p>Note that this <code>popup</code> must not be added to any
282      * parent before or after it is set on the tray icon.  If you add
283      * it to some parent, the <code>popup</code> may be removed from
284      * that parent.
285      *
286      * <p>The {@code popup} can be set on one {@code TrayIcon} only.
287      * Setting the same popup on multiple {@code TrayIcon}s will cause
288      * an {@code IllegalArgumentException}.
289      *
290      * <p><strong>Note:</strong> Some platforms may not support
291      * showing the user-specified popup menu component when the user
292      * right-clicks the tray icon.  In this situation, either no menu
293      * will be displayed or, on some systems, a native version of the
294      * menu may be displayed.
295      *
296      * @throws IllegalArgumentException if the {@code popup} is already
297      * set for another {@code TrayIcon}
298      * @param popup a <code>PopupMenu</code> or <code>null</code> to
299      * remove any popup menu
300      * @see #getPopupMenu
301      */
302     public void setPopupMenu(PopupMenu popup) {
303         if (popup == this.popup) {
304             return;
305         }
306         synchronized (TrayIcon.class) {
307             if (popup != null) {
308                 if (popup.isTrayIconPopup) {
309                     throw new IllegalArgumentException("the PopupMenu is already set for another TrayIcon");
310                 }
311                 popup.isTrayIconPopup = true;
312             }
313             if (this.popup != null) {
314                 this.popup.isTrayIconPopup = false;
315             }
316             this.popup = popup;
317         }
318     }
319 
320     /**
321      * Returns the popup menu associated with this <code>TrayIcon</code>.
322      *
323      * @return the popup menu or <code>null</code> if none exists
324      * @see #setPopupMenu(PopupMenu)
325      */
326     public PopupMenu getPopupMenu() {
327         return popup;
328     }
329 
330     /**
331      * Sets the tooltip string for this <code>TrayIcon</code>. The
332      * tooltip is displayed automatically when the mouse hovers over
333      * the icon.  Setting the tooltip to <code>null</code> removes any
334      * tooltip text.
335      *
336      * When displayed, the tooltip string may be truncated on some platforms;
337      * the number of characters that may be displayed is platform-dependent.
338      *
339      * @param tooltip the string for the tooltip; if the value is
340      * <code>null</code> no tooltip is shown
341      * @see #getToolTip
342      */
343     public void setToolTip(String tooltip) {
344         this.tooltip = tooltip;
345 
346         TrayIconPeer peer = this.peer;
347         if (peer != null) {
348             peer.setToolTip(tooltip);
349         }
350     }
351 
352     /**
353      * Returns the tooltip string associated with this
354      * <code>TrayIcon</code>.
355      *
356      * @return the tooltip string or <code>null</code> if none exists
357      * @see #setToolTip(String)
358      */
359     public String getToolTip() {
360         return tooltip;
361     }
362 
363     /**
364      * Sets the auto-size property.  Auto-size determines whether the
365      * tray image is automatically sized to fit the space allocated
366      * for the image on the tray.  By default, the auto-size property
367      * is set to <code>false</code>.
368      *
369      * <p> If auto-size is <code>false</code>, and the image size
370      * doesn't match the tray icon space, the image is painted as-is
371      * inside that space &#151; if larger than the allocated space, it will
372      * be cropped.
373      *
374      * <p> If auto-size is <code>true</code>, the image is stretched or shrunk to
375      * fit the tray icon space.
376      *
377      * @param autosize <code>true</code> to auto-size the image,
378      * <code>false</code> otherwise
379      * @see #isImageAutoSize
380      */
381     public void setImageAutoSize(boolean autosize) {
382         this.autosize = autosize;
383 
384         TrayIconPeer peer = this.peer;
385         if (peer != null) {
386             peer.updateImage();
387         }
388     }
389 
390     /**
391      * Returns the value of the auto-size property.
392      *
393      * @return <code>true</code> if the image will be auto-sized,
394      * <code>false</code> otherwise
395      * @see #setImageAutoSize(boolean)
396      */
397     public boolean isImageAutoSize() {
398         return autosize;
399     }
400 
401     /**
402      * Adds the specified mouse listener to receive mouse events from
403      * this <code>TrayIcon</code>.  Calling this method with a
404      * <code>null</code> value has no effect.
405      *
406      * <p><b>Note</b>: The {@code MouseEvent}'s coordinates (received
407      * from the {@code TrayIcon}) are relative to the screen, not the
408      * {@code TrayIcon}.
409      *
410      * <p> <b>Note: </b>The <code>MOUSE_ENTERED</code> and
411      * <code>MOUSE_EXITED</code> mouse events are not supported.
412      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
413      * >AWT Threading Issues</a> for details on AWT's threading model.
414      *
415      * @param    listener the mouse listener
416      * @see      java.awt.event.MouseEvent
417      * @see      java.awt.event.MouseListener
418      * @see      #removeMouseListener(MouseListener)
419      * @see      #getMouseListeners
420      */
421     public synchronized void addMouseListener(MouseListener listener) {
422         if (listener == null) {
423             return;
424         }
425         mouseListener = AWTEventMulticaster.add(mouseListener, listener);
426     }
427 
428     /**
429      * Removes the specified mouse listener.  Calling this method with
430      * <code>null</code> or an invalid value has no effect.
431      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
432      * >AWT Threading Issues</a> for details on AWT's threading model.
433      *
434      * @param    listener   the mouse listener
435      * @see      java.awt.event.MouseEvent
436      * @see      java.awt.event.MouseListener
437      * @see      #addMouseListener(MouseListener)
438      * @see      #getMouseListeners
439      */
440     public synchronized void removeMouseListener(MouseListener listener) {
441         if (listener == null) {
442             return;
443         }
444         mouseListener = AWTEventMulticaster.remove(mouseListener, listener);
445     }
446 
447     /**
448      * Returns an array of all the mouse listeners
449      * registered on this <code>TrayIcon</code>.
450      *
451      * @return all of the <code>MouseListeners</code> registered on
452      * this <code>TrayIcon</code> or an empty array if no mouse
453      * listeners are currently registered
454      *
455      * @see      #addMouseListener(MouseListener)
456      * @see      #removeMouseListener(MouseListener)
457      * @see      java.awt.event.MouseListener
458      */
459     public synchronized MouseListener[] getMouseListeners() {
460         return AWTEventMulticaster.getListeners(mouseListener, MouseListener.class);
461     }
462 
463     /**
464      * Adds the specified mouse listener to receive mouse-motion
465      * events from this <code>TrayIcon</code>.  Calling this method
466      * with a <code>null</code> value has no effect.
467      *
468      * <p><b>Note</b>: The {@code MouseEvent}'s coordinates (received
469      * from the {@code TrayIcon}) are relative to the screen, not the
470      * {@code TrayIcon}.
471      *
472      * <p> <b>Note: </b>The <code>MOUSE_DRAGGED</code> mouse event is not supported.
473      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
474      * >AWT Threading Issues</a> for details on AWT's threading model.
475      *
476      * @param    listener   the mouse listener
477      * @see      java.awt.event.MouseEvent
478      * @see      java.awt.event.MouseMotionListener
479      * @see      #removeMouseMotionListener(MouseMotionListener)
480      * @see      #getMouseMotionListeners
481      */
482     public synchronized void addMouseMotionListener(MouseMotionListener listener) {
483         if (listener == null) {
484             return;
485         }
486         mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener, listener);
487     }
488 
489     /**
490      * Removes the specified mouse-motion listener.  Calling this method with
491      * <code>null</code> or an invalid value has no effect.
492      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
493      * >AWT Threading Issues</a> for details on AWT's threading model.
494      *
495      * @param    listener   the mouse listener
496      * @see      java.awt.event.MouseEvent
497      * @see      java.awt.event.MouseMotionListener
498      * @see      #addMouseMotionListener(MouseMotionListener)
499      * @see      #getMouseMotionListeners
500      */
501     public synchronized void removeMouseMotionListener(MouseMotionListener listener) {
502         if (listener == null) {
503             return;
504         }
505         mouseMotionListener = AWTEventMulticaster.remove(mouseMotionListener, listener);
506     }
507 
508     /**
509      * Returns an array of all the mouse-motion listeners
510      * registered on this <code>TrayIcon</code>.
511      *
512      * @return all of the <code>MouseInputListeners</code> registered on
513      * this <code>TrayIcon</code> or an empty array if no mouse
514      * listeners are currently registered
515      *
516      * @see      #addMouseMotionListener(MouseMotionListener)
517      * @see      #removeMouseMotionListener(MouseMotionListener)
518      * @see      java.awt.event.MouseMotionListener
519      */
520     public synchronized MouseMotionListener[] getMouseMotionListeners() {
521         return AWTEventMulticaster.getListeners(mouseMotionListener, MouseMotionListener.class);
522     }
523 
524     /**
525      * Returns the command name of the action event fired by this tray icon.
526      *
527      * @return the action command name, or <code>null</code> if none exists
528      * @see #addActionListener(ActionListener)
529      * @see #setActionCommand(String)
530      */
531     public String getActionCommand() {
532         return actionCommand;
533     }
534 
535     /**
536      * Sets the command name for the action event fired by this tray
537      * icon.  By default, this action command is set to
538      * <code>null</code>.
539      *
540      * @param command  a string used to set the tray icon's
541      *                 action command.
542      * @see java.awt.event.ActionEvent
543      * @see #addActionListener(ActionListener)
544      * @see #getActionCommand
545      */
546     public void setActionCommand(String command) {
547         actionCommand = command;
548     }
549 
550     /**
551      * Adds the specified action listener to receive
552      * <code>ActionEvent</code>s from this <code>TrayIcon</code>.
553      * Action events usually occur when a user selects the tray icon,
554      * using either the mouse or keyboard.  The conditions in which
555      * action events are generated are platform-dependent.
556      *
557      * <p>Calling this method with a <code>null</code> value has no
558      * effect.
559      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
560      * >AWT Threading Issues</a> for details on AWT's threading model.
561      *
562      * @param         listener the action listener
563      * @see           #removeActionListener
564      * @see           #getActionListeners
565      * @see           java.awt.event.ActionListener
566      * @see #setActionCommand(String)
567      */
568     public synchronized void addActionListener(ActionListener listener) {
569         if (listener == null) {
570             return;
571         }
572         actionListener = AWTEventMulticaster.add(actionListener, listener);
573     }
574 
575     /**
576      * Removes the specified action listener.  Calling this method with
577      * <code>null</code> or an invalid value has no effect.
578      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
579      * >AWT Threading Issues</a> for details on AWT's threading model.
580      *
581      * @param    listener   the action listener
582      * @see      java.awt.event.ActionEvent
583      * @see      java.awt.event.ActionListener
584      * @see      #addActionListener(ActionListener)
585      * @see      #getActionListeners
586      * @see #setActionCommand(String)
587      */
588     public synchronized void removeActionListener(ActionListener listener) {
589         if (listener == null) {
590             return;
591         }
592         actionListener = AWTEventMulticaster.remove(actionListener, listener);
593     }
594 
595     /**
596      * Returns an array of all the action listeners
597      * registered on this <code>TrayIcon</code>.
598      *
599      * @return all of the <code>ActionListeners</code> registered on
600      * this <code>TrayIcon</code> or an empty array if no action
601      * listeners are currently registered
602      *
603      * @see      #addActionListener(ActionListener)
604      * @see      #removeActionListener(ActionListener)
605      * @see      java.awt.event.ActionListener
606      */
607     public synchronized ActionListener[] getActionListeners() {
608         return AWTEventMulticaster.getListeners(actionListener, ActionListener.class);
609     }
610 
611     /**
612      * The message type determines which icon will be displayed in the
613      * caption of the message, and a possible system sound a message
614      * may generate upon showing.
615      *
616      * @see TrayIcon
617      * @see TrayIcon#displayMessage(String, String, MessageType)
618      * @since 1.6
619      */
620     public enum MessageType {
621         /** An error message */
622         ERROR,
623         /** A warning message */
624         WARNING,
625         /** An information message */
626         INFO,
627         /** Simple message */
628         NONE
629     };
630 
631     /**
632      * Displays a popup message near the tray icon.  The message will
633      * disappear after a time or if the user clicks on it.  Clicking
634      * on the message may trigger an {@code ActionEvent}.
635      *
636      * <p>Either the caption or the text may be <code>null</code>, but an
637      * <code>NullPointerException</code> is thrown if both are
638      * <code>null</code>.
639      *
640      * When displayed, the caption or text strings may be truncated on
641      * some platforms; the number of characters that may be displayed is
642      * platform-dependent.
643      *
644      * <p><strong>Note:</strong> Some platforms may not support
645      * showing a message.
646      *
647      * @param caption the caption displayed above the text, usually in
648      * bold; may be <code>null</code>
649      * @param text the text displayed for the particular message; may be
650      * <code>null</code>
651      * @param messageType an enum indicating the message type
652      * @throws NullPointerException if both <code>caption</code>
653      * and <code>text</code> are <code>null</code>
654      */
655     public void displayMessage(String caption, String text, MessageType messageType) {
656         if (caption == null && text == null) {
657             throw new NullPointerException("displaying the message with both caption and text being null");
658         }
659 
660         TrayIconPeer peer = this.peer;
661         if (peer != null) {
662             peer.displayMessage(caption, text, messageType.name());
663         }
664     }
665 
666     /**
667      * Returns the size, in pixels, of the space that the tray icon
668      * occupies in the system tray.  For the tray icon that is not yet
669      * added to the system tray, the returned size is equal to the
670      * result of the {@link SystemTray#getTrayIconSize}.
671      *
672      * @return the size of the tray icon, in pixels
673      * @see TrayIcon#setImageAutoSize(boolean)
674      * @see java.awt.Image
675      * @see TrayIcon#getSize()
676      */
677     public Dimension getSize() {
678         return SystemTray.getSystemTray().getTrayIconSize();
679     }
680 
681     // ****************************************************************
682     // ****************************************************************
683 
684     void addNotify()
685       throws AWTException
686     {
687         synchronized (this) {
688             if (peer == null) {
689                 Toolkit toolkit = Toolkit.getDefaultToolkit();
690                 if (toolkit instanceof SunToolkit) {
691                     peer = ((SunToolkit)Toolkit.getDefaultToolkit()).createTrayIcon(this);
692                 } else if (toolkit instanceof HeadlessToolkit) {
693                     peer = ((HeadlessToolkit)Toolkit.getDefaultToolkit()).createTrayIcon(this);
694                 }
695             }
696         }
697         peer.setToolTip(tooltip);
698     }
699 
700     void removeNotify() {
701         TrayIconPeer p = null;
702         synchronized (this) {
703             p = peer;
704             peer = null;
705         }
706         if (p != null) {
707             p.dispose();
708         }
709     }
710 
711     void setID(int id) {
712         this.id = id;
713     }
714 
715     int getID(){
716         return id;
717     }
718 
719     void dispatchEvent(AWTEvent e) {
720         EventQueue.setCurrentEventAndMostRecentTime(e);
721         Toolkit.getDefaultToolkit().notifyAWTEventListeners(e);
722         processEvent(e);
723     }
724 
725     void processEvent(AWTEvent e) {
726         if (e instanceof MouseEvent) {
727             switch(e.getID()) {
728             case MouseEvent.MOUSE_PRESSED:
729             case MouseEvent.MOUSE_RELEASED:
730             case MouseEvent.MOUSE_CLICKED:
731                 processMouseEvent((MouseEvent)e);
732                 break;
733             case MouseEvent.MOUSE_MOVED:
734                 processMouseMotionEvent((MouseEvent)e);
735                 break;
736             default:
737                 return;
738             }
739         } else if (e instanceof ActionEvent) {
740             processActionEvent((ActionEvent)e);
741         }
742     }
743 
744     void processMouseEvent(MouseEvent e) {
745         MouseListener listener = mouseListener;
746 
747         if (listener != null) {
748             int id = e.getID();
749             switch(id) {
750             case MouseEvent.MOUSE_PRESSED:
751                 listener.mousePressed(e);
752                 break;
753             case MouseEvent.MOUSE_RELEASED:
754                 listener.mouseReleased(e);
755                 break;
756             case MouseEvent.MOUSE_CLICKED:
757                 listener.mouseClicked(e);
758                 break;
759             default:
760                 return;
761             }
762         }
763     }
764 
765     void processMouseMotionEvent(MouseEvent e) {
766         MouseMotionListener listener = mouseMotionListener;
767         if (listener != null &&
768             e.getID() == MouseEvent.MOUSE_MOVED)
769         {
770             listener.mouseMoved(e);
771         }
772     }
773 
774     void processActionEvent(ActionEvent e) {
775         ActionListener listener = actionListener;
776         if (listener != null) {
777             listener.actionPerformed(e);
778         }
779     }
780 
781     private static native void initIDs();
782 }