1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17
18 /* Microsoft Windows text window for Ghostscript. */
19
20 #include <stdlib.h>
21 #include <string.h> /* use only far items */
22 #include <wchar.h>
23 #include <ctype.h>
24
25 #define STRICT
26 #include <windowsx.h>
27 #include "dwtext.h"
28 #include <commdlg.h>
29 #include <shellapi.h>
30
31 #ifdef WINDOWS_NO_UNICODE
32 #define CHARSIZE 1
33 #else
34 #define CHARSIZE 2
35 #ifndef WM_UNICHAR
36 #define WM_UNICHAR 0x109
37 #endif
38 #endif
39
40 /* Define min and max, but make sure to use the identical definition */
41 /* to the one that all the compilers seem to have.... */
42 #ifndef min
43 # define min(a, b) (((a) < (b)) ? (a) : (b))
44 #endif
45 #ifndef max
46 # define max(a, b) (((a) > (b)) ? (a) : (b))
47 #endif
48
49 #ifndef EOF
50 #define EOF (-1)
51 #endif
52
53 /* sysmenu */
54 #define M_COPY_CLIP 1
55 #define M_PASTE_CLIP 2
56
57 LRESULT CALLBACK WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
58 static void text_error(char *message);
59 static void text_new_line(TW *tw);
60 static void text_update_text(TW *tw, int count);
61 static void text_drag_drop(TW *tw, HDROP hdrop);
62 static void text_copy_to_clipboard(TW *tw);
63 static void text_paste_from_clipboard(TW *tw);
64
65 #ifdef WINDOWS_NO_UNICODE
66 static const char* TextWinClassName = "rjlTextWinClass";
67 #else
68 static const wchar_t* TextWinClassName = L"rjlTextWinClass";
69 #endif
70 static const POINT TextWinMinSize = {16, 4};
71
72 #if !defined(WINDOWS_NO_UNICODE) && defined(_MSC_VER) && _MSC_VER < 1400
73 /*
74 * 'wmemset()' is documented for both Visual Studio 6.0 and .NET 2003, but
75 * a bug in the shipped "wctype.h" makes it available only for C++ programs.
76 * As this is an inline function, it's not found in the libs.
77 */
wmemset(wchar_t * buf,wchar_t w,int count)78 static wchar_t *wmemset(wchar_t *buf, wchar_t w, int count) {
79 while (count > 0)
80 buf[--count] = w;
81 return buf;
82 }
83 #endif
84
85 static void
text_error(char * message)86 text_error(char *message)
87 {
88 MessageBoxA((HWND)NULL,message,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
89 }
90
91 static void
UpdateScrollBarX(TW * tw)92 UpdateScrollBarX(TW *tw)
93 {
94 SCROLLINFO si;
95 si.cbSize = sizeof(si);
96 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
97 si.nMin = 0;
98 si.nTrackPos = 0;
99 si.nPage = tw->ClientSize.x;
100 si.nMax = tw->CharSize.x*tw->ScreenSize.x-1;
101 si.nPos = tw->ScrollPos.x;
102 SetScrollInfo(tw->hwnd, SB_HORZ, &si, TRUE);
103 }
104
105 static void
UpdateScrollBarY(TW * tw)106 UpdateScrollBarY(TW *tw)
107 {
108 SCROLLINFO si;
109 si.cbSize = sizeof(si);
110 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
111 si.nMin = 0;
112 si.nTrackPos = 0;
113 si.nPage = tw->ClientSize.y;
114 si.nMax = tw->CharSize.y*tw->ScreenSize.y-1;
115 si.nPos = tw->ScrollPos.y;
116 SetScrollInfo(tw->hwnd, SB_VERT, &si, TRUE);
117 }
118
119 /* Bring Cursor into text window */
120 void
text_to_cursor(TW * tw)121 text_to_cursor(TW *tw)
122 {
123 int nXinc=0;
124 int nYinc=0;
125 int cxCursor;
126 int cyCursor;
127 cyCursor = tw->CursorPos.y * tw->CharSize.y;
128 if ( (cyCursor + tw->CharSize.y > tw->ScrollPos.y + tw->ClientSize.y)
129 /* || (cyCursor < tw->ScrollPos.y) ) { */
130 /* change to scroll to end of window instead of just making visible */
131 /* so that ALL of error message can be seen */
132 || (cyCursor < tw->ScrollPos.y+tw->ClientSize.y) ) {
133 nYinc = max(0, cyCursor + tw->CharSize.y
134 - tw->ClientSize.y) - tw->ScrollPos.y;
135 nYinc = min(nYinc, tw->ScrollMax.y - tw->ScrollPos.y);
136 }
137 cxCursor = tw->CursorPos.x * tw->CharSize.x;
138 if ( (cxCursor + tw->CharSize.x > tw->ScrollPos.x + tw->ClientSize.x)
139 || (cxCursor < tw->ScrollPos.x) ) {
140 nXinc = max(0, cxCursor + tw->CharSize.x
141 - tw->ClientSize.x/2) - tw->ScrollPos.x;
142 nXinc = min(nXinc, tw->ScrollMax.x - tw->ScrollPos.x);
143 }
144 if (nYinc || nXinc) {
145 tw->ScrollPos.y += nYinc;
146 tw->ScrollPos.x += nXinc;
147 ScrollWindow(tw->hwnd,-nXinc,-nYinc,NULL,NULL);
148 UpdateScrollBarX(tw);
149 UpdateScrollBarY(tw);
150 UpdateWindow(tw->hwnd);
151 }
152 }
153
154 static void
text_new_line(TW * tw)155 text_new_line(TW *tw)
156 {
157 tw->CursorPos.x = 0;
158 tw->CursorPos.y++;
159 if (tw->CursorPos.y >= tw->ScreenSize.y) {
160 int i = tw->ScreenSize.x * (tw->ScreenSize.y - 1);
161 memmove(tw->ScreenBuffer, tw->ScreenBuffer+tw->ScreenSize.x,
162 i * CHARSIZE);
163 #ifdef WINDOWS_NO_UNICODE
164 memset(tw->ScreenBuffer + i, ' ', tw->ScreenSize.x);
165 #else
166 wmemset(tw->ScreenBuffer + i, ' ', tw->ScreenSize.x);
167 #endif
168 tw->CursorPos.y--;
169 ScrollWindow(tw->hwnd,0,-tw->CharSize.y,NULL,NULL);
170 UpdateWindow(tw->hwnd);
171 }
172 if (tw->CursorFlag)
173 text_to_cursor(tw);
174
175 /* TextMessage(); */
176 }
177
178 /* Update count characters in window at cursor position */
179 /* Updates cursor position */
180 static void
text_update_text(TW * tw,int count)181 text_update_text(TW *tw, int count)
182 {
183 HDC hdc;
184 int xpos, ypos;
185 xpos = tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x;
186 ypos = tw->CursorPos.y*tw->CharSize.y - tw->ScrollPos.y;
187 hdc = GetDC(tw->hwnd);
188 SelectFont(hdc, tw->hfont);
189 #ifdef WINDOWS_NO_UNICODE
190 TextOut(hdc,xpos,ypos,
191 (LPSTR)(tw->ScreenBuffer + tw->CursorPos.y*tw->ScreenSize.x
192 + tw->CursorPos.x), count);
193 #else
194 TextOutW(hdc,xpos,ypos,
195 (LPCWSTR)(tw->ScreenBuffer +
196 tw->CursorPos.y*tw->ScreenSize.x +
197 tw->CursorPos.x),
198 count);
199 #endif
200 (void)ReleaseDC(tw->hwnd,hdc);
201 tw->CursorPos.x += count;
202 if (tw->CursorPos.x >= tw->ScreenSize.x)
203 text_new_line(tw);
204 }
205
206 void
text_size(TW * tw,int width,int height)207 text_size(TW *tw, int width, int height)
208 {
209 tw->ScreenSize.x = max(width, TextWinMinSize.x);
210 tw->ScreenSize.y = max(height, TextWinMinSize.y);
211 }
212
213 void
text_font(TW * tw,const char * name,int size)214 text_font(TW *tw, const char *name, int size)
215 {
216 /* make a new font */
217 LOGFONTA lf;
218 TEXTMETRIC tm;
219 LPSTR p;
220 HDC hdc;
221
222 /* reject inappropriate arguments */
223 if (name == NULL)
224 return;
225 if (size < 4)
226 return;
227
228 /* set new name and size */
229 free(tw->fontname);
230 tw->fontname = (char *)malloc(strlen(name)+1);
231 if (tw->fontname == NULL)
232 return;
233 strcpy(tw->fontname, name);
234 tw->fontsize = size;
235
236 /* if window not open, hwnd == 0 == HWND_DESKTOP */
237 hdc = GetDC(tw->hwnd);
238 memset(&lf, 0, sizeof(LOGFONTA));
239 strncpy(lf.lfFaceName,tw->fontname,LF_FACESIZE);
240 lf.lfHeight = -MulDiv(tw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
241 lf.lfPitchAndFamily = FIXED_PITCH;
242 lf.lfCharSet = DEFAULT_CHARSET;
243 if ( (p = strstr(tw->fontname," Italic")) != (LPSTR)NULL ) {
244 lf.lfFaceName[ (unsigned int)(p-tw->fontname) ] = '\0';
245 lf.lfItalic = TRUE;
246 }
247 if ( (p = strstr(tw->fontname," Bold")) != (LPSTR)NULL ) {
248 lf.lfFaceName[ (unsigned int)(p-tw->fontname) ] = '\0';
249 lf.lfWeight = FW_BOLD;
250 }
251 if (tw->hfont)
252 DeleteFont(tw->hfont);
253
254 tw->hfont = CreateFontIndirectA((LOGFONTA FAR *)&lf);
255
256 /* get text size */
257 SelectFont(hdc, tw->hfont);
258 GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
259 tw->CharSize.y = tm.tmHeight;
260 tw->CharSize.x = tm.tmAveCharWidth;
261 tw->CharAscent = tm.tmAscent;
262 if (tw->bFocus)
263 CreateCaret(tw->hwnd, 0, tw->CharSize.x, 2+tw->CaretHeight);
264 ReleaseDC(tw->hwnd, hdc);
265
266 /* redraw window if necessary */
267 if (tw->hwnd != HWND_DESKTOP) {
268 /* INCOMPLETE */
269 }
270 }
271
272 /* Set drag strings */
273 void
text_drag(TW * tw,const char * pre,const char * post)274 text_drag(TW *tw, const char *pre, const char *post)
275 {
276 /* remove old strings */
277 free((char *)tw->DragPre);
278 tw->DragPre = NULL;
279 free((char *)tw->DragPost);
280 tw->DragPost = NULL;
281
282 /* add new strings */
283 tw->DragPre = malloc(strlen(pre)+1);
284 if (tw->DragPre)
285 strcpy(tw->DragPre, pre);
286 tw->DragPost = malloc(strlen(post)+1);
287 if (tw->DragPost)
288 strcpy(tw->DragPost, post);
289 }
290
291 /* Set the window position and size */
292 void
text_setpos(TW * tw,int x,int y,int cx,int cy)293 text_setpos(TW *tw, int x, int y, int cx, int cy)
294 {
295 tw->x = x;
296 tw->y = y;
297 tw->cx = cx;
298 tw->cy = cy;
299 }
300
301 /* Get the window position and size */
text_getpos(TW * tw,int * px,int * py,int * pcx,int * pcy)302 int text_getpos(TW *tw, int *px, int *py, int *pcx, int *pcy)
303 {
304 *px = tw->x;
305 *py = tw->y;
306 *pcx = tw->cx;
307 *pcy = tw->cy;
308 return 0;
309 }
310
311 /* Allocate new text window */
312 TW *
text_new(void)313 text_new(void)
314 {
315 TW *tw;
316 tw = (TW *)malloc(sizeof(TW));
317 if (tw == NULL)
318 return NULL;
319 /* make sure everything is null */
320 memset(tw, 0, sizeof(TW));
321
322 /* set some defaults */
323 text_font(tw, "Courier New", 10);
324 text_size(tw, 80, 24);
325 tw->KeyBufSize = 2048;
326 tw->CursorFlag = 1; /* scroll to cursor after \n or \r */
327 tw->hwnd = HWND_DESKTOP;
328
329 tw->line_end = 0;
330 tw->line_start = 0;
331 tw->line_complete = FALSE;
332 tw->line_eof = FALSE;
333
334 tw->x = CW_USEDEFAULT;
335 tw->y = CW_USEDEFAULT;
336 tw->cx = CW_USEDEFAULT;
337 tw->cy = CW_USEDEFAULT;
338 #ifndef WINDOWS_NO_UNICODE
339 tw->utf8shift = 0;
340 #endif
341 return tw;
342 }
343
344 /* Destroy window and deallocate text window structure */
345 void
text_destroy(TW * tw)346 text_destroy(TW *tw)
347 {
348 if (tw->hwnd)
349 DestroyWindow(tw->hwnd);
350 tw->hwnd = HWND_DESKTOP;
351
352 if (tw->hfont)
353 DeleteFont(tw->hfont);
354 tw->hfont = NULL;
355
356 free((char *)tw->KeyBuf);
357 tw->KeyBuf = NULL;
358
359 free((char *)tw->ScreenBuffer);
360 tw->ScreenBuffer = NULL;
361
362 free((char *)tw->DragPre);
363 tw->DragPre = NULL;
364
365 free((char *)tw->DragPost);
366 tw->DragPost = NULL;
367
368 free((char *)tw->fontname);
369 tw->fontname = NULL;
370
371 #ifndef WINDOWS_NO_UNICODE
372 free((char *)tw->TitleW);
373 tw->TitleW = NULL;
374 #endif
375 }
376
377 /* register the window class */
378 int
text_register_class(TW * tw,HICON hicon)379 text_register_class(TW *tw, HICON hicon)
380 {
381 #ifdef WINDOWS_NO_UNICODE
382 WNDCLASS wndclass;
383 #else
384 WNDCLASSW wndclass;
385 #endif
386 HINSTANCE hInstance = GetModuleHandle(NULL);
387 tw->hIcon = hicon;
388
389 /* register window class */
390 wndclass.style = CS_HREDRAW | CS_VREDRAW;
391 wndclass.lpfnWndProc = WndTextProc;
392 wndclass.cbClsExtra = 0;
393 wndclass.cbWndExtra = sizeof(void *);
394 wndclass.hInstance = hInstance;
395 wndclass.hIcon = tw->hIcon ? tw->hIcon : LoadIcon(NULL, IDI_APPLICATION);
396 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
397 wndclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
398 wndclass.lpszMenuName = NULL;
399 wndclass.lpszClassName = TextWinClassName;
400 #ifdef WINDOWS_NO_UNICODE
401 return RegisterClass(&wndclass);
402 #else
403 return RegisterClassW(&wndclass);
404 #endif
405 }
406
407 /* Show the window */
text_create(TW * tw,const char * app_name,int show_cmd)408 int text_create(TW *tw, const char *app_name, int show_cmd)
409 {
410 HMENU sysmenu;
411 HINSTANCE hInstance = GetModuleHandle(NULL);
412 #ifndef WINDOWS_NO_UNICODE
413 wchar_t *app_nameW, *d;
414 const char *s;
415
416 app_nameW = malloc(strlen(app_name)*2+2);
417 if (app_nameW == NULL) {
418 text_error("Out of memory");
419 return 1;
420 }
421 d = app_nameW;
422 s = app_name;
423 while ((*d++ = (wchar_t)(unsigned char)(*s++)) != 0);
424 tw->TitleW = app_nameW;
425 #endif
426
427 tw->Title = app_name;
428 tw->nCmdShow = show_cmd;
429 tw->quitnow = FALSE;
430
431 /* make sure we have some sensible defaults */
432 if (tw->KeyBufSize < 256)
433 tw->KeyBufSize = 256;
434
435 tw->CursorPos.x = tw->CursorPos.y = 0;
436 tw->bFocus = FALSE;
437 tw->bGetCh = FALSE;
438 tw->CaretHeight = 0;
439
440 /* allocate buffers */
441 tw->KeyBufIn = tw->KeyBufOut = tw->KeyBuf = malloc(tw->KeyBufSize);
442 if (tw->KeyBuf == NULL) {
443 text_error("Out of memory");
444 return 1;
445 }
446 tw->ScreenBuffer = malloc(tw->ScreenSize.x * tw->ScreenSize.y * CHARSIZE);
447 if (tw->ScreenBuffer == NULL) {
448 text_error("Out of memory");
449 return 1;
450 }
451 #ifdef WINDOWS_NO_UNICODE
452 memset(tw->ScreenBuffer, ' ', tw->ScreenSize.x * tw->ScreenSize.y);
453 #else
454 wmemset(tw->ScreenBuffer, ' ', tw->ScreenSize.x * tw->ScreenSize.y);
455 #endif
456
457 #ifdef WINDOWS_NO_UNICODE
458 tw->hwnd = CreateWindow(TextWinClassName, tw->Title,
459 WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
460 tw->x, tw->y, tw->cx, tw->cy,
461 NULL, NULL, hInstance, tw);
462 #else
463 tw->hwnd = CreateWindowW(TextWinClassName, app_nameW,
464 WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
465 tw->x, tw->y, tw->cx, tw->cy,
466 NULL, NULL, hInstance, tw);
467 #endif
468
469 if (tw->hwnd == NULL) {
470 MessageBoxA((HWND)NULL,"Couldn't open text window",(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
471 return 1;
472 }
473
474 ShowWindow(tw->hwnd, tw->nCmdShow);
475 sysmenu = GetSystemMenu(tw->hwnd,0); /* get the sysmenu */
476 AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
477 AppendMenuA(sysmenu, MF_STRING, M_COPY_CLIP, "Copy to Clip&board");
478 AppendMenuA(sysmenu, MF_STRING, M_PASTE_CLIP, "&Paste");
479
480 return 0;
481 }
482
483 int
text_putch(TW * tw,int ch)484 text_putch(TW *tw, int ch)
485 {
486 int pos;
487 int n;
488 #ifndef WINDOWS_NO_UNICODE
489 int shift = tw->utf8shift;
490 tw->utf8shift=0;
491 #endif
492 if (tw->quitnow)
493 return ch; /* don't write error message as we shut down */
494 switch(ch) {
495 case '\r':
496 tw->CursorPos.x = 0;
497 if (tw->CursorFlag)
498 text_to_cursor(tw);
499 break;
500 case '\n':
501 text_new_line(tw);
502 break;
503 case 7:
504 MessageBeep(-1);
505 if (tw->CursorFlag)
506 text_to_cursor(tw);
507 break;
508 case '\t':
509 {
510 for (n = 8 - (tw->CursorPos.x % 8); n>0; n-- )
511 text_putch(tw, ' ');
512 }
513 break;
514 case 0x08:
515 case 0x7f:
516 tw->CursorPos.x--;
517 if (tw->CursorPos.x < 0) {
518 tw->CursorPos.x = tw->ScreenSize.x - 1;
519 tw->CursorPos.y--;
520 }
521 if (tw->CursorPos.y < 0)
522 tw->CursorPos.y = 0;
523 break;
524 default:
525 pos = tw->CursorPos.y*tw->ScreenSize.x + tw->CursorPos.x;
526 #ifndef WINDOWS_NO_UNICODE
527 /* Are we continuing a unicode char? */
528 if ((ch & 0xC0) == 0x80) {
529 tw->ScreenBuffer[pos] |= (ch & 0x3F)<<shift;
530 if (shift > 0)
531 tw->utf8shift = shift-6;
532 else
533 text_update_text(tw, 1); /* Only update when complete */
534 } else if (ch >= 0xe0) { /* 2 more to come */
535 tw->ScreenBuffer[pos] = (ch & 0x0f)<<12;
536 tw->utf8shift = 6;
537 } else if (ch >= 0xC0) { /* 1 more to come */
538 tw->ScreenBuffer[pos] = (ch & 0x01f)<<6;
539 tw->utf8shift = 0;
540 }
541 else
542 #endif
543 {
544 tw->ScreenBuffer[pos] = ch;
545 text_update_text(tw, 1);
546 }
547 }
548 return ch;
549 }
550
551 void
text_write_buf(TW * tw,const char * str,int cnt)552 text_write_buf(TW *tw, const char *str, int cnt)
553 {
554 #ifdef WINDOWS_NO_UNICODE
555 BYTE *p;
556 #else
557 wchar_t *p;
558 #endif
559 int count, limit;
560 int n;
561 if (tw->quitnow)
562 return; /* don't write error message as we shut down */
563 while (cnt>0) {
564 p = tw->ScreenBuffer + tw->CursorPos.y*tw->ScreenSize.x + tw->CursorPos.x;
565 limit = tw->ScreenSize.x - tw->CursorPos.x;
566 for (count=0; (count < limit) && (cnt>0) &&
567 (
568 #ifdef WINDOWS_NO_UNICODE
569 isprint((unsigned char)(*str))
570 #else
571 ((*str >= 32) && (*str <= 0x7F))
572 #endif
573 || *str=='\t'); count++) {
574 if (*str=='\t') {
575 for (n = 8 - ((tw->CursorPos.x+count) % 8); (count < limit) & (n>0); n--, count++ )
576 *p++ = ' ';
577 str++;
578 count--;
579 }
580 else {
581 *p++ = *str++;
582 }
583 cnt--;
584 }
585 if (count>0) {
586 text_update_text(tw, count);
587 }
588 if (cnt > 0) {
589 if (*str=='\n') {
590 text_new_line(tw);
591 str++;
592 cnt--;
593 }
594 else if (!
595 #ifdef WINDOWS_NO_UNICODE
596 isprint((unsigned char)(*str))
597 #else
598 ((*str >= 32) && (*str <= 0x7f))
599 #endif
600 && *str!='\t') {
601 text_putch(tw, *(const unsigned char *)str++);
602 cnt--;
603 }
604 }
605 }
606 }
607
608 /* Put string to window */
609 void
text_puts(TW * tw,const char * str)610 text_puts(TW *tw, const char *str)
611 {
612 text_write_buf(tw, str, strlen(str));
613 }
614
615 /* TRUE if key hit, FALSE if no key */
616 int
text_kbhit(TW * tw)617 text_kbhit(TW *tw)
618 {
619 return (tw->KeyBufIn != tw->KeyBufOut);
620 }
621
622 /* get character from keyboard, no echo */
623 /* need to add extended codes */
624 int
text_getch(TW * tw)625 text_getch(TW *tw)
626 {
627 MSG msg;
628 int ch;
629 text_to_cursor(tw);
630 tw->bGetCh = TRUE;
631 if (tw->bFocus) {
632 SetCaretPos(tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x,
633 tw->CursorPos.y*tw->CharSize.y + tw->CharAscent
634 - tw->CaretHeight - tw->ScrollPos.y);
635 ShowCaret(tw->hwnd);
636 }
637
638 #ifdef WINDOWS_NO_UNICODE
639 while (PeekMessage(&msg, (HWND)NULL, 0, 0, PM_NOREMOVE)) {
640 if (GetMessage(&msg, (HWND)NULL, 0, 0)) {
641 TranslateMessage(&msg);
642 DispatchMessage(&msg);
643 }
644 }
645 #else
646 while (PeekMessageW(&msg, (HWND)NULL, 0, 0, PM_NOREMOVE)) {
647 if (GetMessageW(&msg, (HWND)NULL, 0, 0)) {
648 TranslateMessage(&msg);
649 DispatchMessageW(&msg);
650 }
651 }
652 #endif
653
654 if (tw->quitnow)
655 return EOF; /* window closed */
656
657 while (!text_kbhit(tw)) {
658 if (!tw->quitnow) {
659 #ifdef WINDOWS_NO_UNICODE
660 if (GetMessage(&msg, (HWND)NULL, 0, 0)) {
661 TranslateMessage(&msg);
662 DispatchMessage(&msg);
663 }
664 #else
665 if (GetMessageW(&msg, (HWND)NULL, 0, 0)) {
666 TranslateMessage(&msg);
667 DispatchMessageW(&msg);
668 }
669 #endif
670 }
671 else
672 return EOF; /* window closed */
673 }
674
675 ch = *tw->KeyBufOut++;
676 if (ch=='\r')
677 ch = '\n';
678 if (tw->KeyBufOut - tw->KeyBuf >= tw->KeyBufSize)
679 tw->KeyBufOut = tw->KeyBuf; /* wrap around */
680 if (tw->bFocus)
681 HideCaret(tw->hwnd);
682 tw->bGetCh = FALSE;
683 return ch;
684 }
685
686 /* Read line from keyboard using buffered input
687 * Return at most 'len' characters
688 * Does NOT add null terminating character
689 * This is NOT the same as fgets()
690 * Do not mix this with calls to text_getch()
691 */
692 int
text_read_line(TW * tw,char * line,int len)693 text_read_line(TW *tw, char *line, int len)
694 {
695 int ch;
696 if (tw->line_eof)
697 return 0;
698
699 while (!tw->line_complete) {
700 /* we have not yet collected a full line */
701 ch = text_getch(tw);
702 switch(ch) {
703 case EOF:
704 case 26: /* ^Z == EOF */
705 tw->line_eof = TRUE;
706 tw->line_complete = TRUE;
707 break;
708 case '\b': /* ^H */
709 case 0x7f: /* DEL */
710 if (tw->line_end) {
711 text_putch(tw, '\b');
712 text_putch(tw, ' ');
713 text_putch(tw, '\b');
714 #ifndef WINDOWS_NO_UNICODE
715 while ((tw->line_end) &&
716 ((tw->line_buf[tw->line_end-1] & 0xC0) == 0x80)) {
717 /* It's a UTF-8 continuation char. */
718 --(tw->line_end);
719 }
720 if (tw->line_end == 0)
721 break;
722 #endif
723 --(tw->line_end);
724 }
725 break;
726 case 21: /* ^U */
727 while (tw->line_end) {
728 text_putch(tw, '\b');
729 text_putch(tw, ' ');
730 text_putch(tw, '\b');
731 --(tw->line_end);
732 }
733 break;
734 case '\r':
735 case '\n':
736 tw->line_complete = TRUE;
737 /* fall through */
738 default:
739 tw->line_buf[tw->line_end++] = ch;
740 text_putch(tw, ch);
741 break;
742 }
743 if (tw->line_end >= sizeof(tw->line_buf))
744 tw->line_complete = TRUE;
745 }
746
747 if (tw->quitnow)
748 return -1;
749
750 if (tw->line_complete) {
751 /* We either filled the buffer or got CR, LF or EOF */
752 int count = min(len, tw->line_end - tw->line_start);
753 memcpy(line, tw->line_buf + tw->line_start, count);
754 tw->line_start += count;
755 if (tw->line_start == tw->line_end) {
756 tw->line_start = tw->line_end = 0;
757 tw->line_complete = FALSE;
758 }
759 return count;
760 }
761
762 return 0;
763 }
764
765 /* Read a string from the keyboard, of up to len characters */
766 /* (not including trailing NULL) */
767 int
text_gets(TW * tw,char * line,int len)768 text_gets(TW *tw, char *line, int len)
769 {
770 LPSTR dest = line;
771 LPSTR limit = dest + len; /* don't leave room for '\0' */
772 int ch;
773 do {
774 if (dest >= limit)
775 break;
776 ch = text_getch(tw);
777 switch(ch) {
778 case 26: /* ^Z == EOF */
779 return 0;
780 case '\b': /* ^H */
781 case 0x7f: /* DEL */
782 if (dest > line) {
783 text_putch(tw, '\b');
784 text_putch(tw, ' ');
785 text_putch(tw, '\b');
786 #ifndef WINDOWS_NO_UNICODE
787 while ((dest > line) &&
788 ((dest[-1] & 0xC0) == 0x80)) {
789 /* It's a UTF-8 continuation char. */
790 --(dest);
791 }
792 if (dest == line)
793 break;
794 #endif
795 --dest;
796 }
797 break;
798 case 21: /* ^U */
799 while (dest > line) {
800 text_putch(tw, '\b');
801 text_putch(tw, ' ');
802 text_putch(tw, '\b');
803 --dest;
804 }
805 break;
806 default:
807 *dest++ = ch;
808 text_putch(tw, ch);
809 break;
810 }
811 } while (ch != '\n');
812
813 *dest = '\0';
814 return (dest-line);
815 }
816
817 /* Windows 3.1 drag-drop feature */
818 void
text_drag_drop(TW * tw,HDROP hdrop)819 text_drag_drop(TW *tw, HDROP hdrop)
820 {
821 TCHAR *szFile;
822 int i, cFiles;
823 unsigned int Len, error;
824 const char *p;
825 const TCHAR *t;
826 if ( (tw->DragPre==NULL) || (tw->DragPost==NULL) )
827 return;
828
829 cFiles = DragQueryFile(hdrop, (UINT)(-1), (LPTSTR)NULL, 0);
830 for (i=0; i<cFiles; i++) {
831 Len = DragQueryFile(hdrop, i, NULL, 0);
832 szFile = (TCHAR *)malloc((Len+1)*sizeof(TCHAR));
833 if (szFile != 0) {
834 error = DragQueryFile(hdrop, i, szFile, Len+1);
835 if (error != 0) {
836 for (p=tw->DragPre; *p; p++)
837 SendMessage(tw->hwnd,WM_CHAR,*p,1L);
838 for (t=szFile; *t; t++) {
839 if (*t == '\\')
840 SendMessage(tw->hwnd,WM_CHAR,'/',1L);
841 else
842 SendMessage(tw->hwnd,WM_CHAR,*t,1L);
843 }
844 for (p=tw->DragPost; *p; p++)
845 SendMessage(tw->hwnd,WM_CHAR,*p,1L);
846 }
847 free(szFile);
848 }
849 }
850 DragFinish(hdrop);
851 }
852
853 void
text_copy_to_clipboard(TW * tw)854 text_copy_to_clipboard(TW *tw)
855 {
856 int size, count;
857 HGLOBAL hGMem;
858 #ifdef WINDOWS_NO_UNICODE
859 LPSTR cbuf, cp;
860 HDC hdc;
861 TEXTMETRIC tm;
862 #else
863 LPWSTR cbuf, cp;
864 #endif
865 UINT type;
866 int i;
867
868 size = tw->ScreenSize.y * (tw->ScreenSize.x + 2) + 1;
869 size *= CHARSIZE;
870 hGMem = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)size);
871 #ifdef WINDOWS_NO_UNICODE
872 cbuf = cp = (LPSTR)GlobalLock(hGMem);
873 #else
874 cbuf = cp = (LPWSTR)GlobalLock(hGMem);
875 #endif
876 if (cp == NULL)
877 return;
878
879 for (i=0; i<tw->ScreenSize.y; i++) {
880 count = tw->ScreenSize.x;
881 memcpy(cp, tw->ScreenBuffer + tw->ScreenSize.x*i, count*CHARSIZE);
882 /* remove trailing spaces */
883 for (count=count-1; count>=0; count--) {
884 if (cp[count]!=' ')
885 break;
886 cp[count] = '\0';
887 }
888 cp[++count] = '\r';
889 cp[++count] = '\n';
890 cp[++count] = '\0';
891 cp += count;
892 }
893 /* Now remove completely empty trailing lines */
894 while (cp >= cbuf+4) {
895 if ((cp[-3] != '\n') || (cp[-4] != '\r'))
896 break;
897 cp -= 2;
898 *cp = '\0';
899 }
900 #ifdef WINDOWS_NO_UNICODE
901 size = strlen(cbuf) + 1;
902 #else
903 size = CHARSIZE*(wcslen(cbuf) + 1);
904 #endif
905 GlobalUnlock(hGMem);
906 hGMem = GlobalReAlloc(hGMem, (DWORD)size, GHND | GMEM_SHARE);
907 #ifdef WINDOWS_NO_UNICODE
908 /* find out what type to put into clipboard */
909 hdc = GetDC(tw->hwnd);
910 SelectFont(hdc, tw->hfont);
911 GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
912 if (tm.tmCharSet == OEM_CHARSET)
913 type = CF_OEMTEXT;
914 else
915 type = CF_TEXT;
916 ReleaseDC(tw->hwnd, hdc);
917 #else
918 type = CF_UNICODETEXT;
919 #endif
920 /* give buffer to clipboard */
921 OpenClipboard(tw->hwnd);
922 EmptyClipboard();
923 SetClipboardData(type, hGMem);
924 CloseClipboard();
925 }
926
927 void
text_paste_from_clipboard(TW * tw)928 text_paste_from_clipboard(TW *tw)
929 {
930 HGLOBAL hClipMemory;
931 #ifdef WINDOWS_NO_UNICODE
932 BYTE *p;
933 #else
934 wchar_t *p;
935 #endif
936 long count;
937 OpenClipboard(tw->hwnd);
938 #ifdef WINDOWS_NO_UNICODE
939 if (IsClipboardFormatAvailable(CF_TEXT)) {
940 hClipMemory = GetClipboardData(CF_TEXT);
941 #else
942 if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
943 hClipMemory = GetClipboardData(CF_UNICODETEXT);
944 #endif
945 p = GlobalLock(hClipMemory);
946 while (*p) {
947 /* transfer to keyboard circular buffer */
948 count = tw->KeyBufIn - tw->KeyBufOut;
949 if (count < 0)
950 count += tw->KeyBufSize;
951 #ifndef WINDOWS_NO_UNICODE
952 /* The clipboard contains unicode, but we put it into the key
953 * buffer as if it was typing utf8 */
954 if (*p >= 0x800) {
955 if (count < tw->KeyBufSize-3) {
956 *tw->KeyBufIn++ = 0xE0 | (*p>>12);
957 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
958 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
959 *tw->KeyBufIn++ = 0x80 | ((*p>>6) & 0x3F);
960 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
961 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
962 *tw->KeyBufIn++ = 0x80 | (*p & 0x3f);
963 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
964 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
965 }
966 } else if (*p >= 0x80) {
967 if (count < tw->KeyBufSize-2) {
968 *tw->KeyBufIn++ = 0xC0 | (*p>>6);
969 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
970 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
971 *tw->KeyBufIn++ = 0x80 | (*p & 0x3f);
972 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
973 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
974 }
975 } else
976 #endif
977 if (count < tw->KeyBufSize-1) {
978 *tw->KeyBufIn++ = *p;
979 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
980 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
981 }
982 p++;
983 }
984 GlobalUnlock(hClipMemory);
985 }
986 CloseClipboard();
987 }
988
989 /* text window */
990 LRESULT CALLBACK
991 WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
992 {
993 HDC hdc;
994 PAINTSTRUCT ps;
995 RECT rect;
996 int nYinc, nXinc;
997 TW *tw;
998 if (message == WM_CREATE) {
999 /* Object is stored in window extra data.
1000 * Nothing must try to use the object before WM_CREATE
1001 * initializes it here.
1002 */
1003 tw = (TW *)(((CREATESTRUCT FAR *)lParam)->lpCreateParams);
1004 SetWindowLong(hwnd, 0, (LONG)tw);
1005 }
1006 tw = (TW *)GetWindowLong(hwnd, 0);
1007
1008 switch(message) {
1009 case WM_SYSCOMMAND:
1010 switch(LOWORD(wParam)) {
1011 case M_COPY_CLIP:
1012 text_copy_to_clipboard(tw);
1013 return 0;
1014 case M_PASTE_CLIP:
1015 text_paste_from_clipboard(tw);
1016 return 0;
1017 }
1018 break;
1019 case WM_SETFOCUS:
1020 tw->bFocus = TRUE;
1021 CreateCaret(hwnd, 0, tw->CharSize.x, 2+tw->CaretHeight);
1022 SetCaretPos(tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x,
1023 tw->CursorPos.y*tw->CharSize.y + tw->CharAscent
1024 - tw->CaretHeight - tw->ScrollPos.y);
1025 if (tw->bGetCh)
1026 ShowCaret(hwnd);
1027 break;
1028 case WM_KILLFOCUS:
1029 DestroyCaret();
1030 tw->bFocus = FALSE;
1031 break;
1032 case WM_MOVE:
1033 if (!IsIconic(hwnd) && !IsZoomed(hwnd)) {
1034 GetWindowRect(hwnd, &rect);
1035 tw->x = rect.left;
1036 tw->y = rect.top;
1037 }
1038 break;
1039 case WM_SIZE:
1040 if (wParam == SIZE_MINIMIZED)
1041 return(0);
1042
1043 /* remember current window size */
1044 if (wParam != SIZE_MAXIMIZED) {
1045 GetWindowRect(hwnd, &rect);
1046 tw->cx = rect.right - rect.left;
1047 tw->cy = rect.bottom - rect.top;
1048 tw->x = rect.left;
1049 tw->y = rect.top;
1050 }
1051
1052 tw->ClientSize.y = HIWORD(lParam);
1053 tw->ClientSize.x = LOWORD(lParam);
1054
1055 tw->ScrollMax.y = max(0, tw->CharSize.y*tw->ScreenSize.y - tw->ClientSize.y);
1056 tw->ScrollPos.y = min(tw->ScrollPos.y, tw->ScrollMax.y);
1057
1058 UpdateScrollBarY(tw);
1059
1060 tw->ScrollMax.x = max(0, tw->CharSize.x*tw->ScreenSize.x - tw->ClientSize.x);
1061 tw->ScrollPos.x = min(tw->ScrollPos.x, tw->ScrollMax.x);
1062
1063 UpdateScrollBarX(tw);
1064
1065 if (tw->bFocus && tw->bGetCh) {
1066 SetCaretPos(tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x,
1067 tw->CursorPos.y*tw->CharSize.y + tw->CharAscent
1068 - tw->CaretHeight - tw->ScrollPos.y);
1069 ShowCaret(hwnd);
1070 }
1071 return(0);
1072 case WM_VSCROLL:
1073 switch(LOWORD(wParam)) {
1074 case SB_TOP:
1075 nYinc = -tw->ScrollPos.y;
1076 break;
1077 case SB_BOTTOM:
1078 nYinc = tw->ScrollMax.y - tw->ScrollPos.y;
1079 break;
1080 case SB_LINEUP:
1081 nYinc = -tw->CharSize.y;
1082 break;
1083 case SB_LINEDOWN:
1084 nYinc = tw->CharSize.y;
1085 break;
1086 case SB_PAGEUP:
1087 nYinc = min(-1,-tw->ClientSize.y);
1088 break;
1089 case SB_PAGEDOWN:
1090 nYinc = max(1,tw->ClientSize.y);
1091 break;
1092 case SB_THUMBPOSITION:
1093 nYinc = HIWORD(wParam) - tw->ScrollPos.y;
1094 break;
1095 default:
1096 nYinc = 0;
1097 }
1098 if ( (nYinc = max(-tw->ScrollPos.y,
1099 min(nYinc, tw->ScrollMax.y - tw->ScrollPos.y)))
1100 != 0 ) {
1101 tw->ScrollPos.y += nYinc;
1102 ScrollWindow(hwnd,0,-nYinc,NULL,NULL);
1103 UpdateScrollBarY(tw);
1104 UpdateWindow(hwnd);
1105 }
1106 return(0);
1107 case WM_HSCROLL:
1108 switch(LOWORD(wParam)) {
1109 case SB_LINEUP:
1110 nXinc = -tw->CharSize.x;
1111 break;
1112 case SB_LINEDOWN:
1113 nXinc = tw->CharSize.x;
1114 break;
1115 case SB_PAGEUP:
1116 nXinc = min(-1,-tw->ClientSize.x);
1117 break;
1118 case SB_PAGEDOWN:
1119 nXinc = max(1,tw->ClientSize.x);
1120 break;
1121 case SB_THUMBPOSITION:
1122 nXinc = HIWORD(wParam) - tw->ScrollPos.x;
1123 break;
1124 default:
1125 nXinc = 0;
1126 }
1127 if ( (nXinc = max(-tw->ScrollPos.x,
1128 min(nXinc, tw->ScrollMax.x - tw->ScrollPos.x)))
1129 != 0 ) {
1130 tw->ScrollPos.x += nXinc;
1131 ScrollWindow(hwnd,-nXinc,0,NULL,NULL);
1132 UpdateScrollBarX(tw);
1133 UpdateWindow(hwnd);
1134 }
1135 return(0);
1136 case WM_KEYDOWN:
1137 switch(wParam) {
1138 case VK_HOME:
1139 SendMessage(hwnd, WM_VSCROLL, SB_TOP, (LPARAM)0);
1140 break;
1141 case VK_END:
1142 SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, (LPARAM)0);
1143 break;
1144 case VK_PRIOR:
1145 SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)0);
1146 break;
1147 case VK_NEXT:
1148 SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)0);
1149 break;
1150 case VK_UP:
1151 SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)0);
1152 break;
1153 case VK_DOWN:
1154 SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)0);
1155 break;
1156 case VK_LEFT:
1157 SendMessage(hwnd, WM_HSCROLL, SB_LINEUP, (LPARAM)0);
1158 break;
1159 case VK_RIGHT:
1160 SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, (LPARAM)0);
1161 break;
1162 }
1163 break;
1164 #ifdef WM_UNICHAR
1165 case WM_UNICHAR: /* Belt and braces */
1166 #endif
1167 case WM_CHAR:
1168 { /* We get unicode in, but we put it into the buffer as if the
1169 * user was typing UTF8.
1170 */
1171 long count = tw->KeyBufIn - tw->KeyBufOut;
1172 if (count < 0) count += tw->KeyBufSize;
1173 #ifndef WINDOWS_NO_UNICODE
1174 if (wParam >= 0x800) {
1175 if (count >= tw->KeyBufSize-3)
1176 return 0; /* Silently drop the chars! */
1177 *tw->KeyBufIn++ = 0xE0 | (wParam>>12);
1178 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
1179 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
1180 *tw->KeyBufIn++ = 0x80 | ((wParam>>6) & 0x3F);
1181 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
1182 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
1183 *tw->KeyBufIn++ = 0x80 | (wParam & 0x3f);
1184 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
1185 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
1186 } else if (wParam >= 0x80) {
1187 if (count >= tw->KeyBufSize-2)
1188 return 0; /* Silently drop the chars! */
1189 *tw->KeyBufIn++ = 0xC0 | (wParam>>6);
1190 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
1191 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
1192 *tw->KeyBufIn++ = 0x80 | (wParam & 0x3f);
1193 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
1194 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
1195 } else
1196 #endif
1197 {
1198 if (count >= tw->KeyBufSize-1)
1199 return 0; /* Silently drop the char! */
1200 *tw->KeyBufIn++ = wParam;
1201 if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
1202 tw->KeyBufIn = tw->KeyBuf; /* wrap around */
1203 }
1204 }
1205 return(0);
1206 case WM_PAINT:
1207 {
1208 POINT source, width, dest;
1209 hdc = BeginPaint(hwnd, &ps);
1210 SelectFont(hdc, tw->hfont);
1211 SetMapMode(hdc, MM_TEXT);
1212 SetBkMode(hdc,OPAQUE);
1213 GetClientRect(hwnd, &rect);
1214 source.x = (rect.left + tw->ScrollPos.x) / tw->CharSize.x; /* source */
1215 source.y = (rect.top + tw->ScrollPos.y) / tw->CharSize.y;
1216 dest.x = source.x * tw->CharSize.x - tw->ScrollPos.x; /* destination */
1217 dest.y = source.y * tw->CharSize.y - tw->ScrollPos.y;
1218 width.x = ((rect.right + tw->ScrollPos.x + tw->CharSize.x - 1) / tw->CharSize.x) - source.x; /* width */
1219 width.y = ((rect.bottom + tw->ScrollPos.y + tw->CharSize.y - 1) / tw->CharSize.y) - source.y;
1220 if (source.x < 0)
1221 source.x = 0;
1222 if (source.y < 0)
1223 source.y = 0;
1224 if (source.x+width.x > tw->ScreenSize.x)
1225 width.x = tw->ScreenSize.x - source.x;
1226 if (source.y+width.y > tw->ScreenSize.y)
1227 width.y = tw->ScreenSize.y - source.y;
1228 /* for each line */
1229 while (width.y>0) {
1230 #ifdef WINDOWS_NO_UNICODE
1231 TextOut(hdc,dest.x,dest.y,
1232 (LPSTR)(tw->ScreenBuffer + source.y*tw->ScreenSize.x + source.x),
1233 width.x);
1234 #else
1235 TextOutW(hdc,dest.x,dest.y,
1236 (LPCWSTR)(tw->ScreenBuffer + source.y*tw->ScreenSize.x + source.x),
1237 width.x);
1238 #endif
1239 dest.y += tw->CharSize.y;
1240 source.y++;
1241 width.y--;
1242 }
1243 EndPaint(hwnd, &ps);
1244 return 0;
1245 }
1246 case WM_DROPFILES:
1247 text_drag_drop(tw, (HDROP)wParam);
1248 break;
1249 case WM_CREATE:
1250 {
1251 RECT crect, wrect;
1252 int cx, cy;
1253
1254 tw->hwnd = hwnd;
1255
1256 /* make window no larger than screen buffer */
1257 GetWindowRect(hwnd, &wrect);
1258 GetClientRect(hwnd, &crect);
1259 cx = min(tw->CharSize.x*tw->ScreenSize.x, crect.right);
1260 cy = min(tw->CharSize.y*tw->ScreenSize.y, crect.bottom);
1261 MoveWindow(hwnd, wrect.left, wrect.top,
1262 wrect.right-wrect.left + (cx - crect.right),
1263 wrect.bottom-wrect.top + (cy - crect.bottom),
1264 TRUE);
1265
1266 if ( (tw->DragPre!=(LPSTR)NULL) && (tw->DragPost!=(LPSTR)NULL) )
1267 DragAcceptFiles(hwnd, TRUE);
1268 }
1269 break;
1270 case WM_CLOSE:
1271 /* Tell user that we heard them */
1272 if (!tw->quitnow) {
1273 TCHAR title[256];
1274 int count = GetWindowText(hwnd, title,
1275 sizeof(title)/sizeof(TCHAR)-11);
1276 #ifdef WINDOWS_NO_UNICODE
1277 lstrcpyA(title+count, " - closing");
1278 #else
1279 lstrcpyW(title+count, L" - closing");
1280 #endif
1281 SetWindowText(hwnd, title);
1282 }
1283 tw->quitnow = TRUE;
1284 /* wait until Ghostscript exits before destroying window */
1285 return 0;
1286 case WM_DESTROY:
1287 DragAcceptFiles(hwnd, FALSE);
1288 if (tw->hfont)
1289 DeleteFont(tw->hfont);
1290 tw->hfont = (HFONT)0;
1291 tw->quitnow = TRUE;
1292 PostQuitMessage(0);
1293 break;
1294 }
1295 return DefWindowProc(hwnd, message, wParam, lParam);
1296 }
1297
1298 HWND text_get_handle(TW *tw)
1299 {
1300 return tw->hwnd;
1301 }
1302
1303 #ifdef NOTUSED
1304 /* test program */
1305
1306 int PASCAL
1307 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
1308 {
1309 TW *tw;
1310
1311 /* make a test window */
1312 tw = text_new();
1313
1314 if (!hPrevInstance) {
1315 HICON hicon = LoadIcon(NULL, IDI_APPLICATION);
1316 text_register_class(tw, hicon);
1317 }
1318 text_font(tw, "Courier New", 10);
1319 text_size(tw, 80, 80);
1320 text_drag(tw, "(", ") run\r");
1321
1322 /* show the text window */
1323 if (!text_create(tw, "Application Name", nCmdShow)) {
1324 /* do the real work here */
1325 /* TESTING */
1326 int ch;
1327 int len;
1328 char line[256];
1329 while ( (len = text_read_line(tw, line, 256-1)) != 0 ) {
1330 text_write_buf(tw, line, len);
1331 }
1332 /*
1333 while ( text_gets(tw, line, 256-1) ) {
1334 text_puts(tw, line);
1335 }
1336 */
1337 /*
1338 while ( (ch = text_getch(tw, )) != 4 )
1339 text_putch(tw, ch);
1340 */
1341 }
1342 else {
1343
1344 }
1345
1346 /* clean up */
1347 text_destroy(tw);
1348
1349 /* end program */
1350 return 0;
1351 }
1352 #endif
1353