[2/3] user32: Reorder some functions to avoid forward declarations in edit.c.

Francois Gouget fgouget at free.fr
Sat Feb 7 09:05:33 CST 2009


---
 dlls/user32/edit.c | 4078 +++++++++++++++++++++++++---------------------------
 1 files changed, 1998 insertions(+), 2080 deletions(-)

diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c
index d37cec8..636b957 100644
--- a/dlls/user32/edit.c
+++ b/dlls/user32/edit.c
@@ -173,107 +173,6 @@ typedef struct
 		     (LPARAM)(es->hwndSelf)); \
 	} while(0)
 
-/*********************************************************************
- *
- *	Declarations
- *
- */
-
-/*
- *	Helper functions only valid for one type of control
- */
-static LPWSTR	EDIT_GetPasswordPointer_SL(EDITSTATE *es);
-/*
- *	Helper functions valid for both single line _and_ multi line controls
- */
-static INT	EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action);
-static void	EDIT_LockBuffer(EDITSTATE *es);
-static INT	EDIT_PaintText(EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev);
-static void	EDIT_SetRectNP(EDITSTATE *es, const RECT *lprc);
-static void	EDIT_UnlockBuffer(EDITSTATE *es, BOOL force);
-static void	EDIT_UpdateScrollInfo(EDITSTATE *es);
-static INT      EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action);
-/*
- *	EM_XXX message handlers
- */
-static LRESULT	EDIT_EM_CharFromPos(EDITSTATE *es, INT x, INT y);
-static BOOL	EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol);
-static HLOCAL	EDIT_EM_GetHandle(EDITSTATE *es);
-static HLOCAL16	EDIT_EM_GetHandle16(EDITSTATE *es);
-static INT	EDIT_EM_GetLine(EDITSTATE *es, INT line, LPWSTR dst, BOOL unicode);
-static LRESULT	EDIT_EM_GetSel(const EDITSTATE *es, PUINT start, PUINT end);
-static LRESULT	EDIT_EM_GetThumb(EDITSTATE *es);
-static INT	EDIT_EM_LineFromChar(EDITSTATE *es, INT index);
-static INT	EDIT_EM_LineIndex(const EDITSTATE *es, INT line);
-static INT	EDIT_EM_LineLength(EDITSTATE *es, INT index);
-static BOOL	EDIT_EM_LineScroll(EDITSTATE *es, INT dx, INT dy);
-static BOOL	EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy);
-static LRESULT	EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap);
-static void	EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update, BOOL honor_limit);
-static LRESULT	EDIT_EM_Scroll(EDITSTATE *es, INT action);
-static void	EDIT_EM_ScrollCaret(EDITSTATE *es);
-static void	EDIT_EM_SetHandle(EDITSTATE *es, HLOCAL hloc);
-static void	EDIT_EM_SetHandle16(EDITSTATE *es, HLOCAL16 hloc);
-static void	EDIT_EM_SetLimitText(EDITSTATE *es, UINT limit);
-static void	EDIT_EM_SetMargins(EDITSTATE *es, INT action, WORD left, WORD right, BOOL repaint);
-static void	EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c);
-static void	EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
-static BOOL	EDIT_EM_SetTabStops(EDITSTATE *es, INT count, const INT *tabs);
-static BOOL	EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, const INT16 *tabs);
-static void	EDIT_EM_SetWordBreakProc(EDITSTATE *es, void *wbp);
-static void	EDIT_EM_SetWordBreakProc16(EDITSTATE *es, EDITWORDBREAKPROC16 wbp);
-static BOOL	EDIT_EM_Undo(EDITSTATE *es);
-/*
- *	WM_XXX message handlers
- */
-static LRESULT	EDIT_WM_Char(EDITSTATE *es, WCHAR c);
-static void	EDIT_WM_Command(EDITSTATE *es, INT code, INT id, HWND conrtol);
-static void	EDIT_WM_ContextMenu(EDITSTATE *es, INT x, INT y);
-static void	EDIT_WM_Copy(EDITSTATE *es);
-static LRESULT	EDIT_WM_Create(EDITSTATE *es, LPCWSTR name);
-static LRESULT	EDIT_WM_Destroy(EDITSTATE *es);
-static INT	EDIT_WM_GetText(const EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode);
-static LRESULT	EDIT_WM_HScroll(EDITSTATE *es, INT action, INT pos);
-static LRESULT	EDIT_WM_KeyDown(EDITSTATE *es, INT key);
-static LRESULT	EDIT_WM_KillFocus(EDITSTATE *es);
-static LRESULT	EDIT_WM_LButtonDblClk(EDITSTATE *es);
-static LRESULT	EDIT_WM_LButtonDown(EDITSTATE *es, DWORD keys, INT x, INT y);
-static LRESULT	EDIT_WM_LButtonUp(EDITSTATE *es);
-static LRESULT	EDIT_WM_MButtonDown(EDITSTATE *es);
-static LRESULT	EDIT_WM_MouseMove(EDITSTATE *es, INT x, INT y);
-static LRESULT	EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode);
-static void	EDIT_WM_Paint(EDITSTATE *es, HDC hdc);
-static void	EDIT_WM_Paste(EDITSTATE *es);
-static void	EDIT_WM_SetFocus(EDITSTATE *es);
-static void	EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw);
-static void	EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode);
-static void	EDIT_WM_Size(EDITSTATE *es, UINT action, INT width, INT height);
-static LRESULT  EDIT_WM_StyleChanged(EDITSTATE *es, WPARAM which, const STYLESTRUCT *style);
-static LRESULT	EDIT_WM_SysKeyDown(EDITSTATE *es, INT key, DWORD key_data);
-static void	EDIT_WM_Timer(EDITSTATE *es);
-static LRESULT	EDIT_WM_VScroll(EDITSTATE *es, INT action, INT pos);
-static void	EDIT_UpdateText(EDITSTATE *es, const RECT *rc, BOOL bErase);
-static void	EDIT_UpdateTextRegion(EDITSTATE *es, HRGN hrgn, BOOL bErase);
-static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es);
-
-LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-
-/*********************************************************************
- * edit class descriptor
- */
-static const WCHAR editW[] = {'E','d','i','t',0};
-const struct builtin_class_descr EDIT_builtin_class =
-{
-    editW,                /* name */
-    CS_DBLCLKS | CS_PARENTDC,   /* style */
-    EditWndProcA,         /* procA */
-    EditWndProcW,         /* procW */
-    sizeof(EDITSTATE *),  /* extra */
-    IDC_IBEAM,            /* cursor */
-    0                     /* brush */
-};
-
 
 /*********************************************************************
  *
@@ -298,35 +197,6 @@ static inline void EDIT_EM_EmptyUndoBuffer(EDITSTATE *es)
 }
 
 
-/*********************************************************************
- *
- *	WM_CLEAR
- *
- */
-static inline void EDIT_WM_Clear(EDITSTATE *es)
-{
-	static const WCHAR empty_stringW[] = {0};
-
-	/* Protect read-only edit control from modification */
-	if(es->style & ES_READONLY)
-	    return;
-
-	EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
-}
-
-
-/*********************************************************************
- *
- *	WM_CUT
- *
- */
-static inline void EDIT_WM_Cut(EDITSTATE *es)
-{
-	EDIT_WM_Copy(es);
-	EDIT_WM_Clear(es);
-}
-
-
 /**********************************************************************
  *         get_app_version
  *
@@ -362,18 +232,6 @@ static DWORD get_app_version(void)
     return version;
 }
 
-static inline UINT get_text_length(EDITSTATE *es)
-{
-    if(es->text_length == (UINT)-1)
-        es->text_length = strlenW(es->text);
-    return es->text_length;
-}
-
-static inline void text_buffer_changed(EDITSTATE *es)
-{
-    es->text_length = (UINT)-1;
-}
-
 static HBRUSH EDIT_NotifyCtlColor(EDITSTATE *es, HDC hdc)
 {
         HBRUSH hbrush;
@@ -391,693 +249,141 @@ static HBRUSH EDIT_NotifyCtlColor(EDITSTATE *es, HDC hdc)
         return hbrush;
 }
 
-static inline LRESULT DefWindowProcT(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode)
-{
-	if(unicode)
-		return DefWindowProcW(hwnd, msg, wParam, lParam);
-	else
-		return DefWindowProcA(hwnd, msg, wParam, lParam);
-}
-
-static inline INT get_vertical_line_count(EDITSTATE *es)
-{
-	INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
-	return max(1,vlc);
-}
 
 /*********************************************************************
  *
- *	EditWndProc_common
+ *	EDIT_WordBreakProc
  *
- *	The messages are in the order of the actual integer values
- *	(which can be found in include/windows.h)
- *	Wherever possible the 16 bit versions are converted to
- *	the 32 bit ones, so that we can 'fall through' to the
- *	helper functions.  These are mostly 32 bit (with a few
- *	exceptions, clearly indicated by a '16' extension to their
- *	names).
+ *	Find the beginning of words.
+ *	Note:	unlike the specs for a WordBreakProc, this function only
+ *		allows to be called without linebreaks between s[0] up to
+ *		s[count - 1].  Remember it is only called
+ *		internally, so we can decide this for ourselves.
  *
  */
