home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #4 / amigaacscoverdisc1998-041998.iso / utilities / shareware / dev / ucb_logoppc / source / win32trm.c.win < prev    next >
Encoding:
Text File  |  1997-05-05  |  31.0 KB  |  1,082 lines

  1. /* -*-C-*-
  2.  * win32trm.c -- Module to provide Win32 API compliant graphics routines
  3.  * to UCB Logo.  This module should contain Win32 versions of all necessary
  4.  * drawing functions, as well as the WinMain entry point.
  5.  *
  6.  * Since this is a part of work being done FOR the University, I suppose
  7.  * this part is (c) 1996 Regents of the University of California.
  8.  * All rights reserved and all that jazz.
  9.  *
  10.  */
  11. /*
  12.  * By definition, this file is used for MS Windows versions of the
  13.  * program, so no tests for #ifdef mac (for example) are needed.
  14.  */
  15.  
  16. #include <windows.h>
  17. #include <string.h>
  18. #include <math.h>
  19.  
  20. #include "logo.h"
  21. #include "globals.h"
  22. #include "win32trm.h"
  23.  
  24. // #define WIN32_S
  25.  
  26. LRESULT CALLBACK ParentWindowFunc(HWND, UINT, WPARAM, LPARAM);
  27.  
  28. char szWinName[] = "UCBLogo";
  29. char szGraphWinName[] = "UCBLogoGraph";
  30. char szConWinName[] = "UCBLogoConsole";
  31.  
  32. pen_info turtlePen;
  33.  
  34. HBRUSH hbrush;
  35.  
  36. HBITMAP hbitG, hbitmG, hbitC, hbitmC;
  37. RECT allRect;
  38.  
  39. HDC GraphDC, memGraphDC, ConDC, memConDC;
  40. HWND hGraphWnd, hConWnd, hMainWnd;
  41.  
  42. /* color and palette related information */
  43. static COLORREF palette[200];
  44. FIXNUM back_ground, pen_color, old_pen_color;
  45.  
  46. int maxX, maxY, greeted = 0, oldWidth, oldHeight;
  47. int pre_turtle_pen_mode;
  48. long Xsofar, Ysofar;
  49.  
  50. BOOLEAN in_erase_mode, update_pos, seen_once = FALSE;
  51.  
  52. int in_graphics_mode, in_splitscreen;
  53.  
  54. static char **win32_lines; // for recording what should appear in the text win
  55. static char input_lines[2][200];
  56.  
  57. char *read_line, buffered_char;
  58. int cur_line = 0, cur_index = 0, read_index, hpos = 0, margin, cur_len;
  59. int char_mode = 0, input_line = 0, input_index = 0;
  60.  
  61. int line_avail = FALSE, char_avail = FALSE;
  62.  
  63. #ifdef WIN32_DEBUG
  64. void WinDebug(char *s) {
  65.     ndprintf("%t", s);
  66. }
  67. #endif
  68.  
  69. int win32_screen_right(void) {
  70.     RECT r;
  71.  
  72.     GetClientRect(hMainWnd, &r);
  73.     return (int) r.right;
  74. }
  75.  
  76. int win32_screen_bottom(void) {
  77.     RECT r;
  78.  
  79.     GetClientRect(hMainWnd, &r);
  80.     return (int) r.bottom;
  81. }
  82.  
  83. void moveto(int x, int y) {
  84.     /* no invalidation of the rectangle, etc needs to be done. */
  85.     turtlePen.h = x;
  86.     turtlePen.v = y;
  87.     MoveCursor(x, y);
  88. }
  89.  
  90. void lineto(int x, int y) {
  91.     turtlePen.h = x;
  92.     turtlePen.v = y;
  93.     LineTo(memGraphDC, x, y);
  94.     LineTo(GraphDC, x, y);
  95. }
  96.  
  97. void win32_go_away(void) {
  98.     int i;
  99.  
  100.     if (read_line != NULL)
  101.     free(read_line);
  102.     for (i = 0; i < NUM_LINES; i++)
  103.     if (win32_lines[i] != NULL)
  104.         free(win32_lines[i]);
  105.     if (win32_lines != NULL)
  106.     free(win32_lines);
  107.     DeleteObject(turtlePen.hpen);
  108.     DeleteObject(hbrush);
  109.     DeleteObject(hbitC);
  110.     DeleteObject(hbitmC);
  111.     DeleteObject(hbitG);
  112.     DeleteObject(hbitmG);
  113.     DeleteDC(memConDC);
  114.     DeleteDC(memGraphDC);
  115.     DeleteDC(GraphDC);
  116.     DeleteDC(ConDC);
  117.     exit(0);
  118. }
  119.  
  120. void win32_update_text(void) {
  121.     RECT r;
  122.  
  123.     GetClientRect(hConWnd, &r);
  124.     BitBlt(ConDC, 0, 0, r.right, r.bottom, memConDC, 0, 0, SRCCOPY);
  125. }
  126.  
  127. void win32_repaint_screen(void) {
  128.     SetFocus(hMainWnd);
  129. }
  130.  
  131. void win32_advance_line(void) {
  132.     TEXTMETRIC tm;
  133.     RECT r, inv, foo;
  134.     int xpos, ypos;
  135.  
  136.     GetClientRect(hConWnd, &r);
  137.     GetTextMetrics(memConDC, &tm);
  138.  
  139.     xpos = (tm.tmAveCharWidth * x_coord);
  140.     ypos = ((tm.tmHeight + tm.tmExternalLeading) * y_coord);
  141.  
  142.     if ((ypos + 2 * (tm.tmHeight + tm.tmExternalLeading)) >= r.bottom) {
  143.         ScrollDC(ConDC, 0, - (tm.tmHeight + tm.tmExternalLeading),
  144.                &r, &r, NULL, &inv);
  145.         FillRect(ConDC, &inv, GetStockObject(WHITE_BRUSH));
  146.         foo.left = 0;
  147.         foo.right = Xsofar;
  148.         foo.top = 0;
  149.         foo.bottom = Ysofar;
  150.         ScrollDC(memConDC, 0, - (tm.tmHeight + tm.tmExternalLeading),
  151.                &foo, &foo, NULL, &inv);
  152.         FillRect(memConDC, &inv, GetStockObject(WHITE_BRUSH));
  153.     }
  154. }
  155.  
  156. void draw_string(char *str) {
  157.     TEXTMETRIC tm;
  158.     int x, y;
  159.  
  160.     GetTextMetrics(memGraphDC, &tm);
  161.     x = turtlePen.h;
  162.     y = turtlePen.v;
  163.     TextOut(memGraphDC, x, y - tm.tmHeight, str, strlen(str));
  164.     TextOut(GraphDC, x, y - tm.tmHeight, str, strlen(str));
  165.     /* restore position */
  166.     moveto(x, y);
  167. }
  168.  
  169. char *eight_dot_three_helper(char *in) {
  170.     static char out[20];
  171.     char *filename, *extension;
  172.  
  173.     filename = strtok(in, ".");
  174.     extension = strtok(NULL, ".");
  175.  
  176.     if (extension)
  177.         sprintf(out, "%.8s.%.3s", filename, extension);
  178.     else
  179.         sprintf(out, "%.8s", filename);
  180.     return out;
  181. }
  182.  
  183. char *eight_dot_three(char *in) {
  184.     static char out[100];
  185.     char *last, *last_sep, *fear;
  186.     int index;
  187.  
  188.     if (last_sep = strrchr(in, '\\')) {
  189.         index = last_sep - in;
  190.         index++;
  191.         strncpy(out, in, index);
  192.         out[index] = '\0';
  193.         last = (char *)malloc((strlen(in) - index + 3) * sizeof(char));
  194.         strncpy(last, &in[index], strlen(in) - index);
  195.         last[strlen(in) - index] = '\0';
  196.     } else if (last_sep = strrchr(in, ':')) {
  197.         index = last_sep - in;
  198.         index++;
  199.         strncpy(out, in, index);
  200.         out[index] = '\0';
  201.         last = (char *)malloc((strlen(in) - index + 3) * sizeof(char));
  202.         strncpy(last, &in[index], strlen(in) - index);
  203.         last[strlen(in) - index] = '\0';
  204.     }
  205.     fear = eight_dot_three_helper(last);
  206.     strcat(out, fear);
  207.     free(last);
  208.     return out;
  209. }
  210.  
  211. void MoveCursor(int newx, int newy) {
  212.     MoveToEx(memGraphDC, newx, newy, NULL);
  213.     MoveToEx(GraphDC, newx, newy, NULL);
  214. }
  215.  
  216. void win32_erase_screen(void) {
  217.     RECT r;
  218.  
  219.     /* BLACK brush the whole window */
  220.     GetClientRect(hGraphWnd, &r);
  221.     PatBlt(memGraphDC, 0, 0, r.right, r.bottom, PATCOPY);
  222.     PatBlt(GraphDC, 0, 0, r.right, r.bottom, PATCOPY);
  223.     MoveCursor(screen_x_center, screen_y_center);
  224. }
  225.  
  226. void win32_set_bg(FIXNUM c) {
  227.     /*
  228.      * set global variables that denote the background color, create a new
  229.      * brush with the desired color, repaint the memory context, wait for
  230.      * WM_PAINT, and redraw the old display (using the records...)
  231.      */
  232.     back_ground = c;
  233.     DeleteObject(hbrush);
  234.     hbrush = CreateSolidBrush(palette[back_ground]);
  235.     SelectObject(memGraphDC, hbrush);
  236.     SelectObject(GraphDC, hbrush);
  237.     PatBlt(memGraphDC, 0, 0, maxX, maxY, PATCOPY);
  238.     PatBlt(GraphDC, 0, 0, maxX, maxY, PATCOPY);
  239.     SetBkColor(memGraphDC, palette[back_ground]);
  240.     SetBkColor(GraphDC, palette[back_ground]);
  241.     redraw_graphics();
  242. }
  243.  
  244. void win32_clear_text(void) {
  245.     // RECT r;
  246.     /*
  247.      * Draw over the entire client area, so that in split screen mode, for
  248.      * example, there are no ghosts, when the user returns to textscreen mode.
  249.      */
  250.  
  251.     // GetClientRect(hConWnd, &r);
  252.     FillRect(ConDC, &allRect, GetStockObject(WHITE_BRUSH));
  253.     BitBlt(memConDC, 0, 0, maxX, maxY, ConDC, 0, 0, SRCCOPY);
  254. }
  255.  
  256. LRESULT CALLBACK GraphWindowFunc(HWND hwnd, UINT message, WPARAM wParam,
  257.                  LPARAM lParam) {
  258.     PAINTSTRUCT ps;
  259.  
  260.     switch (message) {
  261.         case WM_CREATE:
  262.             /*
  263.              * Now, create a copy of the entire screen in memory to act as a virtual
  264.              * window to record turtle motions so they can be repainted in a
  265.              * WM_PAINT message.
  266.              */
  267.             GraphDC = GetDC(hwnd);
  268.             memGraphDC = CreateCompatibleDC(GraphDC);
  269.             maxX = GetSystemMetrics(SM_CXSCREEN);
  270.             maxY = GetSystemMetrics(SM_CYSCREEN);
  271.             hbitmG = CreateCompatibleBitmap(GraphDC, maxX, maxY);
  272.             SelectObject(memGraphDC, hbitmG);
  273.             hbitG = CreateCompatibleBitmap(GraphDC, maxX, maxY);
  274.             SelectObject(GraphDC, hbitG);
  275.             /*
  276.              * first-time initialization of the brush for the background requires
  277.              * setting the back_ground, and selecting the right color.  while
  278.              * there may be stock objects that contain the right color for the
  279.              * initial pen/brush, subsequent changes might try to delete these
  280.              * "stock" pens/brushes, and that would be "Bad".
  281.              */
  282.             back_ground = 0;
  283.             hbrush = CreateSolidBrush(palette[back_ground]);
  284.             SetBkColor(memGraphDC, palette[back_ground]);
  285.             SetBkColor(GraphDC, palette[back_ground]);
  286.             SelectObject(memGraphDC, hbrush);
  287.             SelectObject(GraphDC, hbrush);
  288.  
  289.             /*
  290.              * first-time initialization of the pen structure requires setting up
  291.              * all of the fields in the data first, then creating a new pen object
  292.              */
  293.             turtlePen.h = 0; /* ?? */
  294.             turtlePen.v = 0; /* ?? */
  295.             turtlePen.vis = 0;
  296.             turtlePen.mode = WIN_PEN_DOWN;
  297.             turtlePen.width = 1; /* default */
  298.             turtlePen.color = pen_color = old_pen_color = 7;
  299.             /* turtlePen.pattern = ... ? */
  300.             turtlePen.hpen = CreatePen(PS_SOLID, turtlePen.width,
  301.                        palette[turtlePen.color]);
  302.             SetTextColor(memGraphDC, palette[turtlePen.color]);
  303.             SetTextColor(GraphDC, palette[turtlePen.color]);
  304.             SelectObject(memGraphDC, turtlePen.hpen);
  305.             SelectObject(GraphDC, turtlePen.hpen);
  306.             PatBlt(memGraphDC, 0, 0, maxX, maxY, PATCOPY);
  307.             PatBlt(GraphDC, 0, 0, maxX, maxY, PATCOPY);
  308.             oldWidth = win32_screen_right();
  309.             oldHeight = win32_screen_bottom();
  310.             break;
  311.         case WM_USER:
  312.             InvalidateRect(hGraphWnd, NULL, 1);
  313.         case WM_PAINT:
  314.             BeginPaint(hGraphWnd, &ps);
  315.             BitBlt(ps.hdc, 0, 0, maxX, maxY, memGraphDC, 0, 0, SRCCOPY);
  316.             EndPaint(hGraphWnd, &ps);
  317.             break;
  318.         case WM_DESTROY:  /* end program */
  319.         PostQuitMessage(0);
  320.             break;
  321.         default:
  322.             return DefWindowProc(hwnd, message, wParam, lParam);
  323.     }
  324.     return 0;
  325. }
  326.  
  327. void win32_text_cursor(void) {
  328.     print_char(stdout, '_');
  329.     update_coords('\b');
  330. }
  331.  
  332. LRESULT CALLBACK ConsoleWindowFunc(HWND hwnd, UINT message, WPARAM wParam,
  333.                    LPARAM lParam) {
  334.     HFONT hfont;
  335.     PAINTSTRUCT ps;
  336.     RECT rect;
  337.     TEXTMETRIC tm;
  338.  
  339.     switch (message) {
  340.         case WM_CREATE:
  341.             ConDC = GetDC(hwnd);
  342.             memConDC = CreateCompatibleDC(ConDC);
  343.             allRect.left = allRect.top = 0;
  344.             allRect.right = maxX = GetSystemMetrics(SM_CXSCREEN);
  345.             allRect.bottom = maxY = GetSystemMetrics(SM_CYSCREEN);
  346.             hbitmC = CreateCompatibleBitmap(ConDC, maxX, maxY);
  347.             SelectObject(memConDC, hbitmC);
  348.             hbitC = CreateCompatibleBitmap(ConDC, maxX, maxY);
  349.             SelectObject(ConDC, hbitC);
  350.         hfont = GetStockObject(OEM_FIXED_FONT);
  351.             SelectObject(memConDC, hfont);
  352.             SelectObject(ConDC, hfont);
  353.             hbrush = GetStockObject(WHITE_BRUSH);
  354.             SelectObject(memConDC, hbrush);
  355.             SelectObject(ConDC, hbrush);
  356.             FillRect(memConDC, &allRect, hbrush);
  357.             GetClientRect(hConWnd, &rect);
  358.             GetTextMetrics(ConDC, &tm);
  359.             break;
  360.         case WM_CHAR:
  361.             if (char_mode) {
  362.             buffered_char = (char)wParam;
  363.             char_avail++;
  364.             return 0;
  365.             }
  366.         print_space(stdout);        // flush cursor
  367.         update_coords('\b');
  368.             if ((char) wParam == '\b') {
  369.             if (cur_index > 0) {
  370.             update_coords('\b');
  371.             print_space(stdout);
  372.             update_coords('\b');
  373.             win32_text_cursor();
  374.             cur_index--;
  375.         } else {
  376.             MessageBeep(0);
  377.             win32_text_cursor();
  378.         }
  379.             } else if ((char) wParam == '\r') {    // line ready, let's go!
  380.             print_char(stdout, '\n');
  381.  
  382.             win32_lines[cur_line][cur_index++] = '\n'; // reader code expects \n
  383.             cur_len = cur_index;
  384.             read_line = (char *)malloc((strlen(win32_lines[cur_line]) + 1) *
  385.                                 sizeof(char));
  386.             strncpy(read_line, win32_lines[cur_line], cur_index + 1);
  387.             line_avail = 1;
  388.             read_index = 0;
  389.             if (++cur_line >= NUM_LINES)
  390.                 cur_line %= NUM_LINES;  // wrap around
  391.             cur_index = 0;
  392.             return 0;
  393.             } else if ((char)wParam == 17 || (char)wParam == 23) {
  394.             print_char(stdout, '\n');
  395.             read_line = (char *)malloc(sizeof(char));
  396.             *read_line = (char)wParam;
  397.             line_avail = 1;
  398.             read_index = 0;
  399.             cur_index = 0;
  400.             return 0;
  401.             } else {
  402.             win32_lines[cur_line][cur_index++] = (char) wParam;
  403.             print_char(stdout, (char) wParam);
  404.         win32_text_cursor();
  405.             }
  406.             break;
  407.        case WM_USER:
  408.             InvalidateRect(hConWnd, NULL, 1);
  409.        case WM_PAINT:
  410.             BeginPaint(hConWnd, &ps);
  411.             GetClientRect(ps.hdc, &rect);
  412.             BitBlt(ps.hdc, 0, 0, rect.right, rect.bottom, memConDC, 0, 0, SRCCOPY);
  413.             EndPaint(hConWnd, &ps);
  414.             break;
  415.         case WM_DESTROY:  /* end program */
  416.         PostQuitMessage(0);
  417.             break;
  418.         default:
  419.             return DefWindowProc(hwnd, message, wParam, lParam);
  420.     }
  421.     return 0;
  422. }
  423.  
  424. int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs,
  425.            int nWinMode) {
  426.     NODE *exec_list = NIL;
  427.     WNDCLASSEX wGraphCL, wConCL, wParentCL;
  428.     RECT r;
  429.     TEXTMETRIC tm;
  430.     int i;
  431.     char *argv[20];
  432.     int argc;
  433.  
  434.     /* Set up the parameters that define the Graphics window's class */
  435.     wParentCL.hInstance = hThisInst;
  436.     wParentCL.lpszClassName = szWinName;
  437.     wParentCL.lpfnWndProc = ParentWindowFunc;
  438.     wParentCL.style = 0;
  439.     wParentCL.cbSize = sizeof(WNDCLASSEX);
  440.     wParentCL.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  441.     wParentCL.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  442.     wParentCL.hCursor = LoadCursor(NULL, IDC_ARROW);
  443.     wParentCL.lpszMenuName = NULL;
  444.     wParentCL.cbClsExtra = 0;
  445.     wParentCL.cbWndExtra = 0;
  446.     wParentCL.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
  447.  
  448.     /* Set up the parameters that define the "Console" window's class */
  449.     wConCL.hInstance = hThisInst;
  450.     wConCL.lpszClassName = szConWinName;
  451.     wConCL.lpfnWndProc = ConsoleWindowFunc;
  452.     wConCL.style = 0;
  453.     wConCL.cbSize = sizeof(WNDCLASSEX);
  454.     wConCL.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  455.     wConCL.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  456.     wConCL.hCursor = LoadCursor(NULL, IDC_ARROW);
  457.     wConCL.lpszMenuName = NULL;
  458.     wConCL.cbClsExtra = 0;
  459.     wConCL.cbWndExtra = 0;
  460.     wConCL.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  461.  
  462.     /* Set up the parameters that define the Graphics window's class */
  463.     wGraphCL.hInstance = hThisInst;
  464.     wGraphCL.lpszClassName = szGraphWinName;
  465.     wGraphCL.lpfnWndProc = GraphWindowFunc;
  466.     wGraphCL.style = 0;
  467.     wGraphCL.cbSize = sizeof(WNDCLASSEX);
  468.     wGraphCL.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  469.     wGraphCL.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  470.     wGraphCL.hCursor = LoadCursor(NULL, IDC_ARROW);
  471.     wGraphCL.lpszMenuName = NULL;
  472.     wGraphCL.cbClsExtra = 0;
  473.     wGraphCL.cbWndExtra = 0;
  474.     wGraphCL.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
  475.  
  476.     /* Initially, the program is in its "Text only" mode */
  477.     in_graphics_mode = in_splitscreen = 0;
  478.  
  479.     /* Register the Parent (main) window */
  480.     if (!RegisterClassEx(&wParentCL))
  481.         return 0;
  482.     /* Register the Graphics (child) window */
  483.     if (!RegisterClassEx(&wGraphCL))
  484.         return 0;
  485.     /* Register the Console (child) window */
  486.     if (!RegisterClassEx(&wConCL))
  487.         return 0;
  488.  
  489.     win32_init_palette();
  490.  
  491.     hMainWnd = CreateWindow(szWinName, "UCB Logo", WS_OVERLAPPEDWINDOW,
  492.                 CW_USEDEFAULT, CW_USEDEFAULT,
  493.                 CW_USEDEFAULT, CW_USEDEFAULT,
  494.                 HWND_DESKTOP,
  495.                 NULL, hThisInst, NULL);
  496.  
  497.     win32_lines = (char **) malloc(NUM_LINES * sizeof(char *));
  498.     if (win32_lines == NULL) {
  499.         // print some message and puke
  500.     }
  501.     for (i = 0; i < NUM_LINES; i++)
  502.         win32_lines[i] = (char *) malloc(CHARS_PER_LINE * sizeof(char));
  503.     so_arr[0] = '\1'; so_arr[1] = '\0';
  504.     se_arr[0] = '\2'; se_arr[1] = '\0';
  505.  
  506.     ShowWindow(hMainWnd, nWinMode);
  507.     UpdateWindow(hMainWnd);
  508.  
  509.     /*
  510.      * at this point, all of the windows have been created, so it's safe to
  511.      * check on their size
  512.      */
  513.  
  514.     GetTextMetrics(memConDC, &tm);
  515.     GetClientRect(hConWnd, &r);
  516.  
  517.     x_coord = y_coord = 0;
  518.  
  519.     x_max = r.right;
  520.     x_max /= tm.tmAveCharWidth;
  521.     x_max--;  // this eliminates splitting a character over the right border
  522.  
  523.     y_max = r.bottom;
  524.     y_max /= (tm.tmHeight + tm.tmExternalLeading);
  525.     y_max--;
  526.     Xsofar = r.right;
  527.     Ysofar = r.bottom;
  528.  
  529.     argc = 1;
  530.     argv[0] = strtok(lpszArgs, " \t\r\n");
  531.     while (argv[argc] = strtok(NULL, " \t\r\n"))
  532.         argc++;
  533.  
  534.     (void) main(argc, argv);
  535.     win32_go_away();
  536.     return 0;
  537. }
  538.  
  539. NODE *win32_get_node_pen_pattern(void) {
  540.     return cons(make_intnode(-1), NIL);
  541. }
  542.  
  543. NODE *win32_get_node_pen_mode(void) {
  544.     if (in_erase_mode)
  545.         return make_static_strnode("erase");
  546.     if (GetROP2(memGraphDC) == R2_XORPEN)
  547.         return make_static_strnode("reverse");
  548.     return make_static_strnode("paint");
  549. }
  550.  
  551. void logofill(void) {
  552.     COLORREF col;
  553.  
  554.     DeleteObject(hbrush);
  555.     hbrush = CreateSolidBrush(palette[pen_color]);
  556.     SelectObject(memGraphDC, hbrush);
  557.     SelectObject(GraphDC, hbrush);
  558.     col = GetPixel(memGraphDC, g_round(screen_x_coord), g_round(screen_y_coord));
  559.     (void)ExtFloodFill(memGraphDC, g_round(screen_x_coord),
  560.                  g_round(screen_y_coord), col, FLOODFILLSURFACE);
  561.     (void)ExtFloodFill(GraphDC, g_round(screen_x_coord),
  562.                  g_round(screen_y_coord), col, FLOODFILLSURFACE);
  563.     DeleteObject(hbrush);
  564.     hbrush = CreateSolidBrush(palette[back_ground]);
  565.     SelectObject(memGraphDC, hbrush);
  566.     SelectObject(GraphDC, hbrush);
  567. }
  568.  
  569. void get_pen_pattern(void) {
  570. }
  571.  
  572. void set_pen_pattern(void) {
  573. }
  574.  
  575. void get_palette(int slot, unsigned int *r, unsigned int *g, unsigned int *b) {
  576.     *r = (palette[slot % 200] & 0x00ff0000) >> 16;
  577.     *g = (palette[slot % 200] & 0x0000ff00) >> 8;
  578.     *b = (palette[slot % 200] & 0x000000ff);
  579. }
  580.  
  581. void set_palette(int slot, unsigned int r, unsigned int g, unsigned int b) {
  582.     if (slot > 199)  // 200 rgb values
  583.         return;
  584.     palette[slot] = RGB(r, g, b);
  585. }
  586.  
  587. void save_pen(pen_info *p) {
  588.     POINT pt;
  589.  
  590.     p->vis = pen_vis;
  591.     p->color = pen_color;
  592.     GetCurrentPositionEx(memGraphDC, &pt);
  593.     p->h = (int) pt.x;
  594.     p->v = (int) pt.y;
  595.     p->width = turtlePen.width;
  596.     p->mode = turtlePen.mode;
  597. }
  598.  
  599. void restore_pen(pen_info *p) {
  600.     pen_vis = p->vis;
  601.     MoveCursor(p->h, p->v);
  602.     turtlePen.mode = p->mode;
  603.     win32_set_pen_mode(turtlePen.mode);
  604.     turtlePen.width = p->width;
  605.     if (p->color != pen_color) {
  606.         pen_color = p->color;
  607.         DeleteObject(turtlePen.hpen);
  608.         turtlePen.hpen = CreatePen(PS_SOLID, turtlePen.width, palette[pen_color]);
  609.         SelectObject(memGraphDC, turtlePen.hpen);
  610.         SelectObject(GraphDC, turtlePen.hpen);
  611.     }
  612. }
  613.  
  614. void set_list_pen_pattern(void) {
  615. }
  616.  
  617. void label(char *str) {
  618.     draw_string(str);
  619. }
  620.  
  621. void plain_xor_pen(void) {
  622.     SetROP2(memGraphDC, R2_XORPEN);
  623.     SetROP2(GraphDC, R2_XORPEN);
  624. }
  625.  
  626. BOOLEAN check_ibm_stop(void) {
  627.     MSG msg;
  628.     SHORT s;
  629.     static int count;
  630.  
  631.     if ((s = GetAsyncKeyState(VK_CONTROL)) < 0) {
  632.         if ((s = GetAsyncKeyState(65 + ('q' - 'a')) < 0)) {
  633.             err_logo(STOP_ERROR,NIL);
  634.             return (1);
  635.         }
  636.         if ((s = GetAsyncKeyState(65 + ('w' - 'a')) < 0)) {
  637.             // control w
  638.             to_pending = 0;
  639.             lpause(NIL);
  640.         }
  641.     }
  642.     count++;
  643.     count %= 300;  // empirical value
  644.  
  645.     if (!count) {
  646.         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  647.             if (msg.message == WM_QUIT)
  648.         ;
  649.             else {
  650.         TranslateMessage(&msg);
  651.         DispatchMessage(&msg);
  652.             }
  653.         }
  654.     }
  655.     return FALSE;
  656. }
  657.  
  658. void win32_con_full_screen(void) {
  659.     RECT r;
  660.     PAINTSTRUCT ps;
  661.     int deltaX, deltaY;
  662.  
  663.     if (in_graphics_mode && !in_splitscreen)
  664.         return;
  665.     in_graphics_mode = 1;
  666.     in_splitscreen = 0;
  667.  
  668.     GetClientRect(hMainWnd, &r);
  669.     /* position coordinates are relative to the parent's frame. */
  670.     MoveWindow(hGraphWnd, 0, 0, r.right, r.bottom, TRUE);
  671.     ShowWindow(hConWnd, SW_HIDE);
  672.     ShowWindow(hGraphWnd, SW_SHOWNORMAL);
  673.     BeginPaint(hGraphWnd, &ps);
  674.     BitBlt(ps.hdc, 0, 0, maxX, maxY, memGraphDC, 0, 0, SRCCOPY);
  675.     EndPaint(hGraphWnd, &ps);
  676.     deltaX = (win32_screen_right()-oldWidth)/2;
  677.     deltaY = (win32_screen_bottom()-oldHeight)/2;
  678.     oldWidth = win32_screen_right();
  679.     oldHeight = win32_screen_bottom();
  680.     if (deltaX != 0 || deltaY != 0) {
  681.         resize_record(deltaX, deltaY);
  682.         redraw_graphics();
  683.     }
  684. }
  685.  
  686. void win32_prepare_draw(void) {
  687.     if (in_graphics_mode) return;
  688.     win32_con_split_screen();
  689. }
  690.  
  691. long upscroll_text(int limit) {
  692.     TEXTMETRIC tm;
  693.     RECT r, inv;
  694.     int y_new, offset, old, rbot;
  695.  
  696.     GetClientRect(hMainWnd, &r);
  697.     GetTextMetrics(memConDC, &tm);
  698.     y_new = r.bottom;
  699.     y_new /= (tm.tmHeight + tm.tmExternalLeading);
  700.     rbot = y_new * (tm.tmHeight + tm.tmExternalLeading);
  701.     y_new--;
  702.     if (limit > 0 && limit < y_new) {
  703.         y_new = limit;
  704.         rbot = r.bottom = (limit+1) * (tm.tmHeight + tm.tmExternalLeading);
  705.     }
  706.     offset = y_coord - y_new;
  707.     if (offset > 0) {
  708.         old = (y_coord + 1) * (tm.tmHeight + tm.tmExternalLeading);
  709.         BitBlt(ConDC, 0, 0, maxX, maxY, memConDC, 0, old-rbot, SRCCOPY);
  710.         inv.left = 0;
  711.         inv.right = allRect.right;
  712.         inv.top = rbot - 1;
  713.         inv.bottom = allRect.bottom;
  714.         BitBlt(memConDC, 0, 0, maxX, maxY, ConDC, 0, 0, SRCCOPY);
  715.         FillRect(memConDC, &inv, GetStockObject(WHITE_BRUSH));
  716.         y_coord = y_new;
  717.     }
  718.     return r.bottom;
  719. }
  720.  
  721. void reshow_text(void) {
  722.     TEXTMETRIC tm;
  723.     RECT r, foo;
  724.  
  725.     ShowWindow(hConWnd, SW_SHOW);
  726.     GetClientRect(hConWnd, &r);
  727.     GetTextMetrics(memConDC, &tm);
  728.     FillRect(ConDC, &r, GetStockObject(WHITE_BRUSH));
  729.     if (r.right > Xsofar) {
  730.         foo.left = Xsofar;
  731.         foo.right = r.right;
  732.         foo.top = 0;
  733.         foo.bottom = allRect.bottom;
  734.         FillRect(memConDC, &foo, GetStockObject(WHITE_BRUSH));
  735.         Xsofar = r.right;
  736.     }
  737.     if (r.bottom > Ysofar) {
  738.         foo.left = 0;
  739.         foo.right = r.right;
  740.         foo.top = Ysofar;
  741.         foo.bottom = r.bottom;
  742.         FillRect(memConDC, &foo, GetStockObject(WHITE_BRUSH));
  743.         Ysofar = r.bottom;
  744.     }
  745.     BitBlt(ConDC, 0, 0, r.right, r.bottom, memConDC, 0, 0, SRCCOPY);
  746.     ValidateRect(hConWnd, &r);
  747.  
  748.     x_max = r.right;
  749.     x_max /= tm.tmAveCharWidth;
  750.     x_max--;
  751.  
  752.     y_max = r.bottom;
  753.     y_max /= (tm.tmHeight + tm.tmExternalLeading);
  754.     y_max--;
  755. }
  756.  
  757. void win32_con_split_screen(void) {
  758.     RECT r;
  759.     PAINTSTRUCT ps;
  760.     long vert;
  761.     int deltaX, deltaY;
  762.  
  763.     if (in_graphics_mode && in_splitscreen)
  764.         return;
  765.     in_graphics_mode = in_splitscreen = 1;
  766.  
  767.     vert = upscroll_text(3);
  768.     GetClientRect(hMainWnd, &r);
  769.     MoveWindow(hConWnd, 0, r.bottom - vert - 6, r.right, vert + 6, FALSE);
  770.     MoveWindow(hGraphWnd, 0, 0, r.right, r.bottom - vert - 8, TRUE);
  771.     ShowWindow(hGraphWnd, SW_SHOW);
  772.     BeginPaint(hGraphWnd, &ps);
  773.     BitBlt(ps.hdc, 0, 0, maxX, maxY, memGraphDC, 0, 0, SRCCOPY);
  774.     EndPaint(hGraphWnd, &ps);
  775.     reshow_text();
  776.     deltaX = (win32_screen_right()-oldWidth)/2;
  777.     deltaY = (win32_screen_bottom()-oldHeight)/2;
  778.     oldWidth = win32_screen_right();
  779.     oldHeight = win32_screen_bottom();
  780.     if (deltaX != 0 || deltaY != 0) {
  781.         resize_record(deltaX, deltaY);
  782.         redraw_graphics();
  783.     }
  784.     if (!seen_once) {
  785.         seen_once = TRUE;
  786.         lclearscreen(NIL);
  787.     }
  788. }
  789.  
  790. void win32_con_text_screen(void) {
  791.     RECT r;
  792.  
  793.     if (!in_graphics_mode)
  794.         return;
  795.     in_graphics_mode = in_splitscreen = 0;
  796.  
  797.     (void)upscroll_text(0);
  798.     GetClientRect(hMainWnd, &r);
  799.     MoveWindow(hConWnd, 0, 0, r.right, r.bottom, FALSE);
  800.     ShowWindow(hGraphWnd, SW_HIDE);
  801.     reshow_text();
  802. }
  803.  
  804. void show_if_not_shown(void) {
  805.     if (!in_graphics_mode) {
  806.         ShowWindow(hGraphWnd, SW_NORMAL);
  807.         in_graphics_mode = in_splitscreen = 1;
  808.  
  809.         lclearscreen(NIL);
  810.         return ;
  811.     }
  812. }
  813.     
  814. void win32_turtle_prep(void) {
  815.     if (in_erase_mode) {
  816.         /* current pen color != "real" pen color */
  817.         DeleteObject(turtlePen.hpen);
  818.         turtlePen.hpen = CreatePen(PS_SOLID, turtlePen.width, palette[pen_color]);
  819.     }
  820.     update_pos = FALSE;
  821.     SelectObject(memGraphDC, turtlePen.hpen);
  822.     SelectObject(GraphDC, turtlePen.hpen);
  823.     pre_turtle_pen_mode = SetROP2(memGraphDC, R2_XORPEN);
  824.     (void)SetROP2(GraphDC, R2_XORPEN);
  825. }
  826.  
  827. void win32_turtle_end(void) {
  828.     if (in_erase_mode) {
  829.         /*
  830.          * current pen color should now be set to background color to resume
  831.          * "erase mode"
  832.          */
  833.         DeleteObject(turtlePen.hpen);
  834.         turtlePen.hpen = CreatePen(PS_SOLID, turtlePen.width, palette[back_ground]);
  835.     }
  836.     update_pos = TRUE;
  837.     SelectObject(memGraphDC, turtlePen.hpen);
  838.     SelectObject(GraphDC, turtlePen.hpen);
  839.     SetROP2(memGraphDC, pre_turtle_pen_mode);
  840.     SetROP2(GraphDC, pre_turtle_pen_mode);
  841. }
  842.  
  843. void win32_init_palette(void) {
  844.     palette[0] = RGB(0, 0, 0); /* black */
  845.     palette[1] = RGB(0, 0, 255); /* blue */
  846.     palette[2] = RGB(0, 255, 0); /* green */
  847.     palette[3] = RGB(0, 255, 255); /* cyan */
  848.     palette[4] = RGB(255, 0, 0); /* red */
  849.     palette[5] = RGB(255, 0, 255); /* magenta */
  850.     palette[6] = RGB(255, 255, 0); /* yellow */
  851.     palette[7] = RGB(255, 255, 255); /* white */
  852.     palette[8] = RGB(155, 96, 59);    /* brown */
  853.     palette[9] = RGB(197, 136, 18); /* tan */
  854.     palette[10] = RGB(100, 162, 64); /* forest */
  855.     palette[11] = RGB(120, 187, 187); /* aqua */
  856.     palette[12] = RGB(255, 149, 119); /* salmon */
  857.     palette[13] = RGB(144, 113, 208); /* purple */
  858.     palette[14] = RGB(255, 163, 0); /* orange */
  859.     palette[15] = RGB(183, 183, 183); /* gray */
  860.     /* rest are user defined */
  861. }
  862.  
  863. void win32_set_pen_color(int c) {
  864.     draw_turtle();
  865.     turtlePen.color = pen_color = c;
  866.     DeleteObject(turtlePen.hpen);
  867.     turtlePen.hpen = CreatePen(PS_SOLID, turtlePen.width,
  868.                      palette[turtlePen.color]);
  869.     SelectObject(memGraphDC, turtlePen.hpen);
  870.     SelectObject(GraphDC, turtlePen.hpen);
  871.     SetTextColor(memGraphDC, palette[pen_color]);
  872.     SetTextColor(GraphDC, palette[pen_color]);
  873.     draw_turtle();
  874. }
  875.  
  876. int win32_set_pen_width(int w) {
  877.     int old;
  878.  
  879.     old = turtlePen.width;
  880.     turtlePen.width = w;
  881.     DeleteObject(turtlePen.hpen);
  882.     turtlePen.hpen = CreatePen(PS_SOLID, turtlePen.width,
  883.                      palette[turtlePen.color]);
  884.     SelectObject(memGraphDC, turtlePen.hpen);
  885.     SelectObject(GraphDC, turtlePen.hpen);
  886.     return old;
  887. }
  888.  
  889. NODE *win32_lsetcursor(NODE *args) {
  890.     NODE *arg;
  891.     TEXTMETRIC tm;
  892.     int xpos, ypos;
  893.  
  894.     GetTextMetrics(memConDC, &tm);
  895.  
  896.     arg = pos_int_vector_arg(args);
  897.     if (NOT_THROWING) {
  898.         x_coord = x_margin + getint(car(arg));
  899.         y_coord = y_margin + getint(cadr(arg));
  900.         while ((x_coord >= x_max || y_coord >= y_max) && NOT_THROWING) {
  901.             setcar(args, err_logo(BAD_DATA, arg));
  902.             if (NOT_THROWING) {
  903.         arg = pos_int_vector_arg(args);
  904.         x_coord = x_margin + getint(car(arg));
  905.         y_coord = y_margin + getint(cadr(arg));
  906.         }
  907.     }
  908.     }
  909.  
  910.     xpos = tm.tmAveCharWidth * x_coord;
  911.     ypos = (tm.tmHeight + tm.tmExternalLeading) * y_coord;
  912.  
  913.     if (NOT_THROWING) {
  914.         MoveToEx(memConDC, xpos, ypos, NULL);
  915.         MoveToEx(ConDC, xpos, ypos, NULL);
  916.     }
  917.     return(UNBOUND);
  918. }
  919.  
  920. void win32_pen_erase(void) {
  921.     win32_set_pen_mode(WIN_PEN_ERASE);
  922. }
  923.  
  924. void win32_pen_down(void) {
  925.     win32_set_pen_mode(WIN_PEN_DOWN);
  926. }
  927.  
  928. void win32_pen_reverse(void) {
  929.     win32_set_pen_mode(WIN_PEN_REVERSE);
  930. }
  931.  
  932. void win32_set_pen_mode(int newmode) {
  933.     int rop2_mode, newpc;
  934.  
  935.     turtlePen.mode = newmode;
  936.  
  937.     if (newmode == WIN_PEN_ERASE)
  938.         in_erase_mode = TRUE;
  939.     else
  940.         in_erase_mode = FALSE;
  941.  
  942.     if (newmode == WIN_PEN_REVERSE)
  943.         rop2_mode = R2_XORPEN;
  944.     else
  945.         rop2_mode = R2_COPYPEN;
  946.  
  947.     SetROP2(memGraphDC, rop2_mode);
  948.     SetROP2(GraphDC, rop2_mode);
  949.  
  950.     if (newmode != WIN_PEN_REVERSE) {
  951.         if (newmode == WIN_PEN_ERASE)
  952.             newpc = back_ground;
  953.         else
  954.             newpc = pen_color;
  955.         DeleteObject(turtlePen.hpen);
  956.         turtlePen.hpen = CreatePen(PS_SOLID, turtlePen.width, palette[newpc]);
  957.         SelectObject(memGraphDC, turtlePen.hpen);
  958.         SelectObject(GraphDC, turtlePen.hpen);
  959.     }
  960. }
  961.  
  962. LRESULT CALLBACK ParentWindowFunc(HWND hwnd, UINT message, WPARAM wParam,
  963.                  LPARAM lParam) {
  964.     switch (message) {
  965.         case WM_CHAR:
  966.         SendMessage(hConWnd, WM_CHAR, wParam, lParam);
  967.             break;
  968.         case WM_SIZE:
  969.             if (!in_graphics_mode) {   // Text screen mode
  970.                 in_graphics_mode = 1;
  971.                 win32_con_text_screen();
  972.             } else if (in_splitscreen) {
  973.                 in_splitscreen = 0;
  974.                 win32_con_split_screen();
  975.             } else {
  976.                 in_graphics_mode = 0;
  977.                 win32_con_full_screen();
  978.             }
  979.             break;
  980.         case WM_MOVE:
  981.         case WM_SETFOCUS:
  982.         case WM_EXITMENULOOP:
  983.             if (!in_graphics_mode || in_splitscreen)
  984.                 SendMessage(hConWnd, WM_USER, wParam, lParam);
  985.             if (in_graphics_mode)
  986.                 SendMessage(hGraphWnd, WM_USER, wParam, lParam);
  987.             win32_update_text();
  988.             break;
  989.         case WM_PAINT:
  990.             /*
  991.              * The parent window really has nothing to draw.  Therefore, all that
  992.              * the parent window's paint function does is dispatch the appropriate
  993.              * message to the child window.
  994.              */
  995.             if (!in_graphics_mode || in_splitscreen)
  996.         SendMessage(hConWnd, WM_PAINT, wParam, lParam);
  997.             if (in_graphics_mode)
  998.         SendMessage(hGraphWnd, WM_PAINT, wParam, lParam);
  999.             break;
  1000.         case WM_CREATE:
  1001.             hConWnd = CreateWindow(szConWinName, NULL,
  1002.                    WS_CHILDWINDOW | WS_VISIBLE | WS_BORDER,
  1003.                    0, 0, 0, 0,
  1004.                    hwnd, (HMENU) (2 << 8),
  1005.                    (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),
  1006.                    NULL);
  1007.             hGraphWnd = CreateWindow(szGraphWinName, NULL,
  1008.                      WS_CHILDWINDOW | WS_VISIBLE | WS_BORDER,
  1009.                      0, 0, 0, 0,
  1010.                      hwnd, (HMENU) (4 << 8),
  1011.                      (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),
  1012.                      NULL);
  1013.  
  1014.             break;
  1015.         case WM_DESTROY:  /* end program */
  1016.         win32_go_away();
  1017.             break;
  1018.         default:
  1019.             return DefWindowProc(hwnd, message, wParam, lParam);
  1020.     }
  1021.     return 0;
  1022. }
  1023.  
  1024. void CharOut(char c) {
  1025.     TEXTMETRIC tm;
  1026.     RECT r;
  1027.     int xpos, ypos;
  1028.     char nog[3];
  1029.  
  1030.     sprintf(nog, "%c", c);
  1031.  
  1032.     GetTextMetrics(memConDC, &tm);
  1033.     xpos = tm.tmAveCharWidth * x_coord;
  1034.     ypos = (tm.tmHeight + tm.tmExternalLeading) * y_coord;
  1035.  
  1036.     r.left = xpos;
  1037.     r.right = (xpos + tm.tmAveCharWidth);
  1038.  
  1039.     r.top = ypos;
  1040.     r.bottom = (ypos + tm.tmHeight + tm.tmExternalLeading);
  1041.  
  1042.     TextOut(memConDC, xpos, ypos, nog, 1);
  1043.     TextOut(ConDC, xpos, ypos, nog, 1);
  1044. }
  1045.  
  1046. int win32_putc(char c, FILE *strm) {
  1047.     if (strm == stdout || strm == stderr) {
  1048.         if (c == '\n')
  1049.             win32_advance_line();
  1050.     else if (c == '\t') /* do nothing */ ;
  1051.         else {
  1052.             if (x_coord == x_max)
  1053.         new_line(strm);
  1054.             CharOut(c);
  1055.         }
  1056.         return 0;
  1057.     }
  1058.     return putc(c, strm);
  1059. }
  1060.  
  1061. void win32_charmode_on(void) {
  1062.     char_mode = 1;
  1063. }
  1064.  
  1065. void win32_charmode_off(void) {
  1066.     char_mode = 0;
  1067. }
  1068.  
  1069. void ibm_bold_mode(void) {
  1070.     SetTextColor(memConDC, RGB(255, 255, 255));
  1071.     SetTextColor(ConDC, RGB(255, 255, 255));
  1072.     SetBkColor(memConDC, RGB(0, 0, 0));
  1073.     SetBkColor(ConDC, RGB(0, 0, 0));
  1074. }
  1075.  
  1076. void ibm_plain_mode(void) {
  1077.     SetTextColor(memConDC, RGB(0, 0, 0));
  1078.     SetTextColor(ConDC, RGB(0, 0, 0));
  1079.     SetBkColor(memConDC, RGB(255, 255, 255));
  1080.     SetBkColor(ConDC, RGB(255, 255, 255));
  1081. }
  1082.