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 }