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