Back to index

tetex-bin  3.0
win32.c
Go to the documentation of this file.
00001 /*
00002 
00003   Win32  interface for Metafont.
00004   Author: Fabrice Popineau <Fabrice.Popineau@supelec.fr>
00005 
00006  */
00007 
00008 #define       EXTERN extern
00009 #include "../mfd.h"
00010 
00011 #ifdef WIN32WIN
00012 #include <windows.h>
00013 
00014 /* 
00015    The following constant enables some hack that should allow the
00016    window to process its messages. Basically, the principle is to 
00017    create a thread which will do the message loop. Unfortunately,
00018    it does not seem to work very well :-)
00019    */
00020 #undef  LOOPMSG
00021 #define LOOPMSG 1
00022 
00023 #undef  DEBUG
00024 /* #define DEBUG 1 */
00025 
00026 static char szAppName[] = "MF";
00027 static char szTitle[] = " MetaFont V2.718 Online Display";
00028 static HWND my_window;
00029 static HDC my_dc;
00030 static HDC drawing_dc;
00031 static HBITMAP hbm;
00032 static RGBQUAD black = {0,0,0,0};
00033 static RGBQUAD white = {255,255,255,0};
00034 static MSG msg;
00035 static HANDLE hAccelTable;
00036 static HANDLE hMutex;
00037 /* Scrollbars' variables */
00038 static SCROLLINFO si;
00039 static int xMinScroll;
00040 static int xMaxScroll;
00041 static int xCurrentScroll;
00042 static int yMinScroll;
00043 static int yMaxScroll;
00044 static int yCurrentScroll;
00045 static BOOL fScroll;
00046 static BOOL fSize;
00047 
00048 #ifdef LOOPMSG
00049 void __cdecl InitGui(void*);
00050 #endif
00051 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
00052 
00053 int
00054 mf_win32_initscreen()
00055 {
00056   int ret;
00057   if ((ret = _beginthread(InitGui, 0, NULL)) == -1) {
00058     fprintf(stderr, "_beginthread returned with %d\n", ret);
00059     return 0;
00060   }
00061   else
00062     return 1;
00063 }
00064 
00065   /* This window should be registered into a class. And maybe the
00066      message loop could run into a separate thread. */
00067 
00068 void __cdecl InitGui(void *param)
00069 {
00070   HWND hparentwnd;
00071   HANDLE hinst;
00072   WNDCLASSEX wndclass;
00073   char szFile[80];
00074 
00075   hinst = GetModuleHandle(NULL);
00076   GetModuleFileName (hinst, szFile, sizeof(szFile));
00077 #ifdef DEBUG
00078   printf ("hinst = %x\n", hinst);
00079   printf ("File = %s\n", szFile);
00080 #endif
00081   /* Fill in window class structure with parameters that describe
00082      the main window. */
00083   /* CS_OWNDC : un DC pour chaque fenÍtre de la classe */
00084   wndclass.cbSize        = sizeof(wndclass);
00085   wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
00086   wndclass.lpfnWndProc   = (WNDPROC)WndProc;
00087   wndclass.cbClsExtra    = 0;
00088   wndclass.cbWndExtra    = 0;
00089   wndclass.hInstance     = hinst;
00090   wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
00091   wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION);
00092   wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
00093   wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
00094   wndclass.lpszClassName = szFile;
00095   wndclass.lpszMenuName  = NULL;
00096 
00097   if (!RegisterClassEx(&wndclass))
00098     Win32Error("Register class");
00099 
00100   hparentwnd = GetFocus();
00101   my_window = CreateWindow(szFile, szTitle, 
00102                         WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
00103                         CW_USEDEFAULT, 0, 
00104                         CW_USEDEFAULT, 0,
00105                         /* screenwidth, screendepth, */
00106                         hparentwnd, NULL, hinst, NULL);
00107   if (!my_window) {
00108     Win32Error("Create window");
00109   }
00110 #ifdef DEBUG
00111   fprintf(stderr, "my_window = %x\n", my_window);
00112 #endif
00113   
00114 #ifdef LOOPMSG
00115   /* Acknowledge for UpdateWindow() (WM_PAINT message generated) */
00116   hMutex = CreateMutex(NULL, FALSE, "DrawingMutex");
00117   my_dc = GetDC(my_window);
00118   /* Device context for drawing and the associated bitmap. */
00119   drawing_dc = CreateCompatibleDC(my_dc);
00120   hbm = CreateCompatibleBitmap(my_dc, screenwidth, screendepth);
00121   SelectObject(drawing_dc, hbm);
00122   /* Blank the bitmap */
00123   SelectObject(drawing_dc, GetStockObject(WHITE_BRUSH));
00124   PatBlt(drawing_dc, 0, 0, screenwidth, screendepth, PATCOPY);
00125   hAccelTable = LoadAccelerators (hinst, szTitle);
00126 
00127   ShowWindow(my_window, SW_SHOWNORMAL);
00128   UpdateWindow(my_window);
00129 
00130   /* Running the message loop */
00131   while (GetMessage(&msg, my_window, 0, 0)) {
00132       TranslateMessage(&msg);
00133       DispatchMessage(&msg);
00134   }
00135 
00136 #else
00137   drawing_dc = my_dc = GetDC(my_window);
00138 #endif
00139 }
00140 
00141 /* Make sure the screen is up to date. (section 8.6 Handling the output
00142 buffer)  */
00143 
00144 void
00145 mf_win32_updatescreen()
00146 {
00147   RECT r;
00148   r.left   = 0;
00149   r.top    = 0;
00150   r.right  = screenwidth;
00151   r.bottom = screendepth;
00152   
00153   /* Send a WM_PAINT message to the window.
00154      The rectangle should be invalidated for the message being sent. */
00155   InvalidateRect(my_window, &r, FALSE);
00156   UpdateWindow(my_window);
00157 }
00158 
00159 
00160 /* Blank the rectangular inside the given coordinates. We don't need to
00161 reset the foreground to black because we always set it at the beginning
00162 of paintrow (below).  */
00163 
00164 void mf_win32_blankrectangle P4C(screencol, left,
00165                                  screencol, right,
00166                                  screenrow, top,
00167                                  screenrow, bottom)
00168 {
00169   RECT r;
00170   r.left   = left;
00171   r.top    = top;
00172   r.right  = right+1;              /* FIXME: must we fill the last row/column ? */
00173   r.bottom = bottom+1;
00174   /* Fixme : should synchronize with message processing. */
00175   WaitForSingleObject(hMutex, INFINITE);
00176   FillRect(drawing_dc, &r, GetStockObject(WHITE_BRUSH));
00177   ReleaseMutex(hMutex);
00178 }
00179 
00180 
00181 /* Paint a row with the given ``transition specifications''. We might be
00182 able to do something here with drawing many lines.  */
00183 
00184 void
00185 mf_win32_paintrow P4C(screenrow, row,
00186                       pixelcolor, init_color,
00187                       transspec, tvect,
00188                       register screencol, vector_size)
00189 {
00190     register int col;
00191     HGDIOBJ CurrentPen;
00192     HGDIOBJ WhitePen = GetStockObject(WHITE_PEN);
00193     HGDIOBJ BlackPen = GetStockObject(BLACK_PEN);
00194     /* FIXME: should sync with msg processing */
00195     WaitForSingleObject(hMutex, INFINITE);
00196     CurrentPen = (init_color == 0) ? WhitePen : BlackPen;
00197     do {
00198       col = *tvect++;
00199       MoveToEx(drawing_dc, col, (int) row, NULL);
00200       SelectObject(drawing_dc, CurrentPen);
00201       
00202       /* (section 6.3.2 Drawing single and multiple lines)
00203        */
00204       LineTo(drawing_dc, (int) *tvect, (int) row);
00205       CurrentPen = (CurrentPen == WhitePen) ? BlackPen : WhitePen;
00206     } while (--vector_size > 0);
00207     SelectObject(drawing_dc, GetStockObject(NULL_PEN));
00208     ReleaseMutex(hMutex);
00209 }
00210 
00211 #if 0
00212 void Win32Error(char *caller)
00213 {
00214   LPVOID lpMsgBuf;
00215 
00216   FormatMessage(
00217               FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00218               NULL,
00219               GetLastError(),
00220               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
00221               (LPTSTR) &lpMsgBuf,
00222               0,
00223               NULL 
00224               );
00225   /* Display the string. */
00226   MessageBox( NULL, lpMsgBuf, caller, MB_OK|MB_ICONINFORMATION );
00227   /* Free the buffer. */
00228   LocalFree( lpMsgBuf );
00229 }
00230 #endif
00231 
00232 LRESULT APIENTRY WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
00233 {
00234   PAINTSTRUCT ps;
00235   int retval;
00236 
00237 #ifdef DEBUG
00238   fprintf(stderr, "Message %x\n", iMsg);
00239 #endif
00240 #ifdef LOOPMSG
00241   WaitForSingleObject(hMutex, INFINITE);
00242   switch (iMsg) {
00243   case WM_CREATE:
00244     xMinScroll = 0;
00245     xMaxScroll = screenwidth;
00246     xCurrentScroll = 0;
00247 
00248     yMinScroll = 0;
00249     yMaxScroll = screendepth;
00250     yCurrentScroll = 0;
00251 
00252     fScroll = FALSE;
00253     fSize = FALSE;
00254 
00255     break;
00256   case WM_SIZE:
00257     {
00258       int xNewSize, yNewSize;
00259       xNewSize = LOWORD(lParam);
00260       yNewSize = HIWORD(lParam);
00261 
00262       fSize = TRUE;
00263 
00264       xMaxScroll = max(screenwidth, xNewSize);
00265       xCurrentScroll = min(xCurrentScroll, xMaxScroll);
00266 
00267       si.cbSize = sizeof(si);
00268       si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
00269       si.nMin = xMinScroll;
00270       si.nMax = xMaxScroll;
00271       si.nPage = xNewSize;
00272       si.nPos = xCurrentScroll;
00273       SetScrollInfo(my_window, SB_HORZ, &si, TRUE);
00274 
00275       yMaxScroll = max(screendepth, yNewSize);
00276       yCurrentScroll = min(yCurrentScroll, yMaxScroll);
00277 
00278       si.cbSize = sizeof(si);
00279       si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
00280       si.nMin = yMinScroll;
00281       si.nMax = yMaxScroll;
00282       si.nPage = yNewSize;
00283       si.nPos = yCurrentScroll;
00284       SetScrollInfo(my_window, SB_VERT, &si, TRUE);
00285       }
00286   case WM_PAINT:
00287     {
00288 #ifdef DEBUG
00289       fprintf(stderr, "WM_PAINT message hbm = %x\n", hbm);
00290 #endif
00291       BeginPaint(my_window, &ps);
00292       /* Shouldn't repaint all the screen, but so easy! */
00293       if (!BitBlt(my_dc,
00294                   0, 0, 
00295                   screenwidth, screendepth,
00296                   drawing_dc, 
00297                   xCurrentScroll, 
00298                   yCurrentScroll, SRCCOPY))
00299               Win32Error("Bitblt");
00300       EndPaint(my_window, &ps);
00301       retval = 0;
00302       break;
00303     }
00304   case WM_HSCROLL:
00305     {
00306       int xDelta;
00307       int xNewPos;
00308       int yDelta = 0;
00309       switch (LOWORD(wParam)) {
00310       case SB_PAGEUP:
00311        xNewPos = xCurrentScroll - 50;
00312        break;
00313       case SB_PAGEDOWN:
00314        xNewPos = xCurrentScroll + 50;
00315        break;
00316       case SB_LINEUP:
00317        xNewPos = xCurrentScroll - 5;
00318        break;
00319       case SB_LINEDOWN:
00320        xNewPos = xCurrentScroll + 5;
00321        break;
00322       case SB_THUMBPOSITION:
00323        xNewPos = HIWORD(wParam);
00324        break;
00325       default:
00326        xNewPos = xCurrentScroll;
00327       }
00328       xNewPos = max(0, xNewPos);
00329       xNewPos = min(xMaxScroll, xNewPos);
00330       
00331       if (xNewPos == xCurrentScroll)
00332        break;
00333       
00334       fScroll = TRUE;
00335       
00336       xDelta = xNewPos - xCurrentScroll;
00337       xCurrentScroll = xNewPos;
00338       
00339       ScrollWindowEx(my_window, -xDelta, -yDelta, (CONST RECT *)NULL,
00340                    (CONST RECT *)NULL, (HRGN)NULL, (LPRECT)NULL,
00341                    SW_INVALIDATE);
00342       UpdateWindow(my_window);
00343       
00344       si.cbSize = sizeof(si);
00345       si.fMask = SIF_POS;
00346       si.nPos = xCurrentScroll;
00347       SetScrollInfo(my_window, SB_HORZ, &si, TRUE);
00348     }
00349   break;
00350 
00351   case WM_VSCROLL:
00352     {
00353       int xDelta = 0;
00354       int yNewPos;
00355       int yDelta;
00356       switch (LOWORD(wParam)) {
00357       case SB_PAGEUP:
00358        yNewPos = yCurrentScroll - 50;
00359        break;
00360       case SB_PAGEDOWN:
00361        yNewPos = yCurrentScroll + 50;
00362        break;
00363       case SB_LINEUP:
00364        yNewPos = yCurrentScroll - 5;
00365        break;
00366       case SB_LINEDOWN:
00367        yNewPos = yCurrentScroll + 5;
00368        break;
00369       case SB_THUMBPOSITION:
00370        yNewPos = HIWORD(wParam);
00371        break;
00372       default:
00373        yNewPos = yCurrentScroll;
00374       }
00375       yNewPos = max(0, yNewPos);
00376       yNewPos = min(yMaxScroll, yNewPos);
00377       
00378       if (yNewPos == yCurrentScroll)
00379        break;
00380       
00381       fScroll = TRUE;
00382       
00383       yDelta = yNewPos - yCurrentScroll;
00384       yCurrentScroll = yNewPos;
00385       
00386       ScrollWindowEx(my_window, -xDelta, -yDelta, (CONST RECT *)NULL,
00387                    (CONST RECT *)NULL, (HRGN)NULL, (LPRECT)NULL,
00388                    SW_INVALIDATE);
00389       UpdateWindow(my_window);
00390       
00391       si.cbSize = sizeof(si);
00392       si.fMask = SIF_POS;
00393       si.nPos = yCurrentScroll;
00394       SetScrollInfo(my_window, SB_VERT, &si, TRUE);
00395     }
00396   break;
00397   
00398   case WM_DESTROY:
00399     PostQuitMessage(0);
00400     retval = 0;
00401     break;
00402   default:
00403     retval = DefWindowProc(hwnd, iMsg, wParam, lParam);
00404     break;
00405   }
00406   ReleaseMutex(hMutex);
00407   return retval;
00408 #else
00409   return DefWindowProc(hwnd, iMsg, wParam, lParam);
00410 #endif
00411 }
00412 
00413 #else
00414 int win32_dummy;
00415 #endif /* WIN32WIN */