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