1 /*******************************************************************************
2 * Copyright (c) 2000, 2016 IBM Corporation and others.
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
12 * IBM Corporation - initial API and implementation
13 * Tasktop Technologies - initial API and implementation
14 *******************************************************************************/
15 package org.eclipse.swt.widgets;
18 import org.eclipse.swt.*;
19 import org.eclipse.swt.graphics.*;
20 import org.eclipse.swt.internal.win32.*;
23 * Instances of this class represent a task item.
26 * <dt><b>Styles:</b></dt>
28 * <dt><b>Events:</b></dt>
32 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
36 * @noextend This class is not intended to be subclassed by clients.
38 public class TaskItem extends Item {
41 int progress, progressState = SWT.DEFAULT;
43 String overlayText = "";
44 boolean showingText = false;
47 static final int PROGRESS_MAX = 100;
50 * Constructs a new instance of this class given its parent
51 * (which must be a <code>Tray</code>) and a style value
52 * describing its behavior and appearance. The item is added
53 * to the end of the items maintained by its parent.
55 * The style value is either one of the style constants defined in
56 * class <code>SWT</code> which is applicable to instances of this
57 * class, or must be built by <em>bitwise OR</em>'ing together
58 * (that is, using the <code>int</code> "|" operator) two or more
59 * of those <code>SWT</code> style constants. The class description
60 * lists the style constants that are applicable to the class.
61 * Style bits are also inherited from superclasses.
64 * @param parent a composite control which will be the parent of the new instance (cannot be null)
65 * @param style the style of control to construct
67 * @exception IllegalArgumentException <ul>
68 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
70 * @exception SWTException <ul>
71 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
72 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
76 * @see Widget#checkSubclass
77 * @see Widget#getStyle
79 TaskItem (TaskBar parent, int style) {
80 super (parent, style);
82 parent.createItem (this, -1);
86 protected void checkSubclass () {
87 if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
91 void destroyWidget () {
92 parent.destroyItem (this);
97 * Returns the receiver's pop up menu if it has one, or null
100 * @return the receiver's menu
102 * @exception SWTException <ul>
103 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
104 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
108 public Menu getMenu () {
114 * Returns the receiver's overlay image if it has one, or null
117 * @return the receiver's overlay image
119 * @exception SWTException <ul>
120 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
121 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
124 public Image getOverlayImage () {
130 * Returns the receiver's overlay text, which will be an empty
131 * string if it has never been set.
133 * @return the receiver's overlay text
135 * @exception SWTException <ul>
136 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
137 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
140 public String getOverlayText () {
146 * Returns the receiver's parent, which must be a <code>TaskBar</code>.
148 * @return the receiver's parent
150 * @exception SWTException <ul>
151 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
152 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
156 public TaskBar getParent () {
162 * Returns the receiver's progress.
164 * @return the receiver's progress
166 * @exception SWTException <ul>
167 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
168 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
171 public int getProgress () {
177 * Returns the receiver's progress state.
179 * @return the receiver's progress state
181 * @exception SWTException <ul>
182 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
183 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
186 public int getProgressState () {
188 return progressState;
193 if (overlayText.length () != 0) updateText ();
195 if (overlayImage != null) updateImage ();
197 if (progress != 0) updateProgress ();
198 if (progressState != SWT.DEFAULT) updateProgressState ();
202 void releaseHandle () {
203 super.releaseHandle ();
208 void releaseWidget () {
209 super.releaseWidget ();
215 * Sets the receiver's pop up menu to the argument. The way the menu is
216 * shown is platform specific.
219 * This feature might not be available for the receiver on all
220 * platforms. The application code can check if it is supported
221 * by calling the respective get method. When the feature is not
222 * available, the get method will always return the NULL.</p>
225 * For better cross platform support, the application code should
226 * set this feature on the <code>TaskItem</code> for application.<br>
227 * On Windows, this feature will only work on RCP applications.</p>
230 * The menu should be fully created before this method is called.
231 * Dynamic changes to the menu after the method is called will not be reflected
232 * in the native menu.</p>
234 * @param menu the new pop up menu
236 * @exception IllegalArgumentException <ul>
237 * <li>ERROR_MENU_NOT_POP_UP - the menu is not a pop up menu</li>
238 * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li>
240 * @exception SWTException <ul>
241 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
242 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
245 public void setMenu (Menu menu) {
248 if (menu.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
249 if ((menu.style & SWT.POP_UP) == 0) {
250 error (SWT.ERROR_MENU_NOT_POP_UP);
253 if (shell != null) return;
255 parent.setMenu (menu);
259 * Sets the receiver's overlay image, which may be null
260 * indicating that no image should be displayed. The bounds
261 * for the overlay image is determined by the platform and in
262 * general it should be a small image.
265 * This feature might not be available for the receiver on all
266 * platforms. The application code can check if it is supported
267 * by calling the respective get method. When the feature is not
268 * available, the get method will always return the NULL.</p>
271 * For better cross platform support, the application code should
272 * first try to set this feature on the <code>TaskItem</code> for the
273 * main shell then on the <code>TaskItem</code> for the application.</p>
275 * @param overlayImage the new overlay image (may be null)
277 * @exception IllegalArgumentException <ul>
278 * <li>ERROR_INVALID_ARGUMENT - if the overlayImage has been disposed</li>
280 * @exception SWTException <ul>
281 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
282 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
285 public void setOverlayImage (Image overlayImage) {
287 if (overlayImage != null && overlayImage.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
288 if (shell == null) return;
289 this.overlayImage = overlayImage;
290 if (overlayImage != null) {
293 if (overlayText.length () != 0) {
296 parent.mTaskbarList3.SetOverlayIcon(shell.handle, 0, 0);
302 * Sets the receiver's overlay text. The space available to display the
303 * overlay text is platform dependent and in general it should be no longer
304 * than a few characters.
307 * This feature might not be available for the receiver on all
308 * platforms. The application code can check if it is supported
309 * by calling the respective get method. When the feature is not
310 * available, the get method will always return an empty string.</p>
313 * For better cross platform support, the application code should
314 * first try to set this feature on the <code>TaskItem</code> for the
315 * main shell then on the <code>TaskItem</code> for the application.</p>
317 * @param overlayText the new overlay text
319 * @exception IllegalArgumentException <ul>
320 * <li>ERROR_NULL_ARGUMENT - if the overlayText is null</li>
322 * @exception SWTException <ul>
323 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
324 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
327 public void setOverlayText (String overlayText) {
329 if (overlayText == null) error (SWT.ERROR_NULL_ARGUMENT);
330 if (shell == null) return;
331 this.overlayText = overlayText;
332 if (overlayText.length () != 0) {
335 if (overlayImage != null) {
338 parent.mTaskbarList3.SetOverlayIcon(shell.handle, 0, 0);
344 * Sets the receiver's progress, the progress represents a percentage and
345 * should be in range from 0 to 100. The progress is only shown when the progress
346 * state is different than <code>SWT#DEFAULT</code>.
349 * This feature might not be available for the receiver on all
350 * platforms. The application code can check if it is supported
351 * by calling the respective get method. When the feature is not
352 * available, the get method will always return zero.</p>
355 * For better cross platform support, the application code should
356 * first try to set this feature on the <code>TaskItem</code> for the
357 * main shell then on the <code>TaskItem</code> for the application.</p>
359 * @param progress the new progress
361 * @exception SWTException <ul>
362 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
363 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
366 * #see {@link #setProgressState(int)}
368 public void setProgress (int progress) {
370 if (shell == null) return;
371 progress = Math.max (0, Math.min (progress, PROGRESS_MAX));
372 if (this.progress == progress) return;
373 this.progress = progress;
378 * Sets the receiver's progress state, the state can be one of
381 * <li>{@link SWT#DEFAULT}</li>
382 * <li>{@link SWT#NORMAL}</li>
383 * <li>{@link SWT#PAUSED}</li>
384 * <li>{@link SWT#ERROR}</li>
385 * <li>{@link SWT#INDETERMINATE}</li>
388 * The percentage of progress shown by the states <code>SWT#NORMAL</code>, <code>SWT#PAUSED</code>,
389 * <code>SWT#ERROR</code> is set with <code>setProgress()</code>. <br>
390 * The state <code>SWT#DEFAULT</code> indicates that no progress should be shown.
393 * This feature might not be available for the receiver on all
394 * platforms. The application code can check if it is supported
395 * by calling the respective get method. When the feature is not
396 * available, the get method will always return <code>SWT#DEFAULT</code>.</p>
399 * For better cross platform support, the application code should
400 * first try to set this feature on the <code>TaskItem</code> for the
401 * main shell then on the <code>TaskItem</code> for the application.</p>
403 * @param progressState the new progress state
405 * @exception SWTException <ul>
406 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
407 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
410 * #see {@link #setProgress(int)}
412 public void setProgressState (int progressState) {
414 if (shell == null) return;
415 if (this.progressState == progressState) return;
416 this.progressState = progressState;
417 updateProgressState ();
420 void setShell (Shell shell) {
422 shell.addListener (SWT.Dispose, new Listener () {
424 public void handleEvent (Event event) {
425 if (isDisposed ()) return;
431 void updateImage () {
435 switch (overlayImage.type) {
437 image2 = Display.createIcon (overlayImage);
438 hIcon = image2.handle;
441 hIcon = overlayImage.handle;
444 parent.mTaskbarList3.SetOverlayIcon(shell.handle, hIcon, 0);
445 if (image2 != null) image2.dispose ();
448 void updateProgress () {
449 if (progressState == SWT.INDETERMINATE) return;
450 if (progressState == SWT.DEFAULT) return;
451 parent.mTaskbarList3.SetProgressValue(shell.handle, progress, PROGRESS_MAX);
454 void updateProgressState () {
455 int tbpFlags = OS.TBPF_NOPROGRESS;
456 switch (progressState) {
457 case SWT.NORMAL: tbpFlags = OS.TBPF_NORMAL; break;
458 case SWT.ERROR: tbpFlags = OS.TBPF_ERROR; break;
459 case SWT.PAUSED: tbpFlags = OS.TBPF_PAUSED; break;
460 case SWT.INDETERMINATE: tbpFlags = OS.TBPF_INDETERMINATE; break;
462 parent.mTaskbarList3.SetProgressValue(shell.handle, progress, PROGRESS_MAX);
463 parent.mTaskbarList3.SetProgressState(shell.handle, tbpFlags);
468 /* Create resources */
469 int width = 16, height = 16;
470 long hdc = OS.GetDC (0);
471 BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER ();
472 bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
473 bmiHeader.biWidth = width;
474 bmiHeader.biHeight = -height;
475 bmiHeader.biPlanes = 1;
476 bmiHeader.biBitCount = 32;
477 bmiHeader.biCompression = OS.BI_RGB;
478 byte [] bmi = new byte [BITMAPINFOHEADER.sizeof];
479 OS.MoveMemory (bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
480 long [] pBits = new long [1];
481 long hBitmap = OS.CreateDIBSection (0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
482 if (hBitmap == 0) error (SWT.ERROR_NO_HANDLES);
483 long dstHdc = OS.CreateCompatibleDC (hdc);
484 long oldBitmap = OS.SelectObject (dstHdc, hBitmap);
485 long hMask = OS.CreateBitmap (width, height, 1, 1, null);
486 if (hMask == 0) error (SWT.ERROR_NO_HANDLES);
487 long maskHdc = OS.CreateCompatibleDC (hdc);
488 long oldMask = OS.SelectObject (maskHdc, hMask);
491 OS.PatBlt (maskHdc, 0, 0, width, height, OS.WHITENESS);
492 long oldBrush = OS.SelectObject (maskHdc, OS.GetStockObject (OS.BLACK_BRUSH));
493 OS.RoundRect (maskHdc, 0, 0, width, height, 8, 8);
494 OS.SelectObject (maskHdc, oldBrush);
496 long brush = OS.CreateSolidBrush (OS.GetSysColor (OS.COLOR_HIGHLIGHT));
497 oldBrush = OS.SelectObject (dstHdc, brush);
498 OS.RoundRect (dstHdc, 0, 0, width, height, 8, 8);
499 OS.SelectObject (dstHdc, oldBrush);
500 OS.DeleteObject (brush);
502 int uFormat = OS.DT_LEFT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
503 RECT rect = new RECT ();
504 char [] buffer = overlayText.toCharArray ();
505 int length = buffer.length;
506 long hFont = 0, oldHFont = 0;
507 NONCLIENTMETRICS info = new NONCLIENTMETRICS ();
508 info.cbSize = NONCLIENTMETRICS.sizeof;
509 if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) {
510 LOGFONT logFont = info.lfMessageFont;
511 logFont.lfHeight = -10;
512 hFont = OS.CreateFontIndirect (logFont);
513 oldHFont = OS.SelectObject (dstHdc, hFont);
514 OS.DrawText (dstHdc, buffer, length, rect, uFormat | OS.DT_CALCRECT);
515 if (rect.right > width - 2) {
516 OS.SelectObject (dstHdc, oldHFont);
517 OS.DeleteObject (hFont);
518 logFont.lfHeight = -8;
519 hFont = OS.CreateFontIndirect (logFont);
520 OS.SelectObject (dstHdc, hFont);
523 OS.DrawText (dstHdc, buffer, length, rect, uFormat | OS.DT_CALCRECT);
524 OS.OffsetRect (rect, (width - rect.right) / 2, (height - rect.bottom) / 2);
525 int oldBkMode = OS.SetBkMode (dstHdc, OS.TRANSPARENT);
526 OS.SetTextColor (dstHdc, OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT));
527 OS.DrawText (dstHdc, buffer, length, rect, uFormat);
529 OS.SelectObject (dstHdc, oldHFont);
530 OS.DeleteObject (hFont);
532 OS.SetBkMode(dstHdc, oldBkMode);
534 /* Release resources */
535 OS.SelectObject (dstHdc, oldBitmap);
536 OS.DeleteDC (dstHdc);
537 OS.SelectObject (maskHdc, oldMask);
538 OS.DeleteDC (maskHdc);
539 OS.ReleaseDC (0, hdc);
541 ICONINFO iconInfo = new ICONINFO ();
542 iconInfo.fIcon = true;
543 iconInfo.hbmColor = hBitmap;
544 iconInfo.hbmMask = hMask;
545 long hIcon = OS.CreateIconIndirect (iconInfo);
546 if (hIcon == 0) error (SWT.ERROR_NO_HANDLES);
547 OS.DeleteObject (hBitmap);
548 OS.DeleteObject (hMask);
550 parent.mTaskbarList3.SetOverlayIcon(shell.handle, hIcon, 0);
551 OS.DestroyIcon (hIcon);