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