home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / ntwinio.c < prev    next >
C/C++ Source or Header  |  1998-09-27  |  62KB  |  2,748 lines

  1. /*
  2.  * Uses the Win32 screen API.
  3.  *
  4.  * $Header: /usr/build/vile/vile/RCS/ntwinio.c,v 1.34 1998/09/28 01:05:51 cmorgan Exp $
  5.  * Written by T.E.Dickey for vile (october 1997).
  6.  * -- improvements by Clark Morgan (see w32cbrd.c, w32pipe.c).
  7.  */
  8.  
  9. #include <windows.h>
  10. #include <windowsx.h>
  11. #include <commdlg.h>
  12. #include <stdlib.h>
  13. #include <math.h>
  14.  
  15. #define    termdef    1            /* don't define "term" external */
  16.  
  17. #include        "estruct.h"
  18. #include        "edef.h"
  19. #include        "pscreen.h"
  20.  
  21. #undef RECT    /* FIXME: symbol conflict */
  22.  
  23. #define MIN_ROWS MINWLNS
  24. #define MIN_COLS 15
  25.  
  26. #define FIXME_POSCHANGING 1        /* this doesn't seem to help */
  27. #define FIXME_RECUR_SB 0        /* I'm not sure this is needed */
  28.  
  29. #if OPT_TRACE
  30. #define IGN_PROC(tag,name) \
  31.     case name: \
  32.         TRACE((tag #name " (ignored)\n")) \
  33.         break;
  34.  
  35. #define DEF_PROC(tag,name) \
  36.     case name: \
  37.         TRACE((tag #name " (%s)\n", which_window(hWnd))) \
  38.         return (DefWindowProc(hWnd, message, wParam, lParam))
  39. #else
  40. #define IGN_PROC(tag,name) case name: break;
  41. #define DEF_PROC(tag,name) /*nothing*/
  42. #endif
  43.  
  44. #define MAIN_CLASS "VileMain"
  45. #define TEXT_CLASS "VileText"
  46. #define SCRL_CLASS "SCROLLBAR"
  47. #define GRIP_CLASS "VileResize"
  48.  
  49. #define MY_APPLE "Vile Application"
  50.  
  51. #define MY_FONT  SYSTEM_FIXED_FONT    /* or ANSI_FIXED_FONT        */
  52. #define GetMyFont() vile_font
  53.  
  54. #define MM_FILE 1
  55. #define MM_FONT 2
  56.  
  57. #define NROW    128            /* Max Screen size.        */
  58. #define NCOL    256            /* Edit if you want to.         */
  59. #define    MARGIN    8            /* size of minimum margin and    */
  60. #define    SCRSIZ    64            /* scroll size for extended lines */
  61. #define    NPAUSE    200            /* # times thru update to pause */
  62. #define NOKYMAP (-1)
  63.  
  64. #define SetCols(value) term.t_ncol = cur_win->cols = value
  65. #define SetRows(value) term.t_nrow = cur_win->rows = value
  66.  
  67. #define    AttrColor(b,f)    ((WORD)(((ctrans[b] & 15) << 4) | (ctrans[f] & 15)))
  68.  
  69. #define RowToPixel(n) ((n) * nLineHeight)
  70. #define ColToPixel(n) ((n) * nCharWidth)
  71.  
  72. #define PixelToRow(n) ((n) / nLineHeight)
  73. #define PixelToCol(n) ((n) / nCharWidth)
  74.  
  75. #define RectToCols(rect) (PixelToCol(rect.right - rect.left - SbWidth))
  76. #define RectToRows(rect) (PixelToRow(rect.bottom - rect.top))
  77.  
  78. #if OPT_SCROLLBARS
  79. #define SbWidth   nLineHeight
  80. #else
  81. #define SbWidth   0
  82. #endif
  83.  
  84. static    int    ntgetch        (void);
  85. static    void    ntmove        (int, int);
  86. static    void    nteeol        (void);
  87. static    void    nteeop        (void);
  88. static    void    ntbeep        (void);
  89. static    void    ntopen        (void);
  90. static    void    ntrev        (UINT);
  91. static    int    ntcres        (const char *);
  92. static    void    ntclose        (void);
  93. static    void    ntputc        (int);
  94. static    int    nttypahead    (void);
  95. static    void    ntkopen        (void);
  96. static    void    ntkclose    (void);
  97. #if OPT_COLOR
  98. static    void    ntfcol        (int);
  99. static    void    ntbcol        (int);
  100. #endif
  101. static    void    ntflush        (void);
  102. static    void    ntscroll    (int, int, int);
  103. #if OPT_ICURSOR
  104. static    void    nticursor    (int);
  105. #endif
  106. #if OPT_TITLE
  107. static    void    nttitle        (char *);
  108. #endif
  109.  
  110. static    HANDLE    vile_hinstance;
  111. static    HMENU    vile_menu;
  112. static    HFONT    vile_font;
  113. static    LOGFONT    vile_logfont;
  114. static    HANDLE    hAccTable;   /* handle to accelerator table */
  115. static    HCURSOR    hglass_cursor;
  116. static    HCURSOR    arrow_cursor;
  117. static    int    nLineHeight = 10;
  118. static    int    nCharWidth = 8;
  119. static    int    caret_disabled = FALSE;
  120. static    int    caret_visible = 0;
  121. static    int    caret_exists = 0;
  122. static    int    vile_in_getfkey = 0;
  123. static    int    vile_resizing = FALSE;    /* rely on repaint_window if true */
  124. static    int    dont_update_sb = FALSE;
  125. static    DWORD    default_fcolor;
  126. static    DWORD    default_bcolor;
  127.  
  128. #ifdef VILE_OLE
  129. static    OLEAUTO_OPTIONS oa_opts;
  130. #endif
  131.  
  132. static int    nfcolor = -1;        /* normal foreground color */
  133. static int    nbcolor = -1;        /* normal background color */
  134. static int    ninvert = FALSE;    /* normal colors inverted? */
  135. static int    crow = -1;        /* current row */
  136. static int    ccol = -1;        /* current col */
  137.  
  138. /* ansi to ibm color translation table */
  139. static    const char *initpalettestr = "0 4 2 6 1 5 3 7 8 12 10 14 9 13 11 15";
  140. /* black, red, green, yellow, blue, magenta, cyan, white   */
  141.  
  142. static    int    cur_pos = 0;
  143. static    VIDEO_ATTR cur_atr = 0;
  144.  
  145. typedef    struct {
  146.     HWND    w;
  147.     RECT    r;
  148.     int    shown;
  149. } SBDATA;
  150.  
  151. struct    gui_info {
  152.     HWND    main_hwnd;        /* the top-level window */
  153.     HWND    text_hwnd;        /* the enclosed text area */
  154.     int    closed;
  155.     int    cols;
  156.     int    rows;
  157.     RECT    xy_limit;
  158.     int    x_border;
  159.     int    y_border;
  160.     int    y_titles;        /* height of caption/titles */
  161.     int    nscrollbars;
  162.     int    maxscrollbars;
  163.     SBDATA    *scrollbars;
  164.     SBDATA    size_box;
  165.     SBDATA    size_grip;
  166. } only_window, *cur_win = &only_window;
  167.  
  168. #if OPT_SCROLLBARS
  169. static    int    check_scrollbar_allocs(void);
  170. static    void    update_scrollbar_sizes(void);
  171. #endif
  172.  
  173. /*
  174.  * Standard terminal interface dispatch table. None of the fields point into
  175.  * "termio" code.
  176.  */
  177.  
  178. TERM    term    = {
  179.     NROW,
  180.     NROW,
  181.     NCOL,
  182.     NCOL,
  183.     MARGIN,
  184.     SCRSIZ,
  185.     NPAUSE,
  186.     ntopen,
  187.     ntclose,
  188.     ntkopen,
  189.     ntkclose,
  190.     ntgetch,
  191.     ntputc,
  192.     nttypahead,
  193.     ntflush,
  194.     ntmove,
  195.     nteeol,
  196.     nteeop,
  197.     ntbeep,
  198.     ntrev,
  199.     ntcres,
  200. #if OPT_COLOR
  201.     ntfcol,
  202.     ntbcol,
  203.     set_ctrans,
  204. #else
  205.     null_t_setfor,
  206.     null_t_setback,
  207.     null_t_setpal,
  208. #endif
  209.     ntscroll,
  210.     null_t_pflush,
  211. #if OPT_ICURSOR
  212.     nticursor,
  213. #else
  214.     null_t_icursor,
  215. #endif
  216. #if OPT_TITLE
  217.     nttitle,
  218. #else
  219.     null_t_title,
  220. #endif
  221.     null_t_watchfd,
  222.     null_t_unwatchfd,
  223. };
  224.  
  225. #if OPT_TRACE
  226. static char *
  227. which_window(HWND hwnd)
  228. {
  229.     if (hwnd == 0) {
  230.         return "NULL";
  231.     } if (hwnd == cur_win->main_hwnd) {
  232.         return "main";
  233.     } else if (hwnd == cur_win->text_hwnd) {
  234.         return "text";
  235.     } else {
  236.         int n;
  237.         static char temp[20];
  238.         sprintf(temp, "%#lx", hwnd);
  239.         for (n = 0; n < cur_win->nscrollbars; n++) {
  240.             if (hwnd == cur_win->scrollbars[n].w) {
  241.                 sprintf(temp, "sb%d", n);
  242.                 break;
  243.             }
  244.         }
  245.         return temp;
  246.     }
  247. }
  248.  
  249. static char *
  250. message2s(unsigned code)
  251. {
  252.     static struct {
  253.         WORD code;
  254.         char *name;
  255.     } table[] = {
  256.         { WM_ACTIVATE,        "WM_ACTIVATE" },
  257.         { WM_ACTIVATEAPP,    "WM_ACTIVATEAPP" },
  258.         { WM_CANCELMODE,    "WM_CANCELMODE" },
  259.         { WM_CAPTURECHANGED,    "WM_CAPTURECHANGED" },
  260.         { WM_CLOSE,        "WM_CLOSE" },
  261.         { WM_CREATE,        "WM_CREATE" },
  262.         { WM_CTLCOLORSCROLLBAR,    "WM_CTLCOLORSCROLLBAR" },
  263.         { WM_ENABLE,        "WM_ENABLE" },
  264.         { WM_ENTERIDLE,        "WM_ENTERIDLE" },
  265.         { WM_ENTERMENULOOP,    "WM_ENTERMENULOOP" },
  266.         { WM_ENTERSIZEMOVE,    "WM_ENTERSIZEMOVE" },
  267.         { WM_ERASEBKGND,    "WM_ERASEBKGND" },
  268.         { WM_EXITMENULOOP,    "WM_EXITMENULOOP" },
  269.         { WM_EXITSIZEMOVE,    "WM_EXITSIZEMOVE" },
  270.         { WM_GETMINMAXINFO,    "WM_GETMINMAXINFO" },
  271.         { WM_GETTEXT,        "WM_GETTEXT" },
  272.         { WM_KILLFOCUS,        "WM_KILLFOCUS" },
  273.         { WM_INITMENU,        "WM_INITMENU" },
  274.         { WM_INITMENUPOPUP,    "WM_INITMENUPOPUP" },
  275.         { WM_KEYDOWN,        "WM_KEYDOWN" },
  276.         { WM_KEYUP,        "WM_KEYUP" },
  277.         { WM_MENUSELECT,    "WM_MENUSELECT" },
  278.         { WM_MOUSEACTIVATE,    "WM_MOUSEACTIVATE" },
  279.         { WM_MOVE,        "WM_MOVE" },
  280.         { WM_MOVING,        "WM_MOVING" },
  281.         { WM_NCACTIVATE,    "WM_NCACTIVATE" },
  282.         { WM_NCCALCSIZE,    "WM_NCCALCSIZE" },
  283.         { WM_NCCREATE,        "WM_NCCREATE" },
  284.         { WM_NCHITTEST,        "WM_NCHITTEST" },
  285.         { WM_NCLBUTTONDOWN,    "WM_NCLBUTTONDOWN" },
  286.         { WM_NCMOUSEMOVE,    "WM_NCMOUSEMOVE" },
  287.         { WM_NCPAINT,        "WM_NCPAINT" },
  288.         { WM_PAINT,        "WM_PAINT" },
  289.         { WM_PARENTNOTIFY,    "WM_PARENTNOTIFY" },
  290.         { WM_QUERYNEWPALETTE,    "WM_QUERYNEWPALETTE" },
  291.         { WM_SETCURSOR,        "WM_SETCURSOR" },
  292.         { WM_SETFOCUS,        "WM_SETFOCUS" },
  293.         { WM_SETTEXT,        "WM_SETTEXT" },
  294.         { WM_SHOWWINDOW,    "WM_SHOWWINDOW" },
  295.         { WM_SIZE,        "WM_SIZE" },
  296.         { WM_SIZING,        "WM_SIZING" },
  297.         { WM_SYSCOMMAND,    "WM_SYSCOMMAND" },
  298.         { WM_WINDOWPOSCHANGED,    "WM_WINDOWPOSCHANGED" },
  299.         { WM_WINDOWPOSCHANGING,    "WM_WINDOWPOSCHANGING" },
  300.     };
  301.     size_t n;
  302.     static char temp[20];
  303.  
  304.     for (n = 0; n < TABLESIZE(table); n++) {
  305.         if (table[n].code == code) {
  306.             return table[n].name;
  307.         }
  308.     }
  309.     sprintf(temp, "%#x", code);
  310.     return temp;
  311. }
  312.  
  313. static char *
  314. syscommand2s(unsigned code)
  315. {
  316.     static struct {
  317.         WORD code;
  318.         char *name;
  319.     } table[] = {
  320.         { SC_SIZE,        "SC_SIZE" },
  321.         { SC_MOVE,        "SC_MOVE" },
  322.         { SC_MINIMIZE,        "SC_MINIMIZE" },
  323.         { SC_MAXIMIZE,        "SC_MAXIMIZE" },
  324.         { SC_NEXTWINDOW,    "SC_NEXTWINDOW" },
  325.         { SC_PREVWINDOW,    "SC_PREVWINDOW" },
  326.         { SC_CLOSE,        "SC_CLOSE" },
  327.         { SC_VSCROLL,        "SC_VSCROLL" },
  328.         { SC_HSCROLL,        "SC_HSCROLL" },
  329.         { SC_MOUSEMENU,        "SC_MOUSEMENU" },
  330.         { SC_KEYMENU,        "SC_KEYMENU" },
  331.         { SC_ARRANGE,        "SC_ARRANGE" },
  332.         { SC_RESTORE,        "SC_RESTORE" },
  333.         { SC_TASKLIST,        "SC_TASKLIST" },
  334.         { SC_SCREENSAVE,    "SC_SCREENSAVE" },
  335.         { SC_HOTKEY,        "SC_HOTKEY" },
  336.     };
  337.     size_t n;
  338.     static char temp[80];
  339.     unsigned remainder = code & 0xf;
  340.  
  341.     for (n = 0; n < TABLESIZE(table); n++) {
  342.         if (table[n].code == (code - remainder)) {
  343.             sprintf(temp, "%s+%X", table[n].name, remainder);
  344.             return temp;
  345.         }
  346.     }
  347.     sprintf(temp, "%#x", code);
  348.     return temp;
  349. }
  350.  
  351. static void
  352. TraceWindowRect(HWND hwnd)
  353. {
  354.     RECT wrect;
  355.     int rows;
  356.     int cols;
  357.     GetWindowRect(hwnd, &wrect);
  358.     cols = RectToCols(wrect);
  359.     rows = RectToRows(wrect);
  360.     TRACE(("... (%3d,%3d) (%3d,%3d), window is %dx%d cells (%dx%d pixels)%s\n",
  361.         wrect.top, wrect.left,
  362.         wrect.bottom, wrect.right,
  363.         rows,
  364.         cols,
  365.         RowToPixel(rows),
  366.         ColToPixel(cols),
  367.         IsZoomed(hwnd) ? " zoomed" : ""
  368.         ))
  369. }
  370.  
  371. static void
  372. TraceClientRect(HWND hwnd)
  373. {
  374.     RECT crect;
  375.     int rows;
  376.     int cols;
  377.     GetClientRect(hwnd, &crect);
  378.     cols = RectToCols(crect);
  379.     rows = RectToRows(crect);
  380.     TRACE(("... (%3d,%3d) (%3d,%3d), client is %dx%d cells (%dx%d pixels)\n",
  381.         crect.top, crect.left,
  382.         crect.bottom, crect.right,
  383.         rows,
  384.         cols,
  385.         RowToPixel(rows),
  386.         ColToPixel(cols)
  387.         ))
  388. }
  389. #else
  390. #define TraceWindowRect(hwnd) /* nothing */
  391. #define TraceClientRect(hwnd) /* nothing */
  392. #endif
  393.  
  394. static HBRUSH
  395. Background(HDC hdc)
  396. {
  397.     TRACE(("Background %#06x\n", GetBkColor(hdc)))
  398.     return CreateSolidBrush(GetBkColor(hdc));
  399. }
  400.  
  401. void
  402. gui_resize(int cols, int rows)
  403. {
  404.     static int level;
  405.     RECT crect;
  406.     RECT wrect;
  407.     int main_wide;
  408.     int main_high;
  409.     int text_wide;
  410.     int text_high;
  411.  
  412.     level++;
  413.     TRACE(("gui_resize(%d x %d) begin %d\n", rows, cols, level))
  414.     TraceWindowRect(cur_win->main_hwnd);
  415.     TraceClientRect(cur_win->main_hwnd);
  416.  
  417.     GetClientRect(cur_win->main_hwnd, &crect);
  418.     GetWindowRect(cur_win->main_hwnd, &wrect);
  419.  
  420.     text_wide = ColToPixel(cols);
  421.     text_high = RowToPixel(rows);
  422.     wrect.right  += text_wide - crect.right;
  423.     wrect.bottom += text_high - crect.bottom;
  424. #if FIXME_POSCHANGING
  425.     main_wide = text_wide + (2 * cur_win->x_border) + SbWidth;
  426.     main_high = text_high + (2 * cur_win->y_border) + cur_win->y_titles;
  427. #else
  428.     main_wide = wrect.right - wrect.left + SbWidth;
  429.     main_high = wrect.bottom - wrect.top;
  430. #endif
  431.  
  432.     TRACE(("... gui_resize -> (%d,%d) (%d,%d) main %dx%d, text %dx%d\n",
  433.         wrect.top,
  434.         wrect.left,
  435.         wrect.bottom,
  436.         wrect.right,
  437.         main_high,
  438.         main_wide,
  439.         text_high,
  440.         text_wide))
  441.  
  442.     MoveWindow(cur_win->main_hwnd,
  443.         wrect.left,
  444.         wrect.top,
  445.         main_wide,
  446.         main_high,
  447.         TRUE);
  448.     MoveWindow(cur_win->text_hwnd,
  449.         0,
  450.         0,
  451.         text_wide,
  452.         text_high,
  453.         TRUE);
  454.  
  455.     TraceWindowRect(cur_win->main_hwnd);
  456.     TraceClientRect(cur_win->main_hwnd);
  457. #if OPT_SCROLLBARS
  458.     update_scrollbar_sizes();
  459. #endif
  460.     TRACE(("... gui_resize finish %d\n", level))
  461.     level--;
  462. }
  463.  
  464. static int
  465. AdjustedHeight(int high)
  466. {
  467.     int    extra = cur_win->y_titles + (2 * cur_win->y_border);
  468.     int    rows;
  469.     if (high > cur_win->xy_limit.bottom)
  470.         high = cur_win->xy_limit.bottom;
  471.     rows = (high - extra) / nLineHeight;
  472.     if (rows < MIN_ROWS)
  473.         rows = MIN_ROWS;
  474.     return (rows * nLineHeight) + extra;
  475. }
  476.  
  477. static int
  478. AdjustedWidth(int wide)
  479. {
  480.     int    extra = SbWidth + (2 * cur_win->x_border);
  481.     int    cols;
  482.     if (wide > cur_win->xy_limit.right)
  483.         wide = cur_win->xy_limit.right;
  484.     cols = (wide - extra) / nCharWidth;
  485.     if (cols < MIN_COLS)
  486.         cols = MIN_COLS;
  487.     return (cols * nCharWidth) + extra;
  488. }
  489.  
  490. #if FIXME_POSCHANGING
  491. static int
  492. AdjustPosChanging(HWND hwnd, WINDOWPOS *pos)
  493. {
  494.     if (!(pos->flags & SWP_NOSIZE)) {
  495.         int wide = AdjustedWidth(pos->cx);
  496.         int high = AdjustedHeight(pos->cy);
  497.  
  498.         TRACE(("...%s position %d,%d, resize from %d,%d to %d,%d\n",
  499.             IsZoomed(hwnd) ? " zoomed" : "",
  500.             pos->y,  pos->x,
  501.             pos->cy, pos->cx, high, wide))
  502.         pos->cx = wide;
  503.         pos->cy = high;
  504.     }
  505.     return 0;
  506. }
  507. #endif
  508.  
  509. /*
  510.  * Handle WM_SIZING, forcing the screen size to stay in multiples of a
  511.  * character cell.
  512.  */
  513. static int
  514. AdjustResizing(HWND hwnd, WPARAM fwSide, RECT *rect)
  515. {
  516.     int    wide = rect->right - rect->left;
  517.     int    high = rect->bottom - rect->top;
  518.     int    adjX = wide - AdjustedWidth(wide);
  519.     int    adjY = high - AdjustedHeight(high);
  520.  
  521.     TRACE(("AdjustResizing now (%d,%d) (%d,%d) (%dx%d pixels)\n",
  522.         rect->top, rect->left, rect->bottom, rect->right,
  523.         rect->bottom - rect->top,
  524.         rect->right - rect->left))
  525.  
  526.     TraceWindowRect(hwnd);
  527.     TraceClientRect(hwnd);
  528.  
  529.     if (fwSide == WMSZ_LEFT
  530.      || fwSide == WMSZ_TOPLEFT
  531.      || fwSide == WMSZ_BOTTOMLEFT)
  532.         rect->left += adjX;
  533.     else
  534.     if (fwSide == WMSZ_RIGHT
  535.      || fwSide == WMSZ_TOPRIGHT
  536.      || fwSide == WMSZ_BOTTOMRIGHT)
  537.         rect->right -= adjX;
  538.  
  539.     if (fwSide == WMSZ_TOP
  540.      || fwSide == WMSZ_TOPLEFT
  541.      || fwSide == WMSZ_TOPRIGHT)
  542.         rect->top += adjY;
  543.     else
  544.     if (fwSide == WMSZ_BOTTOM
  545.      || fwSide == WMSZ_BOTTOMLEFT
  546.      || fwSide == WMSZ_BOTTOMRIGHT)
  547.         rect->bottom -= adjY;
  548.  
  549.     TRACE(("... AdjustResizing (%d,%d) (%d,%d) adjY:%d, adjX:%d\n",
  550.         rect->top, rect->left, rect->bottom, rect->right,
  551.         adjY, adjX))
  552.  
  553.     return TRUE;
  554. }
  555.  
  556. static void
  557. ResizeClient()
  558. {
  559.     static int level;
  560.     int h, w;
  561.     RECT crect;
  562.  
  563.     if (cur_win->closed) {
  564.         TRACE(("ResizeClient ignored (closed)\n"))
  565.         return;
  566.     }
  567.  
  568.     level++;
  569.     TRACE(("ResizeClient begin %d, currently %dx%d\n", level, term.t_nrow, term.t_ncol))
  570.     TraceWindowRect(cur_win->main_hwnd);
  571.     TraceClientRect(cur_win->main_hwnd);
  572.     GetClientRect(cur_win->main_hwnd, &crect);
  573.  
  574.     h = RectToRows(crect);
  575.     w = RectToCols(crect);
  576.  
  577.     /*
  578.      * The WM_WINDOWPOSCHANGING message is supposed to allow modification
  579.      * to keep a window in bounds.  But it doesn't work.  This does (by
  580.      * forcing the calls on MoveWindow to have a "good" value).
  581.      */
  582.     if (h < MIN_ROWS)
  583.         h = MIN_ROWS;
  584.  
  585.     if (w < MIN_COLS)
  586.         w = MIN_COLS;
  587.  
  588.     if ((h > 1 && h != term.t_nrow) || (w > 1 && w != term.t_ncol)) {
  589.         TRACE(("...ResizeClient %dx%d\n", h, w))
  590.         vile_resizing = TRUE;
  591.         newscreensize(h, w);
  592.         SetRows(h);
  593.         SetCols(w);
  594. #if OPT_SCROLLBARS
  595.         if (check_scrollbar_allocs() == TRUE) /* no allocation failure */
  596.             update_scrollbar_sizes();
  597. #endif
  598.         vile_resizing = FALSE;
  599.         TRACE(("...ResizeClient %dx%d\n", h, w))
  600.     } else {
  601.         TRACE(("ResizeClient ignored (h=%d, w=%d, vs %d x %d)\n",
  602.             h, w, term.t_nrow, term.t_ncol));
  603.     }
  604.  
  605.     gui_resize(w, h);
  606.     TRACE(("...ResizeClient finish %d\n", level))
  607.     level--;
  608. }
  609.  
  610. #define LTGRAY_COLOR 140
  611. #define NORMAL_COLOR 180
  612. #define BRIGHT_COLOR 255
  613.  
  614. static COLORREF
  615. color_of (int code)
  616. {
  617.     int red = 0, green = 0, blue = 0;
  618.     COLORREF result = 0;
  619.     if (code & 1)
  620.         red = NORMAL_COLOR;
  621.     if (code & 2)
  622.         green = NORMAL_COLOR;
  623.     if (code & 4)
  624.         blue = NORMAL_COLOR;
  625.     if (code & 8) {
  626.         if (red)   red   = BRIGHT_COLOR;
  627.         if (green) green = BRIGHT_COLOR;
  628.         if (blue)  blue  = BRIGHT_COLOR;
  629.         if (code == 8) {
  630.             red   = LTGRAY_COLOR;
  631.             green = LTGRAY_COLOR;
  632.             blue  = LTGRAY_COLOR;
  633.         }
  634.     }
  635.     return PALETTERGB(red, green, blue);
  636. }
  637.  
  638. static void
  639. attr_to_colors(VIDEO_ATTR attr, int *fcolor, int *bcolor)
  640. {
  641.     *fcolor = nfcolor;
  642.     *bcolor = nbcolor;
  643.     ninvert = FALSE;
  644.  
  645.     if (attr) {
  646.         if (attr & VASPCOL)
  647.             *fcolor = (attr & (NCOLORS - 1));
  648.         else if (attr == VABOLD)
  649.             *fcolor |= FOREGROUND_INTENSITY;
  650.         else if (attr == VAITAL)
  651.             *bcolor |= BACKGROUND_INTENSITY;
  652.         else if (attr & VACOLOR)
  653.             *fcolor = ((VCOLORNUM(attr)) & (NCOLORS - 1));
  654.  
  655.         if (attr & (VASEL|VAREV)) {  /* reverse video? */
  656.             int temp = *bcolor;
  657.             *bcolor = *fcolor;
  658.             *fcolor = temp;
  659.             ninvert = TRUE;
  660.         }
  661.     }
  662. }
  663.  
  664. static void
  665. set_colors (HDC hdc, VIDEO_ATTR attr)
  666. {
  667.     int fcolor;
  668.     int bcolor;
  669.  
  670.     attr_to_colors(attr, &fcolor, &bcolor);
  671.  
  672.     if (fcolor < 0)
  673.         fcolor = ninvert
  674.             ? default_bcolor
  675.             : default_fcolor;
  676.     else
  677.         fcolor = color_of(fcolor);
  678.  
  679.     if (bcolor < 0)
  680.         bcolor = ninvert
  681.             ? default_fcolor
  682.             : default_bcolor;
  683.     else
  684.         bcolor = color_of(bcolor);
  685.  
  686.     SetTextColor(hdc, fcolor);
  687.     SetBkColor(hdc,   bcolor);
  688. }
  689.  
  690. #if OPT_ICURSOR
  691. static void nticursor(int cmode)
  692. {
  693. }
  694. #endif
  695.  
  696. static int fhide_cursor(void)
  697. {
  698.     TRACE(("fhide_cursor pos %#lx,%#lx (visible:%d, exists:%d)\n", ttrow, ttcol, caret_visible, caret_exists))
  699.     if(caret_visible) {
  700.         HideCaret(cur_win->text_hwnd);
  701.         caret_visible = 0;
  702.     }
  703.     if(caret_exists) {
  704.         DestroyCaret();
  705.         caret_exists = 0;
  706.     }
  707.     return 0;
  708. }
  709.  
  710. static void fshow_cursor(void)
  711. {
  712.     int x, y;
  713.     POINT z;
  714.  
  715.     if (caret_disabled        /* reject display during font-dialog */
  716.      || ttrow > term.t_nrow        /* reject bogus position in init */
  717.      || ttcol > term.t_ncol)
  718.         return;
  719.  
  720.     TRACE(("fshow_cursor pos %#lx,%#lx (visible:%d, exists:%d)\n", ttrow, ttcol, caret_visible, caret_exists))
  721.     x = ColToPixel(ttcol) + 1;
  722.     y = RowToPixel(ttrow) + 1;
  723.     if (caret_exists) {
  724.         GetCaretPos(&z);
  725.         if (x != z.x
  726.          || y != z.y)
  727.             fhide_cursor();
  728.     }
  729.  
  730.     if (!caret_exists) {
  731.         TRACE(("...CreateCaret(%d,%d)\n", ttrow, ttcol))
  732.         CreateCaret(cur_win->text_hwnd, (HBITMAP) 0, nCharWidth, nLineHeight);
  733.         caret_exists = 1;
  734.         SetCaretPos(x, y);
  735.         ShowCaret(cur_win->text_hwnd);
  736.         caret_visible = 1;
  737.     }
  738. }
  739.  
  740. static void
  741. get_borders(void)
  742. {
  743.     SystemParametersInfo(SPI_GETWORKAREA, 0, &cur_win->xy_limit, 0);
  744.     TRACE(("WORKAREA: %d,%d %d,%d\n",
  745.         cur_win->xy_limit.top,
  746.         cur_win->xy_limit.left,
  747.         cur_win->xy_limit.right,
  748.         cur_win->xy_limit.bottom))
  749.     cur_win->x_border = GetSystemMetrics(SM_CXSIZEFRAME);
  750.     cur_win->y_border = GetSystemMetrics(SM_CYSIZEFRAME);
  751.     cur_win->y_titles = GetSystemMetrics(SM_CYCAPTION);
  752.     TRACE(("X border: %d, Y border: %d\n", cur_win->x_border, cur_win->y_border))
  753.     TRACE(("CYFRAME:   %d\n", GetSystemMetrics(SM_CYFRAME)))
  754.     TRACE(("CYCAPTION: %d\n", cur_win->y_titles))
  755. }
  756.  
  757. /* Notes: lpntm is a pointer to a TEXTMETRIC struct if FontType does not
  758.  * have TRUETYPE_FONTTYPE set, but we only need the tmPitchAndFamily member,
  759.  * which has the same alignment as in NEWTEXTMETRIC.
  760.  */
  761. static int CALLBACK
  762. enumerate_fonts(
  763.     ENUMLOGFONT *lpelf,
  764.     NEWTEXTMETRIC *lpntm,
  765.     DWORD FontType,
  766.     LPARAM lParam)
  767. {
  768.     int code = 2;
  769.     LOGFONT *src = &(lpelf->elfLogFont);
  770.     LOGFONT *dst = ((LOGFONT *)lParam);
  771.  
  772.     if ((src->lfPitchAndFamily & 3) != FIXED_PITCH) {
  773.         code = 1;
  774.     } else {
  775.         *dst = *src;
  776.         if (src->lfCharSet == ANSI_CHARSET) {
  777.             code = 0;
  778.             TRACE(("Found good font:%s\n", lpelf->elfFullName))
  779.         }
  780.         TRACE(("Found ok font:%s\n", lpelf->elfFullName))
  781.         TRACE(("Pitch/Family:   %#x\n", dst->lfPitchAndFamily))
  782.     }
  783.  
  784.     return code;
  785. }
  786.  
  787. static int is_fixed_pitch(HFONT font)
  788. {
  789.     BOOL        ok;
  790.     HDC             hDC;
  791.     TEXTMETRIC      metrics;
  792.  
  793.     hDC = GetDC(cur_win->text_hwnd);
  794.     SelectObject(hDC, font);
  795.     ok = GetTextMetrics(hDC, &metrics);
  796.     ReleaseDC(cur_win->text_hwnd, hDC);
  797.  
  798.     if (ok)
  799.         ok = ((metrics.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
  800.  
  801.     TRACE(("is_fixed_pitch: %d\n",  ok))
  802.     TRACE(("Ave Text width: %d\n",  metrics.tmAveCharWidth))
  803.     TRACE(("Max Text width: %d\n",  metrics.tmMaxCharWidth))
  804.     TRACE(("Pitch/Family:   %#x\n", metrics.tmPitchAndFamily))
  805.  
  806.     return (ok);
  807. }
  808.  
  809. static int new_font(LOGFONT *lf)
  810. {
  811.     HFONT font = CreateFontIndirect(lf);
  812.  
  813.     if (font != 0) {
  814.         if (is_fixed_pitch(font)) {
  815.             DeleteObject(vile_font);
  816.             vile_font = font;
  817.             TRACE(("created new font\n"))
  818.             return TRUE;
  819.         }
  820.         else
  821.             DeleteObject(font);
  822.     }
  823.     return FALSE;
  824. }
  825.  
  826. static void get_font(LOGFONT *lf)
  827. {
  828.     HDC             hDC;
  829.  
  830.     vile_font = GetStockObject(MY_FONT);
  831.     hDC = GetDC(cur_win->text_hwnd);
  832.     if (EnumFontFamilies(hDC, NULL, enumerate_fonts, (LPARAM) lf) <= 0)
  833.     {
  834.         TRACE(("Creating Pitch/Family: %#x\n", lf->lfPitchAndFamily))
  835.         new_font(lf);
  836.     }
  837.     ReleaseDC(cur_win->text_hwnd, hDC);
  838. }
  839.  
  840. static void use_font(HFONT my_font, BOOL resizable)
  841. {
  842.     HDC             hDC;
  843.     TEXTMETRIC      textmetric;
  844.     RECT        crect;
  845.  
  846.     hDC = GetDC(cur_win->text_hwnd);
  847.     SelectObject(hDC, my_font);
  848.     GetTextMetrics(hDC, &textmetric);
  849.     ReleaseDC(cur_win->text_hwnd, hDC);
  850.  
  851.     TRACE(("Text height:    %d\n",  textmetric.tmHeight))
  852.     TRACE(("Ave Text width: %d\n",  textmetric.tmAveCharWidth))
  853.     TRACE(("Max Text width: %d\n",  textmetric.tmMaxCharWidth))
  854.     TRACE(("Pitch/Family:   %#x\n", textmetric.tmPitchAndFamily))
  855.  
  856.     /*
  857.      * We'll use the average text-width, since some fonts (e.g., Courier
  858.      * New) have a bogus max text-width.
  859.      */
  860.     nLineHeight = textmetric.tmExternalLeading + textmetric.tmHeight;
  861.     nCharWidth  = textmetric.tmAveCharWidth;
  862.     get_borders();
  863.  
  864.     if (resizable) {
  865.         GetClientRect(cur_win->main_hwnd, &crect);
  866.  
  867.         SetCols(RectToCols(crect));
  868.         SetRows(RectToRows(crect));
  869.     }
  870.  
  871.     gui_resize(term.t_ncol, term.t_nrow);
  872. }
  873.  
  874. static void set_font(void)
  875. {
  876.     HDC        hDC;
  877.     CHOOSEFONT    choose;
  878.  
  879.     TRACE(("set_font\n"))
  880.     fhide_cursor();
  881.     caret_disabled = TRUE;
  882.     memset(&choose, 0, sizeof(choose));
  883.     choose.lStructSize = sizeof(choose);
  884.     choose.hwndOwner   = cur_win->text_hwnd;
  885.     choose.Flags       = CF_SCREENFONTS
  886.                | CF_FIXEDPITCHONLY
  887.                | CF_FORCEFONTEXIST
  888.                | CF_NOSCRIPTSEL
  889.                | CF_INITTOLOGFONTSTRUCT;
  890.     choose.lpLogFont   = &vile_logfont;
  891.  
  892.     hDC = GetDC(cur_win->text_hwnd);
  893.     SelectObject(hDC, GetMyFont());
  894.     GetTextFace(hDC, sizeof(vile_logfont.lfFaceName), vile_logfont.lfFaceName);
  895.     ReleaseDC(cur_win->text_hwnd, hDC);
  896.  
  897.     vile_logfont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
  898.     vile_logfont.lfCharSet = ANSI_CHARSET;
  899.     TRACE(("LOGFONT Facename:%s\n", vile_logfont.lfFaceName))
  900.  
  901.     if (ChooseFont(&choose)) {
  902.         TRACE(("ChooseFont '%s'\n", vile_logfont.lfFaceName))
  903.         if (new_font(&vile_logfont)) {
  904.             int saverow = ttrow;
  905.             int savecol = ttcol;
  906.             mlwrite("[Set font to %s]", vile_logfont.lfFaceName);
  907.             movecursor(saverow, savecol);
  908.             use_font(vile_font, FALSE);
  909.             vile_refresh(FALSE,0);
  910.         } else {
  911.             mlforce("[Cannot create font]");
  912.         }
  913.     } else {
  914.         mlforce("[No font selected]");
  915.     }
  916.  
  917.     caret_disabled = FALSE;
  918.     fshow_cursor();
  919.     TRACE(("...set_font, LOGFONT Facename:%s\n", vile_logfont.lfFaceName))
  920. }
  921.  
  922. static int
  923. last_w32_error(int use_msg_box)
  924. {
  925.     if (use_msg_box)
  926.         disp_win32_error(W32_SYS_ERROR, winvile_hwnd());
  927.     else
  928.     {
  929.         char *msg = NULL;
  930.  
  931.         fmt_win32_error(W32_SYS_ERROR, &msg, 0);
  932.         mlforce(msg);
  933.         LocalFree(msg);
  934.     }
  935.     return (FALSE);
  936. }
  937.  
  938. /*
  939.  * Set font from string specification.  See the function parse_font_str()
  940.  * in file w32misc.c for acceptable font string syntax.
  941.  *
  942.  * Prerequistes before calling this function:
  943.  *
  944.  *    winvile's windows and default font (vile_font) created.
  945.  *
  946.  * Returns: T -> all is well, F -> failure.
  947.  */
  948. int
  949. ntwinio_font_frm_str(
  950.     const char *fontstr,
  951.     int        use_mb    /* Boolean, T -> errors reported via MessageBox.
  952.                           *          F -> errors reported via message line.
  953.                           */
  954.                      )
  955. {
  956.     int             face_specified;
  957.     HDC             hdc;
  958.     HFONT           hfont;
  959.     HWND            hwnd;
  960.     LOGFONT         logfont;
  961.     char            *msg, font_mapper_face[LF_FACESIZE + 1];
  962.     TEXTMETRIC      metrics;
  963.     FONTSTR_OPTIONS str_rslts;
  964.  
  965.     if (! parse_font_str(fontstr, &str_rslts))
  966.     {
  967.         msg = "Font syntax invalid";
  968.         if (use_mb)
  969.             MessageBox(winvile_hwnd(), msg, prognam, MB_ICONSTOP|MB_OK);
  970.         else
  971.             mlforce(msg);
  972.         return (FALSE);
  973.     }
  974.     hwnd           = cur_win->text_hwnd;
  975.     face_specified = (str_rslts.face[0] != '\0');
  976.     if (! ((hdc = GetDC(hwnd)) && SelectObject(hdc, vile_font)))
  977.     {
  978.         if (hdc)
  979.             ReleaseDC(hwnd, hdc);
  980.         return (last_w32_error(use_mb));
  981.     }
  982.     if (! face_specified)
  983.     {
  984.         /* user didn't specify a face name, get current name. */
  985.  
  986.         if ((GetTextFace(hdc, sizeof(str_rslts.face), str_rslts.face)) == 0)
  987.         {
  988.             ReleaseDC(hwnd, hdc);
  989.             return (last_w32_error(use_mb));
  990.         }
  991.     }
  992.  
  993.     /* Build up LOGFONT data structure. */
  994.     memset(&logfont, 0, sizeof(logfont));
  995.     logfont.lfWeight = (str_rslts.bold) ? FW_BOLD : FW_NORMAL;
  996.     logfont.lfHeight = -MulDiv(str_rslts.size,
  997.                                GetDeviceCaps(hdc, LOGPIXELSY),
  998.                                72);
  999.     if (str_rslts.italic)
  1000.         logfont.lfItalic = TRUE;
  1001.     logfont.lfCharSet        = DEFAULT_CHARSET; 
  1002.     logfont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
  1003.     strncpy(logfont.lfFaceName, str_rslts.face, LF_FACESIZE - 1);
  1004.     logfont.lfFaceName[LF_FACESIZE - 1] = '\0';
  1005.     if (! ((hfont = CreateFontIndirect(&logfont)) && SelectObject(hdc, hfont)))
  1006.     {
  1007.         if (hfont)
  1008.             DeleteObject(hfont);
  1009.         ReleaseDC(hwnd, hdc);
  1010.         return (last_w32_error(use_mb));
  1011.     }
  1012.  
  1013.     /*
  1014.      * The font mapper will substitute some other font for a font request
  1015.      * that cannot exactly be met.  Ck first to see if the face name
  1016.      * matches the user chosen face (if applicatble).
  1017.      */
  1018.     if (face_specified)
  1019.     {
  1020.         if ((GetTextFace(hdc, sizeof(font_mapper_face), font_mapper_face)) == 0)
  1021.         {
  1022.             ReleaseDC(hwnd, hdc);
  1023.             DeleteObject(hfont);
  1024.             return (last_w32_error(use_mb));
  1025.         }
  1026.         if (stricmp(font_mapper_face, str_rslts.face) != 0)
  1027.         {
  1028.             ReleaseDC(hwnd, hdc);
  1029.             DeleteObject(hfont);
  1030.             msg = "Font face unknown or size/style unsupported"; 
  1031.             if (use_mb)
  1032.                 MessageBox(winvile_hwnd(), msg, prognam, MB_ICONSTOP|MB_OK);
  1033.             else
  1034.                 mlforce(msg);
  1035.             return (FALSE);
  1036.         }
  1037.     }
  1038.  
  1039.     /* Next, font must be fixed pitch. */
  1040.     if (! GetTextMetrics(hdc, &metrics))
  1041.     {
  1042.         ReleaseDC(hwnd, hdc);
  1043.         DeleteObject(hfont);
  1044.         return (last_w32_error(use_mb));
  1045.     }
  1046.     if ((metrics.tmPitchAndFamily & TMPF_FIXED_PITCH) != 0)
  1047.     {
  1048.         /* Misnamed constant! */
  1049.  
  1050.         ReleaseDC(hwnd, hdc);
  1051.         DeleteObject(hfont);
  1052.         msg = "Font not fixed pitch";
  1053.         if (use_mb)
  1054.             MessageBox(winvile_hwnd(), msg, prognam, MB_ICONSTOP|MB_OK);
  1055.         else
  1056.             mlforce(msg);
  1057.         return (FALSE);
  1058.     }
  1059.     DeleteObject(vile_font);      /* Nuke original font     */
  1060.     ReleaseDC(hwnd, hdc);         /* finally done with this */
  1061.     vile_font = hfont;
  1062.     memcpy(&vile_logfont, &logfont, sizeof(vile_logfont));
  1063.     use_font(vile_font, FALSE);
  1064.     vile_refresh(FALSE, 0);
  1065.     return (TRUE);
  1066. }
  1067.  
  1068. char *
  1069. ntwinio_current_font(void)
  1070. {
  1071.     static char   *buf;
  1072.     HDC           hdc;
  1073.     HWND          hwnd;
  1074.     LONG          size;
  1075.     char          *style;
  1076.  
  1077.     if (! buf)
  1078.     {
  1079.         buf = castalloc(char,
  1080.                         sizeof("bold-italic") +
  1081.                         LF_FACESIZE +
  1082.                         16); /* space for delimiters and point size */
  1083.         if (! buf)
  1084.             return ("out of memory");
  1085.     }
  1086.     hwnd = cur_win->text_hwnd;
  1087.     if (! ((hdc = GetDC(hwnd)) && SelectObject(hdc, vile_font)))
  1088.     {
  1089.         char *msg = NULL;
  1090.  
  1091.         if (hdc)
  1092.             ReleaseDC(hwnd, hdc);
  1093.  
  1094.         fmt_win32_error(W32_SYS_ERROR, &msg, 0);
  1095.         return (msg);
  1096.         /* "msg" leaks here, but this code path should never be taken. */
  1097.     }
  1098.     if (vile_logfont.lfWeight == FW_BOLD && vile_logfont.lfItalic)
  1099.         style = "bold-italic";
  1100.     else if (vile_logfont.lfWeight == FW_BOLD)
  1101.         style = "bold";
  1102.     else if (vile_logfont.lfItalic)
  1103.         style = "italic";
  1104.     else
  1105.         style = NULL;
  1106.     size = MulDiv(labs(vile_logfont.lfHeight),
  1107.                   72,
  1108.                   GetDeviceCaps(hdc, LOGPIXELSY));
  1109.     sprintf(buf,
  1110.             "%s,%ld%s%s",
  1111.             vile_logfont.lfFaceName,
  1112.             size,
  1113.             (style) ? "," : "",
  1114.             (style) ? style : "");
  1115.     ReleaseDC(hwnd, hdc);
  1116.     return (buf);
  1117. }
  1118.  
  1119. #if OPT_TITLE
  1120. static void
  1121. nttitle(char *title)        /* set the current window title */
  1122. {
  1123.     SetWindowText(winvile_hwnd(), title);
  1124. }
  1125. #endif
  1126.  
  1127. static void
  1128. scflush(void)
  1129. {
  1130.     if (cur_pos && !vile_resizing) {
  1131.         HDC hdc;
  1132.  
  1133.         TRACE(("PUTC:flush %2d (%2d,%2d) (%.*s)\n", cur_pos, crow,ccol, cur_pos, &CELL_TEXT(crow,ccol)))
  1134.  
  1135.         hdc = GetDC(cur_win->text_hwnd);
  1136.         SelectObject(hdc, GetMyFont());
  1137.         set_colors(hdc, cur_atr);
  1138.  
  1139.         TextOut(hdc,
  1140.             ColToPixel(ccol),
  1141.             RowToPixel(crow),
  1142.             &CELL_TEXT(crow,ccol), cur_pos);
  1143.  
  1144.         ReleaseDC(cur_win->text_hwnd, hdc);
  1145.     }
  1146.     ccol = ccol + cur_pos;
  1147.     cur_pos = 0;
  1148. }
  1149.  
  1150. #if OPT_COLOR
  1151. static void
  1152. ntfcol(int color)        /* set the current output color */
  1153. {
  1154.     scflush();
  1155.     nfcolor = color;
  1156. }
  1157.  
  1158. static void
  1159. ntbcol(int color)        /* set the current background color */
  1160. {
  1161.     scflush();
  1162.     nbcolor = color;
  1163. }
  1164. #endif
  1165.  
  1166. static void
  1167. ntflush(void)
  1168. {
  1169.     scflush();
  1170.     SetCaretPos(ColToPixel(ccol), RowToPixel(crow));
  1171. }
  1172.  
  1173. static void
  1174. ntmove(int row, int col)
  1175. {
  1176.     scflush();
  1177.     crow = (short) row;
  1178.     ccol = (short) col;
  1179. }
  1180.  
  1181. /* erase to the end of the line */
  1182. static void
  1183. nteeol(void)
  1184. {
  1185.     HDC    hDC;
  1186.     HBRUSH    brush;
  1187.     RECT    rect;
  1188.     int    x;
  1189.  
  1190.     scflush();
  1191.  
  1192.     TRACE(("NTEEOL %d,%d, atr %#x\n", crow, ccol, cur_atr))
  1193.     for (x = ccol; x < term.t_ncol; x++) {
  1194.         CELL_TEXT(crow,x) = ' ';
  1195.         CELL_ATTR(crow,x) = cur_atr;
  1196.     }
  1197.  
  1198.     GetClientRect(cur_win->text_hwnd, &rect);
  1199.     rect.left   = ColToPixel(ccol);
  1200.     rect.top    = RowToPixel(crow);
  1201.     rect.right  = ColToPixel(term.t_ncol);
  1202.     rect.bottom = RowToPixel(crow+1);
  1203.  
  1204.     hDC = GetDC(cur_win->text_hwnd);
  1205.     set_colors(hDC, cur_atr);
  1206.     brush = Background(hDC);
  1207.     FillRect(hDC, &rect, brush);
  1208.     DeleteObject(brush);
  1209.     ReleaseDC(cur_win->text_hwnd, hDC);
  1210. }
  1211.  
  1212. /*
  1213.  * vile very rarely generates any of the ASCII printing control characters
  1214.  * except for a few hand coded routines but we have to support them anyway.
  1215.  */
  1216.  
  1217. /* put a character at the current position in the current colors */
  1218. static void
  1219. ntputc(int ch)
  1220. {
  1221.     /* This is an optimization for the most common case. */
  1222.     if (ch >= ' ') {
  1223.         CELL_TEXT(crow,ccol+cur_pos) = (char) ch;
  1224.         CELL_ATTR(crow,ccol+cur_pos) = cur_atr;
  1225.         cur_pos++;
  1226.     } else {
  1227.  
  1228.         switch (ch) {
  1229.  
  1230.         case '\b':
  1231.             scflush();
  1232.             if (ccol)
  1233.                 ccol--;
  1234.             break;
  1235.  
  1236.         case '\a':
  1237.             ntbeep();
  1238.             break;
  1239.  
  1240.         case '\t':
  1241.             scflush();
  1242.             do {
  1243.                 CELL_TEXT(crow,ccol+cur_pos) = ' ';
  1244.                 CELL_ATTR(crow,ccol+cur_pos) = cur_atr;
  1245.                 cur_pos++;
  1246.             } while ((ccol + cur_pos) % 8 != 0);
  1247.             break;
  1248.  
  1249.         case '\r':
  1250.             scflush();
  1251.             ccol = 0;
  1252.             break;
  1253.  
  1254.         case '\n':
  1255.             scflush();
  1256.             if (crow < term.t_nrow - 1)
  1257.                 crow++;
  1258.             else
  1259.                 ntscroll(1, 0, term.t_nrow - 1);
  1260.             break;
  1261.  
  1262.         default:
  1263.             CELL_TEXT(crow,ccol+cur_pos) = (char) ch;
  1264.             CELL_ATTR(crow,ccol+cur_pos) = cur_atr;
  1265.             cur_pos++;
  1266.             break;
  1267.         }
  1268.     }
  1269. }
  1270.  
  1271. static void
  1272. nteeop(void)
  1273. {
  1274.     HDC    hDC;
  1275.     HBRUSH    brush;
  1276.     RECT    rect;
  1277.     int    y, x, x0;
  1278.  
  1279.     scflush();
  1280.  
  1281.     x0 = ccol;
  1282.     TRACE(("NTEEOP %d,%d, atr %#x\n", crow, ccol, cur_atr))
  1283.     for (y = crow; y < term.t_nrow; y++) {
  1284.         for (x = 0; x < term.t_ncol; x++) {
  1285.             CELL_TEXT(y,x) = ' ';
  1286.             CELL_ATTR(y,x) = cur_atr;
  1287.         }
  1288.         x0 = 0;
  1289.     }
  1290.  
  1291.     rect.left   = ColToPixel(ccol);
  1292.     rect.top    = RowToPixel(crow);
  1293.     rect.right  = ColToPixel(term.t_ncol);
  1294.     rect.bottom = RowToPixel(term.t_nrow);
  1295.  
  1296.     if (!vile_resizing) {
  1297.         hDC = GetDC(cur_win->text_hwnd);
  1298.         set_colors(hDC, cur_atr);
  1299.         brush = Background(hDC);
  1300.         FillRect(hDC, &rect, brush);
  1301.         DeleteObject(brush);
  1302.         ReleaseDC(cur_win->text_hwnd, hDC);
  1303.     }
  1304. }
  1305.  
  1306. static void
  1307. ntrev(UINT reverse)        /* change reverse video state */
  1308. {
  1309.     scflush();
  1310.     cur_atr = (VIDEO_ATTR) reverse;
  1311. }
  1312.  
  1313. static int
  1314. ntcres(const char *res)        /* change screen resolution */
  1315. {
  1316.     scflush();
  1317.     return 0;
  1318. }
  1319.  
  1320. #if    OPT_FLASH
  1321. static void
  1322. flash_display()
  1323. {
  1324.     RECT    rect;
  1325.     HDC    hDC;
  1326.  
  1327.     GetClientRect(cur_win->text_hwnd, &rect);
  1328.     hDC = GetDC(cur_win->text_hwnd);
  1329.     InvertRect(hDC, &rect);
  1330.     Sleep(100);
  1331.     InvertRect(hDC, &rect);
  1332.     ReleaseDC(cur_win->text_hwnd, hDC);
  1333. }
  1334. #endif
  1335.  
  1336. static void
  1337. ntbeep(void)
  1338. {
  1339. #if    OPT_FLASH
  1340.     if (global_g_val(GMDFLASH)) {
  1341.         flash_display();
  1342.         return;
  1343.     }
  1344. #endif
  1345.     MessageBeep(0xffffffff);
  1346. }
  1347.  
  1348. static void
  1349. ntopen(void)
  1350. {
  1351.     TRACE(("ntopen\n"))
  1352.  
  1353.     set_palette(initpalettestr);
  1354. }
  1355.  
  1356. static int old_title_set = 0;
  1357. static char old_title[256];
  1358. static int orig_title_set = 0;
  1359. static char orig_title[256];
  1360.  
  1361. static void
  1362. ntclose(void)
  1363. {
  1364.     TRACE(("ntclose\n"))
  1365.  
  1366.     scflush();
  1367.     ntmove(term.t_nrow - 1, 0);
  1368.     nteeol();
  1369.     ntflush();
  1370. }
  1371.  
  1372. static void
  1373. ntkopen(void)    /* open the keyboard */
  1374. {
  1375. }
  1376.  
  1377. static void
  1378. ntkclose(void)    /* close the keyboard */
  1379. {
  1380. }
  1381.  
  1382. static struct {
  1383.     int    windows;
  1384.     int    vile;
  1385. } keyxlate[] = {
  1386.     { VK_NEXT,    KEY_Next },
  1387.     { VK_PRIOR,    KEY_Prior },
  1388.     { VK_END,    KEY_End },
  1389.     { VK_HOME,    KEY_Home },
  1390.     { VK_LEFT,    KEY_Left },
  1391.     { VK_RIGHT,    KEY_Right },
  1392.     { VK_UP,    KEY_Up },
  1393.     { VK_DOWN,    KEY_Down },
  1394.     { VK_INSERT,    KEY_Insert },
  1395.     { VK_DELETE,    KEY_Delete },
  1396.     { VK_HELP,    KEY_Help },
  1397.     { VK_SELECT,    KEY_Select },
  1398. #if 0
  1399.     /* Merely pressing the Alt key generates a VK_MENU key event. */
  1400.     { VK_MENU,    KEY_Menu },
  1401. #endif
  1402.     { VK_F1,    KEY_F1 },
  1403.     { VK_F2,    KEY_F2 },
  1404.     { VK_F3,    KEY_F3 },
  1405.     { VK_F4,    KEY_F4 },
  1406.     { VK_F5,    KEY_F5 },
  1407.     { VK_F6,    KEY_F6 },
  1408.     { VK_F7,    KEY_F7 },
  1409.     { VK_F8,    KEY_F8 },
  1410.     { VK_F9,    KEY_F9 },
  1411.     { VK_F10,    KEY_F10 },
  1412.     { VK_F11,    KEY_F11 },
  1413.     { VK_F12,    KEY_F12 },
  1414.     { VK_F13,    KEY_F13 },
  1415.     { VK_F14,    KEY_F14 },
  1416.     { VK_F15,    KEY_F15 },
  1417.     { VK_F16,    KEY_F16 },
  1418.     { VK_F17,    KEY_F17 },
  1419.     { VK_F18,    KEY_F18 },
  1420.     { VK_F19,    KEY_F19 },
  1421.     { VK_F20,    KEY_F20 },
  1422.     /* Allow ^-6 to invoke the alternate-buffer command, a la Unix.  */
  1423.     { '6',        '6' },
  1424. };
  1425.  
  1426. static int savedChar;
  1427. static int saveCount = 0;
  1428.  
  1429. static int
  1430. decode_key_event(KEY_EVENT_RECORD *irp)
  1431. {
  1432.     int key;
  1433.     int i;
  1434.  
  1435.     if ((key = (unsigned char) irp->uChar.AsciiChar) != 0)
  1436.         return key;
  1437.  
  1438.     for (i = 0; i < TABLESIZE(keyxlate); i++)
  1439.     {
  1440.         if (keyxlate[i].windows == irp->wVirtualKeyCode)
  1441.         {
  1442.         DWORD state = irp->dwControlKeyState;
  1443.  
  1444.         /*
  1445.          * This is a combination from the window menu which is caught when
  1446.          * we've grabbed focus.  Just ignore it here, and it will be
  1447.          * processed properly.
  1448.          */
  1449.         if (keyxlate[i].windows == VK_F4
  1450.         && (state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)))
  1451.         break;
  1452.  
  1453.         /*
  1454.          * If this key is modified in some way, we'll prefer to use the
  1455.          * Win32 definition.  But only for the modifiers that we
  1456.          * recognize.  Specifically, we don't care about ENHANCED_KEY,
  1457.          * since we already have portable pageup/pagedown and arrow key
  1458.          * bindings that would be lost if we used the Win32-only
  1459.          * definition.
  1460.          */
  1461.         if (state &
  1462.         (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED
  1463.         | LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED
  1464.         | SHIFT_PRESSED))
  1465.             {
  1466.                 key = W32_KEY | keyxlate[i].windows;
  1467.                 if (state & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
  1468.                     key |= W32_CTRL;
  1469.                 if (state & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))
  1470.                     key |= W32_ALT;
  1471.                 if (state & SHIFT_PRESSED)
  1472.                     key |= W32_SHIFT;
  1473.             }
  1474.             else
  1475.                 key = keyxlate[i].vile;
  1476.             TRACE(("... %#x -> %#x\n", irp->wVirtualKeyCode, key))
  1477.             break;
  1478.         }
  1479.     }
  1480.     if (key == 0)
  1481.         return (NOKYMAP);
  1482.  
  1483.     return key;
  1484. }
  1485.  
  1486. static int
  1487. get_keyboard_state(void)
  1488. {
  1489.     int result = 0;
  1490.  
  1491.     if (GetKeyState(VK_CONTROL) < 0)
  1492.         result |= (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED);
  1493.     if (GetKeyState(VK_MENU) < 0)
  1494.         result |= (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED);
  1495.     if (GetKeyState(VK_SHIFT) < 0)
  1496.         result |= SHIFT_PRESSED;
  1497.     return result;
  1498. }
  1499.  
  1500. static int
  1501. ntgetch(void)
  1502. {
  1503.     int buttondown = FALSE;
  1504.     MSG msg;
  1505.     POINTS points;
  1506.     POINT first;
  1507.     int have_focus = 0;
  1508.     int result = 0;
  1509.     DWORD dword;
  1510.     KEY_EVENT_RECORD ker;
  1511.  
  1512.     if (saveCount > 0) {
  1513.         saveCount--;
  1514.         return savedChar;
  1515.     }
  1516.  
  1517.     vile_in_getfkey = 1;
  1518.     while(! result) {
  1519.         if(GetFocus() == cur_win->main_hwnd) {
  1520.             if(! have_focus) {
  1521.                 have_focus = 1;
  1522.                 fshow_cursor();
  1523.             }
  1524.         } else {
  1525.             if(have_focus) {
  1526.                 have_focus = 0;
  1527.                 fhide_cursor();
  1528.             }
  1529.         }
  1530.         if(GetMessage(&msg, (HWND)0, 0, 0) != TRUE) {
  1531.             PostQuitMessage(1);
  1532.             TRACE(("GETC:no message\n"))
  1533.             quit(TRUE,1);
  1534.         }
  1535.  
  1536.         if (TranslateAccelerator(cur_win->main_hwnd, hAccTable, &msg)) {
  1537.             TRACE(("GETC:no accelerator\n"))
  1538.             continue;
  1539.         }
  1540.  
  1541.         TranslateMessage(&msg);
  1542.  
  1543.         switch(msg.message) {
  1544.         case WM_DESTROY:
  1545.             TRACE(("GETC:DESTROY\n"))
  1546.             PostQuitMessage(0);
  1547.             continue;
  1548.  
  1549.         case WM_CHAR:
  1550.             TRACE(("GETC:CHAR:%#x\n", msg.wParam))
  1551.             result = msg.wParam;
  1552.             if (result == ESC) {
  1553.                 sel_release();
  1554.                 (void)update(TRUE);
  1555.             }
  1556.             break;
  1557.  
  1558.         case WM_KEYDOWN:
  1559.         case WM_SYSKEYDOWN:
  1560.             ker.uChar.AsciiChar = 0;
  1561.             ker.wVirtualKeyCode = (SHORT) msg.wParam;
  1562.             ker.dwControlKeyState = get_keyboard_state();
  1563.             result = decode_key_event(&ker);
  1564.             TRACE(("GETC:%sKEYDOWN:%#x ->%#x\n",
  1565.                 (msg.message == WM_SYSKEYDOWN) ? "SYS" : "",
  1566.                 msg.wParam, result))
  1567.             if (result == NOKYMAP) {
  1568.                 DispatchMessage(&msg);
  1569.                 result = 0;
  1570.             } else if (result == (int) msg.wParam) {
  1571.                 result = 0; /* we'll get a WM_CHAR next */
  1572.             }
  1573.             break;
  1574.  
  1575.         case WM_LBUTTONDOWN:
  1576.             TRACE(("GETC:LBUTTONDOWN %s\n", which_window(msg.hwnd)))
  1577.             if (msg.hwnd == cur_win->text_hwnd) {
  1578.                 dword = GetMessagePos();
  1579.                 points = MAKEPOINTS(dword);
  1580.                 POINTSTOPOINT(first, points);
  1581.                 ScreenToClient(cur_win->main_hwnd, &first);
  1582.                 first.x /= nCharWidth;
  1583.                 first.y /= nLineHeight;
  1584.                 TRACE(("GETC:setcursor(%d, %d)\n", first.y, first.x))
  1585.                 if (setcursor(first.y, first.x)) {
  1586.                     fhide_cursor();
  1587.                     (void)sel_begin();
  1588.                     (void)update(TRUE);
  1589.                     buttondown = TRUE;
  1590.                 }
  1591.             } else {
  1592.                 DispatchMessage(&msg);
  1593.             }
  1594.             break;
  1595.  
  1596.         case WM_RBUTTONDOWN:
  1597.             TRACE(("GETC:RBUTTONDOWN %s\n", which_window(msg.hwnd)))
  1598.             if (msg.hwnd == cur_win->text_hwnd) {
  1599.                 if (buttondown) {
  1600.                     (void)sel_release();
  1601.                     (void)update(TRUE);
  1602.                 }
  1603.             } else {
  1604.                 DispatchMessage(&msg);
  1605.             }
  1606.             break;
  1607.  
  1608.         case WM_MOUSEMOVE:
  1609.             if (buttondown) {
  1610.                 int x = PixelToCol(LOWORD(msg.lParam));
  1611.                 int y = PixelToRow(HIWORD(msg.lParam));
  1612.  
  1613.                 TRACE(("GETC:MOUSEMOVE (%d,%d)%s\n",
  1614.                     x, y, buttondown ? " selecting" : ""));
  1615.  
  1616.                 fhide_cursor();
  1617.                 if (!setcursor(y, x))
  1618.                     break;
  1619.                 if (get_keyboard_state()
  1620.                  & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
  1621.                     (void)sel_setshape(RECTANGLE);
  1622.                 if (!sel_extend(TRUE, TRUE))
  1623.                     break;
  1624.                 (void)update(TRUE);
  1625.             }
  1626.             break;
  1627.  
  1628.         case WM_LBUTTONUP:
  1629.             TRACE(("GETC:LBUTTONUP %s\n", which_window(msg.hwnd)))
  1630.             if (msg.hwnd == cur_win->text_hwnd) {
  1631.                 fhide_cursor();
  1632.                 if (buttondown) {
  1633.                     sel_yank(0);
  1634.                     buttondown = FALSE;
  1635.                 }
  1636.                 (void)update(TRUE);
  1637.                 fshow_cursor();
  1638.             } else {
  1639.                 DispatchMessage(&msg);
  1640.             }
  1641.             break;
  1642.  
  1643.         default:
  1644.             TRACE(("GETC:default(%s)\n", message2s(msg.message)))
  1645.         case WM_COMMAND:
  1646.         case WM_KEYUP:
  1647.         case WM_NCHITTEST:
  1648.         case WM_NCMOUSEMOVE:
  1649.         case WM_NCLBUTTONDOWN:
  1650.         case WM_PAINT:
  1651.         case WM_NCACTIVATE:
  1652.         case WM_SETCURSOR:
  1653.         case 0x118:
  1654.             DispatchMessage(&msg);
  1655.             break;
  1656.         }
  1657.     }
  1658.     fhide_cursor();
  1659.     vile_in_getfkey = 0;
  1660.  
  1661.     TRACE(("...ntgetch %#x\n", result))
  1662.     return result;
  1663. }
  1664.  
  1665. /*
  1666.  * The function `kbhit' returns true if there are *any* input records
  1667.  * available.  We need to define our own type ahead routine because
  1668.  * otherwise events which we will discard (like pressing or releasing
  1669.  * the Shift key) can block screen updates because `ntgetch' won't
  1670.  * return until a ordinary key event occurs.
  1671.  */
  1672.  
  1673. static int
  1674. nttypahead()
  1675. {
  1676. #if FIXME
  1677. #endif
  1678.     return 0;
  1679. }
  1680.  
  1681. /*
  1682.  * Move 'n' lines starting at 'from' to 'to'
  1683.  *
  1684.  * OPT_PRETTIER_SCROLL is prettier but slower -- it scrolls a line at a time
  1685.  *    instead of all at once.
  1686.  */
  1687.  
  1688. /* move howmany lines starting at from to to */
  1689. static void
  1690. ntscroll(int from, int to, int n)
  1691. {
  1692.     HDC     hDC;
  1693.     HBRUSH    brush;
  1694.     RECT region;
  1695.     RECT tofill;
  1696.  
  1697.     scflush();
  1698.     if (to == from)
  1699.         return;
  1700. #if OPT_PRETTIER_SCROLL
  1701.     if (absol(from-to) > 1) {
  1702.         ntscroll(from, (from<to) ? to-1:to+1, n);
  1703.         if (from < to)
  1704.             from = to-1;
  1705.         else
  1706.             from = to+1;
  1707.     }
  1708. #endif
  1709.  
  1710.     region.left   = 0;
  1711.     region.right  = (SHORT) ColToPixel(term.t_ncol);
  1712.  
  1713.     if (from > to) {
  1714.         region.top    = (SHORT) RowToPixel(to);
  1715.         region.bottom = (SHORT) RowToPixel(from + n);
  1716.     } else {
  1717.         region.top    = (SHORT) RowToPixel(from);
  1718.         region.bottom = (SHORT) RowToPixel(to + n);
  1719.     }
  1720.  
  1721.     TRACE(("ScrollWindowEx from=%d, to=%d, n=%d  (%d,%d)/(%d,%d)\n",
  1722.         from, to, n,
  1723.         region.left, region.top,
  1724.         region.right, region.bottom));
  1725.  
  1726.     ScrollWindowEx(
  1727.         cur_win->text_hwnd,    /* handle of window to scroll */
  1728.         0,        /* amount of horizontal scrolling */
  1729.         RowToPixel(to-from),    /* amount of vertical scrolling */
  1730.         ®ion,    /* address of structure with scroll rectangle */
  1731.         ®ion,    /* address of structure with clip rectangle */
  1732.         (HRGN)0,    /* handle of update region */
  1733.         &tofill,    /* address of structure for update rectangle */
  1734.         SW_ERASE    /* scrolling flags */
  1735.         );
  1736.     TRACE(("fill: (%d,%d)/(%d,%d)\n",
  1737.         tofill.left, tofill.top,
  1738.         tofill.right, tofill.bottom));
  1739.  
  1740.     hDC = GetDC(cur_win->text_hwnd);
  1741.     set_colors(hDC, cur_atr);
  1742.     brush = Background(hDC);
  1743.     FillRect(hDC, &tofill, brush);
  1744.     DeleteObject(brush);
  1745.     ReleaseDC(cur_win->text_hwnd, hDC);
  1746. }
  1747.  
  1748.  
  1749. #if OPT_SCROLLBARS
  1750. static
  1751. int check_scrollbar_allocs(void)
  1752. {
  1753.     int newmax = cur_win->rows/2;
  1754.     int oldmax = cur_win->maxscrollbars;
  1755.  
  1756.     TRACE(("check_scrollbar_allocs %d > %d ?\n", oldmax, newmax))
  1757.     if (newmax > oldmax) {
  1758.         GROW(cur_win->scrollbars, SBDATA, oldmax, newmax);
  1759.         cur_win->maxscrollbars = newmax;
  1760.         TRACE(("GROW scrollbars=%p, oldmax=%d, newmax=%d\n",
  1761.             cur_win->scrollbars, oldmax, newmax))
  1762.     }
  1763.     return TRUE;
  1764. }
  1765.  
  1766. static SBDATA
  1767. new_scrollbar(void)
  1768. {
  1769.     SBDATA result;
  1770.  
  1771.     result.shown    = FALSE;
  1772.     result.r.top    = -1;
  1773.     result.r.left   = -1;
  1774.     result.r.bottom = -1;
  1775.     result.r.right  = -1;
  1776.  
  1777.     result.w = CreateWindow(
  1778.         SCRL_CLASS,
  1779.         "scrollbar",
  1780.         WS_CHILD | SBS_VERT | WS_CLIPSIBLINGS,
  1781.         0,        /* x */
  1782.         0,        /* y */
  1783.         SbWidth,    /* width */
  1784.         1,        /* height */
  1785.         cur_win->main_hwnd,
  1786.         (HMENU)0,
  1787.         vile_hinstance,
  1788.         (LPVOID)0
  1789.         );
  1790.     return result;
  1791. }
  1792.  
  1793. static int
  1794. show_scrollbar(int n, int flag)
  1795. {
  1796.     if (cur_win->scrollbars[n].shown != flag) {
  1797.         ShowScrollBar(cur_win->scrollbars[n].w, SB_CTL, flag);
  1798.         cur_win->scrollbars[n].shown = flag;
  1799.         return TRUE;
  1800.     }
  1801.     return FALSE;
  1802. }
  1803.  
  1804. static void
  1805. set_scrollbar_range(int n, WINDOW *wp)
  1806. {
  1807.     SCROLLINFO info;
  1808.     int lnum, lcnt;
  1809.  
  1810.     lnum = line_no(wp->w_bufp, wp->w_dot.l);
  1811.     lnum = max(lnum, 1);
  1812.  
  1813.     lcnt = line_count(wp->w_bufp);
  1814.     lcnt = max(lcnt, 1) + wp->w_ntrows - 1;
  1815.  
  1816.     TRACE(("set_scrollbar_range(%d, %s) %d:%d\n",
  1817.         n, wp->w_bufp->b_bname, lnum, lcnt))
  1818.  
  1819.     info.cbSize = sizeof(info);
  1820.     info.fMask  = SIF_POS | SIF_RANGE | SIF_PAGE;
  1821.     info.nPos   = lnum - 1;
  1822.     info.nMin   = 0;
  1823.     info.nMax   = lcnt - 1;
  1824.     info.nPage  = wp->w_ntrows;
  1825.     SetScrollInfo(cur_win->scrollbars[n].w, SB_CTL, &info, TRUE);
  1826. }
  1827.  
  1828. /*
  1829.  * All we want to do here is to paint the gap between the real resize-grip and
  1830.  * the borders of the dummy window we're surrounding it with.  That's because
  1831.  * the resize-grip itself isn't resizable.
  1832.  */
  1833. LONG FAR PASCAL GripWndProc(
  1834.             HWND hWnd,
  1835.             UINT message,
  1836.             WPARAM wParam,
  1837.             LONG lParam)
  1838. {
  1839.     PAINTSTRUCT ps;
  1840.     HBRUSH brush;
  1841.  
  1842.     TRACE(("GRIP:%s\n", message2s(message)))
  1843.  
  1844.     switch (message) {
  1845.     case WM_PAINT:
  1846.         BeginPaint(hWnd, &ps);
  1847.         TRACE(("...painting (%d,%d) (%d,%d)\n",
  1848.             ps.rcPaint.top,
  1849.             ps.rcPaint.left,
  1850.             ps.rcPaint.bottom,
  1851.             ps.rcPaint.right))
  1852.         brush = CreateSolidBrush(GetSysColor(COLOR_SCROLLBAR));
  1853.         SelectObject(ps.hdc, brush);
  1854.         Rectangle(ps.hdc,
  1855.             ps.rcPaint.left,
  1856.             ps.rcPaint.top,
  1857.             ps.rcPaint.right,
  1858.             ps.rcPaint.bottom);
  1859.         DeleteObject(brush);
  1860.         EndPaint(hWnd, &ps);
  1861.         break;
  1862.     }
  1863.     return (DefWindowProc(hWnd, message, wParam, lParam));
  1864. }
  1865.  
  1866. static void
  1867. update_scrollbar_sizes(void)
  1868. {
  1869.     RECT crect;
  1870.     register WINDOW *wp;
  1871.     int i, top, left;
  1872.     int newsbcnt;
  1873.     int oldsbcnt = cur_win->nscrollbars;
  1874.  
  1875.     TRACE(("update_scrollbar_sizes\n"))
  1876.  
  1877.     i = 0;
  1878.     for_each_visible_window(wp)
  1879.         i++;
  1880.     newsbcnt = i;
  1881.  
  1882.     for (i = cur_win->nscrollbars+1; i <= newsbcnt; i++) {
  1883.         if (cur_win->scrollbars[i].w == NULL) {
  1884.             cur_win->scrollbars[i] = new_scrollbar();
  1885.             TRACE(("... created sb%d=%#x\n", i, cur_win->scrollbars[i].w))
  1886.         }
  1887.     }
  1888.     cur_win->nscrollbars = newsbcnt;
  1889.  
  1890.     /* Set sizes and positions on scrollbars and sliders */
  1891.     i = 0;
  1892.     GetClientRect(cur_win->main_hwnd, &crect);
  1893.     top = crect.top;
  1894.     left = crect.right - SbWidth;
  1895.     for_each_visible_window(wp) {
  1896.         int high = RowToPixel(wp->w_ntrows + 1);
  1897.         int wide = SbWidth;
  1898.         if (show_scrollbar(i, TRUE)
  1899.          || cur_win->scrollbars[i].r.top    != top
  1900.          || cur_win->scrollbars[i].r.left   != left
  1901.          || cur_win->scrollbars[i].r.bottom != high
  1902.          || cur_win->scrollbars[i].r.right  != wide) {
  1903.             MoveWindow(cur_win->scrollbars[i].w,
  1904.                 cur_win->scrollbars[i].r.left   = left,
  1905.                 cur_win->scrollbars[i].r.top    = top,
  1906.                 cur_win->scrollbars[i].r.right  = wide,
  1907.                 cur_win->scrollbars[i].r.bottom = high,
  1908.                 TRUE);
  1909.             TRACE(("... adjusted %s to (%d,%d) (%d,%d)\n",
  1910.                 which_window(cur_win->scrollbars[i].w),
  1911.                 left,
  1912.                 top,
  1913.                 SbWidth,
  1914.                 high));
  1915.          }
  1916.         if (cur_win->nscrollbars == i+1)
  1917.             set_scrollbar_range(i, wp);
  1918.         i++;
  1919.         top += high;
  1920.     }
  1921.  
  1922.     while (i < oldsbcnt) {
  1923.         (void) show_scrollbar(i, FALSE);
  1924.         i++;
  1925.     }
  1926. #if FIXME_RECUR_SB
  1927.     for_each_visible_window(wp) {
  1928.         wp->w_flag &= ~WFSBAR;
  1929.         gui_update_scrollbar(wp);
  1930.     }
  1931. #endif
  1932.  
  1933.     if (cur_win->size_box.w == 0) {
  1934.         cur_win->size_box.w = CreateWindow(
  1935.             GRIP_CLASS,
  1936.             "sizebox",
  1937.             WS_CHILD
  1938.             | WS_VISIBLE
  1939.             | WS_CLIPSIBLINGS,
  1940.             cur_win->size_box.r.left   = left,
  1941.             cur_win->size_box.r.top    = top,
  1942.             cur_win->size_box.r.right  = SbWidth + 1,
  1943.             cur_win->size_box.r.bottom = nLineHeight,
  1944.             cur_win->main_hwnd,
  1945.             (HMENU)0,
  1946.             vile_hinstance,
  1947.             (LPVOID)0
  1948.             );
  1949.         cur_win->size_grip.w = CreateWindow(
  1950.             "SCROLLBAR",
  1951.             "sizebox",
  1952.             WS_CHILD
  1953.             | WS_VISIBLE
  1954.             | SB_CTL
  1955.             | SBS_SIZEGRIP
  1956.             | WS_CLIPSIBLINGS
  1957.             | SBS_SIZEBOXBOTTOMRIGHTALIGN,
  1958.             cur_win->size_box.r.left   = 0,
  1959.             cur_win->size_box.r.top    = 0,
  1960.             cur_win->size_box.r.right  = SbWidth,
  1961.             cur_win->size_box.r.bottom = nLineHeight,
  1962.             cur_win->size_box.w,
  1963.             (HMENU)0,
  1964.             vile_hinstance,
  1965.             (LPVOID)0
  1966.             );
  1967.         TRACE(("... made SIZEGRIP %x at %d,%d\n", cur_win->size_box.w, left, top))
  1968.     } else {
  1969.         int ok;
  1970.  
  1971.         if (cur_win->size_box.r.left   != left
  1972.          || cur_win->size_box.r.top    != top
  1973.          || cur_win->size_box.r.right  != SbWidth
  1974.          || cur_win->size_box.r.bottom != nLineHeight) {
  1975.             ok = MoveWindow(cur_win->size_box.w,
  1976.                 cur_win->size_box.r.left   = left,
  1977.                 cur_win->size_box.r.top    = top,
  1978.                 cur_win->size_box.r.right  = SbWidth,
  1979.                 cur_win->size_box.r.bottom = nLineHeight,
  1980.                 TRUE);
  1981.             TRACE(("... move SIZE_BOX %d:%x to %d,%d\n",
  1982.                 ok, cur_win->size_box.w, left, top))
  1983.         }
  1984.  
  1985.         left = 0;
  1986.         top  = 0;
  1987.         if (cur_win->size_grip.r.left   != left
  1988.          || cur_win->size_grip.r.top    != top
  1989.          || cur_win->size_grip.r.right  != SbWidth
  1990.          || cur_win->size_grip.r.bottom != nLineHeight) {
  1991.             ok = MoveWindow(cur_win->size_grip.w,
  1992.                 cur_win->size_grip.r.left   = left,
  1993.                 cur_win->size_grip.r.top    = top,
  1994.                 cur_win->size_grip.r.right  = SbWidth,
  1995.                 cur_win->size_grip.r.bottom = nLineHeight,
  1996.                 TRUE);
  1997.             TRACE(("... move SIZEGRIP %d:%x to %d,%d\n",
  1998.                 ok, cur_win->size_grip.w, left, top))
  1999.         }
  2000.     }
  2001. }
  2002.  
  2003. void
  2004. gui_update_scrollbar(WINDOW *uwp)
  2005. {
  2006.     WINDOW *wp;
  2007.     int i;
  2008.  
  2009.     TRACE(("gui_update_scrollbar uwp=%p %s\n", uwp, uwp->w_bufp->b_bname))
  2010.     if (dont_update_sb)
  2011.         return;
  2012.  
  2013.     i = 0;
  2014.     for_each_visible_window(wp) {
  2015.         TRACE(("wp=%p name='%s'\n", wp, wp->w_bufp->b_bname))
  2016.         if (wp == uwp)
  2017.             break;
  2018.         i++;
  2019.     }
  2020.  
  2021.     TRACE(("i=%d, nscrollbars=%d\n", i, cur_win->nscrollbars))
  2022.     if (i >= cur_win->nscrollbars || (wp->w_flag & WFSBAR)) {
  2023.         /*
  2024.          * update_scrollbar_sizes will recursively invoke gui_update_scrollbar,
  2025.          * but with WFSBAR disabled.
  2026.          */
  2027.         update_scrollbar_sizes();
  2028.         return;
  2029.     }
  2030.  
  2031.     set_scrollbar_range(i, wp);
  2032. }
  2033.  
  2034. static int find_scrollbar (HWND hWnd)
  2035. {
  2036.     WINDOW *wp;
  2037.     int i = 0;
  2038.  
  2039.     for_each_visible_window(wp) {
  2040.         if (cur_win->scrollbars[i].w == hWnd) {
  2041.             set_curwp (wp);
  2042.             if (wp->w_bufp != curbp) {
  2043.                 swbuffer(wp->w_bufp);
  2044.             }
  2045.             return i;
  2046.         }
  2047.         i++;
  2048.     }
  2049.     return -1;
  2050. }
  2051.  
  2052. static void handle_scrollbar (HWND hWnd, int msg, int nPos)
  2053. {
  2054.     int snum = find_scrollbar(hWnd);
  2055.  
  2056.     TRACE(("handle_scrollbar msg=%d, nPos=%d\n", msg, nPos))
  2057.  
  2058.     if (snum < 0) {
  2059.         TRACE(("...could not find window for %s\n", which_window(hWnd)))
  2060.         return;
  2061.     }
  2062.  
  2063.     fhide_cursor();
  2064.     switch (msg)
  2065.     {
  2066.     case SB_BOTTOM:
  2067.         TRACE(("-> SB_BOTTOM\n"))
  2068.         gotoline(FALSE, 1);
  2069.         break;
  2070.     case SB_ENDSCROLL:
  2071.         TRACE(("-> SB_ENDSCROLL\n"))
  2072.         break;
  2073.     case SB_LINEDOWN:
  2074.         TRACE(("-> SB_LINEDOWN\n"))
  2075.         mvdnwind(FALSE,1);
  2076.         break;
  2077.     case SB_LINEUP:
  2078.         TRACE(("-> SB_LINEUP\n"))
  2079.         mvupwind(FALSE,1);
  2080.         break;
  2081.     case SB_PAGEDOWN:
  2082.         TRACE(("-> SB_PAGEDOWN\n"))
  2083.         forwpage(FALSE,1);
  2084.         break;
  2085.     case SB_PAGEUP:
  2086.         TRACE(("-> SB_PAGEUP\n"))
  2087.         backpage(FALSE,1);
  2088.         break;
  2089.     case SB_THUMBPOSITION:
  2090.         TRACE(("-> SB_THUMBPOSITION: %d\n", nPos))
  2091.         gotoline(TRUE, nPos + 1);
  2092.         break;
  2093.     case SB_THUMBTRACK:
  2094.         TRACE(("-> SB_THUMBTRACK: %d\n", nPos))
  2095.         mvupwind(TRUE, line_no(curwp->w_bufp, curwp->w_line.l) - nPos);
  2096.         break;
  2097.     case SB_TOP:
  2098.         TRACE(("-> SB_TOP\n"))
  2099.         gotoline(TRUE, 1);
  2100.         break;
  2101.     }
  2102.     (void)update(TRUE);
  2103.     set_scrollbar_range(snum, curwp);
  2104.     fshow_cursor();
  2105. }
  2106. #endif /* OPT_SCROLLBARS */
  2107.  
  2108. static void repaint_window(HWND hWnd)
  2109. {
  2110.     PAINTSTRUCT ps;
  2111.     HBRUSH brush;
  2112.     int x0, y0, x1, y1;
  2113.     int row, col;
  2114.  
  2115.     BeginPaint(hWnd, &ps);
  2116.     TRACE(("repaint_window (erase:%d)\n", ps.fErase))
  2117.     SelectObject(ps.hdc, GetMyFont());
  2118.     set_colors(ps.hdc, cur_atr);
  2119.     brush = Background(ps.hdc);
  2120.  
  2121.     TRACE(("...painting (%d,%d) (%d,%d)\n",
  2122.         ps.rcPaint.top,
  2123.         ps.rcPaint.left,
  2124.         ps.rcPaint.bottom,
  2125.         ps.rcPaint.right))
  2126.  
  2127.     y0 = (ps.rcPaint.top) / nLineHeight;
  2128.     x0 = (ps.rcPaint.left) / nCharWidth;
  2129.     y1 = (ps.rcPaint.bottom + nLineHeight) / nLineHeight;
  2130.     x1 = (ps.rcPaint.right  + nCharWidth)  / nCharWidth;
  2131.  
  2132.     if (y0 < 0)
  2133.         y0 = 0;
  2134.     if (x0 < 0)
  2135.         x0 = 0;
  2136.  
  2137.     TRACE(("...erase %d\n", ps.fErase))
  2138.     TRACE(("...cells (%d,%d) - (%d,%d)\n", y0,x0, y1,x1))
  2139.     TRACE(("...top:    %d\n", RowToPixel(y0) - ps.rcPaint.top))
  2140.     TRACE(("...left:   %d\n", ColToPixel(x0) - ps.rcPaint.left))
  2141.     TRACE(("...bottom: %d\n", RowToPixel(y1) - ps.rcPaint.bottom))
  2142.     TRACE(("...right:  %d\n", ColToPixel(x1) - ps.rcPaint.right))
  2143.  
  2144.     for (row = y0; row < y1; row++) {
  2145.         if (pscreen != 0
  2146.          && pscreen[row]->v_text != 0
  2147.          && pscreen[row]->v_attrs != 0) {
  2148.             for (col = x0; col < x1; col++) {
  2149.                 set_colors(ps.hdc, CELL_ATTR(row,col));
  2150.                 TextOut(ps.hdc,
  2151.                     ColToPixel(col),
  2152.                     RowToPixel(row),
  2153.                     &CELL_TEXT(row,col), 1);
  2154.             }
  2155.         }
  2156.     }
  2157.     DeleteObject(brush);
  2158.  
  2159.     TRACE(("...repaint_window\n"))
  2160.     EndPaint(hWnd, &ps);
  2161. }
  2162.  
  2163. static int khit = 0;
  2164.  
  2165. int kbhit(void)
  2166. {
  2167.     MSG msg;
  2168.     int hit;
  2169.  
  2170.     if(PeekMessage(&msg, (HWND)0, (UINT)0, (UINT)0, PM_REMOVE)){
  2171.         TranslateMessage(&msg);
  2172.         DispatchMessage(&msg);
  2173.     }
  2174.  
  2175.     hit = khit;
  2176.     khit = 0;
  2177.     return hit;
  2178. }
  2179.  
  2180. static void HandleClose(HWND hWnd)
  2181. {
  2182.  
  2183.     quit(FALSE,1);
  2184. }
  2185.  
  2186. LONG FAR PASCAL TextWndProc(
  2187.             HWND hWnd,
  2188.             UINT message,
  2189.             WPARAM wParam,
  2190.             LONG lParam)
  2191. {
  2192.     TRACE(("TEXT:%s, %s\n", message2s(message), which_window(hWnd)))
  2193.  
  2194.     switch (message) {
  2195.     case WM_PAINT:
  2196.         if (GetUpdateRect(hWnd, (LPRECT)0, FALSE)) {
  2197.             repaint_window(hWnd);
  2198.         } else {
  2199.             TRACE(("FIXME:WM_PAINT\n"))
  2200.             return (DefWindowProc(hWnd, message, wParam, lParam));
  2201.         }
  2202.         break;
  2203.  
  2204.     case WM_KEYDOWN:
  2205.     case WM_LBUTTONDOWN:
  2206.     case WM_RBUTTONDOWN:
  2207.     case WM_SYSKEYDOWN:
  2208.         khit = 1;
  2209.         /* FALLTHRU */
  2210.     default:
  2211.         return (DefWindowProc(hWnd, message, wParam, lParam));
  2212.  
  2213.     IGN_PROC("TEXT:", WM_ERASEBKGND);
  2214.     }
  2215.     return (0);
  2216. }
  2217.  
  2218. LONG FAR PASCAL MainWndProc(
  2219.             HWND hWnd,
  2220.             UINT message,
  2221.             WPARAM wParam,
  2222.             LONG lParam)
  2223. {
  2224. #if FIXME
  2225.     FARPROC lpProcAbout;
  2226. #endif
  2227.  
  2228.     TRACE(("MAIN:%s, %s\n", message2s(message), which_window(hWnd)))
  2229.  
  2230.     switch (message) {
  2231.     HANDLE_MSG(hWnd, WM_CLOSE,    HandleClose);
  2232.     case WM_COMMAND:
  2233. #if FIXME
  2234.         switch (wParam) {
  2235.         case IDC_button:
  2236.             khit = 1;
  2237.             wParam = IDC_button_x;
  2238.             PostMessage(hWnd, message, wParam, lParam);
  2239.             break;
  2240.         case IDM_ABOUT:
  2241.             lpProcAbout = MakeProcInstance(About, vile_hinstance);
  2242.             DialogBox(vile_hinstance, "AboutBox", hWnd, lpProcAbout);
  2243.             FreeProcInstance(lpProcAbout);
  2244.             break;
  2245.  
  2246.         /* file menu commands */
  2247.  
  2248.         case IDM_PRINT:
  2249.             MessageBox (
  2250.                 GetFocus(),
  2251.                 "Command not implemented",
  2252.                 MY_APPLE,
  2253.                 MB_ICONASTERISK | MB_OK);
  2254.             break;
  2255.  
  2256.         case IDM_EXIT:
  2257.             DestroyWindow(hWnd);
  2258.             break;
  2259.         }
  2260. #endif
  2261.         break;
  2262.  
  2263. /*
  2264.     case WM_SIZE:
  2265.         MoveWindow(cur_win->main_hwnd, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
  2266.         break;
  2267. */
  2268.     case WM_SETFOCUS:
  2269.         fshow_cursor();
  2270.         break;
  2271.  
  2272.     case WM_KILLFOCUS:
  2273.         fhide_cursor();
  2274.         break;
  2275.  
  2276.     case WM_DESTROY:
  2277.         PostQuitMessage(0);
  2278.         break;
  2279.  
  2280.     case WM_WINDOWPOSCHANGED:
  2281.         ResizeClient();
  2282.         return (DefWindowProc(hWnd, message, wParam, lParam));
  2283.  
  2284.     case WM_WINDOWPOSCHANGING:
  2285. #if FIXME_POSCHANGING
  2286.         if (wheadp != 0)
  2287.             return AdjustPosChanging(hWnd, (LPWINDOWPOS)lParam);
  2288. #endif
  2289.         return (DefWindowProc(hWnd, message, wParam, lParam));
  2290.  
  2291.     case WM_SIZING:
  2292.         return AdjustResizing(hWnd, wParam, (LPRECT)lParam);
  2293.  
  2294.     case WM_EXITSIZEMOVE:
  2295.         ResizeClient();
  2296.         return (DefWindowProc(hWnd, message, wParam, lParam));
  2297.  
  2298.     case WM_SYSCOMMAND:
  2299.         TRACE(("MAIN:WM_SYSCOMMAND %s at %d,%d\n",
  2300.             syscommand2s(LOWORD(wParam)),
  2301.             HIWORD(lParam),
  2302.             LOWORD(lParam)))
  2303.         switch(LOWORD(wParam))
  2304.         {
  2305.         case MM_FONT:
  2306.             set_font();
  2307.             break;
  2308.         }
  2309.         return (DefWindowProc(hWnd, message, wParam, lParam));
  2310.  
  2311. #if OPT_SCROLLBARS
  2312.     case WM_VSCROLL:
  2313.         handle_scrollbar((HWND)lParam, LOWORD(wParam), HIWORD(wParam));
  2314.         return (DefWindowProc(hWnd, message, wParam, lParam));
  2315. #endif
  2316.  
  2317.     case WM_KEYDOWN:
  2318.     case WM_LBUTTONDOWN:
  2319.     case WM_RBUTTONDOWN:
  2320.     case WM_SYSKEYDOWN:
  2321.         khit = 1;
  2322.         /* FALLTHRU */
  2323.     default:
  2324.         return (TextWndProc(hWnd, message, wParam, lParam));
  2325.  
  2326.     IGN_PROC("MAIN:", WM_ERASEBKGND);
  2327.     }
  2328.     return (1);
  2329. }
  2330.  
  2331. static BOOL
  2332. InitInstance(HINSTANCE hInstance, int nCmdShow)
  2333. {
  2334.     WNDCLASS  wc;
  2335.  
  2336.     hglass_cursor    = LoadCursor((HINSTANCE)0, IDC_WAIT);
  2337.     arrow_cursor     = LoadCursor((HINSTANCE)0, IDC_ARROW);
  2338.  
  2339.     default_bcolor   = GetSysColor(COLOR_WINDOWTEXT+1);
  2340.     default_fcolor   = GetSysColor(COLOR_WINDOW+1);
  2341.  
  2342.     ZeroMemory(&wc, sizeof(&wc));
  2343.     wc.style         = CS_VREDRAW | CS_HREDRAW;
  2344.     wc.lpfnWndProc   = (WNDPROC) MainWndProc;
  2345.     wc.cbClsExtra    = 0;
  2346.     wc.cbWndExtra    = 0;
  2347.     wc.hInstance     = hInstance;
  2348.     wc.hIcon         = LoadIcon(hInstance, "VilewIcon");
  2349.     wc.hCursor       = arrow_cursor;
  2350.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  2351.     wc.lpszMenuName  = "VileMenu";
  2352.     wc.lpszClassName = MAIN_CLASS;
  2353.  
  2354.     if(! RegisterClass(&wc))
  2355.         return FALSE;
  2356.  
  2357.     TRACE(("Registered(%s)\n", MAIN_CLASS))
  2358.  
  2359.     vile_hinstance = hInstance;
  2360.     hAccTable = LoadAccelerators(vile_hinstance, "VileAcc");
  2361.  
  2362.     cur_win->main_hwnd = CreateWindow(
  2363.         MAIN_CLASS,
  2364.         MY_APPLE,
  2365.         WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  2366.         CW_USEDEFAULT,
  2367.         CW_USEDEFAULT,
  2368.         1,
  2369.         1,
  2370.         (HWND)0,
  2371.         (HMENU)0,
  2372.         hInstance,
  2373.         (LPVOID)0
  2374.     );
  2375.     TRACE(("CreateWindow(main) -> %#lx\n", cur_win->main_hwnd))
  2376.     if (!cur_win->main_hwnd)
  2377.         return (FALSE);
  2378.  
  2379.     ZeroMemory(&wc, sizeof(&wc));
  2380.     wc.style         = CS_VREDRAW | CS_HREDRAW;
  2381.     wc.lpfnWndProc   = (WNDPROC) TextWndProc;
  2382.     wc.cbClsExtra    = 0;
  2383.     wc.cbWndExtra    = 0;
  2384.     wc.hInstance     = hInstance;
  2385.     wc.hIcon         = 0;
  2386.     wc.hCursor       = arrow_cursor;
  2387.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  2388.     wc.lpszMenuName  = 0;
  2389.     wc.lpszClassName = TEXT_CLASS;
  2390.  
  2391.     if(! RegisterClass(&wc))
  2392.         return FALSE;
  2393.  
  2394.     TRACE(("Registered(%s)\n", TEXT_CLASS))
  2395.  
  2396.     cur_win->text_hwnd = CreateWindow(
  2397.         TEXT_CLASS,
  2398.         "text",
  2399.         WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
  2400.         CW_USEDEFAULT,
  2401.         CW_USEDEFAULT,
  2402.         1,
  2403.         1,
  2404.         cur_win->main_hwnd,
  2405.         (HMENU)0,
  2406.         hInstance,
  2407.         (LPVOID)0
  2408.     );
  2409.     TRACE(("CreateWindow(text) -> %#lx\n", cur_win->text_hwnd))
  2410.     if (!cur_win->text_hwnd)
  2411.         return (FALSE);
  2412.  
  2413.     /*
  2414.      * Register the GRIP_CLASS now also, otherwise it won't succeed when
  2415.      * we create the first scrollbars, until we resize the window.
  2416.      */
  2417. #if OPT_SCROLLBARS
  2418.     ZeroMemory(&wc, sizeof(&wc));
  2419.     wc.style         = CS_VREDRAW | CS_HREDRAW;
  2420.     wc.lpfnWndProc   = (WNDPROC) GripWndProc;
  2421.     wc.cbClsExtra    = 0;
  2422.     wc.cbWndExtra    = 0;
  2423.     wc.hInstance     = vile_hinstance;
  2424.     wc.hCursor       = arrow_cursor;
  2425.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  2426.     wc.lpszMenuName  = 0;
  2427.     wc.lpszClassName = GRIP_CLASS;
  2428.  
  2429.     if(! RegisterClass(&wc)) {
  2430.         TRACE(("could not register class %s:%#x\n", GRIP_CLASS, GetLastError()))
  2431.         return (FALSE);
  2432.     }
  2433.     TRACE(("Registered(%s)\n", GRIP_CLASS))
  2434. #endif
  2435.  
  2436.     cur_win->nscrollbars = -1;
  2437.  
  2438.     /*
  2439.      * Insert "File" and "Font" before "Close" in the system menu.
  2440.      */
  2441.     vile_menu = GetSystemMenu(cur_win->main_hwnd, FALSE);
  2442.     AppendMenu(vile_menu, MF_SEPARATOR, 0, NULL);
  2443. #if 0    /* FIXME: later */
  2444.     AppendMenu(vile_menu, MF_STRING, MM_FILE, "File");
  2445. #endif
  2446.     AppendMenu(vile_menu, MF_STRING, MM_FONT, "&Font");
  2447.  
  2448. #if OPT_SCROLLBARS
  2449.     if (check_scrollbar_allocs() != TRUE)
  2450.         return (FALSE);
  2451. #endif
  2452.  
  2453.     get_font(&vile_logfont);
  2454.     use_font(vile_font, FALSE);
  2455.  
  2456.     ShowWindow(cur_win->main_hwnd, nCmdShow);
  2457.     UpdateWindow(cur_win->main_hwnd);
  2458.     return (TRUE);
  2459. }
  2460.  
  2461. int WINAPI
  2462. WinMain(
  2463.     HINSTANCE hInstance,
  2464.     HINSTANCE hPrevInstance,
  2465.     LPSTR lpCmdLine,
  2466.     int nCmdShow)
  2467. {
  2468. #define MAXARGS 12
  2469.     int argc = 0;
  2470.     int n;
  2471.     char *argv[MAXARGS];
  2472.     char *ptr, *fontstr;
  2473. #ifdef VILE_OLE
  2474.     int oa_invoke, oa_reg;
  2475.  
  2476.     memset(&oa_opts, 0, sizeof(oa_opts));
  2477.     oa_invoke = oa_reg = FALSE;
  2478. #endif
  2479.  
  2480.     TRACE(("Starting ntvile, CmdLine:%s\n", lpCmdLine))
  2481.  
  2482.     argv[argc++] = "VILE";
  2483.  
  2484.     for(ptr = lpCmdLine; *ptr != '\0';) {
  2485.         char delim = ' ';
  2486.  
  2487.         while (*ptr == ' ')
  2488.             ptr++;
  2489.  
  2490.         if (*ptr == '\''
  2491.          || *ptr == '"'
  2492.          || *ptr == ' ') {
  2493.             delim = *ptr++;
  2494.         }
  2495.         TRACE(("argv%d:%s\n", argc, ptr))
  2496.         argv[argc++] = ptr;
  2497.         if (argc+1 >= MAXARGS) {
  2498.             break;
  2499.         }
  2500.         while (*ptr != delim && *ptr != '\0')
  2501.             ptr++;
  2502.         if (*ptr == delim)
  2503.             *ptr++ = '\0';
  2504.     }
  2505.     fontstr = argv[argc] = 0;
  2506.  
  2507.     SetCols(80);
  2508.     SetRows(24);
  2509.  
  2510.     /*
  2511.      * Get screen size and OLE options, if any.  Parsing logic is
  2512.      * messy, but must remain that way to handle the various command
  2513.      * line options available with and without OLE automation.
  2514.      */
  2515.     for (n = 1; n < argc; n++) {
  2516.         int m = n, eat = 0;
  2517.         if (n + 1 < argc) {
  2518.             if (strcmp(argv[n], "-geometry") == 0) {
  2519.                 char *src = argv[n+1];
  2520.                 char *dst = 0;
  2521.                 int value = strtol(src, &dst, 0);
  2522.                 if (dst != src) {
  2523.                     if (value > 2)
  2524.                         SetCols(value);
  2525.                     if (*dst++ == 'x') {
  2526.                         src = dst;
  2527.                         value = strtol(src, &dst, 0);
  2528.                         if (value > 2) {
  2529.                             SetRows(value);
  2530. #ifdef VILE_OLE
  2531.                             oa_opts.cols = term.t_ncol;
  2532.                             oa_opts.rows = term.t_nrow;
  2533. #endif
  2534.                         }
  2535.                     }
  2536.                     eat = 2;
  2537.                 }
  2538.             }
  2539.             else if (strcmp(argv[n], "-font") == 0 ||
  2540.                         strcmp(argv[n], "-fn") == 0)
  2541.             {
  2542.                 fontstr = argv[n + 1];
  2543.                 eat     = 2;
  2544.             }
  2545.         }
  2546. #ifdef VILE_OLE
  2547.         if (eat == 0)
  2548.         {
  2549.             /* No valid options seen yet. */
  2550.  
  2551.             if (argv[n][0] == '-' && argv[n][1] == 'O')
  2552.             {
  2553.                 int which = argv[n][2];
  2554.  
  2555.                 if (which == 'r')
  2556.                 {
  2557.                     /*
  2558.                      * Flag OLE registration request,
  2559.                      * but don't eat argument.  Instead,
  2560.                      * registration will be carried out
  2561.                      * in main.c, so that the regular
  2562.                      * cmdline parser has an opportunity
  2563.                      * to flag misspelled OLE options.
  2564.                      *
  2565.                      * Ex:  winvile -Or -mutiple
  2566.                      */
  2567.  
  2568.                     oa_reg = TRUE;
  2569.                 }
  2570.                 else if (which == 'u')
  2571.                     ExitProgram(oleauto_unregister());
  2572.                 else if (which == 'a')
  2573.                 {
  2574.                     oa_invoke = TRUE;
  2575.                     eat       = 1;
  2576.                 }
  2577.             }
  2578.             else if (strcmp(argv[n], "-invisible") == 0)
  2579.             {
  2580.                 oa_opts.invisible = TRUE;
  2581.                 eat               = 1;
  2582.             }
  2583.             else if (strcmp(argv[n], "-multiple") == 0)
  2584.             {
  2585.                 oa_opts.multiple = TRUE;
  2586.                 eat            = 1;
  2587.             }
  2588.         }
  2589. #endif
  2590.         if (eat) {
  2591.             while (m+eat <= argc) {
  2592.                 argv[m] = argv[m+eat];
  2593.                 m++;
  2594.             }
  2595.             n--;
  2596.             argc -= eat;
  2597.         }
  2598.     }
  2599.  
  2600. #ifdef VILE_OLE
  2601.     if (oa_reg && oa_invoke)
  2602.     {
  2603.         /* tsk tsk */
  2604.  
  2605.         MessageBox(cur_win->main_hwnd,
  2606.                "-Oa and -Or are mutually exclusive",
  2607.                prognam,
  2608.                MB_OK|MB_ICONSTOP);
  2609.         ExitProgram(1);
  2610.     }
  2611.     if (oa_reg)
  2612.     {
  2613.         /*
  2614.          * The main program's cmd line parser will eventually cause
  2615.          * OLE autoamation registration to occur, at which point
  2616.          * winvile exits.  So don't show a window.
  2617.          */
  2618.  
  2619.         nCmdShow = SW_HIDE;
  2620.     }
  2621.     if (oa_opts.invisible)
  2622.         nCmdShow = SW_HIDE;
  2623. #endif
  2624.  
  2625.     if (!InitInstance(hInstance, nCmdShow))
  2626.         return (FALSE);
  2627.  
  2628.     /*
  2629.      * Vile window created and default font set.  It's now kosher to set
  2630.      * the font from a cmdline switch.
  2631.      */
  2632.     if (fontstr)
  2633.     {
  2634.         int success = ntwinio_font_frm_str(fontstr, TRUE);
  2635.  
  2636. #ifdef VILE_OLE
  2637.         if (oa_reg)
  2638.         {
  2639.             if (! success)
  2640.             {
  2641.                 /*
  2642.                  * That's it, game over -- crummy font spec detected during
  2643.                  * OLE registration.
  2644.                  */
  2645.  
  2646.                 ExitProgram(1);
  2647.             }
  2648.             else
  2649.                 oa_opts.fontstr = fontstr;
  2650.         }
  2651. #endif
  2652.         /* Regardless of success or failure, continue with new/default font. */
  2653.     }
  2654.  
  2655. #ifdef VILE_OLE
  2656.     if (oa_invoke)
  2657.     {
  2658.         /* Intialize OLE Automation */
  2659.  
  2660.         if (! oleauto_init(&oa_opts))
  2661.             ExitProgram(1);
  2662.     }
  2663. #endif
  2664.  
  2665.     return MainProgram(argc, argv);
  2666. }
  2667.  
  2668. void *
  2669. winvile_hwnd(void)
  2670. {
  2671.     return (cur_win->main_hwnd);
  2672. }
  2673.  
  2674. #ifdef VILE_OLE
  2675. void
  2676. ntwinio_oleauto_reg(void)
  2677. {
  2678.     /* Pound a bunch of OLE registration data into the registry & exit. */
  2679.  
  2680.     ExitProgram(oleauto_register(&oa_opts));
  2681. }
  2682. #endif
  2683.  
  2684. /*
  2685.  * Split the version-message to allow us to format with tabs, so the
  2686.  * proportional font doesn't look ugly.
  2687.  */
  2688. static size_t
  2689. option_size(const char *option)
  2690. {
  2691.     if (*option == '-') {
  2692.         const char *next = skip_ctext(option);
  2693.         if (next[0] == ' '
  2694.          && next[1] != ' '
  2695.          && next[1] != 0) {
  2696.             next = skip_ctext(next + 1);
  2697.             return next - option;
  2698.         }
  2699.         return 14;    /* use embedded blanks to fix the tabs ... */
  2700.     }
  2701.     return 0;
  2702. }
  2703.  
  2704. void
  2705. gui_version(char *program)
  2706. {
  2707.     ShowWindow(cur_win->main_hwnd, SW_HIDE);
  2708.     MessageBox(cur_win->main_hwnd, getversion(), prognam, MB_OK|MB_ICONSTOP);
  2709. }
  2710.  
  2711. void
  2712. gui_usage(char *program, const char *const *options, size_t length)
  2713. {
  2714.     char *buf, *s;
  2715.     size_t need, n;
  2716.     const char *fmt1 = "%s\n\nOptions:\n";
  2717.     const char *fmt2 = "    %s\t%s\n";
  2718.     const char *fmt3 = "%s\n";
  2719.  
  2720.     /*
  2721.      * Hide the (partly-constructed) main window.  It'll flash (FIXME).
  2722.      */
  2723.     ShowWindow(cur_win->main_hwnd, SW_HIDE);
  2724.  
  2725.     need = strlen(fmt1) + strlen(prognam);
  2726.     for (n = 0; n < length; n++) {
  2727.         if (option_size(options[n]))
  2728.             need += strlen(fmt2) + strlen(options[n]);
  2729.         else
  2730.             need += strlen(fmt3) + strlen(options[n]);
  2731.     }
  2732.     buf = malloc(need);
  2733.  
  2734.     s = lsprintf(buf, fmt1, prognam);
  2735.     for (n = 0; n < length; n++) {
  2736.         char    temp[80];
  2737.         if ((need = option_size(options[n])) != 0) {
  2738.             strncpy(temp, options[n], need);
  2739.             temp[need] = EOS;
  2740.             s = lsprintf(s, fmt2, temp, skip_cblanks(options[n] + need));
  2741.         } else {
  2742.             s = lsprintf(s, fmt3, options[n]);
  2743.         }
  2744.     }
  2745.  
  2746.     MessageBox(cur_win->main_hwnd, buf, prognam, MB_OK|MB_ICONSTOP);
  2747. }
  2748.