1 /*
   2  * Copyright (c) 2005, 2016, 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.desktop.AboutHandler;
  29 import java.awt.desktop.OpenFilesHandler;
  30 import java.awt.desktop.OpenURIHandler;
  31 import java.awt.desktop.PreferencesHandler;
  32 import java.awt.desktop.PrintFilesHandler;
  33 import java.awt.desktop.QuitHandler;
  34 import java.awt.desktop.QuitStrategy;
  35 import java.awt.desktop.SystemEventListener;
  36 import java.awt.peer.DesktopPeer;
  37 import java.io.File;
  38 import java.io.FilePermission;
  39 import java.io.IOException;
  40 import java.net.MalformedURLException;
  41 import java.net.URI;
  42 import java.net.URISyntaxException;
  43 import java.net.URL;
  44 
  45 import sun.awt.SunToolkit;
  46 import sun.security.util.SecurityConstants;
  47 
  48 /**
  49  * The {@code Desktop} class allows interact with various desktop capabilities.
  50  *
  51  * <p> Supported operations include:
  52  * <ul>
  53  *   <li>launching the user-default browser to show a specified
  54  *       URI;</li>
  55  *   <li>launching the user-default mail client with an optional
  56  *       {@code mailto} URI;</li>
  57  *   <li>launching a registered application to open, edit or print a
  58  *       specified file.</li>
  59  * </ul>
  60  *
  61  * <p> This class provides methods corresponding to these
  62  * operations. The methods look for the associated application
  63  * registered on the current platform, and launch it to handle a URI
  64  * or file. If there is no associated application or the associated
  65  * application fails to be launched, an exception is thrown.
  66  *
  67  * Please see {@link Desktop.Action} for the full list of supported operations
  68  * and capabilities.
  69  *
  70  * <p> An application is registered to a URI or file type.
  71  * The mechanism of registering, accessing, and
  72  * launching the associated application is platform-dependent.
  73  *
  74  * <p> Each operation is an action type represented by the {@link
  75  * Desktop.Action} class.
  76  *
  77  * <p> Note: when some action is invoked and the associated
  78  * application is executed, it will be executed on the same system as
  79  * the one on which the Java application was launched.
  80  *
  81  * @see Action
  82  *
  83  * @since 1.6
  84  * @author Armin Chen
  85  * @author George Zhang
  86  */
  87 public class Desktop {
  88 
  89     /**
  90      * Represents an action type.  Each platform supports a different
  91      * set of actions.  You may use the {@link Desktop#isSupported}
  92      * method to determine if the given action is supported by the
  93      * current platform.
  94      * @see java.awt.Desktop#isSupported(java.awt.Desktop.Action)
  95      * @since 1.6
  96      */
  97     public static enum Action {
  98         /**
  99          * Represents an "open" action.
 100          * @see Desktop#open(java.io.File)
 101          */
 102         OPEN,
 103         /**
 104          * Represents an "edit" action.
 105          * @see Desktop#edit(java.io.File)
 106          */
 107         EDIT,
 108         /**
 109          * Represents a "print" action.
 110          * @see Desktop#print(java.io.File)
 111          */
 112         PRINT,
 113         /**
 114          * Represents a "mail" action.
 115          * @see Desktop#mail()
 116          * @see Desktop#mail(java.net.URI)
 117          */
 118         MAIL,
 119 
 120         /**
 121          * Represents a "browse" action.
 122          * @see Desktop#browse(java.net.URI)
 123          */
 124         BROWSE,
 125 
 126         /**
 127          * Represents an AppForegroundListener
 128          * @see java.awt.desktop.AppForegroundListener
 129          * @since 9
 130          */
 131         APP_EVENT_FOREGROUND,
 132 
 133         /**
 134          * Represents an AppHiddenListener
 135          * @see java.awt.desktop.AppHiddenListener
 136          * @since 9
 137          */
 138         APP_EVENT_HIDDEN,
 139 
 140         /**
 141          * Represents an AppReopenedListener
 142          * @see java.awt.desktop.AppReopenedListener
 143          * @since 9
 144          */
 145         APP_EVENT_REOPENED,
 146 
 147         /**
 148          * Represents a ScreenSleepListener
 149          * @see java.awt.desktop.ScreenSleepListener
 150          * @since 9
 151          */
 152         APP_EVENT_SCREEN_SLEEP,
 153 
 154         /**
 155          * Represents a SystemSleepListener
 156          * @see java.awt.desktop.SystemSleepListener
 157          * @since 9
 158          */
 159         APP_EVENT_SYSTEM_SLEEP,
 160 
 161         /**
 162          * Represents a UserSessionListener
 163          * @see java.awt.desktop.UserSessionListener
 164          * @since 9
 165          */
 166         APP_EVENT_USER_SESSION,
 167 
 168         /**
 169          * Represents an AboutHandler
 170          * @see #setAboutHandler(java.awt.desktop.AboutHandler)
 171          * @since 9
 172          */
 173         APP_ABOUT,
 174 
 175         /**
 176          * Represents a PreferencesHandler
 177          * @see #setPreferencesHandler(java.awt.desktop.PreferencesHandler)
 178          * @since 9
 179          */
 180         APP_PREFERENCES,
 181 
 182         /**
 183          * Represents an OpenFilesHandler
 184          * @see #setOpenFileHandler(java.awt.desktop.OpenFilesHandler)
 185          * @since 9
 186          */
 187         APP_OPEN_FILE,
 188 
 189         /**
 190          * Represents a PrintFilesHandler
 191          * @see #setPrintFileHandler(java.awt.desktop.PrintFilesHandler)
 192          * @since 9
 193          */
 194         APP_PRINT_FILE,
 195 
 196         /**
 197          * Represents an OpenURIHandler
 198          * @see #setOpenURIHandler(java.awt.desktop.OpenURIHandler)
 199          * @since 9
 200          */
 201         APP_OPEN_URI,
 202 
 203         /**
 204          * Represents a QuitHandler
 205          * @see #setQuitHandler(java.awt.desktop.QuitHandler)
 206          * @since 9
 207          */
 208         APP_QUIT_HANDLER,
 209 
 210         /**
 211          * Represents a QuitStrategy
 212          * @see #setQuitStrategy(java.awt.desktop.QuitStrategy)
 213          * @since 9
 214          */
 215         APP_QUIT_STRATEGY,
 216 
 217         /**
 218          * Represents a SuddenTermination
 219          * @see #enableSuddenTermination()
 220          * @since 9
 221          */
 222         APP_SUDDEN_TERMINATION,
 223 
 224         /**
 225          * Represents a requestForeground
 226          * @see #requestForeground(boolean)
 227          * @since 9
 228          */
 229         APP_REQUEST_FOREGROUND,
 230 
 231         /**
 232          * Represents a HelpViewer
 233          * @see #openHelpViewer()
 234          * @since 9
 235          */
 236         APP_HELP_VIEWER,
 237 
 238         /**
 239          * Represents a menu bar
 240          * @see #setDefaultMenuBar(java.awt.MenuBar)
 241          * @since 9
 242          */
 243         APP_MENU_BAR,
 244 
 245         /**
 246          * Represents a browse file directory
 247          * @see #browseFileDirectory(java.io.File)
 248          * @since 9
 249          */
 250         BROWSE_FILE_DIR,
 251 
 252         /**
 253          * Represents a move to trash
 254          * @see #moveToTrash(java.io.File)
 255          * @since 9
 256          */
 257         MOVE_TO_TRASH
 258     };
 259 
 260     private DesktopPeer peer;
 261 
 262     /**
 263      * Suppresses default constructor for noninstantiability.
 264      */
 265     private Desktop() {
 266         Toolkit defaultToolkit = Toolkit.getDefaultToolkit();
 267         // same cast as in isDesktopSupported()
 268         if (defaultToolkit instanceof SunToolkit) {
 269             peer = ((SunToolkit) defaultToolkit).createDesktopPeer(this);
 270         }
 271     }
 272 
 273     private void checkEventsProcessingPermission() {
 274         SecurityManager sm = System.getSecurityManager();
 275         if (sm != null) {
 276             sm.checkPermission(new RuntimePermission(
 277                     "canProcessApplicationEvents"));
 278         }
 279     }
 280 
 281     /**
 282      * Returns the {@code Desktop} instance of the current
 283      * desktop context. On some platforms the Desktop API may not be
 284      * supported; use the {@link #isDesktopSupported} method to
 285      * determine if the current desktop is supported.
 286      * @return the Desktop instance
 287      * @throws HeadlessException if {@link
 288      * GraphicsEnvironment#isHeadless()} returns {@code true}
 289      * @throws UnsupportedOperationException if this class is not
 290      * supported on the current platform
 291      * @see #isDesktopSupported()
 292      * @see java.awt.GraphicsEnvironment#isHeadless
 293      */
 294     public static synchronized Desktop getDesktop(){
 295         if (GraphicsEnvironment.isHeadless()) throw new HeadlessException();
 296         if (!Desktop.isDesktopSupported()) {
 297             throw new UnsupportedOperationException("Desktop API is not " +
 298                                                     "supported on the current platform");
 299         }
 300 
 301         sun.awt.AppContext context = sun.awt.AppContext.getAppContext();
 302         Desktop desktop = (Desktop)context.get(Desktop.class);
 303 
 304         if (desktop == null) {
 305             desktop = new Desktop();
 306             context.put(Desktop.class, desktop);
 307         }
 308 
 309         return desktop;
 310     }
 311 
 312     /**
 313      * Tests whether this class is supported on the current platform.
 314      * If it's supported, use {@link #getDesktop()} to retrieve an
 315      * instance.
 316      *
 317      * @return {@code true} if this class is supported on the
 318      *         current platform; {@code false} otherwise
 319      * @see #getDesktop()
 320      */
 321     public static boolean isDesktopSupported(){
 322         Toolkit defaultToolkit = Toolkit.getDefaultToolkit();
 323         if (defaultToolkit instanceof SunToolkit) {
 324             return ((SunToolkit)defaultToolkit).isDesktopSupported();
 325         }
 326         return false;
 327     }
 328 
 329     /**
 330      * Tests whether an action is supported on the current platform.
 331      *
 332      * <p>Even when the platform supports an action, a file or URI may
 333      * not have a registered application for the action.  For example,
 334      * most of the platforms support the {@link Desktop.Action#OPEN}
 335      * action.  But for a specific file, there may not be an
 336      * application registered to open it.  In this case, {@link
 337      * #isSupported} may return {@code true}, but the corresponding
 338      * action method will throw an {@link IOException}.
 339      *
 340      * @param action the specified {@link Action}
 341      * @return {@code true} if the specified action is supported on
 342      *         the current platform; {@code false} otherwise
 343      * @see Desktop.Action
 344      */
 345     public boolean isSupported(Action action) {
 346         return peer.isSupported(action);
 347     }
 348 
 349     /**
 350      * Checks if the file is a valid file and readable.
 351      *
 352      * @throws SecurityException If a security manager exists and its
 353      *         {@link SecurityManager#checkRead(java.lang.String)} method
 354      *         denies read access to the file
 355      * @throws NullPointerException if file is null
 356      * @throws IllegalArgumentException if file doesn't exist
 357      */
 358     private static void checkFileValidation(File file){
 359         if (file == null) throw new NullPointerException("File must not be null");
 360 
 361         if (!file.exists()) {
 362             throw new IllegalArgumentException("The file: "
 363                     + file.getPath() + " doesn't exist.");
 364         }
 365 
 366         file.canRead();
 367     }
 368 
 369     /**
 370      * Checks if the action type is supported.
 371      *
 372      * @param actionType the action type in question
 373      * @throws UnsupportedOperationException if the specified action type is not
 374      *         supported on the current platform
 375      */
 376     private void checkActionSupport(Action actionType){
 377         if (!isSupported(actionType)) {
 378             throw new UnsupportedOperationException("The " + actionType.name()
 379                     + " action is not supported on the current platform!");
 380         }
 381     }
 382 
 383 
 384     /**
 385      *  Calls to the security manager's {@code checkPermission} method with
 386      *  an {@code AWTPermission("showWindowWithoutWarningBanner")}
 387      *  permission.
 388      */
 389     private void checkAWTPermission(){
 390         SecurityManager sm = System.getSecurityManager();
 391         if (sm != null) {
 392             sm.checkPermission(new AWTPermission(
 393                     "showWindowWithoutWarningBanner"));
 394         }
 395     }
 396 
 397     /**
 398      * Launches the associated application to open the file.
 399      *
 400      * <p> If the specified file is a directory, the file manager of
 401      * the current platform is launched to open it.
 402      *
 403      * @param file the file to be opened with the associated application
 404      * @throws NullPointerException if {@code file} is {@code null}
 405      * @throws IllegalArgumentException if the specified file doesn't
 406      * exist
 407      * @throws UnsupportedOperationException if the current platform
 408      * does not support the {@link Desktop.Action#OPEN} action
 409      * @throws IOException if the specified file has no associated
 410      * application or the associated application fails to be launched
 411      * @throws SecurityException if a security manager exists and its
 412      * {@link java.lang.SecurityManager#checkRead(java.lang.String)}
 413      * method denies read access to the file, or it denies the
 414      * {@code AWTPermission("showWindowWithoutWarningBanner")}
 415      * permission, or the calling thread is not allowed to create a
 416      * subprocess
 417      * @see java.awt.AWTPermission
 418      */
 419     public void open(File file) throws IOException {
 420         checkAWTPermission();
 421         checkExec();
 422         checkActionSupport(Action.OPEN);
 423         checkFileValidation(file);
 424 
 425         peer.open(file);
 426     }
 427 
 428     /**
 429      * Launches the associated editor application and opens a file for
 430      * editing.
 431      *
 432      * @param file the file to be opened for editing
 433      * @throws NullPointerException if the specified file is {@code null}
 434      * @throws IllegalArgumentException if the specified file doesn't
 435      * exist
 436      * @throws UnsupportedOperationException if the current platform
 437      * does not support the {@link Desktop.Action#EDIT} action
 438      * @throws IOException if the specified file has no associated
 439      * editor, or the associated application fails to be launched
 440      * @throws SecurityException if a security manager exists and its
 441      * {@link java.lang.SecurityManager#checkRead(java.lang.String)}
 442      * method denies read access to the file, or {@link
 443      * java.lang.SecurityManager#checkWrite(java.lang.String)} method
 444      * denies write access to the file, or it denies the
 445      * {@code AWTPermission("showWindowWithoutWarningBanner")}
 446      * permission, or the calling thread is not allowed to create a
 447      * subprocess
 448      * @see java.awt.AWTPermission
 449      */
 450     public void edit(File file) throws IOException {
 451         checkAWTPermission();
 452         checkExec();
 453         checkActionSupport(Action.EDIT);
 454         file.canWrite();
 455         checkFileValidation(file);
 456 
 457         peer.edit(file);
 458     }
 459 
 460     /**
 461      * Prints a file with the native desktop printing facility, using
 462      * the associated application's print command.
 463      *
 464      * @param file the file to be printed
 465      * @throws NullPointerException if the specified file is {@code
 466      * null}
 467      * @throws IllegalArgumentException if the specified file doesn't
 468      * exist
 469      * @throws UnsupportedOperationException if the current platform
 470      *         does not support the {@link Desktop.Action#PRINT} action
 471      * @throws IOException if the specified file has no associated
 472      * application that can be used to print it
 473      * @throws SecurityException if a security manager exists and its
 474      * {@link java.lang.SecurityManager#checkRead(java.lang.String)}
 475      * method denies read access to the file, or its {@link
 476      * java.lang.SecurityManager#checkPrintJobAccess()} method denies
 477      * the permission to print the file, or the calling thread is not
 478      * allowed to create a subprocess
 479      */
 480     public void print(File file) throws IOException {
 481         checkExec();
 482         SecurityManager sm = System.getSecurityManager();
 483         if (sm != null) {
 484             sm.checkPrintJobAccess();
 485         }
 486         checkActionSupport(Action.PRINT);
 487         checkFileValidation(file);
 488 
 489         peer.print(file);
 490     }
 491 
 492     /**
 493      * Launches the default browser to display a {@code URI}.
 494      * If the default browser is not able to handle the specified
 495      * {@code URI}, the application registered for handling
 496      * {@code URIs} of the specified type is invoked. The application
 497      * is determined from the protocol and path of the {@code URI}, as
 498      * defined by the {@code URI} class.
 499      * <p>
 500      * If the calling thread does not have the necessary permissions,
 501      * and this is invoked from within an applet,
 502      * {@code AppletContext.showDocument()} is used. Similarly, if the calling
 503      * does not have the necessary permissions, and this is invoked from within
 504      * a Java Web Started application, {@code BasicService.showDocument()}
 505      * is used.
 506      *
 507      * @param uri the URI to be displayed in the user default browser
 508      * @throws NullPointerException if {@code uri} is {@code null}
 509      * @throws UnsupportedOperationException if the current platform
 510      * does not support the {@link Desktop.Action#BROWSE} action
 511      * @throws IOException if the user default browser is not found,
 512      * or it fails to be launched, or the default handler application
 513      * failed to be launched
 514      * @throws SecurityException if a security manager exists and it
 515      * denies the
 516      * {@code AWTPermission("showWindowWithoutWarningBanner")}
 517      * permission, or the calling thread is not allowed to create a
 518      * subprocess; and not invoked from within an applet or Java Web Started
 519      * application
 520      * @throws IllegalArgumentException if the necessary permissions
 521      * are not available and the URI can not be converted to a {@code URL}
 522      * @see java.net.URI
 523      * @see java.awt.AWTPermission
 524      * @see java.applet.AppletContext
 525      */
 526     public void browse(URI uri) throws IOException {
 527         SecurityException securityException = null;
 528         try {
 529             checkAWTPermission();
 530             checkExec();
 531         } catch (SecurityException e) {
 532             securityException = e;
 533         }
 534         checkActionSupport(Action.BROWSE);
 535         if (uri == null) {
 536             throw new NullPointerException();
 537         }
 538         if (securityException == null) {
 539             peer.browse(uri);
 540             return;
 541         }
 542 
 543         // Calling thread doesn't have necessary privileges.
 544         // Delegate to DesktopBrowse so that it can work in
 545         // applet/webstart.
 546         URL url = null;
 547         try {
 548             url = uri.toURL();
 549         } catch (MalformedURLException e) {
 550             throw new IllegalArgumentException("Unable to convert URI to URL", e);
 551         }
 552         sun.awt.DesktopBrowse db = sun.awt.DesktopBrowse.getInstance();
 553         if (db == null) {
 554             // Not in webstart/applet, throw the exception.
 555             throw securityException;
 556         }
 557         db.browse(url);
 558     }
 559 
 560     /**
 561      * Launches the mail composing window of the user default mail
 562      * client.
 563      *
 564      * @throws UnsupportedOperationException if the current platform
 565      * does not support the {@link Desktop.Action#MAIL} action
 566      * @throws IOException if the user default mail client is not
 567      * found, or it fails to be launched
 568      * @throws SecurityException if a security manager exists and it
 569      * denies the
 570      * {@code AWTPermission("showWindowWithoutWarningBanner")}
 571      * permission, or the calling thread is not allowed to create a
 572      * subprocess
 573      * @see java.awt.AWTPermission
 574      */
 575     public void mail() throws IOException {
 576         checkAWTPermission();
 577         checkExec();
 578         checkActionSupport(Action.MAIL);
 579         URI mailtoURI = null;
 580         try{
 581             mailtoURI = new URI("mailto:?");
 582             peer.mail(mailtoURI);
 583         } catch (URISyntaxException e){
 584             // won't reach here.
 585         }
 586     }
 587 
 588     /**
 589      * Launches the mail composing window of the user default mail
 590      * client, filling the message fields specified by a {@code
 591      * mailto:} URI.
 592      *
 593      * <p> A {@code mailto:} URI can specify message fields
 594      * including <i>"to"</i>, <i>"cc"</i>, <i>"subject"</i>,
 595      * <i>"body"</i>, etc.  See <a
 596      * href="http://www.ietf.org/rfc/rfc2368.txt">The mailto URL
 597      * scheme (RFC 2368)</a> for the {@code mailto:} URI specification
 598      * details.
 599      *
 600      * @param mailtoURI the specified {@code mailto:} URI
 601      * @throws NullPointerException if the specified URI is {@code
 602      * null}
 603      * @throws IllegalArgumentException if the URI scheme is not
 604      *         {@code "mailto"}
 605      * @throws UnsupportedOperationException if the current platform
 606      * does not support the {@link Desktop.Action#MAIL} action
 607      * @throws IOException if the user default mail client is not
 608      * found or fails to be launched
 609      * @throws SecurityException if a security manager exists and it
 610      * denies the
 611      * {@code AWTPermission("showWindowWithoutWarningBanner")}
 612      * permission, or the calling thread is not allowed to create a
 613      * subprocess
 614      * @see java.net.URI
 615      * @see java.awt.AWTPermission
 616      */
 617     public  void mail(URI mailtoURI) throws IOException {
 618         checkAWTPermission();
 619         checkExec();
 620         checkActionSupport(Action.MAIL);
 621         if (mailtoURI == null) throw new NullPointerException();
 622 
 623         if (!"mailto".equalsIgnoreCase(mailtoURI.getScheme())) {
 624             throw new IllegalArgumentException("URI scheme is not \"mailto\"");
 625         }
 626 
 627         peer.mail(mailtoURI);
 628     }
 629 
 630     private void checkExec() throws SecurityException {
 631         SecurityManager sm = System.getSecurityManager();
 632         if (sm != null) {
 633             sm.checkPermission(new FilePermission("<<ALL FILES>>",
 634                     SecurityConstants.FILE_EXECUTE_ACTION));
 635         }
 636     }
 637 
 638     private void checkRead() throws SecurityException {
 639         SecurityManager sm = System.getSecurityManager();
 640         if (sm != null) {
 641             sm.checkPermission(new FilePermission("<<ALL FILES>>",
 642                     SecurityConstants.FILE_READ_ACTION));
 643         }
 644     }
 645 
 646     private void checkDelete() throws SecurityException {
 647         SecurityManager sm = System.getSecurityManager();
 648         if (sm != null) {
 649             sm.checkPermission(new FilePermission("<<ALL FILES>>",
 650                     SecurityConstants.FILE_DELETE_ACTION));
 651         }
 652     }
 653 
 654     private void checkQuitPermission() {
 655         SecurityManager sm = System.getSecurityManager();
 656         if (sm != null) {
 657             sm.checkExit(0);
 658         }
 659     }
 660 
 661     /**
 662      * Adds sub-types of {@link SystemEventListener} to listen for notifications
 663      * from the native system.
 664      *
 665      * Has no effect if SystemEventListener's sub-type is unsupported on the current
 666      * platform.
 667      *
 668      * @param listener listener
 669      *
 670      * @throws SecurityException if a security manager exists and it
 671      * denies the
 672      * {@code RuntimePermission("canProcessApplicationEvents")}
 673      * permission
 674      *
 675      * @see java.awt.desktop.AppForegroundListener
 676      * @see java.awt.desktop.AppHiddenListener
 677      * @see java.awt.desktop.AppReopenedListener
 678      * @see java.awt.desktop.ScreenSleepListener
 679      * @see java.awt.desktop.SystemSleepListener
 680      * @see java.awt.desktop.UserSessionListener
 681      * @since 9
 682      */
 683     public void addAppEventListener(final SystemEventListener listener) {
 684         checkEventsProcessingPermission();
 685         peer.addAppEventListener(listener);
 686     }
 687 
 688     /**
 689      * Removes sub-types of {@link SystemEventListener} to listen for notifications
 690      * from the native system.
 691      *
 692      * Has no effect if SystemEventListener's sub-type is unsupported on  the current
 693      * platform.
 694      *
 695      * @param listener listener
 696      *
 697      * @throws SecurityException if a security manager exists and it
 698      * denies the
 699      * {@code RuntimePermission("canProcessApplicationEvents")}
 700      * permission
 701      *
 702      * @see java.awt.desktop.AppForegroundListener
 703      * @see java.awt.desktop.AppHiddenListener
 704      * @see java.awt.desktop.AppReopenedListener
 705      * @see java.awt.desktop.ScreenSleepListener
 706      * @see java.awt.desktop.SystemSleepListener
 707      * @see java.awt.desktop.UserSessionListener
 708      * @since 9
 709      */
 710     public void removeAppEventListener(final SystemEventListener listener) {
 711         checkEventsProcessingPermission();
 712         peer.removeAppEventListener(listener);
 713     }
 714 
 715     /**
 716      * Installs a handler to show a custom About window for your application.
 717      * <p>
 718      * Setting the {@link java.awt.desktop.AboutHandler} to {@code null} reverts it to the
 719      * default behavior.
 720      *
 721      * @param aboutHandler the handler to respond to the
 722      * {@link java.awt.desktop.AboutHandler#handleAbout} )} message
 723      *
 724      * @throws SecurityException if a security manager exists and it
 725      * denies the
 726      * {@code RuntimePermission("canProcessApplicationEvents")}
 727      * permission
 728      * @throws UnsupportedOperationException if the current platform
 729      * does not support the {@link Desktop.Action#APP_ABOUT} action
 730      *
 731      * @since 9
 732      */
 733     public void setAboutHandler(final AboutHandler aboutHandler) {
 734         checkEventsProcessingPermission();
 735         checkActionSupport(Action.APP_ABOUT);
 736         peer.setAboutHandler(aboutHandler);
 737     }
 738 
 739     /**
 740      * Installs a handler to show a custom Preferences window for your
 741      * application.
 742      * <p>
 743      * Setting the {@link PreferencesHandler} to {@code null} reverts it to
 744      * the default behavior
 745      *
 746      * @param preferencesHandler the handler to respond to the
 747      * {@link PreferencesHandler#handlePreferences(PreferencesEvent)}
 748      *
 749      * @throws SecurityException if a security manager exists and it
 750      * denies the
 751      * {@code RuntimePermission("canProcessApplicationEvents")} permission
 752      * @throws UnsupportedOperationException if the current platform
 753      * does not support the {@link Desktop.Action#APP_PREFERENCES} action
 754      * @since 9
 755      */
 756     public void setPreferencesHandler(final PreferencesHandler preferencesHandler) {
 757         checkEventsProcessingPermission();
 758         checkActionSupport(Action.APP_PREFERENCES);
 759         peer.setPreferencesHandler(preferencesHandler);
 760     }
 761 
 762     /**
 763      * Installs the handler which is notified when the application is asked to
 764      * open a list of files.
 765      *
 766      * @implNote Please note that for Mac OS, notifications
 767      * are only sent if the Java app is a bundled application,
 768      * with a {@code CFBundleDocumentTypes} array present in its
 769      * Info.plist. See the
 770      * <a href="http://developer.apple.com/mac/library/documentation/General/Reference/InfoPlistKeyReference">
 771      * Info.plist Key Reference</a> for more information about adding a
 772      * {@code CFBundleDocumentTypes} key to your app's Info.plist.
 773      *
 774      * @param openFileHandler handler
 775      *
 776      * @throws SecurityException if a security manager exists and its
 777      * {@link java.lang.SecurityManager#checkRead(java.lang.String)}
 778      * method denies read access to the files, or it denies the
 779      * {@code RuntimePermission("canProcessApplicationEvents")}
 780      * permission, or the calling thread is not allowed to create a
 781      * subprocess
 782      * @throws UnsupportedOperationException if the current platform
 783      * does not support the {@link Desktop.Action#APP_OPEN_FILE} action
 784      * @since 9
 785      */
 786     public void setOpenFileHandler(final OpenFilesHandler openFileHandler) {
 787         checkEventsProcessingPermission();
 788         checkExec();
 789         checkRead();
 790         checkActionSupport(Action.APP_OPEN_FILE);
 791         peer.setOpenFileHandler(openFileHandler);
 792     }
 793 
 794     /**
 795      * Installs the handler which is notified when the application is asked to
 796      * print a list of files.
 797      *
 798      * @implNote Please note that for Mac OS, notifications
 799      * are only sent if the Java app is a bundled application,
 800      * with a {@code CFBundleDocumentTypes} array present in its
 801      * Info.plist. See the
 802      * <a href="http://developer.apple.com/mac/library/documentation/General/Reference/InfoPlistKeyReference">
 803      * Info.plist Key Reference</a> for more information about adding a
 804      * {@code CFBundleDocumentTypes} key to your app's Info.plist.
 805      *
 806      * @param printFileHandler handler
 807      * @throws SecurityException if a security manager exists and its
 808      * {@link java.lang.SecurityManager#checkPrintJobAccess()} method denies
 809      * the permission to print or it denies the
 810      * {@code RuntimePermission("canProcessApplicationEvents")} permission
 811      * @throws UnsupportedOperationException if the current platform
 812      * does not support the {@link Desktop.Action#APP_PRINT_FILE} action
 813      * @since 9
 814      */
 815     public void setPrintFileHandler(final PrintFilesHandler printFileHandler) {
 816         checkEventsProcessingPermission();
 817         SecurityManager sm = System.getSecurityManager();
 818         if (sm != null) {
 819             sm.checkPrintJobAccess();
 820         }
 821         checkActionSupport(Action.APP_PRINT_FILE);
 822         peer.setPrintFileHandler(printFileHandler);
 823     }
 824 
 825     /**
 826      * Installs the handler which is notified when the application is asked to
 827      * open a URL.
 828      *
 829      * Setting the handler to {@code null} causes all
 830      * {@link OpenURIHandler#openURI(AppEvent.OpenURIEvent)} requests to be
 831      * enqueued until another handler is set.
 832      *
 833      * @implNote Please note that for Mac OS, notifications
 834      * are only sent if the Java app is a bundled application,
 835      * with a {@code CFBundleDocumentTypes} array present in its
 836      * Info.plist. See the
 837      * <a href="http://developer.apple.com/mac/library/documentation/General/Reference/InfoPlistKeyReference">
 838      * Info.plist Key Reference</a> for more information about adding a
 839      * {@code CFBundleDocumentTypes} key to your app's Info.plist.
 840      *
 841      * @param openURIHandler handler
 842      *
 843      * {@code RuntimePermission("canProcessApplicationEvents")}
 844      * permission, or the calling thread is not allowed to create a
 845      * subprocess
 846      * @throws UnsupportedOperationException if the current platform
 847      * does not support the {@link Desktop.Action#APP_OPEN_URI} action
 848      * @since 9
 849      */
 850     public void setOpenURIHandler(final OpenURIHandler openURIHandler) {
 851         checkEventsProcessingPermission();
 852         checkExec();
 853         checkActionSupport(Action.APP_OPEN_URI);
 854         peer.setOpenURIHandler(openURIHandler);
 855     }
 856 
 857     /**
 858      * Installs the handler which determines if the application should quit. The
 859      * handler is passed a one-shot {@link java.awt.desktop.QuitResponse} which can cancel or
 860      * proceed with the quit. Setting the handler to {@code null} causes
 861      * all quit requests to directly perform the default {@link QuitStrategy}.
 862      *
 863      * @param quitHandler the handler that is called when the application is
 864      * asked to quit
 865      *
 866      * @throws SecurityException if a security manager exists and it
 867      * will not allow the caller to invoke {@code System.exit} or it denies the
 868      * {@code RuntimePermission("canProcessApplicationEvents")} permission
 869      * @throws UnsupportedOperationException if the current platform
 870      * does not support the {@link Desktop.Action#APP_QUIT_HANDLER} action
 871      * @since 9
 872      */
 873     public void setQuitHandler(final QuitHandler quitHandler) {
 874         checkEventsProcessingPermission();
 875         checkQuitPermission();
 876         checkActionSupport(Action.APP_QUIT_HANDLER);
 877         peer.setQuitHandler(quitHandler);
 878     }
 879 
 880     /**
 881      * Sets the default strategy used to quit this application. The default is
 882      * calling SYSTEM_EXIT_0.
 883      *
 884      * @param strategy the way this application should be shutdown
 885      *
 886      * @throws SecurityException if a security manager exists and it
 887      * will not allow the caller to invoke {@code System.exit} or it denies the
 888      * {@code RuntimePermission("canProcessApplicationEvents")} permission
 889      * @throws UnsupportedOperationException if the current platform
 890      * does not support the {@link Desktop.Action#APP_QUIT_STRATEGY} action
 891      * @see QuitStrategy
 892      * @since 9
 893      */
 894     public void setQuitStrategy(final QuitStrategy strategy) {
 895         checkEventsProcessingPermission();
 896         checkQuitPermission();
 897         checkActionSupport(Action.APP_QUIT_STRATEGY);
 898         peer.setQuitStrategy(strategy);
 899     }
 900 
 901     /**
 902      * Enables this application to be suddenly terminated.
 903      *
 904      * Call this method to indicate your application's state is saved, and
 905      * requires no notification to be terminated. Letting your application
 906      * remain terminatable improves the user experience by avoiding re-paging in
 907      * your application when it's asked to quit.
 908      *
 909      * <b>Note: enabling sudden termination will allow your application to be
 910      * quit without notifying your QuitHandler, or running any shutdown
 911      * hooks.</b>
 912      * E.g. user-initiated Cmd-Q, logout, restart, or shutdown requests will
 913      * effectively "kill -KILL" your application.
 914      *
 915      * @throws SecurityException if a security manager exists and it
 916      * will not allow the caller to invoke {@code System.exit} or it denies the
 917      * {@code RuntimePermission("canProcessApplicationEvents")} permission
 918      * @throws UnsupportedOperationException if the current platform
 919      * does not support the {@link Desktop.Action#APP_SUDDEN_TERMINATION} action
 920      * @see #disableSuddenTermination()
 921      * @since 9
 922      */
 923     public void enableSuddenTermination() {
 924         checkEventsProcessingPermission();
 925         checkQuitPermission();
 926         checkActionSupport(Action.APP_SUDDEN_TERMINATION);
 927         peer.enableSuddenTermination();
 928     }
 929 
 930     /**
 931      * Prevents this application from being suddenly terminated.
 932      *
 933      * Call this method to indicate that your application has unsaved state, and
 934      * may not be terminated without notification.
 935      *
 936      * @throws SecurityException if a security manager exists and it
 937      * will not allow the caller to invoke {@code System.exit} or it denies the
 938      * {@code RuntimePermission("canProcessApplicationEvents")} permission
 939      * @throws UnsupportedOperationException if the current platform
 940      * does not support the {@link Desktop.Action#APP_SUDDEN_TERMINATION} action
 941      * @see #enableSuddenTermination()
 942      * @since 9
 943      */
 944     public void disableSuddenTermination() {
 945         checkEventsProcessingPermission();
 946         checkQuitPermission();
 947         checkActionSupport(Action.APP_SUDDEN_TERMINATION);
 948         peer.disableSuddenTermination();
 949     }
 950 
 951     /**
 952      * Requests this application to move to the foreground.
 953      *
 954      * @param allWindows if all windows of this application should be moved to
 955      * the foreground, or only the foremost one
 956      * @throws SecurityException if a security manager exists and it denies the
 957      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 958      * @throws UnsupportedOperationException if the current platform
 959      * does not support the {@link Desktop.Action#APP_REQUEST_FOREGROUND} action
 960      * @since 9
 961      */
 962     public void requestForeground(final boolean allWindows) {
 963         checkEventsProcessingPermission();
 964         checkActionSupport(Action.APP_REQUEST_FOREGROUND);
 965         peer.requestForeground(allWindows);
 966     }
 967 
 968     /**
 969      * Opens the native help viewer application.
 970      *
 971      * @implNote Please note that for Mac OS, it opens the native help viewer
 972      * application if a Help Book has been added to the application bundler
 973      * and registered in the Info.plist with CFBundleHelpBookFolder
 974      *
 975      * @throws SecurityException if a security manager exists and it denies the
 976      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 977      * @throws UnsupportedOperationException if the current platform
 978      * does not support the {@link Desktop.Action#APP_HELP_VIEWER} action
 979      * @since 9
 980      */
 981     public void openHelpViewer() {
 982         checkEventsProcessingPermission();
 983         checkActionSupport(Action.APP_HELP_VIEWER);
 984         peer.openHelpViewer();
 985     }
 986 
 987     /**
 988      * Sets the default menu bar to use when there are no active frames.
 989      *
 990      * @implNote Aqua Look and Feel should be active to support this on Mac OS.
 991      *
 992      * @param menuBar to use when no other frames are active
 993      * @throws SecurityException if a security manager exists and it denies the
 994      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 995      * @throws UnsupportedOperationException if the current platform
 996      * does not support the {@link Desktop.Action#APP_MENU_BAR} action
 997      * @since 9
 998      */
 999     public void setDefaultMenuBar(final MenuBar menuBar) {
1000         checkEventsProcessingPermission();
1001         checkActionSupport(Action.APP_MENU_BAR);
1002         peer.setDefaultMenuBar(menuBar);
1003     }
1004 
1005     /**
1006      * Opens a folder containing the {@code file} and selects it
1007      * in a default system file manager.
1008      * @param file the file
1009      * @throws SecurityException If a security manager exists and its
1010      *         {@link SecurityManager#checkRead(java.lang.String)} method
1011      *         denies read access to the file
1012      * @throws UnsupportedOperationException if the current platform
1013      *         does not support the {@link Desktop.Action#BROWSE_FILE_DIR} action
1014      * @throws NullPointerException if {@code file} is {@code null}
1015      * @throws IllegalArgumentException if the specified file doesn't
1016      * exist
1017      * @since 9
1018      */
1019     public void browseFileDirectory(File file) {
1020         checkRead();
1021         checkActionSupport(Action.BROWSE_FILE_DIR);
1022         checkFileValidation(file);
1023         peer.browseFileDirectory(file);
1024     }
1025 
1026     /**
1027      * Moves the specified file to the trash.
1028      *
1029      * @param file the file
1030      * @return returns true if successfully moved the file to the trash.
1031      * @throws SecurityException If a security manager exists and its
1032      *         {@link SecurityManager#checkDelete(java.lang.String)} method
1033      *         denies deletion of the file
1034      * @throws UnsupportedOperationException if the current platform
1035      *         does not support the {@link Desktop.Action#MOVE_TO_TRASH} action
1036      * @throws NullPointerException if {@code file} is {@code null}
1037      * @throws IllegalArgumentException if the specified file doesn't
1038      * exist
1039      *
1040      * @since 9
1041      */
1042     public boolean moveToTrash(final File file) {
1043         checkDelete();
1044         checkActionSupport(Action.MOVE_TO_TRASH);
1045         checkFileValidation(file);
1046         return peer.moveToTrash(file);
1047     }
1048 }