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  *******************************************************************************/
14 package org.eclipse.swt.widgets;
15 
16 
17 import java.util.*;
18 
19 import org.eclipse.swt.*;
20 import org.eclipse.swt.events.*;
21 import org.eclipse.swt.graphics.*;
22 import org.eclipse.swt.internal.*;
23 import org.eclipse.swt.internal.win32.*;
24 
25 /**
26  * Instances of this class are selectable user interface
27  * objects that allow the user to enter and modify text.
28  * Text controls can be either single or multi-line.
29  * When a text control is created with a border, the
30  * operating system includes a platform specific inset
31  * around the contents of the control.  When created
32  * without a border, an effort is made to remove the
33  * inset such that the preferred size of the control
34  * is the same size as the contents.
35  * <dl>
36  * <dt><b>Styles:</b></dt>
37  * <dd>CENTER, ICON_CANCEL, ICON_SEARCH, LEFT, MULTI, PASSWORD, SEARCH, SINGLE, RIGHT, READ_ONLY, WRAP</dd>
38  * <dt><b>Events:</b></dt>
39  * <dd>DefaultSelection, Modify, Verify, OrientationChange</dd>
40  * </dl>
41  * <p>
42  * Note: Only one of the styles MULTI and SINGLE may be specified,
43  * and only one of the styles LEFT, CENTER, and RIGHT may be specified.
44  * </p>
45  * <p>
46  * Note: The styles ICON_CANCEL and ICON_SEARCH are hints used in combination with SEARCH.
47  * When the platform supports the hint, the text control shows these icons.  When an icon
48  * is selected, a default selection event is sent with the detail field set to one of
49  * ICON_CANCEL or ICON_SEARCH.  Normally, application code does not need to check the
50  * detail.  In the case of ICON_CANCEL, the text is cleared before the default selection
51  * event is sent causing the application to search for an empty string.
52  * </p>
53  * <p>
54  * Note: Some text actions such as Undo are not natively supported on all platforms.
55  * </p>
56  * <p>
57  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
58  * </p>
59  *
60  * @see <a href="http://www.eclipse.org/swt/snippets/#text">Text snippets</a>
61  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
62  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
63  * @noextend This class is not intended to be subclassed by clients.
64  */
65 public class Text extends Scrollable {
66 	int tabs, oldStart, oldEnd;
67 	boolean doubleClick, ignoreModify, ignoreVerify, ignoreCharacter, allowPasswordChar;
68 	String message;
69 	int[] segments;
70 	int clearSegmentsCount = 0;
71 	long hwndActiveIcon;
72 
73 	static final char LTR_MARK = '\u200e';
74 	static final char RTL_MARK = '\u200f';
75 
76 	/* Custom icons defined in swt.rc */
77 	static final int IDI_SEARCH = 101;
78 	static final int IDI_CANCEL = 102;
79 
80 	/**
81 	* The maximum number of characters that can be entered
82 	* into a text widget.
83 	* <p>
84 	* Note that this value is platform dependent, based upon
85 	* the native widget implementation.
86 	* </p>
87 	*/
88 	public static final int LIMIT;
89 
90 	/**
91 	* The delimiter used by multi-line text widgets.  When text
92 	* is queried and from the widget, it will be delimited using
93 	* this delimiter.
94 	*/
95 	public static final String DELIMITER;
96 
97 	/*
98 	* These values can be different on different platforms.
99 	* Therefore they are not initialized in the declaration
100 	* to stop the compiler from inlining.
101 	*/
102 	static {
103 		LIMIT = 0x7FFFFFFF;
104 		DELIMITER = "\r\n";
105 	}
106 
107 	static final long EditProc;
108 	static final TCHAR EditClass = new TCHAR (0, "EDIT", true);
109 	static {
110 		WNDCLASS lpWndClass = new WNDCLASS ();
111 		OS.GetClassInfo (0, EditClass, lpWndClass);
112 		EditProc = lpWndClass.lpfnWndProc;
113 	}
114 
115 /**
116  * Constructs a new instance of this class given its parent
117  * and a style value describing its behavior and appearance.
118  * <p>
119  * The style value is either one of the style constants defined in
120  * class <code>SWT</code> which is applicable to instances of this
121  * class, or must be built by <em>bitwise OR</em>'ing together
122  * (that is, using the <code>int</code> "|" operator) two or more
123  * of those <code>SWT</code> style constants. The class description
124  * lists the style constants that are applicable to the class.
125  * Style bits are also inherited from superclasses.
126  * </p>
127  *
128  * @param parent a composite control which will be the parent of the new instance (cannot be null)
129  * @param style the style of control to construct
130  *
131  * @exception IllegalArgumentException <ul>
132  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
133  * </ul>
134  * @exception SWTException <ul>
135  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
136  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
137  * </ul>
138  *
139  * @see SWT#SINGLE
140  * @see SWT#MULTI
141  * @see SWT#READ_ONLY
142  * @see SWT#WRAP
143  * @see SWT#LEFT
144  * @see SWT#RIGHT
145  * @see SWT#CENTER
146  * @see SWT#PASSWORD
147  * @see SWT#SEARCH
148  * @see SWT#ICON_SEARCH
149  * @see SWT#ICON_CANCEL
150  * @see Widget#checkSubclass
151  * @see Widget#getStyle
152  */
Text(Composite parent, int style)153 public Text (Composite parent, int style) {
154 	super (parent, checkStyle (style));
155 }
156 
157 @Override
callWindowProc(long hwnd, int msg, long wParam, long lParam)158 long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
159 	if (handle == 0) return 0;
160 	boolean redraw = false;
161 	switch (msg) {
162 		case OS.WM_ERASEBKGND: {
163 			if (findImageControl () != null) return 0;
164 			break;
165 		}
166 		case OS.WM_HSCROLL:
167 		case OS.WM_VSCROLL: {
168 			redraw = findImageControl () != null && getDrawing () && OS.IsWindowVisible (handle);
169 			if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
170 			break;
171 		}
172 		case OS.WM_PAINT: {
173 			boolean doubleBuffer = findImageControl () != null;
174 			boolean drawMessage = false;
175 			if ((style & SWT.SINGLE) != 0 && (style & SWT.READ_ONLY) != 0 && message.length () > 0 ) {
176 				drawMessage = hwnd != OS.GetFocus () && OS.GetWindowTextLength (handle) == 0;
177 			}
178 			if (doubleBuffer || drawMessage) {
179 				long paintDC = 0;
180 				PAINTSTRUCT ps = new PAINTSTRUCT ();
181 				paintDC = OS.BeginPaint (handle, ps);
182 				int width = ps.right - ps.left;
183 				int height = ps.bottom - ps.top;
184 				if (width != 0 && height != 0) {
185 					long hDC = paintDC, hBitmap = 0, hOldBitmap = 0;
186 					POINT lpPoint1 = null, lpPoint2 = null;
187 					if (doubleBuffer) {
188 						hDC = OS.CreateCompatibleDC (paintDC);
189 						lpPoint1 = new POINT ();
190 						lpPoint2 = new POINT ();
191 						OS.SetWindowOrgEx (hDC, ps.left, ps.top, lpPoint1);
192 						OS.SetBrushOrgEx (hDC, ps.left, ps.top, lpPoint2);
193 						hBitmap = OS.CreateCompatibleBitmap (paintDC, width, height);
194 						hOldBitmap = OS.SelectObject (hDC, hBitmap);
195 						RECT rect = new RECT ();
196 						OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
197 						drawBackground (hDC, rect);
198 					}
199 
200 					OS.CallWindowProc (EditProc, hwnd, OS.WM_PAINT, hDC, lParam);
201 					/*
202 					* Bug in Windows.  Windows does not draw the cue message when the Edit
203 					* control is read-only. The fix is to draw the cue messages ourselves.
204 					*/
205 					if (drawMessage) {
206 						RECT rect = new RECT();
207 						OS.GetClientRect(handle, rect);
208 						long margins = OS.SendMessage (handle, OS.EM_GETMARGINS, 0, 0);
209 						rect.left += OS.LOWORD (margins);
210 						rect.right -= OS.HIWORD (margins);
211 						if ((style & SWT.BORDER) != 0) {
212 							rect.left++;
213 							rect.top++;
214 							rect.right--;
215 							rect.bottom--;
216 						}
217 						char [] buffer = message.toCharArray ();
218 						int uFormat = OS.DT_EDITCONTROL;
219 						boolean rtl = (style & SWT.RIGHT_TO_LEFT) != 0;
220 						if (rtl) uFormat |= OS.DT_RTLREADING;
221 						int alignment = style & (SWT.LEFT | SWT.CENTER | SWT.RIGHT);
222 						switch (alignment) {
223 							case SWT.LEFT: uFormat |= (rtl ? OS.DT_RIGHT : OS.DT_LEFT); break;
224 							case SWT.CENTER: uFormat |= OS.DT_CENTER;
225 							case SWT.RIGHT: uFormat |= (rtl ? OS.DT_LEFT : OS.DT_RIGHT); break;
226 						}
227 						long hFont = OS.SendMessage (hwnd, OS.WM_GETFONT, 0, 0);
228 						long hOldFont = OS.SelectObject (hDC, hFont);
229 						OS.SetTextColor (hDC, OS.GetSysColor (OS.COLOR_GRAYTEXT));
230 						OS.SetBkMode (hDC, OS.TRANSPARENT);
231 						OS.DrawText (hDC, buffer, buffer.length, rect, uFormat);
232 						OS.SelectObject (hDC, hOldFont);
233 					}
234 
235 					if (doubleBuffer) {
236 						OS.SetWindowOrgEx (hDC, lpPoint1.x, lpPoint1.y, null);
237 						OS.SetBrushOrgEx (hDC, lpPoint2.x, lpPoint2.y, null);
238 						OS.BitBlt (paintDC, ps.left, ps.top, width, height, hDC, 0, 0, OS.SRCCOPY);
239 						OS.SelectObject (hDC, hOldBitmap);
240 						OS.DeleteObject (hBitmap);
241 						OS.DeleteObject (hDC);
242 					}
243 				}
244 				OS.EndPaint (handle, ps);
245 				return 0;
246 			}
247 			break;
248 		}
249 	}
250 	if ((style & SWT.SEARCH) != 0) {
251 		switch (msg) {
252 			case OS.WM_MOUSEMOVE: {
253 				POINT pt = new POINT ();
254 				OS.POINTSTOPOINT(pt, lParam);
255 				long hwndIcon = OS.ChildWindowFromPointEx (handle, pt, OS.CWP_SKIPINVISIBLE);
256 				if (hwndIcon == handle) hwndIcon = 0;
257 				if (hwndIcon != hwndActiveIcon) {
258 					if (hwndActiveIcon != 0) OS.InvalidateRect (hwndActiveIcon, null, false);
259 					if (hwndIcon != 0) OS.InvalidateRect (hwndIcon, null, false);
260 					hwndActiveIcon = hwndIcon;
261 				}
262 				break;
263 			}
264 			case OS.WM_MOUSELEAVE:
265 				if (hwndActiveIcon != 0) {
266 					OS.InvalidateRect (hwndActiveIcon, null, false);
267 					hwndActiveIcon = 0;
268 				}
269 				break;
270 			case OS.WM_LBUTTONDOWN:
271 				if (hwndActiveIcon != 0) {
272 					OS.InvalidateRect (hwndActiveIcon, null, false);
273 					return 0; // prevent mouse selection
274 				}
275 				break;
276 			case OS.WM_LBUTTONUP: {
277 				if (hwndActiveIcon != 0) {
278 					Event e = new Event();
279 					if (hwndActiveIcon == OS.GetDlgItem (handle, SWT.ICON_SEARCH)) {
280 						e.detail = SWT.ICON_SEARCH;
281 					} else {
282 						e.detail = SWT.ICON_CANCEL;
283 						setText ("");
284 					}
285 					setFocus ();
286 					selectAll ();
287 					sendSelectionEvent (SWT.DefaultSelection, e, false);
288 				}
289 				break;
290 			}
291 		}
292 	}
293 	long code = OS.CallWindowProc (EditProc, hwnd, msg, wParam, lParam);
294 	switch (msg) {
295 		case OS.WM_HSCROLL:
296 		case OS.WM_VSCROLL: {
297 			if (redraw) {
298 				OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
299 				OS.InvalidateRect (handle, null, true);
300 			}
301 			break;
302 		}
303 	}
304 	return code;
305 }
306 
307 @Override
createHandle()308 void createHandle () {
309 	long editStyle = widgetStyle ();
310 	if ((editStyle & OS.WS_BORDER) == 0)
311 		super.createHandle ();
312 	else {
313 		/*
314 		 * Feature on Windows: when `Edit` control is created, it removes
315 		 * `WS_BORDER`, but then internally draws the border over the client
316 		 * area. This is undesirable because all SWT coordinates will then
317 		 * need to be adjusted by the border size. The workaround is to create
318 		 * control without `WS_BORDER` and add it just after creating.
319 		 */
320 		style &= ~SWT.BORDER;
321 		super.createHandle ();
322 		style |= SWT.BORDER;
323 
324 		editStyle = OS.GetWindowLongPtr(handle, OS.GWL_STYLE);
325 		editStyle |= OS.WS_BORDER;
326 		OS.SetWindowLongPtr(handle, OS.GWL_STYLE, editStyle);
327 
328 		OS.SetWindowPos(handle, 0, 0, 0, 0, 0, OS.SWP_NOMOVE | OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_FRAMECHANGED);
329 	}
330 
331 	OS.SendMessage (handle, OS.EM_LIMITTEXT, 0, 0);
332 	if ((style & SWT.READ_ONLY) != 0) {
333 		if (applyThemeBackground () == 1) {
334 			state |= THEME_BACKGROUND;
335 		}
336 	}
337 	if ((style & SWT.SEARCH) != 0) {
338 		if (display.hIconSearch == 0) {
339 			long [] phicon = new long [1];
340 			int hresult = OS.LoadIconMetric (OS.GetLibraryHandle (), IDI_SEARCH, OS.LIM_SMALL, phicon);
341 			if (hresult != OS.S_OK) error (SWT.ERROR_NO_HANDLES);
342 			display.hIconSearch = phicon [0];
343 			hresult = OS.LoadIconMetric (OS.GetLibraryHandle (), IDI_CANCEL, OS.LIM_SMALL, phicon);
344 			if (hresult != OS.S_OK) error (SWT.ERROR_NO_HANDLES);
345 			display.hIconCancel = phicon [0];
346 		}
347 		if ((style & SWT.ICON_SEARCH) != 0) {
348 			long hwndSearch = OS.CreateWindowEx (
349 				0,
350 				Label.LabelClass,
351 				null,
352 				OS.WS_CHILD | OS.WS_VISIBLE | OS.WS_CLIPSIBLINGS | OS.SS_OWNERDRAW,
353 				0, 0, 0, 0,
354 				handle,
355 				SWT.ICON_SEARCH,
356 				OS.GetModuleHandle (null),
357 				null);
358 			if (hwndSearch == 0) error (SWT.ERROR_NO_HANDLES);
359 		}
360 		if ((style & SWT.ICON_CANCEL) != 0) {
361 			state |= TRACK_MOUSE;
362 			long hwndCancel = OS.CreateWindowEx (
363 				0,
364 				Label.LabelClass, null,
365 				OS.WS_CHILD | OS.WS_CLIPSIBLINGS | OS.SS_OWNERDRAW,
366 				0, 0, 0, 0,
367 				handle,
368 				SWT.ICON_CANCEL,
369 				OS.GetModuleHandle (null),
370 				null);
371 			if (hwndCancel == 0) error (SWT.ERROR_NO_HANDLES);
372 		}
373 	}
374 }
375 
376 @Override
applyThemeBackground()377 int applyThemeBackground () {
378 	return (backgroundAlpha == 0 || (style & (SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL)) == 0) ? 1 : 0;
379 }
380 
381 /**
382  * Adds the listener to the collection of listeners who will
383  * be notified when the receiver's text is modified, by sending
384  * it one of the messages defined in the <code>ModifyListener</code>
385  * interface.
386  *
387  * @param listener the listener which should be notified
388  *
389  * @exception IllegalArgumentException <ul>
390  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
391  * </ul>
392  * @exception SWTException <ul>
393  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
394  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
395  * </ul>
396  *
397  * @see ModifyListener
398  * @see #removeModifyListener
399  */
addModifyListener(ModifyListener listener)400 public void addModifyListener (ModifyListener listener) {
401 	checkWidget ();
402 	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
403 	TypedListener typedListener = new TypedListener (listener);
404 	addListener (SWT.Modify, typedListener);
405 }
406 
407 /**
408  * Adds a segment listener.
409  * <p>
410  * A <code>SegmentEvent</code> is sent whenever text content is being modified or
411  * a segment listener is added or removed. You can
412  * customize the appearance of text by indicating certain characters to be inserted
413  * at certain text offsets. This may be used for bidi purposes, e.g. when
414  * adjacent segments of right-to-left text should not be reordered relative to
415  * each other.
416  * E.g., multiple Java string literals in a right-to-left language
417  * should generally remain in logical order to each other, that is, the
418  * way they are stored.
419  * </p>
420  * <p>
421  * <b>Warning</b>: This API is currently only implemented on Windows and GTK.
422  * <code>SegmentEvent</code>s won't be sent on Cocoa.
423  * </p>
424  *
425  * @param listener the listener which should be notified
426  *
427  * @exception IllegalArgumentException <ul>
428  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
429  * </ul>
430  * @exception SWTException <ul>
431  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
432  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
433  * </ul>
434  *
435  * @see SegmentEvent
436  * @see SegmentListener
437  * @see #removeSegmentListener
438  *
439  * @since 3.8
440  */
addSegmentListener(SegmentListener listener)441 public void addSegmentListener (SegmentListener listener) {
442 	checkWidget ();
443 	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
444 	addListener (SWT.Segments, new TypedListener (listener));
445 	clearSegments (true);
446 	applySegments ();
447 }
448 
449 /**
450  * Adds the listener to the collection of listeners who will
451  * be notified when the control is selected by the user, by sending
452  * it one of the messages defined in the <code>SelectionListener</code>
453  * interface.
454  * <p>
455  * <code>widgetSelected</code> is not called for texts.
456  * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed in a single-line text,
457  * or when ENTER is pressed in a search text. If the receiver has the <code>SWT.SEARCH | SWT.ICON_CANCEL</code> style
458  * and the user cancels the search, the event object detail field contains the value <code>SWT.ICON_CANCEL</code>.
459  * Likewise, if the receiver has the <code>SWT.ICON_SEARCH</code> style and the icon search is selected, the
460  * event object detail field contains the value <code>SWT.ICON_SEARCH</code>.
461  * </p>
462  *
463  * @param listener the listener which should be notified when the control is selected by the user
464  *
465  * @exception IllegalArgumentException <ul>
466  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
467  * </ul>
468  * @exception SWTException <ul>
469  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
470  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
471  * </ul>
472  *
473  * @see SelectionListener
474  * @see #removeSelectionListener
475  * @see SelectionEvent
476  */
addSelectionListener(SelectionListener listener)477 public void addSelectionListener (SelectionListener listener) {
478 	checkWidget ();
479 	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
480 	TypedListener typedListener = new TypedListener (listener);
481 	addListener (SWT.Selection,typedListener);
482 	addListener (SWT.DefaultSelection,typedListener);
483 }
484 
485 /**
486  * Adds the listener to the collection of listeners who will
487  * be notified when the receiver's text is verified, by sending
488  * it one of the messages defined in the <code>VerifyListener</code>
489  * interface.
490  *
491  * @param listener the listener which should be notified
492  *
493  * @exception IllegalArgumentException <ul>
494  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
495  * </ul>
496  * @exception SWTException <ul>
497  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
498  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
499  * </ul>
500  *
501  * @see VerifyListener
502  * @see #removeVerifyListener
503  */
addVerifyListener(VerifyListener listener)504 public void addVerifyListener (VerifyListener listener) {
505 	checkWidget ();
506 	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
507 	TypedListener typedListener = new TypedListener (listener);
508 	addListener (SWT.Verify, typedListener);
509 }
510 
511 /**
512  * Appends a string.
513  * <p>
514  * The new text is appended to the text at
515  * the end of the widget.
516  * </p>
517  *
518  * @param string the string to be appended
519  *
520  * @exception IllegalArgumentException <ul>
521  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
522  * </ul>
523  * @exception SWTException <ul>
524  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
525  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
526  * </ul>
527  */
append(String string)528 public void append (String string) {
529 	checkWidget ();
530 	if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
531 	string = Display.withCrLf (string);
532 	int length = OS.GetWindowTextLength (handle);
533 	if (hooks (SWT.Verify) || filters (SWT.Verify)) {
534 		string = verifyText (string, length, length, null);
535 		if (string == null) return;
536 	}
537 	OS.SendMessage (handle, OS.EM_SETSEL, length, length);
538 	clearSegments (true);
539 	TCHAR buffer = new TCHAR (getCodePage (), string, true);
540 	/*
541 	* Feature in Windows.  When an edit control with ES_MULTILINE
542 	* style that does not have the WS_VSCROLL style is full (i.e.
543 	* there is no space at the end to draw any more characters),
544 	* EM_REPLACESEL sends a WM_CHAR with a backspace character
545 	* to remove any further text that is added.  This is an
546 	* implementation detail of the edit control that is unexpected
547 	* and can cause endless recursion when EM_REPLACESEL is sent
548 	* from a WM_CHAR handler.  The fix is to ignore calling the
549 	* handler from WM_CHAR.
550 	*/
551 	ignoreCharacter = true;
552 	OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
553 	ignoreCharacter = false;
554 	OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
555 	if ((state & HAS_AUTO_DIRECTION) != 0) {
556 		super.updateTextDirection (AUTO_TEXT_DIRECTION);
557 	}
558 	applySegments ();
559 }
560 
applySegments()561 void applySegments () {
562 	/*
563 	 * It is possible (but unlikely), that application code could have
564 	 * disposed the widget in the modify event. If this happens, return to
565 	 * cancel the operation.
566 	 */
567 	if (isDisposed() || --clearSegmentsCount != 0) return;
568 	if (!hooks (SWT.Segments) && !filters (SWT.Segments)) return;
569 	int length = OS.GetWindowTextLength (handle);
570 	char [] buffer = new char [length + 1];
571 	if (length > 0) OS.GetWindowText (handle, buffer, length + 1);
572 	String string = new String (buffer, 0, length);
573 	/* Get segments text */
574 	Event event = new Event ();
575 	event.text = string;
576 	event.segments = segments;
577 	sendEvent (SWT.Segments, event);
578 	segments = event.segments;
579 	if (segments == null) return;
580 	int nSegments = segments.length;
581 	if (nSegments == 0) return;
582 	length = string == null ? 0 : string.length ();
583 
584 	for (int i = 1; i < nSegments; i++) {
585 		if (event.segments [i] < event.segments [i - 1] || event.segments [i] > length) {
586 			error (SWT.ERROR_INVALID_ARGUMENT);
587 		}
588 	}
589 	char [] segmentsChars = event.segmentsChars;
590 	char [] segmentsCharsCrLf = segmentsChars == null ? null : Display.withCrLf(segmentsChars);
591 	if (segmentsChars != segmentsCharsCrLf) {
592 		int [] segmentsCrLf = new int [nSegments + Math.min (nSegments, segmentsCharsCrLf.length - segmentsChars.length)];
593 		for (int i = 0, c = 0; i < segmentsChars.length && i < nSegments; i++) {
594 			if (segmentsChars [i] == '\n' && segmentsCharsCrLf [i + c] == '\r') {
595 				segmentsCrLf [i + c++] = segments [i];
596 			}
597 			segmentsCrLf [i + c] = segments [i];
598 		}
599 		segments = segmentsCrLf;
600 		nSegments = segments.length;
601 		segmentsChars = segmentsCharsCrLf;
602 	}
603 
604 	int limit = (int)OS.SendMessage (handle, OS.EM_GETLIMITTEXT, 0, 0) & 0x7fffffff;
605 	OS.SendMessage (handle, OS.EM_SETLIMITTEXT, limit + Math.min (nSegments, LIMIT - limit), 0);
606 	length += nSegments;
607 	char [] newChars = new char [length + 1];
608 	int charCount = 0, segmentCount = 0;
609 	char defaultSeparator = getOrientation () == SWT.RIGHT_TO_LEFT ? RTL_MARK : LTR_MARK;
610 	while (charCount < length) {
611 		if (segmentCount < nSegments && charCount - segmentCount == segments [segmentCount]) {
612 			char separator = segmentsChars != null && segmentsChars.length > segmentCount ? segmentsChars [segmentCount] : defaultSeparator;
613 			newChars [charCount++] = separator;
614 			segmentCount++;
615 		} else if (string != null) {
616 			newChars [charCount] = string.charAt (charCount++ - segmentCount);
617 		}
618 	}
619 	while (segmentCount < nSegments) {
620 		segments [segmentCount] = charCount - segmentCount;
621 		char separator = segmentsChars != null && segmentsChars.length > segmentCount ? segmentsChars [segmentCount] : defaultSeparator;
622 		newChars [charCount++] = separator;
623 		segmentCount++;
624 	}
625 	/* Get the current selection */
626 	int [] start = new int [1], end = new int [1];
627 	OS.SendMessage (handle, OS.EM_GETSEL, start, end);
628 	boolean oldIgnoreCharacter = ignoreCharacter, oldIgnoreModify = ignoreModify, oldIgnoreVerify = ignoreVerify;
629 	ignoreCharacter = ignoreModify = ignoreVerify = true;
630 	/*
631 	 * SetWindowText empties the undo buffer and disables undo menu item.
632 	 * Sending OS.EM_REPLACESEL message instead.
633 	 */
634 	newChars [length] = 0;
635 	OS.SendMessage (handle, OS.EM_SETSEL, 0, -1);
636 	long undo = OS.SendMessage (handle, OS.EM_CANUNDO, 0, 0);
637 	OS.SendMessage (handle, OS.EM_REPLACESEL, undo, newChars);
638 	/* Restore selection */
639 	start [0] = translateOffset (start [0]);
640 	end [0] = translateOffset (end [0]);
641 	OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]);
642 	ignoreCharacter = oldIgnoreCharacter;
643 	ignoreModify = oldIgnoreModify;
644 	ignoreVerify = oldIgnoreVerify;
645 }
646 
checkStyle(int style)647 static int checkStyle (int style) {
648 	if ((style & SWT.SINGLE) != 0 && (style & SWT.MULTI) != 0) {
649 		style &= ~SWT.MULTI;
650 	}
651 	style = checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
652 	/*
653 	 * NOTE: ICON_CANCEL and ICON_SEARCH have the same value as H_SCROLL and
654 	 * V_SCROLL. The meaning is determined by whether SWT.SEARCH is set.
655 	 */
656 	if ((style & SWT.SEARCH) != 0) {
657 		style |= SWT.SINGLE | SWT.BORDER;
658 		style &= ~(SWT.PASSWORD | SWT.WRAP);
659 	} else if ((style & SWT.SINGLE) != 0) {
660 		style &= ~(SWT.H_SCROLL | SWT.V_SCROLL | SWT.WRAP);
661 	}
662 	if ((style & SWT.WRAP) != 0) {
663 		style |= SWT.MULTI;
664 		style &= ~SWT.H_SCROLL;
665 	}
666 	if ((style & SWT.MULTI) != 0) style &= ~SWT.PASSWORD;
667 	if ((style & (SWT.SINGLE | SWT.MULTI)) != 0) return style;
668 	if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) != 0) return style | SWT.MULTI;
669 	return style | SWT.SINGLE;
670 }
671 
clearSegments(boolean applyText)672 void clearSegments (boolean applyText) {
673 	if (clearSegmentsCount++ != 0) return;
674 	if (segments == null) return;
675 	int nSegments = segments.length;
676 	if (nSegments == 0) return;
677 	int limit = (int)OS.SendMessage (handle, OS.EM_GETLIMITTEXT, 0, 0) & 0x7fffffff;
678 	if (limit < LIMIT) {
679 		OS.SendMessage (handle, OS.EM_SETLIMITTEXT, Math.max (1, limit - nSegments), 0);
680 	}
681 	if (!applyText) {
682 		segments = null;
683 		return;
684 	}
685 	boolean oldIgnoreCharacter = ignoreCharacter, oldIgnoreModify = ignoreModify, oldIgnoreVerify = ignoreVerify;
686 	ignoreCharacter = ignoreModify = ignoreVerify = true;
687 	int length = OS.GetWindowTextLength (handle);
688 	int cp = getCodePage ();
689 	TCHAR buffer = new TCHAR (cp, length + 1);
690 	if (length > 0) OS.GetWindowText (handle, buffer, length + 1);
691 	buffer = deprocessText (buffer, 0, -1, true);
692 	/* Get the current selection */
693 	int [] start = new int [1], end = new int [1];
694 	OS.SendMessage (handle, OS.EM_GETSEL, start, end);
695 	start [0] = untranslateOffset (start [0]);
696 	end [0] = untranslateOffset (end[0]);
697 	segments = null;
698 	/*
699 	 * SetWindowText empties the undo buffer and disables undo in the context
700 	 * menu. Sending OS.EM_REPLACESEL message instead.
701 	 */
702 	OS.SendMessage (handle, OS.EM_SETSEL, 0, -1);
703 	long undo = OS.SendMessage (handle, OS.EM_CANUNDO, 0, 0);
704 	OS.SendMessage (handle, OS.EM_REPLACESEL, undo, buffer);
705 	OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]);
706 	ignoreCharacter = oldIgnoreCharacter;
707 	ignoreModify = oldIgnoreModify;
708 	ignoreVerify = oldIgnoreVerify;
709 }
710 
711 /**
712  * Clears the selection.
713  *
714  * @exception SWTException <ul>
715  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
716  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
717  * </ul>
718  */
clearSelection()719 public void clearSelection () {
720 	checkWidget ();
721 	OS.SendMessage (handle, OS.EM_SETSEL, -1, 0);
722 }
723 
computeSizeInPixels(int wHint, int hHint, boolean changed)724 @Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
725 	checkWidget ();
726 	int height = 0, width = 0;
727 	if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
728 		long newFont, oldFont = 0;
729 		long hDC = OS.GetDC (handle);
730 		newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
731 		if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
732 		TEXTMETRIC tm = new TEXTMETRIC ();
733 		OS.GetTextMetrics (hDC, tm);
734 		int count = (style & SWT.SINGLE) != 0 ? 1 : (int)OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0);
735 		height = count * tm.tmHeight;
736 		RECT rect = new RECT ();
737 		int flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_NOPREFIX;
738 		boolean wrap = (style & SWT.MULTI) != 0 && (style & SWT.WRAP) != 0;
739 		if (wrap && wHint != SWT.DEFAULT) {
740 			flags |= OS.DT_WORDBREAK;
741 			rect.right = wHint;
742 		}
743 		int length = OS.GetWindowTextLength (handle);
744 		if (length != 0) {
745 			char [] buffer = new char [length + 1];
746 			OS.GetWindowText (handle, buffer, length + 1);
747 			OS.DrawText (hDC, buffer, length, rect, flags);
748 			Arrays.fill (buffer, '\0'); // erase sensitive data
749 			width = rect.right - rect.left;
750 		}
751 		if (wrap && hHint == SWT.DEFAULT) {
752 			int newHeight = rect.bottom - rect.top;
753 			if (newHeight != 0) height = newHeight;
754 		}
755 		if ((style & SWT.SINGLE) != 0 && message.length () > 0) {
756 			OS.SetRect (rect, 0, 0, 0, 0);
757 			char [] buffer = message.toCharArray ();
758 			OS.DrawText (hDC, buffer, buffer.length, rect, flags);
759 			width = Math.max (width, rect.right - rect.left);
760 		}
761 		if (newFont != 0) OS.SelectObject (hDC, oldFont);
762 		OS.ReleaseDC (handle, hDC);
763 	}
764 	if (width == 0) width = DEFAULT_WIDTH;
765 	if (height == 0) height = DEFAULT_HEIGHT;
766 	if (wHint != SWT.DEFAULT) width = wHint;
767 	if (hHint != SWT.DEFAULT) height = hHint;
768 	Rectangle trim = computeTrimInPixels (0, 0, width, height);
769 	return new Point (trim.width, trim.height);
770 }
771 
computeTrimInPixels(int x, int y, int width, int height)772 @Override Rectangle computeTrimInPixels (int x, int y, int width, int height) {
773 	checkWidget ();
774 	Rectangle rect = super.computeTrimInPixels (x, y, width, height);
775 	/*
776 	* The preferred height of a single-line text widget
777 	* has been hand-crafted to be the same height as
778 	* the single-line text widget in an editable combo
779 	* box.
780 	*/
781 	long margins = OS.SendMessage(handle, OS.EM_GETMARGINS, 0, 0);
782 	rect.x -= OS.LOWORD (margins);
783 	rect.width += OS.LOWORD (margins) + OS.HIWORD (margins);
784 	if ((style & SWT.H_SCROLL) != 0) rect.width++;
785 	if ((style & SWT.BORDER) != 0) {
786 		rect.x -= 1;
787 		rect.y -= 1;
788 		rect.width += 2;
789 		rect.height += 2;
790 
791 		// When WS_BORDER is used instead of WS_EX_CLIENTEDGE, compensate the size difference
792 		if (isUseWsBorder ()) {
793 			int dx = OS.GetSystemMetrics (OS.SM_CXEDGE) - OS.GetSystemMetrics (OS.SM_CXBORDER);
794 			int dy = OS.GetSystemMetrics (OS.SM_CYEDGE) - OS.GetSystemMetrics (OS.SM_CYBORDER);
795 			rect.x -= dx;
796 			rect.y -= dy;
797 			rect.width += 2*dx;
798 			rect.height += 2*dy;
799 		}
800 	}
801 
802 	return rect;
803 }
804 
805 /**
806  * Copies the selected text.
807  * <p>
808  * The current selection is copied to the clipboard.
809  * </p>
810  *
811  * @exception SWTException <ul>
812  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
813  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
814  * </ul>
815  */
copy()816 public void copy () {
817 	checkWidget ();
818 	OS.SendMessage (handle, OS.WM_COPY, 0, 0);
819 }
820 
821 @Override
createScrollBar(int type)822 ScrollBar createScrollBar (int type) {
823 	return (style & SWT.SEARCH) == 0 ? super.createScrollBar(type) : null;
824 }
825 
826 @Override
createWidget()827 void createWidget () {
828 	super.createWidget ();
829 	message = "";
830 	doubleClick = true;
831 	setTabStops (tabs = 8);
832 	fixAlignment ();
833 }
834 
835 /**
836  * Cuts the selected text.
837  * <p>
838  * The current selection is first copied to the
839  * clipboard and then deleted from the widget.
840  * </p>
841  *
842  * @exception SWTException <ul>
843  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
844  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
845  * </ul>
846  */
cut()847 public void cut () {
848 	checkWidget ();
849 	if ((style & SWT.READ_ONLY) != 0) return;
850 	OS.SendMessage (handle, OS.WM_CUT, 0, 0);
851 }
852 
853 @Override
defaultBackground()854 int defaultBackground () {
855 	int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
856 	if ((bits & OS.ES_READONLY) != 0 || !OS.IsWindowEnabled (handle)) {
857 		return OS.GetSysColor (OS.COLOR_3DFACE);
858 	}
859 	return OS.GetSysColor (OS.COLOR_WINDOW);
860 }
861 
deprocessText(TCHAR text, int start, int end, boolean terminate)862 TCHAR deprocessText (TCHAR text, int start, int end, boolean terminate) {
863 	if (text == null) return null;
864 	int length = text.length ();
865 	char [] chars;
866 	if (start < 0) start = 0;
867 	chars = text.chars;
868 	if (text.chars [length - 1] == 0) length--;
869 	if (end == -1) end = length;
870 	if (segments != null && end > segments [0]) {
871 		int nSegments = segments.length;
872 		if (nSegments > 0 && start <= segments [nSegments - 1]) {
873 			int nLeadSegments = 0;
874 			while (start - nLeadSegments > segments [nLeadSegments]) nLeadSegments++;
875 			int segmentCount = nLeadSegments;
876 			for (int i = start; i < end; i++) {
877 				if (segmentCount < nSegments && i - segmentCount == segments [segmentCount]) {
878 					++segmentCount;
879 				} else {
880 					chars [i - segmentCount + nLeadSegments] = chars [i];
881 				}
882 			}
883 			length = end - start - segmentCount + nLeadSegments;
884 		}
885 	}
886 	if (start != 0 || end != length) {
887 		char [] newChars = new char [length];
888 		System.arraycopy(chars, start, newChars, 0, length);
889 		return new TCHAR (getCodePage (), newChars, terminate);
890 	}
891 	return text;
892 }
893 
894 @Override
dragDetect(long hwnd, int x, int y, boolean filter, boolean [] detect, boolean [] consume)895 boolean dragDetect (long hwnd, int x, int y, boolean filter, boolean [] detect, boolean [] consume) {
896 	if (filter) {
897 		int [] start = new int [1], end = new int [1];
898 		OS.SendMessage (handle, OS.EM_GETSEL, start, end);
899 		if (start [0] != end [0]) {
900 			long lParam = OS.MAKELPARAM (x, y);
901 			int position = OS.LOWORD (OS.SendMessage (handle, OS.EM_CHARFROMPOS, 0, lParam));
902 			if (start [0] <= position && position < end [0]) {
903 				if (super.dragDetect (hwnd, x, y, filter, detect, consume)) {
904 					if (consume != null) consume [0] = true;
905 					return true;
906 				}
907 			}
908 		}
909 		return false;
910 	}
911 	return super.dragDetect (hwnd, x, y, filter, detect, consume);
912 }
913 
914 @Override
enableDarkModeExplorerTheme()915 void enableDarkModeExplorerTheme() {
916 	/*
917 	 * Feature in Windows. If the control has default foreground and
918 	 * background, the background gets black without focus and white with
919 	 * focus, but the foreground color always stays black.
920 	 */
921 	if (hasCustomBackground() || hasCustomForeground()) {
922 		super.enableDarkModeExplorerTheme();
923 	}
924 }
925 
fixAlignment()926 void fixAlignment () {
927 	/*
928 	* Feature in Windows.  When the edit control is not
929 	* mirrored, it uses WS_EX_RIGHT, WS_EX_RTLREADING and
930 	* WS_EX_LEFTSCROLLBAR to give the control a right to
931 	* left appearance.  This causes the control to be lead
932 	* aligned no matter what alignment was specified by
933 	* the programmer.  For example, setting ES_RIGHT and
934 	* WS_EX_LAYOUTRTL should cause the contents of the
935 	* control to be left (trail) aligned in a mirrored world.
936 	* When the orientation is changed by the user or
937 	* specified by the programmer, WS_EX_RIGHT conflicts
938 	* with the mirrored alignment.  The fix is to clear
939 	* or set WS_EX_RIGHT to achieve the correct alignment
940 	* according to the orientation and mirroring.
941 	*/
942 	if ((style & SWT.MIRRORED) != 0) return;
943 	int bits1 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
944 	int bits2 = OS.GetWindowLong (handle, OS.GWL_STYLE);
945 	if ((style & SWT.LEFT_TO_RIGHT) != 0) {
946 		if ((style & SWT.RIGHT) != 0) {
947 			bits1 |= OS.WS_EX_RIGHT;
948 			bits2 |= OS.ES_RIGHT;
949 		}
950 		if ((style & SWT.LEFT) != 0) {
951 			bits1 &= ~OS.WS_EX_RIGHT;
952 			bits2 &= ~OS.ES_RIGHT;
953 		}
954 	} else {
955 		if ((style & SWT.RIGHT) != 0) {
956 			bits1 &= ~OS.WS_EX_RIGHT;
957 			bits2 &= ~OS.ES_RIGHT;
958 		}
959 		if ((style & SWT.LEFT) != 0) {
960 			bits1 |= OS.WS_EX_RIGHT;
961 			bits2 |= OS.ES_RIGHT;
962 		}
963 	}
964 	if ((style & SWT.CENTER) != 0) {
965 		bits2 |= OS.ES_CENTER;
966 	}
967 	OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits1);
968 	OS.SetWindowLong (handle, OS.GWL_STYLE, bits2);
969 }
970 
getBorderWidthInPixels()971 @Override int getBorderWidthInPixels () {
972 	checkWidget ();
973 	/*
974 	* Feature in Windows 2000 and XP.  Despite the fact that WS_BORDER
975 	* is set when the edit control is created, the style bit is cleared.
976 	* The fix is to avoid the check for WS_BORDER and use the SWT widget
977 	* style bits instead.
978 	*/
979 //	if ((style & SWT.BORDER) != 0 && (style & SWT.FLAT) != 0) {
980 //		return OS.GetSystemMetrics (OS.SM_CXBORDER);
981 //	}
982 	return super.getBorderWidthInPixels ();
983 }
984 
985 /**
986  * Returns the line number of the caret.
987  * <p>
988  * The line number of the caret is returned.
989  * </p>
990  *
991  * @return the line number
992  *
993  * @exception SWTException <ul>
994  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
995  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
996  * </ul>
997  */
getCaretLineNumber()998 public int getCaretLineNumber () {
999 	checkWidget ();
1000 	return (int)OS.SendMessage (handle, OS.EM_LINEFROMCHAR, -1, 0);
1001 }
1002 
1003 /**
1004  * Returns a point describing the location of the caret relative
1005  * to the receiver.
1006  *
1007  * @return a point, the location of the caret
1008  *
1009  * @exception SWTException <ul>
1010  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1011  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1012  * </ul>
1013  */
getCaretLocation()1014 public Point getCaretLocation () {
1015 	checkWidget ();
1016 	return DPIUtil.autoScaleDown(getCaretLocationInPixels());
1017 }
1018 
getCaretLocationInPixels()1019 Point getCaretLocationInPixels () {
1020 	/*
1021 	* Bug in Windows.  For some reason, Windows is unable
1022 	* to return the pixel coordinates of the last character
1023 	* in the widget.  The fix is to temporarily insert a
1024 	* space, query the coordinates and delete the space.
1025 	* The selection is always an i-beam in this case because
1026 	* this is the only time the start of the selection can
1027 	* be equal to the last character position in the widget.
1028 	* If EM_POSFROMCHAR fails for any other reason, return
1029 	* pixel coordinates (0,0).
1030 	*/
1031 	int position = translateOffset (getCaretPosition ());
1032 	long caretPos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, position, 0);
1033 	if (caretPos == -1) {
1034 		caretPos = 0;
1035 		if (position >= OS.GetWindowTextLength (handle)) {
1036 			int [] start = new int [1], end = new int [1];
1037 			OS.SendMessage (handle, OS.EM_GETSEL, start, end);
1038 			OS.SendMessage (handle, OS.EM_SETSEL, position, position);
1039 			/*
1040 			* Feature in Windows.  When an edit control with ES_MULTILINE
1041 			* style that does not have the WS_VSCROLL style is full (i.e.
1042 			* there is no space at the end to draw any more characters),
1043 			* EM_REPLACESEL sends a WM_CHAR with a backspace character
1044 			* to remove any further text that is added.  This is an
1045 			* implementation detail of the edit control that is unexpected
1046 			* and can cause endless recursion when EM_REPLACESEL is sent
1047 			* from a WM_CHAR handler.  The fix is to ignore calling the
1048 			* handler from WM_CHAR.
1049 			*/
1050 			ignoreCharacter = ignoreModify = true;
1051 			OS.SendMessage (handle, OS.EM_REPLACESEL, 0, new char [] {' ', '\0'});
1052 			caretPos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, position, 0);
1053 			OS.SendMessage (handle, OS.EM_SETSEL, position, position + 1);
1054 			OS.SendMessage (handle, OS.EM_REPLACESEL, 0, new char [] {'\0'});
1055 			ignoreCharacter = ignoreModify = false;
1056 			OS.SendMessage (handle, OS.EM_SETSEL, start [0], start [0]);
1057 			OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]);
1058 		}
1059 	}
1060 	return new Point (OS.GET_X_LPARAM (caretPos), OS.GET_Y_LPARAM (caretPos));
1061 }
1062 
1063 /**
1064  * Returns the character position of the caret.
1065  * <p>
1066  * Indexing is zero based.
1067  * </p>
1068  *
1069  * @return the position of the caret
1070  *
1071  * @exception SWTException <ul>
1072  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1073  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1074  * </ul>
1075  */
getCaretPosition()1076 public int getCaretPosition () {
1077 	checkWidget ();
1078 	int [] start = new int [1], end = new int [1];
1079 	OS.SendMessage (handle, OS.EM_GETSEL, start, end);
1080 	/*
1081 	* In Windows, there is no API to get the position of the caret
1082 	* when the selection is not an i-beam.  The best that can be done
1083 	* is to query the pixel position of the current caret and compare
1084 	* it to the pixel position of the start and end of the selection.
1085 	*
1086 	* NOTE:  This does not work when the i-beam belongs to another
1087 	* control.  In this case, guess that the i-beam is at the start
1088 	* of the selection.
1089 	*/
1090 	int caret = start [0];
1091 	if (start [0] != end [0]) {
1092 		int startLine = (int)OS.SendMessage (handle, OS.EM_LINEFROMCHAR, start [0], 0);
1093 		int endLine = (int)OS.SendMessage (handle, OS.EM_LINEFROMCHAR, end [0], 0);
1094 		if (startLine == endLine) {
1095 			int idThread = OS.GetWindowThreadProcessId (handle, null);
1096 			GUITHREADINFO lpgui = new GUITHREADINFO ();
1097 			lpgui.cbSize = GUITHREADINFO.sizeof;
1098 			if (OS.GetGUIThreadInfo (idThread, lpgui)) {
1099 				if (lpgui.hwndCaret == handle || lpgui.hwndCaret == 0) {
1100 					POINT ptCurrentPos = new POINT ();
1101 					if (OS.GetCaretPos (ptCurrentPos)) {
1102 						long endPos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, end [0], 0);
1103 						if (endPos == -1) {
1104 							long startPos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, start [0], 0);
1105 							int startX = OS.GET_X_LPARAM (startPos);
1106 							if (ptCurrentPos.x > startX) caret = end [0];
1107 						} else {
1108 							int endX = OS.GET_X_LPARAM (endPos);
1109 							if (ptCurrentPos.x >= endX) caret = end [0];
1110 						}
1111 					}
1112 				}
1113 			}
1114 		} else {
1115 			int caretPos = (int)OS.SendMessage (handle, OS.EM_LINEINDEX, -1, 0);
1116 			int caretLine = (int)OS.SendMessage (handle, OS.EM_LINEFROMCHAR, caretPos, 0);
1117 			if (caretLine == endLine) caret = end [0];
1118 		}
1119 	}
1120 	return untranslateOffset (caret);
1121 }
1122 
1123 /**
1124  * Returns the number of characters.
1125  *
1126  * @return number of characters in the widget
1127  *
1128  * @exception SWTException <ul>
1129  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1130  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1131  * </ul>
1132  */
getCharCount()1133 public int getCharCount () {
1134 	checkWidget ();
1135 	int length = OS.GetWindowTextLength (handle);
1136 	return untranslateOffset (length);
1137 }
1138 
1139 /**
1140  * Returns the double click enabled flag.
1141  * <p>
1142  * The double click flag enables or disables the
1143  * default action of the text widget when the user
1144  * double clicks.
1145  * </p>
1146  *
1147  * @return whether or not double click is enabled
1148  *
1149  * @exception SWTException <ul>
1150  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1151  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1152  * </ul>
1153  */
getDoubleClickEnabled()1154 public boolean getDoubleClickEnabled () {
1155 	checkWidget ();
1156 	return doubleClick;
1157 }
1158 
1159 /**
1160  * Returns the echo character.
1161  * <p>
1162  * The echo character is the character that is
1163  * displayed when the user enters text or the
1164  * text is changed by the programmer.
1165  * </p>
1166  *
1167  * @return the echo character
1168  *
1169  * @exception SWTException <ul>
1170  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1171  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1172  * </ul>
1173  *
1174  * @see #setEchoChar
1175  */
getEchoChar()1176 public char getEchoChar () {
1177 	checkWidget ();
1178 	return (char) OS.SendMessage (handle, OS.EM_GETPASSWORDCHAR, 0, 0);
1179 }
1180 
1181 /**
1182  * Returns the editable state.
1183  *
1184  * @return whether or not the receiver is editable
1185  *
1186  * @exception SWTException <ul>
1187  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1188  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1189  * </ul>
1190  */
getEditable()1191 public boolean getEditable () {
1192 	checkWidget ();
1193 	int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1194 	return (bits & OS.ES_READONLY) == 0;
1195 }
1196 
1197 /**
1198  * Returns the number of lines.
1199  *
1200  * @return the number of lines in the widget
1201  *
1202  * @exception SWTException <ul>
1203  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1204  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1205  * </ul>
1206  */
getLineCount()1207 public int getLineCount () {
1208 	checkWidget ();
1209 	return (int)OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0);
1210 }
1211 
1212 /**
1213  * Returns the line delimiter.
1214  *
1215  * @return a string that is the line delimiter
1216  *
1217  * @exception SWTException <ul>
1218  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1219  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1220  * </ul>
1221  *
1222  * @see #DELIMITER
1223  */
getLineDelimiter()1224 public String getLineDelimiter () {
1225 	checkWidget ();
1226 	return DELIMITER;
1227 }
1228 
1229 /**
1230  * Returns the height of a line.
1231  *
1232  * @return the height of a row of text
1233  *
1234  * @exception SWTException <ul>
1235  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1236  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1237  * </ul>
1238  */
getLineHeight()1239 public int getLineHeight () {
1240 	checkWidget ();
1241 	return DPIUtil.autoScaleDown(getLineHeightInPixels ());
1242 }
1243 
getLineHeightInPixels()1244 int getLineHeightInPixels () {
1245 	long newFont, oldFont = 0;
1246 	long hDC = OS.GetDC (handle);
1247 	newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1248 	if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1249 	TEXTMETRIC tm = new TEXTMETRIC ();
1250 	OS.GetTextMetrics (hDC, tm);
1251 	if (newFont != 0) OS.SelectObject (hDC, oldFont);
1252 	OS.ReleaseDC (handle, hDC);
1253 	return tm.tmHeight;
1254 }
1255 
1256 /**
1257  * Returns the orientation of the receiver, which will be one of the
1258  * constants <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
1259  *
1260  * @return the orientation style
1261  *
1262  * @exception SWTException <ul>
1263  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1264  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1265  * </ul>
1266  *
1267  * @since 2.1.2
1268  */
1269 @Override
getOrientation()1270 public int getOrientation () {
1271 	return super.getOrientation ();
1272 }
1273 
1274 /**
1275  * Returns the widget message.  The message text is displayed
1276  * as a hint for the user, indicating the purpose of the field.
1277  * <p>
1278  * Typically this is used in conjunction with <code>SWT.SEARCH</code>.
1279  * </p>
1280  *
1281  * @return the widget message
1282  *
1283  * @exception SWTException <ul>
1284  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1285  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1286  * </ul>
1287  *
1288  * @since 3.3
1289  */
getMessage()1290 public String getMessage () {
1291 	checkWidget ();
1292 	return message;
1293 }
1294 
1295 /**
1296  * Returns the character position at the given point in the receiver
1297  * or -1 if no such position exists. The point is in the coordinate
1298  * system of the receiver.
1299  * <p>
1300  * Indexing is zero based.
1301  * </p>
1302  *
1303  * @return the position of the caret
1304  *
1305  * @exception SWTException <ul>
1306  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1307  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1308  * </ul>
1309  *
1310  * @since 3.3
1311  */
1312 //TODO - Javadoc
getPosition(Point point)1313 /*public*/ int getPosition (Point point) {
1314 	checkWidget();
1315 	if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
1316 	long lParam = OS.MAKELPARAM (point.x, point.y);
1317 	int position = OS.LOWORD (OS.SendMessage (handle, OS.EM_CHARFROMPOS, 0, lParam));
1318 	return untranslateOffset (position);
1319 }
1320 
1321 /**
1322  * Returns a <code>Point</code> whose x coordinate is the
1323  * character position representing the start of the selected
1324  * text, and whose y coordinate is the character position
1325  * representing the end of the selection. An "empty" selection
1326  * is indicated by the x and y coordinates having the same value.
1327  * <p>
1328  * Indexing is zero based.  The range of a selection is from
1329  * 0..N where N is the number of characters in the widget.
1330  * </p>
1331  *
1332  * @return a point representing the selection start and end
1333  *
1334  * @exception SWTException <ul>
1335  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1336  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1337  * </ul>
1338  */
getSelection()1339 public Point getSelection () {
1340 	checkWidget ();
1341 	int [] start = new int [1], end = new int [1];
1342 	OS.SendMessage (handle, OS.EM_GETSEL, start, end);
1343 	return new Point (untranslateOffset (start [0]), untranslateOffset (end [0]));
1344 }
1345 
1346 /**
1347  * Returns the number of selected characters.
1348  *
1349  * @return the number of selected characters.
1350  *
1351  * @exception SWTException <ul>
1352  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1353  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1354  * </ul>
1355  */
getSelectionCount()1356 public int getSelectionCount () {
1357 	checkWidget ();
1358 	Point selection = getSelection ();
1359 	return selection.y - selection.x;
1360 }
1361 
1362 /**
1363  * Gets the selected text, or an empty string if there is no current selection.
1364  *
1365  * @return the selected text
1366  *
1367  * @exception SWTException <ul>
1368  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1369  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1370  * </ul>
1371  */
getSelectionText()1372 public String getSelectionText () {
1373 	checkWidget ();
1374 	int length = OS.GetWindowTextLength (handle);
1375 	if (length == 0) return "";
1376 	int [] start = new int [1], end = new int [1];
1377 	OS.SendMessage (handle, OS.EM_GETSEL, start, end);
1378 	if (start [0] == end [0]) return "";
1379 	TCHAR buffer = new TCHAR (getCodePage (), length + 1);
1380 	OS.GetWindowText (handle, buffer, length + 1);
1381 	if (segments != null) {
1382 		buffer = deprocessText (buffer, start [0], end [0], false);
1383 		return buffer.toString ();
1384 	}
1385 	return buffer.toString (start [0], end [0] - start [0]);
1386 }
1387 
1388 /**
1389  * Returns the number of tabs.
1390  * <p>
1391  * Tab stop spacing is specified in terms of the
1392  * space (' ') character.  The width of a single
1393  * tab stop is the pixel width of the spaces.
1394  * </p>
1395  *
1396  * @return the number of tab characters
1397  *
1398  * @exception SWTException <ul>
1399  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1400  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1401  * </ul>
1402  */
getTabs()1403 public int getTabs () {
1404 	checkWidget ();
1405 	return tabs;
1406 }
1407 
getTabWidth(int tabs)1408 int getTabWidth (int tabs) {
1409 	long oldFont = 0;
1410 	RECT rect = new RECT ();
1411 	long hDC = OS.GetDC (handle);
1412 	long newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1413 	if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1414 	int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1415 	OS.DrawText (hDC, new char [] {' '}, 1, rect, flags);
1416 	if (newFont != 0) OS.SelectObject (hDC, oldFont);
1417 	OS.ReleaseDC (handle, hDC);
1418 	return (rect.right - rect.left) * tabs;
1419 }
1420 
1421 /**
1422  * Returns the widget text.
1423  * <p>
1424  * The text for a text widget is the characters in the widget, or
1425  * an empty string if this has never been set.
1426  * </p>
1427  *
1428  * @return the widget text
1429  *
1430  * @exception SWTException <ul>
1431  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1432  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1433  * </ul>
1434  */
getText()1435 public String getText () {
1436 	checkWidget ();
1437 	int length = OS.GetWindowTextLength (handle);
1438 	if (length == 0) return "";
1439 	TCHAR buffer = new TCHAR (getCodePage (), length + 1);
1440 	OS.GetWindowText (handle, buffer, length + 1);
1441 	if (segments != null) {
1442 		buffer = deprocessText (buffer, 0, -1, false);
1443 		return buffer.toString ();
1444 	}
1445 	return buffer.toString (0, length);
1446 }
1447 
1448 /**
1449  * Returns the widget's text as a character array.
1450  * <p>
1451  * The text for a text widget is the characters in the widget, or
1452  * a zero-length array if this has never been set.
1453  * </p>
1454  * <p>
1455  * Note: Use this API to prevent the text from being written into a String
1456  * object whose lifecycle is outside of your control. This can help protect
1457  * the text, for example, when the widget is used as a password field.
1458  * However, the text can't be protected if an {@link SWT#Segments} or
1459  * {@link SWT#Verify} listener has been added to the widget.
1460  * </p>
1461  *
1462  * @return a character array that contains the widget's text
1463  *
1464  * @exception SWTException <ul>
1465  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1466  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1467  * </ul>
1468  *
1469  * @see #setTextChars(char[])
1470  *
1471  * @since 3.7
1472  */
getTextChars()1473 public char[] getTextChars () {
1474 	checkWidget ();
1475 	int length = OS.GetWindowTextLength (handle);
1476 	if (length == 0) return new char[0];
1477 	TCHAR buffer = new TCHAR (getCodePage (), length + 1);
1478 	OS.GetWindowText (handle, buffer, length + 1);
1479 	if (segments != null) buffer = deprocessText (buffer, 0, -1, false);
1480 	char [] chars = new char [length];
1481 	System.arraycopy (buffer.chars, 0, chars, 0, length);
1482 	buffer.clear ();
1483 	return chars;
1484 }
1485 
1486 /**
1487  * Returns a range of text.  Returns an empty string if the
1488  * start of the range is greater than the end.
1489  * <p>
1490  * Indexing is zero based.  The range of
1491  * a selection is from 0..N-1 where N is
1492  * the number of characters in the widget.
1493  * </p>
1494  *
1495  * @param start the start of the range
1496  * @param end the end of the range
1497  * @return the range of text
1498  *
1499  * @exception SWTException <ul>
1500  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1501  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1502  * </ul>
1503  */
getText(int start, int end)1504 public String getText (int start, int end) {
1505 	checkWidget ();
1506 	if (!(start <= end && 0 <= end)) return "";
1507 	int length = OS.GetWindowTextLength (handle);
1508 	end = Math.min (end, untranslateOffset (length) - 1);
1509 	if (start > end) return "";
1510 	start = Math.max (0, start);
1511 	/*
1512 	* NOTE: The current implementation uses substring ()
1513 	* which can reference a potentially large character
1514 	* array.
1515 	*/
1516 	return getText ().substring (start, end + 1);
1517 }
1518 
1519 /**
1520  * Returns the maximum number of characters that the receiver is capable of holding.
1521  * <p>
1522  * If this has not been changed by <code>setTextLimit()</code>,
1523  * it will be the constant <code>Text.LIMIT</code>.
1524  * </p>
1525  *
1526  * @return the text limit
1527  *
1528  * @exception SWTException <ul>
1529  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1530  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1531  * </ul>
1532  *
1533  * @see #LIMIT
1534  */
getTextLimit()1535 public int getTextLimit () {
1536 	checkWidget ();
1537 	int limit = (int)OS.SendMessage (handle, OS.EM_GETLIMITTEXT, 0, 0) & 0x7FFFFFFF;
1538 	if (segments != null && limit < LIMIT) limit = Math.max (1, limit - segments.length);
1539 	return limit;
1540 }
1541 
1542 /**
1543  * Returns the zero-relative index of the line which is currently
1544  * at the top of the receiver.
1545  * <p>
1546  * This index can change when lines are scrolled or new lines are added or removed.
1547  * </p>
1548  *
1549  * @return the index of the top line
1550  *
1551  * @exception SWTException <ul>
1552  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1553  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1554  * </ul>
1555  */
getTopIndex()1556 public int getTopIndex () {
1557 	checkWidget ();
1558 	if ((style & SWT.SINGLE) != 0) return 0;
1559 	return (int)OS.SendMessage (handle, OS.EM_GETFIRSTVISIBLELINE, 0, 0);
1560 }
1561 
1562 /**
1563  * Returns the top SWT logical point.
1564  * <p>
1565  * The top point is the SWT logical point position of the line
1566  * that is currently at the top of the widget.  On
1567  * some platforms, a text widget can be scrolled by
1568  * points instead of lines so that a partial line
1569  * is displayed at the top of the widget.
1570  * </p><p>
1571  * The top SWT logical point changes when the widget is scrolled.
1572  * The top SWT logical point does not include the widget trimming.
1573  * </p>
1574  *
1575  * @return the SWT logical point position of the top line
1576  *
1577  * @exception SWTException <ul>
1578  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1579  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1580  * </ul>
1581  */
getTopPixel()1582 public int getTopPixel () {
1583 	checkWidget ();
1584 	return DPIUtil.autoScaleDown(getTopPixelInPixels());
1585 }
1586 
getTopPixelInPixels()1587 int getTopPixelInPixels () {
1588 	/*
1589 	* Note, EM_GETSCROLLPOS is implemented in Rich Edit 3.0
1590 	* and greater.  The plain text widget and previous versions
1591 	* of Rich Edit return zero.
1592 	*/
1593 	int [] buffer = new int [2];
1594 	long code = OS.SendMessage (handle, OS.EM_GETSCROLLPOS, 0, buffer);
1595 	if (code == 1) return buffer [1];
1596 	return getTopIndex () * getLineHeightInPixels ();
1597 }
1598 
1599 /**
1600  * Inserts a string.
1601  * <p>
1602  * The old selection is replaced with the new text.
1603  * </p>
1604  *
1605  * @param string the string
1606  *
1607  * @exception IllegalArgumentException <ul>
1608  *    <li>ERROR_NULL_ARGUMENT - if the string is <code>null</code></li>
1609  * </ul>
1610  * @exception SWTException <ul>
1611  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1612  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1613  * </ul>
1614  */
insert(String string)1615 public void insert (String string) {
1616 	checkWidget ();
1617 	if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1618 	string = Display.withCrLf (string);
1619 	if (hooks (SWT.Verify) || filters (SWT.Verify)) {
1620 		int [] start = new int [1], end = new int [1];
1621 		OS.SendMessage (handle, OS.EM_GETSEL, start, end);
1622 		string = verifyText (string, start [0], end [0], null);
1623 		if (string == null) return;
1624 	}
1625 	clearSegments (true);
1626 	TCHAR buffer = new TCHAR (getCodePage (), string, true);
1627 	/*
1628 	* Feature in Windows.  When an edit control with ES_MULTILINE
1629 	* style that does not have the WS_VSCROLL style is full (i.e.
1630 	* there is no space at the end to draw any more characters),
1631 	* EM_REPLACESEL sends a WM_CHAR with a backspace character
1632 	* to remove any further text that is added.  This is an
1633 	* implementation detail of the edit control that is unexpected
1634 	* and can cause endless recursion when EM_REPLACESEL is sent
1635 	* from a WM_CHAR handler.  The fix is to ignore calling the
1636 	* handler from WM_CHAR.
1637 	*/
1638 	ignoreCharacter = true;
1639 	OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
1640 	ignoreCharacter = false;
1641 	if ((state & HAS_AUTO_DIRECTION) != 0) {
1642 		super.updateTextDirection (AUTO_TEXT_DIRECTION);
1643 	}
1644 	applySegments ();
1645 }
1646 
1647 @Override
isUseWsBorder()1648 boolean isUseWsBorder () {
1649 	return super.isUseWsBorder () || ((display != null) && display.useWsBorderText);
1650 }
1651 
1652 /**
1653  * Pastes text from clipboard.
1654  * <p>
1655  * The selected text is deleted from the widget
1656  * and new text inserted from the clipboard.
1657  * </p>
1658  *
1659  * @exception SWTException <ul>
1660  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1661  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1662  * </ul>
1663  */
paste()1664 public void paste () {
1665 	checkWidget ();
1666 	if ((style & SWT.READ_ONLY) != 0) return;
1667 	OS.SendMessage (handle, OS.WM_PASTE, 0, 0);
1668 }
1669 
1670 @Override
releaseWidget()1671 void releaseWidget () {
1672 	super.releaseWidget ();
1673 	message = null;
1674 }
1675 
1676 /**
1677  * Removes the listener from the collection of listeners who will
1678  * be notified when the receiver's text is modified.
1679  *
1680  * @param listener the listener which should no longer be notified
1681  *
1682  * @exception IllegalArgumentException <ul>
1683  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1684  * </ul>
1685  * @exception SWTException <ul>
1686  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1687  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1688  * </ul>
1689  *
1690  * @see ModifyListener
1691  * @see #addModifyListener
1692  */
removeModifyListener(ModifyListener listener)1693 public void removeModifyListener (ModifyListener listener) {
1694 	checkWidget ();
1695 	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
1696 	if (eventTable == null) return;
1697 	eventTable.unhook (SWT.Modify, listener);
1698 }
1699 
1700 /**
1701  * Removes the listener from the collection of listeners who will
1702  * be notified when the receiver's text is modified.
1703  *
1704  * @param listener the listener which should no longer be notified
1705  *
1706  * @exception IllegalArgumentException <ul>
1707  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1708  * </ul>
1709  * @exception SWTException <ul>
1710  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1711  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1712  * </ul>
1713  *
1714  * @see SegmentEvent
1715  * @see SegmentListener
1716  * @see #addSegmentListener
1717  *
1718  * @since 3.8
1719  */
removeSegmentListener(SegmentListener listener)1720 public void removeSegmentListener (SegmentListener listener) {
1721 	checkWidget ();
1722 	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
1723 	eventTable.unhook (SWT.Segments, listener);
1724 	clearSegments (true);
1725 	applySegments ();
1726 }
1727 
1728 /**
1729  * Removes the listener from the collection of listeners who will
1730  * be notified when the control is selected by the user.
1731  *
1732  * @param listener the listener which should no longer be notified
1733  *
1734  * @exception IllegalArgumentException <ul>
1735  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1736  * </ul>
1737  * @exception SWTException <ul>
1738  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1739  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1740  * </ul>
1741  *
1742  * @see SelectionListener
1743  * @see #addSelectionListener
1744  */
removeSelectionListener(SelectionListener listener)1745 public void removeSelectionListener (SelectionListener listener) {
1746 	checkWidget ();
1747 	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
1748 	if (eventTable == null) return;
1749 	eventTable.unhook (SWT.Selection, listener);
1750 	eventTable.unhook (SWT.DefaultSelection,listener);
1751 }
1752 
1753 /**
1754  * Removes the listener from the collection of listeners who will
1755  * be notified when the control is verified.
1756  *
1757  * @param listener the listener which should no longer be notified
1758  *
1759  * @exception IllegalArgumentException <ul>
1760  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1761  * </ul>
1762  * @exception SWTException <ul>
1763  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1764  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1765  * </ul>
1766  *
1767  * @see VerifyListener
1768  * @see #addVerifyListener
1769  */
removeVerifyListener(VerifyListener listener)1770 public void removeVerifyListener (VerifyListener listener) {
1771 	checkWidget ();
1772 	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
1773 	if (eventTable == null) return;
1774 	eventTable.unhook (SWT.Verify, listener);
1775 }
1776 
1777 @Override
resolveTextDirection()1778 int resolveTextDirection() {
1779 	int textDirection = SWT.NONE;
1780 	int length = OS.GetWindowTextLength (handle);
1781 	if (length > 0) {
1782 		TCHAR buffer = new TCHAR (getCodePage (), length + 1);
1783 		OS.GetWindowText (handle, buffer, length + 1);
1784 		if (segments != null) {
1785 			buffer = deprocessText (buffer, 0, -1, false);
1786 			textDirection = BidiUtil.resolveTextDirection(buffer.toString ());
1787 		} else {
1788 			textDirection = BidiUtil.resolveTextDirection(buffer.toString (0, length));
1789 		}
1790 		if (textDirection == SWT.NONE) {
1791 			/*
1792 			 * Force direction update also when there are no strong bidi chars.
1793 			*/
1794 			textDirection = (style & SWT.RIGHT_TO_LEFT) != 0 ? SWT.RIGHT_TO_LEFT : SWT.LEFT_TO_RIGHT;
1795 		}
1796 	}
1797 	return textDirection;
1798 }
1799 
1800 /**
1801  * Selects all the text in the receiver.
1802  *
1803  * @exception SWTException <ul>
1804  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1805  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1806  * </ul>
1807  */
selectAll()1808 public void selectAll () {
1809 	checkWidget ();
1810 	OS.SendMessage (handle, OS.EM_SETSEL, 0, -1);
1811 }
1812 
1813 @Override
sendKeyEvent(int type, int msg, long wParam, long lParam, Event event)1814 boolean sendKeyEvent (int type, int msg, long wParam, long lParam, Event event) {
1815 	if (!super.sendKeyEvent (type, msg, wParam, lParam, event)) {
1816 		return false;
1817 	}
1818 	if ((style & SWT.READ_ONLY) != 0) return true;
1819 	if (ignoreVerify) return true;
1820 	if (type != SWT.KeyDown) return true;
1821 	if (msg != OS.WM_CHAR && msg != OS.WM_KEYDOWN && msg != OS.WM_IME_CHAR) {
1822 		return true;
1823 	}
1824 	if (event.character == 0) return true;
1825 	if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return true;
1826 	char key = event.character;
1827 	int stateMask = event.stateMask;
1828 
1829 	/*
1830 	* Disable all magic keys that could modify the text
1831 	* and don't send events when Alt, Shift or Ctrl is
1832 	* pressed.
1833 	*/
1834 	switch (msg) {
1835 		case OS.WM_CHAR:
1836 			if (key != 0x08 && key != 0x7F && key != '\r' && key != '\t' && key != '\n') break;
1837 			// FALL THROUGH
1838 		case OS.WM_KEYDOWN:
1839 			if ((stateMask & (SWT.ALT | SWT.SHIFT | SWT.CONTROL)) != 0) return false;
1840 			break;
1841 	}
1842 
1843 	/*
1844 	* Feature in Windows.  If the left button is down in
1845 	* the text widget, it refuses the character.  The fix
1846 	* is to detect this case and avoid sending a verify
1847 	* event.
1848 	*/
1849 	if (OS.GetKeyState (OS.VK_LBUTTON) < 0) {
1850 		if (handle == OS.GetCapture()) return true;
1851 	}
1852 
1853 	/* Verify the character */
1854 	String oldText = "";
1855 	int [] start = new int [1], end = new int [1];
1856 	OS.SendMessage (handle, OS.EM_GETSEL, start, end);
1857 	switch (key) {
1858 		case 0x08:	/* Bs */
1859 			if (start [0] == end [0]) {
1860 				if (start [0] == 0) return true;
1861 				int lineStart = (int)OS.SendMessage (handle, OS.EM_LINEINDEX, -1, 0);
1862 				if (start [0] == lineStart) {
1863 					start [0] = start [0] - DELIMITER.length ();
1864 				} else {
1865 					start [0] = start [0] - 1;
1866 				}
1867 				start [0] = Math.max (start [0], 0);
1868 			}
1869 			break;
1870 		case 0x7F:	/* Del */
1871 			if (start [0] == end [0]) {
1872 				int length = OS.GetWindowTextLength (handle);
1873 				if (start [0] == length) return true;
1874 				int line = (int)OS.SendMessage (handle, OS.EM_LINEFROMCHAR, end [0], 0);
1875 				int lineStart = (int)OS.SendMessage (handle, OS.EM_LINEINDEX, line + 1, 0);
1876 				if (end [0] == lineStart - DELIMITER.length ()) {
1877 					end [0] = end [0] + DELIMITER.length ();
1878 				} else {
1879 					end [0] = end [0] + 1;
1880 				}
1881 				end [0] = Math.min (end [0], length);
1882 			}
1883 			break;
1884 		case '\r':	/* Return */
1885 			if ((style & SWT.SINGLE) != 0) return true;
1886 			oldText = DELIMITER;
1887 			break;
1888 		default:	/* Tab and other characters */
1889 			if (key != '\t' && key < 0x20) return true;
1890 			oldText = new String (new char [] {key});
1891 			break;
1892 	}
1893 	String newText = verifyText (oldText, start [0], end [0], event);
1894 	if (newText == null) return false;
1895 	if (newText == oldText) return true;
1896 	newText = Display.withCrLf (newText);
1897 	TCHAR buffer = new TCHAR (getCodePage (), newText, true);
1898 	OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]);
1899 	/*
1900 	* Feature in Windows.  When an edit control with ES_MULTILINE
1901 	* style that does not have the WS_VSCROLL style is full (i.e.
1902 	* there is no space at the end to draw any more characters),
1903 	* EM_REPLACESEL sends a WM_CHAR with a backspace character
1904 	* to remove any further text that is added.  This is an
1905 	* implementation detail of the edit control that is unexpected
1906 	* and can cause endless recursion when EM_REPLACESEL is sent
1907 	* from a WM_CHAR handler.  The fix is to ignore calling the
1908 	* handler from WM_CHAR.
1909 	*/
1910 	ignoreCharacter = true;
1911 	OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
1912 	ignoreCharacter = false;
1913 	return false;
1914 }
1915 
1916 @Override
setBackgroundImage(long hBitmap)1917 void setBackgroundImage (long hBitmap) {
1918 	int flags = OS.RDW_ERASE | OS.RDW_ALLCHILDREN | OS.RDW_INVALIDATE;
1919 	OS.RedrawWindow (handle, null, 0, flags);
1920 }
1921 
1922 @Override
setBackgroundPixel(int pixel)1923 void setBackgroundPixel (int pixel) {
1924 	enableDarkModeExplorerTheme();
1925 	int flags = OS.RDW_ERASE | OS.RDW_ALLCHILDREN | OS.RDW_INVALIDATE;
1926 	OS.RedrawWindow (handle, null, 0, flags);
1927 }
1928 
1929 @Override
setBoundsInPixels(int x, int y, int width, int height, int flags)1930 void setBoundsInPixels (int x, int y, int width, int height, int flags) {
1931 	/*
1932 	* Feature in Windows.  When the caret is moved,
1933 	* the text widget scrolls to show the new location.
1934 	* This means that the text widget may be scrolled
1935 	* to the right in order to show the caret when the
1936 	* widget is not large enough to show both the caret
1937 	* location and all the text.  Unfortunately, when
1938 	* the text widget is resized such that all the text
1939 	* and the caret could be visible, Windows does not
1940 	* scroll the widget back.  The fix is to resize the
1941 	* text widget, set the selection to the start of the
1942 	* text and then restore the selection.  This will
1943 	* cause the text widget compute the correct scroll
1944 	* position.
1945 	*/
1946 	if ((flags & OS.SWP_NOSIZE) == 0 && width != 0) {
1947 		RECT rect = new RECT ();
1948 		OS.GetWindowRect (handle, rect);
1949 		long margins = OS.SendMessage (handle, OS.EM_GETMARGINS, 0, 0);
1950 		int marginWidth = OS.LOWORD (margins) + OS.HIWORD (margins);
1951 		if (rect.right - rect.left <= marginWidth) {
1952 			int [] start = new int [1], end = new int [1];
1953 			OS.SendMessage (handle, OS.EM_GETSEL, start, end);
1954 			if (start [0] != 0 || end [0] != 0) {
1955 				OS.SetWindowPos (handle, 0, x, y, width, height, flags);
1956 				OS.SendMessage (handle, OS.EM_SETSEL, 0, 0);
1957 				OS.SendMessage (handle, OS.EM_SETSEL, start [0], end [0]);
1958 				return;
1959 			}
1960 		}
1961 	}
1962 	super.setBoundsInPixels (x, y, width, height, flags);
1963 
1964 	/*
1965 	* Bug in Windows. If the client area height is smaller than
1966 	* the font height, then the multi-line text widget does not
1967 	* update the formatting rectangle when resized. The fix is to
1968 	* detect this case and explicitly set the formatting rectangle.
1969 	*/
1970 	if ((flags & OS.SWP_NOSIZE) == 0) {
1971 		int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1972 		if ((bits & OS.ES_MULTILINE) != 0) {
1973 			long newFont, oldFont = 0;
1974 			long hDC = OS.GetDC (handle);
1975 			newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1976 			if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1977 			TEXTMETRIC tm = new TEXTMETRIC ();
1978 			OS.GetTextMetrics (hDC, tm);
1979 			if (newFont != 0) OS.SelectObject (hDC, oldFont);
1980 			OS.ReleaseDC (handle, hDC);
1981 			RECT rect = new RECT();
1982 			OS.GetClientRect (handle, rect);
1983 			if ((rect.bottom - rect.top) < tm.tmHeight) {
1984 				long margins = OS.SendMessage (handle, OS.EM_GETMARGINS, 0, 0);
1985 				rect.left += OS.LOWORD (margins);
1986 				rect.right -= OS.HIWORD (margins);
1987 				rect.top = 0;
1988 				rect.bottom = tm.tmHeight;
1989 				OS.SendMessage (handle, OS.EM_SETRECT, 0, rect);
1990 			}
1991 		}
1992 	}
1993 }
1994 
1995 @Override
setDefaultFont()1996 void setDefaultFont () {
1997 	super.setDefaultFont ();
1998 	setMargins ();
1999 }
2000 
2001 /**
2002  * Sets the double click enabled flag.
2003  * <p>
2004  * The double click flag enables or disables the
2005  * default action of the text widget when the user
2006  * double clicks.
2007  * </p><p>
2008  * Note: This operation is a hint and is not supported on
2009  * platforms that do not have this concept.
2010  * </p>
2011  *
2012  * @param doubleClick the new double click flag
2013  *
2014  * @exception SWTException <ul>
2015  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2016  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2017  * </ul>
2018  */
setDoubleClickEnabled(boolean doubleClick)2019 public void setDoubleClickEnabled (boolean doubleClick) {
2020 	checkWidget ();
2021 	this.doubleClick = doubleClick;
2022 }
2023 
2024 /**
2025  * Sets the echo character.
2026  * <p>
2027  * The echo character is the character that is
2028  * displayed when the user enters text or the
2029  * text is changed by the programmer. Setting
2030  * the echo character to '\0' clears the echo
2031  * character and redraws the original text.
2032  * If for any reason the echo character is invalid,
2033  * or if the platform does not allow modification
2034  * of the echo character, the default echo character
2035  * for the platform is used.
2036  * </p>
2037  *
2038  * @param echo the new echo character
2039  *
2040  * @exception SWTException <ul>
2041  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2042  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2043  * </ul>
2044  */
setEchoChar(char echo)2045 public void setEchoChar (char echo) {
2046 	checkWidget ();
2047 	if ((style & SWT.MULTI) != 0) return;
2048 	allowPasswordChar = true;
2049 	OS.SendMessage (handle, OS.EM_SETPASSWORDCHAR, echo, 0);
2050 	allowPasswordChar = false;
2051 	/*
2052 	* Bug in Windows.  When the password character is changed,
2053 	* Windows does not redraw to show the new password character.
2054 	* The fix is to force a redraw when the character is set.
2055 	*/
2056 	OS.InvalidateRect (handle, null, true);
2057 }
2058 
2059 /**
2060  * Sets the editable state.
2061  *
2062  * @param editable the new editable state
2063  *
2064  * @exception SWTException <ul>
2065  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2066  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2067  * </ul>
2068  */
setEditable(boolean editable)2069 public void setEditable (boolean editable) {
2070 	checkWidget ();
2071 	style &= ~SWT.READ_ONLY;
2072 	if (!editable) style |= SWT.READ_ONLY;
2073 	OS.SendMessage (handle, OS.EM_SETREADONLY, editable ? 0 : 1, 0);
2074 }
2075 
2076 @Override
setFont(Font font)2077 public void setFont (Font font) {
2078 	checkWidget ();
2079 	super.setFont (font);
2080 	setTabStops (tabs);
2081 	setMargins ();
2082 }
2083 
2084 @Override
setForegroundPixel(int pixel)2085 void setForegroundPixel (int pixel) {
2086 	enableDarkModeExplorerTheme();
2087 	super.setForegroundPixel(pixel);
2088 }
2089 
setMargins()2090 void setMargins () {
2091 	if ((style & SWT.SEARCH) != 0) {
2092 		boolean rtl = (style & SWT.RIGHT_TO_LEFT) != 0;
2093 		int fLeading = rtl ? OS.EC_RIGHTMARGIN : OS.EC_LEFTMARGIN;
2094 		int fTrailing = rtl ? OS.EC_LEFTMARGIN : OS.EC_RIGHTMARGIN;
2095 		int flags = 0;
2096 		if ((style & SWT.ICON_SEARCH) != 0) flags |= fLeading;
2097 		if ((style & SWT.ICON_CANCEL) != 0) flags |= fTrailing;
2098 		if (flags != 0) {
2099 			int iconWidth = OS.GetSystemMetrics (OS.SM_CXSMICON);
2100 			OS.SendMessage (handle, OS.EM_SETMARGINS, flags, OS.MAKELPARAM(iconWidth, iconWidth));
2101 		}
2102 	}
2103 }
2104 
2105 /**
2106  * Sets the widget message. The message text is displayed
2107  * as a hint for the user, indicating the purpose of the field.
2108  * <p>
2109  * Typically this is used in conjunction with <code>SWT.SEARCH</code>.
2110  * </p>
2111  *
2112  * @param message the new message
2113  *
2114  * @exception IllegalArgumentException <ul>
2115  *    <li>ERROR_NULL_ARGUMENT - if the message is null</li>
2116  * </ul>
2117  * @exception SWTException <ul>
2118  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2119  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2120  * </ul>
2121  *
2122  * @since 3.3
2123  */
setMessage(String message)2124 public void setMessage (String message) {
2125 	checkWidget ();
2126 	if (message == null) error (SWT.ERROR_NULL_ARGUMENT);
2127 	this.message = message;
2128 	int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2129 	if ((bits & OS.ES_MULTILINE) == 0) {
2130 		int length = message.length ();
2131 		char [] chars = new char [length + 1];
2132 		message.getChars(0, length, chars, 0);
2133 		OS.SendMessage (handle, OS.EM_SETCUEBANNER, 0, chars);
2134 	}
2135 }
2136 
2137 /**
2138  * Sets the orientation of the receiver, which must be one
2139  * of the constants <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
2140  * <p>
2141  * Note: This operation is a hint and is not supported on
2142  * platforms that do not have this concept.
2143  * </p>
2144  *
2145  * @param orientation new orientation style
2146  *
2147  * @exception SWTException <ul>
2148  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2149  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2150  * </ul>
2151  *
2152  * @since 2.1.2
2153  */
2154 @Override
setOrientation(int orientation)2155 public void setOrientation (int orientation) {
2156 	super.setOrientation (orientation);
2157 }
2158 
2159 /**
2160  * Sets the selection.
2161  * <p>
2162  * Indexing is zero based.  The range of
2163  * a selection is from 0..N where N is
2164  * the number of characters in the widget.
2165  * </p><p>
2166  * Text selections are specified in terms of
2167  * caret positions.  In a text widget that
2168  * contains N characters, there are N+1 caret
2169  * positions, ranging from 0..N.  This differs
2170  * from other functions that address character
2171  * position such as getText () that use the
2172  * regular array indexing rules.
2173  * </p>
2174  *
2175  * @param start new caret position
2176  *
2177  * @exception SWTException <ul>
2178  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2179  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2180  * </ul>
2181  */
setSelection(int start)2182 public void setSelection (int start) {
2183 	checkWidget ();
2184 	start = translateOffset (start);
2185 	OS.SendMessage (handle, OS.EM_SETSEL, start, start);
2186 	OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
2187 }
2188 
2189 /**
2190  * Sets the selection to the range specified
2191  * by the given start and end indices.
2192  * <p>
2193  * Indexing is zero based.  The range of
2194  * a selection is from 0..N where N is
2195  * the number of characters in the widget.
2196  * </p><p>
2197  * Text selections are specified in terms of
2198  * caret positions.  In a text widget that
2199  * contains N characters, there are N+1 caret
2200  * positions, ranging from 0..N.  This differs
2201  * from other functions that address character
2202  * position such as getText () that use the
2203  * usual array indexing rules.
2204  * </p>
2205  *
2206  * @param start the start of the range
2207  * @param end the end of the range
2208  *
2209  * @exception SWTException <ul>
2210  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2211  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2212  * </ul>
2213  */
setSelection(int start, int end)2214 public void setSelection (int start, int end) {
2215 	checkWidget ();
2216 	start = translateOffset (start);
2217 	end = translateOffset (end);
2218 	OS.SendMessage (handle, OS.EM_SETSEL, start, end);
2219 	OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
2220 }
2221 
2222 @Override
setRedraw(boolean redraw)2223 public void setRedraw (boolean redraw) {
2224 	checkWidget ();
2225 	super.setRedraw (redraw);
2226 	/*
2227 	* Feature in Windows.  When WM_SETREDRAW is used to turn
2228 	* redraw off, the edit control is not scrolled to show the
2229 	* i-beam.  The fix is to detect that the i-beam has moved
2230 	* while redraw is turned off and force it to be visible
2231 	* when redraw is restored.
2232 	*/
2233 	if (!getDrawing ()) return;
2234 	int [] start = new int [1], end = new int [1];
2235 	OS.SendMessage (handle, OS.EM_GETSEL, start, end);
2236 	if (!redraw) {
2237 		oldStart = start [0];  oldEnd = end [0];
2238 	} else {
2239 		if (oldStart == start [0] && oldEnd == end [0]) return;
2240 		OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
2241 	}
2242 }
2243 
2244 /**
2245  * Sets the selection to the range specified
2246  * by the given point, where the x coordinate
2247  * represents the start index and the y coordinate
2248  * represents the end index.
2249  * <p>
2250  * Indexing is zero based.  The range of
2251  * a selection is from 0..N where N is
2252  * the number of characters in the widget.
2253  * </p><p>
2254  * Text selections are specified in terms of
2255  * caret positions.  In a text widget that
2256  * contains N characters, there are N+1 caret
2257  * positions, ranging from 0..N.  This differs
2258  * from other functions that address character
2259  * position such as getText () that use the
2260  * usual array indexing rules.
2261  * </p>
2262  *
2263  * @param selection the point
2264  *
2265  * @exception IllegalArgumentException <ul>
2266  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
2267  * </ul>
2268  * @exception SWTException <ul>
2269  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2270  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2271  * </ul>
2272  */
setSelection(Point selection)2273 public void setSelection (Point selection) {
2274 	checkWidget ();
2275 	if (selection == null) error (SWT.ERROR_NULL_ARGUMENT);
2276 	setSelection (selection.x, selection.y);
2277 }
2278 
2279 /**
2280  * Sets the number of tabs.
2281  * <p>
2282  * Tab stop spacing is specified in terms of the
2283  * space (' ') character.  The width of a single
2284  * tab stop is the pixel width of the spaces.
2285  * </p>
2286  *
2287  * @param tabs the number of tabs
2288  *
2289  * @exception SWTException <ul>
2290  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2291  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2292  * </ul>
2293  */
setTabs(int tabs)2294 public void setTabs (int tabs) {
2295 	checkWidget ();
2296 	if (tabs < 0) return;
2297 	setTabStops (this.tabs = tabs);
2298 }
2299 
setTabStops(int tabs)2300 void setTabStops (int tabs) {
2301 	/*
2302 	* Feature in Windows.  Windows expects the tab spacing in
2303 	* dialog units so we must convert from space widths.  Due
2304 	* to round off error, the tab spacing may not be the exact
2305 	* number of space widths, depending on the font.
2306 	*/
2307 	int width = (getTabWidth (tabs) * 4) / OS.LOWORD (OS.GetDialogBaseUnits ());
2308 	OS.SendMessage (handle, OS.EM_SETTABSTOPS, 1, new int [] {width});
2309 }
2310 
2311 /**
2312  * Sets the contents of the receiver to the given string. If the receiver has style
2313  * SINGLE and the argument contains multiple lines of text, the result of this
2314  * operation is undefined and may vary from platform to platform.
2315  * <p>
2316  * Note: If control characters like '\n', '\t' etc. are used
2317  * in the string, then the behavior is platform dependent.
2318  * </p>
2319  * @param string the new text
2320  *
2321  * @exception IllegalArgumentException <ul>
2322  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
2323  * </ul>
2324  * @exception SWTException <ul>
2325  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2326  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2327  * </ul>
2328  */
setText(String string)2329 public void setText (String string) {
2330 	checkWidget ();
2331 	if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
2332 	string = Display.withCrLf (string);
2333 	if (hooks (SWT.Verify) || filters (SWT.Verify)) {
2334 		int length = OS.GetWindowTextLength (handle);
2335 		string = verifyText (string, 0, length, null);
2336 		if (string == null) return;
2337 	}
2338 	clearSegments (false);
2339 	int limit = (int)OS.SendMessage (handle, OS.EM_GETLIMITTEXT, 0, 0) & 0x7FFFFFFF;
2340 	if (string.length () > limit) string = string.substring (0, limit);
2341 	TCHAR buffer = new TCHAR (getCodePage (), string, true);
2342 	OS.SetWindowText (handle, buffer);
2343 	if ((state & HAS_AUTO_DIRECTION) != 0) {
2344 		super.updateTextDirection(AUTO_TEXT_DIRECTION);
2345 	}
2346 	applySegments ();
2347 	/*
2348 	* Bug in Windows.  When the widget is multi line
2349 	* text widget, it does not send a WM_COMMAND with
2350 	* control code EN_CHANGE from SetWindowText () to
2351 	* notify the application that the text has changed.
2352 	* The fix is to send the event.
2353 	*/
2354 	int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2355 	if ((bits & OS.ES_MULTILINE) != 0) {
2356 		sendEvent (SWT.Modify);
2357 		// widget could be disposed at this point
2358 	}
2359 }
2360 
2361 /**
2362  * Sets the contents of the receiver to the characters in the array. If the receiver
2363  * has style <code>SWT.SINGLE</code> and the argument contains multiple lines of text
2364  * then the result of this operation is undefined and may vary between platforms.
2365  * <p>
2366  * Note: Use this API to prevent the text from being written into a String
2367  * object whose lifecycle is outside of your control. This can help protect
2368  * the text, for example, when the widget is used as a password field.
2369  * However, the text can't be protected if an {@link SWT#Segments} or
2370  * {@link SWT#Verify} listener has been added to the widget.
2371  * </p>
2372  *
2373  * @param text a character array that contains the new text
2374  *
2375  * @exception IllegalArgumentException <ul>
2376  *    <li>ERROR_NULL_ARGUMENT - if the array is null</li>
2377  * </ul>
2378  * @exception SWTException <ul>
2379  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2380  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2381  * </ul>
2382  *
2383  * @see #getTextChars()
2384  *
2385  * @since 3.7
2386  */
setTextChars(char[] text)2387 public void setTextChars (char[] text) {
2388 	checkWidget ();
2389 	if (text == null) error (SWT.ERROR_NULL_ARGUMENT);
2390 	text = Display.withCrLf (text);
2391 	if (hooks (SWT.Verify) || filters (SWT.Verify)) {
2392 		int length = OS.GetWindowTextLength (handle);
2393 		String string = verifyText (new String (text), 0, length, null);
2394 		if (string == null) return;
2395 		text = new char [string.length()];
2396 		string.getChars (0, text.length, text, 0);
2397 	}
2398 	clearSegments (false);
2399 	int limit = (int)OS.SendMessage (handle, OS.EM_GETLIMITTEXT, 0, 0) & 0x7FFFFFFF;
2400 	if (text.length > limit) {
2401 		char [] temp = new char [limit];
2402 		System.arraycopy(text, 0, temp, 0, limit);
2403 		text = temp;
2404 	}
2405 	TCHAR buffer = new TCHAR (getCodePage (), text, true);
2406 	OS.SetWindowText (handle, buffer);
2407 	buffer.clear ();
2408 	if ((state & HAS_AUTO_DIRECTION) != 0) {
2409 		super.updateTextDirection (AUTO_TEXT_DIRECTION);
2410 	}
2411 	applySegments ();
2412 	/*
2413 	* Bug in Windows.  When the widget is multi line
2414 	* text widget, it does not send a WM_COMMAND with
2415 	* control code EN_CHANGE from SetWindowText () to
2416 	* notify the application that the text has changed.
2417 	* The fix is to send the event.
2418 	*/
2419 	int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2420 	if ((bits & OS.ES_MULTILINE) != 0) {
2421 		sendEvent (SWT.Modify);
2422 		// widget could be disposed at this point
2423 	}
2424 }
2425 
2426 /**
2427  * Sets the maximum number of characters that the receiver
2428  * is capable of holding to be the argument.
2429  * <p>
2430  * Instead of trying to set the text limit to zero, consider
2431  * creating a read-only text widget.
2432  * </p><p>
2433  * To reset this value to the default, use <code>setTextLimit(Text.LIMIT)</code>.
2434  * Specifying a limit value larger than <code>Text.LIMIT</code> sets the
2435  * receiver's limit to <code>Text.LIMIT</code>.
2436  * </p>
2437  *
2438  * @param limit new text limit
2439  *
2440  * @exception IllegalArgumentException <ul>
2441  *    <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
2442  * </ul>
2443  * @exception SWTException <ul>
2444  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2445  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2446  * </ul>
2447  *
2448  * @see #LIMIT
2449  */
setTextLimit(int limit)2450 public void setTextLimit (int limit) {
2451 	checkWidget ();
2452 	if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO);
2453 	if (segments != null && limit > 0) {
2454 		OS.SendMessage (handle, OS.EM_SETLIMITTEXT, limit + Math.min (segments.length, LIMIT - limit), 0);
2455 	} else {
2456 		OS.SendMessage (handle, OS.EM_SETLIMITTEXT, limit, 0);
2457 	}
2458 }
2459 
2460 /**
2461  * Sets the zero-relative index of the line which is currently
2462  * at the top of the receiver. This index can change when lines
2463  * are scrolled or new lines are added and removed.
2464  *
2465  * @param index the index of the top item
2466  *
2467  * @exception SWTException <ul>
2468  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2469  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2470  * </ul>
2471  */
setTopIndex(int index)2472 public void setTopIndex (int index) {
2473 	checkWidget ();
2474 	if ((style & SWT.SINGLE) != 0) return;
2475 	int count = (int)OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0);
2476 	index = Math.min (Math.max (index, 0), count - 1);
2477 	int topIndex = (int)OS.SendMessage (handle, OS.EM_GETFIRSTVISIBLELINE, 0, 0);
2478 	OS.SendMessage (handle, OS.EM_LINESCROLL, 0, index - topIndex);
2479 }
2480 
2481 /**
2482  * Shows the selection.
2483  * <p>
2484  * If the selection is already showing
2485  * in the receiver, this method simply returns.  Otherwise,
2486  * lines are scrolled until the selection is visible.
2487  * </p>
2488  *
2489  * @exception SWTException <ul>
2490  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2491  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2492  * </ul>
2493  */
showSelection()2494 public void showSelection () {
2495 	checkWidget ();
2496 	OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
2497 }
2498 
translateOffset(int offset)2499 int translateOffset (int offset) {
2500 	if (segments == null) return offset;
2501 	for (int i = 0, nSegments = segments.length; i < nSegments && offset - i >= segments [i]; i++) {
2502 		offset++;
2503 	}
2504 	return offset;
2505 }
2506 
untranslateOffset(int offset)2507 int untranslateOffset (int offset) {
2508 	if (segments == null) return offset;
2509 	for (int i = 0, nSegments = segments.length; i < nSegments && offset > segments [i]; i++) {
2510 		offset--;
2511 	}
2512 	return offset;
2513 }
2514 
2515 @Override
updateMenuLocation(Event event)2516 void updateMenuLocation (Event event) {
2517 	Point point = display.mapInPixels (this, null, getCaretLocationInPixels ());
2518 	event.setLocationInPixels(point.x, point.y + getLineHeightInPixels ());
2519 }
2520 
2521 @Override
updateOrientation()2522 void updateOrientation (){
2523 	int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
2524 	if ((style & SWT.RIGHT_TO_LEFT) != 0) {
2525 		bits |= OS.WS_EX_RTLREADING | OS.WS_EX_LEFTSCROLLBAR;
2526 	} else {
2527 		bits &= ~(OS.WS_EX_RTLREADING | OS.WS_EX_LEFTSCROLLBAR);
2528 	}
2529 	OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
2530 	fixAlignment ();
2531 }
2532 
2533 @Override
updateTextDirection(int textDirection)2534 boolean updateTextDirection(int textDirection) {
2535 	if (super.updateTextDirection(textDirection)) {
2536 		clearSegments (true);
2537 		applySegments ();
2538 		return true;
2539 	}
2540 	return false;
2541 }
2542 
verifyText(String string, int start, int end, Event keyEvent)2543 String verifyText (String string, int start, int end, Event keyEvent) {
2544 	if (ignoreVerify) return string;
2545 	Event event = new Event ();
2546 	event.text = string;
2547 	event.start = start;
2548 	event.end = end;
2549 	if (keyEvent != null) {
2550 		event.character = keyEvent.character;
2551 		event.keyCode = keyEvent.keyCode;
2552 		event.stateMask = keyEvent.stateMask;
2553 	}
2554 	event.start = untranslateOffset (event.start);
2555 	event.end = untranslateOffset (event.end);
2556 
2557 	/*
2558 	* It is possible (but unlikely), that application
2559 	* code could have disposed the widget in the verify
2560 	* event.  If this happens, answer null to cancel
2561 	* the operation.
2562 	*/
2563 	sendEvent (SWT.Verify, event);
2564 	if (!event.doit || isDisposed ()) return null;
2565 	return event.text;
2566 }
2567 
2568 @Override
widgetStyle()2569 int widgetStyle () {
2570 	int bits = super.widgetStyle () | OS.ES_AUTOHSCROLL;
2571 	/*
2572 	 * NOTE: ICON_CANCEL and ICON_SEARCH have the same value as H_SCROLL and
2573 	 * V_SCROLL. The meaning is determined by whether SWT.SEARCH is set.
2574 	 */
2575 	if ((style & SWT.SEARCH) != 0) {
2576 		bits &= ~OS.WS_HSCROLL;
2577 		bits &= ~OS.WS_VSCROLL;
2578 	}
2579 	if ((style & SWT.PASSWORD) != 0) bits |= OS.ES_PASSWORD;
2580 	if ((style & SWT.CENTER) != 0) bits |= OS.ES_CENTER;
2581 	if ((style & SWT.RIGHT) != 0) bits |= OS.ES_RIGHT;
2582 	if ((style & SWT.READ_ONLY) != 0) bits |= OS.ES_READONLY;
2583 	if ((style & SWT.SEARCH) != 0) bits |= OS.WS_CLIPCHILDREN;
2584 	if ((style & SWT.SINGLE) != 0) {
2585 		/*
2586 		* Feature in Windows.  When a text control is read-only,
2587 		* uses COLOR_3DFACE for the background .  If the text
2588 		* controls single-line and is within a tab folder or
2589 		* some other themed control, using WM_ERASEBKGND and
2590 		* WM_CTRCOLOR to draw the theme background results in
2591 		* pixel corruption.  The fix is to use an ES_MULTILINE
2592 		* text control instead.
2593 		* Refer Bug438901:- ES_MULTILINE doesn't apply for:
2594 		* SWT.PASSWORD | SWT.READ_ONLY style combination.
2595 		*/
2596 		if ((style & SWT.READ_ONLY) != 0) {
2597 			if ((style & (SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.PASSWORD)) == 0) {
2598 				if (OS.IsAppThemed ()) {
2599 					bits |= OS.ES_MULTILINE;
2600 				}
2601 			}
2602 		}
2603 		return bits;
2604 	}
2605 	bits |= OS.ES_MULTILINE | OS.ES_NOHIDESEL | OS.ES_AUTOVSCROLL;
2606 	if ((style & SWT.WRAP) != 0) bits &= ~(OS.WS_HSCROLL | OS.ES_AUTOHSCROLL);
2607 	return bits;
2608 }
2609 
2610 @Override
windowClass()2611 TCHAR windowClass () {
2612 	return EditClass;
2613 }
2614 
2615 @Override
windowProc()2616 long windowProc () {
2617 	return EditProc;
2618 }
2619 
2620 @Override
windowProc(long hwnd, int msg, long wParam, long lParam)2621 long windowProc (long hwnd, int msg, long wParam, long lParam) {
2622 	boolean processSegments = hooks (SWT.Segments) || filters (SWT.Segments), redraw = false, updateDirection = (state & HAS_AUTO_DIRECTION) != 0;
2623 	long code;
2624 	if (processSegments || updateDirection) {
2625 		switch (msg) {
2626 			case OS.EM_CANUNDO:
2627 				if (processSegments) return 0;
2628 				updateDirection = false;
2629 				break;
2630 			case OS.EM_UNDO:
2631 			case OS.WM_UNDO:
2632 				if (processSegments) return 0;
2633 				break;
2634 			case OS.WM_KEYDOWN:
2635 				if (wParam != OS.VK_DELETE) {
2636 					processSegments = updateDirection = false;
2637 				}
2638 				break;
2639 			case OS.WM_COPY:
2640 				processSegments = segments != null;
2641 				updateDirection = false;
2642 				break;
2643 			case OS.WM_CHAR:
2644 				if (ignoreCharacter || OS.GetKeyState (OS.VK_CONTROL) < 0 || OS.GetKeyState (OS.VK_MENU) < 0) {
2645 					processSegments = updateDirection = false;
2646 				}
2647 				break;
2648 			case OS.WM_PASTE:
2649 			case OS.WM_CUT:
2650 			case OS.WM_CLEAR:
2651 				break;
2652 			default:
2653 				processSegments = updateDirection = false;
2654 		}
2655 	}
2656 	if (processSegments) {
2657 		if (getDrawing () && OS.IsWindowVisible (handle)) {
2658 			redraw = true;
2659 			OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
2660 		}
2661 		clearSegments (true);
2662 	}
2663 	if (msg == OS.EM_UNDO) {
2664 		int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2665 		if ((bits & OS.ES_MULTILINE) == 0) {
2666 			LRESULT result = wmClipboard (OS.EM_UNDO, wParam, lParam);
2667 			if (result != null) return result.value;
2668 			return callWindowProc (hwnd, OS.EM_UNDO, wParam, lParam);
2669 		}
2670 	}
2671 	if (msg == OS.EM_SETPASSWORDCHAR) {
2672 		if (!allowPasswordChar) {
2673 			return 1;
2674 		}
2675 	}
2676 	if (msg == Display.SWT_RESTORECARET) {
2677 		callWindowProc (hwnd, OS.WM_KILLFOCUS, 0, 0);
2678 		callWindowProc (hwnd, OS.WM_SETFOCUS, 0, 0);
2679 		return 1;
2680 	}
2681 	code = super.windowProc (hwnd, msg, wParam, lParam);
2682 	if (updateDirection) {
2683 		super.updateTextDirection (AUTO_TEXT_DIRECTION);
2684 	}
2685 	if (processSegments) {
2686 		applySegments ();
2687 		if (redraw) {
2688 			OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
2689 			OS.InvalidateRect (handle, null, true);
2690 		}
2691 		OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
2692 	}
2693 	return code;
2694 }
2695 
2696 @Override
WM_CHAR(long wParam, long lParam)2697 LRESULT WM_CHAR (long wParam, long lParam) {
2698 	if (ignoreCharacter) return null;
2699 	LRESULT result = super.WM_CHAR (wParam, lParam);
2700 	if (result != null) return result;
2701 
2702 	/*
2703 	* Bug in Windows.  When the user types CTRL and BS
2704 	* in an edit control, a DEL character is generated.
2705 	* Rather than deleting the text, the DEL character
2706 	* is inserted into the control.  The fix is to detect
2707 	* this case and not call the window proc.
2708 	*/
2709 	switch ((int)wParam) {
2710 		case SWT.DEL:
2711 			if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
2712 				if ((style & SWT.READ_ONLY) != 0 || (style & SWT.PASSWORD) != 0) return LRESULT.ZERO;
2713 				Point selection = getSelection ();
2714 				int x = selection.x;
2715 				int y = selection.y;
2716 				if (x == y) {
2717 					String actText = getText (0, x - 1);
2718 					java.util.regex.Matcher m = CTRL_BS_PATTERN.matcher (actText);
2719 					if (m.find ()) {
2720 						x = m.start ();
2721 						y = m.end ();
2722 						OS.SendMessage (handle, OS.EM_SETSEL, x, y);
2723 					}
2724 				}
2725 				if (x < y) {
2726 					/*
2727 					* Instead of setting the new text directly we send the replace selection event to
2728 					* guarantee that the action is pushed to the undo buffer.
2729 					*/
2730 					OS.SendMessage (handle, OS.EM_REPLACESEL, 1, 0);
2731 				}
2732 				return LRESULT.ZERO;
2733 			}
2734 	}
2735 
2736 	/*
2737 	* Feature in Windows.  For some reason, when the
2738 	* widget is a single line text widget, when the
2739 	* user presses tab, return or escape, Windows beeps.
2740 	* The fix is to look for these keys and not call
2741 	* the window proc.
2742 	*/
2743 	if ((style & SWT.SINGLE) != 0) {
2744 		switch ((int)wParam) {
2745 			case SWT.CR:
2746 				sendSelectionEvent (SWT.DefaultSelection);
2747 				// FALL THROUGH
2748 			case SWT.TAB:
2749 			case SWT.ESC: return LRESULT.ZERO;
2750 		}
2751 	}
2752 	return result;
2753 }
2754 
2755 @Override
WM_CLEAR(long wParam, long lParam)2756 LRESULT WM_CLEAR (long wParam, long lParam) {
2757 	LRESULT result = super.WM_CLEAR (wParam, lParam);
2758 	if (result != null) return result;
2759 	return wmClipboard (OS.WM_CLEAR, wParam, lParam);
2760 }
2761 
2762 @Override
WM_CUT(long wParam, long lParam)2763 LRESULT WM_CUT (long wParam, long lParam) {
2764 	LRESULT result = super.WM_CUT (wParam, lParam);
2765 	if (result != null) return result;
2766 	return wmClipboard (OS.WM_CUT, wParam, lParam);
2767 }
2768 
2769 @Override
WM_DRAWITEM(long wParam, long lParam)2770 LRESULT WM_DRAWITEM (long wParam, long lParam) {
2771 	DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
2772 	OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
2773 	RECT rect = new RECT ();
2774 	OS.SetRect (rect, struct.left, struct.top, struct.right, struct.bottom);
2775 	POINT pt = new POINT ();
2776 	OS.MapWindowPoints (struct.hwndItem, handle, pt, 1);
2777 	drawBackground (struct.hDC, rect, -1, pt.x, pt.y);
2778 	if (struct.CtlID == SWT.ICON_CANCEL && struct.hwndItem == hwndActiveIcon && OS.IsAppThemed()) {
2779 		int state = OS.GetKeyState (OS.VK_LBUTTON) < 0 ? OS.PBS_PRESSED : OS.PBS_HOT;
2780 		OS.DrawThemeBackground (display.hButtonTheme (), struct.hDC, OS.BP_PUSHBUTTON, state, rect, null);
2781 	}
2782 	long hIcon = (struct.CtlID == SWT.ICON_SEARCH) ? display.hIconSearch : display.hIconCancel;
2783 	int y = (rect.bottom - rect.right) / 2;
2784 	OS.DrawIconEx (struct.hDC, 0, y, hIcon, 0, 0, 0, 0, OS.DI_NORMAL);
2785 	return LRESULT.ONE;
2786 }
2787 
2788 @Override
2789 LRESULT WM_ERASEBKGND (long wParam, long lParam) {
2790 	LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
2791 	if ((style & SWT.READ_ONLY) != 0) {
2792 		if ((style & (SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL)) == 0) {
2793 			int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2794 			if ((bits & OS.ES_MULTILINE) != 0) {
2795 				Control control = findBackgroundControl ();
2796 				if (control == null && background == -1) {
2797 					if ((state & THEME_BACKGROUND) != 0) {
2798 						if (OS.IsAppThemed ()) {
2799 							control = findThemeControl ();
2800 							if (control != null) {
2801 								RECT rect = new RECT ();
2802 								OS.GetClientRect (handle, rect);
2803 								fillThemeBackground (wParam, control, rect);
2804 								return LRESULT.ONE;
2805 							}
2806 						}
2807 					}
2808 				}
2809 			}
2810 		}
2811 	}
2812 	return result;
2813 }
2814 
2815 @Override
2816 LRESULT WM_GETDLGCODE (long wParam, long lParam) {
2817 	LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
2818 	if (result != null) return result;
2819 
2820 	/*
2821 	* Feature in Windows.  Despite the fact that the
2822 	* edit control is read only, it still returns a
2823 	* dialog code indicating that it wants all keys.
2824 	* The fix is to detect this case and clear the bits.
2825 	*
2826 	* NOTE: A read only edit control processes arrow keys
2827 	* so DLGC_WANTARROWS should not be cleared.
2828 	*/
2829 	if ((style & SWT.READ_ONLY) != 0) {
2830 		long code = callWindowProc (handle, OS.WM_GETDLGCODE, wParam, lParam);
2831 		code &= ~(OS.DLGC_WANTALLKEYS | OS.DLGC_WANTTAB);
2832 		return new LRESULT (code);
2833 	}
2834 	return null;
2835 }
2836 
2837 @Override
2838 LRESULT WM_GETOBJECT (long wParam, long lParam) {
2839 	/*
2840 	* Ensure that there is an accessible object created for this
2841 	* control because support for search text accessibility is
2842 	* implemented in the accessibility package.
2843 	*/
2844 	if ((style & SWT.SEARCH) != 0) {
2845 		if (accessible == null) accessible = new_Accessible (this);
2846 	}
2847 	return super.WM_GETOBJECT (wParam, lParam);
2848 }
2849 
2850 @Override
2851 LRESULT WM_IME_CHAR (long wParam, long lParam) {
2852 
2853 	/* Process a DBCS character */
2854 	Display display = this.display;
2855 	display.lastKey = 0;
2856 	display.lastAscii = (int)wParam;
2857 	display.lastVirtual = display.lastNull = display.lastDead = false;
2858 	if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) {
2859 		return LRESULT.ZERO;
2860 	}
2861 
2862 	/*
2863 	* Feature in Windows.  The Windows text widget uses
2864 	* two 2 WM_CHAR's to process a DBCS key instead of
2865 	* using WM_IME_CHAR.  The fix is to allow the text
2866 	* widget to get the WM_CHAR's but ignore sending
2867 	* them to the application.
2868 	*/
2869 	ignoreCharacter = true;
2870 	long result = callWindowProc (handle, OS.WM_IME_CHAR, wParam, lParam);
2871 	MSG msg = new MSG ();
2872 	int flags = OS.PM_REMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
2873 	while (OS.PeekMessage (msg, handle, OS.WM_CHAR, OS.WM_CHAR, flags)) {
2874 		OS.TranslateMessage (msg);
2875 		OS.DispatchMessage (msg);
2876 	}
2877 	ignoreCharacter = false;
2878 
2879 	sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
2880 	// widget could be disposed at this point
2881 	display.lastKey = display.lastAscii = 0;
2882 	return new LRESULT (result);
2883 }
2884 
2885 @Override
2886 LRESULT WM_LBUTTONDBLCLK (long wParam, long lParam) {
2887 	/*
2888 	* Prevent Windows from processing WM_LBUTTONDBLCLK
2889 	* when double clicking behavior is disabled by not
2890 	* calling the window proc.
2891 	*/
2892 	LRESULT result = null;
2893 	sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam);
2894 	if (!sendMouseEvent (SWT.MouseDoubleClick, 1, handle, OS.WM_LBUTTONDBLCLK, wParam, lParam)) {
2895 		result = LRESULT.ZERO;
2896 	}
2897 	if (!display.captureChanged && !isDisposed ()) {
2898 		if (OS.GetCapture () != handle) OS.SetCapture (handle);
2899 	}
2900 	if (!doubleClick) return LRESULT.ZERO;
2901 
2902 	/*
2903 	* Bug in Windows.  When the last line of text in the
2904 	* widget is double clicked and the line is empty, Windows
2905 	* hides the i-beam then moves it to the first line in
2906 	* the widget but does not scroll to show the user.
2907 	* If the user types without clicking the mouse, invalid
2908 	* characters are displayed at the end of each line of
2909 	* text in the widget.  The fix is to detect this case
2910 	* and avoid calling the window proc.
2911 	*/
2912 	int [] start = new int [1], end = new int [1];
2913 	OS.SendMessage (handle, OS.EM_GETSEL, start, end);
2914 	if (start [0] == end [0]) {
2915 		int length = OS.GetWindowTextLength (handle);
2916 		if (length == start [0]) {
2917 			int code = (int)OS.SendMessage (handle, OS.EM_LINELENGTH, length, 0);
2918 			if (code == 0) return LRESULT.ZERO;
2919 		}
2920 	}
2921 	return result;
2922 }
2923 
2924 @Override
2925 LRESULT WM_PASTE (long wParam, long lParam) {
2926 	LRESULT result = super.WM_PASTE (wParam, lParam);
2927 	if (result != null) return result;
2928 	return wmClipboard (OS.WM_PASTE, wParam, lParam);
2929 }
2930 
2931 @Override
2932 LRESULT WM_SETCURSOR (long wParam, long lParam) {
2933 	LRESULT result = super.WM_SETCURSOR(wParam, lParam);
2934 	if (result != null) return result;
2935 	if ((style & SWT.SEARCH) != 0) {
2936 		int hitTest = (short) OS.LOWORD (lParam);
2937 		if (hitTest == OS.HTCLIENT) {
2938 			POINT pt = new POINT ();
2939 			OS.GetCursorPos (pt);
2940 			OS.ScreenToClient (handle, pt);
2941 			long hwndIcon = OS.ChildWindowFromPointEx (handle, pt, OS.CWP_SKIPINVISIBLE);
2942 			if (hwndIcon != handle) {
2943 				OS.SetCursor (OS.LoadCursor (0, OS.IDC_ARROW));
2944 				return LRESULT.ONE;
2945 			}
2946 		}
2947 	}
2948 	return null;
2949 }
2950 
2951 @Override
2952 LRESULT WM_SIZE(long wParam, long lParam) {
2953 	LRESULT result = super.WM_SIZE (wParam, lParam);
2954 	if (isDisposed ()) return result;
2955 	if ((style & SWT.SEARCH) != 0) {
2956 		/* NOTE: EDIT controls don't support mirrored layout. */
2957 		boolean rtl = (style & SWT.RIGHT_TO_LEFT) != 0;
2958 		long hwndLeading = OS.GetDlgItem (handle, rtl ? SWT.ICON_CANCEL : SWT.ICON_SEARCH);
2959 		long hwndTrailing = OS.GetDlgItem (handle, rtl ? SWT.ICON_SEARCH : SWT.ICON_CANCEL);
2960 		int width = OS.LOWORD (lParam);
2961 		int height = OS.HIWORD (lParam);
2962 		int iconWidth = OS.GetSystemMetrics (OS.SM_CXSMICON);
2963 		int flags = OS.SWP_NOZORDER | OS.SWP_NOACTIVATE | OS.SWP_NOCOPYBITS;
2964 		if (hwndLeading != 0) OS.SetWindowPos (hwndLeading, 0, 0, 0, iconWidth, height, flags);
2965 		if (hwndTrailing != 0) OS.SetWindowPos (hwndTrailing, 0, width - iconWidth, 0, iconWidth, height, flags);
2966 	}
2967 	return result;
2968 }
2969 
2970 @Override
2971 LRESULT WM_UNDO (long wParam, long lParam) {
2972 	LRESULT result = super.WM_UNDO (wParam, lParam);
2973 	if (result != null) return result;
2974 	return wmClipboard (OS.WM_UNDO, wParam, lParam);
2975 }
2976 
2977 LRESULT wmClipboard (int msg, long wParam, long lParam) {
2978 	if ((style & SWT.READ_ONLY) != 0) return null;
2979 	if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return null;
2980 	boolean call = false;
2981 	int [] start = new int [1], end = new int [1];
2982 	String newText = null;
2983 	switch (msg) {
2984 		case OS.WM_CLEAR:
2985 		case OS.WM_CUT:
2986 			OS.SendMessage (handle, OS.EM_GETSEL, start, end);
2987 			if (start [0] != end [0]) {
2988 				newText = "";
2989 				call = true;
2990 			}
2991 			break;
2992 		case OS.WM_PASTE:
2993 			OS.SendMessage (handle, OS.EM_GETSEL, start, end);
2994 			newText = getClipboardText ();
2995 			break;
2996 		case OS.EM_UNDO:
2997 		case OS.WM_UNDO:
2998 			if (OS.SendMessage (handle, OS.EM_CANUNDO, 0, 0) != 0) {
2999 				ignoreModify = ignoreCharacter = true;
3000 				callWindowProc (handle, msg, wParam, lParam);
3001 				int length = OS.GetWindowTextLength (handle);
3002 				int [] newStart = new int [1], newEnd = new int [1];
3003 				OS.SendMessage (handle, OS.EM_GETSEL, newStart, newEnd);
3004 				if (length != 0 && newStart [0] != newEnd [0]) {
3005 					char [] buffer = new char [length + 1];
3006 					OS.GetWindowText (handle, buffer, length + 1);
3007 					newText = new String (buffer, newStart [0], newEnd [0] - newStart [0]);
3008 				} else {
3009 					newText = "";
3010 				}
3011 				callWindowProc (handle, msg, wParam, lParam);
3012 				OS.SendMessage (handle, OS.EM_GETSEL, start, end);
3013 				ignoreModify = ignoreCharacter = false;
3014 			}
3015 			break;
3016 	}
3017 	if (newText != null) {
3018 		String oldText = newText;
3019 		newText = verifyText (newText, start [0], end [0], null);
3020 		if (newText == null) return LRESULT.ZERO;
3021 		if (!newText.equals (oldText)) {
3022 			if (call) {
3023 				callWindowProc (handle, msg, wParam, lParam);
3024 			}
3025 			newText = Display.withCrLf (newText);
3026 			TCHAR buffer = new TCHAR (getCodePage (), newText, true);
3027 			/*
3028 			* Feature in Windows.  When an edit control with ES_MULTILINE
3029 			* style that does not have the WS_VSCROLL style is full (i.e.
3030 			* there is no space at the end to draw any more characters),
3031 			* EM_REPLACESEL sends a WM_CHAR with a backspace character
3032 			* to remove any further text that is added.  This is an
3033 			* implementation detail of the edit control that is unexpected
3034 			* and can cause endless recursion when EM_REPLACESEL is sent
3035 			* from a WM_CHAR handler.  The fix is to ignore calling the
3036 			* handler from WM_CHAR.
3037 			*/
3038 			ignoreCharacter = true;
3039 			OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
3040 			ignoreCharacter = false;
3041 			return LRESULT.ZERO;
3042 		}
3043 	}
3044 	if (msg == OS.WM_UNDO) {
3045 		ignoreVerify = ignoreCharacter = true;
3046 		callWindowProc (handle, OS.WM_UNDO, wParam, lParam);
3047 		ignoreVerify = ignoreCharacter = false;
3048 		return LRESULT.ONE;
3049 	}
3050 	return null;
3051 }
3052 
3053 @Override
3054 LRESULT wmColorChild (long wParam, long lParam) {
3055 	if ((style & SWT.READ_ONLY) != 0) {
3056 		if ((style & (SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL)) == 0) {
3057 			int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
3058 			if ((bits & OS.ES_MULTILINE) != 0) {
3059 				Control control = findBackgroundControl ();
3060 				if (control == null && background == -1) {
3061 					if ((state & THEME_BACKGROUND) != 0) {
3062 						if (OS.IsAppThemed ()) {
3063 							control = findThemeControl ();
3064 							if (control != null) {
3065 								OS.SetTextColor (wParam, getForegroundPixel ());
3066 								OS.SetBkColor (wParam, getBackgroundPixel ());
3067 								OS.SetBkMode (wParam, OS.TRANSPARENT);
3068 								return new LRESULT (OS.GetStockObject (OS.NULL_BRUSH));
3069 							}
3070 						}
3071 					}
3072 				}
3073 			}
3074 		}
3075 	}
3076 	return super.wmColorChild (wParam, lParam);
3077 }
3078 
3079 @Override
3080 LRESULT wmCommandChild (long wParam, long lParam) {
3081 	int code = OS.HIWORD (wParam);
3082 	switch (code) {
3083 		case OS.EN_CHANGE:
3084 			if (findImageControl () != null) {
3085 				OS.InvalidateRect (handle, null, true);
3086 			}
3087 			if ((style & SWT.SEARCH) != 0) {
3088 				boolean showCancel = OS.GetWindowTextLength (handle) != 0;
3089 				long hwndCancel = OS.GetDlgItem (handle, SWT.ICON_CANCEL);
3090 				if (hwndCancel != 0) OS.ShowWindow (hwndCancel, showCancel ? OS.SW_SHOW : OS.SW_HIDE);
3091 			}
3092 			if (ignoreModify) break;
3093 			/*
3094 			* It is possible (but unlikely), that application
3095 			* code could have disposed the widget in the modify
3096 			* event.  If this happens, end the processing of the
3097 			* Windows message by returning zero as the result of
3098 			* the window proc.
3099 			*/
3100 			sendEvent (SWT.Modify);
3101 			if (isDisposed ()) return LRESULT.ZERO;
3102 			break;
3103 		case OS.EN_ALIGN_LTR_EC:
3104 		case OS.EN_ALIGN_RTL_EC:
3105 			/*
3106 			 * Ctrl + Shift to set explicit LTR or RTL text direction was
3107 			 * pressed, so auto direction should no longer be effective.
3108 			 */
3109 			state &= ~HAS_AUTO_DIRECTION;
3110 			int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
3111 			if ((bits & OS.WS_EX_RTLREADING) != 0) {
3112 				style &= ~SWT.LEFT_TO_RIGHT;
3113 				style |= SWT.RIGHT_TO_LEFT;
3114 			} else {
3115 				style &= ~SWT.RIGHT_TO_LEFT;
3116 				style |= SWT.LEFT_TO_RIGHT;
3117 			}
3118 			Event event = new Event();
3119 			event.doit = true;
3120 			sendEvent(SWT.OrientationChange, event);
3121 			if (!event.doit) {
3122 				if (code == OS.EN_ALIGN_LTR_EC) {
3123 					bits |= (OS.WS_EX_RTLREADING | OS.WS_EX_LEFTSCROLLBAR);
3124 					style &= ~SWT.LEFT_TO_RIGHT;
3125 					style |= SWT.RIGHT_TO_LEFT;
3126 				} else {
3127 					bits &= ~(OS.WS_EX_RTLREADING | OS.WS_EX_LEFTSCROLLBAR);
3128 					style &= ~SWT.RIGHT_TO_LEFT;
3129 					style |= SWT.LEFT_TO_RIGHT;
3130 				}
3131 				OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
3132 			} else {
3133 				clearSegments (true);
3134 				applySegments ();
3135 			}
3136 			fixAlignment();
3137 			break;
3138 	}
3139 	return super.wmCommandChild (wParam, lParam);
3140 }
3141 
3142 @Override
3143 LRESULT wmKeyDown (long hwnd, long wParam, long lParam) {
3144 	LRESULT result = super.wmKeyDown (hwnd, wParam, lParam);
3145 	if (result != null) return result;
3146 
3147 	if (segments != null) {
3148 		switch ((int)wParam) {
3149 		case OS.VK_LEFT:
3150 		case OS.VK_UP:
3151 		case OS.VK_RIGHT:
3152 		case OS.VK_DOWN:
3153 			long code = 0;
3154 			int [] start = new int [1], end = new int [1], newStart = new int [1], newEnd = new int [1];
3155 			OS.SendMessage (handle, OS.EM_GETSEL, start, end);
3156 			while (true) {
3157 				code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam);
3158 				OS.SendMessage (handle, OS.EM_GETSEL, newStart, newEnd);
3159 				if (newStart [0] != start [0]) {
3160 					if (untranslateOffset (newStart [0]) != untranslateOffset (start [0])) break;
3161 				} else if (newEnd [0] != end [0]) {
3162 					if (untranslateOffset (newEnd [0]) != untranslateOffset (end [0]))  break;
3163 				} else {
3164 					break;
3165 				}
3166 				start [0] = newStart [0];
3167 				end [0] = newEnd [0];
3168 			}
3169 			result = code == 0 ? LRESULT.ZERO : new LRESULT (code);
3170 		}
3171 	}
3172 	return result;
3173 }
3174 
3175 }
3176