]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TrayItem.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / TrayItem.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 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  *******************************************************************************/
14 package org.eclipse.swt.widgets;
15
16
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.events.*;
19 import org.eclipse.swt.graphics.*;
20 import org.eclipse.swt.internal.win32.*;
21
22 /**
23  * Instances of this class represent icons that can be placed on the
24  * system tray or task bar status area.
25  * <dl>
26  * <dt><b>Styles:</b></dt>
27  * <dd>(none)</dd>
28  * <dt><b>Events:</b></dt>
29  * <dd>DefaultSelection, MenuDetect, Selection</dd>
30  * </dl>
31  * <p>
32  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
33  * </p>
34  *
35  * @see <a href="http://www.eclipse.org/swt/snippets/#tray">Tray, TrayItem snippets</a>
36  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
37  *
38  * @since 3.0
39  * @noextend This class is not intended to be subclassed by clients.
40  */
41 public class TrayItem extends Item {
42         Tray parent;
43         int id;
44         Image image2, highlightImage;
45         ToolTip toolTip;
46         String toolTipText;
47         boolean visible = true;
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 public TrayItem (Tray parent, int style) {
80         super (parent, style);
81         this.parent = parent;
82         parent.createItem (this, parent.getItemCount ());
83         createUpdateWidget (true);
84 }
85
86 /**
87  * Adds the listener to the collection of listeners who will
88  * be notified when the receiver is selected by the user, by sending
89  * it one of the messages defined in the <code>SelectionListener</code>
90  * interface.
91  * <p>
92  * <code>widgetSelected</code> is called when the receiver is selected
93  * <code>widgetDefaultSelected</code> is called when the receiver is double-clicked
94  * </p>
95  *
96  * @param listener the listener which should be notified when the receiver is selected by the user
97  *
98  * @exception IllegalArgumentException <ul>
99  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
100  * </ul>
101  * @exception SWTException <ul>
102  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
103  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
104  * </ul>
105  *
106  * @see SelectionListener
107  * @see #removeSelectionListener
108  * @see SelectionEvent
109  */
110 public void addSelectionListener(SelectionListener listener) {
111         checkWidget ();
112         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
113         TypedListener typedListener = new TypedListener (listener);
114         addListener (SWT.Selection,typedListener);
115         addListener (SWT.DefaultSelection,typedListener);
116 }
117
118 /**
119  * Adds the listener to the collection of listeners who will
120  * be notified when the platform-specific context menu trigger
121  * has occurred, by sending it one of the messages defined in
122  * the <code>MenuDetectListener</code> interface.
123  *
124  * @param listener the listener which should be notified
125  *
126  * @exception IllegalArgumentException <ul>
127  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
128  * </ul>
129  * @exception SWTException <ul>
130  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
131  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
132  * </ul>
133  *
134  * @see MenuDetectListener
135  * @see #removeMenuDetectListener
136  *
137  * @since 3.3
138  */
139 public void addMenuDetectListener (MenuDetectListener listener) {
140         checkWidget ();
141         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
142         TypedListener typedListener = new TypedListener (listener);
143         addListener (SWT.MenuDetect, typedListener);
144 }
145
146 @Override
147 protected void checkSubclass () {
148         if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
149 }
150
151 void createUpdateWidget (boolean newIcon) {
152         NOTIFYICONDATA iconData = new NOTIFYICONDATA ();
153         iconData.cbSize = NOTIFYICONDATA.sizeof;
154         /*
155          * As per MSDN article iconData.uID is unique for every TrayItem
156          * instance(https://msdn.microsoft.com/en-us/library/windows/desktop/
157          * bb762159%28v=vs.85%29.aspx) and this uID value should be specified
158          * during TrayItem instance creation & should be cached and used in
159          * subsequent calls to Shell_NotifyIcon to perform later actions on the
160          * TrayItem instance refer Win10 bug 488739.
161          */
162         iconData.uID = id = (newIcon ? display.nextTrayId++ : id);
163         iconData.hWnd = display.hwndMessage;
164         iconData.uFlags = OS.NIF_MESSAGE;
165         iconData.uCallbackMessage = Display.SWT_TRAYICONMSG;
166         /*
167          * OS.NIM_ADD message should be called only once in a TrayItem instance
168          * life-cycle i.e. in the TrayItem instance creation step only, else
169          * will lead to multiple TrayIcons entries on Win10 refer bug 488739.
170          */
171         OS.Shell_NotifyIcon ((newIcon ? OS.NIM_ADD : OS.NIM_MODIFY), iconData);
172 }
173
174 @Override
175 void destroyWidget () {
176         parent.destroyItem (this);
177         releaseHandle ();
178 }
179
180 /**
181  * Returns the receiver's highlight image if it has one, or null
182  * if it does not.
183  *
184  * @return the receiver's highlight image
185  *
186  * @exception SWTException <ul>
187  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
188  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
189  * </ul>
190  *
191  * @since 3.8
192  */
193 public Image getHighlightImage () {
194         checkWidget ();
195         return highlightImage;
196 }
197
198 /**
199  * Returns the receiver's parent, which must be a <code>Tray</code>.
200  *
201  * @return the receiver's parent
202  *
203  * @exception SWTException <ul>
204  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
205  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
206  * </ul>
207  *
208  * @since 3.2
209  */
210 public Tray getParent () {
211         checkWidget ();
212         return parent;
213 }
214
215 /**
216  * Returns the receiver's tool tip, or null if it has
217  * not been set.
218  *
219  * @return the receiver's tool tip text
220  *
221  * @exception SWTException <ul>
222  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
223  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
224  * </ul>
225  *
226  * @since 3.2
227  */
228 public ToolTip getToolTip () {
229         checkWidget ();
230         return toolTip;
231 }
232
233 /**
234  * Returns the receiver's tool tip text, or null if it has
235  * not been set.
236  *
237  * @return the receiver's tool tip text
238  *
239  * @exception SWTException <ul>
240  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
241  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
242  * </ul>
243  */
244 public String getToolTipText () {
245         checkWidget ();
246         return toolTipText;
247 }
248
249 /**
250  * Returns <code>true</code> if the receiver is visible and
251  * <code>false</code> otherwise.
252  *
253  * @return the receiver's visibility
254  *
255  * @exception SWTException <ul>
256  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
257  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
258  * </ul>
259  */
260 public boolean getVisible () {
261         checkWidget ();
262         return visible;
263 }
264
265 long messageProc (long hwnd, int msg, long wParam, long lParam) {
266         /*
267         * Feature in Windows.  When the user clicks on the tray
268         * icon, another application may be the foreground window.
269         * This means that the event loop is not running and can
270         * cause problems.  For example, if a menu is shown, when
271         * the user clicks outside of the menu to cancel it, the
272         * menu is not hidden until an event is processed.  If
273         * another application is the foreground window, then the
274         * menu is not hidden.  The fix is to force the tray icon
275         * message window to the foreground when sending an event.
276         */
277         switch ((int)lParam) {
278                 case OS.WM_LBUTTONDOWN:
279                         if (hooks (SWT.Selection)) {
280                                 OS.SetForegroundWindow (hwnd);
281                                 sendSelectionEvent (SWT.Selection);
282                         }
283                         break;
284                 case OS.WM_LBUTTONDBLCLK:
285                 case OS.WM_RBUTTONDBLCLK:
286                         if (hooks (SWT.DefaultSelection)) {
287                                 OS.SetForegroundWindow (hwnd);
288                                 sendSelectionEvent (SWT.DefaultSelection);
289                         }
290                         break;
291                 case OS.WM_RBUTTONUP: {
292                         if (hooks (SWT.MenuDetect)) {
293                                 OS.SetForegroundWindow (hwnd);
294                                 sendEvent (SWT.MenuDetect);
295                                 // widget could be disposed at this point
296                                 if (isDisposed()) return 0;
297                         }
298                         break;
299                 }
300                 case OS.NIN_BALLOONSHOW:
301                         if (toolTip != null && !toolTip.visible) {
302                                 toolTip.visible = true;
303                                 if (toolTip.hooks (SWT.Show)) {
304                                         OS.SetForegroundWindow (hwnd);
305                                         toolTip.sendEvent (SWT.Show);
306                                         // widget could be disposed at this point
307                                         if (isDisposed()) return 0;
308                                 }
309                         }
310                         break;
311                 case OS.NIN_BALLOONHIDE:
312                 case OS.NIN_BALLOONTIMEOUT:
313                 case OS.NIN_BALLOONUSERCLICK:
314                         if (toolTip != null) {
315                                 if (toolTip.visible) {
316                                         toolTip.visible = false;
317                                         if (toolTip.hooks (SWT.Hide)) {
318                                                 OS.SetForegroundWindow (hwnd);
319                                                 toolTip.sendEvent (SWT.Hide);
320                                                 // widget could be disposed at this point
321                                                 if (isDisposed()) return 0;
322                                         }
323                                 }
324                                 if (lParam == OS.NIN_BALLOONUSERCLICK) {
325                                         if (toolTip.hooks (SWT.Selection)) {
326                                                 OS.SetForegroundWindow (hwnd);
327                                                 toolTip.sendSelectionEvent (SWT.Selection);
328                                                 // widget could be disposed at this point
329                                                 if (isDisposed()) return 0;
330                                         }
331                                 }
332                         }
333                         break;
334         }
335         display.wakeThread ();
336         return 0;
337 }
338
339 void recreate () {
340         createUpdateWidget (false);
341         if (!visible) setVisible (false);
342         if (text.length () != 0) setText (text);
343         if (image != null) setImage (image);
344         if (toolTipText != null) setToolTipText (toolTipText);
345 }
346
347 @Override
348 void releaseHandle () {
349         super.releaseHandle ();
350         parent = null;
351 }
352
353 @Override
354 void releaseWidget () {
355         super.releaseWidget ();
356         if (toolTip != null) toolTip.item = null;
357         toolTip = null;
358         if (image2 != null) image2.dispose ();
359         image2 = null;
360         highlightImage = null;
361         toolTipText = null;
362         NOTIFYICONDATA iconData = new NOTIFYICONDATA ();
363         iconData.cbSize = NOTIFYICONDATA.sizeof;
364         iconData.uID = id;
365         iconData.hWnd = display.hwndMessage;
366         OS.Shell_NotifyIcon (OS.NIM_DELETE, iconData);
367 }
368
369 /**
370  * Removes the listener from the collection of listeners who will
371  * be notified when the receiver is selected by the user.
372  *
373  * @param listener the listener which should no longer be notified
374  *
375  * @exception IllegalArgumentException <ul>
376  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
377  * </ul>
378  * @exception SWTException <ul>
379  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
380  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
381  * </ul>
382  *
383  * @see SelectionListener
384  * @see #addSelectionListener
385  */
386 public void removeSelectionListener(SelectionListener listener) {
387         checkWidget ();
388         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
389         if (eventTable == null) return;
390         eventTable.unhook (SWT.Selection, listener);
391         eventTable.unhook (SWT.DefaultSelection,listener);
392 }
393
394 /**
395  * Removes the listener from the collection of listeners who will
396  * be notified when the platform-specific context menu trigger has
397  * occurred.
398  *
399  * @param listener the listener which should no longer be notified
400  *
401  * @exception IllegalArgumentException <ul>
402  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
403  * </ul>
404  * @exception SWTException <ul>
405  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
406  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
407  * </ul>
408  *
409  * @see MenuDetectListener
410  * @see #addMenuDetectListener
411  *
412  * @since 3.3
413  */
414 public void removeMenuDetectListener (MenuDetectListener listener) {
415         checkWidget ();
416         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
417         if (eventTable == null) return;
418         eventTable.unhook (SWT.MenuDetect, listener);
419 }
420
421 /**
422  * Sets the receiver's highlight image.
423  *
424  * @param image the new highlight image
425  *
426  * @exception IllegalArgumentException <ul>
427  *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
428  * </ul>
429  * @exception SWTException <ul>
430  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
431  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
432  * </ul>
433  *
434  * @since 3.8
435  */
436 public void setHighlightImage (Image image) {
437         checkWidget ();
438         if (image != null && image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
439         highlightImage = image;
440 }
441
442 /**
443  * Sets the receiver's image.
444  *
445  * @param image the new image
446  *
447  * @exception IllegalArgumentException <ul>
448  *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
449  * </ul>
450  * @exception SWTException <ul>
451  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
452  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
453  * </ul>
454  */
455 @Override
456 public void setImage (Image image) {
457         checkWidget ();
458         if (image != null && image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
459         super.setImage (image);
460         if (image2 != null) image2.dispose ();
461         image2 = null;
462         long hIcon = 0;
463         Image icon = image;
464         if (icon != null) {
465                 switch (icon.type) {
466                         case SWT.BITMAP:
467                                 image2 = Display.createIcon (image);
468                                 hIcon = image2.handle;
469                                 break;
470                         case SWT.ICON:
471                                 hIcon = icon.handle;
472                                 break;
473                 }
474         }
475         NOTIFYICONDATA iconData = new NOTIFYICONDATA ();
476         iconData.cbSize = NOTIFYICONDATA.sizeof;
477         iconData.uID = id;
478         iconData.hWnd = display.hwndMessage;
479         iconData.hIcon = hIcon;
480         iconData.uFlags = OS.NIF_ICON;
481         OS.Shell_NotifyIcon (OS.NIM_MODIFY, iconData);
482 }
483
484 /**
485  * Sets the receiver's tool tip to the argument, which
486  * may be null indicating that no tool tip should be shown.
487  *
488  * @param toolTip the new tool tip (or null)
489  *
490  * @exception SWTException <ul>
491  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
492  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
493  * </ul>
494  *
495  * @since 3.2
496  */
497 public void setToolTip (ToolTip toolTip) {
498         checkWidget ();
499         ToolTip oldTip = this.toolTip, newTip = toolTip;
500         if (oldTip != null) oldTip.item = null;
501         this.toolTip = newTip;
502         if (newTip != null) newTip.item = this;
503 }
504
505 /**
506  * Sets the receiver's tool tip text to the argument, which
507  * may be null indicating that the default tool tip for the
508  * control will be shown. For a control that has a default
509  * tool tip, such as the Tree control on Windows, setting
510  * the tool tip text to an empty string replaces the default,
511  * causing no tool tip text to be shown.
512  * <p>
513  * The mnemonic indicator (character '&amp;') is not displayed in a tool tip.
514  * To display a single '&amp;' in the tool tip, the character '&amp;' can be
515  * escaped by doubling it in the string.
516  * </p>
517  * <p>
518  * NOTE: This operation is a hint and behavior is platform specific, on Windows
519  * for CJK-style mnemonics of the form " (&amp;C)" at the end of the tooltip text
520  * are not shown in tooltip.
521  * </p>
522  *
523  * @param string the new tool tip text (or null)
524  *
525  * @exception SWTException <ul>
526  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
527  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
528  * </ul>
529  */
530 public void setToolTipText (String string) {
531         checkWidget ();
532         toolTipText = string;
533         NOTIFYICONDATA iconData = new NOTIFYICONDATA ();
534         if (string != null) {
535                 char [] szTip = iconData.szTip;
536                 int length = Math.min (szTip.length - 1, string.length ());
537                 string.getChars (0, length, szTip, 0);
538         }
539         iconData.cbSize = NOTIFYICONDATA.sizeof;
540         iconData.uID = id;
541         iconData.hWnd = display.hwndMessage;
542         iconData.uFlags = OS.NIF_TIP;
543         OS.Shell_NotifyIcon (OS.NIM_MODIFY, iconData);
544 }
545
546 /**
547  * Makes the receiver visible if the argument is <code>true</code>,
548  * and makes it invisible otherwise.
549  *
550  * @param visible the new visibility state
551  *
552  * @exception SWTException <ul>
553  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
554  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
555  * </ul>
556  */
557 public void setVisible (boolean visible) {
558         checkWidget ();
559         if (this.visible == visible) return;
560         if (visible) {
561                 /*
562                 * It is possible (but unlikely), that application
563                 * code could have disposed the widget in the show
564                 * event.  If this happens, just return.
565                 */
566                 sendEvent (SWT.Show);
567                 if (isDisposed ()) return;
568         }
569         this.visible = visible;
570         NOTIFYICONDATA iconData = new NOTIFYICONDATA ();
571         iconData.cbSize = NOTIFYICONDATA.sizeof;
572         iconData.uID = id;
573         iconData.hWnd = display.hwndMessage;
574         iconData.uFlags = OS.NIF_STATE;
575         iconData.dwState = visible ? 0 : OS.NIS_HIDDEN;
576         iconData.dwStateMask = OS.NIS_HIDDEN;
577         OS.Shell_NotifyIcon (OS.NIM_MODIFY, iconData);
578         if (!visible) sendEvent (SWT.Hide);
579 }
580
581 }