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