-static LRESULT EditWndProc_common( HWND hwnd, UINT msg,
-                                   WPARAM wParam, LPARAM lParam, BOOL unicode )
+static INT EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action)
 {
-	EDITSTATE *es = (EDITSTATE *)GetWindowLongPtrW( hwnd, 0 );
-	LRESULT result = 0;
-
-        TRACE("hwnd=%p msg=%x (%s) wparam=%lx lparam=%lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), wParam, lParam);
-	
-	if (!es && msg != WM_NCCREATE)
-		return DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
-
-	if (es && (msg != WM_DESTROY)) EDIT_LockBuffer(es);
-
-	switch (msg) {
-	case EM_GETSEL16:
-		wParam = 0;
-		lParam = 0;
-		/* fall through */
-	case EM_GETSEL:
-		result = EDIT_EM_GetSel(es, (PUINT)wParam, (PUINT)lParam);
-		break;
-
-	case EM_SETSEL16:
-		if ((short)LOWORD(lParam) == -1)
-			EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
-		else
-			EDIT_EM_SetSel(es, LOWORD(lParam), HIWORD(lParam), FALSE);
-		if (!wParam)
-			EDIT_EM_ScrollCaret(es);
-		result = 1;
-		break;
-	case EM_SETSEL:
-		EDIT_EM_SetSel(es, wParam, lParam, FALSE);
-		EDIT_EM_ScrollCaret(es);
-		result = 1;
-		break;
-
-	case EM_GETRECT16:
-		if (lParam)
-                {
-                    RECT16 *r16 = MapSL(lParam);
-                    r16->left   = es->format_rect.left;
-                    r16->top    = es->format_rect.top;
-                    r16->right  = es->format_rect.right;
-                    r16->bottom = es->format_rect.bottom;
-                }
-		break;
-	case EM_GETRECT:
-		if (lParam)
-			CopyRect((LPRECT)lParam, &es->format_rect);
-		break;
-
-	case EM_SETRECT16:
-		if ((es->style & ES_MULTILINE) && lParam) {
-			RECT rc;
-			RECT16 *r16 = MapSL(lParam);
-			rc.left   = r16->left;
-			rc.top    = r16->top;
-			rc.right  = r16->right;
-			rc.bottom = r16->bottom;
-			EDIT_SetRectNP(es, &rc);
-			EDIT_UpdateText(es, NULL, TRUE);
-		}
-		break;
-	case EM_SETRECT:
-		if ((es->style & ES_MULTILINE) && lParam) {
-			EDIT_SetRectNP(es, (LPRECT)lParam);
-			EDIT_UpdateText(es, NULL, TRUE);
-		}
-		break;
-
-	case EM_SETRECTNP16:
-		if ((es->style & ES_MULTILINE) && lParam) {
-			RECT rc;
-			RECT16 *r16 = MapSL(lParam);
-			rc.left   = r16->left;
-			rc.top    = r16->top;
-			rc.right  = r16->right;
-			rc.bottom = r16->bottom;
-			EDIT_SetRectNP(es, &rc);
-		}
-		break;
-	case EM_SETRECTNP:
-		if ((es->style & ES_MULTILINE) && lParam)
-			EDIT_SetRectNP(es, (LPRECT)lParam);
-		break;
-
-	case EM_SCROLL16:
-	case EM_SCROLL:
-		result = EDIT_EM_Scroll(es, (INT)wParam);
-                break;
-
-	case EM_LINESCROLL16:
-		wParam = (WPARAM)(INT)(SHORT)HIWORD(lParam);
-		lParam = (LPARAM)(INT)(SHORT)LOWORD(lParam);
-		/* fall through */
-	case EM_LINESCROLL:
-		result = (LRESULT)EDIT_EM_LineScroll(es, (INT)wParam, (INT)lParam);
-		break;
-
-	case EM_SCROLLCARET16:
-	case EM_SCROLLCARET:
-		EDIT_EM_ScrollCaret(es);
-		result = 1;
-		break;
-
-	case EM_GETMODIFY16:
-	case EM_GETMODIFY:
-		result = ((es->flags & EF_MODIFIED) != 0);
-		break;
-
-	case EM_SETMODIFY16:
-	case EM_SETMODIFY:
-		if (wParam)
-			es->flags |= EF_MODIFIED;
-		else
-                        es->flags &= ~(EF_MODIFIED | EF_UPDATE);  /* reset pending updates */
-		break;
-
-	case EM_GETLINECOUNT16:
-	case EM_GETLINECOUNT:
-		result = (es->style & ES_MULTILINE) ? es->line_count : 1;
-		break;
-
-	case EM_LINEINDEX16:
-		if ((INT16)wParam == -1)
-			wParam = (WPARAM)-1;
-		/* fall through */
-	case EM_LINEINDEX:
-		result = (LRESULT)EDIT_EM_LineIndex(es, (INT)wParam);
-		break;
-
-	case EM_SETHANDLE16:
-		EDIT_EM_SetHandle16(es, (HLOCAL16)wParam);
-		break;
-	case EM_SETHANDLE:
-		EDIT_EM_SetHandle(es, (HLOCAL)wParam);
-		break;
-
-	case EM_GETHANDLE16:
-		result = (LRESULT)EDIT_EM_GetHandle16(es);
-		break;
-	case EM_GETHANDLE:
-		result = (LRESULT)EDIT_EM_GetHandle(es);
-		break;
-
-	case EM_GETTHUMB16:
-	case EM_GETTHUMB:
-		result = EDIT_EM_GetThumb(es);
-		break;
-
-	/* these messages missing from specs */
-	case WM_USER+15:
-	case 0x00bf:
-	case WM_USER+16:
-	case 0x00c0:
-	case WM_USER+19:
-	case 0x00c3:
-	case WM_USER+26:
-	case 0x00ca:
-		FIXME("undocumented message 0x%x, please report\n", msg);
-		result = DefWindowProcW(hwnd, msg, wParam, lParam);
-		break;
-		
-	case EM_LINELENGTH16:
-	case EM_LINELENGTH:
-		result = (LRESULT)EDIT_EM_LineLength(es, (INT)wParam);
-		break;
-
-	case EM_REPLACESEL16:
-		lParam = (LPARAM)MapSL(lParam);
-		unicode = FALSE;  /* 16-bit message is always ascii */
-		/* fall through */
-	case EM_REPLACESEL:
-	{
-		LPWSTR textW;
-
-		if(unicode)
-		    textW = (LPWSTR)lParam;
-		else
-		{
-		    LPSTR textA = (LPSTR)lParam;
-		    INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
-		    if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
-			MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
-		}
-
-		EDIT_EM_ReplaceSel(es, (BOOL)wParam, textW, TRUE, TRUE);
-		result = 1;
-
-		if(!unicode)
-		    HeapFree(GetProcessHeap(), 0, textW);
-		break;
-	}
-
-	case EM_GETLINE16:
-		lParam = (LPARAM)MapSL(lParam);
-		unicode = FALSE;  /* 16-bit message is always ascii */
-		/* fall through */
-	case EM_GETLINE:
-		result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, (LPWSTR)lParam, unicode);
-		break;
-
-	case EM_LIMITTEXT16:
-	case EM_SETLIMITTEXT:
-		EDIT_EM_SetLimitText(es, wParam);
-		break;
-
-	case EM_CANUNDO16:
-	case EM_CANUNDO:
-		result = (LRESULT)EDIT_EM_CanUndo(es);
-		break;
-
-	case EM_UNDO16:
-	case EM_UNDO:
-	case WM_UNDO:
-		result = (LRESULT)EDIT_EM_Undo(es);
-		break;
-
-	case EM_FMTLINES16:
-	case EM_FMTLINES:
-		result = (LRESULT)EDIT_EM_FmtLines(es, (BOOL)wParam);
-		break;
-
-	case EM_LINEFROMCHAR16:
-	case EM_LINEFROMCHAR:
-		result = (LRESULT)EDIT_EM_LineFromChar(es, (INT)wParam);
-		break;
-
-	case EM_SETTABSTOPS16:
-		result = (LRESULT)EDIT_EM_SetTabStops16(es, (INT)wParam, MapSL(lParam));
-		break;
-	case EM_SETTABSTOPS:
-		result = (LRESULT)EDIT_EM_SetTabStops(es, (INT)wParam, (LPINT)lParam);
-		break;
-
-	case EM_SETPASSWORDCHAR16:
-		unicode = FALSE;  /* 16-bit message is always ascii */
-		/* fall through */
-	case EM_SETPASSWORDCHAR:
-	{
-		WCHAR charW = 0;
-
-		if(unicode)
-		    charW = (WCHAR)wParam;
-		else
-		{
-		    CHAR charA = wParam;
-		    MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
-		}
-
-		EDIT_EM_SetPasswordChar(es, charW);
-		break;
-	}
+	INT ret = 0;
 
-	case EM_EMPTYUNDOBUFFER16:
-	case EM_EMPTYUNDOBUFFER:
-		EDIT_EM_EmptyUndoBuffer(es);
-		break;
+	TRACE("s=%p, index=%d, count=%d, action=%d\n", s, index, count, action);
 
-	case EM_GETFIRSTVISIBLELINE16:
-		result = es->y_offset;
-		break;
-	case EM_GETFIRSTVISIBLELINE:
-		result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset;
-		break;
+	if(!s) return 0;
 
-	case EM_SETREADONLY16:
-	case EM_SETREADONLY:
-		if (wParam) {
-                    SetWindowLongW( hwnd, GWL_STYLE,
-                                    GetWindowLongW( hwnd, GWL_STYLE ) | ES_READONLY );
-                    es->style |= ES_READONLY;
+	switch (action) {
+	case WB_LEFT:
+		if (!count)
+			break;
+		if (index)
+			index--;
+		if (s[index] == ' ') {
+			while (index && (s[index] == ' '))
+				index--;
+			if (index) {
+				while (index && (s[index] != ' '))
+					index--;
+				if (s[index] == ' ')
+					index++;
+			}
 		} else {
-                    SetWindowLongW( hwnd, GWL_STYLE,
-                                    GetWindowLongW( hwnd, GWL_STYLE ) & ~ES_READONLY );
-                    es->style &= ~ES_READONLY;
-		}
-                result = 1;
- 		break;
-
-	case EM_SETWORDBREAKPROC16:
-		EDIT_EM_SetWordBreakProc16(es, (EDITWORDBREAKPROC16)lParam);
-		break;
-	case EM_SETWORDBREAKPROC:
-		EDIT_EM_SetWordBreakProc(es, (void *)lParam);
-		break;
-
-	case EM_GETWORDBREAKPROC16:
-		result = (LRESULT)es->word_break_proc16;
-		break;
-	case EM_GETWORDBREAKPROC:
-		result = (LRESULT)es->word_break_proc;
-		break;
-
-	case EM_GETPASSWORDCHAR16:
-		unicode = FALSE;  /* 16-bit message is always ascii */
-		/* fall through */
-	case EM_GETPASSWORDCHAR:
-	{
-		if(unicode)
-		    result = es->password_char;
-		else
-		{
-		    WCHAR charW = es->password_char;
-		    CHAR charA = 0;
-		    WideCharToMultiByte(CP_ACP, 0, &charW, 1, &charA, 1, NULL, NULL);
-		    result = charA;
-		}
-		break;
-	}
-
-	/* The following EM_xxx are new to win95 and don't exist for 16 bit */
-
-	case EM_SETMARGINS:
-		EDIT_EM_SetMargins(es, (INT)wParam, LOWORD(lParam), HIWORD(lParam), TRUE);
-		break;
-
-	case EM_GETMARGINS:
-		result = MAKELONG(es->left_margin, es->right_margin);
-		break;
-
-	case EM_GETLIMITTEXT:
-		result = es->buffer_limit;
-		break;
-
-	case EM_POSFROMCHAR:
-		if ((INT)wParam >= get_text_length(es)) result = -1;
-		else result = EDIT_EM_PosFromChar(es, (INT)wParam, FALSE);
-		break;
-
-	case EM_CHARFROMPOS:
-		result = EDIT_EM_CharFromPos(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
-		break;
-
-        /* End of the EM_ messages which were in numerical order; what order
-         * are these in?  vaguely alphabetical?
-         */
-
-	case WM_NCCREATE:
-		result = EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTW)lParam, unicode);
-		break;
-
-	case WM_DESTROY:
-		result = EDIT_WM_Destroy(es);
-		es = NULL;
-		break;
-
-	case WM_GETDLGCODE:
-		result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
-		
-		if (es->style & ES_MULTILINE)
-		   result |= DLGC_WANTALLKEYS;
-
-		if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
-		{
-		   int vk = (int)((LPMSG)lParam)->wParam;
-
-                   if (es->hwndListBox)
-                   {
-                       if (vk == VK_RETURN || vk == VK_ESCAPE)
-                           if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
-                               result |= DLGC_WANTMESSAGE;
-                   }
-                   else
-                   {
-                       switch (vk)
-                       {
-                           case VK_ESCAPE:
-                               SendMessageW(GetParent(hwnd), WM_CLOSE, 0, 0);
-                               break;
-                           default:
-                               break;
-                       }
-                   }
-                }
-		break;
-
-        case WM_IME_CHAR:
-            if (!unicode)
-            {
-                WCHAR charW;
-                CHAR  strng[2];
-
-                strng[0] = wParam >> 8;
-                strng[1] = wParam & 0xff;
-                if (strng[0]) MultiByteToWideChar(CP_ACP, 0, strng, 2, &charW, 1);
-                else MultiByteToWideChar(CP_ACP, 0, &strng[1], 1, &charW, 1);
-		result = EDIT_WM_Char(es, charW);
-		break;
-            }
-            /* fall through */
-	case WM_CHAR:
-	{
-		WCHAR charW;
-
-		if(unicode)
-		    charW = wParam;
-		else
-		{
-		    CHAR charA = wParam;
-		    MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
+			while (index && (s[index] != ' '))
+				index--;
+			if (s[index] == ' ')
+				index++;
 		}
-
-                if (es->hwndListBox)
-                {
-                    if (charW == VK_RETURN || charW == VK_ESCAPE)
-                    {
-                        if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
-                            SendMessageW(GetParent(hwnd), WM_KEYDOWN, charW, 0);
-                        break;
-                    }
-                }
-		result = EDIT_WM_Char(es, charW);
-		break;
-	}
-
-        case WM_UNICHAR:
-                if (unicode)
-                {
-                    if (wParam == UNICODE_NOCHAR) return TRUE;
-                    if (wParam <= 0x000fffff)
-                    {
-                        if(wParam > 0xffff) /* convert to surrogates */
-                        {
-                            wParam -= 0x10000;
-                            EDIT_WM_Char(es, (wParam >> 10) + 0xd800);
-                            EDIT_WM_Char(es, (wParam & 0x03ff) + 0xdc00);
-                        }
-                        else EDIT_WM_Char(es, wParam);
-                    }
-                    return 0;
-                }
-                break;
-
-	case WM_CLEAR:
-		EDIT_WM_Clear(es);
-		break;
-
-	case WM_COMMAND:
-		EDIT_WM_Command(es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
-		break;
-
-        case WM_CONTEXTMENU:
-		EDIT_WM_ContextMenu(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
-		break;
-
-	case WM_COPY:
-		EDIT_WM_Copy(es);
+		ret = index;
 		break;
-
-	case WM_CREATE:
-		if(unicode)
-		    result = EDIT_WM_Create(es, ((LPCREATESTRUCTW)lParam)->lpszName);
-		else
-		{
-		    LPCSTR nameA = ((LPCREATESTRUCTA)lParam)->lpszName;
-		    LPWSTR nameW = NULL;
-		    if(nameA)
-		    {
-			INT countW = MultiByteToWideChar(CP_ACP, 0, nameA, -1, NULL, 0);
-			if((nameW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
-			    MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW);
-		    }
-		    result = EDIT_WM_Create(es, nameW);
-                    HeapFree(GetProcessHeap(), 0, nameW);
+	case WB_RIGHT:
+		if (!count)
+			break;
+		if (index)
+			index--;
+		if (s[index] == ' ')
+			while ((index < count) && (s[index] == ' ')) index++;
+		else {
+			while (s[index] && (s[index] != ' ') && (index < count))
+				index++;
+			while ((s[index] == ' ') && (index < count)) index++;
 		}
+		ret = index;
 		break;
-
-	case WM_CUT:
-		EDIT_WM_Cut(es);
-		break;
-
-	case WM_ENABLE:
-                es->bEnableState = (BOOL) wParam;
-		EDIT_UpdateText(es, NULL, TRUE);
-		break;
-
-	case WM_ERASEBKGND:
-		/* we do the proper erase in EDIT_WM_Paint */
-		result = 1;
-		break;
-
-	case WM_GETFONT:
-		result = (LRESULT)es->font;
-		break;
-
-	case WM_GETTEXT:
-		result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, (LPWSTR)lParam, unicode);
-		break;
-
-	case WM_GETTEXTLENGTH:
-                if (unicode) result = get_text_length(es);
-                else result = WideCharToMultiByte( CP_ACP, 0, es->text, get_text_length(es),
-                                                   NULL, 0, NULL, NULL );
-		break;
-
-	case WM_HSCROLL:
-		result = EDIT_WM_HScroll(es, LOWORD(wParam), (short)HIWORD(wParam));
-		break;
-
-	case WM_KEYDOWN:
-		result = EDIT_WM_KeyDown(es, (INT)wParam);
-		break;
-
-	case WM_KILLFOCUS:
-		result = EDIT_WM_KillFocus(es);
-		break;
-
-	case WM_LBUTTONDBLCLK:
-		result = EDIT_WM_LButtonDblClk(es);
-		break;
-
-	case WM_LBUTTONDOWN:
-		result = EDIT_WM_LButtonDown(es, wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
-		break;
-
-	case WM_LBUTTONUP:
-		result = EDIT_WM_LButtonUp(es);
-		break;
-
-	case WM_MBUTTONDOWN:
-  		result = EDIT_WM_MButtonDown(es);
-		break;
-
-	case WM_MOUSEMOVE:
-		result = EDIT_WM_MouseMove(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
-		break;
-
-	case WM_PRINTCLIENT:
-	case WM_PAINT:
-	        EDIT_WM_Paint(es, (HDC)wParam);
-		break;
-
-	case WM_PASTE:
-		EDIT_WM_Paste(es);
-		break;
-
-	case WM_SETFOCUS:
-		EDIT_WM_SetFocus(es);
-		break;
-
-	case WM_SETFONT:
-		EDIT_WM_SetFont(es, (HFONT)wParam, LOWORD(lParam) != 0);
-		break;
-
-	case WM_SETREDRAW:
-		/* FIXME: actually set an internal flag and behave accordingly */
-		break;
-
-	case WM_SETTEXT:
-		EDIT_WM_SetText(es, (LPCWSTR)lParam, unicode);
-		result = TRUE;
-		break;
-
-	case WM_SIZE:
-		EDIT_WM_Size(es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
-		break;
-
-        case WM_STYLECHANGED:
-                result = EDIT_WM_StyleChanged(es, wParam, (const STYLESTRUCT *)lParam);
-                break;
-
-        case WM_STYLECHANGING:
-                result = 0; /* See EDIT_WM_StyleChanged */
-                break;
-
-	case WM_SYSKEYDOWN:
-		result = EDIT_WM_SysKeyDown(es, (INT)wParam, (DWORD)lParam);
-		break;
-
-	case WM_TIMER:
-		EDIT_WM_Timer(es);
-		break;
-
-	case WM_VSCROLL:
-		result = EDIT_WM_VScroll(es, LOWORD(wParam), (short)HIWORD(wParam));
-		break;
-
-        case WM_MOUSEWHEEL:
-                {
-                    int gcWheelDelta = 0;
-                    UINT pulScrollLines = 3;
-                    SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
-
-                    if (wParam & (MK_SHIFT | MK_CONTROL)) {
-                        result = DefWindowProcW(hwnd, msg, wParam, lParam);
-                        break;
-                    }
-                    gcWheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
-                    if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
-                    {
-                        int cLineScroll= (int) min((UINT) es->line_count, pulScrollLines);
-                        cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
-			result = EDIT_EM_LineScroll(es, 0, cLineScroll);
-                    }
-                }
-                break;
-
-            
-	/* IME messages to make the edit control IME aware */           
-	case WM_IME_SETCONTEXT:
-		break;
-
-	case WM_IME_STARTCOMPOSITION:
-		es->composition_start = es->selection_end;
-		es->composition_len = 0;
-		break;
-
-	case WM_IME_COMPOSITION:
-                EDIT_ImeComposition(hwnd, lParam, es);
-		break;
-
-	case WM_IME_ENDCOMPOSITION:
-                if (es->composition_len > 0)
-                {
-                        static const WCHAR empty_stringW[] = {0};
-                        EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
-                        es->selection_end = es->selection_start;
-                        es->composition_len= 0;
-                }
-		break;
-
-	case WM_IME_COMPOSITIONFULL:
-		break;
-
-	case WM_IME_SELECT:
-		break;
-
-	case WM_IME_CONTROL:
+	case WB_ISDELIMITER:
+		ret = (s[index] == ' ');
 		break;
-                
 	default:
-		result = DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
+		ERR("unknown action code, please report !\n");
 		break;
 	}
-	
-	if (es) EDIT_UnlockBuffer(es, FALSE);
-
-        TRACE("hwnd=%p msg=%x (%s) -- 0x%08lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), result);
-
-	return result;
+	return ret;
 }
 
-/*********************************************************************
- *
- *	EditWndProcW   (USER32.@)
- */
-LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    return EditWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
-}
 
 /*********************************************************************
  *
- *	EditWndProc   (USER32.@)
+ *	EDIT_CallWordBreakProc
+ *
+ *	Call appropriate WordBreakProc (internal or external).
+ *
+ *	Note: The "start" argument should always be an index referring
+ *		to es->text.  The actual wordbreak proc might be
+ *		16 bit, so we can't always pass any 32 bit LPSTR.
+ *		Hence we assume that es->text is the buffer that holds
+ *		the string under examination (we can decide this for ourselves).
+ *
  */
-LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action)
 {
-    return EditWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
+	INT ret;
+
+	if (es->word_break_proc16) {
+	    HGLOBAL16 hglob16;
+	    SEGPTR segptr;
+	    INT countA;
+            WORD args[5];
+            DWORD result;
+
+	    countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
+	    hglob16 = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT, countA);
+	    segptr = WOWGlobalLock16(hglob16);
+	    WideCharToMultiByte(CP_ACP, 0, es->text + start, count, MapSL(segptr), countA, NULL, NULL);
+            args[4] = SELECTOROF(segptr);
+            args[3] = OFFSETOF(segptr);
+            args[2] = index;
+            args[1] = countA;
+            args[0] = action;
+            WOWCallback16Ex((DWORD)es->word_break_proc16, WCB16_PASCAL, sizeof(args), args, &result);
+            ret = LOWORD(result);
+	    GlobalUnlock16(hglob16);
+	    GlobalFree16(hglob16);
+	}
+	else if (es->word_break_proc)
+        {
+	    if(es->is_unicode)
+	    {
+		EDITWORDBREAKPROCW wbpW = (EDITWORDBREAKPROCW)es->word_break_proc;
+
+		TRACE_(relay)("(UNICODE wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
+			es->word_break_proc, debugstr_wn(es->text + start, count), index, count, action);
+		ret = wbpW(es->text + start, index, count, action);
+	    }
+	    else
+	    {
+		EDITWORDBREAKPROCA wbpA = (EDITWORDBREAKPROCA)es->word_break_proc;
+		INT countA;
+		CHAR *textA;
+
+		countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
+		textA = HeapAlloc(GetProcessHeap(), 0, countA);
+		WideCharToMultiByte(CP_ACP, 0, es->text + start, count, textA, countA, NULL, NULL);
+		TRACE_(relay)("(ANSI wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
+			es->word_break_proc, debugstr_an(textA, countA), index, countA, action);
+		ret = wbpA(textA, index, countA, action);
+		HeapFree(GetProcessHeap(), 0, textA);
+	    }
+        }
+	else
+            ret = EDIT_WordBreakProc(es->text + start, index, count, action);
+
+	return ret;
 }
 
 /*********************************************************************
@@ -1360,6 +666,34 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
 	ReleaseDC(es->hwndSelf, dc);
 }
 
+
+static inline UINT get_text_length(EDITSTATE *es)
+{
+    if(es->text_length == (UINT)-1)
+        es->text_length = strlenW(es->text);
+    return es->text_length;
+}
+
+/*********************************************************************
+ *
+ *	EDIT_GetPasswordPointer_SL
+ *
+ *	note: caller should free the (optionally) allocated buffer
+ *
+ */
+static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es)
+{
+	if (es->style & ES_PASSWORD) {
+		INT len = get_text_length(es);
+		LPWSTR text = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+		text[len] = '\0';
+		while(len) text[--len] = es->password_char;
+		return text;
+	} else
+		return es->text;
+}
+
+
 /*********************************************************************
  *
  *	EDIT_CalcLineWidth_SL
@@ -1392,76 +726,6 @@ static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
 
 /*********************************************************************
  *
- *	EDIT_CallWordBreakProc
- *
- *	Call appropriate WordBreakProc (internal or external).
- *
- *	Note: The "start" argument should always be an index referring
- *		to es->text.  The actual wordbreak proc might be
- *		16 bit, so we can't always pass any 32 bit LPSTR.
- *		Hence we assume that es->text is the buffer that holds
- *		the string under examination (we can decide this for ourselves).
- *
- */
-static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action)
-{
-	INT ret;
-
-	if (es->word_break_proc16) {
-	    HGLOBAL16 hglob16;
-	    SEGPTR segptr;
-	    INT countA;
-            WORD args[5];
-            DWORD result;
-
-	    countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
-	    hglob16 = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT, countA);
-	    segptr = WOWGlobalLock16(hglob16);
-	    WideCharToMultiByte(CP_ACP, 0, es->text + start, count, MapSL(segptr), countA, NULL, NULL);
-            args[4] = SELECTOROF(segptr);
-            args[3] = OFFSETOF(segptr);
-            args[2] = index;
-            args[1] = countA;
-            args[0] = action;
-            WOWCallback16Ex((DWORD)es->word_break_proc16, WCB16_PASCAL, sizeof(args), args, &result);
-            ret = LOWORD(result);
-	    GlobalUnlock16(hglob16);
-	    GlobalFree16(hglob16);
-	}
-	else if (es->word_break_proc)
-        {
-	    if(es->is_unicode)
-	    {
-		EDITWORDBREAKPROCW wbpW = (EDITWORDBREAKPROCW)es->word_break_proc;
-
-		TRACE_(relay)("(UNICODE wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
-			es->word_break_proc, debugstr_wn(es->text + start, count), index, count, action);
-		ret = wbpW(es->text + start, index, count, action);
-	    }
-	    else
-	    {
-		EDITWORDBREAKPROCA wbpA = (EDITWORDBREAKPROCA)es->word_break_proc;
-		INT countA;
-		CHAR *textA;
-
-		countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
-		textA = HeapAlloc(GetProcessHeap(), 0, countA);
-		WideCharToMultiByte(CP_ACP, 0, es->text + start, count, textA, countA, NULL, NULL);
-		TRACE_(relay)("(ANSI wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
-			es->word_break_proc, debugstr_an(textA, countA), index, countA, action);
-		ret = wbpA(textA, index, countA, action);
-		HeapFree(GetProcessHeap(), 0, textA);
-	    }
-        }
-	else
-            ret = EDIT_WordBreakProc(es->text + start, index, count, action);
-
-	return ret;
-}
-
-
-/*********************************************************************
- *
  *	EDIT_CharFromPos
  *
  *	Beware: This is not the function called on EM_CHARFROMPOS
@@ -1620,6 +884,209 @@ static void EDIT_ConfinePoint(const EDITSTATE *es, LPINT x, LPINT y)
 
 /*********************************************************************
  *
+ *	EM_LINEFROMCHAR
+ *
+ */
+static INT EDIT_EM_LineFromChar(EDITSTATE *es, INT index)
+{
+	INT line;
+	LINEDEF *line_def;
+
+	if (!(es->style & ES_MULTILINE))
+		return 0;
+	if (index > (INT)get_text_length(es))
+		return es->line_count - 1;
+	if (index == -1)
+		index = min(es->selection_start, es->selection_end);
+
+	line = 0;
+	line_def = es->first_line_def;
+	index -= line_def->length;
+	while ((index >= 0) && line_def->next) {
+		line++;
+		line_def = line_def->next;
+		index -= line_def->length;
+	}
+	return line;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_LINEINDEX
+ *
+ */
+static INT EDIT_EM_LineIndex(const EDITSTATE *es, INT line)
+{
+	INT line_index;
+	const LINEDEF *line_def;
+
+	if (!(es->style & ES_MULTILINE))
+		return 0;
+	if (line >= es->line_count)
+		return -1;
+
+	line_index = 0;
+	line_def = es->first_line_def;
+	if (line == -1) {
+		INT index = es->selection_end - line_def->length;
+		while ((index >= 0) && line_def->next) {
+			line_index += line_def->length;
+			line_def = line_def->next;
+			index -= line_def->length;
+		}
+	} else {
+		while (line > 0) {
+			line_index += line_def->length;
+			line_def = line_def->next;
+			line--;
+		}
+	}
+	return line_index;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_LINELENGTH
+ *
+ */
+static INT EDIT_EM_LineLength(EDITSTATE *es, INT index)
+{
+	LINEDEF *line_def;
+
+	if (!(es->style & ES_MULTILINE))
+		return get_text_length(es);
+
+	if (index == -1) {
+		/* get the number of remaining non-selected chars of selected lines */
+		INT32 l; /* line number */
+		INT32 li; /* index of first char in line */
+		INT32 count;
+		l = EDIT_EM_LineFromChar(es, es->selection_start);
+		/* # chars before start of selection area */
+		count = es->selection_start - EDIT_EM_LineIndex(es, l);
+		l = EDIT_EM_LineFromChar(es, es->selection_end);
+		/* # chars after end of selection */
+		li = EDIT_EM_LineIndex(es, l);
+		count += li + EDIT_EM_LineLength(es, li) - es->selection_end;
+		return count;
+	}
+	line_def = es->first_line_def;
+	index -= line_def->length;
+	while ((index >= 0) && line_def->next) {
+		line_def = line_def->next;
+		index -= line_def->length;
+	}
+	return line_def->net_length;
+}
+
+
+/*********************************************************************
+ *
+ *	EM_POSFROMCHAR
+ *
+ */
+static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
+{
+	INT len = get_text_length(es);
+	INT l;
+	INT li;
+	INT x;
+	INT y = 0;
+	INT w;
+	INT lw = 0;
+	INT ll = 0;
+	HDC dc;
+	HFONT old_font = 0;
+	SIZE size;
+	LINEDEF *line_def;
+
+	index = min(index, len);
+	dc = GetDC(es->hwndSelf);
+	if (es->font)
+		old_font = SelectObject(dc, es->font);
+	if (es->style & ES_MULTILINE) {
+		l = EDIT_EM_LineFromChar(es, index);
+		y = (l - es->y_offset) * es->line_height;
+		li = EDIT_EM_LineIndex(es, l);
+		if (after_wrap && (li == index) && l) {
+			INT l2 = l - 1;
+			line_def = es->first_line_def;
+			while (l2) {
+				line_def = line_def->next;
+				l2--;
+			}
+			if (line_def->ending == END_WRAP) {
+				l--;
+				y -= es->line_height;
+				li = EDIT_EM_LineIndex(es, l);
+			}
+		}
+
+		line_def = es->first_line_def;
+		while (line_def->index != li)
+			line_def = line_def->next;
+
+		ll = line_def->net_length;
+		lw = line_def->width;
+
+		w = es->format_rect.right - es->format_rect.left;
+		if (es->style & ES_RIGHT)
+		{
+			x = LOWORD(GetTabbedTextExtentW(dc, es->text + li + (index - li), ll - (index - li),
+				es->tabs_count, es->tabs)) - es->x_offset;
+			x = w - x;
+		}
+		else if (es->style & ES_CENTER)
+		{
+			x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
+				es->tabs_count, es->tabs)) - es->x_offset;
+			x += (w - lw) / 2;
+		}
+		else /* ES_LEFT */
+		{
+		    x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
+				es->tabs_count, es->tabs)) - es->x_offset;
+		}
+	} else {
+		LPWSTR text = EDIT_GetPasswordPointer_SL(es);
+		if (index < es->x_offset) {
+			GetTextExtentPoint32W(dc, text + index,
+					es->x_offset - index, &size);
+			x = -size.cx;
+		} else {
+			GetTextExtentPoint32W(dc, text + es->x_offset,
+					index - es->x_offset, &size);
+			 x = size.cx;
+
+			if (!es->x_offset && (es->style & (ES_RIGHT | ES_CENTER)))
+			{
+				w = es->format_rect.right - es->format_rect.left;
+				if (w > es->text_width)
+				{
+					if (es->style & ES_RIGHT)
+						x += w - es->text_width;
+					else if (es->style & ES_CENTER)
+						x += (w - es->text_width) / 2;
+				}
+			}
+		}
+		y = 0;
+		if (es->style & ES_PASSWORD)
+			HeapFree(GetProcessHeap(), 0, text);
+	}
+	x += es->format_rect.left;
+	y += es->format_rect.top;
+	if (es->font)
+		SelectObject(dc, old_font);
+	ReleaseDC(es->hwndSelf, dc);
+	return MAKELONG((INT16)x, (INT16)y);
+}
+
+
+/*********************************************************************
+ *
  *	EDIT_GetLineRect
  *
  *	Calculates the bounding rectangle for a line from a starting
@@ -1640,26 +1107,11 @@ static void EDIT_GetLineRect(EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT
 }
 
 
-/*********************************************************************
- *
- *	EDIT_GetPasswordPointer_SL
- *
- *	note: caller should free the (optionally) allocated buffer
- *
- */
-static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es)
+static inline void text_buffer_changed(EDITSTATE *es)
 {
-	if (es->style & ES_PASSWORD) {
-		INT len = get_text_length(es);
-		LPWSTR text = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
-		text[len] = '\0';
-		while(len) text[--len] = es->password_char;
-		return text;
-	} else
-		return es->text;
+    es->text_length = (UINT)-1;
 }
 
