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 }