Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / win / wtext.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: wtext.c,v 1.15.2.2 2008/05/29 20:01:25 sfeam Exp $"); }
3 #endif
4
5 /* GNUPLOT - win/wtext.c */
6 /*[
7  * Copyright 1992, 1993, 1998, 2004   Russell Lang
8  *
9  * Permission to use, copy, and distribute this software and its
10  * documentation for any purpose with or without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and
12  * that both that copyright notice and this permission notice appear
13  * in supporting documentation.
14  *
15  * Permission to modify the software is granted, but not the right to
16  * distribute the complete modified source code.  Modifications are to
17  * be distributed as patches to the released version.  Permission to
18  * distribute binaries produced by compiling modified sources is granted,
19  * provided you
20  *   1. distribute the corresponding source modifications from the
21  *    released version in the form of a patch file along with the binaries,
22  *   2. add special version identification to distinguish your version
23  *    in addition to the base release version number,
24  *   3. provide your name and address as the primary contact for the
25  *    support of your modified version, and
26  *   4. retain our contact information in regard to use of the base
27  *    software.
28  * Permission to distribute the released version of the source code along
29  * with corresponding source modifications in the form of a patch file is
30  * granted with same provisions 2 through 4 for binary distributions.
31  *
32  * This software is provided "as is" without express or implied warranty
33  * to the extent permitted by applicable law.
34 ]*/
35
36 /*
37  * AUTHORS
38  *
39  *   Russell Lang
40  */
41
42 /* WARNING: Do not write to stdout/stderr with functions not listed
43    in win/wtext.h */
44
45 #define STRICT
46
47 #include <string.h>     /* use only far items */
48 #include <stdlib.h>
49 #include <ctype.h>
50 #include <dos.h>
51 #ifndef __MSC__
52 # include <mem.h>
53 #endif
54
55 #ifdef WIN32
56 /* needed for mouse scroll wheel support */
57 #define _WIN32_WINNT 0x0400
58 #endif
59
60 #include <windows.h>
61 #include <windowsx.h>
62 #if WINVER >= 0x030a
63 # include <commdlg.h>
64 #endif
65
66 #include "wgnuplib.h"
67 #include "wresourc.h"
68 #include "wcommon.h"
69
70 /* font stuff */
71 #define TEXTFONTSIZE 9
72 #define TEXTFONTNAME "Terminal"
73
74 #ifndef EOF /* HBB 980809: for MinGW32 */
75 #define EOF -1          /* instead of using <stdio.h> */
76 #endif
77 /* limits */
78 #define MAXSTR 256
79 POINT ScreenMinSize = {16,4};
80
81 LRESULT CALLBACK WINEXPORT WndParentProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
82 LRESULT CALLBACK WINEXPORT WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
83
84 void ReadTextIni(LPTW lptw);
85 void LimitMark(LPTW lptw, POINT FAR *lppt);
86
87 char szNoMemory[] = "out of memory";
88 COLORREF TextColorTable[16] = {
89         RGB(0,0,0),                     /* black */
90         RGB(0,0,128),           /* dark blue */
91         RGB(0,128,0),           /* dark green */
92         RGB(0,128,128),         /* dark cyan */
93         RGB(128,0,0),           /* dark red */
94         RGB(128,0,128),         /* dark magenta */
95         RGB(128,128,0),         /* dark yellow */
96         RGB(128,128,128),       /* dark grey */
97         RGB(192,192,192),       /* light grey */
98         RGB(0,0,255),           /* blue */
99         RGB(0,255,0),           /* green */
100         RGB(0,255,255),         /* cyan */
101         RGB(255,0,0),           /* red */
102         RGB(255,0,255),         /* magenta */
103         RGB(255,255,0),         /* yellow */
104         RGB(255,255,255),       /* white */
105 };
106 #define NOTEXT 0xF0
107 #define MARKFORE RGB(255,255,255)
108 #define MARKBACK RGB(0,0,128)
109 #define TextFore(attr) TextColorTable[(attr) & 15]
110 #define TextBack(attr) TextColorTable[(attr>>4) & 15]
111
112
113 void WDPROC
114 TextMessage()
115 {
116     MSG msg;
117
118     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
119 #if 1 /* HBB 19990505: Petzold says we should check this: */
120         if (msg.message == WM_QUIT)
121             return;
122 #endif
123         TranslateMessage(&msg);
124         DispatchMessage(&msg);
125     }
126 }
127
128
129
130 void
131 CreateTextClass(LPTW lptw)
132 {
133     WNDCLASS wndclass;
134
135 #ifdef WIN32
136     hdllInstance = lptw->hInstance;     /* not using a DLL */
137 #endif
138     wndclass.style = CS_HREDRAW | CS_VREDRAW;
139     wndclass.lpfnWndProc = WndTextProc;
140     wndclass.cbClsExtra = 0;
141     wndclass.cbWndExtra = 2 * sizeof(void FAR *);
142     wndclass.hInstance = lptw->hInstance;
143     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
144     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
145     wndclass.hbrBackground = NULL;
146     lptw->hbrBackground = CreateSolidBrush(lptw->bSysColors ?
147                                            GetSysColor(COLOR_WINDOW) : RGB(0,0,0));
148     wndclass.lpszMenuName = NULL;
149     wndclass.lpszClassName = szTextClass;
150     RegisterClass(&wndclass);
151
152     wndclass.style = CS_HREDRAW | CS_VREDRAW;
153     wndclass.lpfnWndProc = WndParentProc;
154     wndclass.cbClsExtra = 0;
155     wndclass.cbWndExtra = 2 * sizeof(void FAR *);
156     wndclass.hInstance = lptw->hInstance;
157     if (lptw->hIcon)
158         wndclass.hIcon = lptw->hIcon;
159     else
160         wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
161     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
162     wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
163     wndclass.lpszMenuName = NULL;
164     wndclass.lpszClassName = szParentClass;
165     RegisterClass(&wndclass);
166 }
167
168
169 /* make text window */
170 int WDPROC
171 TextInit(LPTW lptw)
172 {
173     RECT rect;
174     HMENU sysmenu;
175     HGLOBAL hglobal;
176
177     ReadTextIni(lptw);
178
179     if (!lptw->hPrevInstance)
180         CreateTextClass(lptw);
181
182     if (lptw->KeyBufSize == 0)
183         lptw->KeyBufSize = 256;
184
185     if (lptw->ScreenSize.x < ScreenMinSize.x)
186         lptw->ScreenSize.x = ScreenMinSize.x;
187     if (lptw->ScreenSize.y < ScreenMinSize.y)
188         lptw->ScreenSize.y = ScreenMinSize.y;
189
190     lptw->CursorPos.x = lptw->CursorPos.y = 0;
191     lptw->bFocus = FALSE;
192     lptw->bGetCh = FALSE;
193     lptw->CaretHeight = 0;
194     if (!lptw->nCmdShow)
195         lptw->nCmdShow = SW_SHOWNORMAL;
196     if (!lptw->Attr)
197         lptw->Attr = 0xf0;      /* black on white */
198
199     hglobal = GlobalAlloc(GHND, lptw->ScreenSize.x * lptw->ScreenSize.y);
200     lptw->ScreenBuffer = (BYTE FAR *)GlobalLock(hglobal);
201     if (lptw->ScreenBuffer == (BYTE FAR *)NULL) {
202         MessageBox((HWND)NULL,szNoMemory,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
203         return(1);
204     }
205     _fmemset(lptw->ScreenBuffer, ' ', lptw->ScreenSize.x * lptw->ScreenSize.y);
206     hglobal = GlobalAlloc(GHND, lptw->ScreenSize.x * lptw->ScreenSize.y);
207     lptw->AttrBuffer = (BYTE FAR *)GlobalLock(hglobal);
208     if (lptw->AttrBuffer == (BYTE FAR *)NULL) {
209         MessageBox((HWND)NULL,szNoMemory,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
210         return(1);
211     }
212     _fmemset(lptw->AttrBuffer, NOTEXT, lptw->ScreenSize.x * lptw->ScreenSize.y);
213     hglobal = GlobalAlloc(LHND, lptw->KeyBufSize);
214     lptw->KeyBuf = (BYTE FAR *)GlobalLock(hglobal);
215     if (lptw->KeyBuf == (BYTE FAR *)NULL) {
216         MessageBox((HWND)NULL,szNoMemory,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
217         return(1);
218     }
219     lptw->KeyBufIn = lptw->KeyBufOut = lptw->KeyBuf;
220
221     lptw->hWndParent = CreateWindow(szParentClass, lptw->Title,
222                                     WS_OVERLAPPEDWINDOW,
223                                     lptw->Origin.x, lptw->Origin.y,
224                                     lptw->Size.x, lptw->Size.y,
225                                     NULL, NULL, lptw->hInstance, lptw);
226     if (lptw->hWndParent == (HWND)NULL) {
227         MessageBox((HWND)NULL,"Couldn't open parent text window",(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
228         return(1);
229     }
230     GetClientRect(lptw->hWndParent, &rect);
231
232     lptw->hWndText = CreateWindow(szTextClass, lptw->Title,
233                                   WS_CHILD | WS_VSCROLL | WS_HSCROLL,
234                                   0, lptw->ButtonHeight,
235                                   rect.right, rect.bottom-lptw->ButtonHeight,
236                                   lptw->hWndParent, NULL, lptw->hInstance, lptw);
237     if (lptw->hWndText == (HWND)NULL) {
238         MessageBox((HWND)NULL,"Couldn't open text window",(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
239         return(1);
240     }
241
242     lptw->hPopMenu = CreatePopupMenu();
243     AppendMenu(lptw->hPopMenu, MF_STRING, M_COPY_CLIP, "&Copy to Clipboard\tCtrl-Ins");
244     AppendMenu(lptw->hPopMenu, MF_STRING, M_PASTE, "&Paste\tShift-Ins");
245     AppendMenu(lptw->hPopMenu, MF_SEPARATOR, 0, NULL);
246 #if WINVER >= 0x030a
247     AppendMenu(lptw->hPopMenu, MF_STRING, M_CHOOSE_FONT, "Choose &Font...");
248 #endif
249     AppendMenu(lptw->hPopMenu, MF_STRING | (lptw->bSysColors ? MF_CHECKED : MF_UNCHECKED),
250                M_SYSCOLORS, "&System Colors");
251     if (lptw->IniFile != (LPSTR)NULL) {
252         char buf[MAX_PATH+80];
253         wsprintf(buf,"&Update %s", lptw->IniFile);
254         AppendMenu(lptw->hPopMenu, MF_STRING, M_WRITEINI, (LPSTR)buf);
255     }
256
257     sysmenu = GetSystemMenu(lptw->hWndParent,0);        /* get the sysmenu */
258     AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
259     AppendMenu(sysmenu, MF_POPUP, (UINT)lptw->hPopMenu, "&Options");
260     AppendMenu(sysmenu, MF_STRING, M_ABOUT, "&About");
261
262     if (lptw->lpmw)
263         LoadMacros(lptw);
264
265     ShowWindow(lptw->hWndText, SW_SHOWNORMAL);
266     BringWindowToTop(lptw->hWndText);
267     SetFocus(lptw->hWndText);
268     TextMessage();
269     return(0);
270 }
271
272 /* close a text window */
273 void WDPROC
274 TextClose(LPTW lptw)
275 {
276     HGLOBAL hglobal;
277
278     /* close window */
279     if (lptw->hWndParent)
280         DestroyWindow(lptw->hWndParent);
281     TextMessage();
282
283     hglobal = (HGLOBAL)GlobalHandle( SELECTOROF(lptw->ScreenBuffer) );
284     if (hglobal) {
285         GlobalUnlock(hglobal);
286         GlobalFree(hglobal);
287     }
288     hglobal = (HGLOBAL)GlobalHandle( SELECTOROF(lptw->AttrBuffer) );
289     if (hglobal) {
290         GlobalUnlock(hglobal);
291         GlobalFree(hglobal);
292     }
293     hglobal = (HGLOBAL)GlobalHandle( SELECTOROF(lptw->KeyBuf) );
294     if (hglobal) {
295         GlobalUnlock(hglobal);
296         GlobalFree(hglobal);
297     }
298
299     if (lptw->lpmw)
300         CloseMacros(lptw);
301     lptw->hWndParent = (HWND)NULL;
302 }
303
304 void
305 WriteTextIni(LPTW lptw)
306 {
307     RECT rect;
308     LPSTR file = lptw->IniFile;
309     LPSTR section = lptw->IniSection;
310     char profile[80];
311     int iconic;
312
313
314     if ((file == (LPSTR)NULL) || (section == (LPSTR)NULL))
315         return;
316
317     iconic = IsIconic(lptw->hWndParent);
318     if (iconic)
319         ShowWindow(lptw->hWndParent, SW_SHOWNORMAL);
320     GetWindowRect(lptw->hWndParent,&rect);
321     wsprintf(profile, "%d %d", rect.left, rect.top);
322     WritePrivateProfileString(section, "TextOrigin", profile, file);
323     wsprintf(profile, "%d %d", rect.right-rect.left, rect.bottom-rect.top);
324     WritePrivateProfileString(section, "TextSize", profile, file);
325     wsprintf(profile, "%d", iconic);
326     WritePrivateProfileString(section, "TextMinimized", profile, file);
327     wsprintf(profile, "%s,%d", lptw->fontname, lptw->fontsize);
328     WritePrivateProfileString(section, "TextFont", profile, file);
329     wsprintf(profile, "%d", lptw->bSysColors);
330     WritePrivateProfileString(section, "SysColors", profile, file);
331     if (iconic)
332         ShowWindow(lptw->hWndParent, SW_SHOWMINIMIZED);
333     return;
334 }
335
336 void
337 ReadTextIni(LPTW lptw)
338 {
339     LPSTR file = lptw->IniFile;
340     LPSTR section = lptw->IniSection;
341     char profile[81];
342     LPSTR p;
343     BOOL bOKINI;
344
345     bOKINI = (file != (LPSTR)NULL) && (section != (LPSTR)NULL);
346     profile[0] = '\0';
347
348     if (bOKINI)
349         GetPrivateProfileString(section, "TextOrigin", "", profile, 80, file);
350     if ( (p = GetInt(profile, (LPINT)&lptw->Origin.x)) == NULL)
351         lptw->Origin.x = CW_USEDEFAULT;
352     if ( (p = GetInt(p, (LPINT)&lptw->Origin.y)) == NULL)
353         lptw->Origin.y = CW_USEDEFAULT;
354     if ( (file != (LPSTR)NULL) && (section != (LPSTR)NULL) )
355         GetPrivateProfileString(section, "TextSize", "", profile, 80, file);
356     if ( (p = GetInt(profile, (LPINT)&lptw->Size.x)) == NULL)
357         lptw->Size.x = CW_USEDEFAULT;
358     if ( (p = GetInt(p, (LPINT)&lptw->Size.y)) == NULL)
359         lptw->Size.y = CW_USEDEFAULT;
360
361     if (bOKINI)
362         GetPrivateProfileString(section, "TextFont", "", profile, 80, file);
363     {
364         char FAR *size;
365         size = _fstrchr(profile,',');
366         if (size) {
367             *size++ = '\0';
368             if ( (p = GetInt(size, &lptw->fontsize)) == NULL)
369                 lptw->fontsize = TEXTFONTSIZE;
370         }
371         _fstrcpy(lptw->fontname, profile);
372         if (lptw->fontsize == 0)
373             lptw->fontsize = TEXTFONTSIZE;
374         if (!(*lptw->fontname))
375             _fstrcpy(lptw->fontname,TEXTFONTNAME);
376     }
377
378     if (bOKINI) {
379         int iconic;
380         GetPrivateProfileString(section, "TextMinimized", "", profile, 80, file);
381         if ((p = GetInt(profile, &iconic)) == NULL)
382             iconic = 0;
383         if (iconic)
384             lptw->nCmdShow = SW_SHOWMINIMIZED;
385     }
386     lptw->bSysColors = FALSE;
387     GetPrivateProfileString(section, "SysColors", "", profile, 80, file);
388     if ((p = GetInt(profile, &lptw->bSysColors)) == NULL)
389         lptw->bSysColors = 0;
390 }
391
392
393 /* Bring Cursor into text window */
394 void WDPROC
395 TextToCursor(LPTW lptw)
396 {
397     int nXinc=0;
398     int nYinc=0;
399     int cxCursor;
400     int cyCursor;
401
402     cyCursor = lptw->CursorPos.y * lptw->CharSize.y;
403     if ( (cyCursor + lptw->CharSize.y > lptw->ScrollPos.y + lptw->ClientSize.y)
404          || (cyCursor < lptw->ScrollPos.y) ) {
405         nYinc = max(0, cyCursor + lptw->CharSize.y - lptw->ClientSize.y) - lptw->ScrollPos.y;
406         nYinc = min(nYinc, lptw->ScrollMax.y - lptw->ScrollPos.y);
407     }
408     cxCursor = lptw->CursorPos.x * lptw->CharSize.x;
409     if ( (cxCursor + lptw->CharSize.x > lptw->ScrollPos.x + lptw->ClientSize.x)
410          || (cxCursor < lptw->ScrollPos.x) ) {
411         nXinc = max(0, cxCursor + lptw->CharSize.x - lptw->ClientSize.x/2) - lptw->ScrollPos.x;
412         nXinc = min(nXinc, lptw->ScrollMax.x - lptw->ScrollPos.x);
413     }
414     if (nYinc || nXinc) {
415         lptw->ScrollPos.y += nYinc;
416         lptw->ScrollPos.x += nXinc;
417         ScrollWindow(lptw->hWndText,-nXinc,-nYinc,NULL,NULL);
418         SetScrollPos(lptw->hWndText,SB_VERT,lptw->ScrollPos.y,TRUE);
419         SetScrollPos(lptw->hWndText,SB_HORZ,lptw->ScrollPos.x,TRUE);
420         UpdateWindow(lptw->hWndText);
421     }
422 }
423
424 void
425 NewLine(LPTW lptw)
426 {
427     lptw->CursorPos.x = 0;
428     lptw->CursorPos.y++;
429     if (lptw->CursorPos.y >= lptw->ScreenSize.y) {
430         int i =  lptw->ScreenSize.x * (lptw->ScreenSize.y - 1);
431         _fmemmove(lptw->ScreenBuffer, lptw->ScreenBuffer+lptw->ScreenSize.x, i);
432         _fmemset(lptw->ScreenBuffer + i, ' ', lptw->ScreenSize.x);
433         _fmemmove(lptw->AttrBuffer, lptw->AttrBuffer+lptw->ScreenSize.x, i);
434         _fmemset(lptw->AttrBuffer + i, NOTEXT, lptw->ScreenSize.x);
435         lptw->CursorPos.y--;
436         ScrollWindow(lptw->hWndText,0,-lptw->CharSize.y,NULL,NULL);
437         lptw->MarkBegin.y--;
438         lptw->MarkEnd.y--;
439         LimitMark(lptw, &lptw->MarkBegin);
440         LimitMark(lptw, &lptw->MarkEnd);
441         UpdateWindow(lptw->hWndText);
442     }
443     if (lptw->CursorFlag)
444         TextToCursor(lptw);
445     TextMessage();
446 }
447
448 /* Update count characters in window at cursor position */
449 /* Updates cursor position */
450 void
451 UpdateText(LPTW lptw, int count)
452 {
453     HDC hdc;
454     int xpos, ypos;
455
456     xpos = lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x;
457     ypos = lptw->CursorPos.y*lptw->CharSize.y - lptw->ScrollPos.y;
458     hdc = GetDC(lptw->hWndText);
459     if (lptw->bSysColors) {
460         SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
461         SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
462     } else {
463         SetTextColor(hdc, TextFore(lptw->Attr));
464         SetBkColor(hdc, TextBack(lptw->Attr));
465     }
466     SelectObject(hdc, lptw->hfont);
467     TextOut(hdc,xpos,ypos,
468             (LPSTR)(lptw->ScreenBuffer + lptw->CursorPos.y*lptw->ScreenSize.x +
469                     lptw->CursorPos.x), count);
470     ReleaseDC(lptw->hWndText,hdc);
471     lptw->CursorPos.x += count;
472     if (lptw->CursorPos.x >= lptw->ScreenSize.x)
473         NewLine(lptw);
474 }
475
476 int WDPROC
477 TextPutCh(LPTW lptw, BYTE ch)
478 {
479 int pos;
480         switch(ch) {
481                 case '\r':
482                         lptw->CursorPos.x = 0;
483                         if (lptw->CursorFlag)
484                                 TextToCursor(lptw);
485                         break;
486                 case '\n':
487                         NewLine(lptw);
488                         break;
489                 case 7:
490                         MessageBeep(0xFFFFFFFF);
491                         if (lptw->CursorFlag)
492                                 TextToCursor(lptw);
493                         break;
494                 case '\t':
495                         {
496                         int n;
497                                 for ( n = 8 - (lptw->CursorPos.x % 8); n>0; n-- )
498                                         TextPutCh(lptw, ' ');
499                         }
500                         break;
501                 case 0x08:
502                 case 0x7f:
503                         lptw->CursorPos.x--;
504                         if (lptw->CursorPos.x < 0) {
505                                 lptw->CursorPos.x = lptw->ScreenSize.x - 1;
506                                 lptw->CursorPos.y--;
507                         }
508                         if (lptw->CursorPos.y < 0)
509                                 lptw->CursorPos.y = 0;
510                         break;
511                 default:
512                         pos = lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
513                         lptw->ScreenBuffer[pos] = ch;
514                         lptw->AttrBuffer[pos] = lptw->Attr;
515                         UpdateText(lptw, 1);
516         }
517         return ch;
518 }
519
520 void
521 TextPutStr(LPTW lptw, LPSTR str)
522 {
523     BYTE FAR *p, FAR *pa;
524     int count, limit;
525
526     while (*str) {
527         p = lptw->ScreenBuffer + lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
528         pa = lptw->AttrBuffer + lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
529         limit = lptw->ScreenSize.x - lptw->CursorPos.x;
530         for (count=0; (count < limit) && *str && (isprint(*str) || *str=='\t'); count++) {
531             if (*str=='\t') {
532                 int n;
533
534                 for ( n = 8 - ((lptw->CursorPos.x+count) % 8); (count < limit) & (n>0); n--, count++ ) {
535                     *p++ = ' ';
536                     *pa++ = lptw->Attr;
537                 }
538                 str++;
539                 count--;
540             } else {
541                 *p++ = *str++;
542                 *pa++ = lptw->Attr;
543             }
544         }
545         if (count>0) {
546             UpdateText(lptw, count);
547         }
548         if (*str=='\n') {
549             NewLine(lptw);
550             str++;
551         } else if (*str && !isprint(*str) && *str!='\t') {
552             TextPutCh(lptw, *str++);
553         }
554     }
555 }
556
557
558 void
559 LimitMark(LPTW lptw, POINT FAR *lppt)
560 {
561     if (lppt->x < 0)
562         lppt->x = 0;
563     if (lppt->y < 0) {
564         lppt->x = 0;
565         lppt->y = 0;
566     }
567     if (lppt->x > lptw->ScreenSize.x)
568         lppt->x = lptw->ScreenSize.x;
569     if (lppt->y >= lptw->ScreenSize.y) {
570         lppt->x = 0;
571         lppt->y = lptw->ScreenSize.y;
572     }
573 }
574
575 void
576 ClearMark(LPTW lptw, POINT pt)
577 {
578     RECT rect1, rect2, rect3;
579     int tmp;
580
581     if ((lptw->MarkBegin.x != lptw->MarkEnd.x) ||
582         (lptw->MarkBegin.y != lptw->MarkEnd.y) ) {
583         if (lptw->MarkBegin.x > lptw->MarkEnd.x) {
584             tmp = lptw->MarkBegin.x;
585             lptw->MarkBegin.x = lptw->MarkEnd.x;
586             lptw->MarkEnd.x = tmp;
587         }
588         if (lptw->MarkBegin.y > lptw->MarkEnd.y) {
589             tmp = lptw->MarkBegin.y;
590             lptw->MarkBegin.y = lptw->MarkEnd.y;
591             lptw->MarkEnd.y = tmp;
592         }
593         /* calculate bounding rectangle in character coordinates */
594         if (lptw->MarkBegin.y != lptw->MarkEnd.y) {
595             rect1.left = 0;
596             rect1.right = lptw->ScreenSize.x;
597         } else {
598             rect1.left = lptw->MarkBegin.x;
599             rect1.right = lptw->MarkEnd.x + 1;
600         }
601         rect1.top = lptw->MarkBegin.y;
602         rect1.bottom = lptw->MarkEnd.y + 1;
603         /* now convert to client coordinates */
604         rect1.left   = rect1.left   * lptw->CharSize.x - lptw->ScrollPos.x;
605         rect1.right  = rect1.right  * lptw->CharSize.x - lptw->ScrollPos.x;
606         rect1.top    = rect1.top    * lptw->CharSize.y - lptw->ScrollPos.y;
607         rect1.bottom = rect1.bottom * lptw->CharSize.y - lptw->ScrollPos.y;
608         /* get client rect and calculate intersection */
609         GetClientRect(lptw->hWndText, &rect2);
610         IntersectRect(&rect3,  &rect1, &rect2);
611         /* update window if necessary */
612         if (!IsRectEmpty(&rect3)) {
613             InvalidateRect(lptw->hWndText, &rect3, TRUE);
614         }
615     }
616     LimitMark(lptw, &pt);
617     lptw->MarkBegin.x = lptw->MarkEnd.x = pt.x;
618     lptw->MarkBegin.y = lptw->MarkEnd.y = pt.y;
619     UpdateWindow(lptw->hWndText);
620 }
621
622
623 /* output a line including attribute changes as needed */
624 void
625 DoLine(LPTW lptw, HDC hdc, int xpos, int ypos, int offset, int count)
626 {
627     BYTE FAR *pa, attr;
628     int idx, num;
629
630     pa = lptw->AttrBuffer + offset;
631     if ((offset < 0) || (offset >= lptw->ScreenSize.x*lptw->ScreenSize.y))
632         MessageBox((HWND)NULL, "panic", "panic", MB_OK | MB_ICONEXCLAMATION);
633     idx = 0;
634     num = count;
635     while (num > 0) {
636         attr = *pa;
637         while ((num > 0) && (attr == *pa)) {
638             /* skip over bytes with same attribute */
639             num--;
640             pa++;
641         }
642         if (lptw->bSysColors) {
643             SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
644             SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
645         } else {
646             SetTextColor(hdc, TextFore(attr));
647             SetBkColor(hdc, TextBack(attr));
648         }
649         TextOut(hdc,xpos,ypos, (LPSTR)(lptw->ScreenBuffer + offset + idx),
650                 count-num-idx);
651         xpos += lptw->CharSize.x * (count-num-idx);
652         idx = count-num;
653     }
654 }
655
656 void
657 DoMark(LPTW lptw, POINT pt, POINT end, BOOL mark)
658 {
659     int xpos, ypos;
660     HDC hdc;
661     int count;
662     int offset;
663
664     offset = lptw->ScreenSize.x * pt.y + pt.x;
665     hdc = GetDC(lptw->hWndText);
666     SelectObject(hdc, lptw->hfont);
667     if (lptw->bSysColors) {
668         SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
669         SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
670     } else {
671         SetTextColor(hdc, MARKFORE);
672         SetBkColor(hdc, MARKBACK);
673     }
674     while (pt.y < end.y) {
675         /* multiple lines */
676         xpos = pt.x*lptw->CharSize.x - lptw->ScrollPos.x;
677         ypos = pt.y*lptw->CharSize.y - lptw->ScrollPos.y;
678         count = lptw->ScreenSize.x - pt.x;
679         if (mark)
680             TextOut(hdc,xpos,ypos, (LPSTR)(lptw->ScreenBuffer + offset), count);
681         else {
682             DoLine(lptw, hdc, xpos, ypos, offset, count);
683             if (lptw->bSysColors) {
684                 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
685                 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
686             } else {
687                 SetTextColor(hdc, MARKFORE);
688                 SetBkColor(hdc, MARKBACK);
689             }
690         }
691         offset += count;
692         pt.y++;
693         pt.x=0;
694     }
695     /* partial line */
696     xpos = pt.x*lptw->CharSize.x - lptw->ScrollPos.x;
697     ypos = pt.y*lptw->CharSize.y - lptw->ScrollPos.y;
698     count = end.x - pt.x;
699     if (end.y != lptw->ScreenSize.y) {
700         if (mark)
701             TextOut(hdc,xpos,ypos, (LPSTR)(lptw->ScreenBuffer + offset), count);
702         else
703             DoLine(lptw, hdc, xpos, ypos, offset, count);
704     }
705     ReleaseDC(lptw->hWndText,hdc);
706 }
707
708 void
709 UpdateMark(LPTW lptw, POINT pt)
710 {
711     int begin, point, end;
712
713     LimitMark(lptw, &pt);
714     begin = lptw->ScreenSize.x*lptw->MarkBegin.y + lptw->MarkBegin.x;
715     point = lptw->ScreenSize.x*pt.y + pt.x;
716     end   = lptw->ScreenSize.x*lptw->MarkEnd.y + lptw->MarkEnd.x;
717
718     if (begin <= end) {
719         /* forward mark */
720         if (point >= end) {
721             /* extend marked area */
722             DoMark(lptw, lptw->MarkEnd, pt, TRUE);
723         } else if (point >= begin) {
724             /* retract marked area */
725             DoMark(lptw, pt, lptw->MarkEnd, FALSE);
726         } else {        /* retract and reverse */
727             DoMark(lptw, lptw->MarkBegin, lptw->MarkEnd, FALSE);
728             DoMark(lptw, pt, lptw->MarkBegin, TRUE);
729         }
730     } else {
731         /* reverse mark */
732         if (point <= end) {
733             /* extend marked area */
734             DoMark(lptw, pt, lptw->MarkEnd, TRUE);
735         } else if (point <= begin) {
736             /* retract marked area */
737             DoMark(lptw, lptw->MarkEnd, pt, FALSE);
738         } else {        /* retract and reverse */
739             DoMark(lptw, lptw->MarkEnd, lptw->MarkBegin, FALSE);
740             DoMark(lptw, lptw->MarkBegin, pt, TRUE);
741         }
742     }
743     lptw->MarkEnd.x = pt.x;
744     lptw->MarkEnd.y = pt.y;
745 }
746
747
748 #if WINVER >= 0x030a
749 /* Windows 3.1 drag-drop feature */
750
751 void
752 DragFunc(LPTW lptw, HDROP hdrop)
753 {
754     int i, cFiles;
755     LPSTR p;
756
757     if ((lptw->DragPre==(LPSTR)NULL) || (lptw->DragPost==(LPSTR)NULL))
758         return;
759     cFiles = DragQueryFile(hdrop, (UINT) -1, (LPSTR)NULL, 0);
760     for (i=0; i<cFiles; i++) {
761         char szFile[MAX_PATH];
762
763         DragQueryFile(hdrop, i, szFile, MAX_PATH);
764         for (p=lptw->DragPre; *p; p++)
765             SendMessage(lptw->hWndText,WM_CHAR,*p,1L);
766         for (p=szFile; *p; p++)
767             SendMessage(lptw->hWndText,WM_CHAR,*p,1L);
768         for (p=lptw->DragPost; *p; p++)
769             SendMessage(lptw->hWndText,WM_CHAR,*p,1L);
770     }
771     DragFinish(hdrop);
772 }
773 #endif
774
775
776 void
777 TextCopyClip(LPTW lptw)
778 {
779     int size, count;
780     HGLOBAL hGMem;
781     LPSTR cbuf, cp;
782     POINT pt, end;
783     TEXTMETRIC tm;
784     UINT type;
785     HDC hdc;
786
787     if ((lptw->MarkBegin.x == lptw->MarkEnd.x) &&
788         (lptw->MarkBegin.y == lptw->MarkEnd.y) ) {
789         /* copy user text */
790         return;
791     }
792
793     size = (lptw->MarkEnd.y - lptw->MarkBegin.y + 1)
794         * (lptw->ScreenSize.x + 2) + 1;
795     hGMem = GlobalAlloc(GMEM_MOVEABLE, (DWORD)size);
796     cbuf = cp = (LPSTR)GlobalLock(hGMem);
797     if (cp == (LPSTR)NULL)
798         return;
799
800     pt.x = lptw->MarkBegin.x;
801     pt.y = lptw->MarkBegin.y;
802     end.x   = lptw->MarkEnd.x;
803     end.y   = lptw->MarkEnd.y;
804
805     while (pt.y < end.y) {
806         /* copy to global buffer */
807         count = lptw->ScreenSize.x - pt.x;
808         _fmemcpy(cp,
809                  lptw->ScreenBuffer + lptw->ScreenSize.x * pt.y + pt.x,
810                  count);
811         /* remove trailing spaces */
812         for (count=count-1; count>=0; count--) {
813             if (cp[count]!=' ')
814                 break;
815             cp[count] = '\0';
816         }
817         cp[++count] = '\r';
818         cp[++count] = '\n';
819         cp[++count] = '\0';
820         cp += count;
821         pt.y++;
822         pt.x=0;
823     }
824     /* partial line */
825     count = end.x - pt.x;
826     if (end.y != lptw->ScreenSize.y) {
827         _fmemcpy(cp, lptw->ScreenBuffer + lptw->ScreenSize.x*pt.y+pt.x, count);
828         cp[count] = '\0';
829     }
830     size = _fstrlen(cbuf) + 1;
831     GlobalUnlock(hGMem);
832     hGMem = GlobalReAlloc(hGMem, (DWORD)size, GMEM_MOVEABLE);
833     /* find out what type to put into clipboard */
834     hdc = GetDC(lptw->hWndText);
835     SelectObject(hdc, lptw->hfont);
836     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
837     if (tm.tmCharSet == OEM_CHARSET)
838         type = CF_OEMTEXT;
839     else
840         type = CF_TEXT;
841     ReleaseDC(lptw->hWndText, hdc);
842     /* give buffer to clipboard */
843     OpenClipboard(lptw->hWndParent);
844     EmptyClipboard();
845     SetClipboardData(type, hGMem);
846     CloseClipboard();
847 }
848
849 void
850 TextMakeFont(LPTW lptw)
851 {
852     LOGFONT lf;
853     TEXTMETRIC tm;
854     LPSTR p;
855     HDC hdc;
856
857     hdc = GetDC(lptw->hWndText);
858     _fmemset(&lf, 0, sizeof(LOGFONT));
859     _fstrncpy(lf.lfFaceName,lptw->fontname,LF_FACESIZE);
860     lf.lfHeight = -MulDiv(lptw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
861     lf.lfPitchAndFamily = FIXED_PITCH;
862     lf.lfCharSet = DEFAULT_CHARSET;
863     if ( (p = _fstrstr(lptw->fontname," Italic")) != (LPSTR)NULL ) {
864         lf.lfFaceName[ (unsigned int)(p-lptw->fontname) ] = '\0';
865         lf.lfItalic = TRUE;
866     }
867     if ( (p = _fstrstr(lptw->fontname," Bold")) != (LPSTR)NULL ) {
868         lf.lfFaceName[ (unsigned int)(p-lptw->fontname) ] = '\0';
869         lf.lfWeight = FW_BOLD;
870     }
871     if (lptw->hfont != 0)
872         DeleteObject(lptw->hfont);
873     lptw->hfont = CreateFontIndirect((LOGFONT FAR *)&lf);
874     /* get text size */
875     SelectObject(hdc, lptw->hfont);
876     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
877     lptw->CharSize.y = tm.tmHeight;
878     lptw->CharSize.x = tm.tmAveCharWidth;
879     lptw->CharAscent = tm.tmAscent;
880     if (lptw->bFocus)
881         CreateCaret(lptw->hWndText, 0, lptw->CharSize.x, 2+lptw->CaretHeight);
882     ReleaseDC(lptw->hWndText, hdc);
883     return;
884 }
885
886 void
887 TextSelectFont(LPTW lptw) {
888 #if WINVER >= 0x030a
889     LOGFONT lf;
890     CHOOSEFONT cf;
891     HDC hdc;
892     char lpszStyle[LF_FACESIZE];
893     LPSTR p;
894
895     /* Set all structure fields to zero. */
896     _fmemset(&cf, 0, sizeof(CHOOSEFONT));
897     _fmemset(&lf, 0, sizeof(LOGFONT));
898     cf.lStructSize = sizeof(CHOOSEFONT);
899     cf.hwndOwner = lptw->hWndParent;
900     _fstrncpy(lf.lfFaceName,lptw->fontname,LF_FACESIZE);
901     if ( (p = _fstrstr(lptw->fontname," Bold")) != (LPSTR)NULL ) {
902         _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
903         lf.lfFaceName[ (unsigned int)(p-lptw->fontname) ] = '\0';
904     }
905     else if ( (p = _fstrstr(lptw->fontname," Italic")) != (LPSTR)NULL ) {
906         _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
907         lf.lfFaceName[ (unsigned int)(p-lptw->fontname) ] = '\0';
908     } else
909         _fstrcpy(lpszStyle,"Regular");
910     cf.lpszStyle = lpszStyle;
911     hdc = GetDC(lptw->hWndText);
912     lf.lfHeight = -MulDiv(lptw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
913     ReleaseDC(lptw->hWndText, hdc);
914     lf.lfPitchAndFamily = FIXED_PITCH;
915     cf.lpLogFont = &lf;
916     cf.nFontType = SCREEN_FONTTYPE;
917     cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_INITTOLOGFONTSTRUCT | CF_USESTYLE;
918     if (ChooseFont(&cf)) {
919         RECT rect;
920         _fstrcpy(lptw->fontname,lf.lfFaceName);
921         lptw->fontsize = cf.iPointSize / 10;
922         if (cf.nFontType & BOLD_FONTTYPE)
923             lstrcat(lptw->fontname," Bold");
924         if (cf.nFontType & ITALIC_FONTTYPE)
925             lstrcat(lptw->fontname," Italic");
926         TextMakeFont(lptw);
927         /* force a window update */
928         GetClientRect(lptw->hWndText, (LPRECT) &rect);
929         SendMessage(lptw->hWndText, WM_SIZE, SIZE_RESTORED,
930                     MAKELPARAM(rect.right-rect.left, rect.bottom-rect.top));
931         GetClientRect(lptw->hWndText, (LPRECT) &rect);
932         InvalidateRect(lptw->hWndText, (LPRECT) &rect, 1);
933         UpdateWindow(lptw->hWndText);
934     }
935 #endif
936 }
937
938
939 /* parent overlapped window */
940 LRESULT CALLBACK WINEXPORT
941 WndParentProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
942 {
943     HDC hdc;
944     PAINTSTRUCT ps;
945     RECT rect;
946     LPTW lptw;
947
948     lptw = (LPTW)GetWindowLong(hwnd, 0);
949
950     switch(message) {
951     case WM_SYSCOMMAND:
952         switch(LOWORD(wParam)) {
953         case M_COPY_CLIP:
954         case M_PASTE:
955         case M_CHOOSE_FONT:
956         case M_SYSCOLORS:
957         case M_WRITEINI:
958         case M_ABOUT:
959             SendMessage(lptw->hWndText, WM_COMMAND, wParam, lParam);
960         }
961         break;
962     case WM_SETFOCUS:
963         if (IsWindow(lptw->hWndText)) {
964             SetFocus(lptw->hWndText);
965             return(0);
966         }
967         break;
968     case WM_GETMINMAXINFO:
969     {
970         POINT FAR * MMinfo = (POINT FAR *)lParam;
971         TEXTMETRIC tm;
972
973         hdc = GetDC(hwnd);
974         SelectObject(hdc, GetStockObject(OEM_FIXED_FONT));
975         GetTextMetrics(hdc,(LPTEXTMETRIC)&tm);
976         ReleaseDC(hwnd,hdc);
977         /* minimum size */
978         MMinfo[3].x = ScreenMinSize.x*tm.tmAveCharWidth
979             + GetSystemMetrics(SM_CXVSCROLL) + 2*GetSystemMetrics(SM_CXFRAME);
980         MMinfo[3].y = ScreenMinSize.y*tm.tmHeight
981             + GetSystemMetrics(SM_CYHSCROLL) + 2*GetSystemMetrics(SM_CYFRAME)
982             + GetSystemMetrics(SM_CYCAPTION);
983         return(0);
984     }
985     case WM_SIZE:
986         SetWindowPos(lptw->hWndText, (HWND)NULL, 0, lptw->ButtonHeight,
987                      LOWORD(lParam), HIWORD(lParam)-lptw->ButtonHeight,
988                      SWP_NOZORDER | SWP_NOACTIVATE);
989         return(0);
990     case WM_COMMAND:
991         if (IsWindow(lptw->hWndText))
992             SetFocus(lptw->hWndText);
993         SendMessage(lptw->hWndText, message, wParam, lParam); /* pass on menu commands */
994         return(0);
995     case WM_PAINT:
996         hdc = BeginPaint(hwnd, &ps);
997         if (lptw->ButtonHeight) {
998             HBRUSH hbrush;
999             GetClientRect(hwnd, &rect);
1000             hbrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
1001             rect.bottom = lptw->ButtonHeight-1;
1002             FillRect(hdc, &rect, hbrush);
1003             DeleteObject(hbrush);
1004             SelectObject(hdc, GetStockObject(BLACK_PEN));
1005             MoveTo(hdc, rect.left, lptw->ButtonHeight-1);
1006             LineTo(hdc, rect.right, lptw->ButtonHeight-1);
1007         }
1008         EndPaint(hwnd, &ps);
1009         return 0;
1010
1011 #if WINVER >= 0x030a
1012     case WM_DROPFILES:
1013     {
1014         WORD version = LOWORD(GetVersion());
1015
1016         if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
1017             DragFunc(lptw, (HDROP)wParam);
1018     }
1019     break;
1020 #endif
1021
1022     case WM_CREATE:
1023     {
1024         RECT crect, wrect;
1025         TEXTMETRIC tm;
1026
1027         lptw = ((CREATESTRUCT FAR *)lParam)->lpCreateParams;
1028         SetWindowLong(hwnd, 0, (LONG)lptw);
1029         lptw->hWndParent = hwnd;
1030         /* get character size */
1031         TextMakeFont(lptw);
1032         hdc = GetDC(hwnd);
1033         SelectObject(hdc, lptw->hfont);
1034         GetTextMetrics(hdc,(LPTEXTMETRIC)&tm);
1035         lptw->CharSize.y = tm.tmHeight;
1036         lptw->CharSize.x = tm.tmAveCharWidth;
1037         lptw->CharAscent = tm.tmAscent;
1038         ReleaseDC(hwnd,hdc);
1039         GetClientRect(hwnd, &crect);
1040         if ( lptw->CharSize.x*lptw->ScreenSize.x < crect.right ) {
1041             /* shrink x size */
1042             GetWindowRect(lptw->hWndParent,&wrect);
1043             MoveWindow(lptw->hWndParent, wrect.left, wrect.top,
1044                        wrect.right-wrect.left + (lptw->CharSize.x*lptw->ScreenSize.x - crect.right),
1045                        wrect.bottom-wrect.top,
1046                        TRUE);
1047         }
1048         if ( lptw->CharSize.y*lptw->ScreenSize.y < crect.bottom ) {
1049             /* shrink y size */
1050             GetWindowRect(lptw->hWndParent,&wrect);
1051             MoveWindow(lptw->hWndParent, wrect.left, wrect.top,
1052                        wrect.right-wrect.left,
1053                        wrect.bottom-wrect.top + (lptw->CharSize.y*lptw->ScreenSize.y+lptw->ButtonHeight - crect.bottom),
1054                        TRUE);
1055         }
1056     }
1057
1058 #if WINVER >= 0x030a
1059     {
1060         WORD version = LOWORD(GetVersion());
1061
1062         if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
1063             if ( (lptw->DragPre!=(LPSTR)NULL) && (lptw->DragPost!=(LPSTR)NULL) )
1064                 DragAcceptFiles(hwnd, TRUE);
1065     }
1066 #endif
1067     break;
1068
1069     case WM_DESTROY:
1070 #if WINVER >= 0x030a
1071     {
1072         WORD version = LOWORD(GetVersion());
1073
1074         if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
1075             DragAcceptFiles(hwnd, FALSE);
1076     }
1077 #endif
1078
1079     DeleteObject(lptw->hfont);
1080     lptw->hfont = 0;
1081     break;
1082
1083     case WM_CLOSE:
1084         if (lptw->shutdown) {
1085             FARPROC lpShutDown = lptw->shutdown;
1086             (*lpShutDown)();
1087         }
1088         break;
1089     } /* switch() */
1090
1091     return DefWindowProc(hwnd, message, wParam, lParam);
1092 }
1093
1094
1095 /* PM 20011218: Reallocate larger keyboard buffer */
1096 int
1097 ReallocateKeyBuf(LPTW lptw)
1098 {
1099     int newbufsize = lptw->KeyBufSize + 16*1024; /* new buffer size */
1100     HGLOBAL h_old = (HGLOBAL)GlobalHandle( SELECTOROF(lptw->KeyBuf) );
1101     HGLOBAL h = GlobalAlloc(LHND, newbufsize);
1102     int pos_in = lptw->KeyBufIn - lptw->KeyBuf;
1103     int pos_out = lptw->KeyBufOut - lptw->KeyBuf;
1104     BYTE FAR *NewKeyBuf = (BYTE FAR *)GlobalLock(h);
1105
1106     if (NewKeyBuf == (BYTE FAR *)NULL) {
1107         MessageBox((HWND)NULL, szNoMemory, (LPSTR)NULL,
1108                    MB_ICONHAND | MB_SYSTEMMODAL);
1109         return 1;
1110     }
1111     if (lptw->KeyBufIn > lptw->KeyBufOut) {
1112         /*  | Buf ... Out ... In | */
1113         _fmemcpy(NewKeyBuf, lptw->KeyBufOut,
1114                   lptw->KeyBufIn - lptw->KeyBufOut);
1115         lptw->KeyBufIn = NewKeyBuf + (pos_in - pos_out);
1116     } else {
1117         /*  | Buf ... In ... Out ... | */
1118         _fmemcpy(NewKeyBuf, lptw->KeyBufOut, lptw->KeyBufSize - pos_out );
1119         _fmemcpy(NewKeyBuf, lptw->KeyBuf, pos_in );
1120         lptw->KeyBufIn = NewKeyBuf + (lptw->KeyBufSize - pos_out + pos_in);
1121     }
1122     if (h_old) {
1123         GlobalUnlock(h_old);
1124         GlobalFree(h_old);
1125     }
1126     lptw->KeyBufSize = newbufsize;
1127     lptw->KeyBufOut = lptw->KeyBuf = NewKeyBuf;
1128     return 0;
1129 }
1130
1131
1132 /* child text window */
1133 LRESULT CALLBACK WINEXPORT
1134 WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1135 {
1136     HDC hdc;
1137     PAINTSTRUCT ps;
1138     RECT rect;
1139     int nYinc, nXinc;
1140     LPTW lptw;
1141
1142     lptw = (LPTW)GetWindowLong(hwnd, 0);
1143
1144     switch(message) {
1145     case WM_SETFOCUS:
1146         lptw->bFocus = TRUE;
1147         CreateCaret(hwnd, 0, lptw->CharSize.x, 2+lptw->CaretHeight);
1148         SetCaretPos(lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x,
1149                     lptw->CursorPos.y*lptw->CharSize.y + lptw->CharAscent
1150                     - lptw->CaretHeight - lptw->ScrollPos.y);
1151         if (lptw->bGetCh)
1152             ShowCaret(hwnd);
1153         break;
1154     case WM_KILLFOCUS:
1155         DestroyCaret();
1156         lptw->bFocus = FALSE;
1157         break;
1158     case WM_SIZE:
1159         lptw->ClientSize.y = HIWORD(lParam);
1160         lptw->ClientSize.x = LOWORD(lParam);
1161
1162         lptw->ScrollMax.y = max(0, lptw->CharSize.y*lptw->ScreenSize.y - lptw->ClientSize.y);
1163         lptw->ScrollPos.y = min(lptw->ScrollPos.y, lptw->ScrollMax.y);
1164
1165         SetScrollRange(hwnd, SB_VERT, 0, lptw->ScrollMax.y, FALSE);
1166         SetScrollPos(hwnd, SB_VERT, lptw->ScrollPos.y, TRUE);
1167
1168         lptw->ScrollMax.x = max(0, lptw->CharSize.x*lptw->ScreenSize.x - lptw->ClientSize.x);
1169         lptw->ScrollPos.x = min(lptw->ScrollPos.x, lptw->ScrollMax.x);
1170
1171         SetScrollRange(hwnd, SB_HORZ, 0, lptw->ScrollMax.x, FALSE);
1172         SetScrollPos(hwnd, SB_HORZ, lptw->ScrollPos.x, TRUE);
1173
1174         if (lptw->bFocus && lptw->bGetCh) {
1175             SetCaretPos(lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x,
1176                         lptw->CursorPos.y*lptw->CharSize.y + lptw->CharAscent
1177                         - lptw->CaretHeight - lptw->ScrollPos.y);
1178             ShowCaret(hwnd);
1179         }
1180         return(0);
1181     case WM_VSCROLL:
1182         switch(LOWORD(wParam)) {
1183         case SB_TOP:
1184             nYinc = -lptw->ScrollPos.y;
1185             break;
1186         case SB_BOTTOM:
1187             nYinc = lptw->ScrollMax.y - lptw->ScrollPos.y;
1188             break;
1189         case SB_LINEUP:
1190             nYinc = -lptw->CharSize.y;
1191             break;
1192         case SB_LINEDOWN:
1193             nYinc = lptw->CharSize.y;
1194             break;
1195         case SB_PAGEUP:
1196             nYinc = min(-1,-lptw->ClientSize.y);
1197             break;
1198         case SB_PAGEDOWN:
1199             nYinc = max(1,lptw->ClientSize.y);
1200             break;
1201         case SB_THUMBPOSITION:
1202             nYinc = HIWORD(wParam) - lptw->ScrollPos.y;
1203             break;
1204         default:
1205             nYinc = 0;
1206         } /* switch(loword(wparam)) */
1207
1208         if ( (nYinc = max(-lptw->ScrollPos.y,
1209                           min(nYinc, lptw->ScrollMax.y - lptw->ScrollPos.y)))
1210              != 0 ) {
1211             lptw->ScrollPos.y += nYinc;
1212             ScrollWindow(hwnd,0,-nYinc,NULL,NULL);
1213             SetScrollPos(hwnd,SB_VERT,lptw->ScrollPos.y,TRUE);
1214             UpdateWindow(hwnd);
1215         }
1216         return(0);
1217     case WM_HSCROLL:
1218         switch(LOWORD(wParam)) {
1219         case SB_LINEUP:
1220             nXinc = -lptw->CharSize.x;
1221             break;
1222         case SB_LINEDOWN:
1223             nXinc = lptw->CharSize.x;
1224             break;
1225         case SB_PAGEUP:
1226             nXinc = min(-1,-lptw->ClientSize.x);
1227             break;
1228         case SB_PAGEDOWN:
1229             nXinc = max(1,lptw->ClientSize.x);
1230             break;
1231         case SB_THUMBPOSITION:
1232             nXinc = HIWORD(wParam) - lptw->ScrollPos.x;
1233             break;
1234         default:
1235             nXinc = 0;
1236         } /* switch(loword(wparam)) */
1237
1238         if ( (nXinc = max(-lptw->ScrollPos.x,
1239                           min(nXinc, lptw->ScrollMax.x - lptw->ScrollPos.x)))
1240              != 0 ) {
1241             lptw->ScrollPos.x += nXinc;
1242             ScrollWindow(hwnd,-nXinc,0,NULL,NULL);
1243             SetScrollPos(hwnd,SB_HORZ,lptw->ScrollPos.x,TRUE);
1244             UpdateWindow(hwnd);
1245         }
1246         return(0);
1247     case WM_KEYDOWN:
1248         if (GetKeyState(VK_SHIFT) < 0) {
1249             switch(wParam) {
1250             case VK_HOME:
1251                 SendMessage(hwnd, WM_VSCROLL, SB_TOP, (LPARAM)0);
1252                 break;
1253             case VK_END:
1254                 SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, (LPARAM)0);
1255                 break;
1256             case VK_PRIOR:
1257                 SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)0);
1258                 break;
1259             case VK_NEXT:
1260                 SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)0);
1261                 break;
1262             case VK_UP:
1263                 SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)0);
1264                 break;
1265             case VK_DOWN:
1266                 SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)0);
1267                 break;
1268             case VK_LEFT:
1269                 SendMessage(hwnd, WM_HSCROLL, SB_LINEUP, (LPARAM)0);
1270                 break;
1271             case VK_RIGHT:
1272                 SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, (LPARAM)0);
1273                 break;
1274             } /* switch(wparam) */
1275         } else {                /* if(shift) */
1276             switch(wParam) {
1277             case VK_HOME:
1278             case VK_END:
1279             case VK_PRIOR:
1280             case VK_NEXT:
1281             case VK_UP:
1282             case VK_DOWN:
1283             case VK_LEFT:
1284             case VK_RIGHT:
1285             case VK_DELETE: { /* store key in circular buffer */
1286                 long count = lptw->KeyBufIn - lptw->KeyBufOut;
1287
1288                 if (count < 0)
1289                     count += lptw->KeyBufSize;
1290                 if (count < lptw->KeyBufSize-2) {
1291                     *lptw->KeyBufIn++ = 0;
1292                     if (lptw->KeyBufIn - lptw->KeyBuf >= lptw->KeyBufSize)
1293                         lptw->KeyBufIn = lptw->KeyBuf;  /* wrap around */
1294                     *lptw->KeyBufIn++ = HIWORD(lParam) & 0xff;
1295                     if (lptw->KeyBufIn - lptw->KeyBuf >= lptw->KeyBufSize)
1296                         lptw->KeyBufIn = lptw->KeyBuf;  /* wrap around */
1297                 }
1298             }
1299             } /* switch(wparam) */
1300         } /* else(shift) */
1301         break;
1302     case WM_KEYUP:
1303         if (GetKeyState(VK_SHIFT) < 0) {
1304             switch(wParam) {
1305             case VK_INSERT:
1306                 /* Shift-Insert: paste clipboard */
1307                 SendMessage(lptw->hWndText, WM_COMMAND, M_PASTE, (LPARAM)0);
1308                 break;
1309             }
1310         } /* if(shift) */
1311         if (GetKeyState(VK_CONTROL) < 0) {
1312             switch(wParam) {
1313             case VK_INSERT:
1314                 /* Ctrl-Insert: copy to clipboard */
1315                 SendMessage(lptw->hWndText, WM_COMMAND, M_COPY_CLIP, (LPARAM)0);
1316                 break;
1317             case 'V':
1318                 /* Ctrl-V: paste clipboard */
1319                 SendMessage(lptw->hWndText, WM_COMMAND, M_PASTE, (LPARAM)0);
1320                 break;
1321             } /* switch(wparam) */
1322         } /* if(Ctrl) */
1323         break;
1324
1325     case WM_RBUTTONDOWN:
1326     {
1327         POINT pt;
1328
1329         pt.x = LOWORD(lParam);
1330         pt.y = HIWORD(lParam);
1331         ClientToScreen(hwnd,&pt);
1332         TrackPopupMenu(lptw->hPopMenu, TPM_LEFTALIGN,
1333                        pt.x, pt.y, 0, hwnd, NULL);
1334         return(0);
1335     }
1336     case WM_LBUTTONDOWN:
1337     { /* start marking text */
1338         POINT pt;
1339
1340         pt.x = LOWORD(lParam);
1341         pt.y = HIWORD(lParam);
1342         pt.x = (pt.x + lptw->ScrollPos.x)/lptw->CharSize.x;
1343         pt.y = (pt.y + lptw->ScrollPos.y)/lptw->CharSize.y;
1344         ClearMark(lptw, pt);
1345         SetCapture(hwnd);       /* track the mouse */
1346         lptw->Marking = TRUE;
1347         break;
1348     }
1349     case WM_LBUTTONUP:
1350     { /* finish marking text */
1351         /* ensure begin mark is before end mark */
1352         ReleaseCapture();
1353         lptw->Marking = FALSE;
1354         if ((lptw->ScreenSize.x*lptw->MarkBegin.y + lptw->MarkBegin.x) >
1355             (lptw->ScreenSize.x*lptw->MarkEnd.y   + lptw->MarkEnd.x)) {
1356             POINT tmp;
1357             tmp.x = lptw->MarkBegin.x;
1358             tmp.y = lptw->MarkBegin.y;
1359             lptw->MarkBegin.x = lptw->MarkEnd.x;
1360             lptw->MarkBegin.y = lptw->MarkEnd.y;
1361             lptw->MarkEnd.x   = tmp.x;
1362             lptw->MarkEnd.y   = tmp.y;
1363         }
1364         break;
1365     }
1366     case WM_MOUSEMOVE:
1367         if ((wParam & MK_LBUTTON) && lptw->Marking) {
1368             RECT rect;
1369             POINT pt;
1370
1371             pt.x = LOWORD(lParam);
1372             pt.y = HIWORD(lParam);
1373             GetClientRect(hwnd, &rect);
1374             if (PtInRect(&rect, pt)) {
1375                 pt.x = (pt.x + lptw->ScrollPos.x)/lptw->CharSize.x;
1376                 pt.y = (pt.y + lptw->ScrollPos.y)/lptw->CharSize.y;
1377                 UpdateMark(lptw, pt);
1378             } else {
1379                 int nXinc, nYinc;
1380
1381                 do {
1382                     nXinc = 0;
1383                     nYinc = 0;
1384                     if (pt.x > rect.right) {
1385                         nXinc = lptw->CharSize.x * 4;
1386                         pt.x = (rect.right + lptw->ScrollPos.x)
1387                             / lptw->CharSize.x + 2;
1388                     } else if (pt.x < rect.left) {
1389                         nXinc = -lptw->CharSize.x * 4;
1390                         pt.x = (rect.left + lptw->ScrollPos.x)
1391                             / lptw->CharSize.x - 2;
1392                     } else
1393                         pt.x = (pt.x + lptw->ScrollPos.x)
1394                             /lptw->CharSize.x;
1395                     if (pt.y > rect.bottom) {
1396                         nYinc = lptw->CharSize.y;
1397                         pt.y = (rect.bottom + lptw->ScrollPos.y)
1398                             / lptw->CharSize.y + 1;
1399                     } else if (pt.y < rect.top) {
1400                         nYinc = -lptw->CharSize.y;
1401                         pt.y = (rect.top + lptw->ScrollPos.y)
1402                             / lptw->CharSize.y - 1;
1403                     } else
1404                         pt.y = (pt.y + lptw->ScrollPos.y)
1405                             / lptw->CharSize.y;
1406
1407                     LimitMark(lptw, &pt);
1408                     nXinc = max(nXinc, -lptw->ScrollPos.x);
1409                     nYinc = max(nYinc, -lptw->ScrollPos.y);
1410                     nYinc = min(nYinc, lptw->ScrollMax.y - lptw->ScrollPos.y);
1411                     nXinc = min(nXinc, lptw->ScrollMax.x - lptw->ScrollPos.x);
1412                     if (nYinc || nXinc) {
1413                         lptw->ScrollPos.y += nYinc;
1414                         lptw->ScrollPos.x += nXinc;
1415                         ScrollWindow(lptw->hWndText, -nXinc, -nYinc,
1416                                      NULL, NULL);
1417                         SetScrollPos(lptw->hWndText, SB_VERT,
1418                                      lptw->ScrollPos.y, TRUE);
1419                         SetScrollPos(lptw->hWndText, SB_HORZ,
1420                                      lptw->ScrollPos.x, TRUE);
1421                         UpdateWindow(lptw->hWndText);
1422                     }
1423                     UpdateMark(lptw, pt);
1424                     GetCursorPos(&pt);
1425                     ScreenToClient(hwnd, &pt);
1426                 }
1427                 while((nYinc || nXinc) && !PtInRect(&rect, pt)
1428                       && (GetAsyncKeyState(VK_LBUTTON) < 0));
1429             } /* moved inside viewport */
1430         } /* if(dragging) */
1431         break;
1432 #if _WIN32_WINNT >= 0x0400
1433     case WM_MOUSEWHEEL: {
1434             WORD fwKeys;
1435             short int zDelta;
1436
1437             fwKeys = LOWORD(wParam);
1438             zDelta = HIWORD(wParam);
1439             switch (fwKeys) {
1440             case 0:
1441                 if (zDelta < 0)
1442                     SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)0);
1443                 else
1444                     SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)0);
1445                 return 0;
1446             case MK_SHIFT:
1447                 if (zDelta < 0)
1448                     SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)0);
1449                 else
1450                     SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)0);
1451                 return 0;
1452             case MK_CONTROL:
1453                 if (zDelta < 0)
1454                     SendMessage(hwnd, WM_CHAR, 0x0e, (LPARAM)0); // CTRL-N
1455                 else
1456                     SendMessage(hwnd, WM_CHAR, 0x10, (LPARAM)0); // CTRL-P
1457                 return 0;
1458             }
1459         }
1460         break;
1461 #endif
1462     case WM_CHAR: {
1463         /* store key in circular buffer */
1464         long count = lptw->KeyBufIn - lptw->KeyBufOut;
1465
1466         if (count < 0)
1467             count += lptw->KeyBufSize;
1468         if (count == lptw->KeyBufSize-1) {
1469             /* PM 20011218: Keyboard buffer is full, thus reallocate
1470              * larger one.  (Up to now: forthcoming characters were
1471              * silently ignored.)
1472              */
1473             if ( ReallocateKeyBuf(lptw) )
1474                 return 0; /* not enough memory */
1475         }
1476         if (count < lptw->KeyBufSize-1) {
1477             *lptw->KeyBufIn++ = wParam;
1478             if (lptw->KeyBufIn - lptw->KeyBuf >= lptw->KeyBufSize)
1479                 lptw->KeyBufIn = lptw->KeyBuf;  /* wrap around */
1480         }
1481         return 0;
1482     }
1483     case WM_COMMAND:
1484         if (LOWORD(wParam) < NUMMENU)
1485             SendMacro(lptw, LOWORD(wParam));
1486         else
1487             switch(LOWORD(wParam)) {
1488             case M_COPY_CLIP:
1489                 TextCopyClip(lptw);
1490                 return 0;
1491             case M_PASTE:
1492             {
1493                 HGLOBAL hGMem;
1494                 BYTE FAR *cbuf;
1495                 TEXTMETRIC tm;
1496                 UINT type;
1497
1498                 /* find out what type to get from clipboard */
1499                 hdc = GetDC(hwnd);
1500                 SelectObject(hdc, lptw->hfont);
1501                 GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
1502                 if (tm.tmCharSet == OEM_CHARSET)
1503                     type = CF_OEMTEXT;
1504                 else
1505                     type = CF_TEXT;
1506                 ReleaseDC(lptw->hWndText, hdc);
1507                 /* now get it from clipboard */
1508                 OpenClipboard(hwnd);
1509                 hGMem = GetClipboardData(type);
1510                 if (hGMem) {
1511                     cbuf = (BYTE FAR *) GlobalLock(hGMem);
1512                     while (*cbuf) {
1513                         if (*cbuf != '\n')
1514                             SendMessage(lptw->hWndText,WM_CHAR,*cbuf,1L);
1515                         cbuf++;
1516                     }
1517                     GlobalUnlock(hGMem);
1518                 } /* if(hGmem) */
1519                 CloseClipboard();
1520                 return 0;
1521             }
1522             case M_CHOOSE_FONT:
1523                 TextSelectFont(lptw);
1524                 return 0;
1525             case M_SYSCOLORS:
1526                 lptw->bSysColors = !lptw->bSysColors;
1527                 if (lptw->bSysColors)
1528                     CheckMenuItem(lptw->hPopMenu, M_SYSCOLORS, MF_BYCOMMAND | MF_CHECKED);
1529                 else
1530                     CheckMenuItem(lptw->hPopMenu, M_SYSCOLORS, MF_BYCOMMAND | MF_UNCHECKED);
1531                 SendMessage(hwnd, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0);
1532                 InvalidateRect(hwnd, (LPRECT)NULL, 1);
1533                 UpdateWindow(hwnd);
1534                 return 0;
1535             case M_WRITEINI:
1536                 WriteTextIni(lptw);
1537                 return 0;
1538             case M_ABOUT:
1539                 AboutBox(hwnd,lptw->AboutText);
1540                 return 0;
1541             } /* switch(loword(wparam)) */
1542         return(0);
1543
1544     case WM_SYSCOLORCHANGE:
1545         DeleteObject(lptw->hbrBackground);
1546         lptw->hbrBackground = CreateSolidBrush(lptw->bSysColors ?
1547                                                GetSysColor(COLOR_WINDOW) : RGB(0,0,0));
1548         return(0);
1549     case WM_ERASEBKGND:
1550         return(1);      /* we will erase it ourselves */
1551     case WM_PAINT:
1552     {
1553         POINT source, width, dest;
1554         POINT MarkBegin, MarkEnd;
1555
1556         hdc = BeginPaint(hwnd, &ps);
1557         if (ps.fErase)
1558             FillRect(hdc, &ps.rcPaint, lptw->hbrBackground);
1559         SelectObject(hdc, lptw->hfont);
1560         SetMapMode(hdc, MM_TEXT);
1561         SetBkMode(hdc,OPAQUE);
1562         GetClientRect(hwnd, &rect);
1563         /* source */
1564         source.x = (rect.left + lptw->ScrollPos.x) / lptw->CharSize.x;
1565         source.y = (rect.top + lptw->ScrollPos.y) / lptw->CharSize.y;
1566         /* destination */
1567         dest.x = source.x * lptw->CharSize.x - lptw->ScrollPos.x;
1568         dest.y = source.y * lptw->CharSize.y - lptw->ScrollPos.y;
1569         width.x = ((rect.right  + lptw->ScrollPos.x + lptw->CharSize.x - 1)
1570                    / lptw->CharSize.x) - source.x;
1571         width.y = ((rect.bottom + lptw->ScrollPos.y + lptw->CharSize.y - 1)
1572                    / lptw->CharSize.y) - source.y;
1573         if (source.x < 0)
1574             source.x = 0;
1575         if (source.y < 0)
1576             source.y = 0;
1577         if (source.x+width.x > lptw->ScreenSize.x)
1578             width.x = lptw->ScreenSize.x - source.x;
1579         if (source.y+width.y > lptw->ScreenSize.y)
1580             width.y = lptw->ScreenSize.y - source.y;
1581         /* ensure begin mark is before end mark */
1582         if ((lptw->ScreenSize.x*lptw->MarkBegin.y + lptw->MarkBegin.x) >
1583             (lptw->ScreenSize.x*lptw->MarkEnd.y   + lptw->MarkEnd.x)) {
1584             MarkBegin.x = lptw->MarkEnd.x;
1585             MarkBegin.y = lptw->MarkEnd.y;
1586             MarkEnd.x   = lptw->MarkBegin.x;
1587             MarkEnd.y   = lptw->MarkBegin.y;
1588         } else {
1589             MarkBegin.x = lptw->MarkBegin.x;
1590             MarkBegin.y = lptw->MarkBegin.y;
1591             MarkEnd.x   = lptw->MarkEnd.x;
1592             MarkEnd.y   = lptw->MarkEnd.y;
1593         }
1594
1595         /* for each line */
1596         while (width.y>0) {
1597             if ((source.y >= MarkBegin.y) && (source.y <= MarkEnd.y)) {
1598                 int start, end;
1599                 int count, offset;
1600
1601                 if (source.y == MarkBegin.y)
1602                     start = MarkBegin.x;
1603                 else
1604                     start = 0;
1605                 if (source.y == MarkEnd.y)
1606                     end = MarkEnd.x;
1607                 else
1608                     end = lptw->ScreenSize.x;
1609                 /* do stuff before marked text */
1610                 offset = 0;
1611                 count = start - source.x;
1612                 if (count > 0)
1613                     DoLine(lptw, hdc, dest.x, dest.y,
1614                            source.y*lptw->ScreenSize.x + source.x, count);
1615                 /* then the marked text */
1616                 offset += count;
1617                 count = end - start;
1618                 if ((count > 0) && (offset < width.x)){
1619                     if (lptw->bSysColors) {
1620                         SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1621                         SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1622                     } else {
1623                         SetTextColor(hdc, MARKFORE);
1624                         SetBkColor(hdc, MARKBACK);
1625                     }
1626                     TextOut(hdc, dest.x + lptw->CharSize.x*offset, dest.y,
1627                             (LPSTR)(lptw->ScreenBuffer
1628                                     + source.y * lptw->ScreenSize.x
1629                                     + source.x + offset),
1630                             count);
1631                 }
1632                 /* then stuff after marked text */
1633                 offset += count;
1634                 count = width.x + source.x - end;
1635                 if ((count > 0) && (offset < width.x))
1636                     DoLine(lptw, hdc, dest.x + lptw->CharSize.x*offset, dest.y,
1637                            source.y * lptw->ScreenSize.x + source.x + offset,
1638                            count);
1639             } else {
1640                 DoLine(lptw, hdc, dest.x, dest.y,
1641                        source.y*lptw->ScreenSize.x + source.x, width.x);
1642             }
1643             dest.y += lptw->CharSize.y;
1644             source.y++;
1645             width.y--;
1646         }
1647         EndPaint(hwnd, &ps);
1648         return 0;
1649     }
1650     case WM_CREATE:
1651         lptw = ((CREATESTRUCT FAR *)lParam)->lpCreateParams;
1652         SetWindowLong(hwnd, 0, (LONG)lptw);
1653         lptw->hWndText = hwnd;
1654         break;
1655     case WM_DESTROY:
1656         DeleteObject(lptw->hbrBackground);
1657         break;
1658     } /* switch(message) */
1659     return DefWindowProc(hwnd, message, wParam, lParam);
1660 }
1661
1662
1663 /* ================================== */
1664 /* replacement stdio routines */
1665
1666 /* TRUE if key hit, FALSE if no key */
1667 int WDPROC
1668 TextKBHit(LPTW lptw)
1669 {
1670     return (lptw->KeyBufIn != lptw->KeyBufOut);
1671 }
1672
1673 /* get character from keyboard, no echo */
1674 /* need to add extended codes */
1675 int WDPROC
1676 TextGetCh(LPTW lptw)
1677 {
1678     int ch;
1679     TextToCursor(lptw);
1680     lptw->bGetCh = TRUE;
1681     if (lptw->bFocus) {
1682         SetCaretPos(lptw->CursorPos.x * lptw->CharSize.x - lptw->ScrollPos.x,
1683                     lptw->CursorPos.y * lptw->CharSize.y + lptw->CharAscent
1684                     - lptw->CaretHeight - lptw->ScrollPos.y);
1685         ShowCaret(lptw->hWndText);
1686     }
1687     while (!TextKBHit(lptw)) {
1688         /* CMW: can't use TextMessage here as it does not idle properly */
1689         MSG msg;
1690         GetMessage(&msg, 0, 0, 0);
1691         TranslateMessage(&msg);
1692         DispatchMessage(&msg);
1693     }
1694     ch = *lptw->KeyBufOut++;
1695     if (ch=='\r')
1696         ch = '\n';
1697     if (lptw->KeyBufOut - lptw->KeyBuf >= lptw->KeyBufSize)
1698         lptw->KeyBufOut = lptw->KeyBuf; /* wrap around */
1699     if (lptw->bFocus)
1700         HideCaret(lptw->hWndText);
1701     lptw->bGetCh = FALSE;
1702     return ch;
1703 }
1704
1705 /* get character from keyboard, with echo */
1706 int WDPROC
1707 TextGetChE(LPTW lptw)
1708 {
1709     int ch;
1710
1711     ch = TextGetCh(lptw);
1712     TextPutCh(lptw, (BYTE)ch);
1713     return ch;
1714 }
1715
1716 LPSTR WDPROC
1717 TextGetS(LPTW lptw, LPSTR str, unsigned int size)
1718 {
1719     LPSTR next = str;
1720
1721     while (--size>0) {
1722         switch(*next = TextGetChE(lptw)) {
1723         case EOF:
1724             *next = 0;
1725             if (next == str)
1726                 return (LPSTR) NULL;
1727             return str;
1728         case '\n':
1729             *(next+1) = 0;
1730             return str;
1731         case 0x08:
1732         case 0x7f:
1733             if (next > str)
1734                 --next;
1735             break;
1736         default:
1737             ++next;
1738         }
1739     }
1740     *next = 0;
1741     return str;
1742 }
1743
1744 int WDPROC
1745 TextPutS(LPTW lptw, LPSTR str)
1746 {
1747     TextPutStr(lptw, str);
1748     return str[_fstrlen(str)-1];
1749 }
1750
1751 /* ================================== */
1752 /* routines added for elvis */
1753
1754 void WDPROC
1755 TextGotoXY(LPTW lptw, int x, int y)
1756 {
1757     lptw->CursorPos.x = x;
1758     lptw->CursorPos.y = y;
1759 }
1760
1761 int  WDPROC
1762 TextWhereX(LPTW lptw)
1763 {
1764     return lptw->CursorPos.x;
1765 }
1766
1767 int  WDPROC
1768 TextWhereY(LPTW lptw)
1769 {
1770     return lptw->CursorPos.y;
1771 }
1772
1773 void WDPROC
1774 TextCursorHeight(LPTW lptw, int height)
1775 {
1776     lptw->CaretHeight = height;
1777     if (lptw->bFocus)
1778         CreateCaret(lptw->hWndText, 0, lptw->CharSize.x, 2+lptw->CaretHeight);
1779 }
1780
1781 void WDPROC
1782 TextClearEOL(LPTW lptw)
1783 {
1784     HDC hdc;
1785     int xpos, ypos;
1786     int from, len;
1787     POINT pt;
1788
1789     pt.x = pt.y = 0;
1790     ClearMark(lptw, pt);
1791     from = lptw->CursorPos.y * lptw->ScreenSize.x + lptw->CursorPos.x;
1792     len = lptw->ScreenSize.x-lptw->CursorPos.x;
1793     _fmemset(lptw->ScreenBuffer + from, ' ', len);
1794     _fmemset(lptw->AttrBuffer + from, NOTEXT, len);
1795     xpos = lptw->CursorPos.x * lptw->CharSize.x - lptw->ScrollPos.x;
1796     ypos = lptw->CursorPos.y * lptw->CharSize.y - lptw->ScrollPos.y;
1797     hdc = GetDC(lptw->hWndText);
1798     if (lptw->bSysColors) {
1799         SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
1800         SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
1801     } else {
1802         SetTextColor(hdc, TextFore(lptw->Attr));
1803         SetBkColor(hdc, TextBack(lptw->Attr));
1804     }
1805     SelectObject(hdc, (lptw->hfont));
1806     TextOut(hdc,xpos,ypos,
1807             (LPSTR)(lptw->ScreenBuffer
1808                     + lptw->CursorPos.y * lptw->ScreenSize.x
1809                     + lptw->CursorPos.x),
1810             lptw->ScreenSize.x - lptw->CursorPos.x);
1811     ReleaseDC(lptw->hWndText,hdc);
1812 }
1813
1814 void WDPROC
1815 TextClearEOS(LPTW lptw)
1816 {
1817     RECT rect;
1818     int from, len;
1819     POINT pt;
1820
1821     pt.x = pt.y = 0;
1822     ClearMark(lptw, pt);
1823     from = lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
1824     len = lptw->ScreenSize.x-lptw->CursorPos.x
1825         + (lptw->ScreenSize.y - lptw->CursorPos.y - 1) * lptw->ScreenSize.x;
1826     _fmemset(lptw->ScreenBuffer + from, ' ', len);
1827     _fmemset(lptw->AttrBuffer + from, NOTEXT, len);
1828     GetClientRect(lptw->hWndText, (LPRECT) &rect);
1829     InvalidateRect(lptw->hWndText, (LPRECT) &rect, 1);
1830     UpdateWindow(lptw->hWndText);
1831 }
1832
1833 void WDPROC
1834 TextInsertLine(LPTW lptw)
1835 {
1836     RECT rect;
1837     int from, to, len;
1838     POINT pt;
1839
1840     pt.x = pt.y = 0;
1841     ClearMark(lptw, pt);
1842     from = lptw->CursorPos.y * lptw->ScreenSize.x;
1843     to = (lptw->CursorPos.y + 1) * lptw->ScreenSize.x;
1844     len = (lptw->ScreenSize.y - lptw->CursorPos.y - 1) * lptw->ScreenSize.x;
1845     _fmemmove(lptw->ScreenBuffer + to, lptw->ScreenBuffer + from, len);
1846     _fmemmove(lptw->AttrBuffer + to, lptw->AttrBuffer + from, len);
1847     _fmemset(lptw->ScreenBuffer + from, ' ', lptw->ScreenSize.x);
1848     _fmemset(lptw->AttrBuffer + from, NOTEXT, lptw->ScreenSize.x);
1849     GetClientRect(lptw->hWndText, (LPRECT) &rect);
1850     InvalidateRect(lptw->hWndText, (LPRECT) &rect, 1);
1851     UpdateWindow(lptw->hWndText);
1852     if (lptw->CursorFlag)
1853         TextToCursor(lptw);
1854 }
1855
1856 void WDPROC
1857 TextDeleteLine(LPTW lptw)
1858 {
1859     RECT rect;
1860     int from, to, len;
1861     POINT pt;
1862
1863     pt.x = pt.y = 0;
1864     ClearMark(lptw, pt);
1865     to = lptw->CursorPos.y * lptw->ScreenSize.x;
1866     from = (lptw->CursorPos.y + 1) * lptw->ScreenSize.x;
1867     len = (lptw->ScreenSize.y - lptw->CursorPos.y - 1) * lptw->ScreenSize.x;
1868     _fmemmove(lptw->ScreenBuffer + to, lptw->ScreenBuffer + from, len);
1869     _fmemmove(lptw->AttrBuffer + to, lptw->AttrBuffer + from, len);
1870     from = lptw->ScreenSize.x * (lptw->ScreenSize.y -1);
1871     _fmemset(lptw->ScreenBuffer + from, ' ', lptw->ScreenSize.x);
1872     _fmemset(lptw->AttrBuffer + from, NOTEXT, lptw->ScreenSize.x);
1873     GetClientRect(lptw->hWndText, (LPRECT) &rect);
1874     InvalidateRect(lptw->hWndText, (LPRECT) &rect, 1);
1875     UpdateWindow(lptw->hWndText);
1876     if (lptw->CursorFlag)
1877         TextToCursor(lptw);
1878 }
1879
1880 void WDPROC
1881 TextScrollReverse(LPTW lptw)
1882 {
1883     RECT rect;
1884     int len = lptw->ScreenSize.x * (lptw->ScreenSize.y - 1);
1885
1886     _fmemmove(lptw->ScreenBuffer+lptw->ScreenSize.x, lptw->ScreenBuffer, len);
1887     _fmemset(lptw->ScreenBuffer, ' ', lptw->ScreenSize.x);
1888     _fmemmove(lptw->AttrBuffer+lptw->ScreenSize.x, lptw->AttrBuffer, len);
1889     _fmemset(lptw->AttrBuffer, NOTEXT, lptw->ScreenSize.x);
1890     if (lptw->CursorPos.y)
1891         lptw->CursorPos.y--;
1892     ScrollWindow(lptw->hWndText, 0, lptw->CharSize.y, NULL, NULL);
1893     GetClientRect(lptw->hWndText, (LPRECT) &rect);
1894     rect.top = lptw->ScreenSize.y * lptw->CharSize.y;
1895     if (rect.top < rect.bottom)
1896         InvalidateRect(lptw->hWndText, (LPRECT) &rect, 1);
1897     lptw->MarkBegin.y++;
1898     lptw->MarkEnd.y++;
1899     LimitMark(lptw, &lptw->MarkBegin);
1900     LimitMark(lptw, &lptw->MarkEnd);
1901     UpdateWindow(lptw->hWndText);
1902 }
1903
1904 void WDPROC
1905 TextAttr(LPTW lptw, BYTE attr)
1906 {
1907     lptw->Attr = attr;
1908 }
1909
1910 /* About Box */
1911 BOOL CALLBACK WINEXPORT
1912 AboutDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
1913 {
1914     switch (wMsg) {
1915     case WM_INITDIALOG:
1916     {
1917         char buf[80];
1918
1919         GetWindowText(GetParent(hDlg),buf,80);
1920         SetDlgItemText(hDlg, AB_TEXT1, buf);
1921         SetDlgItemText(hDlg, AB_TEXT2, (LPSTR)lParam);
1922 #ifdef __DLL__
1923         wsprintf(buf,"WGNUPLOT.DLL Version %s",(LPSTR)WGNUPLOTVERSION);
1924         SetDlgItemText(hDlg, AB_TEXT3, buf);
1925 #endif
1926         return TRUE;
1927     }
1928     case WM_DRAWITEM:
1929     {
1930         LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
1931 #ifdef WIN32
1932         DrawIcon(lpdis->hDC, 0, 0, (HICON)GetClassLong(GetParent(hDlg), GCL_HICON));
1933 #else
1934         DrawIcon(lpdis->hDC, 0, 0, (HICON)GetClassWord(GetParent(hDlg), GCW_HICON));
1935 #endif
1936         return FALSE;
1937     }
1938     case WM_COMMAND:
1939         switch (LOWORD(wParam)) {
1940         case IDCANCEL:
1941         case IDOK:
1942             EndDialog(hDlg, LOWORD(wParam));
1943             return TRUE;
1944         }
1945         break;
1946     } /* switch(message) */
1947     return FALSE;
1948 }
1949
1950
1951 void WDPROC
1952 AboutBox(HWND hwnd, LPSTR str)
1953 {
1954 #ifdef WIN32
1955     DialogBoxParam(hdllInstance, "AboutDlgBox", hwnd,
1956                    AboutDlgProc, (LPARAM)str);
1957 #else
1958     DLGPROC lpfnAboutDlgProc;
1959
1960 # ifdef __DLL__
1961     lpfnAboutDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "AboutDlgProc");
1962 # else
1963     lpfnAboutDlgProc = (DLGPROC)MakeProcInstance((FARPROC)AboutDlgProc,
1964                                                  hdllInstance);
1965 # endif /* __DLL__ */
1966     DialogBoxParam(hdllInstance,"AboutDlgBox", hwnd, lpfnAboutDlgProc,
1967                    (LPARAM)str);
1968     EnableWindow(hwnd,TRUE);
1969 # ifndef __DLL__
1970     FreeProcInstance((FARPROC)lpfnAboutDlgProc);
1971 # endif /* __DLL__ */
1972 #endif /* WIN32 */
1973 }