gui_w32.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:132k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. FILE *fd;
  2. char line[LINE_LEN];
  3. char_u *fname;
  4. fname = expand_env_save((char_u *)"$VIM/rgb.txt");
  5. if (fname == NULL)
  6.     return (GuiColor)-1;
  7. fd = fopen((char *)fname, "rt");
  8. vim_free(fname);
  9. if (fd == NULL)
  10.     return (GuiColor)-1;
  11. while (!feof(fd))
  12. {
  13.     int     len;
  14.     int     pos;
  15.     char    *color;
  16.     fgets(line, LINE_LEN, fd);
  17.     len = strlen(line);
  18.     if (len <= 1 || line[len-1] != 'n')
  19. continue;
  20.     line[len-1] = '';
  21.     i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
  22.     if (i != 3)
  23. continue;
  24.     color = line + pos;
  25.     if (STRICMP(color, name) == 0)
  26.     {
  27. fclose(fd);
  28. return (GuiColor) RGB(r,g,b);
  29.     }
  30. }
  31. fclose(fd);
  32.     }
  33.     return (GuiColor)-1;
  34. }
  35. /*
  36.  * Set the current text foreground color.
  37.  */
  38.     void
  39. gui_mch_set_fg_color(GuiColor color)
  40. {
  41.     gui.currFgColor = color;
  42. }
  43. /*
  44.  * Set the current text background color.
  45.  */
  46.     void
  47. gui_mch_set_bg_color(GuiColor color)
  48. {
  49.     gui.currBgColor = color;
  50. }
  51. #if defined(MULTI_BYTE) || defined(PROTO)
  52. /*
  53.  * Multi-byte handling, by Sung-Hoon Baek
  54.  */
  55.     static void
  56. HanExtTextOut(HDC hdc,int X, int Y, UINT fuOption, const RECT *lprc,
  57. LPCTSTR lpString, UINT cbCount, const int *lpDx, BOOL bOpaque)
  58. {
  59.     LPCTSTR pszTemp;
  60.     int i;
  61.     HPEN hpen, old_pen;
  62.     POINT point;
  63.     if (gui.char_width == sysfixed_width && gui.char_height == sysfixed_height)
  64.     {
  65. hpen = CreatePen(PS_SOLID, 2, gui.currFgColor);
  66. old_pen = SelectObject(hdc, hpen);
  67. pszTemp = lpString;
  68. i = 0;
  69. while (cbCount > 0)
  70. {
  71.     if (cbCount > 1 && IsLeadByte(*pszTemp))
  72.     {
  73. cbCount -= 2;
  74. pszTemp += 2;
  75. i += 2;
  76.     }
  77.     else if (*pszTemp == '\')
  78.     {
  79. if (i > 0)
  80.     ExtTextOut(hdc, X+((pszTemp-i)-lpString)*gui.char_width, Y,
  81.     fuOption, lprc, pszTemp-i, i, lpDx);
  82. MoveToEx(hdc, (int)(X+(pszTemp-lpString)*gui.char_width
  83.     + gui.char_width*0.2),
  84. (int)(Y + gui.char_height*0.2), &point);
  85. LineTo(hdc, (int)(X+(pszTemp-lpString)*gui.char_width
  86.     + gui.char_width*0.8),
  87. (int)(Y + gui.char_height*0.75));
  88. pszTemp++;
  89. cbCount--;
  90. i = 0;
  91.     }
  92.     else
  93.     {
  94. pszTemp++;
  95. cbCount--;
  96. i++;
  97.     }
  98. }
  99. if (i > 0)
  100. {
  101.     int OldBkMode;
  102.     if (bOpaque)
  103.     {
  104. OldBkMode = GetBkMode(hdc);
  105. SetBkMode(hdc, OPAQUE);
  106.     }
  107.     ExtTextOut(hdc,X+((pszTemp-i)-lpString)*gui.char_width,Y,
  108.     fuOption,lprc,pszTemp-i,i,lpDx);
  109.     if (bOpaque)
  110. SetBkMode(hdc, OldBkMode);
  111. }
  112. DeleteObject(SelectObject(hdc, old_pen));
  113.     }
  114.     else
  115. ExtTextOut(hdc,X,Y,fuOption,lprc,lpString,cbCount,lpDx);
  116. }
  117. # if defined(MULTI_BYTE_IME) || defined(PROTO)
  118. #include <imm.h>
  119. static BOOL bKoreanMode = FALSE;
  120. static char lpCompStr[100]; // Pointer to composition str.
  121. static BOOL bInComposition=FALSE;
  122. static BOOL bCommandMode=TRUE;
  123. static BOOL bImeKorean=FALSE;
  124. /*
  125.  * display composition string(korean)
  126.  */
  127.     static void
  128. DisplayCompStringOpaque(char_u *s, int len)
  129. {
  130.     int OldBkMode = GetBkMode(s_hdc);
  131.     SetBkMode(s_hdc,OPAQUE);
  132.     gui_outstr_nowrap(s,len,GUI_MON_TRS_CURSOR , (GuiColor)0, (GuiColor)0 ,0);
  133.     SetBkMode(s_hdc,OldBkMode);
  134. }
  135. /*
  136.  * When enter to insert mode, set IME to previous language mode
  137.  */
  138.     void
  139. ImeSetOriginMode(void)
  140. {
  141.     HIMC    hImc;
  142.     DWORD   dwConvMode, dwSentMode;
  143.     if ((hImc = ImmGetContext(s_hwnd)))
  144.     {
  145. ImmGetConversionStatus(hImc, &dwConvMode, &dwSentMode);
  146. if (!(dwConvMode & IME_CMODE_NATIVE) && bKoreanMode == TRUE)
  147. {
  148.     ImmSimulateHotKey(s_hwnd, IME_KHOTKEY_ENGLISH);
  149. }
  150. else
  151.     bKoreanMode = FALSE;
  152.     }
  153.     bCommandMode = FALSE;
  154. }
  155. /* When enter to command mode, set IME to english mode */
  156.     void
  157. ImeSetEnglishMode(void)
  158. {
  159.     HIMC    hImc;
  160.     DWORD   dwConvMode, dwSentMode;
  161.     if ((hImc = ImmGetContext(s_hwnd)))
  162.     {
  163. ImmGetConversionStatus(hImc, &dwConvMode, &dwSentMode);
  164. if (dwConvMode & IME_CMODE_NATIVE)
  165. {
  166.     ImmSimulateHotKey(s_hwnd, IME_KHOTKEY_ENGLISH);
  167.     bKoreanMode = TRUE;
  168. }
  169. else
  170.     bKoreanMode = FALSE;
  171.     }
  172.     bCommandMode = TRUE;
  173. }
  174. /* get composition string from WIN_IME */
  175.     static void
  176. GetCompositionStr(HWND hwnd, LPARAM CompFlag)
  177. {
  178.     DWORD dwBufLen; // Stogare for len. of composition str
  179.     HIMC hIMC; // Input context handle.
  180.     // If fail to get input context handle then do nothing.
  181.     // Applications should call ImmGetContext API to get
  182.     // input context handle.
  183.     if (!(hIMC = ImmGetContext(hwnd)))
  184. return;
  185.     // Determines how much memory space to store the composition string.
  186.     // Applications should call ImmGetCompositionString with
  187.     // GCS_COMPSTR flag on, buffer length zero, to get the bullfer
  188.     // length.
  189.     if ((dwBufLen = ImmGetCompositionString( hIMC, GCS_COMPSTR,
  190.     (void FAR*)NULL, 0l)) < 0)
  191. goto exit2;
  192.     if (dwBufLen > 99)
  193. goto exit2;
  194.     // Reads in the composition string.
  195.     if ( dwBufLen != 0 )
  196.     {
  197. ImmGetCompositionString(hIMC, GCS_COMPSTR, lpCompStr, dwBufLen);
  198. lpCompStr[dwBufLen] = 0;
  199.     }
  200.     else
  201.     {
  202. strcpy(lpCompStr,"  ");
  203. dwBufLen = 2;
  204.     }
  205.     // Display new composition chars.
  206.     DisplayCompStringOpaque(lpCompStr, dwBufLen);
  207. exit2:
  208.     ImmReleaseContext(hwnd, hIMC);
  209. }
  210. // void GetResultStr()
  211. //
  212. // This handles WM_IME_COMPOSITION with GCS_RESULTSTR flag on.
  213. //
  214. // get complete composition string
  215.     static void
  216. GetResultStr(HWND hwnd)
  217. {
  218.     DWORD dwBufLen; // Storage for length of result str.
  219.     HIMC hIMC; // Input context handle.
  220.     // If fail to get input context handle then do nothing.
  221.     if (!(hIMC = ImmGetContext(hwnd)))
  222. return;
  223.     // Determines how much memory space to store the result string.
  224.     // Applications should call ImmGetCompositionString with
  225.     // GCS_RESULTSTR flag on, buffer length zero, to get the bullfer
  226.     // length.
  227.     if ((dwBufLen = ImmGetCompositionString( hIMC, GCS_RESULTSTR,
  228.     (void FAR *)NULL, (DWORD) 0)) <= 0)
  229. goto exit2;
  230.     if (dwBufLen > 99)
  231. goto exit2;
  232.     // Reads in the result string.
  233.     ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpCompStr, dwBufLen);
  234.     // Displays the result string.
  235.     DisplayCompStringOpaque(lpCompStr, dwBufLen);
  236. exit2:
  237.     ImmReleaseContext(hwnd, hIMC);
  238. }
  239. /* this handles WM_IME_STARTCOMPOSITION */
  240.     static void
  241. ImeUIStartComposition(HWND hwnd)
  242. {
  243.      bInComposition = TRUE;
  244.      //GetResultStr( hwnd );
  245. }
  246. /* WM_IME_COMPOSITION */
  247.     static void
  248. ImeUIComposition(HWND hwnd, WPARAM wParam,LPARAM CompFlag)
  249. {
  250.     if (CompFlag & GCS_RESULTSTR)
  251. GetResultStr( hwnd );
  252.     else if (CompFlag & GCS_COMPSTR)
  253. GetCompositionStr( hwnd, CompFlag );
  254. }
  255. /* WM_IME_COMPOSITION */
  256.     static void
  257. ImeUIEndComposition(HWND hwnd)
  258. {
  259.     bInComposition = FALSE;
  260.     //GetResultStr( hwnd );
  261. }
  262.     static char *
  263. ImeGetTempComposition(void)
  264. {
  265.     if ( bInComposition == TRUE /* && bCommandMode == FALSE */)
  266.     {
  267. HIMC    hImc;
  268. DWORD   dwConvMode, dwSentMode;
  269. if ((hImc = ImmGetContext(s_hwnd)))
  270. {
  271.     ImmGetConversionStatus(hImc, &dwConvMode, &dwSentMode);
  272.     if ((dwConvMode & IME_CMODE_NATIVE))
  273. return lpCompStr;
  274. }
  275.     }
  276.     return NULL;
  277. }
  278.     static void
  279. ImeNotify(WPARAM w, LPARAM l)
  280. {
  281.     HIMC    hImc;
  282.     DWORD   dwConvMode, dwSentMode;
  283.     if ((hImc = ImmGetContext(s_hwnd)))
  284.     {
  285. ImmGetConversionStatus(hImc, &dwConvMode, &dwSentMode);
  286. if (dwConvMode & IME_CMODE_NATIVE)
  287.     bImeKorean = TRUE;
  288. else
  289.     bImeKorean = FALSE;
  290.     }
  291. }
  292. #  if 0 // This is not used !?
  293.     void
  294. ImeOpenClose(HWND hWnd, BOOL fFlag)
  295. {
  296.     HIMC hIMC;
  297.     //
  298.     // If fFlag is true then open IME; otherwise close it.
  299.     //
  300.     if (!(hIMC = ImmGetContext(hWnd)))
  301. return;
  302.     ImmSetOpenStatus(hIMC, fFlag);
  303.     ImmReleaseContext(hWnd, hIMC);
  304. }
  305. /*
  306. *   IsDBCSTrailByte - returns TRUE if the given byte is a DBCS trail byte
  307. *
  308. * The algorithm searchs backward in the string, to some known
  309. * character boundary, counting consecutive bytes in the lead
  310. * byte range. An odd number indicates the current byte is part
  311. * of a two byte character code.
  312. *
  313. *   INPUT: PCHAR  - pointer to a preceding known character boundary.
  314. *    PCHAR  - pointer to the character to test.
  315. *
  316. *   OUTPUT:BOOL   - indicating truth of p==trailbyte.
  317. *
  318. */
  319.     int
  320. IsDBCSTrailByte(char *base, char *p)
  321. {
  322.     int lbc = 0;    // lead byte count
  323.     if (base > p)
  324. return 0;
  325.     if (strlen(base) <= (size_t)(p-base))
  326. return 0;
  327.     while (p > base)
  328.     {
  329. if (!IsLeadByte(*(--p)))
  330.     break;
  331. lbc++;
  332.     }
  333.     return (lbc & 1);
  334. }
  335. #  endif /* not used */
  336. # endif /* MULTI_BYTE_IME */
  337. #endif /* MULTI_BYTE */
  338. #define UNIBUFSIZE 2000 /* a big buffer */
  339.     void
  340. gui_mch_draw_string(
  341.     int row,
  342.     int col,
  343.     char_u *s,
  344.     int len,
  345.     int flags)
  346. {
  347.     static int *padding = NULL;
  348.     static int pad_size = 0;
  349. #ifdef MULTI_BYTE
  350.     static WCHAR *unicodebuf = NULL;
  351. #endif
  352.     HPEN hpen, old_pen;
  353.     int y;
  354.     int i;
  355. #if 1
  356.     /*
  357.      * Italic and bold text seems to have an extra row of pixels at the bottom
  358.      * (below where the bottom of the character should be).  If we draw the
  359.      * characters with a solid background, the top row of pixels in the
  360.      * character below will be overwritten.  We can fix this by filling in the
  361.      * background ourselves, to the correct character proportions, and then
  362.      * writing the character in transparent mode.  Still have a problem when
  363.      * the character is "_", which gets written on to the character below.
  364.      * New fix: set gui.char_ascent to -1.  This shifts all characters up one
  365.      * pixel in their slots, which fixes the problem with the bottom row of
  366.      * pixels. We still need this code because otherwise the top row of pixels
  367.      * becomes a problem. - webb.
  368.      */
  369.     HBRUSH hbr;
  370.     RECT rc;
  371. #ifdef MULTI_BYTE_IME
  372.     char *szComp;
  373. #endif
  374. #ifdef MULTI_BYTE
  375.     int OrgLen;
  376.     if (is_dbcs)
  377.     {
  378. OrgLen = len;
  379. if (IsLeadByte(s[len-1]))
  380. {
  381.     if (s[len] > 30)
  382. len++;
  383. }
  384.     }
  385. #endif
  386.     if (!(flags & DRAW_TRANSP))
  387.     {
  388. /*
  389.  * Clear background first.
  390.  * Note: FillRect() excludes right and bottom of rectangle.
  391.  */
  392. rc.left = FILL_X(col);
  393. rc.top = FILL_Y(row);
  394. rc.right = FILL_X(col + len);     /* Add +1 to erase fake bold? */
  395. rc.bottom = FILL_Y(row + 1);
  396. hbr = CreateSolidBrush(gui.currBgColor);
  397. FillRect(s_hdc, &rc, hbr);
  398. DeleteBrush(hbr);
  399. SetBkMode(s_hdc, TRANSPARENT);
  400.     }
  401. #else
  402.     /*
  403.      * The alternative would be to write the characters in opaque mode, but
  404.      * when the text is not exactly the same proportions as normal text, too
  405.      * big or too little a rectangle gets drawn for the background.
  406.      */
  407.     SetBkMode(s_hdc, OPAQUE);
  408.     SetBkColor(s_hdc, gui.currBgColor);
  409. #endif
  410.     SetTextColor(s_hdc, gui.currFgColor);
  411.     SelectFont(s_hdc, gui.currFont);
  412.     if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width)
  413.     {
  414. vim_free(padding);
  415. pad_size = Columns;
  416. padding = (int *)alloc(pad_size * sizeof(int));
  417. if (padding != NULL)
  418.     for (i = 0; i < pad_size; i++)
  419. padding[i] = gui.char_width;
  420.     }
  421.     /*
  422.      * We have to provide the padding argument because italic and bold versions
  423.      * of fixed-width fonts are often one pixel or so wider than their normal
  424.      * versions.
  425.      * No check for DRAW_BOLD, Windows will have done it already.
  426.      */
  427. #ifdef MULTI_BYTE_IME
  428.     if (is_dbcs)
  429.     {
  430.     /* draw an incomplete composition character(korean) */
  431. if (OrgLen == 1 && blink_state == BLINK_ON
  432. && (szComp = ImeGetTempComposition()) != NULL) // hangul
  433.     HanExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL, szComp,
  434.     2, padding, TRUE);
  435. else
  436.     HanExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL, (char *)s,
  437.     len, padding, FALSE);
  438.     }
  439.     else
  440. #endif
  441.     {
  442. #ifdef MULTI_BYTE
  443. /* if we want to display DBCS, and the current CP is not the DBCS one,
  444.  * we need to go via Unicode */
  445. if (is_funky_dbcs)
  446. {
  447.     /* check if our output buffer exists, if not create it */
  448.     if (unicodebuf == NULL)
  449. unicodebuf = (WCHAR *)alloc(UNIBUFSIZE);
  450.     if (unicodebuf != NULL)
  451.     {
  452. if (len = MultiByteToWideChar(is_dbcs,
  453.     MB_PRECOMPOSED,
  454.     (char *)s, len,
  455.     (LPWSTR)unicodebuf, UNIBUFSIZE))
  456.     ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL,
  457.        unicodebuf, len, NULL);
  458.     }
  459. }
  460. else
  461. #endif
  462.     ExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL,
  463.      (char *)s, len, padding);
  464.     }
  465.     if (flags & DRAW_UNDERL)
  466.     {
  467. hpen = CreatePen(PS_SOLID, 1, gui.currFgColor);
  468. old_pen = SelectObject(s_hdc, hpen);
  469. y = FILL_Y(row + 1) - 1;
  470. MoveToEx(s_hdc, FILL_X(col), y, NULL);
  471. /* Note: LineTo() excludes the last pixel in the line. */
  472. LineTo(s_hdc, FILL_X(col + len), y);
  473. DeleteObject(SelectObject(s_hdc, old_pen));
  474.     }
  475. }
  476. /*
  477.  * Return OK if the key with the termcap name "name" is supported.
  478.  */
  479.     int
  480. gui_mch_haskey(char_u *name)
  481. {
  482.     int i;
  483.     for (i = 0; special_keys[i].vim_code1 != NUL; i++)
  484. if (name[0] == special_keys[i].vim_code0 &&
  485.  name[1] == special_keys[i].vim_code1)
  486.     return OK;
  487.     return FAIL;
  488. }
  489.     void
  490. gui_mch_beep(void)
  491. {
  492.     MessageBeep(MB_OK);
  493. }
  494.     void
  495. gui_mch_flash(void)
  496. {
  497.     RECT    rc;
  498.     /*
  499.      * Note: InvertRect() excludes right and bottom of rectangle.
  500.      */
  501.     rc.left = 0;
  502.     rc.top = 0;
  503.     rc.right = gui.num_cols * gui.char_width;
  504.     rc.bottom = gui.num_rows * gui.char_height;
  505.     InvertRect(s_hdc, &rc);
  506.     ui_delay(20L, TRUE); /* wait 1/50 of a second */
  507.     InvertRect(s_hdc, &rc);
  508. }
  509. /*
  510.  * Invert a rectangle from row r, column c, for nr rows and nc columns.
  511.  */
  512.     void
  513. gui_mch_invert_rectangle(
  514.     int     r,
  515.     int     c,
  516.     int     nr,
  517.     int     nc)
  518. {
  519.     RECT    rc;
  520.     /*
  521.      * Note: InvertRect() excludes right and bottom of rectangle.
  522.      */
  523.     rc.left = FILL_X(c);
  524.     rc.top = FILL_Y(r);
  525.     rc.right = rc.left + nc * gui.char_width;
  526.     rc.bottom = rc.top + nr * gui.char_height;
  527.     InvertRect(s_hdc, &rc);
  528. }
  529. /*
  530.  * Iconify the GUI window.
  531.  */
  532.     void
  533. gui_mch_iconify(void)
  534. {
  535.     ShowWindow(s_hwnd, SW_MINIMIZE);
  536. }
  537. #if defined(HAVE_OLE) || defined(PROTO)
  538. /*
  539.  * Make the GUI window come to the foreground.
  540.  */
  541.     void
  542. gui_mch_set_foreground(void)
  543. {
  544.     SetForegroundWindow(s_hwnd);
  545. }
  546. #endif
  547. /*
  548.  * Set the window title
  549.  */
  550.     void
  551. gui_mch_settitle(
  552.     char_u  *title,
  553.     char_u  *icon)
  554. {
  555.     if (title != NULL)
  556. SetWindowText(s_hwnd, (LPCSTR)title);
  557. }
  558. /*
  559.  * Draw a cursor without focus.
  560.  */
  561.     void
  562. gui_mch_draw_hollow_cursor(GuiColor color)
  563. {
  564.     HBRUSH  hbr;
  565.     RECT    rc;
  566.     /*
  567.      * Note: FrameRect() excludes right and bottom of rectangle.
  568.      */
  569.     rc.left = FILL_X(gui.col);
  570.     rc.top = FILL_Y(gui.row);
  571.     rc.right = rc.left + gui.char_width;
  572.     rc.bottom = rc.top + gui.char_height;
  573.     hbr = CreateSolidBrush(color);
  574.     FrameRect(s_hdc, &rc, hbr);
  575.     DeleteBrush(hbr);
  576. }
  577. /*
  578.  * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
  579.  * color "color".
  580.  */
  581.     void
  582. gui_mch_draw_part_cursor(
  583.     int w,
  584.     int h,
  585.     GuiColor color)
  586. {
  587.     HBRUSH hbr;
  588.     RECT rc;
  589.     /*
  590.      * Note: FillRect() excludes right and bottom of rectangle.
  591.      */
  592.     rc.left =
  593. #ifdef RIGHTLEFT
  594. /* vertical line should be on the right of current point */
  595. State != CMDLINE && curwin->w_p_rl ?  FILL_X(gui.col + 1) - w :
  596. #endif
  597.     FILL_X(gui.col);
  598.     rc.top = FILL_Y(gui.row) + gui.char_height - h;
  599.     rc.right = rc.left + w;
  600.     rc.bottom = rc.top + h;
  601.     hbr = CreateSolidBrush(color);
  602.     FillRect(s_hdc, &rc, hbr);
  603.     DeleteBrush(hbr);
  604. }
  605. /*
  606.  * Process a single Windows message.
  607.  * If one is not available we hang until one is.
  608.  */
  609.     static void
  610. process_message(void)
  611. {
  612.     MSG     msg;
  613.     UINT    vk; /* Virtual key */
  614.     char_u  string[3];
  615.     int     i;
  616.     int     modifiers = 0;
  617.     int     key;
  618.     GetMessage(&msg, NULL, 0, 0);
  619. #ifdef HAVE_OLE
  620.     /* Look after OLE Automation commands */
  621.     if (msg.message == WM_OLE)
  622.     {
  623. char_u *str = (char_u *)msg.lParam;
  624. add_to_input_buf(str, strlen(str));
  625. vim_free(str);
  626. return;
  627.     }
  628. #endif
  629. #ifdef WIN32_FIND_REPLACE
  630.     /* Don't process messages used by the dialog */
  631.     if ((s_findrep_hwnd) && (IsDialogMessage(s_findrep_hwnd, &msg)))
  632. return;
  633. #endif
  634.     /*
  635.      * Check if it's a special key that we recognise.  If not, call
  636.      * TranslateMessage().
  637.      */
  638.     if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
  639.     {
  640. vk = (int) msg.wParam;
  641. /* handle key after dead key, but ignore shift, alt and control */
  642. if (dead_key && vk != VK_SHIFT && vk != VK_MENU && vk != VK_CONTROL)
  643. {
  644.     dead_key = 0;
  645.     /* handle non-alphabetic keys (ones that hopefully cannot generate
  646.      * umlaut-characters), unless when control is down */
  647.     if (vk < 'A' || vk > 'Z' || (GetKeyState(VK_CONTROL) & 0x8000))
  648.     {
  649. MSG dm;
  650. dm.message = msg.message;
  651. dm.hwnd = msg.hwnd;
  652. dm.wParam = VK_SPACE;
  653. TranslateMessage(&dm);     /* generate dead character */
  654. if (vk != VK_SPACE) /* and send current character once more */
  655.     PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam);
  656. return;
  657.     }
  658. }
  659. /* Check for CTRL-BREAK */
  660. if (vk == VK_CANCEL)
  661. {
  662.     trash_input_buf();
  663.     got_int = TRUE;
  664.     string[0] = Ctrl('C');
  665.     add_to_input_buf(string, 1);
  666. }
  667. for (i = 0; special_keys[i].key_sym != 0; i++)
  668. {
  669.     /* ignore VK_SPACE when ALT key pressed: system menu */
  670.     if (special_keys[i].key_sym == vk
  671.     && (vk != VK_SPACE || !(GetKeyState(VK_MENU) & 0x8000)))
  672.     {
  673. if (GetKeyState(VK_SHIFT) & 0x8000)
  674.     modifiers |= MOD_MASK_SHIFT;
  675. /*
  676.  * Don't use caps-lock as shift, because these are special keys
  677.  * being considered here, and we only want letters to get
  678.  * shifted -- webb
  679.  */
  680. /*
  681. if (GetKeyState(VK_CAPITAL) & 0x0001)
  682.     modifiers ^= MOD_MASK_SHIFT;
  683. */
  684. if (GetKeyState(VK_CONTROL) & 0x8000)
  685.     modifiers |= MOD_MASK_CTRL;
  686. if (GetKeyState(VK_MENU) & 0x8000)
  687.     modifiers |= MOD_MASK_ALT;
  688. if (special_keys[i].vim_code1 == NUL)
  689.     key = special_keys[i].vim_code0;
  690. else
  691.     key = TO_SPECIAL(special_keys[i].vim_code0,
  692.    special_keys[i].vim_code1);
  693. key = simplify_key(key, &modifiers);
  694. if (modifiers)
  695. {
  696.     string[0] = CSI;
  697.     string[1] = KS_MODIFIER;
  698.     string[2] = modifiers;
  699.     add_to_input_buf(string, 3);
  700. }
  701. if (IS_SPECIAL(key))
  702. {
  703.     string[0] = CSI;
  704.     string[1] = K_SECOND(key);
  705.     string[2] = K_THIRD(key);
  706.     add_to_input_buf(string, 3);
  707. }
  708. else
  709. {
  710.     string[0] = key;
  711.     add_to_input_buf(string, 1);
  712. }
  713. break;
  714.     }
  715. }
  716. if (special_keys[i].key_sym == 0)
  717. {
  718.     /* Some keys need C-S- where they should only need C- */
  719.     if ((GetKeyState(VK_CONTROL) & 0x8000)
  720.     && !(GetKeyState(VK_SHIFT) & 0x8000)
  721.     && !(GetKeyState(VK_MENU) & 0x8000))
  722.     {
  723. if (vk == '6')
  724. {
  725.     string[0] = Ctrl('^');
  726.     add_to_input_buf(string, 1);
  727. }
  728. /* vk == 0xDB AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! */
  729. else if (vk == 0xBD) /* QWERTY for CTRL-'-' */
  730. {
  731.     string[0] = Ctrl('_');
  732.     add_to_input_buf(string, 1);
  733. }
  734. else
  735.     TranslateMessage(&msg);
  736.     }
  737.     else
  738. TranslateMessage(&msg);
  739. }
  740.     }
  741. #ifdef MULTI_BYTE_IME
  742.     else if (msg.message == WM_IME_STARTCOMPOSITION)
  743. ImeUIStartComposition(s_hwnd);
  744.     else if (msg.message == WM_IME_COMPOSITION)
  745. ImeUIComposition(s_hwnd, msg.wParam, msg.lParam);
  746.     else if (msg.message == WM_IME_ENDCOMPOSITION)
  747. ImeUIEndComposition(s_hwnd);
  748.     else if (msg.message == WM_IME_COMPOSITIONFULL)
  749. ImeUIEndComposition(s_hwnd);
  750.     else if (msg.message == WM_IME_NOTIFY)
  751. ImeNotify(msg.wParam, msg.lParam);
  752. #endif
  753.     DispatchMessage(&msg);
  754. }
  755. /*
  756.  * Catch up with any queued events.  This may put keyboard input into the
  757.  * input buffer, call resize call-backs, trigger timers etc.  If there is
  758.  * nothing in the event queue (& no timers pending), then we return
  759.  * immediately.
  760.  */
  761.     void
  762. gui_mch_update(void)
  763. {
  764.     MSG     msg;
  765.     while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)
  766.   && !vim_is_input_buf_full())
  767. process_message();
  768. }
  769. /*
  770.  * GUI input routine called by gui_wait_for_chars().  Waits for a character
  771.  * from the keyboard.
  772.  *  wtime == -1     Wait forever.
  773.  *  wtime == 0     This should never happen.
  774.  *  wtime > 0     Wait wtime milliseconds for a character.
  775.  * Returns OK if a character was found to be available within the given time,
  776.  * or FAIL otherwise.
  777.  */
  778.     int
  779. gui_mch_wait_for_chars(int wtime)
  780. {
  781.     MSG msg;
  782.     int focus;
  783.     s_timed_out = FALSE;
  784.     if (wtime > 0)
  785. s_wait_timer = SetTimer(NULL, 0, (UINT)wtime, (TIMERPROC)_OnTimer);
  786.     focus = gui.in_focus;
  787.     while (!s_timed_out)
  788.     {
  789. /* Stop or start blinking when focus changes */
  790. if (gui.in_focus != focus)
  791. {
  792.     if (gui.in_focus)
  793. gui_mch_start_blink();
  794.     else
  795. gui_mch_stop_blink();
  796.     focus = gui.in_focus;
  797. }
  798. /*
  799.  * Don't use gui_mch_update() because then we will spin-lock until a
  800.  * char arrives, instead we use GetMessage() to hang until an
  801.  * event arrives.  No need to check for input_buf_full because we are
  802.  * returning as soon as it contains a single char -- webb
  803.  */
  804. process_message();
  805. if (!vim_is_input_buf_empty())
  806. {
  807.     if (s_wait_timer != 0 && !s_timed_out)
  808.     {
  809. KillTimer(NULL, s_wait_timer);
  810. /* Eat spurious WM_TIMER messages */
  811. while (PeekMessage(&msg, s_hwnd,
  812.       WM_TIMER, WM_TIMER, PM_REMOVE));
  813. s_wait_timer = 0;
  814.     }
  815.     return OK;
  816. }
  817.     }
  818.     return FAIL;
  819. }
  820. /*
  821.  * Output routines.
  822.  */
  823. /* Flush any output to the screen */
  824.     void
  825. gui_mch_flush(void)
  826. {
  827.     /* Is anything needed here? */
  828. }
  829.     static void
  830. clear_rect(RECT *rcp)
  831. {
  832.     HBRUSH  hbr;
  833.     hbr = CreateSolidBrush(gui.back_pixel);
  834.     FillRect(s_hdc, rcp, hbr);
  835.     DeleteBrush(hbr);
  836. }
  837. /*
  838.  * Clear a rectangular region of the screen from text pos (row1, col1) to
  839.  * (row2, col2) inclusive.
  840.  */
  841.     void
  842. gui_mch_clear_block(
  843.     int     row1,
  844.     int     col1,
  845.     int     row2,
  846.     int     col2)
  847. {
  848.     RECT    rc;
  849.     /*
  850.      * Clear one extra pixel at the right, for when bold characters have
  851.      * spilled over to the next column.  Note: FillRect() excludes right and
  852.      * bottom of rectangle.
  853.      * Can this ever erase part of the next character? - webb
  854.      */
  855.     rc.left = FILL_X(col1);
  856.     rc.top = FILL_Y(row1);
  857.     rc.right = FILL_X(col2 + 1) + 1;
  858.     rc.bottom = FILL_Y(row2 + 1);
  859.     clear_rect(&rc);
  860. }
  861. /*
  862.  * Clear the whole text window.
  863.  */
  864.     void
  865. gui_mch_clear_all(void)
  866. {
  867.     RECT    rc;
  868.     rc.left = 0;
  869.     rc.top = 0;
  870.     rc.right = Columns * gui.char_width + 2 * gui.border_width;
  871.     rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
  872.     clear_rect(&rc);
  873. }
  874. /*
  875.  * Delete the given number of lines from the given row, scrolling up any
  876.  * text further down within the scroll region.
  877.  */
  878.     void
  879. gui_mch_delete_lines(
  880.     int     row,
  881.     int     num_lines)
  882. {
  883.     if (num_lines <= 0)
  884. return;
  885.     if (row + num_lines > gui.scroll_region_bot)
  886.     {
  887. /* Scrolled out of region, just blank the lines out */
  888. gui_clear_block(row, 0, gui.scroll_region_bot, Columns - 1);
  889.     }
  890.     else
  891.     {
  892. RECT rc;
  893. rc.left = FILL_X(0);
  894. rc.right = FILL_X(Columns);
  895. rc.top = FILL_Y(row);
  896. rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
  897. /* The SW_INVALIDATE is required when part of the window is covered or
  898.  * off-screen.  How do we avoid it when it's not needed? */
  899. ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height,
  900. &rc, &rc, NULL, NULL, SW_INVALIDATE);
  901. /* Update gui.cursor_row if the cursor scrolled or copied over */
  902. if (gui.cursor_row >= row)
  903. {
  904.     if (gui.cursor_row < row + num_lines)
  905. gui.cursor_is_valid = FALSE;
  906.     else if (gui.cursor_row <= gui.scroll_region_bot)
  907. gui.cursor_row -= num_lines;
  908. }
  909. gui_undraw_cursor();
  910. UpdateWindow(s_textArea);
  911. gui_clear_block(gui.scroll_region_bot - num_lines + 1, 0,
  912.     gui.scroll_region_bot, Columns - 1);
  913.     }
  914. }
  915. /*
  916.  * Insert the given number of lines before the given row, scrolling down any
  917.  * following text within the scroll region.
  918.  */
  919.     void
  920. gui_mch_insert_lines(
  921.     int     row,
  922.     int     num_lines)
  923. {
  924.     if (num_lines <= 0)
  925. return;
  926.     if (row + num_lines > gui.scroll_region_bot)
  927.     {
  928. /* Scrolled out of region, just blank the lines out */
  929. gui_clear_block(row, 0, gui.scroll_region_bot, Columns - 1);
  930.     }
  931.     else
  932.     {
  933. RECT rc;
  934. rc.left = FILL_X(0);
  935. rc.right = FILL_X(Columns);
  936. rc.top = FILL_Y(row);
  937. rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
  938. /* The SW_INVALIDATE is required when part of the window is covered or
  939.  * off-screen.  How do we avoid it when it's not needed? */
  940. ScrollWindowEx(s_textArea, 0, num_lines * gui.char_height,
  941. &rc, &rc, NULL, NULL, SW_INVALIDATE);
  942. /* Update gui.cursor_row if the cursor scrolled or copied over */
  943. if (gui.cursor_row >= gui.row)
  944. {
  945.     if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
  946. gui.cursor_row += num_lines;
  947.     else if (gui.cursor_row <= gui.scroll_region_bot)
  948. gui.cursor_is_valid = FALSE;
  949. }
  950. gui_undraw_cursor();
  951. UpdateWindow(s_textArea);
  952. gui_clear_block(row, 0, row + num_lines - 1, Columns - 1);
  953.     }
  954. }
  955. /*
  956.  * Menu stuff.
  957.  */
  958.     void
  959. gui_mch_enable_menu(int flag)
  960. {
  961.     SetMenu(s_hwnd, flag ? s_menuBar : NULL);
  962. }
  963.     void
  964. gui_mch_set_menu_pos(
  965.     int     x,
  966.     int     y,
  967.     int     w,
  968.     int     h)
  969. {
  970.     /* It will be in the right place anyway */
  971. }
  972. /*
  973.  * Add a sub menu to the menu bar.
  974.  */
  975.     void
  976. gui_mch_add_menu(
  977.     GuiMenu *menu,
  978.     GuiMenu *parent,
  979.     int pos)
  980. {
  981.     menu->submenu_id = CreatePopupMenu();
  982.     menu->id = s_menu_id++;
  983.     menu->parent = parent;
  984.     if (gui_menubar_menu(menu->name))
  985.     {
  986. if (is_winnt_3())
  987. {
  988.     InsertMenu((parent == NULL) ? s_menuBar : parent->submenu_id,
  989.     (UINT)pos, MF_POPUP | MF_STRING | MF_BYPOSITION,
  990.     (UINT)menu->submenu_id, (LPCTSTR) menu->name);
  991. }
  992. else
  993. {
  994.     MENUITEMINFO info;
  995.     info.cbSize = sizeof(info);
  996.     info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID | MIIM_SUBMENU;
  997.     info.dwItemData = (DWORD)menu;
  998.     info.wID = menu->id;
  999.     info.fType = MFT_STRING;
  1000.     info.dwTypeData = (LPTSTR)menu->name;
  1001.     info.cch = STRLEN(menu->name);
  1002.     info.hSubMenu = menu->submenu_id;
  1003.     InsertMenuItem((parent == NULL) ? s_menuBar : parent->submenu_id,
  1004.     (UINT)pos, TRUE, &info);
  1005. }
  1006.     }
  1007.     /* Fix window size if menu may have wrapped */
  1008.     if (parent == NULL)
  1009. gui_w32_get_menu_height(!gui.starting);
  1010. }
  1011.     void
  1012. gui_mch_show_popupmenu(GuiMenu *menu)
  1013. {
  1014.     POINT mp;
  1015.     if (GetCursorPos((LPPOINT)&mp))
  1016.     {
  1017. (void)TrackPopupMenu(
  1018.  (HMENU)menu->submenu_id,
  1019.  TPM_LEFTALIGN | TPM_LEFTBUTTON,
  1020.  (int)mp.x,
  1021.  (int)mp.y,
  1022.  (int)0,     /*reserved param*/
  1023.  s_hwnd,
  1024.  NULL);
  1025. /*
  1026.  * NOTE: The pop-up menu can eat the mouse up event.
  1027.  * We deal with this in normal.c.
  1028.  */
  1029.     }
  1030. }
  1031. /*
  1032.  * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
  1033.  * create it as a pseudo-"tearoff menu".
  1034.  */
  1035.     void
  1036. gui_make_tearoff(char_u *path_name)
  1037. {
  1038.     GuiMenu **menup;
  1039.     GuiMenu *menu = NULL;
  1040.     GuiMenu *parent = NULL;
  1041.     char_u *name;
  1042.     char_u *saved_name;
  1043.     char_u *p;
  1044.     menup = &gui.root_menu;
  1045.     saved_name = vim_strsave(path_name);
  1046.     if (saved_name == NULL)
  1047. return;
  1048.     name = saved_name;
  1049.     while (*name)
  1050.     {
  1051. /* Find in the menu hierarchy */
  1052. p = gui_menu_name_skip(name);
  1053. menu = *menup;
  1054. while (menu != NULL)
  1055. {
  1056.     if (STRCMP(name, menu->name) == 0 || STRCMP(name, menu->dname) == 0)
  1057.     {
  1058. if (*p == NUL && menu->children == NULL)
  1059. {
  1060.     /* not allowed to tear off one item*/
  1061.     EMSG("Menu path must lead to a sub-menu");
  1062.     vim_free(saved_name);
  1063.     return;
  1064. }
  1065. else if (*p != NUL && menu->children == NULL)
  1066. {
  1067.     EMSG("Part of menu-item path is not sub-menu");
  1068.     vim_free(saved_name);
  1069.     return;
  1070. }
  1071. break;
  1072.     }
  1073.     menup = &menu->next;
  1074.     menu = menu->next;
  1075. }
  1076. menup = &menu->children;
  1077. parent = menu;
  1078. name = p;
  1079.     }
  1080.     vim_free(saved_name);
  1081.     if (menu == NULL)
  1082.     {
  1083. EMSG("Menu not found - check menu names");
  1084. return;
  1085.     }
  1086.     /* Found the menu, so tear it off. */
  1087.     gui_mch_tearoff(menu->dname, menu, 0xffffL, 0xffffL);
  1088. }
  1089. /*
  1090.  * Add a menu item to a menu
  1091.  */
  1092.     void
  1093. gui_mch_add_menu_item(
  1094.     GuiMenu *menu,
  1095.     GuiMenu *parent,
  1096.     int idx)
  1097. {
  1098.     menu->id = s_menu_id++;
  1099.     menu->submenu_id = NULL;
  1100.     menu->parent = parent;
  1101.     if (STRNCMP(menu->name, TEAR_STRING, TEAR_LEN) == 0)
  1102.     {
  1103. InsertMenu(parent->submenu_id, (UINT)idx, MF_BITMAP|MF_BYPOSITION,
  1104. (UINT)menu->id, (LPCTSTR) s_htearbitmap);
  1105.     }
  1106. #ifdef USE_GUI_WIN32_TOOLBAR
  1107.     else if (STRCMP(parent->name, "ToolBar") == 0)
  1108.     {
  1109. TBBUTTON newtb;
  1110. vim_memset(&newtb, 0, sizeof(newtb));
  1111. newtb.iBitmap = get_toolbar_bitmap(menu->name);
  1112. newtb.idCommand = menu->id;
  1113. newtb.fsStyle = TBSTYLE_BUTTON;
  1114. newtb.fsState = TBSTATE_ENABLED;
  1115. newtb.iString = 0;
  1116. SendMessage(s_toolbarhwnd, TB_ADDBUTTONS, (WPARAM)1, (LPARAM) &newtb);
  1117. menu->submenu_id = (HMENU)-1;
  1118.     }
  1119. #endif
  1120.     else
  1121.     {
  1122. InsertMenu(parent->submenu_id, (UINT)idx, MF_STRING|MF_BYPOSITION,
  1123. (UINT)menu->id, (LPCTSTR) menu->name);
  1124. if (IsWindow(parent->tearoff_handle))
  1125.     rebuild_tearoff(parent);
  1126.     }
  1127. }
  1128. /*
  1129.  * Destroy the machine specific menu widget.
  1130.  */
  1131.     void
  1132. gui_mch_destroy_menu(GuiMenu *menu)
  1133. {
  1134. #ifdef USE_GUI_WIN32_TOOLBAR
  1135.     /*
  1136.      * is this a toolbar button?
  1137.      */
  1138.     if (menu->submenu_id == (HMENU)-1)
  1139.     {
  1140. int iButton;
  1141. iButton = SendMessage(s_toolbarhwnd, TB_COMMANDTOINDEX, (WPARAM)menu->id, 0);
  1142. SendMessage(s_toolbarhwnd, TB_DELETEBUTTON, (WPARAM)iButton, 0);
  1143.     }
  1144.     else
  1145. #endif
  1146.     {
  1147. RemoveMenu(s_menuBar, menu->id, MF_BYCOMMAND);
  1148. if (menu->submenu_id != NULL)
  1149.     DestroyMenu(menu->submenu_id);
  1150. if (IsWindow(menu->tearoff_handle))
  1151.     DestroyWindow(menu->tearoff_handle);
  1152. if ((menu->parent != NULL) && (IsWindow(menu->parent->tearoff_handle)))
  1153.     rebuild_tearoff(menu->parent);
  1154.     }
  1155. }
  1156.     static void
  1157. rebuild_tearoff(GuiMenu *menu)
  1158. {
  1159.     /*hackish*/
  1160.     char_u  tbuf[128];
  1161.     RECT    trect;
  1162.     RECT    rct;
  1163.     RECT    roct;
  1164.     int     x, y;
  1165.     HWND thwnd = menu->tearoff_handle;
  1166.     GetWindowText(thwnd, tbuf, 127);
  1167.     if (GetWindowRect(thwnd, &trect) &&
  1168. GetWindowRect(s_hwnd, &rct) &&
  1169. GetClientRect(s_hwnd, &roct))
  1170.     {
  1171. x = trect.left - rct.left;
  1172. y = (trect.top -  rct.bottom  + roct.bottom);
  1173.     }
  1174.     else
  1175.     {
  1176. x = y = 0xffffL;
  1177.     }
  1178.     DestroyWindow(thwnd);
  1179.     gui_mch_tearoff(tbuf, menu, x, y);
  1180.     if (IsWindow(menu->tearoff_handle))
  1181. (void) SetWindowPos(menu->tearoff_handle,
  1182.     NULL,
  1183.     (int) trect.left,
  1184.     (int) trect.top,
  1185.     0, 0,
  1186.     SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  1187. }
  1188. /*
  1189.  * Make a menu either grey or not grey.
  1190.  */
  1191.     void
  1192. gui_mch_menu_grey(
  1193.     GuiMenu *menu,
  1194.     int     grey)
  1195. {
  1196. #ifdef USE_GUI_WIN32_TOOLBAR
  1197.     /*
  1198.      * is this a toolbar button?
  1199.      */
  1200.     if (menu->submenu_id == (HMENU)-1)
  1201.     {
  1202. SendMessage(s_toolbarhwnd, TB_ENABLEBUTTON,
  1203.     (WPARAM)menu->id, (LPARAM) MAKELONG((grey ? FALSE : TRUE), 0) );
  1204.     }
  1205.     else
  1206. #endif
  1207.     if (grey)
  1208. EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_GRAYED);
  1209.     else
  1210. EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
  1211. #if 1
  1212.     if ((menu->parent != NULL) && (IsWindow(menu->parent->tearoff_handle)))
  1213.     {
  1214. WORD menuID;
  1215. HWND menuHandle;
  1216. /*
  1217.  * A tearoff button has changed state.
  1218.  */
  1219. if (menu->children == NULL)
  1220.     menuID = (WORD)(menu->id);
  1221. else
  1222.     menuID = (WORD)((WORD)(menu->submenu_id) | (WORD)0x8000);
  1223. menuHandle = GetDlgItem(menu->parent->tearoff_handle, menuID);
  1224. if (menuHandle)
  1225.     EnableWindow(menuHandle, !grey);
  1226.     }
  1227. #endif
  1228. }
  1229. /*
  1230.  * Make menu item hidden or not hidden
  1231.  */
  1232.     void
  1233. gui_mch_menu_hidden(
  1234.     GuiMenu *menu,
  1235.     int     hidden)
  1236. {
  1237.     /*
  1238.      * This doesn't do what we want.  Hmm, just grey the menu items for now.
  1239.      */
  1240.     /*
  1241.     if (hidden)
  1242. EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_DISABLED);
  1243.     else
  1244. EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
  1245.     */
  1246.     gui_mch_menu_grey(menu, hidden);
  1247. }
  1248. /*
  1249.  * This is called after setting all the menus to grey/hidden or not.
  1250.  */
  1251.     void
  1252. gui_mch_draw_menubar(void)
  1253. {
  1254.     DrawMenuBar(s_hwnd);
  1255. }
  1256. /* cproto doesn't create a prototype for main() */
  1257. int main __ARGS((int argc, char **argv));
  1258. #ifndef PROTO
  1259. void
  1260. #ifdef VIMDLL
  1261. _export
  1262. #endif
  1263. _cdecl
  1264. SaveInst(HINSTANCE hInst)
  1265. {
  1266.     s_hinst = hInst;
  1267. }
  1268. #endif
  1269. /*
  1270.  * Return the lightness of a pixel.  White is 255.
  1271.  */
  1272.     int
  1273. gui_mch_get_lightness(pixel)
  1274.     GuiColor pixel;
  1275. {
  1276.     return (GetRValue(pixel)*3 + GetGValue(pixel)*6 + GetBValue(pixel)) / 10;
  1277. }
  1278. /*
  1279.  * Return the RGB value of a pixel as "#RRGGBB".
  1280.  */
  1281.     char_u *
  1282. gui_mch_get_rgb(
  1283.     GuiColor pixel)
  1284. {
  1285.     static char_u retval[10];
  1286.     sprintf((char *)retval, "#%02x%02x%02x",
  1287.     GetRValue(pixel), GetGValue(pixel), GetBValue(pixel));
  1288.     return retval;
  1289. }
  1290. #ifdef USE_BROWSE
  1291. /*
  1292.  * Pop open a file browser and return the file selected, in allocated memory,
  1293.  * or NULL if Cancel is hit.
  1294.  *  saving  - TRUE if the file will be saved to, FALSE if it will be opened.
  1295.  *  title   - Title message for the file browser dialog.
  1296.  *  dflt    - Default name of file.
  1297.  *  ext     - Default extension to be added to files without extensions.
  1298.  *  initdir - directory in which to open the browser (NULL = current dir)
  1299.  *  filter  - Filter for matched files to choose from.
  1300.  * Has a format like this:
  1301.  * "C Files (*.c)*.c"
  1302.  * "All Files*.*"
  1303.  * If these two strings were concatenated, then a choice of two file
  1304.  * filters will be selectable to the user.  Then only matching files will
  1305.  * be shown in the browser.  If NULL, the default allows all files.
  1306.  *
  1307.  * *NOTE* - the filter string must be terminated with TWO nulls.
  1308.  */
  1309.     char_u *
  1310. gui_mch_browse(
  1311. int saving,
  1312. char_u *title,
  1313. char_u *dflt,
  1314. char_u *ext,
  1315. char_u *initdir,
  1316. char_u *filter)
  1317. {
  1318.     OPENFILENAME    fileStruct;
  1319.     char_u     fileBuf[MAX_PATH], *p;
  1320.     if (dflt == NULL)
  1321. fileBuf[0] = '';
  1322.     else
  1323.     {
  1324. STRNCPY(fileBuf, dflt, MAX_PATH - 1);
  1325. fileBuf[MAX_PATH - 1] = NUL;
  1326.     }
  1327.     /*
  1328.      * The default filter. NOTE: should we perhaps put this in
  1329.      * feature.h?
  1330.      */
  1331.     if (filter == NULL)
  1332. filter =
  1333.     "All Files (*.*)*.*"
  1334.     "C source (*.c, *.h)*.c;*.h"
  1335.     "C++ source (*.cpp, *.hpp)*.cpp;*.hpp"
  1336.     "VB code (*.bas, *.frm)*.bas;*.frm"
  1337.     "Vim files (*.vim, _vimrc, _gvimrc)*.vim;_vimrc;_gvimrc";
  1338.     memset(&fileStruct, 0, sizeof(OPENFILENAME));
  1339.     fileStruct.lStructSize = sizeof(OPENFILENAME);
  1340.     fileStruct.lpstrFilter = filter;
  1341.     fileStruct.lpstrFile = fileBuf;
  1342.     fileStruct.nMaxFile = MAX_PATH;
  1343.     fileStruct.lpstrTitle = title;
  1344.     fileStruct.lpstrDefExt = ext;
  1345.     fileStruct.hwndOwner = s_hwnd; /* main Vim window is owner*/
  1346.     /* has an initial dir been specified? */
  1347.     if (initdir != NULL && *initdir != NUL)
  1348. fileStruct.lpstrInitialDir = initdir;
  1349.     /*
  1350.      * TODO: Allow selection of multiple files.  Needs another arg to this
  1351.      * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
  1352.      * Also, should we use OFN_FILEMUSTEXIST when opening?  Vim can edit on
  1353.      * files that don't exist yet, so I haven't put it in.  What about
  1354.      * OFN_PATHMUSTEXIST?
  1355.      */
  1356.     fileStruct.Flags = (OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT
  1357. | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY);
  1358.     if (saving)
  1359.     {
  1360. if (!GetSaveFileName(&fileStruct))
  1361.     return NULL;
  1362.     }
  1363.     else
  1364.     {
  1365. if (!GetOpenFileName(&fileStruct))
  1366.     return NULL;
  1367.     }
  1368.     /* Shorten the file name if possible */
  1369.     mch_dirname(IObuff, IOSIZE);
  1370.     p = shorten_fname(fileBuf, IObuff);
  1371.     if (p == NULL)
  1372. p = fileBuf;
  1373.     return vim_strsave(p);
  1374. }
  1375. #endif /* USE_BROWSE */
  1376. /* Convert pixels in X to dialog units */
  1377. static WORD
  1378. PixelToDialogX(int numPixels)
  1379. {
  1380.     return (WORD)((numPixels * 4) / s_dlgfntwidth);
  1381. }
  1382. /* Convert pixels in Y to dialog units */
  1383. static WORD
  1384. PixelToDialogY(int numPixels)
  1385. {
  1386.     return (WORD)((numPixels * 8) / s_dlgfntheight);
  1387. }
  1388. /* Return the width in pixels of the given text in the given DC. */
  1389. static int
  1390. GetTextWidth(HDC hdc, char_u *str, int len)
  1391. {
  1392.     SIZE    size;
  1393.     GetTextExtentPoint(hdc, str, len, &size);
  1394.     return size.cx;
  1395. }
  1396. #if defined(GUI_DIALOG) || defined(PROTO)
  1397. /*
  1398.  * stuff for dialogs
  1399.  */
  1400. /*
  1401.  * The callback routine used by all the dialogs.  Very simple.  First,
  1402.  * acknowledges the INITDIALOG message so that Windows knows to do standard
  1403.  * dialog stuff (Return = default, Esc = cancel....) Second, if a button is
  1404.  * pressed returns that button's ID - 2, which is the button's number.
  1405.  */
  1406.     static LRESULT CALLBACK
  1407. dialog_callback(
  1408.     HWND hwnd,
  1409.     UINT message,
  1410.     WPARAM wParam,
  1411.     LPARAM lParam)
  1412. {
  1413.     if (message == WM_INITDIALOG)
  1414.     {
  1415. CenterWindow(hwnd, GetWindow(hwnd, GW_OWNER));
  1416. return (TRUE);
  1417.     }
  1418.     if (message == WM_COMMAND)
  1419.     {
  1420. EndDialog (hwnd, (LOWORD(wParam) - IDCANCEL));
  1421. return TRUE;
  1422.     }
  1423.     if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
  1424.     {
  1425. EndDialog (hwnd, 0);
  1426. return TRUE;
  1427.     }
  1428.     return FALSE;
  1429. }
  1430. /*
  1431.  * Create a dialog dynamically from the parameter strings.
  1432.  * type = type of dialog (question, alert, etc.)
  1433.  * title = dialog title. may be NULL for default title.
  1434.  * message = text to display. Dialog sizes to accommodate it.
  1435.  * buttons = 'n' separated list of button captions, default first.
  1436.  * dfltbutton = number of default button.
  1437.  *
  1438.  * This routine returns 1 if the first button is pressed,
  1439.  * 2 for the second, etc.
  1440.  *
  1441.  * 0 indicates Esc was pressed.
  1442.  * -1 for unexpected error
  1443.  *
  1444.  * If stubbing out this fn, return 1.
  1445.  */
  1446. static const char_u *dlg_icons[] = /* must match names in resource file */
  1447. {
  1448.     "IDR_VIM",
  1449.     "IDR_VIM_ERROR",
  1450.     "IDR_VIM_ALERT",
  1451.     "IDR_VIM_INFO",
  1452.     "IDR_VIM_QUESTION"
  1453. };
  1454.     int
  1455. gui_mch_dialog(
  1456.     int  type,
  1457.     char_u *title,
  1458.     char_u *message,
  1459.     char_u *buttons,
  1460.     int  dfltbutton)
  1461. {
  1462.     WORD *p, *pdlgtemplate, *pnumitems;
  1463.     int numButtons;
  1464.     int *buttonWidths, *buttonPositions;
  1465.     char *dflt_text;
  1466.     int nchar, i;
  1467.     DWORD lStyle;
  1468.     int dlgwidth = 0;
  1469.     int horizWidth;
  1470.     int msgheight;
  1471.     char_u *pstart;
  1472.     char_u *pend;
  1473.     char_u *tbuffer;
  1474.     RECT rect;
  1475.     HWND hwnd;
  1476.     HDC hdc;
  1477.     HFONT font, oldFont;
  1478.     TEXTMETRIC fontInfo;
  1479.     int fontHeight;
  1480.     int textWidth, minButtonWidth, messageWidth;
  1481.     int maxDialogWidth;
  1482.     int vertical;
  1483.     int dlgPaddingX;
  1484.     int dlgPaddingY;
  1485. #ifndef NO_CONSOLE
  1486.     /* Don't output anything in silent mode ("ex -s") */
  1487.     if (silent_mode)
  1488. return dfltbutton;   /* return default option */
  1489. #endif
  1490.     if ((type < 0) || (type > VIM_LAST_TYPE))
  1491. type = 0;
  1492.     /* allocate some memory for dialog template */
  1493.     /* TODO should compute this really*/
  1494.     pdlgtemplate = p = (PWORD) LocalAlloc(LPTR, DLG_ALLOC_SIZE);
  1495.     if (p == NULL)
  1496. return -1;
  1497.     /*
  1498.      * make a copy of 'buttons' to fiddle with it.  complier grizzles because
  1499.      * vim_strsave() doesn't take a const arg (why not?), so cast away the
  1500.      * const.
  1501.      */
  1502.     tbuffer = vim_strsave(buttons);
  1503.     if (tbuffer == NULL)
  1504. return -1;
  1505.     --dfltbutton;   /* Change from one-based to zero-based */
  1506.     /* Count buttons, and find default button text */
  1507.     pstart = tbuffer;
  1508.     numButtons = 1;
  1509.     dflt_text = NULL;
  1510.     for (i = 0; tbuffer[i] != ''; i++)
  1511.     {
  1512. if (tbuffer[i] == DLG_BUTTON_SEP)
  1513. {
  1514.     if (numButtons++ == dfltbutton)
  1515. dflt_text = &tbuffer[i + 1];
  1516. }
  1517.     }
  1518.     if (dflt_text == NULL)
  1519.     {
  1520. dflt_text = tbuffer;
  1521. dfltbutton = 0;
  1522.     }
  1523.     /* Allocate array to hold the width of each button */
  1524.     buttonWidths = (int *) lalloc(numButtons * sizeof(int), TRUE);
  1525.     if (buttonWidths == NULL)
  1526. return -1;
  1527.     /* Allocate array to hold the X position of each button */
  1528.     buttonPositions = (int *) lalloc(numButtons * sizeof(int), TRUE);
  1529.     if (buttonPositions == NULL)
  1530. return -1;
  1531.     /*
  1532.      * Calculate how big the dialog must be.
  1533.      */
  1534.     hwnd = GetDesktopWindow();
  1535.     hdc = GetWindowDC(hwnd);
  1536.     font = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1537.       VARIABLE_PITCH , DLG_FONT_NAME);
  1538.     if (s_usenewlook)
  1539.     {
  1540. oldFont = SelectFont(hdc, font);
  1541. dlgPaddingX = DLG_PADDING_X;
  1542. dlgPaddingY = DLG_PADDING_Y;
  1543.     }
  1544.     else
  1545.     {
  1546. oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
  1547. dlgPaddingX = DLG_OLD_STYLE_PADDING_X;
  1548. dlgPaddingY = DLG_OLD_STYLE_PADDING_Y;
  1549.     }
  1550.     GetTextMetrics(hdc, &fontInfo);
  1551.     fontHeight = fontInfo.tmHeight;
  1552.     /* Minimum width for horizontal button */
  1553.     minButtonWidth = GetTextWidth(hdc, "Cancel", 6);
  1554.     /* Maximum width of a dialog, if possible */
  1555.     GetWindowRect(s_hwnd, &rect);
  1556.     maxDialogWidth = rect.right - rect.left
  1557.      - GetSystemMetrics(SM_CXSIZEFRAME) * 2;
  1558.     if (maxDialogWidth < DLG_MIN_MAX_WIDTH)
  1559. maxDialogWidth = DLG_MIN_MAX_WIDTH;
  1560.     /* Set dlgwidth to width of message */
  1561.     pstart = message;
  1562.     messageWidth = 0;
  1563.     msgheight = 0;
  1564.     do
  1565.     {
  1566. pend = vim_strchr(pstart, DLG_BUTTON_SEP);
  1567. if (pend == NULL)
  1568.     pend = pstart + STRLEN(pstart); /* Last line of message. */
  1569. msgheight += fontHeight;
  1570. textWidth = GetTextWidth(hdc, pstart, pend - pstart);
  1571. if (textWidth > messageWidth)
  1572.     messageWidth = textWidth;
  1573. pstart = pend + 1;
  1574.     } while (*pend != NUL);
  1575.     dlgwidth = messageWidth;
  1576.     /* Add width of icon to dlgwidth, and some space */
  1577.     dlgwidth += DLG_ICON_WIDTH + 3 * dlgPaddingX;
  1578.     if (msgheight < DLG_ICON_HEIGHT)
  1579. msgheight = DLG_ICON_HEIGHT;
  1580.     /*
  1581.      * Check button names.  A long one will make the dialog wider.
  1582.      */
  1583.     vertical = (vim_strchr(p_guioptions, 'v') != NULL);
  1584.     if (!vertical)
  1585.     {
  1586. // Place buttons horizontally if they fit.
  1587. horizWidth = dlgPaddingX;
  1588. pstart = tbuffer;
  1589. i = 0;
  1590. do
  1591. {
  1592.     pend = vim_strchr(pstart, DLG_BUTTON_SEP);
  1593.     if (pend == NULL)
  1594. pend = pstart + STRLEN(pstart); // Last button name.
  1595.     textWidth = GetTextWidth(hdc, pstart, pend - pstart);
  1596.     if (textWidth < minButtonWidth)
  1597. textWidth = minButtonWidth;
  1598.     textWidth += dlgPaddingX;     /* Padding within button */
  1599.     buttonWidths[i] = textWidth;
  1600.     buttonPositions[i++] = horizWidth;
  1601.     horizWidth += textWidth + dlgPaddingX; /* Pad between buttons */
  1602.     pstart = pend + 1;
  1603. } while (*pend != NUL);
  1604. if (horizWidth > maxDialogWidth)
  1605.     vertical = TRUE; // Too wide to fit on the screen.
  1606. else if (horizWidth > dlgwidth)
  1607.     dlgwidth = horizWidth;
  1608.     }
  1609.     if (vertical)
  1610.     {
  1611. // Stack buttons vertically.
  1612. pstart = tbuffer;
  1613. do
  1614. {
  1615.     pend = vim_strchr(pstart, DLG_BUTTON_SEP);
  1616.     if (pend == NULL)
  1617. pend = pstart + STRLEN(pstart); // Last button name.
  1618.     textWidth = GetTextWidth(hdc, pstart, pend - pstart);
  1619.     textWidth += dlgPaddingX; /* Padding within button */
  1620.     textWidth += DLG_VERT_PADDING_X * 2; /* Padding around button */
  1621.     if (textWidth > dlgwidth)
  1622. dlgwidth = textWidth;
  1623.     pstart = pend + 1;
  1624. } while (*pend != NUL);
  1625.     }
  1626.     if (dlgwidth < DLG_MIN_WIDTH)
  1627. dlgwidth = DLG_MIN_WIDTH; /* Don't allow a really thin dialog!*/
  1628.     /* start to fill in the dlgtemplate information.  addressing by WORDs */
  1629.     if (s_usenewlook)
  1630. lStyle = DS_MODALFRAME | WS_CAPTION |DS_3DLOOK| WS_VISIBLE |DS_SETFONT;
  1631.     else
  1632. lStyle = DS_MODALFRAME | WS_CAPTION |DS_3DLOOK| WS_VISIBLE;
  1633.     *p++ = LOWORD(lStyle);
  1634.     *p++ = HIWORD(lStyle);
  1635.     *p++ = 0; // LOWORD (lExtendedStyle)
  1636.     *p++ = 0; // HIWORD (lExtendedStyle)
  1637.     pnumitems = p; /*save where the number of items must be stored*/
  1638.     *p++ = 0; // NumberOfItems(will change later)
  1639.     *p++ = 10; // x
  1640.     *p++ = 10; // y
  1641.     *p++ = PixelToDialogX(dlgwidth); // cx
  1642.     // Dialog height.
  1643.     if (vertical)
  1644. *p++ = PixelToDialogY(msgheight + 2 * dlgPaddingY +
  1645.       DLG_VERT_PADDING_Y + 2 * fontHeight * numButtons);
  1646.     else
  1647. *p++ = PixelToDialogY(msgheight + 3 * dlgPaddingY + 2 * fontHeight);
  1648.     *p++ = 0; // Menu
  1649.     *p++ = 0; // Class
  1650.     /* copy the title of the dialog */
  1651.     nchar = nCopyAnsiToWideChar(p, (title ?
  1652.     (LPSTR)title :
  1653.     (LPSTR)("Vim "VIM_VERSION_MEDIUM)));
  1654.     p += nchar;
  1655.     if (s_usenewlook)
  1656.     {
  1657. /* do the font, since DS_3DLOOK doesn't work properly */
  1658. *p++ = DLG_FONT_POINT_SIZE; //point size
  1659. nchar = nCopyAnsiToWideChar (p, TEXT(DLG_FONT_NAME));
  1660. p += nchar;
  1661.     }
  1662.     pstart = dflt_text;
  1663.     horizWidth = (dlgwidth - horizWidth) / 2; /* Now it's X offset */
  1664.     i = dfltbutton; /* Start with default button */
  1665.     do
  1666.     {
  1667. /* get end of this button. */
  1668. for ( pend = pstart;
  1669. *pend && (*pend != DLG_BUTTON_SEP);
  1670. pend++)
  1671.     ;
  1672. if (*pend)
  1673.     *pend = '';
  1674. /*
  1675.  * NOTE:
  1676.  * setting the BS_DEFPUSHBUTTON style doesn't work because Windows sets
  1677.  * the focus to the first tab-able button and in so doing makes that
  1678.  * the default!! Grrr.  Workaround: Make the default button the only
  1679.  * one with WS_TABSTOP style. Means user can't tab between buttons, but
  1680.  * he/she can use arrow keys.
  1681.  */
  1682. if (vertical)
  1683. {
  1684.     p = add_dialog_element(p,
  1685.     BS_PUSHBUTTON | WS_TABSTOP,
  1686.     PixelToDialogX(DLG_VERT_PADDING_X),
  1687.     PixelToDialogY(msgheight + 2 * dlgPaddingY
  1688.    + 2 * fontHeight * i),
  1689.     PixelToDialogX(dlgwidth - 2 * DLG_VERT_PADDING_X),
  1690.     (WORD)(PixelToDialogY(2 * fontHeight) - 1),
  1691.     (WORD)(IDCANCEL + 1 + i), (WORD)0x0080, pstart);
  1692. }
  1693. else
  1694. {
  1695.     p = add_dialog_element(p,
  1696.     BS_PUSHBUTTON | WS_TABSTOP,
  1697.     PixelToDialogX(horizWidth + buttonPositions[i]),
  1698.     PixelToDialogY(msgheight + 2 * dlgPaddingY),
  1699.     PixelToDialogX(buttonWidths[i]),
  1700.     (WORD)(PixelToDialogY(2 * fontHeight) - 1),
  1701.     (WORD)(IDCANCEL + 1 + i), (WORD)0x0080, pstart);
  1702. }
  1703. if (++i >= numButtons)
  1704. {
  1705.     i = 0;
  1706.     pstart = tbuffer;
  1707. }
  1708. else
  1709.     pstart = pend + 1; /*next button*/
  1710.     } while (i != dfltbutton);
  1711.     *pnumitems += numButtons;
  1712.     /* Vim icon */
  1713.     p = add_dialog_element(p, SS_ICON,
  1714.     PixelToDialogX(dlgPaddingX),
  1715.     PixelToDialogY(dlgPaddingY),
  1716.     PixelToDialogX(DLG_ICON_WIDTH),
  1717.     PixelToDialogY(DLG_ICON_HEIGHT),
  1718.     0, (WORD)0x0082, dlg_icons[type]);
  1719.     /* Dialog message */
  1720.     p = add_dialog_element(p, SS_LEFT,//SS_CENTER,
  1721.     PixelToDialogX(2 * dlgPaddingX + DLG_ICON_WIDTH),
  1722.     PixelToDialogY(dlgPaddingY),
  1723.     (WORD)(PixelToDialogX(messageWidth) + 1),
  1724.     PixelToDialogY(msgheight),
  1725.     1, (WORD)0x0082, message);
  1726.     *pnumitems += 2;
  1727.     SelectFont(hdc, oldFont);
  1728.     DeleteObject(font);
  1729.     ReleaseDC(hwnd, hdc);
  1730.     /*show the dialog box modally and get a return value*/
  1731.     nchar = DialogBoxIndirect(
  1732.     s_hinst,
  1733.     (LPDLGTEMPLATE)pdlgtemplate,
  1734.     s_hwnd,
  1735.     (DLGPROC)dialog_callback);
  1736.     LocalFree (LocalHandle (pdlgtemplate));
  1737.     vim_free(tbuffer);
  1738.     vim_free(buttonWidths);
  1739.     vim_free(buttonPositions);
  1740.     return nchar;
  1741. }
  1742. #endif /* GUI_DIALOG */
  1743. /*
  1744.  * Put a simple element (basic class) onto a dialog template in memory.
  1745.  * return a pointer to where the next item shoudl be added.
  1746.  *
  1747.  * parameters:
  1748.  *  lStyle = additional style flags
  1749.  * (be careful, NT3.51 & Win32s will ignore the new ones)
  1750.  *  x,y = x & y positions IN DIALOG UNITS
  1751.  *  w,h = width and height IN DIALOG UNITS
  1752.  *  Id  = ID used in messages
  1753.  *  clss  = class ID, e.g 0x0080 for a button, 0x0082 for a static
  1754.  *  caption = usually text or resource name
  1755.  *
  1756.  *  TODO: use the length information noted here to enable the dialog creation
  1757.  *  routines to work out more exactly how much memory they need to alloc.
  1758.  */
  1759.     static PWORD
  1760. add_dialog_element(
  1761.     PWORD p,
  1762.     DWORD lStyle,
  1763.     WORD x,
  1764.     WORD y,
  1765.     WORD w,
  1766.     WORD h,
  1767.     WORD Id,
  1768.     WORD clss,
  1769.     const char *caption)
  1770. {
  1771.     int nchar;
  1772.     p = lpwAlign(p); /* Align to dword boundary*/
  1773.     lStyle = lStyle | WS_VISIBLE | WS_CHILD;
  1774.     *p++ = LOWORD(lStyle);
  1775.     *p++ = HIWORD(lStyle);
  1776.     *p++ = 0; // LOWORD (lExtendedStyle)
  1777.     *p++ = 0; // HIWORD (lExtendedStyle)
  1778.     *p++ = x;
  1779.     *p++ = y;
  1780.     *p++ = w;
  1781.     *p++ = h;
  1782.     *p++ = Id; //9 or 10 words in all
  1783.     *p++ = (WORD)0xffff;
  1784.     *p++ = clss; //2 more here
  1785.     nchar = nCopyAnsiToWideChar(p, (LPSTR)caption); //strlen(caption)+1
  1786.     p += nchar;
  1787.     *p++ = 0;  // advance pointer over nExtraStuff WORD   - 2 more
  1788.     return p; //total = 15+ (strlen(caption)) words
  1789. //    = 30 + 2(strlen(caption) bytes reqd
  1790. }
  1791. /*
  1792.  * Helper routine.  Take an input pointer, return closest pointer that is
  1793.  * aligned on a DWORD (4 byte) boundary.  Taken from the Win32SDK samples.
  1794.  */
  1795.     static LPWORD
  1796. lpwAlign(
  1797.     LPWORD lpIn)
  1798. {
  1799.     ULONG ul;
  1800.     ul = (ULONG)lpIn;
  1801.     ul += 3;
  1802.     ul >>= 2;
  1803.     ul <<= 2;
  1804.     return (LPWORD)ul;
  1805. }
  1806. /*
  1807.  * Helper routine.  Takes second parameter as Ansi string, copies it to first
  1808.  * parameter as wide character (16-bits / char) string, and returns integer
  1809.  * number of wide characters (words) in string (including the trailing wide
  1810.  * char NULL).  Partly taken from the Win32SDK samples.
  1811.  */
  1812.     static int
  1813. nCopyAnsiToWideChar(
  1814.     LPWORD lpWCStr,
  1815.     LPSTR lpAnsiIn)
  1816. {
  1817.     int nChar = 0;
  1818.     do
  1819.     {
  1820. if (*lpAnsiIn == 't')
  1821.     *lpWCStr++ = (WORD)' ';
  1822. else
  1823.     *lpWCStr++ = (WORD)*lpAnsiIn;
  1824. nChar++;
  1825.     } while (*lpAnsiIn++);
  1826.     return nChar;
  1827. }
  1828. /*
  1829.  * A quick little routine that will center one window over another, handy for
  1830.  * dialog boxes.  Taken from the Win32SDK samples.
  1831.  */
  1832.     static BOOL
  1833. CenterWindow(
  1834.     HWND hwndChild,
  1835.     HWND hwndParent)
  1836. {
  1837.     RECT    rChild, rParent;
  1838.     int     wChild, hChild, wParent, hParent;
  1839.     int     wScreen, hScreen, xNew, yNew;
  1840.     HDC     hdc;
  1841.     GetWindowRect(hwndChild, &rChild);
  1842.     wChild = rChild.right - rChild.left;
  1843.     hChild = rChild.bottom - rChild.top;
  1844.     GetWindowRect(hwndParent, &rParent);
  1845.     wParent = rParent.right - rParent.left;
  1846.     hParent = rParent.bottom - rParent.top;
  1847.     hdc = GetDC(hwndChild);
  1848.     wScreen = GetDeviceCaps (hdc, HORZRES);
  1849.     hScreen = GetDeviceCaps (hdc, VERTRES);
  1850.     ReleaseDC(hwndChild, hdc);
  1851.     xNew = rParent.left + ((wParent - wChild) /2);
  1852.     if (xNew < 0)
  1853.     {
  1854. xNew = 0;
  1855.     }
  1856.     else if ((xNew+wChild) > wScreen)
  1857.     {
  1858. xNew = wScreen - wChild;
  1859.     }
  1860.     yNew = rParent.top  + ((hParent - hChild) /2);
  1861.     if (yNew < 0)
  1862. yNew = 0;
  1863.     else if ((yNew+hChild) > hScreen)
  1864. yNew = hScreen - hChild;
  1865.     return SetWindowPos(hwndChild, NULL, xNew, yNew, 0, 0,
  1866.    SWP_NOSIZE | SWP_NOZORDER);
  1867. }
  1868. /*
  1869.  * The callback function for all the modeless dialogs that make up the
  1870.  * "tearoff menus" Very simple - forward button presses (to fool Vim into
  1871.  * thinking its menus have been clicked), and go away when closed.
  1872.  */
  1873.     static LRESULT CALLBACK
  1874. tearoff_callback(
  1875.     HWND hwnd,
  1876.     UINT message,
  1877.     WPARAM wParam,
  1878.     LPARAM lParam)
  1879. {
  1880.     if (message == WM_INITDIALOG)
  1881. return (TRUE);
  1882.     if (message == WM_COMMAND)
  1883.     {
  1884. if ((WORD)(LOWORD(wParam)) & 0x8000)
  1885. {
  1886.     POINT   mp;
  1887.     RECT    rect;
  1888.     if (GetCursorPos(&mp) && GetWindowRect(hwnd, &rect));
  1889.     {
  1890. (void)TrackPopupMenu(
  1891.  (HMENU)(LOWORD(wParam) ^ 0x8000),
  1892.  TPM_LEFTALIGN | TPM_LEFTBUTTON,
  1893.  (int)rect.right - 8,
  1894.  (int)mp.y,
  1895.  (int)0,     /*reserved param*/
  1896.  s_hwnd,
  1897.  NULL);
  1898. /*
  1899.  * NOTE: The pop-up menu can eat the mouse up event.
  1900.  * We deal with this in normal.c.
  1901.  */
  1902.     }
  1903. }
  1904. else
  1905.     /* Pass on messages to the main Vim window */
  1906.     PostMessage (s_hwnd, WM_COMMAND, LOWORD(wParam), 0);
  1907. /*
  1908.  * Give main window the focus back: this is so after
  1909.  * choosing a tearoff button you can start typing again
  1910.  * straight away.
  1911.  */
  1912. (void)SetFocus(s_hwnd);
  1913. return TRUE;
  1914.     }
  1915.     if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
  1916.     {
  1917. DestroyWindow(hwnd);
  1918. return TRUE;
  1919.     }
  1920.     /* When moved around, give main window the focus back. */
  1921.     if (message == WM_EXITSIZEMOVE)
  1922. (void)SetActiveWindow(s_hwnd);
  1923.     return FALSE;
  1924. }
  1925. /*
  1926.  * Create a pseudo-"tearoff menu" based on the child
  1927.  * items of a given menu pointer.
  1928.  */
  1929.     static void
  1930. gui_mch_tearoff(
  1931.     char_u *title,
  1932.     GuiMenu *menu,
  1933.     int initX,
  1934.     int initY)
  1935. {
  1936.     WORD *p, *pdlgtemplate, *pnumitems, *ptrueheight;
  1937.     int nchar, textWidth, submenuWidth;
  1938.     DWORD lStyle;
  1939.     DWORD lExtendedStyle;
  1940.     WORD dlgwidth;
  1941.     WORD menuID;
  1942.     GuiMenu *pmenu;
  1943.     GuiMenu *the_menu = menu;
  1944.     HWND hwnd;
  1945.     HDC hdc;
  1946.     HFONT font, oldFont;
  1947.     int col, spaceWidth, len;
  1948.     int columnWidths[2];
  1949.     char_u *label, *text, *end, *acEnd;
  1950.     int padding0, padding1, padding2;
  1951.     /*
  1952.      * If this menu is already torn off, then don't
  1953.      * tear it off again, but move the existing tearoff
  1954.      * to the mouse position.
  1955.      */
  1956.     if (IsWindow(menu->tearoff_handle))
  1957.     {
  1958. POINT mp;
  1959. if (GetCursorPos((LPPOINT)&mp))
  1960. {
  1961.     SetWindowPos(menu->tearoff_handle, NULL, mp.x, mp.y, 0, 0,
  1962.     SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  1963. }
  1964. return;
  1965.     }
  1966.     /*
  1967.      * Otherwise, create a new tearoff
  1968.      */
  1969.     if (*title == MNU_HIDDEN_CHAR)
  1970. title++;
  1971.     /* allocate some memory to play with  */
  1972.     /* TODO should compute this really    */
  1973.     pdlgtemplate = p = (PWORD)LocalAlloc(LPTR,  DLG_ALLOC_SIZE);
  1974.     if (p == NULL)
  1975. return;
  1976.     hwnd = GetDesktopWindow();
  1977.     hdc = GetWindowDC(hwnd);
  1978.     font = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1979.       VARIABLE_PITCH , DLG_FONT_NAME);
  1980.     if (s_usenewlook)
  1981. oldFont = SelectFont(hdc, font);
  1982.     else
  1983. oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
  1984.     /*
  1985.      * Calculate width of a single space.  Used for padding columns to the
  1986.      * right width.
  1987.      */
  1988.     spaceWidth = GetTextWidth(hdc, " ", 1);
  1989.     submenuWidth = 0;
  1990.     /* Figure out widths for each column. */
  1991.     for (col = 0; col < 2; col++)
  1992.     {
  1993. columnWidths[col] = 0;
  1994. for (pmenu = menu->children; pmenu != NULL; pmenu = pmenu->next)
  1995. {
  1996.     text = (col == 0) ? pmenu->dname : pmenu->actext;
  1997.     if (pmenu->children != NULL)
  1998. submenuWidth = TEAROFF_COLUMN_PADDING * spaceWidth;
  1999.     if (text != NULL && *text != NUL)
  2000.     {
  2001. end = text + strlen(text);
  2002. textWidth = GetTextWidth(hdc, text, end - text);
  2003. if (textWidth > columnWidths[col])
  2004.     columnWidths[col] = textWidth;
  2005.     }
  2006. }
  2007.     }
  2008.     if (columnWidths[1] == 0)
  2009.     {
  2010. if (submenuWidth != 0)
  2011.     columnWidths[0] += submenuWidth;
  2012. else
  2013.     columnWidths[0] += spaceWidth;
  2014.     }
  2015.     else
  2016.     {
  2017. columnWidths[0] += TEAROFF_COLUMN_PADDING * spaceWidth;
  2018. columnWidths[1] += submenuWidth;
  2019.     }
  2020.     /*
  2021.      * Now find the width of our 'menu'.
  2022.      */
  2023.     textWidth = 0;
  2024.     for (col = 0; col < 2; col++)
  2025. textWidth += columnWidths[col];
  2026.     if (submenuWidth != 0)
  2027.     {
  2028. submenuWidth = GetTextWidth(hdc, TEAROFF_SUBMENU_LABEL,
  2029.       STRLEN(TEAROFF_SUBMENU_LABEL));
  2030. textWidth += submenuWidth;
  2031.     }
  2032.     dlgwidth = GetTextWidth(hdc, title, strlen(title));
  2033.     if (textWidth > dlgwidth)
  2034. dlgwidth = textWidth;
  2035.     dlgwidth += 2 * TEAROFF_PADDING_X + TEAROFF_BUTTON_PAD_X;
  2036.     /* W95 can't do thin dialogs, they look v. weird! */
  2037.     if (mch_windows95() && dlgwidth < TEAROFF_MIN_WIDTH)
  2038. dlgwidth = TEAROFF_MIN_WIDTH;
  2039.     /* start to fill in the dlgtemplate information.  addressing by WORDs */
  2040.     if (s_usenewlook)
  2041. lStyle = DS_MODALFRAME | WS_CAPTION| WS_SYSMENU |DS_SETFONT| WS_VISIBLE;
  2042.     else
  2043. lStyle = DS_MODALFRAME | WS_CAPTION| WS_SYSMENU | WS_VISIBLE;
  2044.     lExtendedStyle = WS_EX_TOOLWINDOW|WS_EX_STATICEDGE;
  2045.     *p++ = LOWORD(lStyle);
  2046.     *p++ = HIWORD(lStyle);
  2047.     *p++ = LOWORD (lExtendedStyle);
  2048.     *p++ = HIWORD (lExtendedStyle);
  2049.     pnumitems = p; /* save where the number of items must be stored */
  2050.     *p++ = 0; // NumberOfItems(will change later)
  2051.     if (initX == 0xffffL)
  2052. *p++ = PixelToDialogX(gui_mch_get_mouse_x()); // x
  2053.     else
  2054. *p++ = PixelToDialogX(initX); // x
  2055.     if (initY == 0xffffL)
  2056. *p++ = PixelToDialogY(gui_mch_get_mouse_y()); // y
  2057.     else
  2058. *p++ = PixelToDialogY(initY); // y
  2059.     *p++ = PixelToDialogX(dlgwidth);    // cx
  2060.     ptrueheight =p;
  2061.     *p++ = 0; // dialog height: changed later anyway
  2062.     *p++ = 0; // Menu
  2063.     *p++ = 0; // Class
  2064.     /* copy the title of the dialog */
  2065.     nchar = nCopyAnsiToWideChar(p, ((*title) ?
  2066.     (LPSTR)title :
  2067.     (LPSTR)("Vim "VIM_VERSION_MEDIUM)));
  2068.     p += nchar;
  2069.     if (s_usenewlook)
  2070.     {
  2071. /* do the font, since DS_3DLOOK doesn't work properly */
  2072. *p++ = DLG_FONT_POINT_SIZE; //point size
  2073. nchar = nCopyAnsiToWideChar (p, TEXT(DLG_FONT_NAME));
  2074. p += nchar;
  2075.     }
  2076.     /* Don't include tearbar in tearoff menu */
  2077.     if (STRCMP(menu->children->name, TEAR_STRING) == 0)
  2078. menu = menu->children->next;
  2079.     else
  2080. menu = menu->children;
  2081.     while (menu != NULL)
  2082.     {
  2083. /* Figure out length of this menu label */
  2084. len = STRLEN(menu->dname);
  2085. end = menu->dname + STRLEN(menu->dname);
  2086. padding0 = (columnWidths[0] - GetTextWidth(hdc, menu->dname,
  2087.     end - menu->dname)) / spaceWidth;
  2088. len += padding0;
  2089. if (menu->actext != NULL)
  2090. {
  2091.     len += STRLEN(menu->actext);
  2092.     acEnd = menu->actext + STRLEN(menu->actext);
  2093. }
  2094. if (menu->actext != NULL)
  2095.     textWidth = GetTextWidth(hdc, menu->actext,
  2096.      acEnd - menu->actext);
  2097. else
  2098.     textWidth = 0;
  2099. padding1 = (columnWidths[1] - textWidth) / spaceWidth;
  2100. len += padding1;
  2101. if (menu->children == NULL)
  2102. {
  2103.     padding2 = submenuWidth / spaceWidth;
  2104.     len += padding2;
  2105.     menuID = (WORD)(menu->id);
  2106. }
  2107. else
  2108. {
  2109.     len += STRLEN(TEAROFF_SUBMENU_LABEL);
  2110.     menuID = (WORD)((WORD)(menu->submenu_id) | (WORD)0x8000);
  2111. }
  2112. /* Allocate menu label and fill it in */
  2113. text = label = alloc((unsigned)len + 1);
  2114. if (label == NULL)
  2115.     break;
  2116. STRNCPY(text, menu->dname, end - menu->dname);
  2117. text += end - menu->dname;
  2118. while (padding0-- > 0)
  2119.     *text++ = ' ';
  2120. if (menu->actext != NULL)
  2121. {
  2122.     STRNCPY(text, menu->actext, acEnd - menu->actext);
  2123.     text += acEnd - menu->actext;
  2124. }
  2125. while (padding1-- > 0)
  2126.     *text++ = ' ';
  2127. if (menu->children != NULL)
  2128. {
  2129.     STRCPY(text, TEAROFF_SUBMENU_LABEL);
  2130.     text += STRLEN(TEAROFF_SUBMENU_LABEL);
  2131. }
  2132. else
  2133. {
  2134.     while (padding2-- > 0)
  2135. *text++ = ' ';
  2136. }
  2137. *text = NUL;
  2138. *end = NUL;
  2139. /*
  2140.  * BS_LEFT will just be ignored on Win32s/NT3.5x - on
  2141.  * W95/NT4 it makes the tear-off look more like a menu.
  2142.  */
  2143.     p = add_dialog_element(p,
  2144.     BS_PUSHBUTTON|BS_LEFT,
  2145. (WORD)PixelToDialogX(TEAROFF_PADDING_X),
  2146.     (WORD)(1 + 13 * (*pnumitems)),
  2147. (WORD)PixelToDialogX(dlgwidth - 2 * TEAROFF_PADDING_X),
  2148. (WORD)12,
  2149. menuID, (WORD)0x0080, label);
  2150. vim_free(label);
  2151.     (*pnumitems)++;
  2152. menu = menu->next;
  2153.     }
  2154.     *ptrueheight = (WORD)(1 + 13 * (*pnumitems));
  2155.     /* show modelessly */
  2156.     the_menu->tearoff_handle = CreateDialogIndirect(
  2157.     s_hinst,
  2158.     (LPDLGTEMPLATE)pdlgtemplate,
  2159.     s_hwnd,
  2160.     (DLGPROC)tearoff_callback);
  2161.     LocalFree(LocalHandle(pdlgtemplate));
  2162.     SelectFont(hdc, oldFont);
  2163.     DeleteObject(font);
  2164.     ReleaseDC(hwnd, hdc);
  2165.     /*
  2166.      * Reassert ourselves as the active window.  This is so that after creating
  2167.      * a tearoff, the user doesn't have to click with the mouse just to start
  2168.      * typing agin!
  2169.      */
  2170.     SetActiveWindow(s_hwnd);
  2171.     /* make sure the right buttons are enabled*/
  2172.     force_menu_update = TRUE;
  2173. }
  2174. /*
  2175.  * Decide whether to use the "new look" (small, non-bold font) or the "old
  2176.  * look" (big, clanky font) for dialogs, and work out a few values for use
  2177.  * later accordingly.
  2178.  */
  2179.     static void
  2180. get_dialog_font_metrics(void)
  2181. {
  2182.     HDC     hdc;
  2183.     HFONT     hfontTools = 0;
  2184.     DWORD     dlgFontSize;
  2185.     SIZE     size;
  2186.     s_usenewlook = FALSE;
  2187.     /*
  2188.      * For NT3.51 and Win32s, we stick with the old look
  2189.      * because it matches everything else.
  2190.      */
  2191.     if (!is_winnt_3())
  2192.     {
  2193. hfontTools = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0,
  2194. 0, 0, 0, 0, VARIABLE_PITCH , DLG_FONT_NAME);
  2195. if (hfontTools)
  2196. {
  2197.     hdc = GetDC (s_hwnd);
  2198.     SelectObject (hdc, hfontTools);
  2199.     /*
  2200.      * GetTextMetrics() doesn't return the right value in
  2201.      * tmAveCharWidth, so we have to figure out the dialog base units
  2202.      * ourselves.
  2203.      */
  2204.     GetTextExtentPoint(hdc,
  2205.     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
  2206.     52, &size);
  2207.     ReleaseDC (s_hwnd, hdc);
  2208.     s_dlgfntwidth = (WORD)((size.cx / 26 + 1) / 2);
  2209.     s_dlgfntheight = (WORD)size.cy;
  2210.     s_usenewlook = TRUE;
  2211. }
  2212.     }
  2213.     if (!s_usenewlook)
  2214.     {
  2215. dlgFontSize = GetDialogBaseUnits(); /* fall back to big old system*/
  2216. s_dlgfntwidth = LOWORD(dlgFontSize);
  2217. s_dlgfntheight = HIWORD(dlgFontSize);
  2218.     }
  2219. }
  2220. #if defined(USE_GUI_WIN32_TOOLBAR) || defined(PROTO)
  2221. #include "gui_w32_rc.h"
  2222. /*
  2223.  * Create the toolbar, initially unpopulated.
  2224.  *  (just like the menu, there are no defaults, it's all
  2225.  *  set up through menu.vim)
  2226.  */
  2227.     static void
  2228. initialise_toolbar(void)
  2229. {
  2230.     InitCommonControls();
  2231.     s_toolbarhwnd = CreateToolbarEx(
  2232.     s_hwnd,
  2233.     WS_CHILD | TBSTYLE_TOOLTIPS,
  2234.     4000, //any old big number
  2235.     28, //number of images in inital bitmap
  2236.     s_hinst,
  2237.     IDR_TOOLBAR1, // id of initial bitmap
  2238.     NULL,
  2239.     0, // initial number of buttons
  2240.     TOOLBAR_BUTTON_WIDTH, //api guide is wrong!
  2241.     TOOLBAR_BUTTON_HEIGHT,
  2242.     TOOLBAR_BUTTON_WIDTH,
  2243.     TOOLBAR_BUTTON_HEIGHT,
  2244.     sizeof(TBBUTTON)
  2245.     );
  2246.     gui_mch_show_toolbar(vim_strchr(p_guioptions, GO_TOOLBAR) != NULL);
  2247. }
  2248.     void
  2249. gui_mch_show_toolbar(int showit)
  2250. {
  2251.     if (s_toolbarhwnd == NULL)
  2252. return;
  2253.     if (showit)
  2254. ShowWindow(s_toolbarhwnd, SW_SHOW);
  2255.     else
  2256. ShowWindow(s_toolbarhwnd, SW_HIDE);
  2257. }
  2258. /*
  2259.  * Find a bitmap by name.
  2260.  * If the name is one of the built-in bitmaps, return the index to that bitmap.
  2261.  * Otherwise, look for $vim/bitmaps/<name>.bmp, load it, add it to the toolbar
  2262.  * bitmap list and return the resulting index on failure return -1, which will
  2263.  * result in a blank (but still functional) button
  2264.  */
  2265. static const char_u *BuiltInBitmaps[] =
  2266. {
  2267.     "New", //0
  2268.     "Open", //1
  2269.     "Save", //2
  2270.     "Undo", //3
  2271.     "Redo", //4
  2272.     "Cut", //5
  2273.     "Copy", //6
  2274.     "Paste", //7
  2275.     "Print", //8
  2276.     "Help", //9
  2277.     "Find", //10
  2278.     "SaveAll", //11
  2279.     "SaveSession", //12
  2280.     "NewSession", //13
  2281.     "LoadSession", //14
  2282.     "RunMacro", //15
  2283.     "Replace", //16
  2284.     "WinClose", //17
  2285.     "WinZoom", //18
  2286.     "WinMin", //19
  2287.     "WinSplit", //20
  2288.     "Shell", //21
  2289.     "FindPrev", //22
  2290.     "FindNext", //23
  2291.     "FindHelp", //24
  2292.     "Make", //25
  2293.     "TagsJump", //26
  2294.     "TagsBuild", //27
  2295.     NULL
  2296. };
  2297.     static int
  2298. get_toolbar_bitmap(char_u *name)
  2299. {
  2300.     int i;
  2301.     if (STRNCMP(name, "BuiltIn", 7) == 0)
  2302.     {
  2303. char_u *dummy;
  2304. /*
  2305.  * reference by index
  2306.  */
  2307. i = strtol(name + 7, &dummy, 0);
  2308. return i;
  2309.     }
  2310.     /*
  2311.      * Check user bitmaps next
  2312.      */
  2313.     i = -1;
  2314.     if (!is_winnt_3())
  2315.     {
  2316. char_u *fname;
  2317. char_u *ffname;
  2318. HANDLE hbitmap;
  2319. fname = alloc(_MAX_PATH);
  2320. STRCPY(fname, "$VIM\bitmaps\");
  2321. strcat(fname, name);
  2322. strcat(fname, ".bmp");
  2323. ffname = expand_env_save(fname);
  2324. hbitmap = LoadImage(
  2325.     NULL,
  2326.     ffname,
  2327.     IMAGE_BITMAP,
  2328.     TOOLBAR_BUTTON_WIDTH,
  2329.     TOOLBAR_BUTTON_HEIGHT,
  2330.     LR_LOADFROMFILE |
  2331.     LR_LOADMAP3DCOLORS
  2332. );
  2333. if (hbitmap != NULL)
  2334. {
  2335.     TBADDBITMAP tbAddBitmap;
  2336.     tbAddBitmap.hInst = NULL;
  2337.     tbAddBitmap.nID = (UINT)hbitmap;
  2338.     i = SendMessage(s_toolbarhwnd, TB_ADDBITMAP,
  2339.     (WPARAM)1, (LPARAM)&tbAddBitmap);
  2340.     /* i will be set to -1 if it fails */
  2341. }
  2342. vim_free(fname);
  2343. vim_free(ffname);
  2344.     }
  2345.     if (i != -1)
  2346. return i;
  2347.     for (i = 0; BuiltInBitmaps[i]; i++)
  2348.     {
  2349. if (STRCMP(name, BuiltInBitmaps[i]) == 0)
  2350.     return i;
  2351.     }
  2352.     return i;
  2353. }
  2354. #endif
  2355.     void
  2356. gui_simulate_alt_key(char_u *keys)
  2357. {
  2358.     PostMessage(s_hwnd, WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (LPARAM)0);
  2359.     while (*keys)
  2360.     {
  2361. if (*keys == '~')
  2362.     *keys = ' ';     /* for showing system menu */
  2363. PostMessage(s_hwnd, WM_CHAR, (WPARAM)*keys, (LPARAM)0);
  2364. keys++;
  2365.     }
  2366. }
  2367. /*
  2368.  * Create the find & replace dialogs
  2369.  * You can't have both at once: ":find" when replace is showing, destroys
  2370.  * the replace dialog first.
  2371.  */
  2372.     void
  2373. gui_mch_find_dialog(char_u *arg)
  2374. {
  2375. #ifdef WIN32_FIND_REPLACE
  2376.     if (s_findrep_msg != 0)
  2377.     {
  2378. if (IsWindow(s_findrep_hwnd) && (s_findrep_is_find == FALSE))
  2379.     DestroyWindow(s_findrep_hwnd);
  2380. if (!IsWindow(s_findrep_hwnd))
  2381. {
  2382.     initialise_findrep(arg);
  2383.     s_findrep_hwnd = FindText((LPFINDREPLACE) &s_findrep_struct);
  2384. }
  2385. (void)SetWindowText(s_findrep_hwnd,
  2386.     (LPCSTR) "Find string (use '\\' to find  a '\')");
  2387. (void)SetFocus(s_findrep_hwnd);
  2388. s_findrep_is_find = TRUE;
  2389.     }
  2390. #endif
  2391. }
  2392.     void
  2393. gui_mch_replace_dialog(char_u *arg)
  2394. {
  2395. #ifdef WIN32_FIND_REPLACE
  2396.     if (s_findrep_msg != 0)
  2397.     {
  2398. if (IsWindow(s_findrep_hwnd) && (s_findrep_is_find == TRUE))
  2399.     DestroyWindow(s_findrep_hwnd);
  2400. if (!IsWindow(s_findrep_hwnd))
  2401. {
  2402.     initialise_findrep(arg);
  2403.     s_findrep_hwnd = ReplaceText((LPFINDREPLACE) &s_findrep_struct);
  2404. }
  2405. (void)SetWindowText(s_findrep_hwnd,
  2406.     (LPCSTR) "Find & Replace (use '\\' to find  a '\')");
  2407. (void)SetFocus(s_findrep_hwnd);
  2408. s_findrep_is_find = FALSE;
  2409.     }
  2410. #endif
  2411. }
  2412. #ifdef WIN32_FIND_REPLACE
  2413.     static void
  2414. initialise_findrep(char_u *initial_string)
  2415. {
  2416.     s_findrep_struct.hwndOwner = s_hwnd;
  2417.     s_findrep_struct.Flags = FR_HIDEMATCHCASE | FR_DOWN;
  2418.     if (initial_string != NULL && *initial_string != NUL)
  2419.     {
  2420. STRCPY(s_findrep_struct.lpstrFindWhat, initial_string);
  2421.     s_findrep_struct.lpstrReplaceWith[0] = NUL;
  2422.     }
  2423. }
  2424. #endif
  2425. /*
  2426.  * Set visibility of the pointer.
  2427.  */
  2428.     void
  2429. gui_mch_mousehide(int hide)
  2430. {
  2431.     if (hide != gui.pointer_hidden)
  2432.     {
  2433. ShowCursor(!hide);
  2434. gui.pointer_hidden = hide;
  2435.     }
  2436. }