-
 /*********************************************************************
  *
  *	EDIT_LockBuffer
@@ -1755,6 +1207,211 @@ static void EDIT_LockBuffer(EDITSTATE *es)
 
 /*********************************************************************
  *
+ *	EDIT_UnlockBuffer
+ *
+ */
+static void EDIT_UnlockBuffer(EDITSTATE *es, BOOL force)
+{
+
+	/* Edit window might be already destroyed */
+	if(!IsWindow(es->hwndSelf))
+	{
+	    WARN("edit hwnd %p already destroyed\n", es->hwndSelf);
+	    return;
+	}
+
+	if (!es->lock_count) {
+		ERR("lock_count == 0 ... please report\n");
+		return;
+	}
+	if (!es->text) {
+		ERR("es->text == 0 ... please report\n");
+		return;
+	}
+
+	if (force || (es->lock_count == 1)) {
+	    if (es->hloc32W) {
+		CHAR *textA = NULL;
+		UINT countA = 0;
+		UINT countW = get_text_length(es) + 1;
+		STACK16FRAME* stack16 = NULL;
+	        HANDLE16 oldDS = 0;
+
+		if(es->hloc32A)
+		{
+		    UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
+		    TRACE("Synchronizing with 32-bit ANSI buffer\n");
+		    TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
+		    countA = LocalSize(es->hloc32A);
+		    if(countA_new > countA)
+		    {
+			HLOCAL hloc32A_new;
+			UINT alloc_size = ROUND_TO_GROW(countA_new);
+			TRACE("Resizing 32-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
+			hloc32A_new = LocalReAlloc(es->hloc32A, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
+			if(hloc32A_new)
+			{
+			    es->hloc32A = hloc32A_new;
+			    countA = LocalSize(hloc32A_new);
+			    TRACE("Real new size %d bytes\n", countA);
+			}
+			else
+			    WARN("FAILED! Will synchronize partially\n");
+		    }
+		    textA = LocalLock(es->hloc32A);
+		}
+		else if(es->hloc16)
+		{
+		    UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
+
+		    TRACE("Synchronizing with 16-bit ANSI buffer\n");
+		    TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
+
+		    stack16 = MapSL(PtrToUlong(NtCurrentTeb()->WOW32Reserved));
+		    oldDS = stack16->ds;
+		    stack16->ds = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
+
+		    countA = LocalSize16(es->hloc16);
+		    if(countA_new > countA)
+		    {
+			HLOCAL16 hloc16_new;
+			UINT alloc_size = ROUND_TO_GROW(countA_new);
+			TRACE("Resizing 16-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
+			hloc16_new = LocalReAlloc16(es->hloc16, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
+			if(hloc16_new)
+			{
+			    es->hloc16 = hloc16_new;
+			    countA = LocalSize16(hloc16_new);
+			    TRACE("Real new size %d bytes\n", countA);
+			}
+			else
+			    WARN("FAILED! Will synchronize partially\n");
+		    }
+		    textA = MapSL(LocalLock16(es->hloc16));
+		}
+
+		if(textA)
+		{
+		    WideCharToMultiByte(CP_ACP, 0, es->text, countW, textA, countA, NULL, NULL);
+		    if(stack16)
+			LocalUnlock16(es->hloc16);
+		    else
+			LocalUnlock(es->hloc32A);
+		}
+
+		if (stack16) stack16->ds = oldDS;
+		LocalUnlock(es->hloc32W);
+		es->text = NULL;
+	    }
+	    else {
+		ERR("no buffer ... please report\n");
+		return;
+	    }
+	}
+	es->lock_count--;
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MakeFit
+ *
+ * Try to fit size + 1 characters in the buffer.
+ */
+static BOOL EDIT_MakeFit(EDITSTATE *es, UINT size)
+{
+	HLOCAL hNew32W;
+
+	if (size <= es->buffer_size)
+		return TRUE;
+
+	TRACE("trying to ReAlloc to %d+1 characters\n", size);
+
+	/* Force edit to unlock it's buffer. es->text now NULL */
+	EDIT_UnlockBuffer(es, TRUE);
+
+	if (es->hloc32W) {
+	    UINT alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
+	    if ((hNew32W = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT))) {
+		TRACE("Old 32 bit handle %p, new handle %p\n", es->hloc32W, hNew32W);
+		es->hloc32W = hNew32W;
+		es->buffer_size = LocalSize(hNew32W)/sizeof(WCHAR) - 1;
+	    }
+	}
+
+	EDIT_LockBuffer(es);
+
+	if (es->buffer_size < size) {
+		WARN("FAILED !  We now have %d+1\n", es->buffer_size);
+		EDIT_NOTIFY_PARENT(es, EN_ERRSPACE);
+		return FALSE;
+	} else {
+		TRACE("We now have %d+1\n", es->buffer_size);
+		return TRUE;
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_MakeUndoFit
+ *
+ *	Try to fit size + 1 bytes in the undo buffer.
+ *
+ */
+static BOOL EDIT_MakeUndoFit(EDITSTATE *es, UINT size)
+{
+	UINT alloc_size;
+
+	if (size <= es->undo_buffer_size)
+		return TRUE;
+
+	TRACE("trying to ReAlloc to %d+1\n", size);
+
+	alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
+	if ((es->undo_text = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, es->undo_text, alloc_size))) {
+		es->undo_buffer_size = alloc_size/sizeof(WCHAR) - 1;
+		return TRUE;
+	}
+	else
+	{
+		WARN("FAILED !  We now have %d+1\n", es->undo_buffer_size);
+		return FALSE;
+	}
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_UpdateTextRegion
+ *
+ */
+static void EDIT_UpdateTextRegion(EDITSTATE *es, HRGN hrgn, BOOL bErase)
+{
+    if (es->flags & EF_UPDATE) {
+        es->flags &= ~EF_UPDATE;
+        EDIT_NOTIFY_PARENT(es, EN_UPDATE);
+    }
+    InvalidateRgn(es->hwndSelf, hrgn, bErase);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_UpdateText
+ *
+ */
+static void EDIT_UpdateText(EDITSTATE *es, const RECT *rc, BOOL bErase)
+{
+    if (es->flags & EF_UPDATE) {
+        es->flags &= ~EF_UPDATE;
+        EDIT_NOTIFY_PARENT(es, EN_UPDATE);
+    }
+    InvalidateRect(es->hwndSelf, rc, bErase);
+}
+
+/*********************************************************************
+ *
  *	EDIT_SL_InvalidateText
  *
  *	Called from EDIT_InvalidateText().
@@ -1772,6 +1429,12 @@ static void EDIT_SL_InvalidateText(EDITSTATE *es, INT start, INT end)
 }
 
 
+static inline INT get_vertical_line_count(EDITSTATE *es)
+{
+	INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+	return max(1,vlc);
+}
+
 /*********************************************************************
  *
  *	EDIT_ML_InvalidateText
@@ -1868,70 +1531,315 @@ static void EDIT_InvalidateText(EDITSTATE *es, INT start, INT end)
 
 /*********************************************************************
  *
- *	EDIT_MakeFit
+ *	EDIT_EM_SetSel
+ *
+ *	note:	unlike the specs say: the order of start and end
+ *		_is_ preserved in Windows.  (i.e. start can be > end)
+ *		In other words: this handler is OK
  *
- * Try to fit size + 1 characters in the buffer.
  */
-static BOOL EDIT_MakeFit(EDITSTATE *es, UINT size)
+static void EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap)
 {
-	HLOCAL hNew32W;
+	UINT old_start = es->selection_start;
+	UINT old_end = es->selection_end;
+	UINT len = get_text_length(es);
 
-	if (size <= es->buffer_size)
-		return TRUE;
+	if (start == (UINT)-1) {
+		start = es->selection_end;
+		end = es->selection_end;
+	} else {
+		start = min(start, len);
+		end = min(end, len);
+	}
+	es->selection_start = start;
+	es->selection_end = end;
+	if (after_wrap)
+		es->flags |= EF_AFTER_WRAP;
+	else
+		es->flags &= ~EF_AFTER_WRAP;
+	/* Compute the necessary invalidation region. */
+	/* Note that we don't need to invalidate regions which have
+	 * "never" been selected, or those which are "still" selected.
+	 * In fact, every time we hit a selection boundary, we can
+	 * *toggle* whether we need to invalidate.  Thus we can optimize by
+	 * *sorting* the interval endpoints.  Let's assume that we sort them
+	 * in this order:
+	 *        start <= end <= old_start <= old_end
+	 * Knuth 5.3.1 (p 183) assures us that this can be done optimally
+	 * in 5 comparisons; i.e. it is impossible to do better than the
+	 * following: */
+        ORDER_UINT(end, old_end);
+        ORDER_UINT(start, old_start);
+        ORDER_UINT(old_start, old_end);
+        ORDER_UINT(start, end);
+	/* Note that at this point 'end' and 'old_start' are not in order, but
+	 * start is definitely the min. and old_end is definitely the max. */
+	if (end != old_start)
+        {
+/*
+ * One can also do
+ *          ORDER_UINT32(end, old_start);
+ *          EDIT_InvalidateText(es, start, end);
+ *          EDIT_InvalidateText(es, old_start, old_end);
+ * in place of the following if statement.
+ * (That would complete the optimal five-comparison four-element sort.)
+ */
+            if (old_start > end )
+            {
+                EDIT_InvalidateText(es, start, end);
+                EDIT_InvalidateText(es, old_start, old_end);
+            }
+            else
+            {
+                EDIT_InvalidateText(es, start, old_start);
+                EDIT_InvalidateText(es, end, old_end);
+            }
+	}
+        else EDIT_InvalidateText(es, start, old_end);
+}
 
-	TRACE("trying to ReAlloc to %d+1 characters\n", size);
 
-	/* Force edit to unlock it's buffer. es->text now NULL */
-	EDIT_UnlockBuffer(es, TRUE);
+/*********************************************************************
+ *
+ *	EDIT_UpdateScrollInfo
+ *
+ */
+static void EDIT_UpdateScrollInfo(EDITSTATE *es)
+{
+    if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK))
+    {
+	SCROLLINFO si;
+	si.cbSize	= sizeof(SCROLLINFO);
+	si.fMask	= SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
+	si.nMin		= 0;
+	si.nMax		= es->line_count - 1;
+	si.nPage	= (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+	si.nPos		= es->y_offset;
+	TRACE("SB_VERT, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
+		si.nMin, si.nMax, si.nPage, si.nPos);
+	SetScrollInfo(es->hwndSelf, SB_VERT, &si, TRUE);
+    }
 
-	if (es->hloc32W) {
-	    UINT alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
-	    if ((hNew32W = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT))) {
-		TRACE("Old 32 bit handle %p, new handle %p\n", es->hloc32W, hNew32W);
-		es->hloc32W = hNew32W;
-		es->buffer_size = LocalSize(hNew32W)/sizeof(WCHAR) - 1;
-	    }
+    if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK))
+    {
+	SCROLLINFO si;
+	si.cbSize	= sizeof(SCROLLINFO);
+	si.fMask	= SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
+	si.nMin		= 0;
+	si.nMax		= es->text_width - 1;
+	si.nPage	= es->format_rect.right - es->format_rect.left;
+	si.nPos		= es->x_offset;
+	TRACE("SB_HORZ, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
+		si.nMin, si.nMax, si.nPage, si.nPos);
+	SetScrollInfo(es->hwndSelf, SB_HORZ, &si, TRUE);
+    }
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_EM_LineScroll_internal
+ *
+ *	Version of EDIT_EM_LineScroll for internal use.
+ *	It doesn't refuse if ES_MULTILINE is set and assumes that
+ *	dx is in pixels, dy - in lines.
+ *
+ */
+static BOOL EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy)
+{
+	INT nyoff;
+	INT x_offset_in_pixels;
+	INT lines_per_page = (es->format_rect.bottom - es->format_rect.top) /
+			      es->line_height;
+
+	if (es->style & ES_MULTILINE)
+	{
+	    x_offset_in_pixels = es->x_offset;
+	}
+	else
+	{
+	    dy = 0;
+	    x_offset_in_pixels = (short)LOWORD(EDIT_EM_PosFromChar(es, es->x_offset, FALSE));
 	}
 
-	EDIT_LockBuffer(es);
+	if (-dx > x_offset_in_pixels)
+		dx = -x_offset_in_pixels;
+	if (dx > es->text_width - x_offset_in_pixels)
+		dx = es->text_width - x_offset_in_pixels;
+	nyoff = max(0, es->y_offset + dy);
+	if (nyoff >= es->line_count - lines_per_page)
+		nyoff = max(0, es->line_count - lines_per_page);
+	dy = (es->y_offset - nyoff) * es->line_height;
+	if (dx || dy) {
+		RECT rc1;
+		RECT rc;
 
-	if (es->buffer_size < size) {
-		WARN("FAILED !  We now have %d+1\n", es->buffer_size);
-		EDIT_NOTIFY_PARENT(es, EN_ERRSPACE);
-		return FALSE;
-	} else {
-		TRACE("We now have %d+1\n", es->buffer_size);
-		return TRUE;
+		es->y_offset = nyoff;
+		if(es->style & ES_MULTILINE)
+		    es->x_offset += dx;
+		else
+		    es->x_offset += dx / es->char_width;
+
+		GetClientRect(es->hwndSelf, &rc1);
+		IntersectRect(&rc, &rc1, &es->format_rect);
+		ScrollWindowEx(es->hwndSelf, -dx, dy,
+				NULL, &rc, NULL, NULL, SW_INVALIDATE);
+		/* force scroll info update */
+		EDIT_UpdateScrollInfo(es);
 	}
+	if (dx && !(es->flags & EF_HSCROLL_TRACK))
+		EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
+	if (dy && !(es->flags & EF_VSCROLL_TRACK))
+		EDIT_NOTIFY_PARENT(es, EN_VSCROLL);
+	return TRUE;
 }
 
-
 /*********************************************************************
  *
- *	EDIT_MakeUndoFit
+ *	EM_LINESCROLL
  *
- *	Try to fit size + 1 bytes in the undo buffer.
+ *	NOTE: dx is in average character widths, dy - in lines;
  *
  */
-static BOOL EDIT_MakeUndoFit(EDITSTATE *es, UINT size)
+static BOOL EDIT_EM_LineScroll(EDITSTATE *es, INT dx, INT dy)
 {
-	UINT alloc_size;
+	if (!(es->style & ES_MULTILINE))
+		return FALSE;
 
-	if (size <= es->undo_buffer_size)
-		return TRUE;
+	dx *= es->char_width;
+	return EDIT_EM_LineScroll_internal(es, dx, dy);
+}
 
-	TRACE("trying to ReAlloc to %d+1\n", size);
 
-	alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
-	if ((es->undo_text = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, es->undo_text, alloc_size))) {
-		es->undo_buffer_size = alloc_size/sizeof(WCHAR) - 1;
-		return TRUE;
+/*********************************************************************
+ *
+ *	EM_SCROLL
+ *
+ */
+static LRESULT EDIT_EM_Scroll(EDITSTATE *es, INT action)
+{
+	INT dy;
+
+	if (!(es->style & ES_MULTILINE))
+		return (LRESULT)FALSE;
+
+	dy = 0;
+
+	switch (action) {
+	case SB_LINEUP:
+		if (es->y_offset)
+			dy = -1;
+		break;
+	case SB_LINEDOWN:
+		if (es->y_offset < es->line_count - 1)
+			dy = 1;
+		break;
+	case SB_PAGEUP:
+		if (es->y_offset)
+			dy = -(es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		break;
+	case SB_PAGEDOWN:
+		if (es->y_offset < es->line_count - 1)
+			dy = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		break;
+	default:
+		return (LRESULT)FALSE;
 	}
-	else
-	{
-		WARN("FAILED !  We now have %d+1\n", es->undo_buffer_size);
-		return FALSE;
+	if (dy) {
+	    INT vlc = get_vertical_line_count(es);
+	    /* check if we are going to move too far */
+	    if(es->y_offset + dy > es->line_count - vlc)
+		dy = es->line_count - vlc - es->y_offset;
+
+	    /* Notification is done in EDIT_EM_LineScroll */
+	    if(dy)
+		EDIT_EM_LineScroll(es, 0, dy);
 	}
+	return MAKELONG((INT16)dy, (BOOL16)TRUE);
+}
+
+
+/*********************************************************************
+ *
+ *	EDIT_SetCaretPos
+ *
+ */
+static void EDIT_SetCaretPos(EDITSTATE *es, INT pos,
+			     BOOL after_wrap)
+{
+	LRESULT res = EDIT_EM_PosFromChar(es, pos, after_wrap);
+	TRACE("%d - %dx%d\n", pos, (short)LOWORD(res), (short)HIWORD(res));
+	SetCaretPos((short)LOWORD(res), (short)HIWORD(res));
+}
+
+
+/*********************************************************************
+ *
+ *	EM_SCROLLCARET
+ *
+ */
+static void EDIT_EM_ScrollCaret(EDITSTATE *es)
+{
+	if (es->style & ES_MULTILINE) {
+		INT l;
+		INT vlc;
+		INT ww;
+		INT cw = es->char_width;
+		INT x;
+		INT dy = 0;
+		INT dx = 0;
+
+		l = EDIT_EM_LineFromChar(es, es->selection_end);
+		x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP));
+		vlc = get_vertical_line_count(es);
+		if (l >= es->y_offset + vlc)
+			dy = l - vlc + 1 - es->y_offset;
+		if (l < es->y_offset)
+			dy = l - es->y_offset;
+		ww = es->format_rect.right - es->format_rect.left;
+		if (x < es->format_rect.left)
+			dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw;
+		if (x > es->format_rect.right)
+			dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
+		if (dy || dx || (es->y_offset && (es->line_count - es->y_offset < vlc)))
+		{
+		    /* check if we are going to move too far */
+		    if(es->x_offset + dx + ww > es->text_width)
+			dx = es->text_width - ww - es->x_offset;
+		    if(dx || dy || (es->y_offset && (es->line_count - es->y_offset < vlc)))
+			EDIT_EM_LineScroll_internal(es, dx, dy);
+		}
+	} else {
+		INT x;
+		INT goal;
+		INT format_width;
+
+		x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
+		format_width = es->format_rect.right - es->format_rect.left;
+		if (x < es->format_rect.left) {
+			goal = es->format_rect.left + format_width / HSCROLL_FRACTION;
+			do {
+				es->x_offset--;
+				x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
+			} while ((x < goal) && es->x_offset);
+			/* FIXME: use ScrollWindow() somehow to improve performance */
+			EDIT_UpdateText(es, NULL, TRUE);
+		} else if (x > es->format_rect.right) {
+			INT x_last;
+			INT len = get_text_length(es);
+			goal = es->format_rect.right - format_width / HSCROLL_FRACTION;
+			do {
+				es->x_offset++;
+				x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
+				x_last = (short)LOWORD(EDIT_EM_PosFromChar(es, len, FALSE));
+			} while ((x > goal) && (x_last > es->format_rect.right));
+			/* FIXME: use ScrollWindow() somehow to improve performance */
+			EDIT_UpdateText(es, NULL, TRUE);
+		}
+	}
+
+    if(es->flags & EF_FOCUSED)
+	EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP);
 }
 
 
@@ -2195,50 +2103,6 @@ static void EDIT_MoveWordForward(EDITSTATE *es, BOOL extend)
 
 /*********************************************************************
  *
- *	EDIT_PaintLine
- *
- */
-static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev)
-{
-	INT s = es->selection_start;
-	INT e = es->selection_end;
-	INT li;
-	INT ll;
-	INT x;
-	INT y;
-	LRESULT pos;
-
-	if (es->style & ES_MULTILINE) {
-		INT vlc = get_vertical_line_count(es);
-
-		if ((line < es->y_offset) || (line > es->y_offset + vlc) || (line >= es->line_count))
-			return;
-	} else if (line)
-		return;
-
-	TRACE("line=%d\n", line);
-
-	pos = EDIT_EM_PosFromChar(es, EDIT_EM_LineIndex(es, line), FALSE);
-	x = (short)LOWORD(pos);
-	y = (short)HIWORD(pos);
-	li = EDIT_EM_LineIndex(es, line);
-	ll = EDIT_EM_LineLength(es, li);
-	s = min(es->selection_start, es->selection_end);
-	e = max(es->selection_start, es->selection_end);
-	s = min(li + ll, max(li, s));
-	e = min(li + ll, max(li, e));
-	if (rev && (s != e) &&
-			((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) {
-		x += EDIT_PaintText(es, dc, x, y, line, 0, s - li, FALSE);
-		x += EDIT_PaintText(es, dc, x, y, line, s - li, e - s, TRUE);
-		x += EDIT_PaintText(es, dc, x, y, line, e - li, li + ll - e, FALSE);
-	} else
-		x += EDIT_PaintText(es, dc, x, y, line, 0, ll, FALSE);
-}
-
-
-/*********************************************************************
- *
  *	EDIT_PaintText
  *
  */
@@ -2308,15 +2172,45 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col
 
 /*********************************************************************
  *
- *	EDIT_SetCaretPos
+ *	EDIT_PaintLine
  *
  */
-static void EDIT_SetCaretPos(EDITSTATE *es, INT pos,
-			     BOOL after_wrap)
+static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev)
 {
-	LRESULT res = EDIT_EM_PosFromChar(es, pos, after_wrap);
-	TRACE("%d - %dx%d\n", pos, (short)LOWORD(res), (short)HIWORD(res));
-	SetCaretPos((short)LOWORD(res), (short)HIWORD(res));
+	INT s = es->selection_start;
+	INT e = es->selection_end;
+	INT li;
+	INT ll;
+	INT x;
+	INT y;
+	LRESULT pos;
+
+	if (es->style & ES_MULTILINE) {
+		INT vlc = get_vertical_line_count(es);
+
+		if ((line < es->y_offset) || (line > es->y_offset + vlc) || (line >= es->line_count))
+			return;
+	} else if (line)
+		return;
+
+	TRACE("line=%d\n", line);
+
+	pos = EDIT_EM_PosFromChar(es, EDIT_EM_LineIndex(es, line), FALSE);
+	x = (short)LOWORD(pos);
+	y = (short)HIWORD(pos);
+	li = EDIT_EM_LineIndex(es, line);
+	ll = EDIT_EM_LineLength(es, li);
+	s = min(es->selection_start, es->selection_end);
+	e = max(es->selection_start, es->selection_end);
+	s = min(li + ll, max(li, s));
+	e = min(li + ll, max(li, e));
+	if (rev && (s != e) &&
+			((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) {
+		x += EDIT_PaintText(es, dc, x, y, line, 0, s - li, FALSE);
+		x += EDIT_PaintText(es, dc, x, y, line, s - li, e - s, TRUE);
+		x += EDIT_PaintText(es, dc, x, y, line, e - li, li + ll - e, FALSE);
+	} else
+		x += EDIT_PaintText(es, dc, x, y, line, 0, ll, FALSE);
 }
 
 
@@ -2419,216 +2313,6 @@ static void EDIT_SetRectNP(EDITSTATE *es, const RECT *rc)
 
 /*********************************************************************
  *
- *	EDIT_UnlockBuffer
- *
- */
-static void EDIT_UnlockBuffer(EDITSTATE *es, BOOL force)
-{
-
-	/* Edit window might be already destroyed */
-	if(!IsWindow(es->hwndSelf))
-	{
-	    WARN("edit hwnd %p already destroyed\n", es->hwndSelf);
-	    return;
-    	}
-
-	if (!es->lock_count) {
-		ERR("lock_count == 0 ... please report\n");
-		return;
-	}
-	if (!es->text) {
-		ERR("es->text == 0 ... please report\n");
-		return;
-	}
-
-	if (force || (es->lock_count == 1)) {
-	    if (es->hloc32W) {
-		CHAR *textA = NULL;
-		UINT countA = 0;
-		UINT countW = get_text_length(es) + 1;
-		STACK16FRAME* stack16 = NULL;
-	        HANDLE16 oldDS = 0;
-
-		if(es->hloc32A)
-		{
-		    UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
-		    TRACE("Synchronizing with 32-bit ANSI buffer\n");
-		    TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
-		    countA = LocalSize(es->hloc32A);
-		    if(countA_new > countA)
-		    {
-			HLOCAL hloc32A_new;
-			UINT alloc_size = ROUND_TO_GROW(countA_new);
-			TRACE("Resizing 32-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
-			hloc32A_new = LocalReAlloc(es->hloc32A, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
-			if(hloc32A_new)
-			{
-			    es->hloc32A = hloc32A_new;
-			    countA = LocalSize(hloc32A_new);
-			    TRACE("Real new size %d bytes\n", countA);
-			}
-			else
-			    WARN("FAILED! Will synchronize partially\n");
-		    }
-		    textA = LocalLock(es->hloc32A);
-		}
-		else if(es->hloc16)
-		{
-		    UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
-
-		    TRACE("Synchronizing with 16-bit ANSI buffer\n");
-		    TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
-
-		    stack16 = MapSL(PtrToUlong(NtCurrentTeb()->WOW32Reserved));
-		    oldDS = stack16->ds;
-		    stack16->ds = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
-
-		    countA = LocalSize16(es->hloc16);
-		    if(countA_new > countA)
-		    {
-			HLOCAL16 hloc16_new;
-			UINT alloc_size = ROUND_TO_GROW(countA_new);
-			TRACE("Resizing 16-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
-			hloc16_new = LocalReAlloc16(es->hloc16, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
-			if(hloc16_new)
-			{
-			    es->hloc16 = hloc16_new;
-			    countA = LocalSize16(hloc16_new);
-			    TRACE("Real new size %d bytes\n", countA);
-			}
-			else
-			    WARN("FAILED! Will synchronize partially\n");
-		    }
-		    textA = MapSL(LocalLock16(es->hloc16));
-		}
-
-		if(textA)
-		{
-		    WideCharToMultiByte(CP_ACP, 0, es->text, countW, textA, countA, NULL, NULL);
-		    if(stack16)
-			LocalUnlock16(es->hloc16);
-		    else
-			LocalUnlock(es->hloc32A);
-		}
-
-		if (stack16) stack16->ds = oldDS;
-		LocalUnlock(es->hloc32W);
-		es->text = NULL;
-	    }
-	    else {
-		ERR("no buffer ... please report\n");
-		return;
-	    }
-	}
-	es->lock_count--;
-}
-
-
-/*********************************************************************
- *
- *	EDIT_UpdateScrollInfo
- *
- */
-static void EDIT_UpdateScrollInfo(EDITSTATE *es)
-{
-    if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK))
-    {
-	SCROLLINFO si;
-	si.cbSize	= sizeof(SCROLLINFO);
-	si.fMask	= SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
-	si.nMin		= 0;
-	si.nMax		= es->line_count - 1;
-	si.nPage	= (es->format_rect.bottom - es->format_rect.top) / es->line_height;
-	si.nPos		= es->y_offset;
-	TRACE("SB_VERT, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
-		si.nMin, si.nMax, si.nPage, si.nPos);
-	SetScrollInfo(es->hwndSelf, SB_VERT, &si, TRUE);
-    }
-
-    if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK))
-    {
-	SCROLLINFO si;
-	si.cbSize	= sizeof(SCROLLINFO);
-	si.fMask	= SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
-	si.nMin		= 0;
-	si.nMax		= es->text_width - 1;
-	si.nPage	= es->format_rect.right - es->format_rect.left;
-	si.nPos		= es->x_offset;
-	TRACE("SB_HORZ, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
-		si.nMin, si.nMax, si.nPage, si.nPos);
-	SetScrollInfo(es->hwndSelf, SB_HORZ, &si, TRUE);
-    }
-}
-
-/*********************************************************************
- *
- *	EDIT_WordBreakProc
- *
- *	Find the beginning of words.
- *	Note:	unlike the specs for a WordBreakProc, this function only
- *		allows to be called without linebreaks between s[0] up to
- *		s[count - 1].  Remember it is only called
- *		internally, so we can decide this for ourselves.
- *
- */
-static INT EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action)
-{
-	INT ret = 0;
-
-	TRACE("s=%p, index=%d, count=%d, action=%d\n", s, index, count, action);
-
-	if(!s) return 0;
-
-	switch (action) {
-	case WB_LEFT:
-		if (!count)
-			break;
-		if (index)
-			index--;
-		if (s[index] == ' ') {
-			while (index && (s[index] == ' '))
-				index--;
-			if (index) {
-				while (index && (s[index] != ' '))
-					index--;
-				if (s[index] == ' ')
-					index++;
-			}
-		} else {
-			while (index && (s[index] != ' '))
-				index--;
-			if (s[index] == ' ')
-				index++;
-		}
-		ret = index;
-		break;
-	case WB_RIGHT:
-		if (!count)
-			break;
-		if (index)
-			index--;
-		if (s[index] == ' ')
-			while ((index < count) && (s[index] == ' ')) index++;
-		else {
-			while (s[index] && (s[index] != ' ') && (index < count))
-				index++;
-			while ((s[index] == ' ') && (index < count)) index++;
-		}
-		ret = index;
-		break;
-	case WB_ISDELIMITER:
-		ret = (s[index] == ' ');
-		break;
-	default:
-		ERR("unknown action code, please report !\n");
-		break;
-	}
-	return ret;
-}
-
-
-/*********************************************************************
- *
  *	EM_CHARFROMPOS
  *
  *      returns line number (not index) in high-order word of result.
@@ -2860,301 +2544,6 @@ static LRESULT EDIT_EM_GetSel(const EDITSTATE *es, PUINT start, PUINT end)
 
 /*********************************************************************
  *
- *	EM_GETTHUMB
- *
- *	FIXME: is this right ?  (or should it be only VSCROLL)
- *	(and maybe only for edit controls that really have their
- *	own scrollbars) (and maybe only for multiline controls ?)
- *	All in all: very poorly documented
- *
- */
-static LRESULT EDIT_EM_GetThumb(EDITSTATE *es)
-{
-	return MAKELONG(EDIT_WM_VScroll(es, EM_GETTHUMB16, 0),
-		EDIT_WM_HScroll(es, EM_GETTHUMB16, 0));
-}
-
-
-/*********************************************************************
- *
- *	EM_LINEFROMCHAR
- *
- */
-static INT EDIT_EM_LineFromChar(EDITSTATE *es, INT index)
-{
-	INT line;
-	LINEDEF *line_def;
-
-	if (!(es->style & ES_MULTILINE))
-		return 0;
-	if (index > (INT)get_text_length(es))
-		return es->line_count - 1;
-	if (index == -1)
-		index = min(es->selection_start, es->selection_end);
-
-	line = 0;
-	line_def = es->first_line_def;
-	index -= line_def->length;
-	while ((index >= 0) && line_def->next) {
-		line++;
-		line_def = line_def->next;
-		index -= line_def->length;
-	}
-	return line;
-}
-
-
-/*********************************************************************
- *
- *	EM_LINEINDEX
- *
- */
-static INT EDIT_EM_LineIndex(const EDITSTATE *es, INT line)
-{
-	INT line_index;
-	const LINEDEF *line_def;
-
-	if (!(es->style & ES_MULTILINE))
-		return 0;
-	if (line >= es->line_count)
-		return -1;
-
-	line_index = 0;
-	line_def = es->first_line_def;
-	if (line == -1) {
-		INT index = es->selection_end - line_def->length;
-		while ((index >= 0) && line_def->next) {
-			line_index += line_def->length;
-			line_def = line_def->next;
-			index -= line_def->length;
-		}
-	} else {
-		while (line > 0) {
-			line_index += line_def->length;
-			line_def = line_def->next;
-			line--;
-		}
-	}
-	return line_index;
-}
-
-
-/*********************************************************************
- *
- *	EM_LINELENGTH
- *
- */
-static INT EDIT_EM_LineLength(EDITSTATE *es, INT index)
-{
-	LINEDEF *line_def;
-
-	if (!(es->style & ES_MULTILINE))
-		return get_text_length(es);
-
-	if (index == -1) {
-		/* get the number of remaining non-selected chars of selected lines */
-		INT32 l; /* line number */
-		INT32 li; /* index of first char in line */
-		INT32 count;
-		l = EDIT_EM_LineFromChar(es, es->selection_start);
-		/* # chars before start of selection area */
-		count = es->selection_start - EDIT_EM_LineIndex(es, l);
-		l = EDIT_EM_LineFromChar(es, es->selection_end);
-		/* # chars after end of selection */
-		li = EDIT_EM_LineIndex(es, l);
-		count += li + EDIT_EM_LineLength(es, li) - es->selection_end;
-		return count;
-	}
-	line_def = es->first_line_def;
-	index -= line_def->length;
-	while ((index >= 0) && line_def->next) {
-		line_def = line_def->next;
-		index -= line_def->length;
-	}
-	return line_def->net_length;
-}
-
-
-/*********************************************************************
- *
- *	EM_LINESCROLL
- *
- *	NOTE: dx is in average character widths, dy - in lines;
- *
- */
-static BOOL EDIT_EM_LineScroll(EDITSTATE *es, INT dx, INT dy)
-{
-	if (!(es->style & ES_MULTILINE))
-		return FALSE;
-
-	dx *= es->char_width;
-	return EDIT_EM_LineScroll_internal(es, dx, dy);
-}
-
-/*********************************************************************
- *
- *	EDIT_EM_LineScroll_internal
- *
- *	Version of EDIT_EM_LineScroll for internal use.
- *	It doesn't refuse if ES_MULTILINE is set and assumes that
- *	dx is in pixels, dy - in lines.
- *
- */
-static BOOL EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy)
-{
-	INT nyoff;
-	INT x_offset_in_pixels;
-	INT lines_per_page = (es->format_rect.bottom - es->format_rect.top) /
-			      es->line_height;
-
-	if (es->style & ES_MULTILINE)
-	{
-	    x_offset_in_pixels = es->x_offset;
-	}
-	else
-	{
-	    dy = 0;
-	    x_offset_in_pixels = (short)LOWORD(EDIT_EM_PosFromChar(es, es->x_offset, FALSE));
-	}
-
-	if (-dx > x_offset_in_pixels)
-		dx = -x_offset_in_pixels;
-	if (dx > es->text_width - x_offset_in_pixels)
-		dx = es->text_width - x_offset_in_pixels;
-	nyoff = max(0, es->y_offset + dy);
-	if (nyoff >= es->line_count - lines_per_page)
-		nyoff = max(0, es->line_count - lines_per_page);
-	dy = (es->y_offset - nyoff) * es->line_height;
-	if (dx || dy) {
-		RECT rc1;
-		RECT rc;
-
-		es->y_offset = nyoff;
-		if(es->style & ES_MULTILINE)
-		    es->x_offset += dx;
-		else
-		    es->x_offset += dx / es->char_width;
-
-		GetClientRect(es->hwndSelf, &rc1);
-		IntersectRect(&rc, &rc1, &es->format_rect);
-		ScrollWindowEx(es->hwndSelf, -dx, dy,
-				NULL, &rc, NULL, NULL, SW_INVALIDATE);
-		/* force scroll info update */
-		EDIT_UpdateScrollInfo(es);
-	}
-	if (dx && !(es->flags & EF_HSCROLL_TRACK))
-		EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
-	if (dy && !(es->flags & EF_VSCROLL_TRACK))
-		EDIT_NOTIFY_PARENT(es, EN_VSCROLL);
-	return TRUE;
-}
-
-
-/*********************************************************************
- *
- *	EM_POSFROMCHAR
- *
- */
-static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
-{
-	INT len = get_text_length(es);
-	INT l;
-	INT li;
-	INT x;
-	INT y = 0;
-	INT w;
-	INT lw = 0;
-	INT ll = 0;
-	HDC dc;
-	HFONT old_font = 0;
-	SIZE size;
-	LINEDEF *line_def;
-
-	index = min(index, len);
-	dc = GetDC(es->hwndSelf);
-	if (es->font)
-		old_font = SelectObject(dc, es->font);
-	if (es->style & ES_MULTILINE) {
-		l = EDIT_EM_LineFromChar(es, index);
-		y = (l - es->y_offset) * es->line_height;
-		li = EDIT_EM_LineIndex(es, l);
-		if (after_wrap && (li == index) && l) {
-			INT l2 = l - 1;
-			line_def = es->first_line_def;
-			while (l2) {
-				line_def = line_def->next;
-				l2--;
-			}
-			if (line_def->ending == END_WRAP) {
-				l--;
-				y -= es->line_height;
-				li = EDIT_EM_LineIndex(es, l);
-			}
-		}
-
-		line_def = es->first_line_def;
-		while (line_def->index != li)
-			line_def = line_def->next;
-
-		ll = line_def->net_length;
-		lw = line_def->width;
-
-		w = es->format_rect.right - es->format_rect.left;
-		if (es->style & ES_RIGHT)
-		{
-			x = LOWORD(GetTabbedTextExtentW(dc, es->text + li + (index - li), ll - (index - li),
-				es->tabs_count, es->tabs)) - es->x_offset;
-			x = w - x;
-		}
-		else if (es->style & ES_CENTER)
-		{
-			x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
-				es->tabs_count, es->tabs)) - es->x_offset;
-			x += (w - lw) / 2;
-		}
-		else /* ES_LEFT */
-		{
-		    x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
-				es->tabs_count, es->tabs)) - es->x_offset;
-		}
-	} else {
-		LPWSTR text = EDIT_GetPasswordPointer_SL(es);
-		if (index < es->x_offset) {
-			GetTextExtentPoint32W(dc, text + index,
-					es->x_offset - index, &size);
-			x = -size.cx;
-		} else {
-			GetTextExtentPoint32W(dc, text + es->x_offset,
-					index - es->x_offset, &size);
-			 x = size.cx;
-
-			if (!es->x_offset && (es->style & (ES_RIGHT | ES_CENTER)))
-			{
-				w = es->format_rect.right - es->format_rect.left;
-				if (w > es->text_width)
-				{
-					if (es->style & ES_RIGHT)
-						x += w - es->text_width;
-					else if (es->style & ES_CENTER)
-						x += (w - es->text_width) / 2;
-				}
-			}
-		}
-		y = 0;
-		if (es->style & ES_PASSWORD)
-			HeapFree(GetProcessHeap(), 0, text);
-	}
-	x += es->format_rect.left;
-	y += es->format_rect.top;
-	if (es->font)
-		SelectObject(dc, old_font);
-	ReleaseDC(es->hwndSelf, dc);
-	return MAKELONG((INT16)x, (INT16)y);
-}
-
-
-/*********************************************************************
- *
  *	EM_REPLACESEL
  *
  *	FIXME: handle ES_NUMBER and ES_OEMCONVERT here
@@ -3363,124 +2752,6 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replac
 
 /*********************************************************************
  *
- *	EM_SCROLL
- *
- */
-static LRESULT EDIT_EM_Scroll(EDITSTATE *es, INT action)
-{
-	INT dy;
-
-	if (!(es->style & ES_MULTILINE))
-		return (LRESULT)FALSE;
-
-	dy = 0;
-
-	switch (action) {
-	case SB_LINEUP:
-		if (es->y_offset)
-			dy = -1;
-		break;
-	case SB_LINEDOWN:
-		if (es->y_offset < es->line_count - 1)
-			dy = 1;
-		break;
-	case SB_PAGEUP:
-		if (es->y_offset)
-			dy = -(es->format_rect.bottom - es->format_rect.top) / es->line_height;
-		break;
-	case SB_PAGEDOWN:
-		if (es->y_offset < es->line_count - 1)
-			dy = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
-		break;
-	default:
-		return (LRESULT)FALSE;
-	}
-	if (dy) {
-	    INT vlc = get_vertical_line_count(es);
-	    /* check if we are going to move too far */
-	    if(es->y_offset + dy > es->line_count - vlc)
-		dy = es->line_count - vlc - es->y_offset;
-
-	    /* Notification is done in EDIT_EM_LineScroll */
-	    if(dy)
-		EDIT_EM_LineScroll(es, 0, dy);
-	}
-	return MAKELONG((INT16)dy, (BOOL16)TRUE);
-}
-
-
-/*********************************************************************
- *
- *	EM_SCROLLCARET
- *
- */
-static void EDIT_EM_ScrollCaret(EDITSTATE *es)
-{
-	if (es->style & ES_MULTILINE) {
-		INT l;
-		INT vlc;
-		INT ww;
-		INT cw = es->char_width;
-		INT x;
-		INT dy = 0;
-		INT dx = 0;
-
-		l = EDIT_EM_LineFromChar(es, es->selection_end);
-		x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP));
-		vlc = get_vertical_line_count(es);
-		if (l >= es->y_offset + vlc)
-			dy = l - vlc + 1 - es->y_offset;
-		if (l < es->y_offset)
-			dy = l - es->y_offset;
-		ww = es->format_rect.right - es->format_rect.left;
-		if (x < es->format_rect.left)
-			dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw;
-		if (x > es->format_rect.right)
-			dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
-		if (dy || dx || (es->y_offset && (es->line_count - es->y_offset < vlc)))
-		{
-		    /* check if we are going to move too far */
-		    if(es->x_offset + dx + ww > es->text_width)
-			dx = es->text_width - ww - es->x_offset;
-		    if(dx || dy || (es->y_offset && (es->line_count - es->y_offset < vlc)))
-			EDIT_EM_LineScroll_internal(es, dx, dy);
-		}
-	} else {
-		INT x;
-		INT goal;
-		INT format_width;
-
-		x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
-		format_width = es->format_rect.right - es->format_rect.left;
-		if (x < es->format_rect.left) {
-			goal = es->format_rect.left + format_width / HSCROLL_FRACTION;
-			do {
-				es->x_offset--;
-				x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
-			} while ((x < goal) && es->x_offset);
-			/* FIXME: use ScrollWindow() somehow to improve performance */
-			EDIT_UpdateText(es, NULL, TRUE);
-		} else if (x > es->format_rect.right) {
-			INT x_last;
-			INT len = get_text_length(es);
-			goal = es->format_rect.right - format_width / HSCROLL_FRACTION;
-			do {
-				es->x_offset++;
-				x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
-				x_last = (short)LOWORD(EDIT_EM_PosFromChar(es, len, FALSE));
-			} while ((x > goal) && (x_last > es->format_rect.right));
-			/* FIXME: use ScrollWindow() somehow to improve performance */
-			EDIT_UpdateText(es, NULL, TRUE);
-		}
-	}
-
-    if(es->flags & EF_FOCUSED)
-	EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP);
-}
-
-
-/*********************************************************************
- *
  *	EM_SETHANDLE
  *
  *	FIXME:	ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
@@ -3765,76 +3036,6 @@ static void EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c)
 
 /*********************************************************************
  *
- *	EDIT_EM_SetSel
- *
- *	note:	unlike the specs say: the order of start and end
- *		_is_ preserved in Windows.  (i.e. start can be > end)
- *		In other words: this handler is OK
- *
- */
-static void EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap)
-{
-	UINT old_start = es->selection_start;
-	UINT old_end = es->selection_end;
-	UINT len = get_text_length(es);
-
-	if (start == (UINT)-1) {
-		start = es->selection_end;
-		end = es->selection_end;
-	} else {
-		start = min(start, len);
-		end = min(end, len);
-	}
-	es->selection_start = start;
-	es->selection_end = end;
-	if (after_wrap)
-		es->flags |= EF_AFTER_WRAP;
-	else
-		es->flags &= ~EF_AFTER_WRAP;
-	/* Compute the necessary invalidation region. */
-	/* Note that we don't need to invalidate regions which have
-	 * "never" been selected, or those which are "still" selected.
-	 * In fact, every time we hit a selection boundary, we can
-	 * *toggle* whether we need to invalidate.  Thus we can optimize by
-	 * *sorting* the interval endpoints.  Let's assume that we sort them
-	 * in this order:
-	 *        start <= end <= old_start <= old_end
-	 * Knuth 5.3.1 (p 183) assures us that this can be done optimally
-	 * in 5 comparisons; i.e. it is impossible to do better than the
-	 * following: */
-        ORDER_UINT(end, old_end);
-        ORDER_UINT(start, old_start);
-        ORDER_UINT(old_start, old_end);
-        ORDER_UINT(start, end);
-	/* Note that at this point 'end' and 'old_start' are not in order, but
-	 * start is definitely the min. and old_end is definitely the max. */
-	if (end != old_start)
-        {
-/*
- * One can also do
- *          ORDER_UINT32(end, old_start);
- *          EDIT_InvalidateText(es, start, end);
- *          EDIT_InvalidateText(es, old_start, old_end);
- * in place of the following if statement.
- * (That would complete the optimal five-comparison four-element sort.)
- */
-            if (old_start > end )
-            {
-                EDIT_InvalidateText(es, start, end);
-                EDIT_InvalidateText(es, old_start, old_end);
-            }
-            else
-            {
-                EDIT_InvalidateText(es, start, old_start);
-                EDIT_InvalidateText(es, end, old_end);
-            }
-	}
-        else EDIT_InvalidateText(es, start, old_end);
-}
-
-
-/*********************************************************************
- *
  *	EM_SETTABSTOPS
  *
  */
