]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TaskItem.java
Work around SWT 4.13 - 4.18 Win32 DnD bug 567422
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / TaskItem.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2016 IBM Corporation and others.
3  *
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/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Tasktop Technologies - initial API and implementation
14  *******************************************************************************/
15 package org.eclipse.swt.widgets;
16
17
18 import org.eclipse.swt.*;
19 import org.eclipse.swt.graphics.*;
20 import org.eclipse.swt.internal.win32.*;
21
22 /**
23  * Instances of this class represent a task item.
24  *
25  * <dl>
26  * <dt><b>Styles:</b></dt>
27  * <dd>(none)</dd>
28  * <dt><b>Events:</b></dt>
29  * <dd>(none)</dd>
30  * </dl>
31  *
32  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
33  *
34  * @since 3.6
35  *
36  * @noextend This class is not intended to be subclassed by clients.
37  */
38 public class TaskItem extends Item {
39         TaskBar parent;
40         Shell shell;
41         int progress, progressState = SWT.DEFAULT;
42         Image overlayImage;
43         String overlayText = "";
44         boolean showingText = false;
45         Menu menu;
46
47         static final int PROGRESS_MAX = 100;
48
49 /**
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.
54  * <p>
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.
62  * </p>
63  *
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
66  *
67  * @exception IllegalArgumentException <ul>
68  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
69  * </ul>
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>
73  * </ul>
74  *
75  * @see SWT
76  * @see Widget#checkSubclass
77  * @see Widget#getStyle
78  */
79 TaskItem (TaskBar parent, int style) {
80         super (parent, style);
81         this.parent = parent;
82         parent.createItem (this, -1);
83 }
84
85 @Override
86 protected void checkSubclass () {
87         if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
88 }
89
90 @Override
91 void destroyWidget () {
92         parent.destroyItem (this);
93         releaseHandle ();
94 }
95
96 /**
97  * Returns the receiver's pop up menu if it has one, or null
98  * if it does not.
99  *
100  * @return the receiver's menu
101  *
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>
105  * </ul>
106  */
107 @Override
108 public Menu getMenu () {
109         checkWidget ();
110         return menu;
111 }
112
113 /**
114  * Returns the receiver's overlay image if it has one, or null
115  * if it does not.
116  *
117  * @return the receiver's overlay image
118  *
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>
122  * </ul>
123  */
124 public Image getOverlayImage () {
125         checkWidget ();
126         return overlayImage;
127 }
128
129 /**
130  * Returns the receiver's overlay text, which will be an empty
131  * string if it has never been set.
132  *
133  * @return the receiver's overlay text
134  *
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>
138  * </ul>
139  */
140 public String getOverlayText () {
141         checkWidget ();
142         return overlayText;
143 }
144
145 /**
146  * Returns the receiver's parent, which must be a <code>TaskBar</code>.
147  *
148  * @return the receiver's parent
149  *
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>
153  * </ul>
154  *
155  */
156 public TaskBar getParent () {
157         checkWidget ();
158         return parent;
159 }
160
161 /**
162  * Returns the receiver's progress.
163  *
164  * @return the receiver's progress
165  *
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>
169  * </ul>
170  */
171 public int getProgress () {
172         checkWidget ();
173         return progress;
174 }
175
176 /**
177  * Returns the receiver's progress state.
178  *
179  * @return the receiver's progress state
180  *
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>
184  * </ul>
185  */
186 public int getProgressState () {
187         checkWidget ();
188         return progressState;
189 }
190
191 void recreate () {
192         if (showingText) {
193                 if (overlayText.length () != 0) updateText ();
194         } else {
195                 if (overlayImage != null) updateImage ();
196         }
197         if (progress != 0) updateProgress ();
198         if (progressState != SWT.DEFAULT) updateProgressState ();
199 }
200
201 @Override
202 void releaseHandle () {
203         super.releaseHandle ();
204         parent = null;
205 }
206
207 @Override
208 void releaseWidget () {
209         super.releaseWidget ();
210         overlayImage = null;
211         overlayText = null;
212 }
213
214 /**
215  * Sets the receiver's pop up menu to the argument. The way the menu is
216  * shown is platform specific.
217  *
218  * <p>
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>
223  *
224  * <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>
228  *
229  * <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>
233  *
234  * @param menu the new pop up menu
235  *
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>
239  * </ul>
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>
243  * </ul>
244  */
245 public void setMenu (Menu menu) {
246         checkWidget ();
247         if (menu != null) {
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);
251                 }
252         }
253         if (shell != null) return;
254         this.menu = menu;
255         parent.setMenu (menu);
256 }
257
258 /**
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.
263  *
264  * <p>
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>
269  *
270  * <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>
274  *
275  * @param overlayImage the new overlay image (may be null)
276  *
277  * @exception IllegalArgumentException <ul>
278  *    <li>ERROR_INVALID_ARGUMENT - if the overlayImage has been disposed</li>
279  * </ul>
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>
283  * </ul>
284  */
285 public void setOverlayImage (Image overlayImage) {
286         checkWidget ();
287         if (overlayImage != null && overlayImage.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
288         if (shell == null) return;
289         this.overlayImage = overlayImage;
290         if (overlayImage != null) {
291                 updateImage ();
292         } else {
293                 if (overlayText.length () != 0) {
294                         updateText ();
295                 } else {
296                         parent.mTaskbarList3.SetOverlayIcon(shell.handle, 0, 0);
297                 }
298         }
299 }
300
301 /**
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.
305  *
306  * <p>
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>
311  *
312  * <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>
316  *
317  * @param overlayText the new overlay text
318  *
319  * @exception IllegalArgumentException <ul>
320  *    <li>ERROR_NULL_ARGUMENT - if the overlayText is null</li>
321  * </ul>
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>
325  * </ul>
326  */
327 public void setOverlayText (String overlayText) {
328         checkWidget ();
329         if (overlayText == null) error (SWT.ERROR_NULL_ARGUMENT);
330         if (shell == null) return;
331         this.overlayText = overlayText;
332         if (overlayText.length () != 0) {
333                 updateText ();
334         } else {
335                 if (overlayImage != null) {
336                         updateImage ();
337                 } else {
338                         parent.mTaskbarList3.SetOverlayIcon(shell.handle, 0, 0);
339                 }
340         }
341 }
342
343 /**
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>.
347  *
348  * <p>
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>
353  *
354  * <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>
358  *
359  * @param progress the new progress
360  *
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>
364  * </ul>
365  *
366  * #see {@link #setProgressState(int)}
367  */
368 public void setProgress (int progress) {
369         checkWidget ();
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;
374         updateProgress ();
375 }
376
377 /**
378  * Sets the receiver's progress state, the state can be one of
379  * the following:
380  * <ul>
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>
386  * </ul>
387  *
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.
391  *
392  * <p>
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>
397  *
398  * <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>
402  *
403  * @param progressState the new progress state
404  *
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>
408  * </ul>
409  *
410  * #see {@link #setProgress(int)}
411  */
412 public void setProgressState (int progressState) {
413         checkWidget ();
414         if (shell == null) return;
415         if (this.progressState == progressState) return;
416         this.progressState = progressState;
417         updateProgressState ();
418 }
419
420 void setShell (Shell shell) {
421         this.shell = shell;
422         shell.addListener (SWT.Dispose, new Listener () {
423                 @Override
424                 public void handleEvent (Event event) {
425                         if (isDisposed ()) return;
426                         dispose ();
427                 }
428         });
429 }
430
431 void updateImage () {
432         showingText = false;
433         Image image2 = null;
434         long hIcon = 0;
435         switch (overlayImage.type) {
436                 case SWT.BITMAP:
437                         image2 = Display.createIcon (overlayImage);
438                         hIcon = image2.handle;
439                         break;
440                 case SWT.ICON:
441                         hIcon = overlayImage.handle;
442                         break;
443         }
444         parent.mTaskbarList3.SetOverlayIcon(shell.handle, hIcon, 0);
445         if (image2 != null) image2.dispose ();
446 }
447
448 void updateProgress () {
449         if (progressState == SWT.INDETERMINATE) return;
450         if (progressState == SWT.DEFAULT) return;
451         parent.mTaskbarList3.SetProgressValue(shell.handle, progress, PROGRESS_MAX);
452 }
453
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;
461         }
462         parent.mTaskbarList3.SetProgressValue(shell.handle, progress, PROGRESS_MAX);
463         parent.mTaskbarList3.SetProgressState(shell.handle, tbpFlags);
464 }
465
466 void updateText () {
467         showingText = true;
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);
489
490         /* Draw content */
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);
495
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);
501
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);
521                 }
522         }
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);
528         if (hFont != 0) {
529                 OS.SelectObject (dstHdc, oldHFont);
530                 OS.DeleteObject (hFont);
531         }
532         OS.SetBkMode(dstHdc, oldBkMode);
533
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);
540
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);
549
550         parent.mTaskbarList3.SetOverlayIcon(shell.handle, hIcon, 0);
551         OS.DestroyIcon (hIcon);
552 }
553
554 }