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