@@ -3983,6 +3184,93 @@ static BOOL EDIT_IsInsideDialog(EDITSTATE *es)
 
 /*********************************************************************
  *
+ *	WM_PASTE
+ *
+ */
+static void EDIT_WM_Paste(EDITSTATE *es)
+{
+	HGLOBAL hsrc;
+	LPWSTR src;
+
+	/* Protect read-only edit control from modification */
+	if(es->style & ES_READONLY)
+	    return;
+
+	OpenClipboard(es->hwndSelf);
+	if ((hsrc = GetClipboardData(CF_UNICODETEXT))) {
+		src = GlobalLock(hsrc);
+		EDIT_EM_ReplaceSel(es, TRUE, src, TRUE, TRUE);
+		GlobalUnlock(hsrc);
+	}
+        else if (es->style & ES_PASSWORD) {
+            /* clear selected text in password edit box even with empty clipboard */
+            const WCHAR empty_strW[] = { 0 };
+            EDIT_EM_ReplaceSel(es, TRUE, empty_strW, TRUE, TRUE);
+        }
+	CloseClipboard();
+}
+
+
+/*********************************************************************
+ *
+ *	WM_COPY
+ *
+ */
+static void EDIT_WM_Copy(EDITSTATE *es)
+{
+	INT s = min(es->selection_start, es->selection_end);
+	INT e = max(es->selection_start, es->selection_end);
+	HGLOBAL hdst;
+	LPWSTR dst;
+	DWORD len;
+
+	if (e == s) return;
+
+	len = e - s;
+	hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (len + 1) * sizeof(WCHAR));
+	dst = GlobalLock(hdst);
+	memcpy(dst, es->text + s, len * sizeof(WCHAR));
+	dst[len] = 0; /* ensure 0 termination */
+	TRACE("%s\n", debugstr_w(dst));
+	GlobalUnlock(hdst);
+	OpenClipboard(es->hwndSelf);
+	EmptyClipboard();
+	SetClipboardData(CF_UNICODETEXT, hdst);
+	CloseClipboard();
+}
+
+
+/*********************************************************************
+ *
+ *	WM_CLEAR
+ *
+ */
+static inline void EDIT_WM_Clear(EDITSTATE *es)
+{
+	static const WCHAR empty_stringW[] = {0};
+
+	/* Protect read-only edit control from modification */
+	if(es->style & ES_READONLY)
+	    return;
+
+	EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
+}
+
+
+/*********************************************************************
+ *
+ *	WM_CUT
+ *
+ */
+static inline void EDIT_WM_Cut(EDITSTATE *es)
+{
+	EDIT_WM_Copy(es);
+	EDIT_WM_Clear(es);
+}
+
+
+/*********************************************************************
+ *
  *	WM_CHAR
  *
  */
