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