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