@@ -4159,125 +3447,6 @@ static void EDIT_WM_ContextMenu(EDITSTATE *es, INT x, INT y)
 
 /*********************************************************************
  *
- *	WM_COPY
- *
- */
-static void EDIT_WM_Copy(EDITSTATE *es)
-{
-	INT s = min(es->selection_start, es->selection_end);
-	INT e = max(es->selection_start, es->selection_end);
-	HGLOBAL hdst;
-	LPWSTR dst;
-	DWORD len;
-
-	if (e == s) return;
-
-	len = e - s;
-	hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (len + 1) * sizeof(WCHAR));
-	dst = GlobalLock(hdst);
-	memcpy(dst, es->text + s, len * sizeof(WCHAR));
-	dst[len] = 0; /* ensure 0 termination */
-	TRACE("%s\n", debugstr_w(dst));
-	GlobalUnlock(hdst);
-	OpenClipboard(es->hwndSelf);
-	EmptyClipboard();
-	SetClipboardData(CF_UNICODETEXT, hdst);
-	CloseClipboard();
-}
-
-
-/*********************************************************************
- *
- *	WM_CREATE
- *
- */
-static LRESULT EDIT_WM_Create(EDITSTATE *es, LPCWSTR name)
-{
-        RECT clientRect;
-        
-	TRACE("%s\n", debugstr_w(name));
-       /*
-        *	To initialize some final structure members, we call some helper
-        *	functions.  However, since the EDITSTATE is not consistent (i.e.
-        *	not fully initialized), we should be very careful which
-        *	functions can be called, and in what order.
-        */
-        EDIT_WM_SetFont(es, 0, FALSE);
-        EDIT_EM_EmptyUndoBuffer(es);
-        
-        /* We need to calculate the format rect
-           (applications may send EM_SETMARGINS before the control gets visible) */
-        GetClientRect(es->hwndSelf, &clientRect);
-        EDIT_SetRectNP(es, &clientRect);
-
-       if (name && *name) {
-	   EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, FALSE);
-	   /* if we insert text to the editline, the text scrolls out
-            * of the window, as the caret is placed after the insert
-            * pos normally; thus we reset es->selection... to 0 and
-            * update caret
-            */
-	   es->selection_start = es->selection_end = 0;
-           /* Adobe Photoshop does NOT like this. and MSDN says that EN_CHANGE
-            * Messages are only to be sent when the USER does something to
-            * change the contents. So I am removing this EN_CHANGE
-            *
-            * EDIT_NOTIFY_PARENT(es, EN_CHANGE);
-            */
-	   EDIT_EM_ScrollCaret(es);
-       }
-       /* force scroll info update */
-       EDIT_UpdateScrollInfo(es);
-       /* The rule seems to return 1 here for success */
-       /* Power Builder masked edit controls will crash  */
-       /* if not. */
-       /* FIXME: is that in all cases so ? */
-       return 1;
-}
-
-
-/*********************************************************************
- *
- *	WM_DESTROY
- *
- */
-static LRESULT EDIT_WM_Destroy(EDITSTATE *es)
-{
-	LINEDEF *pc, *pp;
-
-	if (es->hloc32W) {
-		LocalFree(es->hloc32W);
-	}
-	if (es->hloc32A) {
-		LocalFree(es->hloc32A);
-	}
-	if (es->hloc16) {
-		STACK16FRAME* stack16 = MapSL(PtrToUlong(NtCurrentTeb()->WOW32Reserved));
-		HANDLE16 oldDS = stack16->ds;
-
-		stack16->ds = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
-		while (LocalUnlock16(es->hloc16)) ;
-		LocalFree16(es->hloc16);
-		stack16->ds = oldDS;
-	}
-
-	pc = es->first_line_def;
-	while (pc)
-	{
-		pp = pc->next;
-		HeapFree(GetProcessHeap(), 0, pc);
-		pc = pp;
-	}
-
-        SetWindowLongPtrW( es->hwndSelf, 0, 0 );
-	HeapFree(GetProcessHeap(), 0, es);
-
-	return 0;
-}
-
-
-/*********************************************************************
- *
  *	WM_GETTEXT
  *
  */
