1 /*
2 
3   Win32  interface for Metafont.
4   Author: Fabrice Popineau <Fabrice.Popineau@supelec.fr>
5 
6  */
7 
8 #define	EXTERN	extern
9 #include "../mfd.h"
10 
11 #ifdef WIN32WIN
12 #include <windows.h>
13 
14 #ifndef min
15 #define min(a,b) ((a) < (b) ? (a) : (b))
16 #endif
17 #ifndef max
18 #define max(a,b) ((a) < (b) ? (b) : (a))
19 #endif
20 
21 static void Win32Error(const char *caller);
22 
23 /*
24    The following constant enables some hack that should allow the
25    window to process its messages. Basically, the principle is to
26    create a thread which will do the message loop. Unfortunately,
27    it does not seem to work very well :-)
28    */
29 #undef  LOOPMSG
30 #define LOOPMSG 1
31 
32 #undef  DEBUG
33 /* #define DEBUG 1 */
34 
35 static char szTitle[] = " MetaFont V2.718281 Online Display";
36 static HWND my_window;
37 static HDC my_dc;
38 static HDC drawing_dc;
39 static HBITMAP hbm;
40 static MSG msg;
41 static HANDLE hAccelTable;
42 static HANDLE hMutex;
43 /* Scrollbars' variables */
44 static SCROLLINFO si;
45 static int xMinScroll;
46 static int xMaxScroll;
47 static int xCurrentScroll;
48 static int yMinScroll;
49 static int yMaxScroll;
50 static int yCurrentScroll;
51 static BOOL fScroll;
52 static BOOL fSize;
53 
54 #ifdef LOOPMSG
55 void __cdecl InitGui(void*);
56 #endif
57 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
58 
59 #include <mfdisplay.h>
60 
61 int
mf_win32_initscreen(void)62 mf_win32_initscreen(void)
63 {
64   int ret;
65   if ((ret = _beginthread(InitGui, 0, NULL)) == -1) {
66     fprintf(stderr, "_beginthread returned with %d\n", ret);
67     return 0;
68   }
69   else
70     return 1;
71 }
72 
73   /* This window should be registered into a class. And maybe the
74      message loop could run into a separate thread. */
75 
InitGui(void * param)76 void __cdecl InitGui(void *param)
77 {
78   HWND hparentwnd;
79   HANDLE hinst;
80   WNDCLASSEX wndclass;
81   char szFile[80];
82 
83   hinst = GetModuleHandle(NULL);
84   GetModuleFileName (hinst, szFile, sizeof(szFile));
85 #ifdef DEBUG
86   printf ("hinst = %x\n", hinst);
87   printf ("File = %s\n", szFile);
88 #endif
89   /* Fill in window class structure with parameters that describe
90      the main window. */
91   /* CS_OWNDC : un DC pour chaque fen�tre de la classe */
92   wndclass.cbSize        = sizeof(wndclass);
93   wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
94   wndclass.lpfnWndProc   = (WNDPROC)WndProc;
95   wndclass.cbClsExtra    = 0;
96   wndclass.cbWndExtra    = 0;
97   wndclass.hInstance     = hinst;
98   wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
99   wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION);
100   wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
101   wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
102   wndclass.lpszClassName = szFile;
103   wndclass.lpszMenuName  = NULL;
104 
105   if (!RegisterClassEx(&wndclass))
106     Win32Error("Register class");
107 
108   hparentwnd = GetFocus();
109   my_window = CreateWindow(szFile, szTitle,
110 			   WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
111 			   CW_USEDEFAULT, 0,
112 			   CW_USEDEFAULT, 0,
113 			   /* screenwidth, screendepth, */
114 			   hparentwnd, NULL, hinst, NULL);
115   if (!my_window) {
116     Win32Error("Create window");
117   }
118 #ifdef DEBUG
119   fprintf(stderr, "my_window = %x\n", my_window);
120 #endif
121 
122 #ifdef LOOPMSG
123   /* Acknowledge for UpdateWindow() (WM_PAINT message generated) */
124   hMutex = CreateMutex(NULL, FALSE, "DrawingMutex");
125   my_dc = GetDC(my_window);
126   /* Device context for drawing and the associated bitmap. */
127   drawing_dc = CreateCompatibleDC(my_dc);
128   hbm = CreateCompatibleBitmap(my_dc, screenwidth, screendepth);
129   SelectObject(drawing_dc, hbm);
130   /* Blank the bitmap */
131   SelectObject(drawing_dc, GetStockObject(WHITE_BRUSH));
132   PatBlt(drawing_dc, 0, 0, screenwidth, screendepth, PATCOPY);
133   hAccelTable = LoadAccelerators (hinst, szTitle);
134 
135   ShowWindow(my_window, SW_SHOWNORMAL);
136   UpdateWindow(my_window);
137 
138   /* Running the message loop */
139   while (GetMessage(&msg, my_window, 0, 0)) {
140       TranslateMessage(&msg);
141       DispatchMessage(&msg);
142   }
143 
144 #else
145   drawing_dc = my_dc = GetDC(my_window);
146 #endif
147 }
148 
149 /* Make sure the screen is up to date. (section 8.6 Handling the output
150 buffer)  */
151 
152 void
mf_win32_updatescreen(void)153 mf_win32_updatescreen(void)
154 {
155   RECT r;
156   r.left   = 0;
157   r.top    = 0;
158   r.right  = screenwidth;
159   r.bottom = screendepth;
160 
161   /* Send a WM_PAINT message to the window.
162      The rectangle should be invalidated for the message being sent. */
163   InvalidateRect(my_window, &r, FALSE);
164   UpdateWindow(my_window);
165 }
166 
167 
168 /* Blank the rectangular inside the given coordinates. We don't need to
169 reset the foreground to black because we always set it at the beginning
170 of paintrow (below).  */
171 
172 void
mf_win32_blankrectangle(screencol left,screencol right,screenrow top,screenrow bottom)173 mf_win32_blankrectangle (screencol left,
174                          screencol right,
175                          screenrow top,
176                          screenrow bottom)
177 {
178   RECT r;
179   r.left   = left;
180   r.top    = top;
181   r.right  = right+1;		/* FIXME: must we fill the last row/column ? */
182   r.bottom = bottom+1;
183   /* Fixme : should synchronize with message processing. */
184   WaitForSingleObject(hMutex, INFINITE);
185   FillRect(drawing_dc, &r, GetStockObject(WHITE_BRUSH));
186   ReleaseMutex(hMutex);
187 }
188 
189 
190 /* Paint a row with the given ``transition specifications''. We might be
191 able to do something here with drawing many lines.  */
192 
193 void
mf_win32_paintrow(screenrow row,pixelcolor init_color,transspec tvect,register screencol vector_size)194 mf_win32_paintrow (screenrow row,
195                    pixelcolor init_color,
196                    transspec tvect,
197                    register screencol vector_size)
198 {
199     register int col;
200     HGDIOBJ CurrentPen;
201     HGDIOBJ WhitePen = GetStockObject(WHITE_PEN);
202     HGDIOBJ BlackPen = GetStockObject(BLACK_PEN);
203     /* FIXME: should sync with msg processing */
204     WaitForSingleObject(hMutex, INFINITE);
205     CurrentPen = (init_color == 0) ? WhitePen : BlackPen;
206     do {
207       col = *tvect++;
208       MoveToEx(drawing_dc, col, (int) row, NULL);
209       SelectObject(drawing_dc, CurrentPen);
210 
211       /* (section 6.3.2 Drawing single and multiple lines)
212        */
213       LineTo(drawing_dc, (int) *tvect, (int) row);
214       CurrentPen = (CurrentPen == WhitePen) ? BlackPen : WhitePen;
215     } while (--vector_size > 0);
216     SelectObject(drawing_dc, GetStockObject(NULL_PEN));
217     ReleaseMutex(hMutex);
218 }
219 
Win32Error(const char * caller)220 static void Win32Error(const char *caller)
221 {
222   LPVOID lpMsgBuf;
223 
224   FormatMessage(
225 		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
226 		NULL,
227 		GetLastError(),
228 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
229 		(LPTSTR) &lpMsgBuf,
230 		0,
231 		NULL
232 		);
233   /* Display the string. */
234   MessageBox( NULL, lpMsgBuf, caller, MB_OK|MB_ICONINFORMATION );
235   /* Free the buffer. */
236   LocalFree( lpMsgBuf );
237 }
238 
WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)239 LRESULT APIENTRY WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
240 {
241   PAINTSTRUCT ps;
242   int retval = 0;
243 
244 #ifdef DEBUG
245   fprintf(stderr, "Message %x\n", iMsg);
246 #endif
247 #ifdef LOOPMSG
248   WaitForSingleObject(hMutex, INFINITE);
249   switch (iMsg) {
250   case WM_CREATE:
251     xMinScroll = 0;
252     xMaxScroll = screenwidth;
253     xCurrentScroll = 0;
254 
255     yMinScroll = 0;
256     yMaxScroll = screendepth;
257     yCurrentScroll = 0;
258 
259     fScroll = FALSE;
260     fSize = FALSE;
261 
262     break;
263   case WM_SIZE:
264     {
265       int xNewSize, yNewSize;
266       xNewSize = LOWORD(lParam);
267       yNewSize = HIWORD(lParam);
268 
269       fSize = TRUE;
270 
271       xMaxScroll = max(screenwidth, xNewSize);
272       xCurrentScroll = min(xCurrentScroll, xMaxScroll);
273 
274       si.cbSize = sizeof(si);
275       si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
276       si.nMin = xMinScroll;
277       si.nMax = xMaxScroll;
278       si.nPage = xNewSize;
279       si.nPos = xCurrentScroll;
280       SetScrollInfo(my_window, SB_HORZ, &si, TRUE);
281 
282       yMaxScroll = max(screendepth, yNewSize);
283       yCurrentScroll = min(yCurrentScroll, yMaxScroll);
284 
285       si.cbSize = sizeof(si);
286       si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
287       si.nMin = yMinScroll;
288       si.nMax = yMaxScroll;
289       si.nPage = yNewSize;
290       si.nPos = yCurrentScroll;
291       SetScrollInfo(my_window, SB_VERT, &si, TRUE);
292       }
293   case WM_PAINT:
294     {
295 #ifdef DEBUG
296       fprintf(stderr, "WM_PAINT message hbm = %x\n", hbm);
297 #endif
298       BeginPaint(my_window, &ps);
299       /* Shouldn't repaint all the screen, but so easy! */
300       if (!BitBlt(my_dc,
301 		    0, 0,
302 		    screenwidth, screendepth,
303 		    drawing_dc,
304 		    xCurrentScroll,
305 		    yCurrentScroll, SRCCOPY))
306 		Win32Error("Bitblt");
307       EndPaint(my_window, &ps);
308       retval = 0;
309       break;
310     }
311   case WM_HSCROLL:
312     {
313       int xDelta;
314       int xNewPos;
315       int yDelta = 0;
316       switch (LOWORD(wParam)) {
317       case SB_PAGEUP:
318 	xNewPos = xCurrentScroll - 50;
319 	break;
320       case SB_PAGEDOWN:
321 	xNewPos = xCurrentScroll + 50;
322 	break;
323       case SB_LINEUP:
324 	xNewPos = xCurrentScroll - 5;
325 	break;
326       case SB_LINEDOWN:
327 	xNewPos = xCurrentScroll + 5;
328 	break;
329       case SB_THUMBPOSITION:
330 	xNewPos = HIWORD(wParam);
331 	break;
332       default:
333 	xNewPos = xCurrentScroll;
334       }
335       xNewPos = max(0, xNewPos);
336       xNewPos = min(xMaxScroll, xNewPos);
337 
338       if (xNewPos == xCurrentScroll)
339 	break;
340 
341       fScroll = TRUE;
342 
343       xDelta = xNewPos - xCurrentScroll;
344       xCurrentScroll = xNewPos;
345 
346       ScrollWindowEx(my_window, -xDelta, -yDelta, (CONST RECT *)NULL,
347 		     (CONST RECT *)NULL, (HRGN)NULL, (LPRECT)NULL,
348 		     SW_INVALIDATE);
349       UpdateWindow(my_window);
350 
351       si.cbSize = sizeof(si);
352       si.fMask = SIF_POS;
353       si.nPos = xCurrentScroll;
354       SetScrollInfo(my_window, SB_HORZ, &si, TRUE);
355     }
356   break;
357 
358   case WM_VSCROLL:
359     {
360       int xDelta = 0;
361       int yNewPos;
362       int yDelta;
363       switch (LOWORD(wParam)) {
364       case SB_PAGEUP:
365 	yNewPos = yCurrentScroll - 50;
366 	break;
367       case SB_PAGEDOWN:
368 	yNewPos = yCurrentScroll + 50;
369 	break;
370       case SB_LINEUP:
371 	yNewPos = yCurrentScroll - 5;
372 	break;
373       case SB_LINEDOWN:
374 	yNewPos = yCurrentScroll + 5;
375 	break;
376       case SB_THUMBPOSITION:
377 	yNewPos = HIWORD(wParam);
378 	break;
379       default:
380 	yNewPos = yCurrentScroll;
381       }
382       yNewPos = max(0, yNewPos);
383       yNewPos = min(yMaxScroll, yNewPos);
384 
385       if (yNewPos == yCurrentScroll)
386 	break;
387 
388       fScroll = TRUE;
389 
390       yDelta = yNewPos - yCurrentScroll;
391       yCurrentScroll = yNewPos;
392 
393       ScrollWindowEx(my_window, -xDelta, -yDelta, (CONST RECT *)NULL,
394 		     (CONST RECT *)NULL, (HRGN)NULL, (LPRECT)NULL,
395 		     SW_INVALIDATE);
396       UpdateWindow(my_window);
397 
398       si.cbSize = sizeof(si);
399       si.fMask = SIF_POS;
400       si.nPos = yCurrentScroll;
401       SetScrollInfo(my_window, SB_VERT, &si, TRUE);
402     }
403   break;
404 
405   case WM_DESTROY:
406     PostQuitMessage(0);
407     retval = 0;
408     break;
409   default:
410     retval = DefWindowProc(hwnd, iMsg, wParam, lParam);
411     break;
412   }
413   ReleaseMutex(hMutex);
414   return retval;
415 #else
416   return DefWindowProc(hwnd, iMsg, wParam, lParam);
417 #endif
418 }
419 
420 #else
421 int win32_dummy;
422 #endif /* WIN32WIN */
423