xref: /plan9/sys/src/cmd/gs/src/dwtext.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 1996-2001 Ghostgum Software Pty Ltd.  All rights reserved.
23ff48bf5SDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
53ff48bf5SDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
93ff48bf5SDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
153ff48bf5SDavid du Colombier */
163ff48bf5SDavid du Colombier 
173ff48bf5SDavid du Colombier 
18*593dc095SDavid du Colombier /* $Id: dwtext.c,v 1.9 2005/03/04 10:27:39 ghostgum Exp $ */
193ff48bf5SDavid du Colombier 
203ff48bf5SDavid du Colombier /* Microsoft Windows text window for Ghostscript.
213ff48bf5SDavid du Colombier 
223ff48bf5SDavid du Colombier #include <stdlib.h>
233ff48bf5SDavid du Colombier #include <string.h> 	/* use only far items */
243ff48bf5SDavid du Colombier #include <ctype.h>
253ff48bf5SDavid du Colombier 
263ff48bf5SDavid du Colombier #define STRICT
273ff48bf5SDavid du Colombier #include <windows.h>
283ff48bf5SDavid du Colombier #include <windowsx.h>
293ff48bf5SDavid du Colombier #include <commdlg.h>
303ff48bf5SDavid du Colombier #include <shellapi.h>
313ff48bf5SDavid du Colombier 
323ff48bf5SDavid du Colombier #include "dwtext.h"
333ff48bf5SDavid du Colombier 
343ff48bf5SDavid du Colombier /* Define  min and max, but make sure to use the identical definition */
353ff48bf5SDavid du Colombier /* to the one that all the compilers seem to have.... */
363ff48bf5SDavid du Colombier #ifndef min
373ff48bf5SDavid du Colombier #  define min(a, b) (((a) < (b)) ? (a) : (b))
383ff48bf5SDavid du Colombier #endif
393ff48bf5SDavid du Colombier #ifndef max
403ff48bf5SDavid du Colombier #  define max(a, b) (((a) > (b)) ? (a) : (b))
413ff48bf5SDavid du Colombier #endif
423ff48bf5SDavid du Colombier 
433ff48bf5SDavid du Colombier #ifndef EOF
443ff48bf5SDavid du Colombier #define EOF (-1)
453ff48bf5SDavid du Colombier #endif
463ff48bf5SDavid du Colombier 
473ff48bf5SDavid du Colombier /* sysmenu */
483ff48bf5SDavid du Colombier #define M_COPY_CLIP 1
493ff48bf5SDavid du Colombier #define M_PASTE_CLIP 2
503ff48bf5SDavid du Colombier 
513ff48bf5SDavid du Colombier LRESULT CALLBACK WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
523ff48bf5SDavid du Colombier static void text_error(char *message);
533ff48bf5SDavid du Colombier static void text_new_line(TW *tw);
543ff48bf5SDavid du Colombier static void text_update_text(TW *tw, int count);
553ff48bf5SDavid du Colombier static void text_drag_drop(TW *tw, HDROP hdrop);
563ff48bf5SDavid du Colombier static void text_copy_to_clipboard(TW *tw);
573ff48bf5SDavid du Colombier static void text_paste_from_clipboard(TW *tw);
583ff48bf5SDavid du Colombier 
593ff48bf5SDavid du Colombier static const char* TextWinClassName = "rjlTextWinClass";
603ff48bf5SDavid du Colombier static const POINT TextWinMinSize = {16, 4};
613ff48bf5SDavid du Colombier 
623ff48bf5SDavid du Colombier static void
text_error(char * message)633ff48bf5SDavid du Colombier text_error(char *message)
643ff48bf5SDavid du Colombier {
653ff48bf5SDavid du Colombier     MessageBox((HWND)NULL,message,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
663ff48bf5SDavid du Colombier }
673ff48bf5SDavid du Colombier 
683ff48bf5SDavid du Colombier /* Bring Cursor into text window */
693ff48bf5SDavid du Colombier void
text_to_cursor(TW * tw)703ff48bf5SDavid du Colombier text_to_cursor(TW *tw)
713ff48bf5SDavid du Colombier {
723ff48bf5SDavid du Colombier int nXinc=0;
733ff48bf5SDavid du Colombier int nYinc=0;
743ff48bf5SDavid du Colombier int cxCursor;
753ff48bf5SDavid du Colombier int cyCursor;
763ff48bf5SDavid du Colombier 	cyCursor = tw->CursorPos.y * tw->CharSize.y;
773ff48bf5SDavid du Colombier 	if ( (cyCursor + tw->CharSize.y > tw->ScrollPos.y + tw->ClientSize.y)
783ff48bf5SDavid du Colombier /*	  || (cyCursor < tw->ScrollPos.y) ) { */
793ff48bf5SDavid du Colombier /* change to scroll to end of window instead of just making visible */
803ff48bf5SDavid du Colombier /* so that ALL of error message can be seen */
813ff48bf5SDavid du Colombier 	  || (cyCursor < tw->ScrollPos.y+tw->ClientSize.y) ) {
823ff48bf5SDavid du Colombier 		nYinc = max(0, cyCursor + tw->CharSize.y
833ff48bf5SDavid du Colombier 			- tw->ClientSize.y) - tw->ScrollPos.y;
843ff48bf5SDavid du Colombier 		nYinc = min(nYinc, tw->ScrollMax.y - tw->ScrollPos.y);
853ff48bf5SDavid du Colombier 	}
863ff48bf5SDavid du Colombier 	cxCursor = tw->CursorPos.x * tw->CharSize.x;
873ff48bf5SDavid du Colombier 	if ( (cxCursor + tw->CharSize.x > tw->ScrollPos.x + tw->ClientSize.x)
883ff48bf5SDavid du Colombier 	  || (cxCursor < tw->ScrollPos.x) ) {
893ff48bf5SDavid du Colombier 		nXinc = max(0, cxCursor + tw->CharSize.x
903ff48bf5SDavid du Colombier 			- tw->ClientSize.x/2) - tw->ScrollPos.x;
913ff48bf5SDavid du Colombier 		nXinc = min(nXinc, tw->ScrollMax.x - tw->ScrollPos.x);
923ff48bf5SDavid du Colombier 	}
933ff48bf5SDavid du Colombier 	if (nYinc || nXinc) {
943ff48bf5SDavid du Colombier 		tw->ScrollPos.y += nYinc;
953ff48bf5SDavid du Colombier 		tw->ScrollPos.x += nXinc;
963ff48bf5SDavid du Colombier 		ScrollWindow(tw->hwnd,-nXinc,-nYinc,NULL,NULL);
973ff48bf5SDavid du Colombier 		SetScrollPos(tw->hwnd,SB_VERT,tw->ScrollPos.y,TRUE);
983ff48bf5SDavid du Colombier 		SetScrollPos(tw->hwnd,SB_HORZ,tw->ScrollPos.x,TRUE);
993ff48bf5SDavid du Colombier 		UpdateWindow(tw->hwnd);
1003ff48bf5SDavid du Colombier 	}
1013ff48bf5SDavid du Colombier }
1023ff48bf5SDavid du Colombier 
1033ff48bf5SDavid du Colombier static void
text_new_line(TW * tw)1043ff48bf5SDavid du Colombier text_new_line(TW *tw)
1053ff48bf5SDavid du Colombier {
1063ff48bf5SDavid du Colombier 	tw->CursorPos.x = 0;
1073ff48bf5SDavid du Colombier 	tw->CursorPos.y++;
1083ff48bf5SDavid du Colombier 	if (tw->CursorPos.y >= tw->ScreenSize.y) {
1093ff48bf5SDavid du Colombier 	    int i =  tw->ScreenSize.x * (tw->ScreenSize.y - 1);
1103ff48bf5SDavid du Colombier 		memmove(tw->ScreenBuffer, tw->ScreenBuffer+tw->ScreenSize.x, i);
1113ff48bf5SDavid du Colombier 		memset(tw->ScreenBuffer + i, ' ', tw->ScreenSize.x);
1123ff48bf5SDavid du Colombier 		tw->CursorPos.y--;
1133ff48bf5SDavid du Colombier 		ScrollWindow(tw->hwnd,0,-tw->CharSize.y,NULL,NULL);
1143ff48bf5SDavid du Colombier 		UpdateWindow(tw->hwnd);
1153ff48bf5SDavid du Colombier 	}
1163ff48bf5SDavid du Colombier 	if (tw->CursorFlag)
1173ff48bf5SDavid du Colombier 		text_to_cursor(tw);
1183ff48bf5SDavid du Colombier 
1193ff48bf5SDavid du Colombier /*	TextMessage(); */
1203ff48bf5SDavid du Colombier }
1213ff48bf5SDavid du Colombier 
1223ff48bf5SDavid du Colombier /* Update count characters in window at cursor position */
1233ff48bf5SDavid du Colombier /* Updates cursor position */
1243ff48bf5SDavid du Colombier static void
text_update_text(TW * tw,int count)1253ff48bf5SDavid du Colombier text_update_text(TW *tw, int count)
1263ff48bf5SDavid du Colombier {
1273ff48bf5SDavid du Colombier HDC hdc;
1283ff48bf5SDavid du Colombier int xpos, ypos;
1293ff48bf5SDavid du Colombier 	xpos = tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x;
1303ff48bf5SDavid du Colombier 	ypos = tw->CursorPos.y*tw->CharSize.y - tw->ScrollPos.y;
1313ff48bf5SDavid du Colombier 	hdc = GetDC(tw->hwnd);
1323ff48bf5SDavid du Colombier 	SelectFont(hdc, tw->hfont);
1333ff48bf5SDavid du Colombier 	TextOut(hdc,xpos,ypos,
1343ff48bf5SDavid du Colombier 		(LPSTR)(tw->ScreenBuffer + tw->CursorPos.y*tw->ScreenSize.x
1353ff48bf5SDavid du Colombier 		+ tw->CursorPos.x), count);
1363ff48bf5SDavid du Colombier 	(void)ReleaseDC(tw->hwnd,hdc);
1373ff48bf5SDavid du Colombier 	tw->CursorPos.x += count;
1383ff48bf5SDavid du Colombier 	if (tw->CursorPos.x >= tw->ScreenSize.x)
1393ff48bf5SDavid du Colombier 		text_new_line(tw);
1403ff48bf5SDavid du Colombier }
1413ff48bf5SDavid du Colombier 
1423ff48bf5SDavid du Colombier 
1433ff48bf5SDavid du Colombier void
text_size(TW * tw,int width,int height)1443ff48bf5SDavid du Colombier text_size(TW *tw, int width, int height)
1453ff48bf5SDavid du Colombier {
1463ff48bf5SDavid du Colombier     tw->ScreenSize.x =  max(width, TextWinMinSize.x);
1473ff48bf5SDavid du Colombier     tw->ScreenSize.y =  max(height, TextWinMinSize.y);
1483ff48bf5SDavid du Colombier }
1493ff48bf5SDavid du Colombier 
1503ff48bf5SDavid du Colombier void
text_font(TW * tw,const char * name,int size)1513ff48bf5SDavid du Colombier text_font(TW *tw, const char *name, int size)
1523ff48bf5SDavid du Colombier {
1533ff48bf5SDavid du Colombier     /* make a new font */
1543ff48bf5SDavid du Colombier     LOGFONT lf;
1553ff48bf5SDavid du Colombier     TEXTMETRIC tm;
1563ff48bf5SDavid du Colombier     LPSTR p;
1573ff48bf5SDavid du Colombier     HDC hdc;
1583ff48bf5SDavid du Colombier 
1593ff48bf5SDavid du Colombier     /* reject inappropriate arguments */
1603ff48bf5SDavid du Colombier     if (name == NULL)
1613ff48bf5SDavid du Colombier 	return;
1623ff48bf5SDavid du Colombier     if (size < 4)
1633ff48bf5SDavid du Colombier 	return;
1643ff48bf5SDavid du Colombier 
1653ff48bf5SDavid du Colombier     /* set new name and size */
1663ff48bf5SDavid du Colombier     if (tw->fontname)
1673ff48bf5SDavid du Colombier 	free(tw->fontname);
1683ff48bf5SDavid du Colombier     tw->fontname = (char *)malloc(strlen(name)+1);
1693ff48bf5SDavid du Colombier     if (tw->fontname == NULL)
1703ff48bf5SDavid du Colombier 	return;
1713ff48bf5SDavid du Colombier     strcpy(tw->fontname, name);
1723ff48bf5SDavid du Colombier     tw->fontsize = size;
1733ff48bf5SDavid du Colombier 
1743ff48bf5SDavid du Colombier     /* if window not open, hwnd == 0 == HWND_DESKTOP */
1753ff48bf5SDavid du Colombier     hdc = GetDC(tw->hwnd);
1763ff48bf5SDavid du Colombier     memset(&lf, 0, sizeof(LOGFONT));
1773ff48bf5SDavid du Colombier     strncpy(lf.lfFaceName,tw->fontname,LF_FACESIZE);
1783ff48bf5SDavid du Colombier     lf.lfHeight = -MulDiv(tw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
1793ff48bf5SDavid du Colombier     lf.lfPitchAndFamily = FIXED_PITCH;
1803ff48bf5SDavid du Colombier     lf.lfCharSet = DEFAULT_CHARSET;
1813ff48bf5SDavid du Colombier     if ( (p = strstr(tw->fontname," Italic")) != (LPSTR)NULL ) {
1823ff48bf5SDavid du Colombier 	lf.lfFaceName[ (unsigned int)(p-tw->fontname) ] = '\0';
1833ff48bf5SDavid du Colombier 	lf.lfItalic = TRUE;
1843ff48bf5SDavid du Colombier     }
1853ff48bf5SDavid du Colombier     if ( (p = strstr(tw->fontname," Bold")) != (LPSTR)NULL ) {
1863ff48bf5SDavid du Colombier 	lf.lfFaceName[ (unsigned int)(p-tw->fontname) ] = '\0';
1873ff48bf5SDavid du Colombier 	lf.lfWeight = FW_BOLD;
1883ff48bf5SDavid du Colombier     }
1893ff48bf5SDavid du Colombier     if (tw->hfont)
1903ff48bf5SDavid du Colombier 	DeleteFont(tw->hfont);
1913ff48bf5SDavid du Colombier 
1923ff48bf5SDavid du Colombier     tw->hfont = CreateFontIndirect((LOGFONT FAR *)&lf);
1933ff48bf5SDavid du Colombier 
1943ff48bf5SDavid du Colombier     /* get text size */
1953ff48bf5SDavid du Colombier     SelectFont(hdc, tw->hfont);
1963ff48bf5SDavid du Colombier     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
1973ff48bf5SDavid du Colombier     tw->CharSize.y = tm.tmHeight;
1983ff48bf5SDavid du Colombier     tw->CharSize.x = tm.tmAveCharWidth;
1993ff48bf5SDavid du Colombier     tw->CharAscent = tm.tmAscent;
2003ff48bf5SDavid du Colombier     if (tw->bFocus)
2013ff48bf5SDavid du Colombier 	CreateCaret(tw->hwnd, 0, tw->CharSize.x, 2+tw->CaretHeight);
2023ff48bf5SDavid du Colombier     ReleaseDC(tw->hwnd, hdc);
2033ff48bf5SDavid du Colombier 
2043ff48bf5SDavid du Colombier     /* redraw window if necessary */
2053ff48bf5SDavid du Colombier     if (tw->hwnd != HWND_DESKTOP) {
2063ff48bf5SDavid du Colombier 	/* INCOMPLETE */
2073ff48bf5SDavid du Colombier     }
2083ff48bf5SDavid du Colombier }
2093ff48bf5SDavid du Colombier 
2103ff48bf5SDavid du Colombier 
2113ff48bf5SDavid du Colombier 
2123ff48bf5SDavid du Colombier /* Set drag strings */
2133ff48bf5SDavid du Colombier void
text_drag(TW * tw,const char * pre,const char * post)2143ff48bf5SDavid du Colombier text_drag(TW *tw, const char *pre, const char *post)
2153ff48bf5SDavid du Colombier {
2163ff48bf5SDavid du Colombier     /* remove old strings */
2173ff48bf5SDavid du Colombier     if (tw->DragPre)
2183ff48bf5SDavid du Colombier 	free((char *)tw->DragPre);
2193ff48bf5SDavid du Colombier     tw->DragPre = NULL;
2203ff48bf5SDavid du Colombier     if (tw->DragPost)
2213ff48bf5SDavid du Colombier 	free((char *)tw->DragPost);
2223ff48bf5SDavid du Colombier     tw->DragPost = NULL;
2233ff48bf5SDavid du Colombier 
2243ff48bf5SDavid du Colombier     /* add new strings */
2253ff48bf5SDavid du Colombier     tw->DragPre = malloc(strlen(pre)+1);
2263ff48bf5SDavid du Colombier     if (tw->DragPre)
2273ff48bf5SDavid du Colombier 	strcpy(tw->DragPre, pre);
2283ff48bf5SDavid du Colombier     tw->DragPost = malloc(strlen(post)+1);
2293ff48bf5SDavid du Colombier     if (tw->DragPost)
2303ff48bf5SDavid du Colombier 	strcpy(tw->DragPost, post);
2313ff48bf5SDavid du Colombier }
2323ff48bf5SDavid du Colombier 
2333ff48bf5SDavid du Colombier /* Set the window position and size */
2343ff48bf5SDavid du Colombier void
text_setpos(TW * tw,int x,int y,int cx,int cy)2353ff48bf5SDavid du Colombier text_setpos(TW *tw, int x, int y, int cx, int cy)
2363ff48bf5SDavid du Colombier {
2373ff48bf5SDavid du Colombier     tw->x = x;
2383ff48bf5SDavid du Colombier     tw->y = y;
2393ff48bf5SDavid du Colombier     tw->cx = cx;
2403ff48bf5SDavid du Colombier     tw->cy = cy;
2413ff48bf5SDavid du Colombier }
2423ff48bf5SDavid du Colombier 
2433ff48bf5SDavid du Colombier /* Get the window position and size */
text_getpos(TW * tw,int * px,int * py,int * pcx,int * pcy)2443ff48bf5SDavid du Colombier int text_getpos(TW *tw, int *px, int *py, int *pcx, int *pcy)
2453ff48bf5SDavid du Colombier {
2463ff48bf5SDavid du Colombier     *px = tw->x;
2473ff48bf5SDavid du Colombier     *py = tw->y;
2483ff48bf5SDavid du Colombier     *pcx = tw->cx;
2493ff48bf5SDavid du Colombier     *pcy = tw->cy;
2503ff48bf5SDavid du Colombier     return 0;
2513ff48bf5SDavid du Colombier }
2523ff48bf5SDavid du Colombier 
2533ff48bf5SDavid du Colombier /* Allocate new text window */
2543ff48bf5SDavid du Colombier TW *
text_new(void)2553ff48bf5SDavid du Colombier text_new(void)
2563ff48bf5SDavid du Colombier {
2573ff48bf5SDavid du Colombier     TW *tw;
2583ff48bf5SDavid du Colombier     tw = (TW *)malloc(sizeof(TW));
2593ff48bf5SDavid du Colombier     if (tw == NULL)
2603ff48bf5SDavid du Colombier 	return NULL;
2613ff48bf5SDavid du Colombier     /* make sure everything is null */
2623ff48bf5SDavid du Colombier     memset(tw, 0, sizeof(TW));
2633ff48bf5SDavid du Colombier 
2643ff48bf5SDavid du Colombier     /* set some defaults */
2653ff48bf5SDavid du Colombier     text_font(tw, "Courier New", 10);
2663ff48bf5SDavid du Colombier     text_size(tw, 80, 24);
2673ff48bf5SDavid du Colombier     tw->KeyBufSize = 2048;
2683ff48bf5SDavid du Colombier     tw->CursorFlag = 1;	/* scroll to cursor after \n or \r */
2693ff48bf5SDavid du Colombier     tw->hwnd = HWND_DESKTOP;
2703ff48bf5SDavid du Colombier 
2713ff48bf5SDavid du Colombier     tw->line_end = 0;
2723ff48bf5SDavid du Colombier     tw->line_start = 0;
2733ff48bf5SDavid du Colombier     tw->line_complete = FALSE;
2743ff48bf5SDavid du Colombier     tw->line_eof = FALSE;
2753ff48bf5SDavid du Colombier 
2763ff48bf5SDavid du Colombier     tw->x = CW_USEDEFAULT;
2773ff48bf5SDavid du Colombier     tw->y = CW_USEDEFAULT;
2783ff48bf5SDavid du Colombier     tw->cx = CW_USEDEFAULT;
2793ff48bf5SDavid du Colombier     tw->cy = CW_USEDEFAULT;
2803ff48bf5SDavid du Colombier     return tw;
2813ff48bf5SDavid du Colombier }
2823ff48bf5SDavid du Colombier 
2833ff48bf5SDavid du Colombier /* Destroy window and deallocate text window structure */
2843ff48bf5SDavid du Colombier void
text_destroy(TW * tw)2853ff48bf5SDavid du Colombier text_destroy(TW *tw)
2863ff48bf5SDavid du Colombier {
2873ff48bf5SDavid du Colombier     if (tw->hwnd)
2883ff48bf5SDavid du Colombier         DestroyWindow(tw->hwnd);
2893ff48bf5SDavid du Colombier     tw->hwnd = HWND_DESKTOP;
2903ff48bf5SDavid du Colombier 
2913ff48bf5SDavid du Colombier     if (tw->hfont)
2923ff48bf5SDavid du Colombier 	DeleteFont(tw->hfont);
2933ff48bf5SDavid du Colombier     tw->hfont = NULL;
2943ff48bf5SDavid du Colombier 
2953ff48bf5SDavid du Colombier     if (tw->KeyBuf)
2963ff48bf5SDavid du Colombier 	free((char *)tw->KeyBuf);
2973ff48bf5SDavid du Colombier     tw->KeyBuf = NULL;
2983ff48bf5SDavid du Colombier 
2993ff48bf5SDavid du Colombier     if (tw->ScreenBuffer)
3003ff48bf5SDavid du Colombier 	free((char *)tw->ScreenBuffer);
3013ff48bf5SDavid du Colombier     tw->ScreenBuffer = NULL;
3023ff48bf5SDavid du Colombier 
3033ff48bf5SDavid du Colombier     if (tw->DragPre)
3043ff48bf5SDavid du Colombier 	free((char *)tw->DragPre);
3053ff48bf5SDavid du Colombier     tw->DragPre = NULL;
3063ff48bf5SDavid du Colombier 
3073ff48bf5SDavid du Colombier     if (tw->DragPost)
3083ff48bf5SDavid du Colombier 	free((char *)tw->DragPost);
3093ff48bf5SDavid du Colombier     tw->DragPost = NULL;
3103ff48bf5SDavid du Colombier 
3113ff48bf5SDavid du Colombier     if (tw->fontname)
3123ff48bf5SDavid du Colombier 	free((char *)tw->fontname);
3133ff48bf5SDavid du Colombier     tw->fontname = NULL;
3143ff48bf5SDavid du Colombier }
3153ff48bf5SDavid du Colombier 
3163ff48bf5SDavid du Colombier 
3173ff48bf5SDavid du Colombier /* register the window class */
3183ff48bf5SDavid du Colombier int
text_register_class(TW * tw,HICON hicon)3193ff48bf5SDavid du Colombier text_register_class(TW *tw, HICON hicon)
3203ff48bf5SDavid du Colombier {
3213ff48bf5SDavid du Colombier     WNDCLASS wndclass;
3223ff48bf5SDavid du Colombier     HINSTANCE hInstance = GetModuleHandle(NULL);
3233ff48bf5SDavid du Colombier     tw->hIcon = hicon;
3243ff48bf5SDavid du Colombier 
3253ff48bf5SDavid du Colombier     /* register window class */
3263ff48bf5SDavid du Colombier     wndclass.style = CS_HREDRAW | CS_VREDRAW;
3273ff48bf5SDavid du Colombier     wndclass.lpfnWndProc = WndTextProc;
3283ff48bf5SDavid du Colombier     wndclass.cbClsExtra = 0;
3293ff48bf5SDavid du Colombier     wndclass.cbWndExtra = sizeof(void *);
3303ff48bf5SDavid du Colombier     wndclass.hInstance = hInstance;
3313ff48bf5SDavid du Colombier     wndclass.hIcon = tw->hIcon ? tw->hIcon : LoadIcon(NULL, IDI_APPLICATION);
3323ff48bf5SDavid du Colombier     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
3333ff48bf5SDavid du Colombier     wndclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
3343ff48bf5SDavid du Colombier     wndclass.lpszMenuName = NULL;
3353ff48bf5SDavid du Colombier     wndclass.lpszClassName = TextWinClassName;
3363ff48bf5SDavid du Colombier     return RegisterClass(&wndclass);
3373ff48bf5SDavid du Colombier }
3383ff48bf5SDavid du Colombier 
3393ff48bf5SDavid du Colombier /* Show the window */
3403ff48bf5SDavid du Colombier int
text_create(TW * tw,const char * app_name,int show_cmd)3413ff48bf5SDavid du Colombier text_create(TW *tw, const char *app_name, int show_cmd)
3423ff48bf5SDavid du Colombier {
3433ff48bf5SDavid du Colombier     HMENU sysmenu;
3443ff48bf5SDavid du Colombier     HINSTANCE hInstance = GetModuleHandle(NULL);
3453ff48bf5SDavid du Colombier 
3463ff48bf5SDavid du Colombier     tw->Title = app_name;
3473ff48bf5SDavid du Colombier     tw->nCmdShow = show_cmd;
3483ff48bf5SDavid du Colombier     tw->quitnow = FALSE;
3493ff48bf5SDavid du Colombier 
3503ff48bf5SDavid du Colombier     /* make sure we have some sensible defaults */
3513ff48bf5SDavid du Colombier     if (tw->KeyBufSize < 256)
3523ff48bf5SDavid du Colombier 	tw->KeyBufSize = 256;
3533ff48bf5SDavid du Colombier 
3543ff48bf5SDavid du Colombier     tw->CursorPos.x = tw->CursorPos.y = 0;
3553ff48bf5SDavid du Colombier     tw->bFocus = FALSE;
3563ff48bf5SDavid du Colombier     tw->bGetCh = FALSE;
3573ff48bf5SDavid du Colombier     tw->CaretHeight = 0;
3583ff48bf5SDavid du Colombier 
3593ff48bf5SDavid du Colombier 
3603ff48bf5SDavid du Colombier     /* allocate buffers */
3613ff48bf5SDavid du Colombier     tw->KeyBufIn = tw->KeyBufOut = tw->KeyBuf = malloc(tw->KeyBufSize);
3623ff48bf5SDavid du Colombier     if (tw->KeyBuf == NULL) {
3633ff48bf5SDavid du Colombier 	text_error("Out of memory");
3643ff48bf5SDavid du Colombier 	return 1;
3653ff48bf5SDavid du Colombier     }
3663ff48bf5SDavid du Colombier     tw->ScreenBuffer = malloc(tw->ScreenSize.x * tw->ScreenSize.y);
3673ff48bf5SDavid du Colombier     if (tw->ScreenBuffer == NULL) {
3683ff48bf5SDavid du Colombier 	text_error("Out of memory");
3693ff48bf5SDavid du Colombier 	return 1;
3703ff48bf5SDavid du Colombier     }
3713ff48bf5SDavid du Colombier     memset(tw->ScreenBuffer, ' ', tw->ScreenSize.x * tw->ScreenSize.y);
3723ff48bf5SDavid du Colombier 
3733ff48bf5SDavid du Colombier     tw->hwnd = CreateWindow(TextWinClassName, tw->Title,
3743ff48bf5SDavid du Colombier 		  WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
3753ff48bf5SDavid du Colombier 		  tw->x, tw->y, tw->cx, tw->cy,
3763ff48bf5SDavid du Colombier 		  NULL, NULL, hInstance, tw);
3773ff48bf5SDavid du Colombier 
3783ff48bf5SDavid du Colombier     if (tw->hwnd == NULL) {
3793ff48bf5SDavid du Colombier 	MessageBox((HWND)NULL,"Couldn't open text window",(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
3803ff48bf5SDavid du Colombier 	return 1;
3813ff48bf5SDavid du Colombier     }
3823ff48bf5SDavid du Colombier 
3833ff48bf5SDavid du Colombier     ShowWindow(tw->hwnd, tw->nCmdShow);
3843ff48bf5SDavid du Colombier     sysmenu = GetSystemMenu(tw->hwnd,0);	/* get the sysmenu */
3853ff48bf5SDavid du Colombier     AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
3863ff48bf5SDavid du Colombier     AppendMenu(sysmenu, MF_STRING, M_COPY_CLIP, "Copy to Clip&board");
3873ff48bf5SDavid du Colombier     AppendMenu(sysmenu, MF_STRING, M_PASTE_CLIP, "&Paste");
3883ff48bf5SDavid du Colombier 
3893ff48bf5SDavid du Colombier     return 0;
3903ff48bf5SDavid du Colombier }
3913ff48bf5SDavid du Colombier 
3923ff48bf5SDavid du Colombier 
3933ff48bf5SDavid du Colombier int
text_putch(TW * tw,int ch)3943ff48bf5SDavid du Colombier text_putch(TW *tw, int ch)
3953ff48bf5SDavid du Colombier {
3963ff48bf5SDavid du Colombier int pos;
3973ff48bf5SDavid du Colombier int n;
3983ff48bf5SDavid du Colombier     if (tw->quitnow)
3993ff48bf5SDavid du Colombier 	return ch;	/* don't write error message as we shut down */
4003ff48bf5SDavid du Colombier     switch(ch) {
4013ff48bf5SDavid du Colombier 	case '\r':
4023ff48bf5SDavid du Colombier 		tw->CursorPos.x = 0;
4033ff48bf5SDavid du Colombier 		if (tw->CursorFlag)
4043ff48bf5SDavid du Colombier 		    text_to_cursor(tw);
4053ff48bf5SDavid du Colombier 		break;
4063ff48bf5SDavid du Colombier 	case '\n':
4073ff48bf5SDavid du Colombier 		text_new_line(tw);
4083ff48bf5SDavid du Colombier 		break;
4093ff48bf5SDavid du Colombier 	case 7:
4103ff48bf5SDavid du Colombier 		MessageBeep(-1);
4113ff48bf5SDavid du Colombier 		if (tw->CursorFlag)
4123ff48bf5SDavid du Colombier 		    text_to_cursor(tw);
4133ff48bf5SDavid du Colombier 		break;
4143ff48bf5SDavid du Colombier 	case '\t':
4153ff48bf5SDavid du Colombier 		{
4163ff48bf5SDavid du Colombier 		    for (n = 8 - (tw->CursorPos.x % 8); n>0; n-- )
4173ff48bf5SDavid du Colombier 			    text_putch(tw, ' ');
4183ff48bf5SDavid du Colombier 		}
4193ff48bf5SDavid du Colombier 		break;
4203ff48bf5SDavid du Colombier 	case 0x08:
4213ff48bf5SDavid du Colombier 	case 0x7f:
4223ff48bf5SDavid du Colombier 		tw->CursorPos.x--;
4233ff48bf5SDavid du Colombier 		if (tw->CursorPos.x < 0) {
4243ff48bf5SDavid du Colombier 		    tw->CursorPos.x = tw->ScreenSize.x - 1;
4253ff48bf5SDavid du Colombier 		    tw->CursorPos.y--;
4263ff48bf5SDavid du Colombier 		}
4273ff48bf5SDavid du Colombier 		if (tw->CursorPos.y < 0)
4283ff48bf5SDavid du Colombier 		    tw->CursorPos.y = 0;
4293ff48bf5SDavid du Colombier 		break;
4303ff48bf5SDavid du Colombier 	default:
4313ff48bf5SDavid du Colombier 		pos = tw->CursorPos.y*tw->ScreenSize.x + tw->CursorPos.x;
4323ff48bf5SDavid du Colombier 		tw->ScreenBuffer[pos] = ch;
4333ff48bf5SDavid du Colombier 		text_update_text(tw, 1);
4343ff48bf5SDavid du Colombier     }
4353ff48bf5SDavid du Colombier     return ch;
4363ff48bf5SDavid du Colombier }
4373ff48bf5SDavid du Colombier 
4383ff48bf5SDavid du Colombier void
text_write_buf(TW * tw,const char * str,int cnt)4393ff48bf5SDavid du Colombier text_write_buf(TW *tw, const char *str, int cnt)
4403ff48bf5SDavid du Colombier {
4413ff48bf5SDavid du Colombier BYTE *p;
4423ff48bf5SDavid du Colombier int count, limit;
4433ff48bf5SDavid du Colombier int n;
4443ff48bf5SDavid du Colombier     if (tw->quitnow)
4453ff48bf5SDavid du Colombier 	return;		/* don't write error message as we shut down */
4463ff48bf5SDavid du Colombier     while (cnt>0) {
4473ff48bf5SDavid du Colombier 	p = tw->ScreenBuffer + tw->CursorPos.y*tw->ScreenSize.x + tw->CursorPos.x;
4483ff48bf5SDavid du Colombier 	limit = tw->ScreenSize.x - tw->CursorPos.x;
449*593dc095SDavid du Colombier 	for (count=0; (count < limit) && (cnt>0) &&
450*593dc095SDavid du Colombier 	    (isprint((unsigned char)(*str)) || *str=='\t'); count++) {
4513ff48bf5SDavid du Colombier 	    if (*str=='\t') {
4523ff48bf5SDavid du Colombier 		for (n = 8 - ((tw->CursorPos.x+count) % 8); (count < limit) & (n>0); n--, count++ )
4533ff48bf5SDavid du Colombier 		    *p++ = ' ';
4543ff48bf5SDavid du Colombier 		str++;
4553ff48bf5SDavid du Colombier 		count--;
4563ff48bf5SDavid du Colombier    	    }
4573ff48bf5SDavid du Colombier 	    else {
4583ff48bf5SDavid du Colombier 		*p++ = *str++;
4593ff48bf5SDavid du Colombier 	    }
4603ff48bf5SDavid du Colombier 	    cnt--;
4613ff48bf5SDavid du Colombier 	}
4623ff48bf5SDavid du Colombier 	if (count>0) {
4633ff48bf5SDavid du Colombier 	    text_update_text(tw, count);
4643ff48bf5SDavid du Colombier 	}
4653ff48bf5SDavid du Colombier 	if (cnt > 0) {
4663ff48bf5SDavid du Colombier 	    if (*str=='\n') {
4673ff48bf5SDavid du Colombier 		text_new_line(tw);
4683ff48bf5SDavid du Colombier 		str++;
4693ff48bf5SDavid du Colombier 		cnt--;
4703ff48bf5SDavid du Colombier 	    }
471*593dc095SDavid du Colombier 	    else if (!isprint((unsigned char)(*str)) && *str!='\t') {
4723ff48bf5SDavid du Colombier 		text_putch(tw, *str++);
4733ff48bf5SDavid du Colombier 		cnt--;
4743ff48bf5SDavid du Colombier 	    }
4753ff48bf5SDavid du Colombier 	}
4763ff48bf5SDavid du Colombier     }
4773ff48bf5SDavid du Colombier }
4783ff48bf5SDavid du Colombier 
4793ff48bf5SDavid du Colombier /* Put string to window */
4803ff48bf5SDavid du Colombier void
text_puts(TW * tw,const char * str)4813ff48bf5SDavid du Colombier text_puts(TW *tw, const char *str)
4823ff48bf5SDavid du Colombier {
4833ff48bf5SDavid du Colombier     text_write_buf(tw, str, strlen(str));
4843ff48bf5SDavid du Colombier }
4853ff48bf5SDavid du Colombier 
4863ff48bf5SDavid du Colombier 
4873ff48bf5SDavid du Colombier /* TRUE if key hit, FALSE if no key */
4883ff48bf5SDavid du Colombier int
text_kbhit(TW * tw)4893ff48bf5SDavid du Colombier text_kbhit(TW *tw)
4903ff48bf5SDavid du Colombier {
4913ff48bf5SDavid du Colombier     return (tw->KeyBufIn != tw->KeyBufOut);
4923ff48bf5SDavid du Colombier }
4933ff48bf5SDavid du Colombier 
4943ff48bf5SDavid du Colombier /* get character from keyboard, no echo */
4953ff48bf5SDavid du Colombier /* need to add extended codes */
4963ff48bf5SDavid du Colombier int
text_getch(TW * tw)4973ff48bf5SDavid du Colombier text_getch(TW *tw)
4983ff48bf5SDavid du Colombier {
4993ff48bf5SDavid du Colombier     MSG msg;
5003ff48bf5SDavid du Colombier     int ch;
5013ff48bf5SDavid du Colombier     text_to_cursor(tw);
5023ff48bf5SDavid du Colombier     tw->bGetCh = TRUE;
5033ff48bf5SDavid du Colombier     if (tw->bFocus) {
5043ff48bf5SDavid du Colombier 	SetCaretPos(tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x,
5053ff48bf5SDavid du Colombier 	    tw->CursorPos.y*tw->CharSize.y + tw->CharAscent
5063ff48bf5SDavid du Colombier 	    - tw->CaretHeight - tw->ScrollPos.y);
5073ff48bf5SDavid du Colombier 	ShowCaret(tw->hwnd);
5083ff48bf5SDavid du Colombier     }
5093ff48bf5SDavid du Colombier 
5103ff48bf5SDavid du Colombier     while (PeekMessage(&msg, (HWND)NULL, 0, 0, PM_NOREMOVE)) {
5113ff48bf5SDavid du Colombier 	if (GetMessage(&msg, (HWND)NULL, 0, 0)) {
5123ff48bf5SDavid du Colombier 	    TranslateMessage(&msg);
5133ff48bf5SDavid du Colombier 	    DispatchMessage(&msg);
5143ff48bf5SDavid du Colombier 	}
5153ff48bf5SDavid du Colombier     }
5163ff48bf5SDavid du Colombier     if (tw->quitnow)
5173ff48bf5SDavid du Colombier        return EOF;	/* window closed */
5183ff48bf5SDavid du Colombier 
5193ff48bf5SDavid du Colombier     while (!text_kbhit(tw)) {
5203ff48bf5SDavid du Colombier         if (!tw->quitnow) {
5213ff48bf5SDavid du Colombier 	    if (GetMessage(&msg, (HWND)NULL, 0, 0)) {
5223ff48bf5SDavid du Colombier 		TranslateMessage(&msg);
5233ff48bf5SDavid du Colombier 		DispatchMessage(&msg);
5243ff48bf5SDavid du Colombier 	    }
5253ff48bf5SDavid du Colombier 	}
5263ff48bf5SDavid du Colombier 	else
5273ff48bf5SDavid du Colombier 	   return EOF;	/* window closed */
5283ff48bf5SDavid du Colombier     }
5293ff48bf5SDavid du Colombier 
5303ff48bf5SDavid du Colombier     ch = *tw->KeyBufOut++;
5313ff48bf5SDavid du Colombier     if (ch=='\r')
5323ff48bf5SDavid du Colombier 	ch = '\n';
5333ff48bf5SDavid du Colombier     if (tw->KeyBufOut - tw->KeyBuf >= tw->KeyBufSize)
5343ff48bf5SDavid du Colombier 	tw->KeyBufOut = tw->KeyBuf;		/* wrap around */
5353ff48bf5SDavid du Colombier     if (tw->bFocus)
5363ff48bf5SDavid du Colombier 	HideCaret(tw->hwnd);
5373ff48bf5SDavid du Colombier     tw->bGetCh = FALSE;
5383ff48bf5SDavid du Colombier     return ch;
5393ff48bf5SDavid du Colombier }
5403ff48bf5SDavid du Colombier 
5413ff48bf5SDavid du Colombier /* Read line from keyboard using buffered input
5423ff48bf5SDavid du Colombier  * Return at most 'len' characters
5433ff48bf5SDavid du Colombier  * Does NOT add null terminating character
5443ff48bf5SDavid du Colombier  * This is NOT the same as fgets()
5453ff48bf5SDavid du Colombier  * Do not mix this with calls to text_getch()
5463ff48bf5SDavid du Colombier  */
5473ff48bf5SDavid du Colombier int
text_read_line(TW * tw,char * line,int len)5483ff48bf5SDavid du Colombier text_read_line(TW *tw, char *line, int len)
5493ff48bf5SDavid du Colombier {
5503ff48bf5SDavid du Colombier int ch;
5513ff48bf5SDavid du Colombier     if (tw->line_eof)
5523ff48bf5SDavid du Colombier 	return 0;
5533ff48bf5SDavid du Colombier 
5543ff48bf5SDavid du Colombier     while (!tw->line_complete) {
5553ff48bf5SDavid du Colombier 	/* we have not yet collected a full line */
5563ff48bf5SDavid du Colombier         ch = text_getch(tw);
5573ff48bf5SDavid du Colombier 	switch(ch) {
5583ff48bf5SDavid du Colombier 	    case EOF:
5593ff48bf5SDavid du Colombier 	    case 26:	/* ^Z == EOF */
5603ff48bf5SDavid du Colombier 		tw->line_eof = TRUE;
5613ff48bf5SDavid du Colombier 		tw->line_complete = TRUE;
5623ff48bf5SDavid du Colombier 		break;
5633ff48bf5SDavid du Colombier 	    case '\b':	/* ^H */
5643ff48bf5SDavid du Colombier 	    case 0x7f:  /* DEL */
5653ff48bf5SDavid du Colombier 		if (tw->line_end) {
5663ff48bf5SDavid du Colombier 		    text_putch(tw, '\b');
5673ff48bf5SDavid du Colombier 		    text_putch(tw, ' ');
5683ff48bf5SDavid du Colombier 		    text_putch(tw, '\b');
5693ff48bf5SDavid du Colombier 		    --(tw->line_end);
5703ff48bf5SDavid du Colombier 		}
5713ff48bf5SDavid du Colombier 		break;
5723ff48bf5SDavid du Colombier 	    case 21:	/* ^U */
5733ff48bf5SDavid du Colombier 		while (tw->line_end) {
5743ff48bf5SDavid du Colombier 		    text_putch(tw, '\b');
5753ff48bf5SDavid du Colombier 		    text_putch(tw, ' ');
5763ff48bf5SDavid du Colombier 		    text_putch(tw, '\b');
5773ff48bf5SDavid du Colombier 		    --(tw->line_end);
5783ff48bf5SDavid du Colombier 		}
5793ff48bf5SDavid du Colombier 		break;
5803ff48bf5SDavid du Colombier 	    case '\r':
5813ff48bf5SDavid du Colombier 	    case '\n':
5823ff48bf5SDavid du Colombier 		tw->line_complete = TRUE;
5833ff48bf5SDavid du Colombier 		/* fall through */
5843ff48bf5SDavid du Colombier 	    default:
5853ff48bf5SDavid du Colombier 		tw->line_buf[tw->line_end++] = ch;
5863ff48bf5SDavid du Colombier 		text_putch(tw, ch);
5873ff48bf5SDavid du Colombier 		break;
5883ff48bf5SDavid du Colombier 	}
5893ff48bf5SDavid du Colombier 	if (tw->line_end >= sizeof(tw->line_buf))
5903ff48bf5SDavid du Colombier 	    tw->line_complete = TRUE;
5913ff48bf5SDavid du Colombier     }
5923ff48bf5SDavid du Colombier 
5933ff48bf5SDavid du Colombier     if (tw->quitnow)
5943ff48bf5SDavid du Colombier 	return -1;
5953ff48bf5SDavid du Colombier 
5963ff48bf5SDavid du Colombier     if (tw->line_complete) {
5973ff48bf5SDavid du Colombier 	/* We either filled the buffer or got CR, LF or EOF */
5983ff48bf5SDavid du Colombier 	int count = min(len, tw->line_end - tw->line_start);
5993ff48bf5SDavid du Colombier 	memcpy(line, tw->line_buf + tw->line_start, count);
6003ff48bf5SDavid du Colombier 	tw->line_start += count;
6013ff48bf5SDavid du Colombier 	if (tw->line_start == tw->line_end) {
6023ff48bf5SDavid du Colombier 	    tw->line_start = tw->line_end = 0;
6033ff48bf5SDavid du Colombier 	    tw->line_complete = FALSE;
6043ff48bf5SDavid du Colombier 	}
6053ff48bf5SDavid du Colombier 	return count;
6063ff48bf5SDavid du Colombier     }
6073ff48bf5SDavid du Colombier 
6083ff48bf5SDavid du Colombier     return 0;
6093ff48bf5SDavid du Colombier }
6103ff48bf5SDavid du Colombier 
6113ff48bf5SDavid du Colombier /* Read a string from the keyboard, of up to len characters */
6123ff48bf5SDavid du Colombier /* (not including trailing NULL) */
6133ff48bf5SDavid du Colombier int
text_gets(TW * tw,char * line,int len)6143ff48bf5SDavid du Colombier text_gets(TW *tw, char *line, int len)
6153ff48bf5SDavid du Colombier {
6163ff48bf5SDavid du Colombier LPSTR dest = line;
6173ff48bf5SDavid du Colombier LPSTR limit = dest + len;  /* don't leave room for '\0' */
6183ff48bf5SDavid du Colombier int ch;
6193ff48bf5SDavid du Colombier     do {
6203ff48bf5SDavid du Colombier 	if (dest >= limit)
6213ff48bf5SDavid du Colombier 	    break;
6223ff48bf5SDavid du Colombier 	ch = text_getch(tw);
6233ff48bf5SDavid du Colombier 	switch(ch) {
6243ff48bf5SDavid du Colombier 	    case 26:	/* ^Z == EOF */
6253ff48bf5SDavid du Colombier 		return 0;
6263ff48bf5SDavid du Colombier 	    case '\b':	/* ^H */
6273ff48bf5SDavid du Colombier 	    case 0x7f:  /* DEL */
6283ff48bf5SDavid du Colombier 		if (dest > line) {
6293ff48bf5SDavid du Colombier 		    text_putch(tw, '\b');
6303ff48bf5SDavid du Colombier 		    text_putch(tw, ' ');
6313ff48bf5SDavid du Colombier 		    text_putch(tw, '\b');
6323ff48bf5SDavid du Colombier 		    --dest;
6333ff48bf5SDavid du Colombier 		}
6343ff48bf5SDavid du Colombier 		break;
6353ff48bf5SDavid du Colombier 	    case 21:	/* ^U */
6363ff48bf5SDavid du Colombier 		while (dest > line) {
6373ff48bf5SDavid du Colombier 		    text_putch(tw, '\b');
6383ff48bf5SDavid du Colombier 		    text_putch(tw, ' ');
6393ff48bf5SDavid du Colombier 		    text_putch(tw, '\b');
6403ff48bf5SDavid du Colombier 		    --dest;
6413ff48bf5SDavid du Colombier 		}
6423ff48bf5SDavid du Colombier 		break;
6433ff48bf5SDavid du Colombier 	    default:
6443ff48bf5SDavid du Colombier 		*dest++ = ch;
6453ff48bf5SDavid du Colombier 		text_putch(tw, ch);
6463ff48bf5SDavid du Colombier 		break;
6473ff48bf5SDavid du Colombier 	}
6483ff48bf5SDavid du Colombier     } while (ch != '\n');
6493ff48bf5SDavid du Colombier 
6503ff48bf5SDavid du Colombier     *dest = '\0';
6513ff48bf5SDavid du Colombier     return (dest-line);
6523ff48bf5SDavid du Colombier }
6533ff48bf5SDavid du Colombier 
6543ff48bf5SDavid du Colombier 
6553ff48bf5SDavid du Colombier /* Windows 3.1 drag-drop feature */
6563ff48bf5SDavid du Colombier void
text_drag_drop(TW * tw,HDROP hdrop)6573ff48bf5SDavid du Colombier text_drag_drop(TW *tw, HDROP hdrop)
6583ff48bf5SDavid du Colombier {
6593ff48bf5SDavid du Colombier     char szFile[256];
6603ff48bf5SDavid du Colombier     int i, cFiles;
6613ff48bf5SDavid du Colombier     const char *p;
6623ff48bf5SDavid du Colombier     if ( (tw->DragPre==NULL) || (tw->DragPost==NULL) )
6633ff48bf5SDavid du Colombier 	    return;
6643ff48bf5SDavid du Colombier 
6653ff48bf5SDavid du Colombier     cFiles = DragQueryFile(hdrop, (UINT)(-1), (LPSTR)NULL, 0);
6663ff48bf5SDavid du Colombier     for (i=0; i<cFiles; i++) {
6673ff48bf5SDavid du Colombier 	DragQueryFile(hdrop, i, szFile, 80);
6683ff48bf5SDavid du Colombier 	for (p=tw->DragPre; *p; p++)
6693ff48bf5SDavid du Colombier 		SendMessage(tw->hwnd,WM_CHAR,*p,1L);
6703ff48bf5SDavid du Colombier 	for (p=szFile; *p; p++) {
6713ff48bf5SDavid du Colombier 	    if (*p == '\\')
6723ff48bf5SDavid du Colombier 		SendMessage(tw->hwnd,WM_CHAR,'/',1L);
6733ff48bf5SDavid du Colombier 	    else
6743ff48bf5SDavid du Colombier 		SendMessage(tw->hwnd,WM_CHAR,*p,1L);
6753ff48bf5SDavid du Colombier 	}
6763ff48bf5SDavid du Colombier 	for (p=tw->DragPost; *p; p++)
6773ff48bf5SDavid du Colombier 		SendMessage(tw->hwnd,WM_CHAR,*p,1L);
6783ff48bf5SDavid du Colombier     }
6793ff48bf5SDavid du Colombier     DragFinish(hdrop);
6803ff48bf5SDavid du Colombier }
6813ff48bf5SDavid du Colombier 
6823ff48bf5SDavid du Colombier 
6833ff48bf5SDavid du Colombier void
text_copy_to_clipboard(TW * tw)6843ff48bf5SDavid du Colombier text_copy_to_clipboard(TW *tw)
6853ff48bf5SDavid du Colombier {
6863ff48bf5SDavid du Colombier     int size, count;
6873ff48bf5SDavid du Colombier     HGLOBAL hGMem;
6883ff48bf5SDavid du Colombier     LPSTR cbuf, cp;
6893ff48bf5SDavid du Colombier     TEXTMETRIC tm;
6903ff48bf5SDavid du Colombier     UINT type;
6913ff48bf5SDavid du Colombier     HDC hdc;
6923ff48bf5SDavid du Colombier     int i;
6933ff48bf5SDavid du Colombier 
6943ff48bf5SDavid du Colombier     size = tw->ScreenSize.y * (tw->ScreenSize.x + 2) + 1;
6953ff48bf5SDavid du Colombier     hGMem = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)size);
6963ff48bf5SDavid du Colombier     cbuf = cp = (LPSTR)GlobalLock(hGMem);
6973ff48bf5SDavid du Colombier     if (cp == (LPSTR)NULL)
6983ff48bf5SDavid du Colombier 	return;
6993ff48bf5SDavid du Colombier 
7003ff48bf5SDavid du Colombier     for (i=0; i<tw->ScreenSize.y; i++) {
7013ff48bf5SDavid du Colombier 	count = tw->ScreenSize.x;
7023ff48bf5SDavid du Colombier 	memcpy(cp, tw->ScreenBuffer + tw->ScreenSize.x*i, count);
7033ff48bf5SDavid du Colombier 	/* remove trailing spaces */
7043ff48bf5SDavid du Colombier 	for (count=count-1; count>=0; count--) {
7053ff48bf5SDavid du Colombier 		if (cp[count]!=' ')
7063ff48bf5SDavid du Colombier 			break;
7073ff48bf5SDavid du Colombier 		cp[count] = '\0';
7083ff48bf5SDavid du Colombier 	}
7093ff48bf5SDavid du Colombier 	cp[++count] = '\r';
7103ff48bf5SDavid du Colombier 	cp[++count] = '\n';
7113ff48bf5SDavid du Colombier 	cp[++count] = '\0';
7123ff48bf5SDavid du Colombier 	cp += count;
7133ff48bf5SDavid du Colombier     }
7143ff48bf5SDavid du Colombier     size = strlen(cbuf) + 1;
7153ff48bf5SDavid du Colombier     GlobalUnlock(hGMem);
7163ff48bf5SDavid du Colombier     hGMem = GlobalReAlloc(hGMem, (DWORD)size, GHND | GMEM_SHARE);
7173ff48bf5SDavid du Colombier     /* find out what type to put into clipboard */
7183ff48bf5SDavid du Colombier     hdc = GetDC(tw->hwnd);
7193ff48bf5SDavid du Colombier     SelectFont(hdc, tw->hfont);
7203ff48bf5SDavid du Colombier     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
7213ff48bf5SDavid du Colombier     if (tm.tmCharSet == OEM_CHARSET)
7223ff48bf5SDavid du Colombier 	type = CF_OEMTEXT;
7233ff48bf5SDavid du Colombier     else
7243ff48bf5SDavid du Colombier 	type = CF_TEXT;
7253ff48bf5SDavid du Colombier     ReleaseDC(tw->hwnd, hdc);
7263ff48bf5SDavid du Colombier     /* give buffer to clipboard */
7273ff48bf5SDavid du Colombier     OpenClipboard(tw->hwnd);
7283ff48bf5SDavid du Colombier     EmptyClipboard();
7293ff48bf5SDavid du Colombier     SetClipboardData(type, hGMem);
7303ff48bf5SDavid du Colombier     CloseClipboard();
7313ff48bf5SDavid du Colombier }
7323ff48bf5SDavid du Colombier 
7333ff48bf5SDavid du Colombier void
text_paste_from_clipboard(TW * tw)7343ff48bf5SDavid du Colombier text_paste_from_clipboard(TW *tw)
7353ff48bf5SDavid du Colombier {
7363ff48bf5SDavid du Colombier     HGLOBAL hClipMemory;
7373ff48bf5SDavid du Colombier     BYTE *p;
7383ff48bf5SDavid du Colombier     long count;
7393ff48bf5SDavid du Colombier     OpenClipboard(tw->hwnd);
7403ff48bf5SDavid du Colombier     if (IsClipboardFormatAvailable(CF_TEXT)) {
7413ff48bf5SDavid du Colombier 	hClipMemory = GetClipboardData(CF_TEXT);
7423ff48bf5SDavid du Colombier 	p = GlobalLock(hClipMemory);
7433ff48bf5SDavid du Colombier 	while (*p) {
7443ff48bf5SDavid du Colombier 	    /* transfer to keyboard circular buffer */
7453ff48bf5SDavid du Colombier 	    count = tw->KeyBufIn - tw->KeyBufOut;
7463ff48bf5SDavid du Colombier 	    if (count < 0)
7473ff48bf5SDavid du Colombier 		count += tw->KeyBufSize;
7483ff48bf5SDavid du Colombier 	    if (count < tw->KeyBufSize-1) {
7493ff48bf5SDavid du Colombier 		*tw->KeyBufIn++ = *p;
7503ff48bf5SDavid du Colombier 		if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
7513ff48bf5SDavid du Colombier 		    tw->KeyBufIn = tw->KeyBuf;	/* wrap around */
7523ff48bf5SDavid du Colombier 	    }
7533ff48bf5SDavid du Colombier 	    p++;
7543ff48bf5SDavid du Colombier 	}
7553ff48bf5SDavid du Colombier 	GlobalUnlock(hClipMemory);
7563ff48bf5SDavid du Colombier     }
7573ff48bf5SDavid du Colombier     CloseClipboard();
7583ff48bf5SDavid du Colombier }
7593ff48bf5SDavid du Colombier 
7603ff48bf5SDavid du Colombier /* text window */
7613ff48bf5SDavid du Colombier LRESULT CALLBACK
WndTextProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)7623ff48bf5SDavid du Colombier WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7633ff48bf5SDavid du Colombier {
7643ff48bf5SDavid du Colombier     HDC hdc;
7653ff48bf5SDavid du Colombier     PAINTSTRUCT ps;
7663ff48bf5SDavid du Colombier     RECT rect;
7673ff48bf5SDavid du Colombier     int nYinc, nXinc;
7683ff48bf5SDavid du Colombier     TW *tw;
7693ff48bf5SDavid du Colombier     if (message == WM_CREATE) {
7703ff48bf5SDavid du Colombier 	/* Object is stored in window extra data.
7713ff48bf5SDavid du Colombier 	 * Nothing must try to use the object before WM_CREATE
7723ff48bf5SDavid du Colombier 	 * initializes it here.
7733ff48bf5SDavid du Colombier 	 */
7743ff48bf5SDavid du Colombier 	tw = (TW *)(((CREATESTRUCT FAR *)lParam)->lpCreateParams);
7753ff48bf5SDavid du Colombier 	SetWindowLong(hwnd, 0, (LONG)tw);
7763ff48bf5SDavid du Colombier     }
7773ff48bf5SDavid du Colombier     tw = (TW *)GetWindowLong(hwnd, 0);
7783ff48bf5SDavid du Colombier 
7793ff48bf5SDavid du Colombier     switch(message) {
7803ff48bf5SDavid du Colombier 	case WM_SYSCOMMAND:
7813ff48bf5SDavid du Colombier 	    switch(LOWORD(wParam)) {
7823ff48bf5SDavid du Colombier 		case M_COPY_CLIP:
7833ff48bf5SDavid du Colombier 		    text_copy_to_clipboard(tw);
7843ff48bf5SDavid du Colombier 		    return 0;
7853ff48bf5SDavid du Colombier 		case M_PASTE_CLIP:
7863ff48bf5SDavid du Colombier 		    text_paste_from_clipboard(tw);
7873ff48bf5SDavid du Colombier 		    return 0;
7883ff48bf5SDavid du Colombier 	    }
7893ff48bf5SDavid du Colombier 	    break;
7903ff48bf5SDavid du Colombier 	case WM_SETFOCUS:
7913ff48bf5SDavid du Colombier 	    tw->bFocus = TRUE;
7923ff48bf5SDavid du Colombier 	    CreateCaret(hwnd, 0, tw->CharSize.x, 2+tw->CaretHeight);
7933ff48bf5SDavid du Colombier 	    SetCaretPos(tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x,
7943ff48bf5SDavid du Colombier 		    tw->CursorPos.y*tw->CharSize.y + tw->CharAscent
7953ff48bf5SDavid du Colombier 		     - tw->CaretHeight - tw->ScrollPos.y);
7963ff48bf5SDavid du Colombier 	    if (tw->bGetCh)
7973ff48bf5SDavid du Colombier 		    ShowCaret(hwnd);
7983ff48bf5SDavid du Colombier 	    break;
7993ff48bf5SDavid du Colombier 	case WM_KILLFOCUS:
8003ff48bf5SDavid du Colombier 	    DestroyCaret();
8013ff48bf5SDavid du Colombier 	    tw->bFocus = FALSE;
8023ff48bf5SDavid du Colombier 	    break;
8033ff48bf5SDavid du Colombier 	case WM_MOVE:
8043ff48bf5SDavid du Colombier 	    if (!IsIconic(hwnd) && !IsZoomed(hwnd)) {
8053ff48bf5SDavid du Colombier 		GetWindowRect(hwnd, &rect);
8063ff48bf5SDavid du Colombier 		tw->x = rect.left;
8073ff48bf5SDavid du Colombier 		tw->y = rect.top;
8083ff48bf5SDavid du Colombier 	    }
8093ff48bf5SDavid du Colombier 	    break;
8103ff48bf5SDavid du Colombier 	case WM_SIZE:
8113ff48bf5SDavid du Colombier 	    if (wParam == SIZE_MINIMIZED)
8123ff48bf5SDavid du Colombier 		    return(0);
8133ff48bf5SDavid du Colombier 
8143ff48bf5SDavid du Colombier 	    /* remember current window size */
8153ff48bf5SDavid du Colombier 	    if (wParam != SIZE_MAXIMIZED) {
8163ff48bf5SDavid du Colombier 		GetWindowRect(hwnd, &rect);
8173ff48bf5SDavid du Colombier 		tw->cx = rect.right - rect.left;
8183ff48bf5SDavid du Colombier 		tw->cy = rect.bottom - rect.top;
8193ff48bf5SDavid du Colombier 		tw->x = rect.left;
8203ff48bf5SDavid du Colombier 		tw->y = rect.top;
8213ff48bf5SDavid du Colombier 	    }
8223ff48bf5SDavid du Colombier 
8233ff48bf5SDavid du Colombier 	    tw->ClientSize.y = HIWORD(lParam);
8243ff48bf5SDavid du Colombier 	    tw->ClientSize.x = LOWORD(lParam);
8253ff48bf5SDavid du Colombier 
8263ff48bf5SDavid du Colombier 	    tw->ScrollMax.y = max(0, tw->CharSize.y*tw->ScreenSize.y - tw->ClientSize.y);
8273ff48bf5SDavid du Colombier 	    tw->ScrollPos.y = min(tw->ScrollPos.y, tw->ScrollMax.y);
8283ff48bf5SDavid du Colombier 
8293ff48bf5SDavid du Colombier 	    SetScrollRange(hwnd, SB_VERT, 0, tw->ScrollMax.y, FALSE);
8303ff48bf5SDavid du Colombier 	    SetScrollPos(hwnd, SB_VERT, tw->ScrollPos.y, TRUE);
8313ff48bf5SDavid du Colombier 
8323ff48bf5SDavid du Colombier 	    tw->ScrollMax.x = max(0, tw->CharSize.x*tw->ScreenSize.x - tw->ClientSize.x);
8333ff48bf5SDavid du Colombier 	    tw->ScrollPos.x = min(tw->ScrollPos.x, tw->ScrollMax.x);
8343ff48bf5SDavid du Colombier 
8353ff48bf5SDavid du Colombier 	    SetScrollRange(hwnd, SB_HORZ, 0, tw->ScrollMax.x, FALSE);
8363ff48bf5SDavid du Colombier 	    SetScrollPos(hwnd, SB_HORZ, tw->ScrollPos.x, TRUE);
8373ff48bf5SDavid du Colombier 
8383ff48bf5SDavid du Colombier 	    if (tw->bFocus && tw->bGetCh) {
8393ff48bf5SDavid du Colombier 		SetCaretPos(tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x,
8403ff48bf5SDavid du Colombier 			    tw->CursorPos.y*tw->CharSize.y + tw->CharAscent
8413ff48bf5SDavid du Colombier 			    - tw->CaretHeight - tw->ScrollPos.y);
8423ff48bf5SDavid du Colombier 		ShowCaret(hwnd);
8433ff48bf5SDavid du Colombier 	    }
8443ff48bf5SDavid du Colombier 	    return(0);
8453ff48bf5SDavid du Colombier 	case WM_VSCROLL:
8463ff48bf5SDavid du Colombier 	    switch(LOWORD(wParam)) {
8473ff48bf5SDavid du Colombier 		case SB_TOP:
8483ff48bf5SDavid du Colombier 		    nYinc = -tw->ScrollPos.y;
8493ff48bf5SDavid du Colombier 		    break;
8503ff48bf5SDavid du Colombier 		case SB_BOTTOM:
8513ff48bf5SDavid du Colombier 		    nYinc = tw->ScrollMax.y - tw->ScrollPos.y;
8523ff48bf5SDavid du Colombier 		    break;
8533ff48bf5SDavid du Colombier 		case SB_LINEUP:
8543ff48bf5SDavid du Colombier 		    nYinc = -tw->CharSize.y;
8553ff48bf5SDavid du Colombier 		    break;
8563ff48bf5SDavid du Colombier 		case SB_LINEDOWN:
8573ff48bf5SDavid du Colombier 		    nYinc = tw->CharSize.y;
8583ff48bf5SDavid du Colombier 		    break;
8593ff48bf5SDavid du Colombier 		case SB_PAGEUP:
8603ff48bf5SDavid du Colombier 		    nYinc = min(-1,-tw->ClientSize.y);
8613ff48bf5SDavid du Colombier 		    break;
8623ff48bf5SDavid du Colombier 		case SB_PAGEDOWN:
8633ff48bf5SDavid du Colombier 		    nYinc = max(1,tw->ClientSize.y);
8643ff48bf5SDavid du Colombier 		    break;
8653ff48bf5SDavid du Colombier 		case SB_THUMBPOSITION:
8663ff48bf5SDavid du Colombier 		    nYinc = HIWORD(wParam) - tw->ScrollPos.y;
8673ff48bf5SDavid du Colombier 		    break;
8683ff48bf5SDavid du Colombier 		default:
8693ff48bf5SDavid du Colombier 		    nYinc = 0;
8703ff48bf5SDavid du Colombier 	    }
8713ff48bf5SDavid du Colombier 	    if ( (nYinc = max(-tw->ScrollPos.y,
8723ff48bf5SDavid du Colombier 		    min(nYinc, tw->ScrollMax.y - tw->ScrollPos.y)))
8733ff48bf5SDavid du Colombier 		    != 0 ) {
8743ff48bf5SDavid du Colombier 		    tw->ScrollPos.y += nYinc;
8753ff48bf5SDavid du Colombier 		    ScrollWindow(hwnd,0,-nYinc,NULL,NULL);
8763ff48bf5SDavid du Colombier 		    SetScrollPos(hwnd,SB_VERT,tw->ScrollPos.y,TRUE);
8773ff48bf5SDavid du Colombier 		    UpdateWindow(hwnd);
8783ff48bf5SDavid du Colombier 	    }
8793ff48bf5SDavid du Colombier 	    return(0);
8803ff48bf5SDavid du Colombier 	case WM_HSCROLL:
8813ff48bf5SDavid du Colombier 	    switch(LOWORD(wParam)) {
8823ff48bf5SDavid du Colombier 		case SB_LINEUP:
8833ff48bf5SDavid du Colombier 		    nXinc = -tw->CharSize.x;
8843ff48bf5SDavid du Colombier 		    break;
8853ff48bf5SDavid du Colombier 		case SB_LINEDOWN:
8863ff48bf5SDavid du Colombier 		    nXinc = tw->CharSize.x;
8873ff48bf5SDavid du Colombier 		    break;
8883ff48bf5SDavid du Colombier 		case SB_PAGEUP:
8893ff48bf5SDavid du Colombier 		    nXinc = min(-1,-tw->ClientSize.x);
8903ff48bf5SDavid du Colombier 		    break;
8913ff48bf5SDavid du Colombier 		case SB_PAGEDOWN:
8923ff48bf5SDavid du Colombier 		    nXinc = max(1,tw->ClientSize.x);
8933ff48bf5SDavid du Colombier 		    break;
8943ff48bf5SDavid du Colombier 		case SB_THUMBPOSITION:
8953ff48bf5SDavid du Colombier 		    nXinc = HIWORD(wParam) - tw->ScrollPos.x;
8963ff48bf5SDavid du Colombier 		    break;
8973ff48bf5SDavid du Colombier 		default:
8983ff48bf5SDavid du Colombier 		    nXinc = 0;
8993ff48bf5SDavid du Colombier 	    }
9003ff48bf5SDavid du Colombier 	    if ( (nXinc = max(-tw->ScrollPos.x,
9013ff48bf5SDavid du Colombier 		    min(nXinc, tw->ScrollMax.x - tw->ScrollPos.x)))
9023ff48bf5SDavid du Colombier 		    != 0 ) {
9033ff48bf5SDavid du Colombier 		    tw->ScrollPos.x += nXinc;
9043ff48bf5SDavid du Colombier 		    ScrollWindow(hwnd,-nXinc,0,NULL,NULL);
9053ff48bf5SDavid du Colombier 		    SetScrollPos(hwnd,SB_HORZ,tw->ScrollPos.x,TRUE);
9063ff48bf5SDavid du Colombier 		    UpdateWindow(hwnd);
9073ff48bf5SDavid du Colombier 	    }
9083ff48bf5SDavid du Colombier 	    return(0);
9093ff48bf5SDavid du Colombier 	case WM_KEYDOWN:
9103ff48bf5SDavid du Colombier 	    switch(wParam) {
9113ff48bf5SDavid du Colombier 	      case VK_HOME:
9123ff48bf5SDavid du Colombier 		      SendMessage(hwnd, WM_VSCROLL, SB_TOP, (LPARAM)0);
9133ff48bf5SDavid du Colombier 		      break;
9143ff48bf5SDavid du Colombier 	      case VK_END:
9153ff48bf5SDavid du Colombier 		      SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, (LPARAM)0);
9163ff48bf5SDavid du Colombier 		      break;
9173ff48bf5SDavid du Colombier 	      case VK_PRIOR:
9183ff48bf5SDavid du Colombier 		      SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)0);
9193ff48bf5SDavid du Colombier 		      break;
9203ff48bf5SDavid du Colombier 	      case VK_NEXT:
9213ff48bf5SDavid du Colombier 		      SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)0);
9223ff48bf5SDavid du Colombier 		      break;
9233ff48bf5SDavid du Colombier 	      case VK_UP:
9243ff48bf5SDavid du Colombier 		      SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)0);
9253ff48bf5SDavid du Colombier 		      break;
9263ff48bf5SDavid du Colombier 	      case VK_DOWN:
9273ff48bf5SDavid du Colombier 		      SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)0);
9283ff48bf5SDavid du Colombier 		      break;
9293ff48bf5SDavid du Colombier 	      case VK_LEFT:
9303ff48bf5SDavid du Colombier 		      SendMessage(hwnd, WM_HSCROLL, SB_LINEUP, (LPARAM)0);
9313ff48bf5SDavid du Colombier 		      break;
9323ff48bf5SDavid du Colombier 	      case VK_RIGHT:
9333ff48bf5SDavid du Colombier 		      SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, (LPARAM)0);
9343ff48bf5SDavid du Colombier 		      break;
9353ff48bf5SDavid du Colombier 	    }
9363ff48bf5SDavid du Colombier 	    break;
9373ff48bf5SDavid du Colombier 	case WM_CHAR:
9383ff48bf5SDavid du Colombier 	    { /* store key in circular buffer */
9393ff48bf5SDavid du Colombier 		long count = tw->KeyBufIn - tw->KeyBufOut;
9403ff48bf5SDavid du Colombier 		if (count < 0) count += tw->KeyBufSize;
9413ff48bf5SDavid du Colombier 		if (count < tw->KeyBufSize-1) {
9423ff48bf5SDavid du Colombier 		    *tw->KeyBufIn++ = wParam;
9433ff48bf5SDavid du Colombier 		    if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize)
9443ff48bf5SDavid du Colombier 			tw->KeyBufIn = tw->KeyBuf;	/* wrap around */
9453ff48bf5SDavid du Colombier 		}
9463ff48bf5SDavid du Colombier 	    }
9473ff48bf5SDavid du Colombier 	    return(0);
9483ff48bf5SDavid du Colombier 	case WM_PAINT:
9493ff48bf5SDavid du Colombier 	    {
9503ff48bf5SDavid du Colombier 	    POINT source, width, dest;
9513ff48bf5SDavid du Colombier 	    hdc = BeginPaint(hwnd, &ps);
9523ff48bf5SDavid du Colombier 	    SelectFont(hdc, tw->hfont);
9533ff48bf5SDavid du Colombier 	    SetMapMode(hdc, MM_TEXT);
9543ff48bf5SDavid du Colombier 	    SetBkMode(hdc,OPAQUE);
9553ff48bf5SDavid du Colombier 	    GetClientRect(hwnd, &rect);
9563ff48bf5SDavid du Colombier 	    source.x = (rect.left + tw->ScrollPos.x) / tw->CharSize.x; /* source */
9573ff48bf5SDavid du Colombier 	    source.y = (rect.top + tw->ScrollPos.y) / tw->CharSize.y;
9583ff48bf5SDavid du Colombier 	    dest.x = source.x * tw->CharSize.x - tw->ScrollPos.x; /* destination */
9593ff48bf5SDavid du Colombier 	    dest.y = source.y * tw->CharSize.y - tw->ScrollPos.y;
9603ff48bf5SDavid du Colombier 	    width.x = ((rect.right  + tw->ScrollPos.x + tw->CharSize.x - 1) / tw->CharSize.x) - source.x; /* width */
9613ff48bf5SDavid du Colombier 	    width.y = ((rect.bottom + tw->ScrollPos.y + tw->CharSize.y - 1) / tw->CharSize.y) - source.y;
9623ff48bf5SDavid du Colombier 	    if (source.x < 0)
9633ff48bf5SDavid du Colombier 		    source.x = 0;
9643ff48bf5SDavid du Colombier 	    if (source.y < 0)
9653ff48bf5SDavid du Colombier 		    source.y = 0;
9663ff48bf5SDavid du Colombier 	    if (source.x+width.x > tw->ScreenSize.x)
9673ff48bf5SDavid du Colombier 		    width.x = tw->ScreenSize.x - source.x;
9683ff48bf5SDavid du Colombier 	    if (source.y+width.y > tw->ScreenSize.y)
9693ff48bf5SDavid du Colombier 		    width.y = tw->ScreenSize.y - source.y;
9703ff48bf5SDavid du Colombier 	    /* for each line */
9713ff48bf5SDavid du Colombier 	    while (width.y>0) {
9723ff48bf5SDavid du Colombier 		    TextOut(hdc,dest.x,dest.y,
9733ff48bf5SDavid du Colombier 			(LPSTR)(tw->ScreenBuffer + source.y*tw->ScreenSize.x + source.x),
9743ff48bf5SDavid du Colombier 			width.x);
9753ff48bf5SDavid du Colombier 		    dest.y += tw->CharSize.y;
9763ff48bf5SDavid du Colombier 		    source.y++;
9773ff48bf5SDavid du Colombier 		    width.y--;
9783ff48bf5SDavid du Colombier 	    }
9793ff48bf5SDavid du Colombier 	    EndPaint(hwnd, &ps);
9803ff48bf5SDavid du Colombier 	    return 0;
9813ff48bf5SDavid du Colombier 	    }
9823ff48bf5SDavid du Colombier 	case WM_DROPFILES:
9833ff48bf5SDavid du Colombier 	    text_drag_drop(tw, (HDROP)wParam);
9843ff48bf5SDavid du Colombier 	    break;
9853ff48bf5SDavid du Colombier 	case WM_CREATE:
9863ff48bf5SDavid du Colombier 	    {
9873ff48bf5SDavid du Colombier 	    RECT crect, wrect;
9883ff48bf5SDavid du Colombier 	    int cx, cy;
9893ff48bf5SDavid du Colombier 
9903ff48bf5SDavid du Colombier 	    tw->hwnd = hwnd;
9913ff48bf5SDavid du Colombier 
9923ff48bf5SDavid du Colombier 	    /* make window no larger than screen buffer */
9933ff48bf5SDavid du Colombier 	    GetWindowRect(hwnd, &wrect);
9943ff48bf5SDavid du Colombier 	    GetClientRect(hwnd, &crect);
9953ff48bf5SDavid du Colombier 	    cx = min(tw->CharSize.x*tw->ScreenSize.x, crect.right);
9963ff48bf5SDavid du Colombier 	    cy = min(tw->CharSize.y*tw->ScreenSize.y, crect.bottom);
9973ff48bf5SDavid du Colombier 	    MoveWindow(hwnd, wrect.left, wrect.top,
9983ff48bf5SDavid du Colombier 		 wrect.right-wrect.left + (cx - crect.right),
9993ff48bf5SDavid du Colombier 		 wrect.bottom-wrect.top + (cy - crect.bottom),
10003ff48bf5SDavid du Colombier 		     TRUE);
10013ff48bf5SDavid du Colombier 
10023ff48bf5SDavid du Colombier 	    if ( (tw->DragPre!=(LPSTR)NULL) && (tw->DragPost!=(LPSTR)NULL) )
10033ff48bf5SDavid du Colombier 		DragAcceptFiles(hwnd, TRUE);
10043ff48bf5SDavid du Colombier 	    }
10053ff48bf5SDavid du Colombier 	    break;
10063ff48bf5SDavid du Colombier 	case WM_CLOSE:
10073ff48bf5SDavid du Colombier 	    /* Tell user that we heard them */
10083ff48bf5SDavid du Colombier 	    if (!tw->quitnow) {
10093ff48bf5SDavid du Colombier 		char title[256];
10103ff48bf5SDavid du Colombier 		int count = GetWindowText(hwnd, title, sizeof(title)-11);
10113ff48bf5SDavid du Colombier 		strcpy(title+count, " - closing");
10123ff48bf5SDavid du Colombier 		SetWindowText(hwnd, title);
10133ff48bf5SDavid du Colombier 	    }
10143ff48bf5SDavid du Colombier 	    tw->quitnow = TRUE;
10153ff48bf5SDavid du Colombier 	    /* wait until Ghostscript exits before destroying window */
10163ff48bf5SDavid du Colombier 	    return 0;
10173ff48bf5SDavid du Colombier 	case WM_DESTROY:
10183ff48bf5SDavid du Colombier 	    DragAcceptFiles(hwnd, FALSE);
10193ff48bf5SDavid du Colombier 	    if (tw->hfont)
10203ff48bf5SDavid du Colombier 		DeleteFont(tw->hfont);
10213ff48bf5SDavid du Colombier 	    tw->hfont = (HFONT)0;
10223ff48bf5SDavid du Colombier 	    tw->quitnow = TRUE;
10233ff48bf5SDavid du Colombier 	    PostQuitMessage(0);
10243ff48bf5SDavid du Colombier 	    break;
10253ff48bf5SDavid du Colombier     }
10263ff48bf5SDavid du Colombier     return DefWindowProc(hwnd, message, wParam, lParam);
10273ff48bf5SDavid du Colombier }
10283ff48bf5SDavid du Colombier 
10293ff48bf5SDavid du Colombier 
text_get_handle(TW * tw)10303ff48bf5SDavid du Colombier HWND text_get_handle(TW *tw)
10313ff48bf5SDavid du Colombier {
10323ff48bf5SDavid du Colombier     return tw->hwnd;
10333ff48bf5SDavid du Colombier }
10343ff48bf5SDavid du Colombier 
10353ff48bf5SDavid du Colombier 
10363ff48bf5SDavid du Colombier #ifdef NOTUSED
10373ff48bf5SDavid du Colombier /* test program */
10383ff48bf5SDavid du Colombier #pragma argsused
10393ff48bf5SDavid du Colombier 
10403ff48bf5SDavid du Colombier int PASCAL
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int nCmdShow)10413ff48bf5SDavid du Colombier WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
10423ff48bf5SDavid du Colombier {
10433ff48bf5SDavid du Colombier 
10443ff48bf5SDavid du Colombier 	/* make a test window */
10453ff48bf5SDavid du Colombier 	tw = text_new();
10463ff48bf5SDavid du Colombier 
10473ff48bf5SDavid du Colombier 	if (!hPrevInstance) {
10483ff48bf5SDavid du Colombier 	    HICON hicon = LoadIcon(NULL, IDI_APPLICATION);
10493ff48bf5SDavid du Colombier 	    text_register_class(hicon);
10503ff48bf5SDavid du Colombier 	}
10513ff48bf5SDavid du Colombier 	text_font(tw, "Courier New", 10);
10523ff48bf5SDavid du Colombier 	text_size(tw, 80, 80);
10533ff48bf5SDavid du Colombier 	text_drag(tw, "(", ") run\r");
10543ff48bf5SDavid du Colombier 
10553ff48bf5SDavid du Colombier 	/* show the text window */
10563ff48bf5SDavid du Colombier 	if (!text_create(tw, "Application Name", nCmdShow)) {
10573ff48bf5SDavid du Colombier 	    /* do the real work here */
10583ff48bf5SDavid du Colombier 	    /* TESTING */
10593ff48bf5SDavid du Colombier 	    int ch;
10603ff48bf5SDavid du Colombier 	    int len;
10613ff48bf5SDavid du Colombier 	    char *line = new char[256];
10623ff48bf5SDavid du Colombier 	    while ( (len = text_read_line(tw, line, 256-1)) != 0 ) {
10633ff48bf5SDavid du Colombier 		text_write_buf(tw, line, len);
10643ff48bf5SDavid du Colombier 	    }
10653ff48bf5SDavid du Colombier /*
10663ff48bf5SDavid du Colombier 	    while ( text_gets(tw, line, 256-1) ) {
10673ff48bf5SDavid du Colombier 		text_puts(tw, line);
10683ff48bf5SDavid du Colombier 	    }
10693ff48bf5SDavid du Colombier */
10703ff48bf5SDavid du Colombier /*
10713ff48bf5SDavid du Colombier 	    while ( (ch = text_getch(tw, )) != 4 )
10723ff48bf5SDavid du Colombier 		text_putch(tw, ch);
10733ff48bf5SDavid du Colombier */
10743ff48bf5SDavid du Colombier 	}
10753ff48bf5SDavid du Colombier 	else {
10763ff48bf5SDavid du Colombier 
10773ff48bf5SDavid du Colombier 	}
10783ff48bf5SDavid du Colombier 
10793ff48bf5SDavid du Colombier 	/* clean up */
10803ff48bf5SDavid du Colombier 	text_destroy(tw);
10813ff48bf5SDavid du Colombier 
10823ff48bf5SDavid du Colombier 	/* end program */
10833ff48bf5SDavid du Colombier 	return 0;
10843ff48bf5SDavid du Colombier }
10853ff48bf5SDavid du Colombier #endif
1086