1 /*
   2  * Copyright (c) 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.peer.TaskbarPeer;
  29 import sun.awt.SunToolkit;
  30 
  31 /**
  32  * The {@code Taskbar} class allows a Java application to interact with
  33  * the system task area (taskbar, Dock, etc.).
  34  *
  35  * <p>
  36  * There are a variety of interactions depending on the current platform such as
  37  * displaying progress of some task, appending user-specified menu to the application
  38  * icon context menu, etc.
  39  *
  40  * @implNote Linux support is currently limited to Unity. However to make these
  41  * features work on Unity, the app should be run from a .desktop file with
  42  * specified {@code java.desktop.appName} system property set to this .desktop
  43  * file name:
  44  * {@code Exec=java -Djava.desktop.appName=MyApp.desktop -jar /path/to/myapp.jar}
  45  * see <a href="https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles">
  46  * https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles</a>
  47  *
  48  * @since 9
  49  */
  50 
  51 public class Taskbar {
  52 
  53     /**
  54      * List of provided features. Each platform supports a different
  55      * set of features.  You may use the {@link Taskbar#isSupported}
  56      * method to determine if the given feature is supported by the
  57      * current platform.
  58      */
  59     public static enum Feature {
  60 
  61         /**
  62          * Represents a textual icon badge feature.
  63          * @see #setIconBadge(java.lang.String)
  64          */
  65         ICON_BADGE_TEXT,
  66 
  67         /**
  68          * Represents a numerical icon badge feature.
  69          * @see #setIconBadge(java.lang.String)
  70          */
  71         ICON_BADGE_NUMBER,
  72 
  73         /**
  74          * Represents a graphical icon badge feature for a window.
  75          * @see #setWindowIconBadge(java.awt.Window, java.awt.Image)
  76          */
  77         ICON_BADGE_IMAGE_WINDOW,
  78 
  79         /**
  80          * Represents an icon feature.
  81          * @see #setIconImage(java.awt.Image)
  82          */
  83         ICON_IMAGE,
  84 
  85         /**
  86          * Represents a menu feature.
  87          * @see #setMenu(java.awt.PopupMenu)
  88          * @see #getMenu()
  89          */
  90         MENU,
  91 
  92         /**
  93          * Represents a progress state feature for a specified window.
  94          * @see #setWindowProgressState(java.awt.Window, State)
  95          */
  96         PROGRESS_STATE_WINDOW,
  97 
  98         /**
  99          * Represents a progress value feature.
 100          * @see #setProgressValue(int)
 101          */
 102         PROGRESS_VALUE,
 103 
 104         /**
 105          * Represents a progress value feature for a specified window.
 106          * @see #setWindowProgressValue(java.awt.Window, int)
 107          */
 108         PROGRESS_VALUE_WINDOW,
 109 
 110         /**
 111          * Represents a user attention request feature.
 112          * @see #requestUserAttention(boolean, boolean)
 113          */
 114         USER_ATTENTION,
 115 
 116         /**
 117          * Represents a user attention request feature for a specified window.
 118          * @see #requestWindowUserAttention(java.awt.Window)
 119          */
 120         USER_ATTENTION_WINDOW
 121     }
 122 
 123     /**
 124      * Kinds of available window progress states.
 125      *
 126      * @see #setWindowProgressState(java.awt.Window, java.awt.Taskbar.State)
 127      */
 128     public static enum State {
 129         /**
 130          * Stops displaying the progress.
 131          */
 132         OFF,
 133         /**
 134          * The progress indicator displays with normal color and determinate
 135          * mode.
 136          */
 137         NORMAL,
 138         /**
 139          * Shows progress as paused, progress can be resumed by the user.
 140          * Switches to the determinate display.
 141          */
 142         PAUSED,
 143         /**
 144          * The progress indicator displays activity without specifying what
 145          * proportion of the progress is complete.
 146          */
 147         INDETERMINATE,
 148         /**
 149          * Shows that an error has occurred. Switches to the determinate
 150          * display.
 151          */
 152         ERROR
 153     }
 154 
 155     private TaskbarPeer peer;
 156 
 157     /**
 158      * Tests whether a {@code Feature} is supported on the current platform.
 159      * @param feature the specified {@link Feature}
 160      * @return true if the specified feature is supported on the current platform
 161      */
 162     public boolean isSupported(Feature feature) {
 163         return peer.isSupported(feature);
 164     }
 165 
 166     /**
 167      * Checks if the feature type is supported.
 168      *
 169      * @param featureType the action type in question
 170      * @throws UnsupportedOperationException if the specified action type is not
 171      *         supported on the current platform
 172      */
 173     private void checkFeatureSupport(Feature featureType){
 174         if (!isSupported(featureType)) {
 175             throw new UnsupportedOperationException("The " + featureType.name()
 176                     + " feature is not supported on the current platform!");
 177         }
 178     }
 179 
 180     /**
 181      *  Calls to the security manager's {@code checkPermission} method with
 182      *  an {@code RuntimePermission("canProcessApplicationEvents")} permissions.
 183      */
 184     private void checkEventsProcessingPermission(){
 185         SecurityManager sm = System.getSecurityManager();
 186         if (sm != null) {
 187             sm.checkPermission(new RuntimePermission(
 188                     "canProcessApplicationEvents"));
 189         }
 190     }
 191 
 192     private Taskbar() {
 193         Toolkit defaultToolkit = Toolkit.getDefaultToolkit();
 194         if (defaultToolkit instanceof SunToolkit) {
 195             peer = ((SunToolkit) defaultToolkit).createTaskbarPeer(this);
 196         }
 197     }
 198 
 199     /**
 200      * Returns the {@code Taskbar} instance of the current
 201      * taskbar context.  On some platforms the Taskbar API may not be
 202      * supported; use the {@link #isTaskbarSupported} method to
 203      * determine if the current taskbar is supported.
 204      * @return the Taskbar instance
 205      * @throws HeadlessException if {@link
 206      * GraphicsEnvironment#isHeadless()} returns {@code true}
 207      * @throws UnsupportedOperationException if this class is not
 208      * supported on the current platform
 209      * @see #isTaskbarSupported()
 210      * @see java.awt.GraphicsEnvironment#isHeadless
 211      */
 212     public static synchronized Taskbar getTaskbar(){
 213         if (GraphicsEnvironment.isHeadless()) throw new HeadlessException();
 214 
 215         if (!Taskbar.isTaskbarSupported()) {
 216             throw new UnsupportedOperationException("Taskbar API is not " +
 217                                                     "supported on the current platform");
 218         }
 219 
 220         sun.awt.AppContext context = sun.awt.AppContext.getAppContext();
 221         Taskbar taskbar = (Taskbar)context.get(Taskbar.class);
 222 
 223         if (taskbar == null) {
 224             taskbar = new Taskbar();
 225             context.put(Taskbar.class, taskbar);
 226         }
 227 
 228         return taskbar;
 229     }
 230 
 231     /**
 232      * Tests whether this class is supported on the current platform.
 233      * If it's supported, use {@link #getTaskbar()} to retrieve an
 234      * instance.
 235      *
 236      * @return {@code true} if this class is supported on the
 237      *         current platform; {@code false} otherwise
 238      * @see #getTaskbar()
 239      */
 240     public static boolean isTaskbarSupported(){
 241         Toolkit defaultToolkit = Toolkit.getDefaultToolkit();
 242         if (defaultToolkit instanceof SunToolkit) {
 243             return ((SunToolkit)defaultToolkit).isTaskbarSupported();
 244         }
 245         return false;
 246     }
 247 
 248     /**
 249      * Requests user attention to this application.
 250      *
 251      * Depending on the platform, this may be visually indicated by a bouncing
 252      * or flashing icon in the task area. It may have no effect on an already active
 253      * application.
 254      *
 255      * On some platforms (e.g. Mac OS) this effect may disappear upon app activation
 256      * and cannot be dismissed by setting {@code enabled} to false.
 257      * Other platforms may require an additional call
 258      * {@link #requestUserAttention} to dismiss this request
 259      * with {@code enabled} parameter set to false.
 260      *
 261      * @param enabled disables this request if false
 262      * @param critical if this is an important request
 263      * @throws SecurityException if a security manager exists and it denies the
 264      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 265      * @throws UnsupportedOperationException if the current platform
 266      * does not support the {@link Taskbar.Feature#USER_ATTENTION} feature
 267      */
 268     public void requestUserAttention(final boolean enabled, final boolean critical) {
 269         checkEventsProcessingPermission();
 270         checkFeatureSupport(Feature.USER_ATTENTION);
 271         peer.requestUserAttention(enabled, critical);
 272     }
 273 
 274     /**
 275      * Requests user attention to the specified window.
 276      *
 277      * Has no effect if a window representation is not displayable in 
 278      * the task area. Whether it is displayable is dependent on all 
 279      * of window type, platform, and implementation.
 280      *
 281      * @param w window
 282      * @throws SecurityException if a security manager exists and it denies the
 283      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 284      * @throws UnsupportedOperationException if the current platform
 285      * does not support the {@link Taskbar.Feature#USER_ATTENTION_WINDOW} feature
 286      */
 287     public void requestWindowUserAttention(Window w) {
 288         checkEventsProcessingPermission();
 289         checkFeatureSupport(Feature.USER_ATTENTION_WINDOW);
 290         peer.requestWindowUserAttention(w);
 291     }
 292 
 293     /**
 294      * Attaches the contents of the provided PopupMenu to the application icon
 295      * in the task area.
 296      *
 297      * @param menu the PopupMenu to attach to this application
 298      * @throws SecurityException if a security manager exists and it denies the
 299      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 300      * @throws UnsupportedOperationException if the current platform
 301      * does not support the {@link Taskbar.Feature#MENU} feature
 302      */
 303     public void setMenu(final PopupMenu menu) {
 304         checkEventsProcessingPermission();
 305         checkFeatureSupport(Feature.MENU);
 306         peer.setMenu(menu);
 307     }
 308 
 309     /**
 310      * Gets PopupMenu used to add items to this application's icon in system task area.
 311      *
 312      * @return the PopupMenu
 313      * @throws SecurityException if a security manager exists and it denies the
 314      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 315      * @throws UnsupportedOperationException if the current platform
 316      * does not support the {@link Taskbar.Feature#MENU} feature
 317      */
 318     public PopupMenu getMenu() {
 319         checkEventsProcessingPermission();
 320         checkFeatureSupport(Feature.MENU);
 321         return peer.getMenu();
 322     }
 323 
 324     /**
 325      * Changes this application's icon to the provided image.
 326      *
 327      * @param image to change
 328      * @throws SecurityException if a security manager exists and it denies the
 329      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 330      * @throws UnsupportedOperationException if the current platform
 331      * does not support the {@link Taskbar.Feature#ICON_IMAGE} feature
 332      */
 333     public void setIconImage(final Image image) {
 334         checkEventsProcessingPermission();
 335         checkFeatureSupport(Feature.ICON_IMAGE);
 336         peer.setIconImage(image);
 337     }
 338 
 339     /**
 340      * Obtains an image of this application's icon.
 341      *
 342      * @return an image of this application's icon
 343      * @throws SecurityException if a security manager exists and it denies the
 344      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 345      * @throws UnsupportedOperationException if the current platform
 346      * does not support the {@link Taskbar.Feature#ICON_IMAGE} feature
 347      */
 348     public Image getIconImage() {
 349         checkEventsProcessingPermission();
 350         checkFeatureSupport(Feature.ICON_IMAGE);
 351         return peer.getIconImage();
 352     }
 353 
 354     /**
 355      * Affixes a small system-provided badge to this application's icon.
 356      * Usually a number.
 357      *
 358      * Some platforms do not support string values and accept only integer
 359      * values. In this case, pass an integer represented as a string as parameter.
 360      * This can be tested by {@code Feature.ICON_BADGE_TEXT} and
 361      * {@code Feature.ICON_BADGE_NUMBER}.
 362      *
 363      * Passing {@code null} as parameter hides the badge.
 364      * @param badge label to affix to the icon
 365      * @throws SecurityException if a security manager exists and it denies the
 366      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 367      * @throws UnsupportedOperationException if the current platform
 368      * does not support the {@link Taskbar.Feature#ICON_BADGE_NUMBER}
 369      * or {@link Taskbar.Feature#ICON_BADGE_TEXT} feature
 370      */
 371     public void setIconBadge(final String badge) {
 372         checkEventsProcessingPermission();
 373         checkFeatureSupport(Feature.ICON_BADGE_NUMBER);
 374         peer.setIconBadge(badge);
 375     }
 376 
 377     /**
 378      * Affixes a small badge to this application's icon in the task area
 379      * for the specified window.
 380      * It may be disabled by system settings.
 381      *
 382      * Has no effect if a window representation is not displayable in 
 383      * the task area. Whether it is displayable is dependent on all 
 384      * of window type, platform, and implementation.
 385      *
 386      * @param w window to update
 387      * @param badge image to affix to the icon
 388      * @throws SecurityException if a security manager exists and it denies the
 389      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 390      * @throws UnsupportedOperationException if the current platform
 391      * does not support the {@link Taskbar.Feature#ICON_BADGE_IMAGE_WINDOW} feature
 392      */
 393     public void setWindowIconBadge(Window w, final Image badge) {
 394         checkEventsProcessingPermission();
 395         checkFeatureSupport(Feature.ICON_BADGE_IMAGE_WINDOW);
 396         if (w != null) {
 397             peer.setWindowIconBadge(w, badge);
 398         }
 399     }
 400 
 401 
 402     /**
 403      * Affixes a small system-provided progress bar to this application's icon.
 404      *
 405      * @param value from 0 to 100, other to disable progress indication
 406      * @throws SecurityException if a security manager exists and it denies the
 407      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 408      * @throws UnsupportedOperationException if the current platform
 409      * does not support the {@link Taskbar.Feature#PROGRESS_VALUE} feature
 410      */
 411     public void setProgressValue(int value) {
 412         checkEventsProcessingPermission();
 413         checkFeatureSupport(Feature.PROGRESS_VALUE);
 414         peer.setProgressValue(value);
 415     }
 416 
 417     /**
 418      * Displays a determinate progress bar in the task area for the specified
 419      * window.
 420      *
 421      * Has no effect if a window representation is not displayable in 
 422      * the task area. Whether it is displayable is dependent on all 
 423      * of window type, platform, and implementation.
 424      * 
 425      * <br>
 426      * The visual behavior is platform and {@link State} dependent.
 427      * <br>
 428      * This call cancels the {@link State#INDETERMINATE INDETERMINATE} state
 429      * of the window.
 430      * <br>
 431      * Note that when multiple windows is grouped in the task area
 432      * the behavior is platform specific.
 433      *
 434      * @param w window to update
 435      * @param value from 0 to 100, other to switch to {@link State#OFF} state
 436      *              and disable progress indication
 437      * @see #setWindowProgressState(java.awt.Window, State)
 438      * @throws SecurityException if a security manager exists and it denies the
 439      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 440      * @throws UnsupportedOperationException if the current platform
 441      * does not support the {@link Taskbar.Feature#PROGRESS_VALUE_WINDOW} feature
 442      */
 443     public void setWindowProgressValue(Window w, int value) {
 444         checkEventsProcessingPermission();
 445         checkFeatureSupport(Feature.PROGRESS_VALUE_WINDOW);
 446         if (w != null) {
 447             peer.setWindowProgressValue(w, value);
 448         }
 449     }
 450 
 451     /**
 452      * Sets a progress state for a specified window.
 453      *
 454      * Has no effect if a window representation is not displayable in 
 455      * the task area. Whether it is displayable is dependent on all 
 456      * of window type, platform, and implementation.
 457      * <br>
 458      * Each state displays a progress in a platform-dependent way.
 459      * <br>
 460      * Note than switching from {@link State#INDETERMINATE INDETERMINATE} state
 461      * to any of determinate states may reset value set by
 462      * {@link #setWindowProgressValue(java.awt.Window, int) setWindowProgressValue}
 463      *
 464      * @param w window
 465      * @param state to change to
 466      * @see State#OFF
 467      * @see State#NORMAL
 468      * @see State#PAUSED
 469      * @see State#ERROR
 470      * @see State#INDETERMINATE
 471      * @see #setWindowProgressValue(java.awt.Window, int)
 472      * @throws SecurityException if a security manager exists and it denies the
 473      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
 474      * @throws UnsupportedOperationException if the current platform
 475      * does not support the {@link Taskbar.Feature#PROGRESS_STATE_WINDOW} feature
 476      */
 477     public void setWindowProgressState(Window w, State state) {
 478         checkEventsProcessingPermission();
 479         checkFeatureSupport(Feature.PROGRESS_STATE_WINDOW);
 480         if (w != null) {
 481             peer.setWindowProgressState(w, state);
 482         }
 483     }
 484 }