]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Scale.java
65d41a87af3eb5abe29c95bfc38f6a1c8b9e1b10
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / Scale.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2012 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 the receiver represent a selectable user
24  * interface object that present a range of continuous
25  * numeric values.
26  * <dl>
27  * <dt><b>Styles:</b></dt>
28  * <dd>HORIZONTAL, VERTICAL</dd>
29  * <dt><b>Events:</b></dt>
30  * <dd>Selection</dd>
31  * </dl>
32  * <p>
33  * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
34  * </p>
35  * <p>
36  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
37  * </p>
38  *
39  * @see <a href="http://www.eclipse.org/swt/snippets/#scale">Scale snippets</a>
40  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
41  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
42  * @noextend This class is not intended to be subclassed by clients.
43  */
44 public class Scale extends Control {
45         boolean ignoreResize, ignoreSelection;
46         static final long TrackBarProc;
47         static final TCHAR TrackBarClass = new TCHAR (0, OS.TRACKBAR_CLASS, true);
48         boolean createdAsRTL;
49         static {
50                 WNDCLASS lpWndClass = new WNDCLASS ();
51                 OS.GetClassInfo (0, TrackBarClass, lpWndClass);
52                 TrackBarProc = lpWndClass.lpfnWndProc;
53                 /*
54                 * Feature in Windows.  The track bar window class
55                 * does not include CS_DBLCLKS.  This means that these
56                 * controls will not get double click messages such as
57                 * WM_LBUTTONDBLCLK.  The fix is to register a new
58                 * window class with CS_DBLCLKS.
59                 *
60                 * NOTE:  Screen readers look for the exact class name
61                 * of the control in order to provide the correct kind
62                 * of assistance.  Therefore, it is critical that the
63                 * new window class have the same name.  It is possible
64                 * to register a local window class with the same name
65                 * as a global class.  Since bits that affect the class
66                 * are being changed, it is possible that other native
67                 * code, other than SWT, could create a control with
68                 * this class name, and fail unexpectedly.
69                 */
70                 lpWndClass.hInstance = OS.GetModuleHandle (null);
71                 lpWndClass.style &= ~OS.CS_GLOBALCLASS;
72                 lpWndClass.style |= OS.CS_DBLCLKS;
73                 OS.RegisterClass (TrackBarClass, lpWndClass);
74         }
75
76 /**
77  * Constructs a new instance of this class given its parent
78  * and a style value describing its behavior and appearance.
79  * <p>
80  * The style value is either one of the style constants defined in
81  * class <code>SWT</code> which is applicable to instances of this
82  * class, or must be built by <em>bitwise OR</em>'ing together
83  * (that is, using the <code>int</code> "|" operator) two or more
84  * of those <code>SWT</code> style constants. The class description
85  * lists the style constants that are applicable to the class.
86  * Style bits are also inherited from superclasses.
87  * </p>
88  *
89  * @param parent a composite control which will be the parent of the new instance (cannot be null)
90  * @param style the style of control to construct
91  *
92  * @exception IllegalArgumentException <ul>
93  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
94  * </ul>
95  * @exception SWTException <ul>
96  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
97  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
98  * </ul>
99  *
100  * @see SWT#HORIZONTAL
101  * @see SWT#VERTICAL
102  * @see Widget#checkSubclass
103  * @see Widget#getStyle
104  */
105 public Scale (Composite parent, int style) {
106         super (parent, checkStyle (style));
107 }
108
109 /**
110  * Adds the listener to the collection of listeners who will
111  * be notified when the user changes the receiver's value, by sending
112  * it one of the messages defined in the <code>SelectionListener</code>
113  * interface.
114  * <p>
115  * <code>widgetSelected</code> is called when the user changes the receiver's value.
116  * <code>widgetDefaultSelected</code> is not called.
117  * </p>
118  *
119  * @param listener the listener which should be notified
120  *
121  * @exception IllegalArgumentException <ul>
122  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
123  * </ul>
124  * @exception SWTException <ul>
125  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
126  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
127  * </ul>
128  *
129  * @see SelectionListener
130  * @see #removeSelectionListener
131  */
132 public void addSelectionListener(SelectionListener listener) {
133         checkWidget ();
134         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
135         TypedListener typedListener = new TypedListener (listener);
136         addListener (SWT.Selection,typedListener);
137         addListener (SWT.DefaultSelection,typedListener);
138 }
139
140 @Override
141 long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
142         if (handle == 0) return 0;
143         return OS.CallWindowProc (TrackBarProc, hwnd, msg, wParam, lParam);
144 }
145
146 static int checkStyle (int style) {
147         return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
148 }
149
150 @Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
151         checkWidget ();
152         int border = getBorderWidthInPixels ();
153         int width = border * 2, height = border * 2;
154         RECT rect = new RECT ();
155         OS.SendMessage (handle, OS.TBM_GETTHUMBRECT, 0, rect);
156         if ((style & SWT.HORIZONTAL) != 0) {
157                 width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10;
158                 int scrollY = OS.GetSystemMetrics (OS.SM_CYHSCROLL);
159                 height += (rect.top * 2) + scrollY + (scrollY / 3);
160         } else {
161                 int scrollX = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
162                 width += (rect.left * 2) + scrollX + (scrollX / 3);
163                 height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10;
164         }
165         if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
166         if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
167         return new Point (width, height);
168 }
169
170 @Override
171 void createHandle () {
172         super.createHandle ();
173         state |= THEME_BACKGROUND | DRAW_BACKGROUND;
174         OS.SendMessage (handle, OS.TBM_SETRANGEMAX, 0, 100);
175         OS.SendMessage (handle, OS.TBM_SETPAGESIZE, 0, 10);
176         OS.SendMessage (handle, OS.TBM_SETTICFREQ, 10, 0);
177         createdAsRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
178 }
179
180 @Override
181 int defaultForeground () {
182         return OS.GetSysColor (OS.COLOR_BTNFACE);
183 }
184
185 /**
186  * Returns the amount that the receiver's value will be
187  * modified by when the up/down (or right/left) arrows
188  * are pressed.
189  *
190  * @return the increment
191  *
192  * @exception SWTException <ul>
193  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
194  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
195  * </ul>
196  */
197 public int getIncrement () {
198         checkWidget ();
199         return (int)OS.SendMessage (handle, OS.TBM_GETLINESIZE, 0, 0);
200 }
201
202 /**
203  * Returns the maximum value which the receiver will allow.
204  *
205  * @return the maximum
206  *
207  * @exception SWTException <ul>
208  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
209  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
210  * </ul>
211  */
212 public int getMaximum () {
213         checkWidget ();
214         return (int)OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
215 }
216
217 /**
218  * Returns the minimum value which the receiver will allow.
219  *
220  * @return the minimum
221  *
222  * @exception SWTException <ul>
223  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
224  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
225  * </ul>
226  */
227 public int getMinimum () {
228         checkWidget ();
229         return (int)OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
230 }
231
232 /**
233  * Returns the amount that the receiver's value will be
234  * modified by when the page increment/decrement areas
235  * are selected.
236  *
237  * @return the page increment
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 int getPageIncrement () {
245         checkWidget ();
246         return (int)OS.SendMessage (handle, OS.TBM_GETPAGESIZE, 0, 0);
247 }
248
249 /**
250  * Returns the 'selection', which is the receiver's position.
251  *
252  * @return the selection
253  *
254  * @exception SWTException <ul>
255  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
256  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
257  * </ul>
258  */
259 public int getSelection () {
260         checkWidget ();
261         return (int)OS.SendMessage (handle, OS.TBM_GETPOS, 0, 0);
262 }
263
264 /**
265  * Removes the listener from the collection of listeners who will
266  * be notified when the user changes the receiver's value.
267  *
268  * @param listener the listener which should no longer be notified
269  *
270  * @exception IllegalArgumentException <ul>
271  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
272  * </ul>
273  * @exception SWTException <ul>
274  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
275  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
276  * </ul>
277  *
278  * @see SelectionListener
279  * @see #addSelectionListener
280  */
281 public void removeSelectionListener(SelectionListener listener) {
282         checkWidget ();
283         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
284         if (eventTable == null) return;
285         eventTable.unhook (SWT.Selection, listener);
286         eventTable.unhook (SWT.DefaultSelection,listener);
287 }
288
289 @Override
290 void setBackgroundImage (long hImage) {
291         super.setBackgroundImage (hImage);
292         /*
293         * Bug in Windows.  Changing the background color of the Scale
294         * widget and calling InvalidateRect() still draws with the old
295         * color.  The fix is to send a fake WM_SIZE event to cause
296         * it to redraw with the new background color.
297         */
298         ignoreResize = true;
299         OS.SendMessage (handle, OS.WM_SIZE, 0, 0);
300         ignoreResize = false;
301 }
302
303 @Override
304 void setBackgroundPixel (int pixel) {
305         super.setBackgroundPixel (pixel);
306         /*
307         * Bug in Windows.  Changing the background color of the Scale
308         * widget and calling InvalidateRect() still draws with the old
309         * color.  The fix is to send a fake WM_SIZE event to cause
310         * it to redraw with the new background color.
311         */
312         ignoreResize = true;
313         OS.SendMessage (handle, OS.WM_SIZE, 0, 0);
314         ignoreResize = false;
315 }
316
317 @Override
318 void setBoundsInPixels (int x, int y, int width, int height, int flags, boolean defer) {
319         /*
320         * Bug in Windows.  If SetWindowPos() is called on a
321         * track bar with either SWP_DRAWFRAME, a new size,
322         * or both during mouse down, the track bar posts a
323         * WM_MOUSEMOVE message when the mouse has not moved.
324         * The window proc for the track bar uses WM_MOUSEMOVE
325         * to issue WM_HSCROLL or WM_SCROLL events to notify
326         * the application that the slider has changed.  The
327         * end result is that when the user requests a page
328         * scroll and the application resizes the track bar
329         * during the change notification, continuous stream
330         * of WM_MOUSEMOVE messages are generated and the
331         * thumb moves to the mouse position rather than
332         * scrolling by a page.  The fix is to clear the
333         * SWP_DRAWFRAME flag.
334         *
335         * NOTE:  There is no fix for the WM_MOUSEMOVE that
336         * is generated by a new size.  Clearing SWP_DRAWFRAME
337         * does not fix the problem.  However, it is unlikely
338         * that the programmer will resize the control during
339         * mouse down.
340         */
341         flags &= ~OS.SWP_DRAWFRAME;
342         super.setBoundsInPixels (x, y, width, height, flags, true);
343 }
344
345 /**
346  * Sets the amount that the receiver's value will be
347  * modified by when the up/down (or right/left) arrows
348  * are pressed to the argument, which must be at least
349  * one.
350  *
351  * @param increment the new increment (must be greater than zero)
352  *
353  * @exception SWTException <ul>
354  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
355  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
356  * </ul>
357  */
358 public void setIncrement (int increment) {
359         checkWidget ();
360         if (increment < 1) return;
361         int minimum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
362         int maximum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
363         if (increment > maximum - minimum) return;
364         OS.SendMessage (handle, OS.TBM_SETLINESIZE, 0, increment);
365 }
366
367 /**
368  * Sets the maximum value that the receiver will allow.  This new
369  * value will be ignored if it is not greater than the receiver's current
370  * minimum value.  If the new maximum is applied then the receiver's
371  * selection value will be adjusted if necessary to fall within its new range.
372  *
373  * @param value the new maximum, which must be greater than the current minimum
374  *
375  * @exception SWTException <ul>
376  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
377  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
378  * </ul>
379  */
380 public void setMaximum (int value) {
381         checkWidget ();
382         int minimum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
383         if (0 <= minimum && minimum < value) {
384                 OS.SendMessage (handle, OS.TBM_SETRANGEMAX, 1, value);
385         }
386 }
387
388 /**
389  * Sets the minimum value that the receiver will allow.  This new
390  * value will be ignored if it is negative or is not less than the receiver's
391  * current maximum value.  If the new minimum is applied then the receiver's
392  * selection value will be adjusted if necessary to fall within its new range.
393  *
394  * @param value the new minimum, which must be nonnegative and less than the current maximum
395  *
396  * @exception SWTException <ul>
397  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
398  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
399  * </ul>
400  */
401 public void setMinimum (int value) {
402         checkWidget ();
403         int maximum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
404         if (0 <= value && value < maximum) {
405                 OS.SendMessage (handle, OS.TBM_SETRANGEMIN, 1, value);
406         }
407 }
408
409 /**
410  * Sets the amount that the receiver's value will be
411  * modified by when the page increment/decrement areas
412  * are selected to the argument, which must be at least
413  * one.
414  *
415  * @param pageIncrement the page increment (must be greater than zero)
416  *
417  * @exception SWTException <ul>
418  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
419  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
420  * </ul>
421  */
422 public void setPageIncrement (int pageIncrement) {
423         checkWidget ();
424         if (pageIncrement < 1) return;
425         int minimum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
426         int maximum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
427         if (pageIncrement > maximum - minimum) return;
428         OS.SendMessage (handle, OS.TBM_SETPAGESIZE, 0, pageIncrement);
429         OS.SendMessage (handle, OS.TBM_SETTICFREQ, pageIncrement, 0);
430 }
431
432 /**
433  * Sets the 'selection', which is the receiver's value,
434  * to the argument which must be greater than or equal to zero.
435  *
436  * @param value the new selection (must be zero or greater)
437  *
438  * @exception SWTException <ul>
439  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
440  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
441  * </ul>
442  */
443 public void setSelection (int value) {
444         checkWidget ();
445         OS.SendMessage (handle, OS.TBM_SETPOS, 1, value);
446 }
447
448 @Override
449 int widgetStyle () {
450         int bits = super.widgetStyle () | OS.WS_TABSTOP | OS.TBS_BOTH | OS.TBS_AUTOTICKS;
451         if ((style & SWT.HORIZONTAL) != 0) return bits | OS.TBS_HORZ | OS.TBS_DOWNISLEFT;
452         return bits | OS.TBS_VERT;
453 }
454
455 @Override
456 TCHAR windowClass () {
457         return TrackBarClass;
458 }
459
460 @Override
461 long windowProc () {
462         return TrackBarProc;
463 }
464
465 @Override
466 LRESULT WM_KEYDOWN (long wParam, long lParam) {
467         LRESULT result = super.WM_KEYDOWN (wParam, lParam);
468         if (result != null) return result;
469         switch ((int)wParam) {
470                 case OS.VK_LEFT:
471                 case OS.VK_RIGHT:
472                         /*
473                         * Bug in Windows. The behavior for the left and right keys is not
474                         * changed if the orientation changes after the control was created.
475                         * The fix is to replace VK_LEFT by VK_RIGHT and VK_RIGHT by VK_LEFT
476                         * when the current orientation differs from the orientation used to
477                         * create the control.
478                         */
479                         boolean isRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
480                         if (isRTL != createdAsRTL) {
481                                 long code = callWindowProc (handle, OS.WM_KEYDOWN, wParam == OS.VK_RIGHT ? OS.VK_LEFT : OS.VK_RIGHT, lParam);
482                                 return new LRESULT (code);
483                         }
484                         break;
485         }
486         return result;
487 }
488
489 @Override
490 LRESULT WM_MOUSEWHEEL (long wParam, long lParam) {
491         LRESULT result = super.WM_MOUSEWHEEL (wParam, lParam);
492         if (result != null) return result;
493         /*
494         * Bug in Windows.  When a track bar slider is changed
495         * from WM_MOUSEWHEEL, it does not always send either
496         * a WM_VSCROLL or M_HSCROLL to notify the application
497         * of the change.  The fix is to detect that the selection
498         * has changed and that notification has not been issued
499         * and send the selection event.
500         */
501         int oldPosition = (int)OS.SendMessage (handle, OS.TBM_GETPOS, 0, 0);
502         ignoreSelection = true;
503         long code = callWindowProc (handle, OS.WM_MOUSEWHEEL, wParam, lParam);
504         ignoreSelection = false;
505         int newPosition = (int)OS.SendMessage (handle, OS.TBM_GETPOS, 0, 0);
506         if (oldPosition != newPosition) {
507                 /*
508                 * Send the event because WM_HSCROLL and WM_VSCROLL
509                 * are sent from a modal message loop in windows that
510                 * is active when the user is scrolling.
511                 */
512                 sendSelectionEvent (SWT.Selection, null, true);
513                 // widget could be disposed at this point
514         }
515         return new LRESULT (code);
516 }
517
518 @Override
519 LRESULT WM_PAINT (long wParam, long lParam) {
520         if ((state & DISPOSE_SENT) != 0) return LRESULT.ZERO;
521
522         /*
523         * Bug in Windows.  For some reason, when WM_CTLCOLORSTATIC
524         * is used to implement transparency and returns a NULL brush,
525         * Windows doesn't always draw the track bar.  It seems that
526         * it is drawn correctly the first time.  It is possible that
527         * Windows double buffers the control and the double buffer
528         * strategy fails when WM_CTLCOLORSTATIC returns unexpected
529         * results.  The fix is to send a fake WM_SIZE to force it
530         * to redraw every time there is a WM_PAINT.
531         */
532         boolean fixPaint = findBackgroundControl () != null;
533         if (!fixPaint) {
534                 if (OS.IsAppThemed ()) {
535                         Control control = findThemeControl ();
536                         fixPaint = control != null;
537                 }
538         }
539         if (fixPaint) {
540                 boolean redraw = getDrawing () && OS.IsWindowVisible (handle);
541                 if (redraw) OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
542                 ignoreResize = true;
543                 OS.SendMessage (handle, OS.WM_SIZE, 0, 0);
544                 ignoreResize = false;
545                 if (redraw) {
546                         OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
547                         OS.InvalidateRect (handle, null, false);
548                 }
549         }
550         return super.WM_PAINT (wParam, lParam);
551 }
552
553 @Override
554 LRESULT WM_SIZE (long wParam, long lParam) {
555         if (ignoreResize) return null;
556         return super.WM_SIZE (wParam, lParam);
557 }
558
559 @Override
560 LRESULT wmScrollChild (long wParam, long lParam) {
561
562         /* Do nothing when scrolling is ending */
563         int code = OS.LOWORD (wParam);
564         switch (code) {
565                 case OS.TB_ENDTRACK:
566                 case OS.TB_THUMBPOSITION:
567                         return null;
568         }
569
570         if (!ignoreSelection) {
571                 Event event = new Event ();
572                 /*
573                 * This code is intentionally commented.  The event
574                 * detail field is not currently supported on all
575                 * platforms.
576                 */
577 //              switch (code) {
578 //                      case OS.TB_TOP:                 event.detail = SWT.HOME;  break;
579 //                      case OS.TB_BOTTOM:              event.detail = SWT.END;  break;
580 //                      case OS.TB_LINEDOWN:    event.detail = SWT.ARROW_DOWN;  break;
581 //                      case OS.TB_LINEUP:              event.detail = SWT.ARROW_UP;  break;
582 //                      case OS.TB_PAGEDOWN:    event.detail = SWT.PAGE_DOWN;  break;
583 //                      case OS.TB_PAGEUP:              event.detail = SWT.PAGE_UP;  break;
584 //              }
585                 /*
586                 * Send the event because WM_HSCROLL and WM_VSCROLL
587                 * are sent from a modal message loop in windows that
588                 * is active when the user is scrolling.
589                 */
590                 sendSelectionEvent (SWT.Selection, event, true);
591                 // widget could be disposed at this point
592         }
593         return null;
594 }
595
596 }