@@ -4301,139 +3470,6 @@ static INT EDIT_WM_GetText(const EDITSTATE *es, INT count, LPWSTR dst, BOOL unic
 
 /*********************************************************************
  *
- *	WM_HSCROLL
- *
- */
-static LRESULT EDIT_WM_HScroll(EDITSTATE *es, INT action, INT pos)
-{
-	INT dx;
-	INT fw;
-
-	if (!(es->style & ES_MULTILINE))
-		return 0;
-
-	if (!(es->style & ES_AUTOHSCROLL))
-		return 0;
-
-	dx = 0;
-	fw = es->format_rect.right - es->format_rect.left;
-	switch (action) {
-	case SB_LINELEFT:
-		TRACE("SB_LINELEFT\n");
-		if (es->x_offset)
-			dx = -es->char_width;
-		break;
-	case SB_LINERIGHT:
-		TRACE("SB_LINERIGHT\n");
-		if (es->x_offset < es->text_width)
-			dx = es->char_width;
-		break;
-	case SB_PAGELEFT:
-		TRACE("SB_PAGELEFT\n");
-		if (es->x_offset)
-			dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
-		break;
-	case SB_PAGERIGHT:
-		TRACE("SB_PAGERIGHT\n");
-		if (es->x_offset < es->text_width)
-			dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
-		break;
-	case SB_LEFT:
-		TRACE("SB_LEFT\n");
-		if (es->x_offset)
-			dx = -es->x_offset;
-		break;
-	case SB_RIGHT:
-		TRACE("SB_RIGHT\n");
-		if (es->x_offset < es->text_width)
-			dx = es->text_width - es->x_offset;
-		break;
-	case SB_THUMBTRACK:
-		TRACE("SB_THUMBTRACK %d\n", pos);
-		es->flags |= EF_HSCROLL_TRACK;
-		if(es->style & WS_HSCROLL)
-		    dx = pos - es->x_offset;
-		else
-		{
-		    INT fw, new_x;
-		    /* Sanity check */
-		    if(pos < 0 || pos > 100) return 0;
-		    /* Assume default scroll range 0-100 */
-		    fw = es->format_rect.right - es->format_rect.left;
-		    new_x = pos * (es->text_width - fw) / 100;
-		    dx = es->text_width ? (new_x - es->x_offset) : 0;
-		}
-		break;
-	case SB_THUMBPOSITION:
-		TRACE("SB_THUMBPOSITION %d\n", pos);
-		es->flags &= ~EF_HSCROLL_TRACK;
-		if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_HSCROLL)
-		    dx = pos - es->x_offset;
-		else
-		{
-		    INT fw, new_x;
-		    /* Sanity check */
-		    if(pos < 0 || pos > 100) return 0;
-		    /* Assume default scroll range 0-100 */
-		    fw = es->format_rect.right - es->format_rect.left;
-		    new_x = pos * (es->text_width - fw) / 100;
-		    dx = es->text_width ? (new_x - es->x_offset) : 0;
-		}
-		if (!dx) {
-			/* force scroll info update */
-			EDIT_UpdateScrollInfo(es);
-			EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
-		}
-		break;
-	case SB_ENDSCROLL:
-		TRACE("SB_ENDSCROLL\n");
-		break;
-	/*
-	 *	FIXME : the next two are undocumented !
-	 *	Are we doing the right thing ?
-	 *	At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
-	 *	although it's also a regular control message.
-	 */
-	case EM_GETTHUMB: /* this one is used by NT notepad */
-	case EM_GETTHUMB16:
-	{
-		LRESULT ret;
-		if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_HSCROLL)
-		    ret = GetScrollPos(es->hwndSelf, SB_HORZ);
-		else
-		{
-		    /* Assume default scroll range 0-100 */
-		    INT fw = es->format_rect.right - es->format_rect.left;
-		    ret = es->text_width ? es->x_offset * 100 / (es->text_width - fw) : 0;
-		}
-		TRACE("EM_GETTHUMB: returning %ld\n", ret);
-		return ret;
-	}
-	case EM_LINESCROLL16:
-		TRACE("EM_LINESCROLL16\n");
-		dx = pos;
-		break;
-
-	default:
-		ERR("undocumented WM_HSCROLL action %d (0x%04x), please report\n",
-                    action, action);
-		return 0;
-	}
-	if (dx)
-	{
-	    INT fw = es->format_rect.right - es->format_rect.left;
-	    /* check if we are going to move too far */
-	    if(es->x_offset + dx + fw > es->text_width)
-		dx = es->text_width - fw - es->x_offset;
-	    if(dx)
-		EDIT_EM_LineScroll_internal(es, dx, 0);
-	}
-	return 0;
-}
-
-
-/*********************************************************************
- *
  *	EDIT_CheckCombo
  *
  */
@@ -4758,111 +3794,6 @@ static LRESULT EDIT_WM_MouseMove(EDITSTATE *es, INT x, INT y)
 
 /*********************************************************************
  *
- *	WM_NCCREATE
- *
- * See also EDIT_WM_StyleChanged
- */
-static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode)
-{
-	EDITSTATE *es;
-	UINT alloc_size;
-
-	TRACE("Creating %s edit control, style = %08x\n",
-		unicode ? "Unicode" : "ANSI", lpcs->style);
-
-	if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
-		return FALSE;
-        SetWindowLongPtrW( hwnd, 0, (LONG_PTR)es );
-
-       /*
-        *      Note: since the EDITSTATE has not been fully initialized yet,
-        *            we can't use any API calls that may send
-        *            WM_XXX messages before WM_NCCREATE is completed.
-        */
-
- 	es->is_unicode = unicode;
- 	es->style = lpcs->style;
-
-        es->bEnableState = !(es->style & WS_DISABLED);
-
-	es->hwndSelf = hwnd;
-	/* Save parent, which will be notified by EN_* messages */
-	es->hwndParent = lpcs->hwndParent;
-
-	if (es->style & ES_COMBO)
-	   es->hwndListBox = GetDlgItem(es->hwndParent, ID_CB_LISTBOX);
-
-        /* FIXME: should we handle changes to WS_EX_RIGHT style after creation? */
-        if (lpcs->dwExStyle & WS_EX_RIGHT) es->style |= ES_RIGHT;
-
-        /* Number overrides lowercase overrides uppercase (at least it
-         * does in Win95).  However I'll bet that ES_NUMBER would be
-         * invalid under Win 3.1.
-         */
-        if (es->style & ES_NUMBER) {
-                ; /* do not override the ES_NUMBER */
-        }  else if (es->style & ES_LOWERCASE) {
-                es->style &= ~ES_UPPERCASE;
-        }
-	if (es->style & ES_MULTILINE) {
-		es->buffer_limit = BUFLIMIT_INITIAL;
-		if (es->style & WS_VSCROLL)
-			es->style |= ES_AUTOVSCROLL;
-		if (es->style & WS_HSCROLL)
-			es->style |= ES_AUTOHSCROLL;
-		es->style &= ~ES_PASSWORD;
-		if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) {
-                        /* Confirmed - RIGHT overrides CENTER */
-			if (es->style & ES_RIGHT)
-				es->style &= ~ES_CENTER;
-			es->style &= ~WS_HSCROLL;
-			es->style &= ~ES_AUTOHSCROLL;
-		}
-	} else {
-		es->buffer_limit = BUFLIMIT_INITIAL;
-		if ((es->style & ES_RIGHT) && (es->style & ES_CENTER))
-			es->style &= ~ES_CENTER;
-		es->style &= ~WS_HSCROLL;
-		es->style &= ~WS_VSCROLL;
-		if (es->style & ES_PASSWORD)
-			es->password_char = '*';
-	}
-
-	alloc_size = ROUND_TO_GROW((es->buffer_size + 1) * sizeof(WCHAR));
-	if(!(es->hloc32W = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
-	    return FALSE;
-	es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
-
-	if (!(es->undo_text = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (es->buffer_size + 1) * sizeof(WCHAR))))
-		return FALSE;
-	es->undo_buffer_size = es->buffer_size;
-
-	if (es->style & ES_MULTILINE)
-		if (!(es->first_line_def = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF))))
-			return FALSE;
-	es->line_count = 1;
-
-	/*
-	 * In Win95 look and feel, the WS_BORDER style is replaced by the
-	 * WS_EX_CLIENTEDGE style for the edit control. This gives the edit
-	 * control a nonclient area so we don't need to draw the border.
-         * If WS_BORDER without WS_EX_CLIENTEDGE is specified we shouldn't have
-         * a nonclient area and we should handle painting the border ourselves.
-         *
-         * When making modifications please ensure that the code still works 
-         * for edit controls created directly with style 0x50800000, exStyle 0
-         * (which should have a single pixel border)
-	 */
-	if (lpcs->dwExStyle & WS_EX_CLIENTEDGE)
-		es->style &= ~WS_BORDER;
-        else if (es->style & WS_BORDER)
-		SetWindowLongW(hwnd, GWL_STYLE, es->style & ~WS_BORDER);
-
-	return TRUE;
-}
-
-/*********************************************************************
- *
  *	WM_PAINT
  *
  */
@@ -4953,35 +3884,6 @@ static void EDIT_WM_Paint(EDITSTATE *es, HDC hdc)
 
 /*********************************************************************
  *
- *	WM_PASTE
- *
- */
-static void EDIT_WM_Paste(EDITSTATE *es)
-{
-	HGLOBAL hsrc;
-	LPWSTR src;
-
-	/* Protect read-only edit control from modification */
-	if(es->style & ES_READONLY)
-	    return;
-
-	OpenClipboard(es->hwndSelf);
-	if ((hsrc = GetClipboardData(CF_UNICODETEXT))) {
-		src = GlobalLock(hsrc);
-		EDIT_EM_ReplaceSel(es, TRUE, src, TRUE, TRUE);
-		GlobalUnlock(hsrc);
-	}
-        else if (es->style & ES_PASSWORD) {
-            /* clear selected text in password edit box even with empty clipboard */
-            const WCHAR empty_strW[] = { 0 };
-            EDIT_EM_ReplaceSel(es, TRUE, empty_strW, TRUE, TRUE);
-        }
-	CloseClipboard();
-}
-
-
-/*********************************************************************
- *
  *	WM_SETFOCUS
  *
  */
