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