Release 961102
[wine] / controls / edit.c
1 /*
2  *      Edit control
3  *
4  *      Copyright  David W. Metcalfe, 1994
5  *      Copyright  William Magro, 1995, 1996
6  *      Copyright  Frans van Dorsselaer, 1996
7  *
8  */
9
10 /*
11  *      UNDER CONSTRUCTION, please read EDIT.TODO
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include "windows.h"
18 #include "win.h"
19 #include "local.h"
20 #include "stddebug.h"
21 #include "debug.h"
22 #include "xmalloc.h"
23 #include "callback.h"
24
25 #define BUFLIMIT_MULTI          65534   /* maximum text buffer length (not including '\0') */
26 #define BUFLIMIT_SINGLE         32766
27 #define BUFSTART_MULTI          1024    /* starting length for multi-line control */
28 #define BUFSTART_SINGLE         256     /* starting length for single line control */
29 #define GROWLENGTH              64      /* buffers grow by this much */
30 #define HSCROLL_FRACTION        3       /* scroll window by 1/3 width */
31
32 typedef enum
33 {
34         END_0 = 0,
35         END_DELIMIT,
36         END_NONE,
37         END_HARD,
38         END_SOFT,
39 } LINE_END;
40
41 typedef struct {
42         UINT offset;
43         UINT length;
44         LINE_END ending;
45 } LINEDEF;
46
47 typedef struct
48 {
49         UINT TextWidth;         /* width of the widest line in pixels */
50         HLOCAL16 hBuf;
51         char *text;
52         HFONT16 hFont;
53         LINEDEF *LineDefs;
54         UINT XOffset;           /* offset of the viewport in pixels */
55         UINT FirstVisibleLine;
56         UINT LineCount;
57         UINT LineHeight;        /* height of a screen line in pixels */
58         UINT AveCharWidth;      /* average character width in pixels */
59         UINT BufLimit;
60         UINT BufSize;
61         BOOL TextChanged;
62         BOOL Redraw;
63         UINT SelStart;          /* offset of selection start, == SelEnd if no selection */
64         UINT SelEnd;            /* offset of selection end == current caret position */
65         UINT NumTabStops;
66         LPINT16 TabStops;
67         EDITWORDBREAKPROC WordBreakProc;
68         char PasswordChar;
69 } EDITSTATE;
70
71
72 #define SWAP_UINT(x,y) do { UINT temp = (UINT)(x); (x) = (UINT)(y); (y) = temp; } while(0)
73 #define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT((x),(y)); } while(0)
74
75 /* macros to access window styles */
76 #define IsMultiLine(wndPtr) ((wndPtr)->dwStyle & ES_MULTILINE)
77 #define IsVScrollBar(wndPtr) ((wndPtr)->dwStyle & WS_VSCROLL)
78 #define IsHScrollBar(wndPtr) ((wndPtr)->dwStyle & WS_HSCROLL)
79 #define IsReadOnly(wndPtr) ((wndPtr)->dwStyle & ES_READONLY)
80 #define IsWordWrap(wndPtr) (((wndPtr)->dwStyle & ES_AUTOHSCROLL) == 0)
81 #define IsPassword(wndPtr) ((wndPtr)->dwStyle & ES_PASSWORD)
82 #define IsLower(wndPtr) ((wndPtr)->dwStyle & ES_LOWERCASE)
83 #define IsUpper(wndPtr) ((wndPtr)->dwStyle & ES_UPPERCASE)
84
85 #define EDITSTATEPTR(wndPtr) (*(EDITSTATE **)((wndPtr)->wExtra))
86
87 #define EDIT_SEND_CTLCOLOR(wndPtr,hdc) \
88     (SendMessage32A((wndPtr)->parent->hwndSelf, WM_CTLCOLOREDIT, \
89                     (WPARAM32)(hdc), (LPARAM)(wndPtr)->hwndSelf ))
90 #define EDIT_NOTIFY_PARENT(wndPtr, wNotifyCode) \
91     (SendMessage32A((wndPtr)->parent->hwndSelf, WM_COMMAND, \
92                     MAKEWPARAM((wndPtr)->wIDmenu, wNotifyCode), \
93                     (LPARAM)(wndPtr)->hwndSelf ))
94 #define DPRINTF_EDIT_MSG(str) \
95     dprintf_edit(stddeb, \
96                  "edit: " str ": hwnd=%04x, wParam=%04x, lParam=%08x\n", \
97                  (UINT32)hwnd, (UINT32)wParam, (UINT32)lParam)
98
99
100 /*********************************************************************
101  *
102  *      Declarations
103  *
104  *      Files like these should really be kept in alphabetical order.
105  *
106  */
107 LRESULT EditWndProc(HWND hwnd, UINT msg, WPARAM16 wParam, LPARAM lParam);
108
109 static void    EDIT_BuildLineDefs(WND *wndPtr);
110 static INT     EDIT_CallWordBreakProc(WND *wndPtr, char *s, INT index, INT count, INT action);
111 static UINT    EDIT_ColFromWndX(WND *wndPtr, UINT line, INT x);
112 static void    EDIT_DelEnd(WND *wndPtr);
113 static void    EDIT_DelLeft(WND *wndPtr);
114 static void    EDIT_DelRight(WND *wndPtr);
115 static UINT    EDIT_GetAveCharWidth(WND *wndPtr);
116 static UINT    EDIT_GetLineHeight(WND *wndPtr);
117 static void    EDIT_GetLineRect(WND *wndPtr, UINT line, UINT scol, UINT ecol, LPRECT16 rc);
118 static char *  EDIT_GetPointer(WND *wndPtr);
119 static char *  EDIT_GetPasswordPointer(WND *wndPtr);
120 static LRESULT EDIT_GetRect(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
121 static BOOL    EDIT_GetRedraw(WND *wndPtr);
122 static LRESULT EDIT_GetSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
123 static UINT    EDIT_GetTextWidth(WND *wndPtr);
124 static UINT    EDIT_GetVisibleLineCount(WND *wndPtr);
125 static UINT    EDIT_GetWndWidth(WND *wndPtr);
126 static UINT    EDIT_GetXOffset(WND *wndPtr);
127 static void    EDIT_InvalidateText(WND *wndPtr, UINT start, UINT end);
128 static UINT    EDIT_LineFromWndY(WND *wndPtr, INT y);
129 static BOOL    EDIT_MakeFit(WND *wndPtr, UINT size);
130 static void    EDIT_MoveBackward(WND *wndPtr, BOOL extend);
131 static void    EDIT_MoveDownward(WND *wndPtr, BOOL extend);
132 static void    EDIT_MoveEnd(WND *wndPtr, BOOL extend);
133 static void    EDIT_MoveForward(WND *wndPtr, BOOL extend);
134 static void    EDIT_MoveHome(WND *wndPtr, BOOL extend);
135 static void    EDIT_MovePageDown(WND *wndPtr, BOOL extend);
136 static void    EDIT_MovePageUp(WND *wndPtr, BOOL extend);
137 static void    EDIT_MoveUpward(WND *wndPtr, BOOL extend);
138 static void    EDIT_MoveWordBackward(WND *wndPtr, BOOL extend);
139 static void    EDIT_MoveWordForward(WND *wndPtr, BOOL extend);
140 static void    EDIT_PaintLine(WND *wndPtr, HDC32 hdc, UINT line, BOOL rev);
141 static UINT    EDIT_PaintText(WND *wndPtr, HDC32 hdc, INT x, INT y, UINT line, UINT col, UINT count, BOOL rev);
142 static void    EDIT_ReleasePointer(WND *wndPtr);
143 static LRESULT EDIT_ReplaceSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
144 static void    EDIT_ScrollIntoView(WND *wndPtr);
145 static INT     EDIT_WndXFromCol(WND *wndPtr, UINT line, UINT col);
146 static INT     EDIT_WndYFromLine(WND *wndPtr, UINT line);
147 static INT     EDIT_WordBreakProc(char *s, INT index, INT count, INT action);
148
149 static LRESULT EDIT_EM_CanUndo(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
150 static LRESULT EDIT_EM_EmptyUndoBuffer(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
151 static LRESULT EDIT_EM_FmtLines(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
152 static LRESULT EDIT_EM_GetFirstVisibleLine(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
153 static LRESULT EDIT_EM_GetHandle(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
154 static LRESULT EDIT_EM_GetLine(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
155 static LRESULT EDIT_EM_GetLineCount(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
156 static LRESULT EDIT_EM_GetModify(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
157 static LRESULT EDIT_EM_GetPasswordChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
158 static LRESULT EDIT_EM_GetRect(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
159 static LRESULT EDIT_EM_GetSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
160 static LRESULT EDIT_EM_GetThumb(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
161 static LRESULT EDIT_EM_GetWordBreakProc(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
162 static LRESULT EDIT_EM_LimitText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
163 static LRESULT EDIT_EM_LineFromChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
164 static LRESULT EDIT_EM_LineIndex(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
165 static LRESULT EDIT_EM_LineLength(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
166 static LRESULT EDIT_EM_LineScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
167 static LRESULT EDIT_EM_ReplaceSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
168 static LRESULT EDIT_EM_Scroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
169 static LRESULT EDIT_EM_SetHandle(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
170 static LRESULT EDIT_EM_SetModify(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
171 static LRESULT EDIT_EM_SetPasswordChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
172 static LRESULT EDIT_EM_SetReadOnly(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
173 static LRESULT EDIT_EM_SetRect(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
174 static LRESULT EDIT_EM_SetRectNP(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
175 static LRESULT EDIT_EM_SetSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
176 static LRESULT EDIT_EM_SetTabStops(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
177 static LRESULT EDIT_EM_SetWordBreakProc(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
178 static LRESULT EDIT_EM_Undo(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
179
180 static LRESULT EDIT_WM_Char(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
181 static LRESULT EDIT_WM_Clear(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
182 static LRESULT EDIT_WM_Copy(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
183 static LRESULT EDIT_WM_Cut(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
184 static LRESULT EDIT_WM_Create(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
185 static LRESULT EDIT_WM_Destroy(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
186 static LRESULT EDIT_WM_Enable(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
187 static LRESULT EDIT_WM_EraseBkGnd(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
188 static LRESULT EDIT_WM_GetDlgCode(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
189 static LRESULT EDIT_WM_GetFont(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
190 static LRESULT EDIT_WM_GetText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
191 static LRESULT EDIT_WM_GetTextLength(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
192 static LRESULT EDIT_WM_HScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
193 static LRESULT EDIT_WM_KeyDown(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
194 static LRESULT EDIT_WM_KillFocus(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
195 static LRESULT EDIT_WM_LButtonDblClk(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
196 static LRESULT EDIT_WM_LButtonDown(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
197 static LRESULT EDIT_WM_LButtonUp(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
198 static LRESULT EDIT_WM_MouseMove(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
199 static LRESULT EDIT_WM_Paint(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
200 static LRESULT EDIT_WM_Paste(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
201 static LRESULT EDIT_WM_SetCursor(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
202 static LRESULT EDIT_WM_SetFocus(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
203 static LRESULT EDIT_WM_SetFont(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
204 static LRESULT EDIT_WM_SetRedraw(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
205 static LRESULT EDIT_WM_SetText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
206 static LRESULT EDIT_WM_Size(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
207 static LRESULT EDIT_WM_VScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
208
209
210 /*********************************************************************
211  *
212  *      General shortcuts for variable names:
213  *
214  *      UINT l;         line
215  *      UINT c;         column
216  *      UINT s;         offset of selection start
217  *      UINT e;         offset of selection end
218  *      UINT sl;        line on which the selection starts
219  *      UINT el;        line on which the selection ends
220  *      UINT sc;        column on which the selection starts
221  *      UINT ec;        column on which the selection ends
222  *      UINT li;        line index (offset)
223  *      UINT fv;        first visible line
224  *      UINT vlc;       vissible line count
225  *      UINT lc;        line count
226  *      UINT lh;        line height (in pixels)
227  *      UINT tw;        text width (in pixels)
228  *      UINT ww;        window width (in pixels)
229  *      UINT cw;        character width (average, in pixels)
230  *
231  */
232
233
234 /*********************************************************************
235  *
236  *      EditWndProc()
237  *
238  */
239 LRESULT EditWndProc(HWND hwnd, UINT msg, WPARAM16 wParam, LPARAM lParam)
240 {
241         LRESULT lResult = 0L;
242         WND *wndPtr = WIN_FindWndPtr(hwnd);
243
244         if ((!EDITSTATEPTR(wndPtr)) && (msg != WM_CREATE))
245                 return DefWindowProc16(hwnd, msg, wParam, lParam);
246
247         switch (msg) {
248         case EM_CANUNDO:
249                 DPRINTF_EDIT_MSG("EM_CANUNDO");
250                 lResult = EDIT_EM_CanUndo(wndPtr, wParam, lParam);
251                 break;
252         case EM_EMPTYUNDOBUFFER:
253                 DPRINTF_EDIT_MSG("EM_EMPTYUNDOBUFFER");
254                 lResult = EDIT_EM_EmptyUndoBuffer(wndPtr, wParam, lParam);
255                 break;
256         case EM_FMTLINES:
257                 DPRINTF_EDIT_MSG("EM_FMTLINES");
258                 lResult = EDIT_EM_FmtLines(wndPtr, wParam, lParam);
259                 break;
260         case EM_GETFIRSTVISIBLELINE:
261                 DPRINTF_EDIT_MSG("EM_GETFIRSTVISIBLELINE");
262                 lResult = EDIT_EM_GetFirstVisibleLine(wndPtr, wParam, lParam);
263                 break;
264         case EM_GETHANDLE:
265                 DPRINTF_EDIT_MSG("EM_GETHANDLE");
266                 lResult = EDIT_EM_GetHandle(wndPtr, wParam, lParam);
267                 break;
268         case EM_GETLINE:
269                 DPRINTF_EDIT_MSG("EM_GETLINE");
270                 lResult = EDIT_EM_GetLine(wndPtr, wParam, lParam);
271                 break;
272         case EM_GETLINECOUNT:
273                 DPRINTF_EDIT_MSG("EM_GETLINECOUNT");
274                 lResult = EDIT_EM_GetLineCount(wndPtr, wParam, lParam);
275                 break;
276         case EM_GETMODIFY:
277                 DPRINTF_EDIT_MSG("EM_GETMODIFY");
278                 lResult = EDIT_EM_GetModify(wndPtr, wParam, lParam);
279                 break;
280         case EM_GETPASSWORDCHAR:
281                 DPRINTF_EDIT_MSG("EM_GETPASSWORDCHAR");
282                 lResult = EDIT_EM_GetPasswordChar(wndPtr, wParam, lParam);
283                 break;
284         case EM_GETRECT:
285                 DPRINTF_EDIT_MSG("EM_GETRECT");
286                 lResult = EDIT_EM_GetRect(wndPtr, wParam, lParam);
287                 break;
288         case EM_GETSEL:
289                 DPRINTF_EDIT_MSG("EM_GETSEL");
290                 lResult = EDIT_EM_GetSel(wndPtr, wParam, lParam);
291                 break;
292         case EM_GETTHUMB:
293                 DPRINTF_EDIT_MSG("EM_GETTHUMB");
294                 lResult = EDIT_EM_GetThumb(wndPtr, wParam, lParam);
295                 break;
296         case EM_GETWORDBREAKPROC:
297                 DPRINTF_EDIT_MSG("EM_GETWORDBREAKPROC");
298                 lResult = EDIT_EM_GetWordBreakProc(wndPtr, wParam, lParam);
299                 break;
300         case EM_LIMITTEXT:
301                 DPRINTF_EDIT_MSG("EM_LIMITTEXT");
302                 lResult = EDIT_EM_LimitText(wndPtr, wParam, lParam);
303                 break;
304         case EM_LINEFROMCHAR:
305                 DPRINTF_EDIT_MSG("EM_LINEFROMCHAR");
306                 lResult = EDIT_EM_LineFromChar(wndPtr, wParam, lParam);
307                 break;
308         case EM_LINEINDEX:
309                 DPRINTF_EDIT_MSG("EM_LINEINDEX");
310                 lResult = EDIT_EM_LineIndex(wndPtr, wParam, lParam);
311                 break;
312         case EM_LINELENGTH:
313                 DPRINTF_EDIT_MSG("EM_LINELENGTH");
314                 lResult = EDIT_EM_LineLength(wndPtr, wParam, lParam);
315                 break;
316         case EM_LINESCROLL:
317                 DPRINTF_EDIT_MSG("EM_LINESCROLL");
318                 lResult = EDIT_EM_LineScroll(wndPtr, wParam, lParam);
319                 break;
320         case EM_REPLACESEL:
321                 DPRINTF_EDIT_MSG("EM_REPLACESEL");
322                 lResult = EDIT_EM_ReplaceSel(wndPtr, wParam, lParam);
323                 break;
324         case EM_SCROLL:
325                 DPRINTF_EDIT_MSG("EM_SCROLL");
326                 lResult = EDIT_EM_Scroll(wndPtr, wParam, lParam);
327                 break;
328         case EM_SETHANDLE:
329                 DPRINTF_EDIT_MSG("EM_SETHANDLE");
330                 lResult = EDIT_EM_SetHandle(wndPtr, wParam, lParam);
331                 break;
332         case EM_SETMODIFY:
333                 DPRINTF_EDIT_MSG("EM_SETMODIFY");
334                 lResult = EDIT_EM_SetModify(wndPtr, wParam, lParam);
335                 break;
336         case EM_SETPASSWORDCHAR:
337                 DPRINTF_EDIT_MSG("EM_SETPASSWORDCHAR");
338                 lResult = EDIT_EM_SetPasswordChar(wndPtr, wParam, lParam);
339                 break;
340         case EM_SETREADONLY:
341                 DPRINTF_EDIT_MSG("EM_SETREADONLY");
342                 lResult = EDIT_EM_SetReadOnly(wndPtr, wParam, lParam);
343                 break;
344         case EM_SETRECT:
345                 DPRINTF_EDIT_MSG("EM_SETRECT");
346                 lResult = EDIT_EM_SetRect(wndPtr, wParam, lParam);
347                 break;
348         case EM_SETRECTNP:
349                 DPRINTF_EDIT_MSG("EM_SETRECTNP");
350                 lResult = EDIT_EM_SetRectNP(wndPtr, wParam, lParam);
351                 break;
352         case EM_SETSEL:
353                 DPRINTF_EDIT_MSG("EM_SETSEL");
354                 lResult = EDIT_EM_SetSel(wndPtr, wParam, lParam);
355                 break;
356         case EM_SETTABSTOPS:
357                 DPRINTF_EDIT_MSG("EM_SETTABSTOPS");
358                 lResult = EDIT_EM_SetTabStops(wndPtr, wParam, lParam);
359                 break;
360         case EM_SETWORDBREAKPROC:
361                 DPRINTF_EDIT_MSG("EM_SETWORDBREAKPROC");
362                 lResult = EDIT_EM_SetWordBreakProc(wndPtr, wParam, lParam);
363                 break;
364         case EM_UNDO:
365         case WM_UNDO:
366                 DPRINTF_EDIT_MSG("EM_UNDO / WM_UNDO");
367                 lResult = EDIT_EM_Undo(wndPtr, wParam, lParam);
368                 break;
369         case WM_GETDLGCODE:
370                 DPRINTF_EDIT_MSG("WM_GETDLGCODE");
371                 lResult = EDIT_WM_GetDlgCode(wndPtr, wParam, lParam);
372                 break;
373         case WM_CHAR:
374                 DPRINTF_EDIT_MSG("WM_CHAR");
375                 lResult = EDIT_WM_Char(wndPtr, wParam, lParam);
376                 break;
377         case WM_CLEAR:
378                 DPRINTF_EDIT_MSG("WM_CLEAR");
379                 lResult = EDIT_WM_Clear(wndPtr, wParam, lParam);
380                 break;
381         case WM_COPY:
382                 DPRINTF_EDIT_MSG("WM_COPY");
383                 lResult = EDIT_WM_Copy(wndPtr, wParam, lParam);
384                 break;
385         case WM_CREATE:
386                 DPRINTF_EDIT_MSG("WM_CREATE");
387                 lResult = EDIT_WM_Create(wndPtr, wParam, lParam);
388                 break;
389         case WM_CUT:
390                 DPRINTF_EDIT_MSG("WM_CUT");
391                 lResult = EDIT_WM_Cut(wndPtr, wParam, lParam);
392                 break;
393         case WM_DESTROY:
394                 DPRINTF_EDIT_MSG("WM_DESTROY");
395                 lResult = EDIT_WM_Destroy(wndPtr, wParam, lParam);
396                 break;
397         case WM_ENABLE:
398                 DPRINTF_EDIT_MSG("WM_ENABLE");
399                 lResult = EDIT_WM_Enable(wndPtr, wParam, lParam);
400                 break;
401         case WM_ERASEBKGND:
402                 DPRINTF_EDIT_MSG("WM_ERASEBKGND");
403                 lResult = EDIT_WM_EraseBkGnd(wndPtr, wParam, lParam);
404                 break;
405         case WM_GETFONT:
406                 DPRINTF_EDIT_MSG("WM_GETFONT");
407                 lResult = EDIT_WM_GetFont(wndPtr, wParam, lParam);
408                 break;
409         case WM_GETTEXT:
410                 DPRINTF_EDIT_MSG("WM_GETTEXT");
411                 lResult = EDIT_WM_GetText(wndPtr, wParam, lParam);
412                 break;
413         case WM_GETTEXTLENGTH:
414                 DPRINTF_EDIT_MSG("WM_GETTEXTLENGTH");
415                 lResult = EDIT_WM_GetTextLength(wndPtr, wParam, lParam);
416                 break;
417         case WM_HSCROLL:
418                 DPRINTF_EDIT_MSG("WM_HSCROLL");
419                 lResult = EDIT_WM_HScroll(wndPtr, wParam, lParam);
420                 break;
421         case WM_KEYDOWN:
422                 DPRINTF_EDIT_MSG("WM_KEYDOWN");
423                 lResult = EDIT_WM_KeyDown(wndPtr, wParam, lParam);
424                 break;
425         case WM_KILLFOCUS:
426                 DPRINTF_EDIT_MSG("WM_KILLFOCUS");
427                 lResult = EDIT_WM_KillFocus(wndPtr, wParam, lParam);
428                 break;
429         case WM_LBUTTONDBLCLK:
430                 DPRINTF_EDIT_MSG("WM_LBUTTONDBLCLK");
431                 lResult = EDIT_WM_LButtonDblClk(wndPtr, wParam, lParam);
432                 break;
433         case WM_LBUTTONDOWN:
434                 DPRINTF_EDIT_MSG("WM_LBUTTONDOWN");
435                 lResult = EDIT_WM_LButtonDown(wndPtr, wParam, lParam);
436                 break;
437         case WM_LBUTTONUP:
438                 DPRINTF_EDIT_MSG("WM_LBUTTONUP");
439                 lResult = EDIT_WM_LButtonUp(wndPtr, wParam, lParam);
440                 break;
441         case WM_MOUSEMOVE:
442                 /*
443                  *      DPRINTF_EDIT_MSG("WM_MOUSEMOVE");
444                  */
445                 lResult = EDIT_WM_MouseMove(wndPtr, wParam, lParam);
446                 break;
447         case WM_PAINT:
448                 DPRINTF_EDIT_MSG("WM_PAINT");
449                 lResult = EDIT_WM_Paint(wndPtr, wParam, lParam);
450                 break;
451         case WM_PASTE:
452                 DPRINTF_EDIT_MSG("WM_PASTE");
453                 lResult = EDIT_WM_Paste(wndPtr, wParam, lParam);
454                 break;
455         case WM_SETCURSOR:
456                 /*
457                  *      DPRINTF_EDIT_MSG("WM_SETCURSOR");
458                  */
459                 lResult = EDIT_WM_SetCursor(wndPtr, wParam, lParam);
460                 break;
461         case WM_SETFOCUS:
462                 DPRINTF_EDIT_MSG("WM_SETFOCUS");
463                 lResult = EDIT_WM_SetFocus(wndPtr, wParam, lParam);
464                 break;
465         case WM_SETFONT:
466                 DPRINTF_EDIT_MSG("WM_SETFONT");
467                 lResult = EDIT_WM_SetFont(wndPtr, wParam, lParam);
468                 break;
469         case WM_SETREDRAW:
470                 DPRINTF_EDIT_MSG("WM_SETREDRAW");
471                 lResult = EDIT_WM_SetRedraw(wndPtr, wParam, lParam);
472                 break;
473         case WM_SETTEXT:
474                 DPRINTF_EDIT_MSG("WM_SETTEXT");
475                 lResult = EDIT_WM_SetText(wndPtr, wParam, lParam);
476                 break;
477         case WM_SIZE:
478                 DPRINTF_EDIT_MSG("WM_SIZE");
479                 lResult = EDIT_WM_Size(wndPtr, wParam, lParam);
480                 break;
481         case WM_VSCROLL:
482                 DPRINTF_EDIT_MSG("WM_VSCROLL");
483                 lResult = EDIT_WM_VScroll(wndPtr, wParam, lParam);
484                 break;
485         default:
486                 /* Some programs pass messages obtained through
487                  * RegisterWindowMessage() (>= 0xc000); we just ignore them
488                  */
489                 if ((msg >= WM_USER) && (msg < 0xc000))
490                         fprintf(stdnimp, "edit: undocumented message %d >= WM_USER, please report.\n", msg);
491                 lResult = DefWindowProc16(hwnd, msg, wParam, lParam);
492                 break;
493         }
494         EDIT_ReleasePointer(wndPtr);
495         return lResult;
496 }
497
498
499 /*********************************************************************
500  *
501  *      EDIT_BuildLineDefs
502  *
503  *      Build array of pointers to text lines.
504  *      Lines can end with '\0' (last line), nothing (if it is too long),
505  *      a delimiter (usually ' '), a soft return '\r\r\n' or a hard return '\r\n'
506  *
507  */
508 static void EDIT_BuildLineDefs(WND *wndPtr)
509 {
510         EDITSTATE *es = EDITSTATEPTR(wndPtr);
511         char *text = EDIT_GetPasswordPointer(wndPtr);
512         int ww = EDIT_GetWndWidth(wndPtr);
513         HDC32 hdc;
514         HFONT16 hFont;
515         HFONT32 oldFont = 0;
516         char *start, *cp;
517         int prev, next;
518         int width;
519         int length;
520         LINE_END ending;
521
522         hdc = GetDC32(wndPtr->hwndSelf);
523         hFont = (HFONT16)EDIT_WM_GetFont(wndPtr, 0, 0L);
524         if (hFont) oldFont = SelectObject32(hdc, hFont);
525
526         if (!IsMultiLine(wndPtr)) {
527                 es->LineCount = 1;
528                 es->LineDefs = xrealloc(es->LineDefs, sizeof(LINEDEF));
529                 es->LineDefs[0].offset = 0;
530                 es->LineDefs[0].length = EDIT_WM_GetTextLength(wndPtr, 0, 0L);
531                 es->LineDefs[0].ending = END_0;
532                 es->TextWidth = LOWORD(GetTabbedTextExtent(hdc, text,
533                                         es->LineDefs[0].length,
534                                         es->NumTabStops, es->TabStops));
535         } else {
536                 es->LineCount = 0;
537                 start = text;
538                 do {
539                         if (!(cp = strstr(start, "\r\n"))) {
540                                 ending = END_0;
541                                 length = strlen(start);
542                         } else if ((cp > start) && (*(cp - 1) == '\r')) {
543                                 ending = END_SOFT;
544                                 length = cp - start - 1;
545                         } else {
546                                 ending = END_HARD;
547                                 length = cp - start;
548                         }
549                         width = LOWORD(GetTabbedTextExtent(hdc, start, length,
550                                                 es->NumTabStops, es->TabStops));
551
552                         if (IsWordWrap(wndPtr) && (width > ww)) {
553                                 next = 0;
554                                 do {
555                                         prev = next;
556                                         next = EDIT_CallWordBreakProc(wndPtr, start,
557                                                         prev + 1, length, WB_RIGHT);
558                                         width = LOWORD(GetTabbedTextExtent(hdc, start, next,
559                                                         es->NumTabStops, es->TabStops));
560                                 } while (width <= ww);
561                                 if (!prev) {
562                                         next = 0;
563                                         do {
564                                                 prev = next;
565                                                 next++;
566                                                 width = LOWORD(GetTabbedTextExtent(hdc, start, next,
567                                                                 es->NumTabStops, es->TabStops));
568                                         } while (width <= ww);
569                                         if(!prev) prev = 1;
570                                 }
571                                 length = prev;
572                                 if (EDIT_CallWordBreakProc(wndPtr, start, length - 1,
573                                                                 length, WB_ISDELIMITER)) {
574                                         length--;
575                                         ending = END_DELIMIT;
576                                 } else
577                                         ending = END_NONE;
578                                 width = LOWORD(GetTabbedTextExtent(hdc, start, length,
579                                                         es->NumTabStops, es->TabStops));
580                         }
581
582                         es->LineDefs = xrealloc(es->LineDefs, (es->LineCount + 1) * sizeof(LINEDEF));
583                         es->LineDefs[es->LineCount].offset = start - text;
584                         es->LineDefs[es->LineCount].length = length;
585                         es->LineDefs[es->LineCount].ending = ending;
586                         es->LineCount++;
587                         es->TextWidth = MAX(es->TextWidth, width);
588
589                         start += length;
590                         switch (ending) {
591                         case END_SOFT:
592                                 start += 3;
593                                 break;
594                         case END_HARD:
595                                 start += 2;
596                                 break;
597                         case END_DELIMIT:
598                                 start++;
599                                 break;
600                         default:
601                                 break;
602                         }
603                 } while (*start || (ending == END_SOFT) || (ending == END_HARD));
604         }
605         if (hFont) SelectObject32(hdc, oldFont);
606         ReleaseDC32(wndPtr->hwndSelf, hdc);
607
608         free(text);
609 }
610
611
612 /*********************************************************************
613  *
614  *      EDIT_CallWordBreakProc
615  *
616  *      Call appropriate WordBreakProc (internal or external).
617  *
618  */
619 static INT EDIT_CallWordBreakProc(WND *wndPtr, char *s, INT index, INT count, INT action)
620 {
621     EDITWORDBREAKPROC wbp = (EDITWORDBREAKPROC)EDIT_EM_GetWordBreakProc(wndPtr, 0, 0L);
622
623     if (!wbp) return EDIT_WordBreakProc(s, index, count, action);
624     else
625     {
626         /* We need a SEGPTR here */
627
628         EDITSTATE *es = EDITSTATEPTR(wndPtr);
629         SEGPTR ptr = LOCAL_LockSegptr( wndPtr->hInstance, es->hBuf ) +
630                      (UINT16)(s - EDIT_GetPointer(wndPtr));
631         INT ret = CallWordBreakProc( (FARPROC16)wbp, ptr,
632                                      index, count, action);
633         LOCAL_Unlock( wndPtr->hInstance, es->hBuf );
634         return ret;
635     }
636 }
637
638
639 /*********************************************************************
640  *
641  *      EDIT_ColFromWndX
642  *
643  *      Calculates, for a given line and X-coordinate on the screen, the column.
644  *
645  */
646 static UINT EDIT_ColFromWndX(WND *wndPtr, UINT line, INT x)
647 {       
648         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L);
649         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, line, 0L);
650         UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, li, 0L);
651         UINT i;
652
653         line = MAX(0, MIN(line, lc - 1));
654         for (i = 0 ; i < ll ; i++)
655                 if (EDIT_WndXFromCol(wndPtr, line, i) >= x)
656                         break;
657         return i;
658 }
659
660
661 /*********************************************************************
662  *
663  *      EDIT_DelEnd
664  *
665  *      Delete all characters on this line to right of cursor.
666  *
667  */
668 static void EDIT_DelEnd(WND *wndPtr)
669 {
670         EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(-1, 0));
671         EDIT_MoveEnd(wndPtr, TRUE);
672         EDIT_WM_Clear(wndPtr, 0, 0L);
673 }
674
675
676 /*********************************************************************
677  *
678  *      EDIT_DelLeft
679  *
680  *      Delete character to left of cursor.
681  *
682  */
683 static void EDIT_DelLeft(WND *wndPtr)
684 {
685         EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(-1, 0));
686         EDIT_MoveBackward(wndPtr, TRUE);
687         EDIT_WM_Clear(wndPtr, 0, 0L);
688 }
689
690
691 /*********************************************************************
692  *
693  *      EDIT_DelRight
694  *
695  *      Delete character to right of cursor.
696  *
697  */
698 static void EDIT_DelRight(WND *wndPtr)
699 {
700         EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(-1, 0));
701         EDIT_MoveForward(wndPtr, TRUE);
702         EDIT_WM_Clear(wndPtr, 0, 0L);
703 }
704
705
706 /*********************************************************************
707  *
708  *      EDIT_GetAveCharWidth
709  *
710  */
711 static UINT EDIT_GetAveCharWidth(WND *wndPtr)
712 {
713         EDITSTATE *es = EDITSTATEPTR(wndPtr);
714         
715         return es->AveCharWidth;
716 }
717
718
719 /*********************************************************************
720  *
721  *      EDIT_GetLineHeight
722  *
723  */
724 static UINT EDIT_GetLineHeight(WND *wndPtr)
725 {
726         EDITSTATE *es = EDITSTATEPTR(wndPtr);
727         
728         return es->LineHeight;
729 }
730
731
732 /*********************************************************************
733  *
734  *      EDIT_GetLineRect
735  *
736  *      Calculates the bounding rectangle for a line from a starting
737  *      column to an ending column.
738  *
739  */
740 static void EDIT_GetLineRect(WND *wndPtr, UINT line, UINT scol, UINT ecol, LPRECT16 rc)
741 {
742         rc->top = EDIT_WndYFromLine(wndPtr, line);
743         rc->bottom = rc->top + EDIT_GetLineHeight(wndPtr);
744         rc->left = EDIT_WndXFromCol(wndPtr, line, scol);
745         rc->right = ((INT)ecol == -1) ? EDIT_GetWndWidth(wndPtr) :
746                                 EDIT_WndXFromCol(wndPtr, line, ecol);
747 }
748
749
750 /*********************************************************************
751  *
752  *      EDIT_GetPointer
753  *
754  *      This acts as a LOCAL_Lock(), but it locks only once.  This way
755  *      you can call it whenever you like, without unlocking.
756  *
757  */
758 static char *EDIT_GetPointer(WND *wndPtr)
759 {
760         EDITSTATE *es = EDITSTATEPTR(wndPtr);
761         
762         if (!es->text && es->hBuf)
763                 es->text = LOCAL_Lock(wndPtr->hInstance, es->hBuf);
764         return es->text;
765 }
766
767
768 /*********************************************************************
769  *
770  *      EDIT_GetPasswordPointer
771  *
772  *
773  */
774 static char *EDIT_GetPasswordPointer(WND *wndPtr)
775 {
776         EDITSTATE *es = EDITSTATEPTR(wndPtr);
777         char *text = xstrdup(EDIT_GetPointer(wndPtr));
778         char *p;
779
780         if(es->PasswordChar) {
781                 p = text;
782                 while(*p != '\0') {
783                         if(*p != '\r' && *p != '\n')
784                                 *p = es->PasswordChar;
785                         p++;
786                 }
787         }
788         return text;
789 }
790
791
792 /*********************************************************************
793  *
794  *      EDIT_GetRect
795  *
796  *      Beware: This is not the function called on EM_GETRECT.
797  *      It expects a (LPRECT) in lParam, not a (SEGPTR).
798  *      It is used internally, as if there were no pointer difficulties.
799  *
800  */
801 static LRESULT EDIT_GetRect(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
802 {
803         GetClientRect16( wndPtr->hwndSelf, (LPRECT16)lParam );
804         return 0L;
805 }
806
807
808 /*********************************************************************
809  *
810  *      EDIT_GetRedraw
811  *
812  */
813 static BOOL EDIT_GetRedraw(WND *wndPtr)
814 {
815         EDITSTATE *es = EDITSTATEPTR(wndPtr);
816
817         return es->Redraw;
818 }
819
820
821 /*********************************************************************
822  *
823  *      EDIT_GetSel
824  *
825  *      Beware: This is not the function called on EM_GETSEL.
826  *      It returns the start in the low word and the end in the high word.
827  *      NB s can be greater than e.
828  *
829  */
830 static LRESULT EDIT_GetSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
831 {
832         EDITSTATE *es = EDITSTATEPTR(wndPtr);
833
834         return MAKELONG(es->SelStart, es->SelEnd);
835 }
836
837 /*********************************************************************
838  *
839  *      EDIT_GetTextWidth
840  *
841  */
842 static UINT EDIT_GetTextWidth(WND *wndPtr)
843 {
844         EDITSTATE *es = EDITSTATEPTR(wndPtr);
845         
846         return es->TextWidth;
847 }
848
849
850 /*********************************************************************
851  *
852  *      EDIT_GetVisibleLineCount
853  *
854  */
855 static UINT EDIT_GetVisibleLineCount(WND *wndPtr)
856 {
857         RECT16 rc;
858         
859         EDIT_GetRect(wndPtr, 0, (LPARAM)&rc);
860         return MAX(1, MAX(rc.bottom - rc.top, 0) / EDIT_GetLineHeight(wndPtr));
861 }
862
863
864 /*********************************************************************
865  *
866  *      EDIT_GetWndWidth
867  *
868  */
869 static UINT EDIT_GetWndWidth(WND *wndPtr)
870 {
871         RECT16 rc;
872         
873         EDIT_GetRect(wndPtr, 0, (LPARAM)&rc);
874         return rc.right - rc.left;
875 }
876
877
878 /*********************************************************************
879  *
880  *      EDIT_GetXOffset
881  *
882  */
883 static UINT EDIT_GetXOffset(WND *wndPtr)
884 {
885         EDITSTATE *es = EDITSTATEPTR(wndPtr);
886         
887         return es->XOffset;
888 }
889
890
891 /*********************************************************************
892  *
893  *      EDIT_InvalidateText
894  *
895  *      Invalidate the text from offset start upto, but not including,
896  *      offset end.  Useful for (re)painting the selection.
897  *      Regions outside the linewidth are not invalidated.
898  *      end == -1 means end == TextLength.
899  *      start and end need not be ordered.
900  *
901  */
902 static void EDIT_InvalidateText(WND *wndPtr, UINT start, UINT end)
903 {
904         UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
905         UINT vlc = EDIT_GetVisibleLineCount(wndPtr);
906         UINT sl;
907         UINT el;
908         UINT sc;
909         UINT ec;
910         RECT16 rcWnd;
911         RECT16 rcLine;
912         RECT16 rcUpdate;
913         UINT l;
914
915         if (end == start )
916                 return;
917
918         if ((INT)end == -1)
919                 end = (UINT)EDIT_WM_GetTextLength(wndPtr, 0, 0L);
920         ORDER_UINT(start, end);
921         sl = (UINT)EDIT_EM_LineFromChar(wndPtr, start, 0L);
922         el = (UINT)EDIT_EM_LineFromChar(wndPtr, end, 0L);
923         if ((el < fv) || (sl > fv + vlc))
924                 return;
925
926         sc = start - (UINT)EDIT_EM_LineIndex(wndPtr, sl, 0L);
927         ec = end - (UINT)EDIT_EM_LineIndex(wndPtr, el, 0L);
928         if (sl < fv) {
929                 sl = fv;
930                 sc = 0;
931         }
932         if (el > fv + vlc) {
933                 el = fv + vlc;
934                 ec = (UINT)EDIT_EM_LineLength(wndPtr,
935                                 (UINT)EDIT_EM_LineIndex(wndPtr, el, 0L), 0L);
936         }
937         EDIT_GetRect(wndPtr, 0, (LPARAM)&rcWnd);
938         if (sl == el) {
939                 EDIT_GetLineRect(wndPtr, sl, sc, ec, &rcLine);
940                 if (IntersectRect16(&rcUpdate, &rcWnd, &rcLine))
941                         InvalidateRect16( wndPtr->hwndSelf, &rcUpdate, FALSE );
942         } else {
943                 EDIT_GetLineRect(wndPtr, sl, sc,
944                                 (UINT)EDIT_EM_LineLength(wndPtr,
945                                         (UINT)EDIT_EM_LineIndex(wndPtr, sl, 0L), 0L),
946                                 &rcLine);
947                 if (IntersectRect16(&rcUpdate, &rcWnd, &rcLine))
948                         InvalidateRect16( wndPtr->hwndSelf, &rcUpdate, FALSE );
949                 for (l = sl + 1 ; l < el ; l++) {
950                         EDIT_GetLineRect(wndPtr, l, 0,
951                                 (UINT)EDIT_EM_LineLength(wndPtr,
952                                         (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L), 0L),
953                                 &rcLine);
954                         if (IntersectRect16(&rcUpdate, &rcWnd, &rcLine))
955                                 InvalidateRect16(wndPtr->hwndSelf, &rcUpdate, FALSE);
956                 }
957                 EDIT_GetLineRect(wndPtr, el, 0, ec, &rcLine);
958                 if (IntersectRect16(&rcUpdate, &rcWnd, &rcLine))
959                         InvalidateRect16( wndPtr->hwndSelf, &rcUpdate, FALSE );
960         }
961 }
962
963
964 /*********************************************************************
965  *
966  *      EDIT_LineFromWndY
967  *
968  *      Calculates, for a given Y-coordinate on the screen, the line.
969  *
970  */
971 static UINT EDIT_LineFromWndY(WND *wndPtr, INT y)
972 {
973         UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
974         UINT lh = EDIT_GetLineHeight(wndPtr);
975         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L);
976
977         return MAX(0, MIN(lc - 1, y / lh + fv));
978 }
979
980
981 /*********************************************************************
982  *
983  *      EDIT_MakeFit
984  *
985  *      Try to fit size + 1 bytes in the buffer.  Constrain to limits.
986  *
987  */
988 static BOOL EDIT_MakeFit(WND *wndPtr, UINT size)
989 {
990         EDITSTATE *es = EDITSTATEPTR(wndPtr);
991
992         if (size <= es->BufSize)
993                 return TRUE;
994         if (size > es->BufLimit)
995                 return FALSE;
996         size = ((size / GROWLENGTH) + 1) * GROWLENGTH;
997         if (size > es->BufLimit)
998                 size = es->BufLimit;
999
1000         dprintf_edit(stddeb, "edit: EDIT_MakeFit: trying to ReAlloc to %d+1\n", size);
1001
1002         if (LOCAL_ReAlloc(wndPtr->hInstance, es->hBuf, size + 1, LMEM_MOVEABLE)) {
1003                 es->BufSize = MIN(LOCAL_Size(wndPtr->hInstance, es->hBuf) - 1, es->BufLimit);
1004                 return TRUE;
1005         } else
1006                 return FALSE;
1007 }
1008
1009
1010 /*********************************************************************
1011  *
1012  *      EDIT_MoveBackward
1013  *
1014  */
1015 static void EDIT_MoveBackward(WND *wndPtr, BOOL extend)
1016 {
1017         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1018         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1019         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1020         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1021
1022         if (e - li == 0) {
1023                 if (l) {
1024                         li = (UINT)EDIT_EM_LineIndex(wndPtr, l - 1, 0L);
1025                         e = li + (UINT)EDIT_EM_LineLength(wndPtr, li, 0L);
1026                 }
1027         } else
1028                 e--;
1029         if (!extend)
1030                 s = e;
1031         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
1032 }
1033
1034
1035 /*********************************************************************
1036  *
1037  *      EDIT_MoveDownward
1038  *
1039  */
1040 static void EDIT_MoveDownward(WND *wndPtr, BOOL extend)
1041 {
1042         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1043         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1044         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1045         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, e, 0L);
1046         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1047         INT x;
1048
1049         if (l < lc - 1) {
1050                 x = EDIT_WndXFromCol(wndPtr, l, e - li);
1051                 l++;
1052                 e = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L) +
1053                                 EDIT_ColFromWndX(wndPtr, l, x);
1054         }
1055         if (!extend)
1056                 s = e;
1057         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
1058 }
1059
1060
1061 /*********************************************************************
1062  *
1063  *      EDIT_MoveEnd
1064  *
1065  */
1066 static void EDIT_MoveEnd(WND *wndPtr, BOOL extend)
1067 {
1068         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1069         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1070         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1071         UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, e, 0L);
1072         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1073
1074         e = li + ll;
1075         if (!extend)
1076                 s = e;
1077         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
1078 }
1079
1080
1081 /*********************************************************************
1082  *
1083  *      EDIT_MoveForward
1084  *
1085  */
1086 static void EDIT_MoveForward(WND *wndPtr, BOOL extend)
1087 {
1088         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1089         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1090         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1091         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, e, 0L);
1092         UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, e, 0L);
1093         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1094
1095         if (e - li == ll) {
1096                 if (l != lc - 1)
1097                         e = (UINT)EDIT_EM_LineIndex(wndPtr, l + 1, 0L);
1098         } else
1099                 e++;
1100         if (!extend)
1101                 s = e;
1102         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
1103 }
1104
1105
1106 /*********************************************************************
1107  *
1108  *      EDIT_MoveHome
1109  *
1110  *      Home key: move to beginning of line.
1111  *
1112  */
1113 static void EDIT_MoveHome(WND *wndPtr, BOOL extend)
1114 {
1115         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1116         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1117         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1118         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1119
1120         e = li;
1121         if (!extend)
1122                 s = e;
1123         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
1124 }
1125
1126
1127 /*********************************************************************
1128  *
1129  *      EDIT_MovePageDown
1130  *
1131  */
1132 static void EDIT_MovePageDown(WND *wndPtr, BOOL extend)
1133 {
1134         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1135         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1136         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1137         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, e, 0L);
1138         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1139         INT x;
1140
1141         if (l < lc - 1) {
1142                 x = EDIT_WndXFromCol(wndPtr, l, e - li);
1143                 l = MIN(lc - 1, l + EDIT_GetVisibleLineCount(wndPtr));
1144                 e = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L) +
1145                                 EDIT_ColFromWndX(wndPtr, l, x);
1146         }
1147         if (!extend)
1148                 s = e;
1149         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
1150 }
1151
1152
1153 /*********************************************************************
1154  *
1155  *      EDIT_MovePageUp
1156  *
1157  */
1158 static void EDIT_MovePageUp(WND *wndPtr, BOOL extend)
1159 {
1160         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1161         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1162         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1163         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1164         INT x;
1165
1166         if (l) {
1167                 x = EDIT_WndXFromCol(wndPtr, l, e - li);
1168                 l = MAX(0, l - EDIT_GetVisibleLineCount(wndPtr));
1169                 e = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L) +
1170                                 EDIT_ColFromWndX(wndPtr, l, x);
1171         }
1172         if (!extend)
1173                 s = e;
1174         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
1175 }
1176
1177
1178 /*********************************************************************
1179  *
1180  *      EDIT_MoveUpward
1181  *
1182  */
1183 static void EDIT_MoveUpward(WND *wndPtr, BOOL extend)
1184 {
1185         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1186         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1187         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1188         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1189         INT x;
1190
1191         if (l) {
1192                 x = EDIT_WndXFromCol(wndPtr, l, e - li);
1193                 l--;
1194                 e = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L) +
1195                                 EDIT_ColFromWndX(wndPtr, l, x);
1196         }
1197         if (!extend)
1198                 s = e;
1199         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
1200 }
1201
1202
1203 /*********************************************************************
1204  *
1205  *      EDIT_MoveWordBackward
1206  *
1207  */
1208 static void EDIT_MoveWordBackward(WND *wndPtr, BOOL extend)
1209 {
1210         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1211         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1212         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1213         UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, e, 0L);
1214         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1215         char *text;
1216
1217         if (e - li == 0) {
1218                 if (l) {
1219                         li = (UINT)EDIT_EM_LineIndex(wndPtr, l - 1, 0L);
1220                         e = li + (UINT)EDIT_EM_LineLength(wndPtr, li, 0L);
1221                 }
1222         } else {
1223                 text = EDIT_GetPointer(wndPtr);
1224                 e = li + (UINT)EDIT_CallWordBreakProc(wndPtr,
1225                                 text + li, e - li, ll, WB_LEFT);
1226         }
1227         if (!extend)
1228                 s = e;
1229         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
1230 }
1231
1232
1233 /*********************************************************************
1234  *
1235  *      EDIT_MoveWordForward
1236  *
1237  */
1238 static void EDIT_MoveWordForward(WND *wndPtr, BOOL extend)
1239 {
1240         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1241         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1242         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1243         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, e, 0L);
1244         UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, e, 0L);
1245         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1246         char *text;
1247
1248         if (e - li == ll) {
1249                 if (l != lc - 1)
1250                         e = (UINT)EDIT_EM_LineIndex(wndPtr, l + 1, 0L);
1251         } else {
1252                 text = EDIT_GetPointer(wndPtr);
1253                 e = li + (UINT)EDIT_CallWordBreakProc(wndPtr,
1254                                 text + li, e - li + 1, ll, WB_RIGHT);
1255         }
1256         if (!extend)
1257                 s = e;
1258         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
1259 }
1260
1261
1262 /*********************************************************************
1263  *
1264  *      EDIT_PaintLine
1265  *
1266  */
1267 static void EDIT_PaintLine(WND *wndPtr, HDC32 hdc, UINT line, BOOL rev)
1268 {
1269         UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
1270         UINT vlc = EDIT_GetVisibleLineCount(wndPtr);
1271         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L);
1272         UINT li;
1273         UINT ll;
1274         UINT s;
1275         UINT e;
1276         INT x;
1277         INT y;
1278
1279         if ((line < fv) || (line > fv + vlc) || (line >= lc))
1280                 return;
1281
1282         dprintf_edit(stddeb, "edit: EDIT_PaintLine: line=%d\n", line);
1283
1284         x = EDIT_WndXFromCol(wndPtr, line, 0);
1285         y = EDIT_WndYFromLine(wndPtr, line);
1286         li = (UINT)EDIT_EM_LineIndex(wndPtr, line, 0L);
1287         ll = (UINT)EDIT_EM_LineLength(wndPtr, li, 0L);
1288         s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1289         e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1290         ORDER_UINT(s, e);
1291         s = MIN(li + ll, MAX(li, s));
1292         e = MIN(li + ll, MAX(li, e));
1293         if (rev && (s != e) &&
1294                         ((GetFocus32() == wndPtr->hwndSelf) ||
1295                                 (wndPtr->dwStyle & ES_NOHIDESEL))) {
1296                 x += EDIT_PaintText(wndPtr, hdc, x, y, line, 0, s - li, FALSE);
1297                 x += EDIT_PaintText(wndPtr, hdc, x, y, line, s - li, e - s, TRUE);
1298                 x += EDIT_PaintText(wndPtr, hdc, x, y, line, e - li, li + ll - e, FALSE);
1299         } else
1300                 x += EDIT_PaintText(wndPtr, hdc, x, y, line, 0, ll, FALSE);
1301 }
1302
1303
1304 /*********************************************************************
1305  *
1306  *      EDIT_PaintText
1307  *
1308  */
1309 static UINT EDIT_PaintText(WND *wndPtr, HDC32 hdc, INT x, INT y, UINT line, UINT col, UINT count, BOOL rev)
1310 {
1311         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1312         COLORREF BkColor;
1313         COLORREF TextColor;
1314         UINT ret;
1315         char *text;
1316         UINT li;
1317         UINT xoff;
1318
1319         if (!count)
1320                 return 0;
1321         BkColor = GetBkColor(hdc);
1322         TextColor = GetTextColor(hdc);
1323         if (rev) {
1324                 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1325                 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1326         }
1327         text = EDIT_GetPasswordPointer(wndPtr);
1328         li = (UINT)EDIT_EM_LineIndex(wndPtr, line, 0L);
1329         xoff = EDIT_GetXOffset(wndPtr);
1330         ret = LOWORD(TabbedTextOut(hdc, x, y, text + li + col, count,
1331                                         es->NumTabStops, es->TabStops, -xoff));
1332         free(text);
1333         if (rev) {
1334                 SetBkColor(hdc, BkColor);
1335                 SetTextColor(hdc, TextColor);
1336         }
1337         return ret;
1338 }       
1339
1340
1341 /*********************************************************************
1342  *
1343  *      EDIT_ReleasePointer
1344  *
1345  *      This is the only helper function that can be called with es = NULL.
1346  *      It is called at the end of EditWndProc() to unlock the buffer.
1347  *      
1348  */
1349 static void EDIT_ReleasePointer(WND *wndPtr)
1350 {
1351         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1352         
1353         if (!es)
1354                 return;
1355         if (es->text && es->hBuf)
1356                 LOCAL_Unlock(wndPtr->hInstance, es->hBuf);
1357         es->text = NULL;
1358 }
1359
1360
1361 /*********************************************************************
1362  *
1363  *      EDIT_ReplaceSel
1364  *
1365  *      Beware: This is not the function called on EM_REPLACESEL.
1366  *      It expects a (char *) in lParam, not a (SEGPTR).
1367  *      It is used internally, as if there were no pointer difficulties.
1368  *
1369  */
1370 static LRESULT EDIT_ReplaceSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1371 {
1372         const char *str = (char *)lParam;
1373         int strl = strlen(str);
1374         UINT tl = (UINT)EDIT_WM_GetTextLength(wndPtr, 0, 0L);
1375         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1376         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1377         int i;
1378         char *p;
1379         char *text;
1380         BOOL redraw;
1381
1382         ORDER_UINT(s,e);
1383         if (!EDIT_MakeFit(wndPtr, tl - (e - s) + strl)) {
1384                 EDIT_NOTIFY_PARENT(wndPtr, EN_MAXTEXT);
1385                 return 0L;
1386         }
1387         redraw = EDIT_GetRedraw(wndPtr);
1388         EDIT_WM_SetRedraw(wndPtr, FALSE, 0L);
1389         EDIT_WM_Clear(wndPtr, 0, 0L);
1390         tl = EDIT_WM_GetTextLength(wndPtr, 0, 0L);
1391         e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1392         text = EDIT_GetPointer(wndPtr);
1393         for (p = text + tl ; p >= text + e ; p--)
1394                 p[strl] = p[0];
1395         for (i = 0 , p = text + e ; i < strl ; i++)
1396                 p[i] = str[i];
1397         if(IsUpper(wndPtr))
1398                 AnsiUpperBuff(p, strl);
1399         else if(IsLower(wndPtr))
1400                 AnsiLowerBuff(p, strl);
1401         EDIT_BuildLineDefs(wndPtr);
1402         e += strl;
1403         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(e, e));
1404         EDIT_EM_SetModify(wndPtr, TRUE, 0L);
1405         EDIT_NOTIFY_PARENT(wndPtr, EN_UPDATE);
1406         EDIT_WM_SetRedraw(wndPtr, redraw, 0L);
1407         if (redraw) {
1408                 InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE );
1409                 EDIT_NOTIFY_PARENT(wndPtr, EN_CHANGE);
1410         }
1411         return 0L;
1412 }
1413  
1414
1415 /*********************************************************************
1416  *
1417  *      EDIT_ScrollIntoView
1418  *
1419  *      Makes sure the caret is visible.
1420  *
1421  */
1422 static void EDIT_ScrollIntoView(WND *wndPtr)
1423 {
1424         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1425         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1426         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
1427         UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
1428         UINT vlc = EDIT_GetVisibleLineCount(wndPtr);
1429         UINT ww = EDIT_GetWndWidth(wndPtr);
1430         UINT cw = EDIT_GetAveCharWidth(wndPtr);
1431         INT x = EDIT_WndXFromCol(wndPtr, l, e - li);
1432         int dy = 0;
1433         int dx = 0;
1434
1435         if (l >= fv + vlc)
1436                 dy = l - vlc + 1 - fv;
1437         if (l < fv)
1438                 dy = l - fv;
1439         if (x < 0)
1440                 dx = x - ww / HSCROLL_FRACTION / cw * cw;
1441         if (x > ww)
1442                 dx = x - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
1443         if (dy || dx) {
1444                 EDIT_EM_LineScroll(wndPtr, 0, MAKELPARAM(dy, dx));
1445                 if (dy) 
1446                         EDIT_NOTIFY_PARENT(wndPtr, EN_VSCROLL);
1447                 if (dx)
1448                         EDIT_NOTIFY_PARENT(wndPtr, EN_HSCROLL);
1449         }
1450 }
1451
1452
1453 /*********************************************************************
1454  *
1455  *      EDIT_WndXFromCol
1456  *
1457  *      Calculates, for a given line and column, the X-coordinate on the screen.
1458  *
1459  */
1460 static INT EDIT_WndXFromCol(WND *wndPtr, UINT line, UINT col)
1461 {       
1462         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1463         char *text = EDIT_GetPasswordPointer(wndPtr);
1464         INT ret;
1465         HDC32 hdc;
1466         HFONT16 hFont;
1467         HFONT32 oldFont = 0;
1468         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L);
1469         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, line, 0L);
1470         UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, li, 0L);
1471         UINT xoff = EDIT_GetXOffset(wndPtr);
1472
1473         hdc = GetDC32(wndPtr->hwndSelf);
1474         hFont = (HFONT16)EDIT_WM_GetFont(wndPtr, 0, 0L);
1475         if (hFont) oldFont = SelectObject32(hdc, hFont);
1476         line = MAX(0, MIN(line, lc - 1));
1477         col = MIN(col, ll);
1478         ret = LOWORD(GetTabbedTextExtent(hdc,
1479                         text + li, col,
1480                         es->NumTabStops, es->TabStops)) - xoff;
1481         if (hFont) SelectObject32(hdc, oldFont);
1482         ReleaseDC32(wndPtr->hwndSelf, hdc);
1483         free(text);
1484         return ret;
1485 }
1486
1487
1488 /*********************************************************************
1489  *
1490  *      EDIT_WndYFromLine
1491  *
1492  *      Calculates, for a given line, the Y-coordinate on the screen.
1493  *
1494  */
1495 static INT EDIT_WndYFromLine(WND *wndPtr, UINT line)
1496 {
1497         UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
1498         UINT lh = EDIT_GetLineHeight(wndPtr);
1499
1500         return (line - fv) * lh;
1501 }
1502
1503
1504 /*********************************************************************
1505  *
1506  *      EDIT_WordBreakProc
1507  *
1508  *      Find the beginning of words.
1509  *      Note:   unlike the specs for a WordBreakProc, this function only
1510  *              allows to be called without linebreaks between s[0] upto
1511  *              s[count - 1].  Remember it is only called
1512  *              internally, so we can decide this for ourselves.
1513  *
1514  */
1515 static INT EDIT_WordBreakProc(char *s, INT index, INT count, INT action)
1516 {
1517         INT ret = 0;
1518
1519         dprintf_edit(stddeb, "edit: EDIT_WordBreakProc: s=%p, index=%d"
1520                         ", count=%d, action=%d\n", s, index, count, action);
1521
1522         switch (action) {
1523         case WB_LEFT:
1524                 if (!count) 
1525                         break;
1526                 if (index)
1527                         index--;
1528                 if (s[index] == ' ') {
1529                         while (index && (s[index] == ' '))
1530                                 index--;
1531                         if (index) {
1532                                 while (index && (s[index] != ' '))
1533                                         index--;
1534                                 if (s[index] == ' ')
1535                                         index++;
1536                         }
1537                 } else {
1538                         while (index && (s[index] != ' '))
1539                                 index--;
1540                         if (s[index] == ' ')
1541                                 index++;
1542                 }
1543                 ret = index;
1544                 break;
1545         case WB_RIGHT:
1546                 if (!count)
1547                         break;
1548                 if (index)
1549                         index--;
1550                 if (s[index] == ' ')
1551                         while ((index < count) && (s[index] == ' ')) index++;
1552                 else {
1553                         while (s[index] && (s[index] != ' ') && (index < count))
1554                                 index++;
1555                         while ((s[index] == ' ') && (index < count)) index++;
1556                 }
1557                 ret = index;
1558                 break;
1559         case WB_ISDELIMITER:
1560                 ret = (s[index] == ' ');
1561                 break;
1562         default:
1563                 fprintf(stderr, "edit: EDIT_WordBreakProc: unknown action code, please report !\n");
1564                 break;
1565         }
1566         return ret;
1567 }
1568
1569
1570 /*********************************************************************
1571  *
1572  *      EM_CANUNDO
1573  *
1574  */
1575 static LRESULT EDIT_EM_CanUndo(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1576 {
1577         return 0L;
1578 }
1579
1580
1581 /*********************************************************************
1582  *
1583  *      EM_EMPTYUNDOBUFFER
1584  *
1585  */
1586 static LRESULT EDIT_EM_EmptyUndoBuffer(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1587 {
1588         return 0L;
1589 }
1590
1591
1592 /*********************************************************************
1593  *
1594  *      EM_FMTLINES
1595  *
1596  */
1597 static LRESULT EDIT_EM_FmtLines(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1598 {
1599         fprintf(stdnimp, "edit: EM_FMTLINES: message not implemented.\n");
1600         return wParam ? -1L : 0L;
1601 }
1602
1603
1604 /*********************************************************************
1605  *
1606  *      EM_GETFIRSTVISIBLELINE
1607  *
1608  */
1609 static LRESULT EDIT_EM_GetFirstVisibleLine(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1610 {
1611         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1612         
1613         return (LRESULT)es->FirstVisibleLine;
1614 }
1615
1616
1617 /*********************************************************************
1618  *
1619  *      EM_GETHANDLE
1620  *
1621  */
1622 static LRESULT EDIT_EM_GetHandle(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1623 {
1624         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1625
1626         return (LRESULT)es->hBuf;
1627 }
1628  
1629
1630 /*********************************************************************
1631  *
1632  *      EM_GETLINE
1633  *
1634  */
1635 static LRESULT EDIT_EM_GetLine(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1636 {
1637         char *text;
1638         char *src;
1639         char *dst;
1640         UINT len;
1641         UINT i;
1642         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L);
1643
1644         if (!IsMultiLine(wndPtr))
1645                 wParam = 0;
1646         if ((UINT)wParam >= lc)
1647                 return 0L;
1648         text = EDIT_GetPointer(wndPtr);
1649         src = text + (UINT)EDIT_EM_LineIndex(wndPtr, wParam, 0L);
1650         dst = (char *)PTR_SEG_TO_LIN(lParam);
1651         len = MIN(*(WORD *)dst, (UINT)EDIT_EM_LineLength(wndPtr, wParam, 0L));
1652         for (i = 0 ; i < len ; i++) {
1653                 *dst = *src;
1654                 src++;
1655                 dst++;
1656         }
1657         return (LRESULT)len;
1658 }
1659
1660
1661 /*********************************************************************
1662  *
1663  *      EM_GETLINECOUNT
1664  *
1665  */
1666 static LRESULT EDIT_EM_GetLineCount(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1667 {
1668         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1669         
1670         return (LRESULT)es->LineCount;
1671 }
1672
1673
1674 /*********************************************************************
1675  *
1676  *      EM_GETMODIFY
1677  *
1678  */
1679 static LRESULT EDIT_EM_GetModify(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1680 {
1681         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1682
1683         return (LRESULT)es->TextChanged;
1684 }
1685
1686
1687 /*********************************************************************
1688  *
1689  *      EM_GETPASSWORDCHAR
1690  *
1691  */
1692 static LRESULT EDIT_EM_GetPasswordChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1693 {
1694         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1695
1696         return (LRESULT)es->PasswordChar;
1697 }
1698
1699
1700 /*********************************************************************
1701  *
1702  *      EM_GETRECT
1703  *
1704  */
1705 static LRESULT EDIT_EM_GetRect(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1706 {
1707         return EDIT_GetRect(wndPtr, wParam, (LPARAM)PTR_SEG_TO_LIN(lParam));
1708 }
1709
1710
1711 /*********************************************************************
1712  *
1713  *      EM_GETSEL
1714  *
1715  *      Returns the ordered selection range so that
1716  *      LOWORD(result) < HIWORD(result)
1717  *
1718  */
1719 static LRESULT EDIT_EM_GetSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1720 {
1721         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1722         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1723
1724         ORDER_UINT(s, e);
1725         return MAKELONG(s, e);
1726 }
1727
1728
1729 /*********************************************************************
1730  *
1731  *      EM_GETTHUMB
1732  *
1733  *      FIXME: undocumented: is this right ?
1734  *
1735  */
1736 static LRESULT EDIT_EM_GetThumb(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1737 {
1738         return MAKELONG(EDIT_WM_VScroll(wndPtr, EM_GETTHUMB, 0L),
1739                 EDIT_WM_HScroll(wndPtr, EM_GETTHUMB, 0L));
1740 }
1741
1742
1743 /*********************************************************************
1744  *
1745  *      EM_GETWORDBREAKPROC
1746  *
1747  */
1748 static LRESULT EDIT_EM_GetWordBreakProc(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1749 {
1750         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1751
1752         return (LRESULT)es->WordBreakProc;
1753 }
1754
1755
1756 /*********************************************************************
1757  *
1758  *      EM_LIMITTEXT
1759  *
1760  */
1761 static LRESULT EDIT_EM_LimitText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1762 {
1763         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1764
1765         if (IsMultiLine(wndPtr)) {
1766                 if (wParam)
1767                         es->BufLimit = MIN((UINT)wParam, BUFLIMIT_MULTI);
1768                 else
1769                         es->BufLimit = BUFLIMIT_MULTI;
1770         } else {
1771                 if (wParam)
1772                         es->BufLimit = MIN((UINT)wParam, BUFLIMIT_SINGLE);
1773                 else
1774                         es->BufLimit = BUFLIMIT_SINGLE;
1775         }
1776         return 0L;
1777 }
1778
1779
1780 /*********************************************************************
1781  *
1782  *      EM_LINEFROMCHAR
1783  *
1784  */
1785 static LRESULT EDIT_EM_LineFromChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1786 {
1787         UINT l;
1788
1789         if (!IsMultiLine(wndPtr))
1790                 return 0L;
1791         if ((INT)wParam == -1)
1792                 wParam = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1793         l = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L) - 1;
1794         while ((UINT)EDIT_EM_LineIndex(wndPtr, l, 0L) > (UINT)wParam)
1795                 l--;
1796         return (LRESULT)l;
1797 }
1798
1799
1800 /*********************************************************************
1801  *
1802  *      EM_LINEINDEX
1803  *
1804  */
1805 static LRESULT EDIT_EM_LineIndex(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1806 {
1807         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1808         UINT e;
1809         UINT l;
1810         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L);
1811
1812         if ((INT)wParam == -1) {
1813                 e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1814                 l = lc - 1;
1815                 while (es->LineDefs[l].offset > e)
1816                         l--;
1817                 return (LRESULT)es->LineDefs[l].offset;
1818         }
1819         if ((UINT)wParam >= lc)
1820                 return -1L;
1821         return (LRESULT)es->LineDefs[(UINT)wParam].offset;
1822 }
1823
1824
1825 /*********************************************************************
1826  *
1827  *      EM_LINELENGTH
1828  *
1829  */
1830 static LRESULT EDIT_EM_LineLength(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1831 {
1832         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1833         UINT s;
1834         UINT e;
1835         UINT sl;
1836         UINT el;
1837
1838         if (!IsMultiLine(wndPtr))
1839                 return (LRESULT)es->LineDefs[0].length;
1840         if ((INT)wParam == -1) {
1841                 s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
1842                 e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
1843                 sl = (UINT)EDIT_EM_LineFromChar(wndPtr, s, 0L);
1844                 el = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
1845                 return (LRESULT)(s - es->LineDefs[sl].offset +
1846                                 es->LineDefs[el].offset +
1847                                 es->LineDefs[el].length - e);
1848         }
1849         return (LRESULT)es->LineDefs[(UINT)EDIT_EM_LineFromChar(wndPtr, wParam, 0L)].length;
1850 }
1851  
1852
1853 /*********************************************************************
1854  *
1855  *      EM_LINESCROLL
1856  *
1857  */
1858 static LRESULT EDIT_EM_LineScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1859 {
1860         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1861         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L);
1862         UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
1863         UINT nfv = MAX(0, fv + (INT)LOWORD(lParam));
1864         UINT xoff = EDIT_GetXOffset(wndPtr);
1865         UINT nxoff = MAX(0, xoff + (INT)HIWORD(lParam));
1866         UINT tw = EDIT_GetTextWidth(wndPtr);
1867         INT dx;
1868         INT dy;
1869         POINT16 pos;
1870
1871         if (nfv >= lc)
1872                 nfv = lc - 1;
1873
1874         if (nxoff >= tw)
1875                 nxoff = tw;
1876         dx = xoff - nxoff;
1877         dy = EDIT_WndYFromLine(wndPtr, fv) - EDIT_WndYFromLine(wndPtr, nfv);
1878         if (dx || dy) {
1879                 if (wndPtr->hwndSelf == GetFocus32())
1880                         HideCaret(wndPtr->hwndSelf);
1881                 if (EDIT_GetRedraw(wndPtr)) 
1882                         ScrollWindow(wndPtr->hwndSelf, dx, dy, NULL, NULL);
1883                 es->FirstVisibleLine = nfv;
1884                 es->XOffset = nxoff;
1885                 if (IsVScrollBar(wndPtr))
1886                         SetScrollPos32(wndPtr->hwndSelf, SB_VERT,
1887                                 EDIT_WM_VScroll(wndPtr, EM_GETTHUMB, 0L), TRUE);
1888                 if (IsHScrollBar(wndPtr))
1889                         SetScrollPos32(wndPtr->hwndSelf, SB_HORZ,
1890                                 EDIT_WM_HScroll(wndPtr, EM_GETTHUMB, 0L), TRUE);
1891                 if (wndPtr->hwndSelf == GetFocus32()) {
1892                         GetCaretPos16(&pos);
1893                         SetCaretPos(pos.x + dx, pos.y + dy);
1894                         ShowCaret(wndPtr->hwndSelf);
1895                 }
1896         }
1897         return -1L;
1898 }
1899
1900
1901 /*********************************************************************
1902  *
1903  *      EM_REPLACESEL
1904  *
1905  */
1906 static LRESULT EDIT_EM_ReplaceSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1907 {
1908         return (LRESULT)EDIT_ReplaceSel(wndPtr, wParam,
1909                                 (LPARAM)(char *)PTR_SEG_TO_LIN(lParam));
1910 }
1911  
1912
1913 /*********************************************************************
1914  *
1915  *      EM_SCROLL
1916  *
1917  *      FIXME: undocumented message.
1918  *
1919  */
1920 static LRESULT EDIT_EM_Scroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1921 {
1922         fprintf(stdnimp, "edit: EM_SCROLL: message not implemented (undocumented), please report.\n");
1923         return 0L;
1924 }
1925
1926
1927 /*********************************************************************
1928  *
1929  *      EM_SETHANDLE
1930  *
1931  */
1932 static LRESULT EDIT_EM_SetHandle(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1933 {
1934         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1935
1936         if (IsMultiLine(wndPtr)) {
1937                 EDIT_ReleasePointer(wndPtr);
1938                 /*
1939                  *      old buffer is freed by caller
1940                  */
1941                 es->hBuf = (HLOCAL16)wParam;
1942                 es->BufSize = LOCAL_Size(wndPtr->hInstance, es->hBuf) - 1;
1943                 es->LineCount = 0;
1944                 es->FirstVisibleLine = 0;
1945                 es->SelStart = es->SelEnd = 0;
1946                 EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0L);
1947                 EDIT_EM_SetModify(wndPtr, FALSE, 0L);
1948                 EDIT_BuildLineDefs(wndPtr);
1949                 if (EDIT_GetRedraw(wndPtr))
1950                         InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE );
1951                 EDIT_ScrollIntoView(wndPtr);
1952         }
1953         return 0L;
1954 }
1955
1956
1957 /*********************************************************************
1958  *
1959  *      EM_SETMODIFY
1960  *
1961  */
1962 static LRESULT EDIT_EM_SetModify(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1963 {
1964         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1965
1966         es->TextChanged = (BOOL)wParam;
1967         return 0L;
1968 }
1969
1970
1971 /*********************************************************************
1972  *
1973  *      EM_SETPASSWORDCHAR
1974  *
1975  */
1976 static LRESULT EDIT_EM_SetPasswordChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1977 {
1978         EDITSTATE *es = EDITSTATEPTR(wndPtr);
1979
1980         es->PasswordChar = (char)wParam;
1981         return 0L;
1982 }
1983
1984
1985 /*********************************************************************
1986  *
1987  *      EM_SETREADONLY
1988  *
1989  */
1990 static LRESULT EDIT_EM_SetReadOnly(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1991 {
1992         if ((BOOL)wParam)
1993                 wndPtr->dwStyle |= ES_READONLY;
1994         else
1995                 wndPtr->dwStyle &= ~(DWORD)ES_READONLY;
1996         return 0L;
1997 }
1998
1999
2000 /*********************************************************************
2001  *
2002  *      EM_SETRECT
2003  *
2004  */
2005 static LRESULT EDIT_EM_SetRect(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2006 {
2007         fprintf(stdnimp,"edit: EM_SETRECT: message not implemented, please report.\n");
2008         return 0L;
2009 }
2010
2011
2012 /*********************************************************************
2013  *
2014  *      EM_SETRECTNP
2015  *
2016  */
2017 static LRESULT EDIT_EM_SetRectNP(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2018 {
2019         fprintf(stdnimp,"edit: EM_SETRECTNP: message not implemented, please report.\n");
2020         return 0L;
2021 }
2022
2023
2024 /*********************************************************************
2025  *
2026  *      EM_SETSEL
2027  *
2028  */
2029 static LRESULT EDIT_EM_SetSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2030 {
2031         EDITSTATE *es = EDITSTATEPTR(wndPtr);
2032         UINT ns = LOWORD(lParam);
2033         UINT ne = HIWORD(lParam);
2034         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
2035         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
2036         UINT el;
2037         UINT eli;
2038         UINT tl = (UINT)EDIT_WM_GetTextLength(wndPtr, 0, 0L);
2039
2040         if ((INT)ns == -1) {
2041                 ns = e;
2042                 ne = e;
2043         }
2044         else {
2045                 ns = MIN(ns, tl);
2046                 ne = MIN(ne, tl);
2047         }
2048         es->SelStart = ns;
2049         es->SelEnd = ne;
2050         if (wndPtr->hwndSelf == GetFocus32()) {
2051                 el = (UINT)EDIT_EM_LineFromChar(wndPtr, ne, 0L);
2052                 eli = (UINT)EDIT_EM_LineIndex(wndPtr, el, 0L);
2053                 SetCaretPos(EDIT_WndXFromCol(wndPtr, el, ne - eli),
2054                                 EDIT_WndYFromLine(wndPtr, el));
2055         }
2056         if (!wParam)
2057                 EDIT_ScrollIntoView(wndPtr);
2058         if (EDIT_GetRedraw(wndPtr)) {
2059                 ORDER_UINT(s, e);
2060                 ORDER_UINT(s, ns);
2061                 ORDER_UINT(s, ne);
2062                 ORDER_UINT(e, ns);
2063                 ORDER_UINT(e, ne);
2064                 ORDER_UINT(ns, ne);
2065                 if (e != ns) {
2066                         EDIT_InvalidateText(wndPtr, s, e);
2067                         EDIT_InvalidateText(wndPtr, ns, ne);
2068                 } else
2069                         EDIT_InvalidateText(wndPtr, s, ne);
2070         }
2071         return -1L;
2072 }
2073
2074
2075 /*********************************************************************
2076  *
2077  *      EM_SETTABSTOPS
2078  *
2079  */
2080 static LRESULT EDIT_EM_SetTabStops(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2081 {
2082         EDITSTATE *es = EDITSTATEPTR(wndPtr);
2083
2084         if (!IsMultiLine(wndPtr))
2085                 return 0L;
2086         if (es->TabStops)
2087                 free(es->TabStops);
2088         es->NumTabStops = (UINT)wParam;
2089         if (!wParam)
2090                 es->TabStops = NULL;
2091         else {
2092                 es->TabStops = (LPINT16)xmalloc(wParam * sizeof(INT16));
2093                 memcpy(es->TabStops, (LPINT16)PTR_SEG_TO_LIN(lParam),
2094                                 (UINT)wParam * sizeof(INT16));
2095         }
2096         return 1L;
2097 }
2098
2099
2100 /*********************************************************************
2101  *
2102  *      EM_SETWORDBREAKPROC
2103  *
2104  */
2105 static LRESULT EDIT_EM_SetWordBreakProc(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2106 {
2107         EDITSTATE *es = EDITSTATEPTR(wndPtr);
2108
2109         es->WordBreakProc = (EDITWORDBREAKPROC)lParam;
2110         return 0L;
2111 }
2112
2113
2114 /*********************************************************************
2115  *
2116  *      EM_UNDO
2117  *
2118  */
2119 static LRESULT EDIT_EM_Undo(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2120 {
2121         return 0L;
2122 }
2123
2124
2125 /*********************************************************************
2126  *
2127  *      WM_CHAR
2128  *
2129  */
2130 static LRESULT EDIT_WM_Char(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2131 {
2132         char str[2];
2133         unsigned char c = (unsigned char)wParam;
2134
2135         switch (c) {
2136         case '\r':
2137         case '\n':
2138                 if (IsMultiLine(wndPtr)) {
2139                         if (IsReadOnly(wndPtr)) {
2140                                 EDIT_MoveHome(wndPtr, FALSE);
2141                                 EDIT_MoveDownward(wndPtr, FALSE);
2142                         } else
2143                                 EDIT_ReplaceSel(wndPtr, 0, (LPARAM)"\r\n");
2144                 }
2145                 break;
2146         case '\t':
2147                 if (IsMultiLine(wndPtr) && !IsReadOnly(wndPtr))
2148                         EDIT_ReplaceSel(wndPtr, 0, (LPARAM)"\t");
2149                 break;
2150         default:
2151                 if (!IsReadOnly(wndPtr) && (c >= ' ') && (c != 127)) {
2152                         str[0] = c;
2153                         str[1] = '\0';
2154                         EDIT_ReplaceSel(wndPtr, 0, (LPARAM)str);
2155                 }
2156                 break;
2157         }
2158         return 0L;
2159 }
2160
2161
2162 /*********************************************************************
2163  *
2164  *      WM_CLEAR
2165  *
2166  */
2167 static LRESULT EDIT_WM_Clear(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2168 {
2169         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
2170         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
2171         char *text;
2172         BOOL redraw;
2173         
2174         if (s != e) {
2175                 redraw = EDIT_GetRedraw(wndPtr);
2176                 EDIT_WM_SetRedraw(wndPtr, FALSE, 0L);
2177                 ORDER_UINT(s, e);
2178                 text = EDIT_GetPointer(wndPtr);
2179                 strcpy(text + s, text + e);
2180                 EDIT_BuildLineDefs(wndPtr);
2181                 EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, s));
2182                 EDIT_EM_SetModify(wndPtr, TRUE, 0L);
2183                 EDIT_NOTIFY_PARENT(wndPtr, EN_UPDATE);
2184                 EDIT_WM_SetRedraw(wndPtr, redraw, 0L);
2185                 if (redraw) {
2186                         InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE );
2187                         EDIT_NOTIFY_PARENT(wndPtr, EN_CHANGE);
2188                 }
2189         }
2190         return -1L;
2191 }
2192
2193
2194 /*********************************************************************
2195  *
2196  *      WM_COPY
2197  *
2198  */
2199 static LRESULT EDIT_WM_Copy(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2200 {
2201         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
2202         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
2203         HGLOBAL16 hdst;
2204         char *text;
2205         char *dst;
2206         char *src;
2207         int i;
2208
2209         if (e == s)
2210                 return -1L;
2211         ORDER_UINT(s, e);
2212         hdst = GlobalAlloc16(GMEM_MOVEABLE, (DWORD)(e - s + 1));
2213         dst = GlobalLock16(hdst);
2214         text = EDIT_GetPointer(wndPtr);
2215         src = text + s;
2216         for (i = 0 ; i < e - s ; i++)
2217                 *dst++ = *src++;
2218         *dst = '\0';
2219         GlobalUnlock16(hdst);
2220         OpenClipboard(wndPtr->hwndSelf);
2221         EmptyClipboard();
2222         SetClipboardData(CF_TEXT, hdst);
2223         CloseClipboard();
2224         return -1L;
2225 }
2226
2227
2228 /*********************************************************************
2229  *
2230  *      WM_CREATE
2231  *
2232  */
2233 static LRESULT EDIT_WM_Create(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2234 {
2235         CREATESTRUCT16 *cs = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
2236         EDITSTATE *es;
2237         char *text;
2238
2239         es = xmalloc(sizeof(EDITSTATE));
2240         memset(es, 0, sizeof(EDITSTATE));
2241         *(EDITSTATE **)wndPtr->wExtra = es;
2242
2243         if (cs->style & WS_VSCROLL)
2244                 cs->style |= ES_AUTOVSCROLL;
2245         if (cs->style & WS_HSCROLL)
2246                 cs->style |= ES_AUTOHSCROLL;
2247
2248         /* remove the WS_CAPTION style if it has been set - this is really a  */
2249         /* pseudo option made from a combination of WS_BORDER and WS_DLGFRAME */
2250         if ((cs->style & WS_BORDER) && (cs->style & WS_DLGFRAME))
2251                 cs->style ^= WS_DLGFRAME;
2252
2253         if (IsMultiLine(wndPtr)) {
2254                 es->BufSize = BUFSTART_MULTI;
2255                 es->BufLimit = BUFLIMIT_MULTI;
2256                 es->PasswordChar = '\0';
2257         } else {
2258                 es->BufSize = BUFSTART_SINGLE;
2259                 es->BufLimit = BUFLIMIT_SINGLE;
2260                 es->PasswordChar = (cs->style & ES_PASSWORD) ? '*' : '\0';
2261         }
2262         if (!LOCAL_HeapSize(wndPtr->hInstance)) {
2263                 if (!LocalInit(wndPtr->hInstance, 0,
2264                                GlobalSize16(wndPtr->hInstance))) {
2265                         fprintf(stderr, "edit: WM_CREATE: could not initialize local heap\n");
2266                         return -1L;
2267                 }
2268                 dprintf_edit(stddeb, "edit: WM_CREATE: local heap initialized\n");
2269         }
2270         if (!(es->hBuf = LOCAL_Alloc(wndPtr->hInstance, LMEM_MOVEABLE, es->BufSize + 1))) {
2271                 fprintf(stderr, "edit: WM_CREATE: unable to allocate buffer\n");
2272                 return -1L;
2273         }
2274         es->BufSize = LOCAL_Size(wndPtr->hInstance, es->hBuf) - 1;
2275         text = EDIT_GetPointer(wndPtr);
2276         *text = '\0';
2277         EDIT_BuildLineDefs(wndPtr);
2278         EDIT_WM_SetFont(wndPtr, 0, 0L);
2279         if (cs->lpszName && *(char *)PTR_SEG_TO_LIN(cs->lpszName) != '\0')
2280                 EDIT_EM_ReplaceSel(wndPtr, FALSE, (LPARAM)cs->lpszName);
2281         EDIT_WM_SetRedraw(wndPtr, TRUE, 0L);
2282         return 0L;
2283 }
2284
2285
2286 /*********************************************************************
2287  *
2288  *      WM_CUT
2289  *
2290  */
2291 static LRESULT EDIT_WM_Cut(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2292 {
2293         EDIT_WM_Copy(wndPtr, 0, 0L);
2294         EDIT_WM_Clear(wndPtr, 0, 0L);
2295         return -1L;
2296 }
2297
2298
2299 /*********************************************************************
2300  *
2301  *      WM_DESTROY
2302  *
2303  */
2304 static LRESULT EDIT_WM_Destroy(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2305 {
2306         EDITSTATE *es = EDITSTATEPTR(wndPtr);
2307
2308         free(es->LineDefs);
2309         if (es->TabStops)
2310                 free(es->TabStops);
2311         EDIT_ReleasePointer(wndPtr);
2312         LOCAL_Free(wndPtr->hInstance, es->hBuf);
2313         free(es);
2314         *(EDITSTATE **)&wndPtr->wExtra = NULL;
2315         return 0L;
2316 }
2317
2318
2319 /*********************************************************************
2320  *
2321  *      WM_ENABLE
2322  *
2323  */
2324 static LRESULT EDIT_WM_Enable(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2325 {
2326         EDIT_InvalidateText(wndPtr, 0, -1);
2327         return 0L;
2328 }
2329
2330
2331 /*********************************************************************
2332  *
2333  *      WM_ERASEBKGND
2334  *
2335  */
2336 static LRESULT EDIT_WM_EraseBkGnd(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2337 {
2338         HBRUSH32 hBrush;
2339         RECT16 rc;
2340
2341         hBrush = (HBRUSH16)EDIT_SEND_CTLCOLOR(wndPtr, wParam);
2342         if (!hBrush) hBrush = (HBRUSH32)GetStockObject32(WHITE_BRUSH);
2343
2344         GetClientRect16(wndPtr->hwndSelf, &rc);
2345         IntersectClipRect16( (HDC16)wParam, rc.left, rc.top,
2346                              rc.right, rc.bottom);
2347         GetClipBox16((HDC16)wParam, &rc);
2348         /*
2349          *      FIXME:  specs say that we should UnrealizeObject() the brush,
2350          *              but the specs of UnrealizeObject() say that we shouldn't
2351          *              unrealize a stock object.  The default brush that
2352          *              DefWndProc() returns is ... a stock object.
2353          */
2354         FillRect16((HDC16)wParam, &rc, hBrush);
2355         return -1L;
2356 }
2357
2358
2359 /*********************************************************************
2360  *
2361  *      WM_GETDLGCODE
2362  *
2363  */
2364 static LRESULT EDIT_WM_GetDlgCode(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2365 {
2366         return DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
2367 }
2368
2369
2370 /*********************************************************************
2371  *
2372  *      WM_GETFONT
2373  *
2374  */
2375 static LRESULT EDIT_WM_GetFont(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2376 {
2377         EDITSTATE *es = EDITSTATEPTR(wndPtr);
2378
2379         return (LRESULT)es->hFont;
2380 }
2381
2382
2383 /*********************************************************************
2384  *
2385  *      WM_GETTEXT
2386  *
2387  */
2388 static LRESULT EDIT_WM_GetText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2389 {
2390         char *text = EDIT_GetPointer(wndPtr);
2391         int len;
2392         LRESULT lResult = 0L;
2393
2394         len = strlen(text);
2395         if ((UINT)wParam > len) {
2396                 strcpy((char *)PTR_SEG_TO_LIN(lParam), text);
2397                 lResult = (LRESULT)len ;
2398         }
2399         return lResult;
2400 }
2401
2402
2403 /*********************************************************************
2404  *
2405  *      WM_GETTEXTLENGTH
2406  *
2407  */
2408 static LRESULT EDIT_WM_GetTextLength(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2409 {
2410         char *text = EDIT_GetPointer(wndPtr);
2411
2412         return (LRESULT)strlen(text);
2413 }
2414  
2415
2416 /*********************************************************************
2417  *
2418  *      WM_HSCROLL
2419  *
2420  *      FIXME: scrollbar code itself is broken, so this one is a hack.
2421  *
2422  */
2423 static LRESULT EDIT_WM_HScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2424 {
2425         UINT ww = EDIT_GetWndWidth(wndPtr);
2426         UINT tw = EDIT_GetTextWidth(wndPtr);
2427         UINT cw = EDIT_GetAveCharWidth(wndPtr);
2428         UINT xoff = EDIT_GetXOffset(wndPtr);
2429         INT dx = 0;
2430         BOOL not = TRUE;
2431         LRESULT ret = 0L;
2432
2433         switch (wParam) {
2434         case SB_LINELEFT:
2435                 dx = -cw;
2436                 break;
2437         case SB_LINERIGHT:
2438                 dx = cw;
2439                 break;
2440         case SB_PAGELEFT:
2441                 dx = -ww / HSCROLL_FRACTION / cw * cw;
2442                 break;
2443         case SB_PAGERIGHT:
2444                 dx = ww / HSCROLL_FRACTION / cw * cw;
2445                 break;
2446         case SB_LEFT:
2447                 dx = -xoff;
2448                 break;
2449         case SB_RIGHT:
2450                 dx = tw - xoff;
2451                 break;
2452         case SB_THUMBTRACK:
2453 /*
2454  *              not = FALSE;
2455  */
2456         case SB_THUMBPOSITION:
2457                 dx = LOWORD(lParam) * tw / 100 - xoff;
2458                 break;
2459         /* The next two are undocumented ! */
2460         case EM_GETTHUMB:
2461                 ret = tw ? MAKELONG(xoff * 100 / tw, 0) : 0;
2462                 break;
2463         case EM_LINESCROLL:
2464                 dx = LOWORD(lParam);
2465                 break;
2466         case SB_ENDSCROLL:
2467         default:
2468                 break;
2469         }
2470         if (dx) {
2471                 EDIT_EM_LineScroll(wndPtr, 0, MAKELPARAM(0, dx));
2472                 if (not)
2473                         EDIT_NOTIFY_PARENT(wndPtr, EN_HSCROLL);
2474         }
2475         return ret;
2476 }
2477
2478
2479 /*********************************************************************
2480  *
2481  *      WM_KEYDOWN
2482  *
2483  *      Handling of special keys that don't produce a WM_CHAR
2484  *      (i.e. non-printable keys) & Backspace & Delete
2485  *
2486  */
2487 static LRESULT EDIT_WM_KeyDown(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2488 {
2489         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
2490         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
2491         BOOL shift;
2492         BOOL control;
2493
2494         if (GetKeyState(VK_MENU) & 0x8000)
2495                 return 0L;
2496
2497         shift = GetKeyState(VK_SHIFT) & 0x8000;
2498         control = GetKeyState(VK_CONTROL) & 0x8000;
2499
2500         switch (wParam) {
2501         case VK_LEFT:
2502         case VK_UP:
2503                 if (IsMultiLine(wndPtr) && (wParam == VK_UP))
2504                         EDIT_MoveUpward(wndPtr, shift);
2505                 else
2506                         if (control)
2507                                 EDIT_MoveWordBackward(wndPtr, shift);
2508                         else
2509                                 EDIT_MoveBackward(wndPtr, shift);
2510                 break;
2511         case VK_RIGHT:
2512         case VK_DOWN:
2513                 if (IsMultiLine(wndPtr) && (wParam == VK_DOWN))
2514                         EDIT_MoveDownward(wndPtr, shift);
2515                 else if (control)
2516                         EDIT_MoveWordForward(wndPtr, shift);
2517                 else
2518                         EDIT_MoveForward(wndPtr, shift);
2519                 break;
2520         case VK_HOME:
2521                 EDIT_MoveHome(wndPtr, shift);
2522                 break;
2523         case VK_END:
2524                 EDIT_MoveEnd(wndPtr, shift);
2525                 break;
2526         case VK_PRIOR:
2527                 if (IsMultiLine(wndPtr))
2528                         EDIT_MovePageUp(wndPtr, shift);
2529                 break;
2530         case VK_NEXT:
2531                 if (IsMultiLine(wndPtr))
2532                         EDIT_MovePageDown(wndPtr, shift);
2533                 break;
2534         case VK_BACK:
2535                 if (!IsReadOnly(wndPtr) && !control)
2536                         if (e != s)
2537                                 EDIT_WM_Clear(wndPtr, 0, 0L);
2538                         else
2539                                 EDIT_DelLeft(wndPtr);
2540                 break;
2541         case VK_DELETE:
2542                 if (!IsReadOnly(wndPtr) && !(shift && control))
2543                         if (e != s) {
2544                                 if (shift)
2545                                         EDIT_WM_Cut(wndPtr, 0, 0L);
2546                                 else
2547                                         EDIT_WM_Clear(wndPtr, 0, 0L);
2548                         } else {
2549                                 if (shift)
2550                                         EDIT_DelLeft(wndPtr);
2551                                 else if (control)
2552                                         EDIT_DelEnd(wndPtr);
2553                                 else
2554                                         EDIT_DelRight(wndPtr);
2555                         }
2556                 break;
2557         case VK_INSERT:
2558                 if (shift) {
2559                         if (!IsReadOnly(wndPtr))
2560                                 EDIT_WM_Paste(wndPtr, 0, 0L);
2561                 } else if (control)
2562                         EDIT_WM_Copy(wndPtr, 0, 0L);
2563                 break;
2564         }
2565         return 0L;
2566 }
2567
2568
2569 /*********************************************************************
2570  *
2571  *      WM_KILLFOCUS
2572  *
2573  */
2574 static LRESULT EDIT_WM_KillFocus(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2575 {
2576         UINT s;
2577         UINT e;
2578
2579         DestroyCaret();
2580         if(!(wndPtr->dwStyle & ES_NOHIDESEL)) {
2581                 s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
2582                 e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
2583                 EDIT_InvalidateText(wndPtr, s, e);
2584         }
2585         EDIT_NOTIFY_PARENT(wndPtr, EN_KILLFOCUS);
2586         return 0L;
2587 }
2588
2589
2590 /*********************************************************************
2591  *
2592  *      WM_LBUTTONDBLCLK
2593  *
2594  *      The caret position has been set on the WM_LBUTTONDOWN message
2595  *
2596  */
2597 static LRESULT EDIT_WM_LButtonDblClk(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2598 {
2599         UINT s;
2600         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
2601         UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L);
2602         UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
2603         UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, e, 0L);
2604         char *text = EDIT_GetPointer(wndPtr);
2605
2606         s = li + EDIT_CallWordBreakProc (wndPtr, text + li, e - li, ll, WB_LEFT);
2607         e = li + EDIT_CallWordBreakProc(wndPtr, text + li, e - li, ll, WB_RIGHT);
2608         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
2609         return 0L;
2610 }
2611
2612
2613 /*********************************************************************
2614  *
2615  *      WM_LBUTTONDOWN
2616  *
2617  */
2618 static LRESULT EDIT_WM_LButtonDown(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2619 {
2620         INT x = (INT)LOWORD(lParam);
2621         INT y = (INT)HIWORD(lParam);
2622         UINT l = EDIT_LineFromWndY(wndPtr, y);
2623         UINT c;
2624         UINT s;
2625         UINT e;
2626         UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
2627         UINT vlc = EDIT_GetVisibleLineCount(wndPtr);
2628         UINT li;
2629
2630         SetFocus32(wndPtr->hwndSelf);
2631         SetCapture32(wndPtr->hwndSelf);
2632         l = MIN(fv + vlc - 1, MAX(fv, l));
2633         x = MIN(EDIT_GetWndWidth(wndPtr), MAX(0, x));
2634         c = EDIT_ColFromWndX(wndPtr, l, x);
2635         li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
2636         e = li + c;
2637         if (GetKeyState(VK_SHIFT) & 0x8000)
2638                 s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
2639         else 
2640                 s = e;
2641         EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e));
2642         return 0L;
2643 }
2644
2645
2646 /*********************************************************************
2647  *
2648  *      WM_LBUTTONUP
2649  *
2650  */
2651 static LRESULT EDIT_WM_LButtonUp(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2652 {
2653         if (GetCapture32() == wndPtr->hwndSelf)
2654                 ReleaseCapture();
2655         return 0L;
2656 }
2657
2658
2659 /*********************************************************************
2660  *
2661  *      WM_MOUSEMOVE
2662  *
2663  */
2664 static LRESULT EDIT_WM_MouseMove(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2665 {
2666         INT x;
2667         INT y;
2668         UINT l;
2669         UINT c;
2670         UINT s;
2671         UINT fv;
2672         UINT vlc;
2673         UINT li;
2674
2675         if (GetCapture32() == wndPtr->hwndSelf) {
2676                 x = (INT)LOWORD(lParam);
2677                 y = (INT)HIWORD(lParam);
2678                 fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
2679                 vlc = EDIT_GetVisibleLineCount(wndPtr);
2680                 l = EDIT_LineFromWndY(wndPtr, y);
2681                 l = MIN(fv + vlc - 1, MAX(fv, l));
2682                 x = MIN(EDIT_GetWndWidth(wndPtr), MAX(0, x));
2683                 c = EDIT_ColFromWndX(wndPtr, l, x);
2684                 s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
2685                 li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L);
2686                 EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(s, li + c));
2687         }
2688         return 0L;
2689 }
2690
2691
2692 /*********************************************************************
2693  *
2694  *      WM_PAINT
2695  *
2696  */
2697 static LRESULT EDIT_WM_Paint(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2698 {
2699         PAINTSTRUCT16 ps;
2700         UINT i;
2701         UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
2702         UINT vlc = EDIT_GetVisibleLineCount(wndPtr);
2703         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L);
2704         HDC16 hdc;
2705         HFONT16 hFont;
2706         HFONT32 oldFont = 0;
2707         RECT16 rc;
2708         RECT16 rcLine;
2709         RECT16 rcRgn;
2710         BOOL rev = IsWindowEnabled(wndPtr->hwndSelf) &&
2711                                 ((GetFocus32() == wndPtr->hwndSelf) ||
2712                                         (wndPtr->dwStyle & ES_NOHIDESEL));
2713
2714         hdc = BeginPaint16(wndPtr->hwndSelf, &ps);
2715         GetClientRect16(wndPtr->hwndSelf, &rc);
2716         IntersectClipRect16( hdc, rc.left, rc.top, rc.right, rc.bottom );
2717         hFont = EDIT_WM_GetFont(wndPtr, 0, 0L);
2718         if (hFont) oldFont = SelectObject32(hdc, hFont);
2719         EDIT_SEND_CTLCOLOR(wndPtr, hdc);
2720         if (!IsWindowEnabled(wndPtr->hwndSelf))
2721                 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
2722         GetClipBox16(hdc, &rcRgn);
2723         for (i = fv ; i <= MIN(fv + vlc, fv + lc - 1) ; i++ ) {
2724                 EDIT_GetLineRect(wndPtr, i, 0, -1, &rcLine);
2725                 if (IntersectRect16(&rc, &rcRgn, &rcLine))
2726                         EDIT_PaintLine(wndPtr, hdc, i, rev);
2727         }
2728         if (hFont) SelectObject32(hdc, oldFont);
2729         EndPaint16(wndPtr->hwndSelf, &ps);
2730         return 0L;
2731 }
2732
2733
2734 /*********************************************************************
2735  *
2736  *      WM_PASTE
2737  *
2738  */
2739 static LRESULT EDIT_WM_Paste(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2740 {
2741         HGLOBAL16 hsrc;
2742         char *src;
2743
2744         OpenClipboard(wndPtr->hwndSelf);
2745         if ((hsrc = GetClipboardData(CF_TEXT))) {
2746                 src = (char *)GlobalLock16(hsrc);
2747                 EDIT_ReplaceSel(wndPtr, 0, (LPARAM)src);
2748                 GlobalUnlock16(hsrc);
2749         }
2750         CloseClipboard();
2751         return -1L;
2752 }
2753
2754
2755 /*********************************************************************
2756  *
2757  *      WM_SETCURSOR
2758  *
2759  */
2760 static LRESULT EDIT_WM_SetCursor(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2761 {
2762         if (LOWORD(lParam) == HTCLIENT) {
2763                 SetCursor(LoadCursor16(0, IDC_IBEAM));
2764                 return -1L;
2765         } else
2766                 return 0L;
2767 }
2768
2769
2770 /*********************************************************************
2771  *
2772  *      WM_SETFOCUS
2773  *
2774  */
2775 static LRESULT EDIT_WM_SetFocus(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2776 {
2777         UINT s = LOWORD(EDIT_GetSel(wndPtr, 0, 0L));
2778         UINT e = HIWORD(EDIT_GetSel(wndPtr, 0, 0L));
2779
2780         CreateCaret(wndPtr->hwndSelf, 0, 2, EDIT_GetLineHeight(wndPtr));
2781         EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(s, e));
2782         if(!(wndPtr->dwStyle & ES_NOHIDESEL))
2783                 EDIT_InvalidateText(wndPtr, s, e);
2784         ShowCaret(wndPtr->hwndSelf);
2785         EDIT_NOTIFY_PARENT(wndPtr, EN_SETFOCUS);
2786         return 0L;
2787 }
2788
2789
2790 /*********************************************************************
2791  *
2792  *      WM_SETFONT
2793  *
2794  */
2795 static LRESULT EDIT_WM_SetFont(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2796 {
2797         TEXTMETRIC16 tm;
2798         EDITSTATE *es = EDITSTATEPTR(wndPtr);
2799         LPARAM sel = EDIT_GetSel(wndPtr, 0, 0L);
2800         HDC32 hdc;
2801         HFONT32 oldFont = 0;
2802
2803         es->hFont = (HFONT16)wParam;
2804         hdc = GetDC32(wndPtr->hwndSelf);
2805         if (es->hFont) oldFont = SelectObject32(hdc, es->hFont);
2806         GetTextMetrics16(hdc, &tm);
2807         es->LineHeight = HIWORD(GetTextExtent(hdc, "X", 1));
2808         es->AveCharWidth = tm.tmAveCharWidth;
2809         if (es->hFont) SelectObject32(hdc, oldFont);
2810         ReleaseDC32(wndPtr->hwndSelf, hdc);
2811         EDIT_BuildLineDefs(wndPtr);
2812         if ((BOOL)lParam && EDIT_GetRedraw(wndPtr))
2813                 InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE );
2814         if (wndPtr->hwndSelf == GetFocus32()) {
2815                 DestroyCaret();
2816                 CreateCaret(wndPtr->hwndSelf, 0, 2, EDIT_GetLineHeight(wndPtr));
2817                 EDIT_EM_SetSel(wndPtr, 1, sel);
2818                 ShowCaret(wndPtr->hwndSelf);
2819         }
2820         return 0L;
2821 }
2822
2823
2824 /*********************************************************************
2825  *
2826  *      WM_SETREDRAW
2827  *
2828  */
2829 static LRESULT EDIT_WM_SetRedraw(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2830 {
2831         EDITSTATE *es = EDITSTATEPTR(wndPtr);
2832
2833         es->Redraw = (BOOL)wParam;
2834         return 0L;
2835 }
2836
2837
2838 /*********************************************************************
2839  *
2840  *      WM_SETTEXT
2841  *
2842  */
2843 static LRESULT EDIT_WM_SetText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2844 {
2845         EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(0, -1));
2846         EDIT_WM_Clear(wndPtr, 0, 0L);
2847         if (lParam)
2848                 EDIT_EM_ReplaceSel(wndPtr, 0, lParam);
2849         EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0L);
2850         EDIT_EM_SetModify(wndPtr, TRUE, 0L);
2851         EDIT_ScrollIntoView(wndPtr);
2852         return 0L;
2853 }
2854
2855
2856 /*********************************************************************
2857  *
2858  *      WM_SIZE
2859  *
2860  */
2861 static LRESULT EDIT_WM_Size(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2862 {
2863         if (EDIT_GetRedraw(wndPtr) &&
2864                         ((wParam == SIZE_MAXIMIZED) ||
2865                                 (wParam == SIZE_RESTORED))) {
2866                 if (IsMultiLine(wndPtr) && IsWordWrap(wndPtr))
2867                         EDIT_BuildLineDefs(wndPtr);
2868                 InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE );
2869         }
2870         return 0L;
2871 }
2872
2873
2874 /*********************************************************************
2875  *
2876  *      WM_VSCROLL
2877  *
2878  *      FIXME: scrollbar code itself is broken, so this one is a hack.
2879  *
2880  */
2881 static LRESULT EDIT_WM_VScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
2882 {
2883         UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L);
2884         UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
2885         UINT vlc = EDIT_GetVisibleLineCount(wndPtr);
2886         INT dy = 0;
2887         BOOL not = TRUE;
2888         LRESULT ret = 0L;
2889
2890         switch (wParam) {
2891         case SB_LINEUP:
2892                 dy = -1;
2893                 break;
2894         case SB_LINEDOWN:
2895                 dy = 1;
2896                 break;
2897         case SB_PAGEUP:
2898                 dy = -vlc;
2899                 break;
2900         case SB_PAGEDOWN:
2901                 dy = vlc;
2902                 break;
2903         case SB_TOP:
2904                 dy = -fv;
2905                 break;
2906         case SB_BOTTOM:
2907                 dy = lc - 1 - fv;
2908                 break;
2909         case SB_THUMBTRACK:
2910 /*
2911  *              not = FALSE;
2912  */
2913         case SB_THUMBPOSITION:
2914                 dy = LOWORD(lParam) * (lc - 1) / 100 - fv;
2915                 break;
2916         /* The next two are undocumented ! */
2917         case EM_GETTHUMB:
2918                 ret = (lc > 1) ? MAKELONG(fv * 100 / (lc - 1), 0) : 0L;
2919                 break;
2920         case EM_LINESCROLL:
2921                 dy = LOWORD(lParam);
2922                 break;
2923         case SB_ENDSCROLL:
2924         default:
2925                 break;
2926         }
2927         if (dy) {
2928                 EDIT_EM_LineScroll(wndPtr, 0, MAKELPARAM(dy, 0));
2929                 if (not)
2930                         EDIT_NOTIFY_PARENT(wndPtr, EN_VSCROLL);
2931         }
2932         return ret;
2933 }