@@ -5233,6 +4135,139 @@ static void EDIT_WM_Timer(EDITSTATE *es)
 
 /*********************************************************************
  *
+ *	WM_HSCROLL
+ *
+ */
+static LRESULT EDIT_WM_HScroll(EDITSTATE *es, INT action, INT pos)
+{
+	INT dx;
+	INT fw;
+
+	if (!(es->style & ES_MULTILINE))
+		return 0;
+
+	if (!(es->style & ES_AUTOHSCROLL))
+		return 0;
+
+	dx = 0;
+	fw = es->format_rect.right - es->format_rect.left;
+	switch (action) {
+	case SB_LINELEFT:
+		TRACE("SB_LINELEFT\n");
+		if (es->x_offset)
+			dx = -es->char_width;
+		break;
+	case SB_LINERIGHT:
+		TRACE("SB_LINERIGHT\n");
+		if (es->x_offset < es->text_width)
+			dx = es->char_width;
+		break;
+	case SB_PAGELEFT:
+		TRACE("SB_PAGELEFT\n");
+		if (es->x_offset)
+			dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
+		break;
+	case SB_PAGERIGHT:
+		TRACE("SB_PAGERIGHT\n");
+		if (es->x_offset < es->text_width)
+			dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
+		break;
+	case SB_LEFT:
+		TRACE("SB_LEFT\n");
+		if (es->x_offset)
+			dx = -es->x_offset;
+		break;
+	case SB_RIGHT:
+		TRACE("SB_RIGHT\n");
+		if (es->x_offset < es->text_width)
+			dx = es->text_width - es->x_offset;
+		break;
+	case SB_THUMBTRACK:
+		TRACE("SB_THUMBTRACK %d\n", pos);
+		es->flags |= EF_HSCROLL_TRACK;
+		if(es->style & WS_HSCROLL)
+		    dx = pos - es->x_offset;
+		else
+		{
+		    INT fw, new_x;
+		    /* Sanity check */
+		    if(pos < 0 || pos > 100) return 0;
+		    /* Assume default scroll range 0-100 */
+		    fw = es->format_rect.right - es->format_rect.left;
+		    new_x = pos * (es->text_width - fw) / 100;
+		    dx = es->text_width ? (new_x - es->x_offset) : 0;
+		}
+		break;
+	case SB_THUMBPOSITION:
+		TRACE("SB_THUMBPOSITION %d\n", pos);
+		es->flags &= ~EF_HSCROLL_TRACK;
+		if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_HSCROLL)
+		    dx = pos - es->x_offset;
+		else
+		{
+		    INT fw, new_x;
+		    /* Sanity check */
+		    if(pos < 0 || pos > 100) return 0;
+		    /* Assume default scroll range 0-100 */
+		    fw = es->format_rect.right - es->format_rect.left;
+		    new_x = pos * (es->text_width - fw) / 100;
+		    dx = es->text_width ? (new_x - es->x_offset) : 0;
+		}
+		if (!dx) {
+			/* force scroll info update */
+			EDIT_UpdateScrollInfo(es);
+			EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
+		}
+		break;
+	case SB_ENDSCROLL:
+		TRACE("SB_ENDSCROLL\n");
+		break;
+	/*
+	 *	FIXME : the next two are undocumented !
+	 *	Are we doing the right thing ?
+	 *	At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
+	 *	although it's also a regular control message.
+	 */
+	case EM_GETTHUMB: /* this one is used by NT notepad */
+	case EM_GETTHUMB16:
+	{
+		LRESULT ret;
+		if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_HSCROLL)
+		    ret = GetScrollPos(es->hwndSelf, SB_HORZ);
+		else
+		{
+		    /* Assume default scroll range 0-100 */
+		    INT fw = es->format_rect.right - es->format_rect.left;
+		    ret = es->text_width ? es->x_offset * 100 / (es->text_width - fw) : 0;
+		}
+		TRACE("EM_GETTHUMB: returning %ld\n", ret);
+		return ret;
+	}
+	case EM_LINESCROLL16:
+		TRACE("EM_LINESCROLL16\n");
+		dx = pos;
+		break;
+
+	default:
+		ERR("undocumented WM_HSCROLL action %d (0x%04x), please report\n",
+                    action, action);
+		return 0;
+	}
+	if (dx)
+	{
+	    INT fw = es->format_rect.right - es->format_rect.left;
+	    /* check if we are going to move too far */
+	    if(es->x_offset + dx + fw > es->text_width)
+		dx = es->text_width - fw - es->x_offset;
+	    if(dx)
+		EDIT_EM_LineScroll_internal(es, dx, 0);
+	}
+	return 0;
+}
+
+
+/*********************************************************************
+ *
  *	WM_VSCROLL
  *
  */
@@ -5349,33 +4384,21 @@ static LRESULT EDIT_WM_VScroll(EDITSTATE *es, INT action, INT pos)
 
 /*********************************************************************
  *
- *	EDIT_UpdateText
- *
- */
-static void EDIT_UpdateTextRegion(EDITSTATE *es, HRGN hrgn, BOOL bErase)
-{
-    if (es->flags & EF_UPDATE) {
-        es->flags &= ~EF_UPDATE;
-        EDIT_NOTIFY_PARENT(es, EN_UPDATE);
-    }
-    InvalidateRgn(es->hwndSelf, hrgn, bErase);
-}
-
-
-/*********************************************************************
+ *	EM_GETTHUMB
  *
- *	EDIT_UpdateText
+ *	FIXME: is this right ?  (or should it be only VSCROLL)
+ *	(and maybe only for edit controls that really have their
+ *	own scrollbars) (and maybe only for multiline controls ?)
+ *	All in all: very poorly documented
  *
  */
-static void EDIT_UpdateText(EDITSTATE *es, const RECT *rc, BOOL bErase)
+static LRESULT EDIT_EM_GetThumb(EDITSTATE *es)
 {
-    if (es->flags & EF_UPDATE) {
-        es->flags &= ~EF_UPDATE;
-        EDIT_NOTIFY_PARENT(es, EN_UPDATE);
-    }
-    InvalidateRect(es->hwndSelf, rc, bErase);
+	return MAKELONG(EDIT_WM_VScroll(es, EM_GETTHUMB16, 0),
+		EDIT_WM_HScroll(es, EM_GETTHUMB16, 0));
 }
 
