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} 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.
  51  *
  52  * <p><strong>Note:</strong> When the {@code MouseEvent} is
  53  * dispatched to its registered listeners its {@code component}
  54  * property will be set to {@code null}.  (See {@link
  55  * java.awt.event.ComponentEvent#getComponent}) The
  56  * {@code source} property will be set to this
  57  * {@code TrayIcon}. (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} 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} 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     private transient 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} with the specified image.
 151      *
 152      * @param image the {@code Image} to be used
 153      * @throws IllegalArgumentException if {@code image} is
 154      * {@code null}
 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} with the specified image and
 177      * tooltip text.
 178      *
 179      * @param image the {@code Image} to be used
 180      * @param tooltip the string to be used as tooltip text; if the
 181      * value is {@code null} no tooltip is shown
 182      * @throws IllegalArgumentException if {@code image} is
 183      * {@code null}
 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} with the specified image,
 203      * tooltip and popup menu.
 204      *
 205      * @param image the {@code Image} to be used
 206      * @param tooltip the string to be used as tooltip text; if the
 207      * value is {@code null} 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} no popup menu is shown
 210      * @throws IllegalArgumentException if {@code image} is {@code null}
 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}.  The previous
 233      * tray icon image is discarded without calling the {@link
 234      * java.awt.Image#flush} method — 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} is {@code null}
 247      * @param image the non-null {@code Image} 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}.
 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}.  If
 278      * {@code popup} is {@code null}, no popup menu will be
 279      * associated with this {@code TrayIcon}.
 280      *
 281      * <p>Note that this {@code popup} 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} 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} or {@code null} 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}.
 322      *
 323      * @return the popup menu or {@code null} 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}. The
 332      * tooltip is displayed automatically when the mouse hovers over
 333      * the icon.  Setting the tooltip to {@code null} 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} 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}.
 355      *
 356      * @return the tooltip string or {@code null} 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}.
 368      *
 369      * <p> If auto-size is {@code false}, and the image size
 370      * doesn't match the tray icon space, the image is painted as-is
 371      * inside that space — if larger than the allocated space, it will
 372      * be cropped.
 373      *
 374      * <p> If auto-size is {@code true}, the image is stretched or shrunk to
 375      * fit the tray icon space.
 376      *
 377      * @param autosize {@code true} to auto-size the image,
 378      * {@code false} 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} if the image will be auto-sized,
 394      * {@code false} 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}.  Calling this method with a
 404      * {@code null} 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} and
 411      * {@code MOUSE_EXITED} 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} 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}.
 450      *
 451      * @return all of the {@code MouseListeners} registered on
 452      * this {@code TrayIcon} 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}.  Calling this method
 466      * with a {@code null} 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} 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} 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}.
 511      *
 512      * @return all of the {@code MouseInputListeners} registered on
 513      * this {@code TrayIcon} 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} 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}.
 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}s from this {@code TrayIcon}.
 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} 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} 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}.
 598      *
 599      * @return all of the {@code ActionListeners} registered on
 600      * this {@code TrayIcon} 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}, but an
 637      * {@code NullPointerException} is thrown if both are
 638      * {@code null}.
 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}
 649      * @param text the text displayed for the particular message; may be
 650      * {@code null}
 651      * @param messageType an enum indicating the message type
 652      * @throws NullPointerException if both {@code caption}
 653      * and {@code text} are {@code null}
 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 }