Taskbar.java revision 16928:88125261d41e
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
26package java.awt;
27
28import java.awt.peer.TaskbarPeer;
29import 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
51public 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}
485