+
 /********************************************************************
  * 
  * The Following code is to handle inline editing from IMEs
@@ -5511,3 +4534,898 @@ static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es)
     ImmReleaseContext(hwnd, hIMC);
     EDIT_SetCaretPos(es, es->selection_start + cursor, es->flags & EF_AFTER_WRAP);
 }
+
+
+/*********************************************************************
+ *
+ *	WM_NCCREATE
+ *
+ * See also EDIT_WM_StyleChanged
+ */
+static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode)
+{
+	EDITSTATE *es;
+	UINT alloc_size;
+
+	TRACE("Creating %s edit control, style = %08x\n",
+		unicode ? "Unicode" : "ANSI", lpcs->style);
+
+	if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
+		return FALSE;
+        SetWindowLongPtrW( hwnd, 0, (LONG_PTR)es );
+
+       /*
+        *      Note: since the EDITSTATE has not been fully initialized yet,
+        *            we can't use any API calls that may send
+        *            WM_XXX messages before WM_NCCREATE is completed.
+        */
+
+	es->is_unicode = unicode;
+	es->style = lpcs->style;
+
+        es->bEnableState = !(es->style & WS_DISABLED);
+
+	es->hwndSelf = hwnd;
+	/* Save parent, which will be notified by EN_* messages */
+	es->hwndParent = lpcs->hwndParent;
+
+	if (es->style & ES_COMBO)
+	   es->hwndListBox = GetDlgItem(es->hwndParent, ID_CB_LISTBOX);
+
+        /* FIXME: should we handle changes to WS_EX_RIGHT style after creation? */
+        if (lpcs->dwExStyle & WS_EX_RIGHT) es->style |= ES_RIGHT;
+
+        /* Number overrides lowercase overrides uppercase (at least it
+         * does in Win95).  However I'll bet that ES_NUMBER would be
+         * invalid under Win 3.1.
+         */
+        if (es->style & ES_NUMBER) {
+                ; /* do not override the ES_NUMBER */
+        }  else if (es->style & ES_LOWERCASE) {
+                es->style &= ~ES_UPPERCASE;
+        }
+	if (es->style & ES_MULTILINE) {
+		es->buffer_limit = BUFLIMIT_INITIAL;
+		if (es->style & WS_VSCROLL)
+			es->style |= ES_AUTOVSCROLL;
+		if (es->style & WS_HSCROLL)
+			es->style |= ES_AUTOHSCROLL;
+		es->style &= ~ES_PASSWORD;
+		if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) {
+                        /* Confirmed - RIGHT overrides CENTER */
+			if (es->style & ES_RIGHT)
+				es->style &= ~ES_CENTER;
+			es->style &= ~WS_HSCROLL;
+			es->style &= ~ES_AUTOHSCROLL;
+		}
+	} else {
+		es->buffer_limit = BUFLIMIT_INITIAL;
+		if ((es->style & ES_RIGHT) && (es->style & ES_CENTER))
+			es->style &= ~ES_CENTER;
+		es->style &= ~WS_HSCROLL;
+		es->style &= ~WS_VSCROLL;
+		if (es->style & ES_PASSWORD)
+			es->password_char = '*';
+	}
+
+	alloc_size = ROUND_TO_GROW((es->buffer_size + 1) * sizeof(WCHAR));
+	if(!(es->hloc32W = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
+	    return FALSE;
+	es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
+
+	if (!(es->undo_text = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (es->buffer_size + 1) * sizeof(WCHAR))))
+		return FALSE;
+	es->undo_buffer_size = es->buffer_size;
+
+	if (es->style & ES_MULTILINE)
+		if (!(es->first_line_def = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF))))
+			return FALSE;
+	es->line_count = 1;
+
+	/*
+	 * In Win95 look and feel, the WS_BORDER style is replaced by the
+	 * WS_EX_CLIENTEDGE style for the edit control. This gives the edit
+	 * control a nonclient area so we don't need to draw the border.
+         * If WS_BORDER without WS_EX_CLIENTEDGE is specified we shouldn't have
+         * a nonclient area and we should handle painting the border ourselves.
+         *
+         * When making modifications please ensure that the code still works
+         * for edit controls created directly with style 0x50800000, exStyle 0
+         * (which should have a single pixel border)
+	 */
+	if (lpcs->dwExStyle & WS_EX_CLIENTEDGE)
+		es->style &= ~WS_BORDER;
+        else if (es->style & WS_BORDER)
+		SetWindowLongW(hwnd, GWL_STYLE, es->style & ~WS_BORDER);
+
+	return TRUE;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_CREATE
+ *
+ */
+static LRESULT EDIT_WM_Create(EDITSTATE *es, LPCWSTR name)
+{
+        RECT clientRect;
+
+	TRACE("%s\n", debugstr_w(name));
+       /*
+        *	To initialize some final structure members, we call some helper
+        *	functions.  However, since the EDITSTATE is not consistent (i.e.
+        *	not fully initialized), we should be very careful which
+        *	functions can be called, and in what order.
+        */
+        EDIT_WM_SetFont(es, 0, FALSE);
+        EDIT_EM_EmptyUndoBuffer(es);
+
+        /* We need to calculate the format rect
+           (applications may send EM_SETMARGINS before the control gets visible) */
+        GetClientRect(es->hwndSelf, &clientRect);
+        EDIT_SetRectNP(es, &clientRect);
+
+       if (name && *name) {
+	   EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, FALSE);
+	   /* if we insert text to the editline, the text scrolls out
+            * of the window, as the caret is placed after the insert
+            * pos normally; thus we reset es->selection... to 0 and
+            * update caret
+            */
+	   es->selection_start = es->selection_end = 0;
+           /* Adobe Photoshop does NOT like this. and MSDN says that EN_CHANGE
+            * Messages are only to be sent when the USER does something to
+            * change the contents. So I am removing this EN_CHANGE
+            *
+            * EDIT_NOTIFY_PARENT(es, EN_CHANGE);
+            */
+	   EDIT_EM_ScrollCaret(es);
+       }
+       /* force scroll info update */
+       EDIT_UpdateScrollInfo(es);
+       /* The rule seems to return 1 here for success */
+       /* Power Builder masked edit controls will crash  */
+       /* if not. */
+       /* FIXME: is that in all cases so ? */
+       return 1;
+}
+
+
+/*********************************************************************
+ *
+ *	WM_DESTROY
+ *
+ */
+static LRESULT EDIT_WM_Destroy(EDITSTATE *es)
+{
+	LINEDEF *pc, *pp;
+
+	if (es->hloc32W) {
+		LocalFree(es->hloc32W);
+	}
+	if (es->hloc32A) {
+		LocalFree(es->hloc32A);
+	}
+	if (es->hloc16) {
+		STACK16FRAME* stack16 = MapSL(PtrToUlong(NtCurrentTeb()->WOW32Reserved));
+		HANDLE16 oldDS = stack16->ds;
+
+		stack16->ds = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
+		while (LocalUnlock16(es->hloc16)) ;
+		LocalFree16(es->hloc16);
+		stack16->ds = oldDS;
+	}
+
+	pc = es->first_line_def;
+	while (pc)
+	{
+		pp = pc->next;
+		HeapFree(GetProcessHeap(), 0, pc);
+		pc = pp;
+	}
+
+        SetWindowLongPtrW( es->hwndSelf, 0, 0 );
+	HeapFree(GetProcessHeap(), 0, es);
+
+	return 0;
+}
+
+
+static inline LRESULT DefWindowProcT(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode)
+{
+	if(unicode)
+		return DefWindowProcW(hwnd, msg, wParam, lParam);
+	else
+		return DefWindowProcA(hwnd, msg, wParam, lParam);
+}
+
+/*********************************************************************
+ *
+ *	EditWndProc_common
+ *
+ *	The messages are in the order of the actual integer values
+ *	(which can be found in include/windows.h)
+ *	Wherever possible the 16 bit versions are converted to
+ *	the 32 bit ones, so that we can 'fall through' to the
+ *	helper functions.  These are mostly 32 bit (with a few
+ *	exceptions, clearly indicated by a '16' extension to their
+ *	names).
+ *
+ */
+static LRESULT EditWndProc_common( HWND hwnd, UINT msg,
+                                   WPARAM wParam, LPARAM lParam, BOOL unicode )
+{
+	EDITSTATE *es = (EDITSTATE *)GetWindowLongPtrW( hwnd, 0 );
+	LRESULT result = 0;
+
+        TRACE("hwnd=%p msg=%x (%s) wparam=%lx lparam=%lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), wParam, lParam);
+
+	if (!es && msg != WM_NCCREATE)
+		return DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
+
+	if (es && (msg != WM_DESTROY)) EDIT_LockBuffer(es);
+
+	switch (msg) {
+	case EM_GETSEL16:
+		wParam = 0;
+		lParam = 0;
+		/* fall through */
+	case EM_GETSEL:
+		result = EDIT_EM_GetSel(es, (PUINT)wParam, (PUINT)lParam);
+		break;
+
+	case EM_SETSEL16:
+		if ((short)LOWORD(lParam) == -1)
+			EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
+		else
+			EDIT_EM_SetSel(es, LOWORD(lParam), HIWORD(lParam), FALSE);
+		if (!wParam)
+			EDIT_EM_ScrollCaret(es);
+		result = 1;
+		break;
+	case EM_SETSEL:
+		EDIT_EM_SetSel(es, wParam, lParam, FALSE);
+		EDIT_EM_ScrollCaret(es);
+		result = 1;
+		break;
+
+	case EM_GETRECT16:
+		if (lParam)
+                {
+                    RECT16 *r16 = MapSL(lParam);
+                    r16->left   = es->format_rect.left;
+                    r16->top    = es->format_rect.top;
+                    r16->right  = es->format_rect.right;
+                    r16->bottom = es->format_rect.bottom;
+                }
+		break;
+	case EM_GETRECT:
+		if (lParam)
+			CopyRect((LPRECT)lParam, &es->format_rect);
+		break;
+
+	case EM_SETRECT16:
+		if ((es->style & ES_MULTILINE) && lParam) {
+			RECT rc;
+			RECT16 *r16 = MapSL(lParam);
+			rc.left   = r16->left;
+			rc.top    = r16->top;
+			rc.right  = r16->right;
+			rc.bottom = r16->bottom;
+			EDIT_SetRectNP(es, &rc);
+			EDIT_UpdateText(es, NULL, TRUE);
+		}
+		break;
+	case EM_SETRECT:
+		if ((es->style & ES_MULTILINE) && lParam) {
+			EDIT_SetRectNP(es, (LPRECT)lParam);
+			EDIT_UpdateText(es, NULL, TRUE);
+		}
+		break;
+
+	case EM_SETRECTNP16:
+		if ((es->style & ES_MULTILINE) && lParam) {
+			RECT rc;
+			RECT16 *r16 = MapSL(lParam);
+			rc.left   = r16->left;
+			rc.top    = r16->top;
+			rc.right  = r16->right;
+			rc.bottom = r16->bottom;
+			EDIT_SetRectNP(es, &rc);
+		}
+		break;
+	case EM_SETRECTNP:
+		if ((es->style & ES_MULTILINE) && lParam)
+			EDIT_SetRectNP(es, (LPRECT)lParam);
+		break;
+
+	case EM_SCROLL16:
+	case EM_SCROLL:
+		result = EDIT_EM_Scroll(es, (INT)wParam);
+                break;
+
+	case EM_LINESCROLL16:
+		wParam = (WPARAM)(INT)(SHORT)HIWORD(lParam);
+		lParam = (LPARAM)(INT)(SHORT)LOWORD(lParam);
+		/* fall through */
+	case EM_LINESCROLL:
+		result = (LRESULT)EDIT_EM_LineScroll(es, (INT)wParam, (INT)lParam);
+		break;
+
+	case EM_SCROLLCARET16:
+	case EM_SCROLLCARET:
+		EDIT_EM_ScrollCaret(es);
+		result = 1;
+		break;
+
+	case EM_GETMODIFY16:
+	case EM_GETMODIFY:
+		result = ((es->flags & EF_MODIFIED) != 0);
+		break;
+
+	case EM_SETMODIFY16:
+	case EM_SETMODIFY:
+		if (wParam)
+			es->flags |= EF_MODIFIED;
+		else
+                        es->flags &= ~(EF_MODIFIED | EF_UPDATE);  /* reset pending updates */
+		break;
+
+	case EM_GETLINECOUNT16:
+	case EM_GETLINECOUNT:
+		result = (es->style & ES_MULTILINE) ? es->line_count : 1;
+		break;
+
+	case EM_LINEINDEX16:
+		if ((INT16)wParam == -1)
+			wParam = (WPARAM)-1;
+		/* fall through */
+	case EM_LINEINDEX:
+		result = (LRESULT)EDIT_EM_LineIndex(es, (INT)wParam);
+		break;
+
+	case EM_SETHANDLE16:
+		EDIT_EM_SetHandle16(es, (HLOCAL16)wParam);
+		break;
+	case EM_SETHANDLE:
+		EDIT_EM_SetHandle(es, (HLOCAL)wParam);
+		break;
+
+	case EM_GETHANDLE16:
+		result = (LRESULT)EDIT_EM_GetHandle16(es);
+		break;
+	case EM_GETHANDLE:
+		result = (LRESULT)EDIT_EM_GetHandle(es);
+		break;
+
+	case EM_GETTHUMB16:
+	case EM_GETTHUMB:
+		result = EDIT_EM_GetThumb(es);
+		break;
+
+	/* these messages missing from specs */
+	case WM_USER+15:
+	case 0x00bf:
+	case WM_USER+16:
+	case 0x00c0:
+	case WM_USER+19:
+	case 0x00c3:
+	case WM_USER+26:
+	case 0x00ca:
+		FIXME("undocumented message 0x%x, please report\n", msg);
+		result = DefWindowProcW(hwnd, msg, wParam, lParam);
+		break;
+
+	case EM_LINELENGTH16:
+	case EM_LINELENGTH:
+		result = (LRESULT)EDIT_EM_LineLength(es, (INT)wParam);
+		break;
+
+	case EM_REPLACESEL16:
+		lParam = (LPARAM)MapSL(lParam);
+		unicode = FALSE;  /* 16-bit message is always ascii */
+		/* fall through */
+	case EM_REPLACESEL:
+	{
+		LPWSTR textW;
+
+		if(unicode)
+		    textW = (LPWSTR)lParam;
+		else
+		{
+		    LPSTR textA = (LPSTR)lParam;
+		    INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
+		    if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+			MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
+		}
+
+		EDIT_EM_ReplaceSel(es, (BOOL)wParam, textW, TRUE, TRUE);
+		result = 1;
+
+		if(!unicode)
+		    HeapFree(GetProcessHeap(), 0, textW);
+		break;
+	}
+
+	case EM_GETLINE16:
+		lParam = (LPARAM)MapSL(lParam);
+		unicode = FALSE;  /* 16-bit message is always ascii */
+		/* fall through */
+	case EM_GETLINE:
+		result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, (LPWSTR)lParam, unicode);
+		break;
+
+	case EM_LIMITTEXT16:
+	case EM_SETLIMITTEXT:
+		EDIT_EM_SetLimitText(es, wParam);
+		break;
+
+	case EM_CANUNDO16:
+	case EM_CANUNDO:
+		result = (LRESULT)EDIT_EM_CanUndo(es);
+		break;
+
+	case EM_UNDO16:
+	case EM_UNDO:
+	case WM_UNDO:
+		result = (LRESULT)EDIT_EM_Undo(es);
+		break;
+
+	case EM_FMTLINES16:
+	case EM_FMTLINES:
+		result = (LRESULT)EDIT_EM_FmtLines(es, (BOOL)wParam);
+		break;
+
+	case EM_LINEFROMCHAR16:
+	case EM_LINEFROMCHAR:
+		result = (LRESULT)EDIT_EM_LineFromChar(es, (INT)wParam);
+		break;
+
+	case EM_SETTABSTOPS16:
+		result = (LRESULT)EDIT_EM_SetTabStops16(es, (INT)wParam, MapSL(lParam));
+		break;
+	case EM_SETTABSTOPS:
+		result = (LRESULT)EDIT_EM_SetTabStops(es, (INT)wParam, (LPINT)lParam);
+		break;
+
+	case EM_SETPASSWORDCHAR16:
+		unicode = FALSE;  /* 16-bit message is always ascii */
+		/* fall through */
+	case EM_SETPASSWORDCHAR:
+	{
+		WCHAR charW = 0;
+
+		if(unicode)
+		    charW = (WCHAR)wParam;
+		else
+		{
+		    CHAR charA = wParam;
+		    MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
+		}
+
+		EDIT_EM_SetPasswordChar(es, charW);
+		break;
+	}
+
+	case EM_EMPTYUNDOBUFFER16:
+	case EM_EMPTYUNDOBUFFER:
+		EDIT_EM_EmptyUndoBuffer(es);
+		break;
+
+	case EM_GETFIRSTVISIBLELINE16:
+		result = es->y_offset;
+		break;
+	case EM_GETFIRSTVISIBLELINE:
+		result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset;
+		break;
+
+	case EM_SETREADONLY16:
+	case EM_SETREADONLY:
+		if (wParam) {
+                    SetWindowLongW( hwnd, GWL_STYLE,
+                                    GetWindowLongW( hwnd, GWL_STYLE ) | ES_READONLY );
+                    es->style |= ES_READONLY;
+		} else {
+                    SetWindowLongW( hwnd, GWL_STYLE,
+                                    GetWindowLongW( hwnd, GWL_STYLE ) & ~ES_READONLY );
+                    es->style &= ~ES_READONLY;
+		}
+                result = 1;
+		break;
+
+	case EM_SETWORDBREAKPROC16:
+		EDIT_EM_SetWordBreakProc16(es, (EDITWORDBREAKPROC16)lParam);
+		break;
+	case EM_SETWORDBREAKPROC:
+		EDIT_EM_SetWordBreakProc(es, (void *)lParam);
+		break;
+
+	case EM_GETWORDBREAKPROC16:
+		result = (LRESULT)es->word_break_proc16;
+		break;
+	case EM_GETWORDBREAKPROC:
+		result = (LRESULT)es->word_break_proc;
+		break;
+
+	case EM_GETPASSWORDCHAR16:
+		unicode = FALSE;  /* 16-bit message is always ascii */
+		/* fall through */
+	case EM_GETPASSWORDCHAR:
+	{
+		if(unicode)
+		    result = es->password_char;
+		else
+		{
+		    WCHAR charW = es->password_char;
+		    CHAR charA = 0;
+		    WideCharToMultiByte(CP_ACP, 0, &charW, 1, &charA, 1, NULL, NULL);
+		    result = charA;
+		}
+		break;
+	}
+
+	/* The following EM_xxx are new to win95 and don't exist for 16 bit */
+
+	case EM_SETMARGINS:
+		EDIT_EM_SetMargins(es, (INT)wParam, LOWORD(lParam), HIWORD(lParam), TRUE);
+		break;
+
+	case EM_GETMARGINS:
+		result = MAKELONG(es->left_margin, es->right_margin);
+		break;
+
+	case EM_GETLIMITTEXT:
+		result = es->buffer_limit;
+		break;
+
+	case EM_POSFROMCHAR:
+		if ((INT)wParam >= get_text_length(es)) result = -1;
+		else result = EDIT_EM_PosFromChar(es, (INT)wParam, FALSE);
+		break;
+
+	case EM_CHARFROMPOS:
+		result = EDIT_EM_CharFromPos(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
+		break;
+
+        /* End of the EM_ messages which were in numerical order; what order
+         * are these in?  vaguely alphabetical?
+         */
+
+	case WM_NCCREATE:
+		result = EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTW)lParam, unicode);
+		break;
+
+	case WM_DESTROY:
+		result = EDIT_WM_Destroy(es);
+		es = NULL;
+		break;
+
+	case WM_GETDLGCODE:
+		result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
+
+		if (es->style & ES_MULTILINE)
+		   result |= DLGC_WANTALLKEYS;
+
+		if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
+		{
+		   int vk = (int)((LPMSG)lParam)->wParam;
+
+                   if (es->hwndListBox)
+                   {
+                       if (vk == VK_RETURN || vk == VK_ESCAPE)
+                           if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
+                               result |= DLGC_WANTMESSAGE;
+                   }
+                   else
+                   {
+                       switch (vk)
+                       {
+                           case VK_ESCAPE:
+                               SendMessageW(GetParent(hwnd), WM_CLOSE, 0, 0);
+                               break;
+                           default:
+                               break;
+                       }
+                   }
+                }
+		break;
+
+        case WM_IME_CHAR:
+            if (!unicode)
+            {
+                WCHAR charW;
+                CHAR  strng[2];
+
+                strng[0] = wParam >> 8;
+                strng[1] = wParam & 0xff;
+                if (strng[0]) MultiByteToWideChar(CP_ACP, 0, strng, 2, &charW, 1);
+                else MultiByteToWideChar(CP_ACP, 0, &strng[1], 1, &charW, 1);
+		result = EDIT_WM_Char(es, charW);
+		break;
+            }
+            /* fall through */
+	case WM_CHAR:
+	{
+		WCHAR charW;
+
+		if(unicode)
+		    charW = wParam;
+		else
+		{
+		    CHAR charA = wParam;
+		    MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
+		}
+
+                if (es->hwndListBox)
+                {
+                    if (charW == VK_RETURN || charW == VK_ESCAPE)
+                    {
+                        if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
+                            SendMessageW(GetParent(hwnd), WM_KEYDOWN, charW, 0);
+                        break;
+                    }
+                }
+		result = EDIT_WM_Char(es, charW);
+		break;
+	}
+
+        case WM_UNICHAR:
+                if (unicode)
+                {
+                    if (wParam == UNICODE_NOCHAR) return TRUE;
+                    if (wParam <= 0x000fffff)
+                    {
+                        if(wParam > 0xffff) /* convert to surrogates */
+                        {
+                            wParam -= 0x10000;
+                            EDIT_WM_Char(es, (wParam >> 10) + 0xd800);
+                            EDIT_WM_Char(es, (wParam & 0x03ff) + 0xdc00);
+                        }
+                        else EDIT_WM_Char(es, wParam);
+                    }
+                    return 0;
+                }
+                break;
+
+	case WM_CLEAR:
+		EDIT_WM_Clear(es);
+		break;
+
+	case WM_COMMAND:
+		EDIT_WM_Command(es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
+		break;
+
+        case WM_CONTEXTMENU:
+		EDIT_WM_ContextMenu(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
+		break;
+
+	case WM_COPY:
+		EDIT_WM_Copy(es);
+		break;
+
+	case WM_CREATE:
+		if(unicode)
+		    result = EDIT_WM_Create(es, ((LPCREATESTRUCTW)lParam)->lpszName);
+		else
+		{
+		    LPCSTR nameA = ((LPCREATESTRUCTA)lParam)->lpszName;
+		    LPWSTR nameW = NULL;
+		    if(nameA)
+		    {
+			INT countW = MultiByteToWideChar(CP_ACP, 0, nameA, -1, NULL, 0);
+			if((nameW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
+			    MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW);
+		    }
+		    result = EDIT_WM_Create(es, nameW);
+                    HeapFree(GetProcessHeap(), 0, nameW);
+		}
+		break;
+
+	case WM_CUT:
+		EDIT_WM_Cut(es);
+		break;
+
+	case WM_ENABLE:
+                es->bEnableState = (BOOL) wParam;
+		EDIT_UpdateText(es, NULL, TRUE);
+		break;
+
+	case WM_ERASEBKGND:
+		/* we do the proper erase in EDIT_WM_Paint */
+		result = 1;
+		break;
+
+	case WM_GETFONT:
+		result = (LRESULT)es->font;
+		break;
+
+	case WM_GETTEXT:
+		result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, (LPWSTR)lParam, unicode);
+		break;
+
+	case WM_GETTEXTLENGTH:
+                if (unicode) result = get_text_length(es);
+                else result = WideCharToMultiByte( CP_ACP, 0, es->text, get_text_length(es),
+                                                   NULL, 0, NULL, NULL );
+		break;
+
+	case WM_HSCROLL:
+		result = EDIT_WM_HScroll(es, LOWORD(wParam), (short)HIWORD(wParam));
+		break;
+
+	case WM_KEYDOWN:
+		result = EDIT_WM_KeyDown(es, (INT)wParam);
+		break;
+
+	case WM_KILLFOCUS:
+		result = EDIT_WM_KillFocus(es);
+		break;
+
+	case WM_LBUTTONDBLCLK:
+		result = EDIT_WM_LButtonDblClk(es);
+		break;
+
+	case WM_LBUTTONDOWN:
+		result = EDIT_WM_LButtonDown(es, wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
+		break;
+
+	case WM_LBUTTONUP:
+		result = EDIT_WM_LButtonUp(es);
+		break;
+
+	case WM_MBUTTONDOWN:
+		result = EDIT_WM_MButtonDown(es);
+		break;
+
+	case WM_MOUSEMOVE:
+		result = EDIT_WM_MouseMove(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
+		break;
+
+	case WM_PRINTCLIENT:
+	case WM_PAINT:
+	        EDIT_WM_Paint(es, (HDC)wParam);
+		break;
+
+	case WM_PASTE:
+		EDIT_WM_Paste(es);
+		break;
+
+	case WM_SETFOCUS:
+		EDIT_WM_SetFocus(es);
+		break;
+
+	case WM_SETFONT:
+		EDIT_WM_SetFont(es, (HFONT)wParam, LOWORD(lParam) != 0);
+		break;
+
+	case WM_SETREDRAW:
+		/* FIXME: actually set an internal flag and behave accordingly */
+		break;
+
+	case WM_SETTEXT:
+		EDIT_WM_SetText(es, (LPCWSTR)lParam, unicode);
+		result = TRUE;
+		break;
+
+	case WM_SIZE:
+		EDIT_WM_Size(es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
+		break;
+
+        case WM_STYLECHANGED:
+                result = EDIT_WM_StyleChanged(es, wParam, (const STYLESTRUCT *)lParam);
+                break;
+
+        case WM_STYLECHANGING:
+                result = 0; /* See EDIT_WM_StyleChanged */
+                break;
+
+	case WM_SYSKEYDOWN:
+		result = EDIT_WM_SysKeyDown(es, (INT)wParam, (DWORD)lParam);
+		break;
+
+	case WM_TIMER:
+		EDIT_WM_Timer(es);
+		break;
+
+	case WM_VSCROLL:
+		result = EDIT_WM_VScroll(es, LOWORD(wParam), (short)HIWORD(wParam));
+		break;
+
+        case WM_MOUSEWHEEL:
+                {
+                    int gcWheelDelta = 0;
+                    UINT pulScrollLines = 3;
+                    SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
+
+                    if (wParam & (MK_SHIFT | MK_CONTROL)) {
+                        result = DefWindowProcW(hwnd, msg, wParam, lParam);
+                        break;
+                    }
+                    gcWheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
+                    if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
+                    {
+                        int cLineScroll= (int) min((UINT) es->line_count, pulScrollLines);
+                        cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
+			result = EDIT_EM_LineScroll(es, 0, cLineScroll);
+                    }
+                }
+                break;
+
+
+	/* IME messages to make the edit control IME aware */
+	case WM_IME_SETCONTEXT:
+		break;
+
+	case WM_IME_STARTCOMPOSITION:
+		es->composition_start = es->selection_end;
+		es->composition_len = 0;
+		break;
+
+	case WM_IME_COMPOSITION:
+                EDIT_ImeComposition(hwnd, lParam, es);
+		break;
+
+	case WM_IME_ENDCOMPOSITION:
+                if (es->composition_len > 0)
+                {
+                        static const WCHAR empty_stringW[] = {0};
+                        EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
+                        es->selection_end = es->selection_start;
+                        es->composition_len= 0;
+                }
+		break;
+
+	case WM_IME_COMPOSITIONFULL:
+		break;
+
+	case WM_IME_SELECT:
+		break;
+
+	case WM_IME_CONTROL:
+		break;
+
+	default:
+		result = DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
+		break;
+	}
+
+	if (es) EDIT_UnlockBuffer(es, FALSE);
+
+        TRACE("hwnd=%p msg=%x (%s) -- 0x%08lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), result);
+
+	return result;
+}
+
+/*********************************************************************
+ *
+ *	EditWndProc   (USER32.@)
+ */
+LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    return EditWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
+}
+
+/*********************************************************************
+ *
+ *	EditWndProcW   (USER32.@)
+ */
+LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    return EditWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
+}
+
+/*********************************************************************
+ * edit class descriptor
+ */
+static const WCHAR editW[] = {'E','d','i','t',0};
+const struct builtin_class_descr EDIT_builtin_class =
+{
+    editW,                /* name */
+    CS_DBLCLKS | CS_PARENTDC,   /* style */
+    EditWndProcA,         /* procA */
+    EditWndProcW,         /* procW */
+    sizeof(EDITSTATE *),  /* extra */
+    IDC_IBEAM,            /* cursor */
+    0                     /* brush */
+};
-- 
1.5.6.5




More information about the wine-patches mailing list