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

编辑器/阅读器

开发平台:

DOS

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved by Bram Moolenaar
  4.  * GUI support by Robert Webb
  5.  *
  6.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  7.  * Do ":help credits" in Vim to see a list of people who contributed.
  8.  *
  9.  * Windows GUI.
  10.  *
  11.  * GUI support for Microsoft Windows.  Win32 initially; maybe Win16 later
  12.  *
  13.  * George V. Reilly <gvr@halcyon.com> wrote the original Win32 GUI.
  14.  * Robert Webb reworked it to use the existing GUI stuff and added menu,
  15.  * scrollbars, etc.
  16.  *
  17.  * Note: Clipboard stuff, for cutting and pasting text to other windows, is in
  18.  * os_win32.c. (It can also be done from the terminal version).
  19.  */
  20. #define WIN32_FIND_REPLACE /* include code for find/replace dialog */
  21. #define MENUHINTS /* show menu hints in command line */
  22. #include "vim.h"
  23. #include "version.h" /* used by dialog box routine for default title */
  24. #include <windows.h>
  25. #include <shellapi.h>
  26. #ifdef USE_GUI_WIN32_TOOLBAR
  27. #include <commctrl.h>
  28. #endif
  29. #include <windowsx.h>
  30. /* Some parameters for dialog boxes.  All in pixels. */
  31. #define DLG_PADDING_X 10
  32. #define DLG_PADDING_Y 10
  33. #define DLG_OLD_STYLE_PADDING_X 5
  34. #define DLG_OLD_STYLE_PADDING_Y 5
  35. #define DLG_VERT_PADDING_X 4   /* For vertical buttons */
  36. #define DLG_VERT_PADDING_Y 4
  37. #define DLG_ICON_WIDTH 34
  38. #define DLG_ICON_HEIGHT 34
  39. #define DLG_MIN_WIDTH 150
  40. #define DLG_FONT_NAME "MS Sans Serif"
  41. #define DLG_FONT_POINT_SIZE 8
  42. #define DLG_MIN_MAX_WIDTH 400
  43. /* Some parameters for tearoff menus.  All in pixels. */
  44. #define TEAROFF_PADDING_X 2
  45. #define TEAROFF_BUTTON_PAD_X 8
  46. #define TEAROFF_MIN_WIDTH 200
  47. #define TEAROFF_SUBMENU_LABEL ">>"
  48. #define TEAROFF_COLUMN_PADDING 3 // # spaces to pad column with.
  49. #ifdef PROTO
  50. /*
  51.  * Define a few things for generating prototypes.  This is just to avoid
  52.  * syntax errors, the defines do not need to be correct.
  53.  */
  54. # define HINSTANCE  void *
  55. # define HWND     void *
  56. # define HDC     void *
  57. # define HMENU     void *
  58. # define UINT     int
  59. # define WPARAM     int
  60. # define LPARAM     int
  61. typedef int LOGFONT[];
  62. # define ENUMLOGFONT int
  63. # define NEWTEXTMETRIC int
  64. # define VOID     void
  65. # define CALLBACK
  66. # define WORD     int
  67. # define DWORD     int
  68. # define HBITMAP    int
  69. # define HDROP     int
  70. # define BOOL     int
  71. # define PWORD     int
  72. # define LPWORD     int
  73. # define LPRECT     int
  74. # define LRESULT    int
  75. # define WINAPI
  76. # define APIENTRY
  77. # define LPSTR     int
  78. # define LPWINDOWPOS int
  79. # define RECT     int
  80. # define LPCREATESTRUCT int
  81. # define _cdecl
  82. # define FINDREPLACE int
  83. # define LPCTSTR int
  84. # define OSVERSIONINFO int
  85. #endif
  86. /* For the Intellimouse: */
  87. #ifndef WM_MOUSEWHEEL
  88. #define WM_MOUSEWHEEL 0x20a
  89. #endif
  90. #ifdef MULTI_BYTE
  91. static int sysfixed_width = 0;
  92. static int sysfixed_height = 0;
  93. #endif
  94. /* Local variables: */
  95. static int     s_button_pending = -1;
  96. static int     s_x_pending;
  97. static int     s_y_pending;
  98. static UINT     s_kFlags_pending;
  99. static HINSTANCE    s_hinst = NULL;
  100. static HWND     s_hwnd = NULL;
  101. static HDC     s_hdc = NULL;
  102. #ifdef USE_GUI_WIN32_TOOLBAR
  103. static HWND     s_toolbarhwnd = NULL;
  104. #endif
  105. #ifdef WIN32_FIND_REPLACE
  106. static HWND     s_findrep_hwnd = NULL;
  107. static UINT     s_findrep_msg = 0;
  108. static FINDREPLACE  s_findrep_struct;
  109. static int     s_findrep_is_find;
  110. #endif
  111. static HWND     s_textArea = NULL;
  112. static HMENU     s_menuBar = NULL;
  113. static UINT     s_menu_id = 0;
  114. static UINT     s_wait_timer = 0; /* Timer for get char from user */
  115. static int     destroying = FALSE; /* calling DestroyWindow() ourselves */
  116. static UINT     s_uMsg = 0;
  117. static WPARAM     s_wParam = 0;
  118. static LPARAM     s_lParam = 0;
  119. static int     s_timed_out = FALSE;
  120. static const LOGFONT s_lfDefault =
  121. {
  122.     -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
  123.     OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  124.     PROOF_QUALITY, FIXED_PITCH | FF_DONTCARE,
  125.     "Fixedsys" /* see _ReadVimIni */
  126. };
  127. /* Initialise the "current height" to -12 (same as s_lfDefault) just
  128.  * in case the user specifies a font in "guifont" with no size before a font
  129.  * with an explicit size has been set. This defaults the size to this value
  130.  * (-12 equates to roughly 9pt).
  131.  */
  132. static int current_font_height = -12;
  133. static struct
  134. {
  135.     UINT    key_sym;
  136.     char_u  vim_code0;
  137.     char_u  vim_code1;
  138. } special_keys[] =
  139. {
  140.     {VK_UP,     'k', 'u'},
  141.     {VK_DOWN,     'k', 'd'},
  142.     {VK_LEFT,     'k', 'l'},
  143.     {VK_RIGHT,     'k', 'r'},
  144.     {VK_F1,     'k', '1'},
  145.     {VK_F2,     'k', '2'},
  146.     {VK_F3,     'k', '3'},
  147.     {VK_F4,     'k', '4'},
  148.     {VK_F5,     'k', '5'},
  149.     {VK_F6,     'k', '6'},
  150.     {VK_F7,     'k', '7'},
  151.     {VK_F8,     'k', '8'},
  152.     {VK_F9,     'k', '9'},
  153.     {VK_F10,     'k', ';'},
  154.     {VK_F11,     'F', '1'},
  155.     {VK_F12,     'F', '2'},
  156.     {VK_F13,     'F', '3'},
  157.     {VK_F14,     'F', '4'},
  158.     {VK_F15,     'F', '5'},
  159.     {VK_F16,     'F', '6'},
  160.     {VK_F17,     'F', '7'},
  161.     {VK_F18,     'F', '8'},
  162.     {VK_F19,     'F', '9'},
  163.     {VK_F20,     'F', 'A'},
  164.     {VK_F21,     'F', 'B'},
  165.     {VK_F22,     'F', 'C'},
  166.     {VK_F23,     'F', 'D'},
  167.     {VK_F24,     'F', 'E'},     /* winuser.h defines up to F24 */
  168.     {VK_HELP,     '%', '1'},
  169.     {VK_BACK,     'k', 'b'},
  170.     {VK_INSERT,     'k', 'I'},
  171.     {VK_DELETE,     'k', 'D'},
  172.     {VK_HOME,     'k', 'h'},
  173.     {VK_END,     '@', '7'},
  174.     {VK_PRIOR,     'k', 'P'},
  175.     {VK_NEXT,     'k', 'N'},
  176.     {VK_PRINT,     '%', '9'},
  177.     {VK_ADD,     'K', '6'},
  178.     {VK_SUBTRACT,   'K', '7'},
  179.     {VK_DIVIDE,     'K', '8'},
  180.     {VK_MULTIPLY,   'K', '9'},
  181.     {VK_SEPARATOR,  'K', 'A'},     /* Keypad Enter */
  182.     /* Keys that we want to be able to use any modifier with: */
  183.     {VK_SPACE,     ' ', NUL},
  184.     {VK_TAB,     TAB, NUL},
  185.     {VK_ESCAPE,     ESC, NUL},
  186.     {NL,     NL, NUL},
  187.     {CR,     CR, NUL},
  188.     /* End of list marker: */
  189.     {0,     0, 0}
  190. };
  191. #define VIM_NAME "vim"
  192. #define VIM_CLASS "Vim"
  193. static int dead_key = 0; /* 0 - no dead key, 1 - dead key pressed */
  194. static OSVERSIONINFO os_version;    /* like it says.  Init in gui_mch_init() */
  195. /* ron: No need to be stingy on Win32. Make it 16K - s/b big enough for
  196.  * everyone!
  197.  * I have had problems with the original 1000 byte, and with 2 or 5 K.  But
  198.  * 16K should be good for all but the biggest.  Anyway, we free the memory
  199.  * right away.
  200.  */
  201. #define DLG_ALLOC_SIZE 16 * 1024
  202. /*
  203.  * stuff for dialogs, menus, tearoffs etc.
  204.  */
  205. static LRESULT APIENTRY dialog_callback(HWND, UINT, WPARAM, LPARAM);
  206. static LRESULT APIENTRY tearoff_callback(HWND, UINT, WPARAM, LPARAM);
  207. static BOOL CenterWindow(HWND hwndChild, HWND hwndParent);
  208. static PWORD
  209. add_dialog_element(
  210. PWORD p,
  211. DWORD lStyle,
  212. WORD x,
  213. WORD y,
  214. WORD w,
  215. WORD h,
  216. WORD Id,
  217. WORD clss,
  218. const char *caption);
  219. static LPWORD lpwAlign(LPWORD);
  220. static int nCopyAnsiToWideChar(LPWORD, LPSTR);
  221. static void gui_mch_tearoff(char_u *title, GuiMenu *menu, int initX, int initY);
  222. static void rebuild_tearoff(GuiMenu *menu);
  223. static void get_dialog_font_metrics(void);
  224. /*
  225.  * The scrollbar stuff can handle only up to 32767 lines.  When the file is
  226.  * longer, scroll_shift is set to the number of shifts to reduce the count.
  227.  */
  228. static int scroll_shift = 0;
  229. /* Intellimouse support */
  230. static int mouse_scroll_lines = 0;
  231. static UINT msh_msgmousewheel = 0;
  232. static int s_usenewlook;     /* emulate W95/NT4 non-bold dialogs */
  233. static WORD s_dlgfntheight;     /* height of the dialog font */
  234. static WORD s_dlgfntwidth;     /* width of the dialog font */
  235. static HBITMAP s_htearbitmap;     /* bitmap used to indicate tearoff */
  236. #ifdef USE_GUI_WIN32_TOOLBAR
  237. static void initialise_toolbar(void);
  238. static int get_toolbar_bitmap(char_u *name);
  239. #endif
  240. #ifdef WIN32_FIND_REPLACE
  241. static void initialise_findrep(char_u *initial_string);
  242. static void find_rep_mode_adjust(char_u * buf);
  243. #endif
  244. #ifdef DEBUG
  245. /*
  246.  * Print out the last Windows error message
  247.  */
  248.     static void
  249. print_windows_error(void)
  250. {
  251.     LPVOID  lpMsgBuf;
  252.     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  253.   NULL, GetLastError(),
  254.   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  255.   (LPTSTR) &lpMsgBuf, 0, NULL);
  256.     TRACE1("Error: %sn", lpMsgBuf);
  257.     LocalFree(lpMsgBuf);
  258. }
  259. #endif /* DEBUG */
  260. /*
  261.  * Return TRUE when running under Windows NT 3.x or Win32s, both of which have
  262.  * less fancy GUI APIs.
  263.  */
  264.     static int
  265. is_winnt_3(void)
  266. {
  267.     return ((os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
  268. && os_version.dwMajorVersion == 3)
  269.     || (os_version.dwPlatformId == VER_PLATFORM_WIN32s));
  270. }
  271. /*
  272.  * Return TRUE when running under Win32s.
  273.  */
  274.     int
  275. gui_is_win32s(void)
  276. {
  277.     return (os_version.dwPlatformId == VER_PLATFORM_WIN32s);
  278. }
  279. /*
  280.  * Figure out how high the menu bar is at the moment.
  281.  */
  282.     static int
  283. gui_w32_get_menu_height(
  284.     int     fix_window)     /* If TRUE, resize window if menu height changed */
  285. {
  286.     static int old_menu_height = -1;
  287.     RECT    rc1, rc2;
  288.     int     num;
  289.     int     menu_height;
  290.     if (gui.menu_is_active)
  291. num = GetMenuItemCount(s_menuBar);
  292.     else
  293. num = 0;
  294.     if (num == 0)
  295. menu_height = 0;
  296.     else
  297.     {
  298. if (is_winnt_3()) /* for NT 3.xx */
  299. {
  300.     RECT r1, r2;
  301.     int frameht = GetSystemMetrics(SM_CYFRAME);
  302.     int capht = GetSystemMetrics(SM_CYCAPTION);
  303.     /* get window rect of s_hwnd
  304. get client rect of s_hwnd
  305. get cap height
  306. subtract from window rect, the sum of client height,
  307. (if not maximized)frame thickness, and caption height.
  308.      */
  309.     GetWindowRect(s_hwnd, &r1);
  310.     GetClientRect(s_hwnd, &r2);
  311.     menu_height = r1.bottom - r1.top - (r2.bottom-r2.top +
  312.    2 * frameht * (!IsZoomed(s_hwnd)) + capht);
  313. }
  314. else /* win95 and variants (NT 4.0, I guess) */
  315. {
  316.     GetMenuItemRect(s_hwnd, s_menuBar, 0, &rc1);
  317.     GetMenuItemRect(s_hwnd, s_menuBar, num - 1, &rc2);
  318.     menu_height = rc2.bottom - rc1.top + 1;
  319. }
  320.     }
  321.     if (fix_window && menu_height != old_menu_height)
  322. gui_set_winsize(FALSE);
  323.     old_menu_height = menu_height;
  324.     return menu_height;
  325. }
  326. /*
  327.  * Cursor blink functions.
  328.  *
  329.  * This is a simple state machine:
  330.  * BLINK_NONE not blinking at all
  331.  * BLINK_OFF blinking, cursor is not shown
  332.  * BLINK_ON blinking, cursor is shown
  333.  */
  334. #define BLINK_NONE  0
  335. #define BLINK_OFF   1
  336. #define BLINK_ON    2
  337. static int blink_state = BLINK_NONE;
  338. static long_u blink_waittime = 700;
  339. static long_u blink_ontime = 400;
  340. static long_u blink_offtime = 250;
  341. static UINT blink_timer = 0;
  342.     void
  343. gui_mch_set_blinking(long wait, long on, long off)
  344. {
  345.     blink_waittime = wait;
  346.     blink_ontime = on;
  347.     blink_offtime = off;
  348. }
  349. /* ARGSUSED */
  350.     static VOID CALLBACK
  351. _OnBlinkTimer(
  352.     HWND hwnd,
  353.     UINT uMsg,
  354.     UINT idEvent,
  355.     DWORD dwTime)
  356. {
  357.     MSG msg;
  358.     /*
  359.     TRACE2("Got timer event, id %d, blink_timer %dn", idEvent, blink_timer);
  360.     */
  361.     KillTimer(NULL, idEvent);
  362.     /* Eat spurious WM_TIMER messages */
  363.     while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
  364. ;
  365.     if (blink_state == BLINK_ON)
  366.     {
  367. gui_undraw_cursor();
  368. blink_state = BLINK_OFF;
  369. blink_timer = SetTimer(NULL, 0, (UINT)blink_offtime,
  370.     (TIMERPROC)_OnBlinkTimer);
  371.     }
  372.     else
  373.     {
  374. gui_update_cursor(TRUE, FALSE);
  375. blink_state = BLINK_ON;
  376. blink_timer = SetTimer(NULL, 0, (UINT)blink_ontime,
  377.     (TIMERPROC)_OnBlinkTimer);
  378.     }
  379. }
  380.     static void
  381. gui_w32_rm_blink_timer(void)
  382. {
  383.     MSG msg;
  384.     if (blink_timer != 0)
  385.     {
  386. KillTimer(NULL, blink_timer);
  387. /* Eat spurious WM_TIMER messages */
  388. while (PeekMessage(&msg, s_hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
  389.     ;
  390. blink_timer = 0;
  391.     }
  392. }
  393. /*
  394.  * Stop the cursor blinking.  Show the cursor if it wasn't shown.
  395.  */
  396.     void
  397. gui_mch_stop_blink(void)
  398. {
  399.     gui_w32_rm_blink_timer();
  400.     if (blink_state == BLINK_OFF)
  401. gui_update_cursor(TRUE, FALSE);
  402.     blink_state = BLINK_NONE;
  403. }
  404. /*
  405.  * Start the cursor blinking.  If it was already blinking, this restarts the
  406.  * waiting time and shows the cursor.
  407.  */
  408.     void
  409. gui_mch_start_blink(void)
  410. {
  411.     gui_w32_rm_blink_timer();
  412.     /* Only switch blinking on if none of the times is zero */
  413.     if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
  414.     {
  415. blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
  416.     (TIMERPROC)_OnBlinkTimer);
  417. blink_state = BLINK_ON;
  418. gui_update_cursor(TRUE, FALSE);
  419.     }
  420. }
  421. /*
  422.  * Call-back routines.
  423.  */
  424.     static VOID CALLBACK
  425. _OnTimer(
  426.     HWND hwnd,
  427.     UINT uMsg,
  428.     UINT idEvent,
  429.     DWORD dwTime)
  430. {
  431.     MSG msg;
  432.     /*
  433.     TRACE2("Got timer event, id %d, s_wait_timer %dn", idEvent, s_wait_timer);
  434.     */
  435.     KillTimer(NULL, idEvent);
  436.     s_timed_out = TRUE;
  437.     /* Eat spurious WM_TIMER messages */
  438.     while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
  439. ;
  440.     if (idEvent == s_wait_timer)
  441. s_wait_timer = 0;
  442. }
  443. /*
  444.  * Get this message when the user clicks on the cross in the top right corner
  445.  * of a Windows95 window.
  446.  */
  447.     static void
  448. _OnClose(
  449.     HWND hwnd)
  450. {
  451. #ifdef USE_BROWSE
  452.     int save_browse = browse;
  453. #endif
  454. #if defined(GUI_DIALOG) || defined(CON_DIALOG)
  455.     int save_confirm = confirm;
  456. #endif
  457.     /* Only exit when there are no changed files */
  458.     exiting = TRUE;
  459. #ifdef USE_BROWSE
  460.     browse = TRUE;
  461. #endif
  462. #if defined(GUI_DIALOG) || defined(CON_DIALOG)
  463.     confirm = TRUE;
  464. #endif
  465.     if (!check_changed_any(FALSE))    /* will give warning for changed buffer */
  466. getout(0);
  467.     exiting = FALSE;
  468. #ifdef USE_BROWSE
  469.     browse = save_browse;
  470. #endif
  471. #if defined(GUI_DIALOG) || defined(CON_DIALOG)
  472.     confirm = save_confirm;
  473. #endif
  474.     setcursor();     /* position cursor */
  475.     out_flush();
  476. }
  477. /*
  478.  * Get a message when the user switches back to vim
  479.  */
  480.     static void
  481. _OnActivateApp(
  482.     HWND hwnd,
  483.     BOOL fActivate,
  484.     DWORD dwThreadId)
  485. {
  486.     /* When activated: Check if any file was modified outside of Vim. */
  487.     if (fActivate)
  488. check_timestamps();
  489. }
  490. /*
  491.  * Get a message when the the window is being destroyed.
  492.  */
  493.     static void
  494. _OnDestroy(
  495.     HWND hwnd)
  496. {
  497.     if (!destroying)
  498. _OnClose(hwnd);
  499. }
  500.     static void
  501. _OnDropFiles(
  502.     HWND hwnd,
  503.     HDROP hDrop)
  504. {
  505.     char    szFile[_MAX_PATH];
  506.     UINT    cFiles = DragQueryFile(hDrop, 0xFFFFFFFF, szFile, _MAX_PATH);
  507.     UINT    i;
  508.     char_u  *fname;
  509.     char_u  **fnames;
  510.     char_u  redo_dirs = FALSE;
  511.     /* TRACE("_OnDropFiles: %d files droppedn", cFiles); */
  512.     /* reset_VIsual(); */
  513.     if (VIsual_active)
  514.     {
  515. end_visual_mode();
  516. VIsual_reselect = FALSE;
  517. update_curbuf(NOT_VALID); /* delete the inversion */
  518.     }
  519.     fnames = (char_u **) alloc(cFiles * sizeof(char_u *));
  520.     for (i = 0; i < cFiles; ++i)
  521.     {
  522. DragQueryFile(hDrop, i, szFile, _MAX_PATH);
  523. /* TRACE("  dropped %2u: '%s'n", i, szFile); */
  524. mch_dirname(IObuff, IOSIZE);
  525. fname = shorten_fname(szFile, IObuff);
  526. if (fname == NULL)
  527.     fname = szFile;
  528. fnames[i] = vim_strsave(fname);
  529.     }
  530.     /*
  531.      * Handle dropping a directory on Vim.
  532.      */
  533.     if (cFiles == 1)
  534.     {
  535. if (mch_isdir(fnames[0]))
  536. {
  537.     if (mch_chdir(fnames[0]) == 0)
  538.     {
  539. vim_free(fnames[0]);
  540. fnames[0] = NULL;
  541. redo_dirs = TRUE;
  542.     }
  543. }
  544.     }
  545.     DragFinish(hDrop);
  546.     if (GetKeyState(VK_SHIFT) & 0x8000)
  547.     {
  548. /* Shift held down, change to first file's directory */
  549. if (vim_chdirfile(fnames[0]) == 0)
  550. {
  551.     redo_dirs = TRUE;
  552. }
  553.     }
  554.     /* Handle the drop, by resetting the :args list */
  555.     handle_drop(cFiles, fnames);
  556.     if (redo_dirs)
  557. shorten_fnames();
  558.     /* Update the screen display */
  559.     update_screen(NOT_VALID);
  560.     setcursor();
  561.     out_flush();
  562. }
  563.     static void
  564. _OnDeadChar(
  565.     HWND hwnd,
  566.     UINT ch,
  567.     int cRepeat)
  568. {
  569.     dead_key = 1;
  570. }
  571.     static void
  572. _OnChar(
  573.     HWND hwnd,
  574.     UINT ch,
  575.     int cRepeat)
  576. {
  577.     char_u string[1];
  578.     /* TRACE("OnChar(%d, %c)n", ch, ch); */
  579.     string[0] = ch;
  580.     if (string[0] == Ctrl('C') && !mapped_ctrl_c)
  581.     {
  582. trash_input_buf();
  583. got_int = TRUE;
  584.     }
  585.     add_to_input_buf(string, 1);
  586. }
  587.     static void
  588. _OnSysChar(
  589.     HWND hwnd,
  590.     UINT ch,
  591.     int cRepeat)
  592. {
  593.     char_u string[6]; /* Enough for maximum key sequence - see below */
  594.     int len;
  595.     int modifiers;
  596.     /* TRACE("OnSysChar(%d, %c)n", ch, ch); */
  597.     /* OK, we have a character key (given by ch) which was entered with the
  598.      * ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note
  599.      * that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless
  600.      * CAPSLOCK is pressed) at this point.
  601.      */
  602.     modifiers = MOD_MASK_ALT;
  603.     if (GetKeyState(VK_SHIFT) & 0x8000)
  604. modifiers |= MOD_MASK_SHIFT;
  605.     if (GetKeyState(VK_CONTROL) & 0x8000)
  606. modifiers |= MOD_MASK_CTRL;
  607.     ch = simplify_key(ch, &modifiers);
  608.     /* remove the SHIFT modifier for keys where it's already included, e.g.,
  609.      * '(' and '*' */
  610.     if (ch < 0x100 && (!isalpha(ch)) && isprint(ch))
  611. modifiers &= ~MOD_MASK_SHIFT;
  612.     /* Interpret the ALT key as making the key META */
  613.     if (modifiers & MOD_MASK_ALT)
  614.     {
  615. ch |= 0x80;
  616. modifiers &= ~MOD_MASK_ALT;
  617.     }
  618.     len = 0;
  619.     if (modifiers)
  620.     {
  621. string[len++] = CSI;
  622. string[len++] = KS_MODIFIER;
  623. string[len++] = modifiers;
  624.     }
  625.     if (IS_SPECIAL(ch))
  626.     {
  627. string[len++] = CSI;
  628. string[len++] = K_SECOND(ch);
  629. string[len++] = K_THIRD(ch);
  630.     }
  631.     else
  632. string[len++] = ch;
  633.     add_to_input_buf(string, len);
  634. }
  635.     static void
  636. _OnMouseEvent(
  637.     int button,
  638.     int x,
  639.     int y,
  640.     int repeated_click,
  641.     UINT keyFlags)
  642. {
  643.     int vim_modifiers = 0x0;
  644.     if (keyFlags & MK_SHIFT)
  645. vim_modifiers |= MOUSE_SHIFT;
  646.     if (keyFlags & MK_CONTROL)
  647. vim_modifiers |= MOUSE_CTRL;
  648.     if (GetKeyState(VK_MENU) & 0x8000)
  649. vim_modifiers |= MOUSE_ALT;
  650.     gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
  651. }
  652.     static void
  653. _OnMouseButtonDown(
  654.     HWND hwnd,
  655.     BOOL fDoubleClick,
  656.     int x,
  657.     int y,
  658.     UINT keyFlags)
  659. {
  660.     static LONG s_prevTime = 0;
  661.     LONG    currentTime = GetMessageTime();
  662.     int     button = -1;
  663.     int     repeated_click;
  664.     if (s_uMsg == WM_LBUTTONDOWN || s_uMsg == WM_LBUTTONDBLCLK)
  665. button = MOUSE_LEFT;
  666.     else if (s_uMsg == WM_MBUTTONDOWN || s_uMsg == WM_MBUTTONDBLCLK)
  667. button = MOUSE_MIDDLE;
  668.     else if (s_uMsg == WM_RBUTTONDOWN || s_uMsg == WM_RBUTTONDBLCLK)
  669. button = MOUSE_RIGHT;
  670.     else if (s_uMsg == WM_CAPTURECHANGED)
  671.     {
  672. /* on W95/NT4, somehow you get in here with an odd Msg
  673.  * if you press one button while holding down the other..*/
  674. if (s_button_pending == MOUSE_LEFT)
  675.     button = MOUSE_RIGHT;
  676. else
  677.     button = MOUSE_LEFT;
  678.     }
  679.     if (button >= 0)
  680.     {
  681. repeated_click = ((int)(currentTime - s_prevTime) < p_mouset);
  682. /*
  683.  * Holding down the left and right buttons simulates pushing the middle
  684.  * button.
  685.  */
  686. if (repeated_click &&
  687. ((button == MOUSE_LEFT && s_button_pending == MOUSE_RIGHT) ||
  688.  (button == MOUSE_RIGHT && s_button_pending == MOUSE_LEFT)))
  689. {
  690.     /*
  691.      * Hmm, gui.c will ignore more than one button down at a time, so
  692.      * pretend we let go of it first.
  693.      */
  694.     gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, 0x0);
  695.     button = MOUSE_MIDDLE;
  696.     repeated_click = FALSE;
  697.     s_button_pending = -1;
  698.     _OnMouseEvent(button, x, y, repeated_click, keyFlags);
  699. }
  700. else if ((repeated_click)
  701. || (mouse_model_popup() && (button == MOUSE_RIGHT)))
  702. {
  703.     if (s_button_pending > -1)
  704.     {
  705.     _OnMouseEvent(s_button_pending, x, y, FALSE, keyFlags);
  706.     s_button_pending = -1;
  707.     }
  708.     /* TRACE("Button down at x %d, y %dn", x, y); */
  709.     _OnMouseEvent(button, x, y, repeated_click, keyFlags);
  710. }
  711. else
  712. {
  713.     /*
  714.      * If this is the first press (i.e. not a multiple click) don't
  715.      * action immediately, but store and wait for:
  716.      * i) button-up
  717.      * ii) mouse move
  718.      * iii) another button press
  719.      * before using it.
  720.      * This enables us to make left+right simulate middle button,
  721.      * without left or right being actioned first.  The side-effect is
  722.      * that if you click and hold the mouse without dragging, the
  723.      * cursor doesn't move until you release the button. In practice
  724.      * this is hardly a problem.
  725.      */
  726.     s_button_pending = button;
  727.     s_x_pending = x;
  728.     s_y_pending = y;
  729.     s_kFlags_pending = keyFlags;
  730. }
  731. s_prevTime = currentTime;
  732.     }
  733. }
  734.     static void
  735. _OnMouseMoveOrRelease(
  736.     HWND hwnd,
  737.     int x,
  738.     int y,
  739.     UINT keyFlags)
  740. {
  741.     int button;
  742.     if (s_button_pending > -1)
  743.     {
  744. /* Delayed action for mouse down event */
  745. _OnMouseEvent(s_button_pending, s_x_pending,
  746. s_y_pending, FALSE, s_kFlags_pending);
  747. s_button_pending = -1;
  748.     }
  749.     if (s_uMsg == WM_MOUSEMOVE)
  750.     {
  751. /*
  752.  * It's only a MOUSE_DRAG if one or more mouse buttons are being held
  753.  * down.
  754.  */
  755. if (!(keyFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)))
  756. {
  757.     gui_mouse_moved(y);
  758.     return;
  759. }
  760. /*
  761.  * While button is down, keep grabbing mouse move events when
  762.  * the mouse goes outside the window
  763.  */
  764. SetCapture(s_textArea);
  765. button = MOUSE_DRAG;
  766. /* TRACE("  move at x %d, y %dn", x, y); */
  767.     }
  768.     else
  769.     {
  770. ReleaseCapture();
  771. button = MOUSE_RELEASE;
  772. /* TRACE("  up at x %d, y %dn", x, y); */
  773.     }
  774.     _OnMouseEvent(button, x, y, FALSE, keyFlags);
  775. }
  776.     static void
  777. _OnPaint(
  778.     HWND hwnd)
  779. {
  780.     if (!IsMinimized(hwnd))
  781.     {
  782. PAINTSTRUCT ps;
  783. HDC hdc;
  784. out_flush();     /* make sure all output has been processed */
  785. hdc = BeginPaint(hwnd, &ps);
  786. #ifdef MULTI_BYTE
  787. /* prevent multi-byte characters from misprinting on an invalid
  788.  * rectangle */
  789. if (is_dbcs)
  790. {
  791.     RECT rect;
  792.     GetClientRect(hwnd, &rect);
  793.     ps.rcPaint.left = rect.left;
  794.     ps.rcPaint.right = rect.right;
  795. }
  796. #endif
  797. if (!IsRectEmpty(&ps.rcPaint))
  798.     gui_redraw(ps.rcPaint.left, ps.rcPaint.top,
  799.     ps.rcPaint.right - ps.rcPaint.left + 1,
  800.     ps.rcPaint.bottom - ps.rcPaint.top + 1);
  801. EndPaint(hwnd, &ps);
  802.     }
  803. }
  804.     static void
  805. _OnSize(
  806.     HWND hwnd,
  807.     UINT state,
  808.     int cx,
  809.     int cy)
  810. {
  811.     if (!IsMinimized(hwnd))
  812.     {
  813. gui_resize_window(cx, cy);
  814. /* Menu bar may wrap differently now */
  815. gui_w32_get_menu_height(TRUE);
  816.     }
  817. }
  818.     static void
  819. _OnSetFocus(
  820.     HWND hwnd,
  821.     HWND hwndOldFocus)
  822. {
  823.     gui_focus_change(TRUE);
  824. }
  825.     static void
  826. _OnKillFocus(
  827.     HWND hwnd,
  828.     HWND hwndNewFocus)
  829. {
  830.     gui_focus_change(FALSE);
  831. }
  832. /*
  833.  * Find the GuiMenu with the given id
  834.  */
  835.     static GuiMenu *
  836. gui_w32_find_menu(
  837.     GuiMenu *pMenu,
  838.     int id)
  839. {
  840.     GuiMenu *pChildMenu;
  841.     while (pMenu)
  842.     {
  843. if (pMenu->id == (UINT)id) /* && pMenu->submenu_id == NULL) */
  844.     break;
  845. if (pMenu->children != NULL)
  846. {
  847.     pChildMenu = gui_w32_find_menu(pMenu->children, id);
  848.     if (pChildMenu)
  849.     {
  850. pMenu = pChildMenu;
  851. break;
  852.     }
  853. }
  854. pMenu = pMenu->next;
  855.     }
  856.     return pMenu;
  857. }
  858.     static void
  859. _OnMenu(
  860.     HWND hwnd,
  861.     int id,
  862.     HWND hwndCtl,
  863.     UINT codeNotify)
  864. {
  865.     GuiMenu *pMenu;
  866.     pMenu = gui_w32_find_menu(gui.root_menu, id);
  867.     if (pMenu)
  868. gui_menu_cb(pMenu);
  869. }
  870. /*
  871.  * Find the scrollbar with the given hwnd.
  872.  */
  873.     static GuiScrollbar *
  874. gui_w32_find_scrollbar(HWND hwnd)
  875. {
  876.     WIN *wp;
  877.     if (gui.bottom_sbar.id == hwnd)
  878. return &gui.bottom_sbar;
  879.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  880.     {
  881. if (wp->w_scrollbars[SBAR_LEFT].id == hwnd)
  882.     return &wp->w_scrollbars[SBAR_LEFT];
  883. if (wp->w_scrollbars[SBAR_RIGHT].id == hwnd)
  884.     return &wp->w_scrollbars[SBAR_RIGHT];
  885.     }
  886.     return NULL;
  887. }
  888.     static int
  889. _OnScroll(
  890.     HWND hwnd,
  891.     HWND hwndCtl,
  892.     UINT code,
  893.     int pos)
  894. {
  895.     GuiScrollbar *sb, *sb_info;
  896.     int val;
  897.     int dragging = FALSE;
  898.     SCROLLINFO si;
  899.     WIN *wp;
  900.     sb = gui_w32_find_scrollbar(hwndCtl);
  901.     if (sb == NULL)
  902. return 0;
  903.     if (sb->wp != NULL)     /* Left or right scrollbar */
  904.     {
  905. /*
  906.  * Careful: need to get scrollbar info out of first (left) scrollbar
  907.  * for window, but keep real scrollbar too because we must pass it to
  908.  * gui_drag_scrollbar().
  909.  */
  910. sb_info = &sb->wp->w_scrollbars[0];
  911.     }
  912.     else     /* Bottom scrollbar */
  913. sb_info = sb;
  914.     val = sb_info->value;
  915.     switch (code)
  916.     {
  917. case SB_THUMBTRACK:
  918.     /* TRACE("SB_THUMBTRACK, %dn", pos); */
  919.     val = pos;
  920.     dragging = TRUE;
  921.     if (scroll_shift > 0)
  922. val <<= scroll_shift;
  923.     break;
  924. case SB_LINEDOWN:
  925.     /* TRACE("SB_LINEDOWNn"); */
  926.     val++;
  927.     break;
  928. case SB_LINEUP:
  929.     /* TRACE("SB_LINEUPn"); */
  930.     val--;
  931.     break;
  932. case SB_PAGEDOWN:
  933.     /* TRACE("SB_PAGEDOWNn"); */
  934.     val += (sb_info->size > 2 ? sb_info->size - 2 : 1);
  935.     break;
  936. case SB_PAGEUP:
  937.     /* TRACE("SB_PAGEUPn"); */
  938.     val -= (sb_info->size > 2 ? sb_info->size - 2 : 1);
  939.     break;
  940. case SB_TOP:
  941.     /* TRACE("SB_TOPn"); */
  942.     val = 0;
  943.     break;
  944. case SB_BOTTOM:
  945.     /* TRACE("SB_BOTTOMn"); */
  946.     val = sb_info->max;
  947.     break;
  948. case SB_ENDSCROLL:
  949.     /*
  950.      * "pos" only gives us 16-bit data.  In case of large file, use
  951.      * GetScrollPos() which returns 32-bit.  Unfortunately it is not
  952.      * valid while the scrollbar is being dragged.
  953.      */
  954.     /* TRACE("SB_ENDSCROLLn"); */
  955.     val = GetScrollPos(hwndCtl, SB_CTL);
  956.     if (scroll_shift > 0)
  957. val <<= scroll_shift;
  958.     break;
  959. default:
  960.     /* TRACE("Unknown scrollbar event %dn", code); */
  961.     return 0;
  962.     }
  963.     si.cbSize = sizeof(si);
  964.     si.fMask = SIF_POS;
  965.     if (scroll_shift > 0)
  966. si.nPos = val >> scroll_shift;
  967.     else
  968. si.nPos = val;
  969.     SetScrollInfo(hwndCtl, SB_CTL, &si, TRUE);
  970.     /*
  971.      * When moving a vertical scrollbar, move the other vertical scrollbar too.
  972.      */
  973.     if (sb->wp != NULL)
  974.     {
  975. if (sb == &sb->wp->w_scrollbars[SBAR_LEFT])
  976.     SetScrollInfo(sb->wp->w_scrollbars[SBAR_RIGHT].id,
  977.    SB_CTL, &si, TRUE);
  978. else
  979.     SetScrollInfo(sb->wp->w_scrollbars[SBAR_LEFT].id,
  980.    SB_CTL, &si, TRUE);
  981.     }
  982.     /*
  983.      * Scrollbars seem to grab focus and vim doesn't read the input queue until
  984.      * you stop dragging the scrollbar.  We get here each time the scrollbar is
  985.      * dragged another pixel, but as far as the rest of vim goes, it thinks
  986.      * we're just hanging in the call to DispatchMessage() in
  987.      * process_message().  The DispatchMessage() call that hangs was passed a
  988.      * mouse button click event in the scrollbar window. -- webb.
  989.      *
  990.      * Solution: Do the scrolling right here.  But only when allowed.
  991.      * Ignore the scrollbars while executing an external command or when there
  992.      * are still characters to be processed.
  993.      */
  994.     if (dont_scroll || !termcap_active || !vim_is_input_buf_empty())
  995. return 0;
  996.     if (dragging)
  997.     {
  998. if (sb->wp == NULL)
  999.     gui.dragged_sb = SBAR_BOTTOM;
  1000. else if (sb == &sb->wp->w_scrollbars[SBAR_LEFT])
  1001.     gui.dragged_sb = SBAR_LEFT;
  1002. else
  1003.     gui.dragged_sb = SBAR_RIGHT;
  1004. gui.dragged_wp = sb->wp;
  1005.     }
  1006.     else
  1007. gui.dragged_sb = SBAR_NONE;
  1008.     /* Vertical sbar info is kept in the first sbar (the left one) */
  1009.     if (sb->wp != NULL)
  1010. sb = &sb->wp->w_scrollbars[0];
  1011.     /*
  1012.      * Check validity of value
  1013.      */
  1014.     if (val < 0)
  1015. val = 0;
  1016.     if (val > sb->max - sb->size + 1)
  1017. val = sb->max - sb->size + 1;
  1018.     sb->value = val;
  1019. #ifdef RIGHTLEFT
  1020.     if (sb->wp == NULL && curwin->w_p_rl)
  1021.     {
  1022. val = sb->max + 1 - sb->size - val;
  1023. if (val < 0)
  1024.     val = 0;
  1025.     }
  1026. #endif
  1027.     scrollbar_value = val;
  1028.     if (sb->wp != NULL) /* vertical scrollbar */
  1029.     {
  1030. current_scrollbar = 0;
  1031. for (wp = firstwin; wp != sb->wp && wp != NULL; wp = wp->w_next)
  1032.     current_scrollbar++;
  1033. if (wp == NULL)
  1034.     return 0;
  1035. if (State & NORMAL)
  1036. {
  1037.     gui_do_scroll();
  1038.     setcursor();
  1039. }
  1040. else if (State & INSERT)
  1041. {
  1042.     ins_scroll();
  1043.     setcursor();
  1044. }
  1045. else if (State & CMDLINE)
  1046. {
  1047.     if (!msg_scrolled)
  1048.     {
  1049. gui_do_scroll();
  1050. redrawcmdline();
  1051.     }
  1052. }
  1053.     }
  1054.     else
  1055.     {
  1056. colnr_t     old_leftcol = curwin->w_leftcol;
  1057. if (State & NORMAL)
  1058.     gui_do_horiz_scroll();
  1059. else if (State & INSERT)
  1060.     ins_horscroll();
  1061. else if (State & CMDLINE)
  1062. {
  1063.     if (!msg_scrolled)
  1064.     {
  1065. gui_do_horiz_scroll();
  1066. redrawcmdline();
  1067.     }
  1068. }
  1069. if (old_leftcol != curwin->w_leftcol)
  1070. {
  1071.     updateWindow(curwin);   /* update window, status line and cmdline */
  1072.     setcursor();
  1073. }
  1074.     }
  1075.     out_flush();
  1076.     return 0;
  1077. }
  1078. /*
  1079.  * Setup for the Intellimouse
  1080.  */
  1081.     static void
  1082. init_mouse_wheel(void)
  1083. {
  1084. #ifndef SPI_GETWHEELSCROLLLINES
  1085. # define SPI_GETWHEELSCROLLLINES    104
  1086. #endif
  1087. #define VMOUSEZ_CLASSNAME  "MouseZ" /* hidden wheel window class */
  1088. #define VMOUSEZ_TITLE      "Magellan MSWHEEL" /* hidden wheel window title */
  1089. #define VMSH_MOUSEWHEEL    "MSWHEEL_ROLLMSG"
  1090. #define VMSH_SCROLL_LINES  "MSH_SCROLL_LINES_MSG"
  1091.     HWND hdl_mswheel;
  1092.     UINT msh_msgscrolllines;
  1093.     msh_msgmousewheel = 0;
  1094.     mouse_scroll_lines = 3; /* reasonable default */
  1095.     if (os_version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
  1096.     || (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
  1097. && os_version.dwMajorVersion < 4))
  1098.     { /*
  1099.  * If Win95 or NT 3.51,
  1100.  * try to find the hidden point32 window.
  1101.  */
  1102. hdl_mswheel = FindWindow(VMOUSEZ_CLASSNAME, VMOUSEZ_TITLE);
  1103. if (hdl_mswheel)
  1104. {
  1105.     msh_msgscrolllines = RegisterWindowMessage(VMSH_SCROLL_LINES);
  1106.     if (msh_msgscrolllines)
  1107.     {
  1108. mouse_scroll_lines = SendMessage(hdl_mswheel,
  1109. msh_msgscrolllines, 0, 0);
  1110. msh_msgmousewheel  = RegisterWindowMessage(VMSH_MOUSEWHEEL);
  1111.     }
  1112. }
  1113.     }
  1114.     else if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
  1115.     && os_version.dwMajorVersion >= 4)
  1116.     {
  1117. /* if NT 4.0 (or Win98) get scroll lines directly from system */
  1118. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
  1119. &mouse_scroll_lines, 0);
  1120.     }
  1121. }
  1122. /* Intellimouse wheel handler */
  1123.     static void
  1124. _OnMouseWheel(
  1125.     HWND hwnd,
  1126.     short zDelta)
  1127. {
  1128. /* Treat a mouse wheel event as if it were a scroll request */
  1129.     int i;
  1130.     int size;
  1131.     HWND hwndCtl;
  1132.     if (curwin->w_scrollbars[SBAR_RIGHT].id != 0)
  1133.     {
  1134. hwndCtl = curwin->w_scrollbars[SBAR_RIGHT].id;
  1135. size = curwin->w_scrollbars[SBAR_RIGHT].size;
  1136.     }
  1137.     else if (curwin->w_scrollbars[SBAR_LEFT].id != 0)
  1138.     {
  1139. hwndCtl = curwin->w_scrollbars[SBAR_LEFT].id;
  1140. size = curwin->w_scrollbars[SBAR_LEFT].size;
  1141.     }
  1142.     else
  1143. return;
  1144.     size = curwin->w_height;
  1145.     if (mouse_scroll_lines == 0)
  1146. init_mouse_wheel();
  1147.     if (mouse_scroll_lines > 0
  1148.     && mouse_scroll_lines < (size > 2 ? size - 2 : 1))
  1149.     {
  1150. for (i = mouse_scroll_lines; i > 0; --i)
  1151.     _OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_LINEUP : SB_LINEDOWN, 0);
  1152.     }
  1153.     else
  1154. _OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_PAGEUP : SB_PAGEDOWN, 0);
  1155. }
  1156. /*
  1157.  * Get current x mouse coordinate in text window.
  1158.  * Return -1 when unknown.
  1159.  */
  1160.     int
  1161. gui_mch_get_mouse_x(void)
  1162. {
  1163.     RECT rct;
  1164.     POINT mp;
  1165.     if (GetWindowRect(s_textArea, &rct))
  1166.     {
  1167. if (GetCursorPos((LPPOINT)&mp))
  1168.     return (int)(mp.x - rct.left);
  1169.     }
  1170.     return -1;
  1171. }
  1172. /*
  1173.  * Get current y mouse coordinate in text window.
  1174.  * Return -1 when unknown.
  1175.  */
  1176.     int
  1177. gui_mch_get_mouse_y(void)
  1178. {
  1179.     RECT rct;
  1180.     POINT mp;
  1181.     if (GetWindowRect(s_textArea, &rct))
  1182.     {
  1183. if (GetCursorPos((LPPOINT)&mp))
  1184.     return (int)(mp.y - rct.top);
  1185.     }
  1186.     return -1;
  1187. }
  1188. /*
  1189.  * Move mouse pointer to character at (x, y).
  1190.  */
  1191.     void
  1192. gui_mch_setmouse(int x, int y)
  1193. {
  1194.     RECT rct;
  1195.     if (GetWindowRect(s_textArea, &rct))
  1196. (void)SetCursorPos(x + gui.border_offset + rct.left,
  1197.    y + gui.border_offset + rct.top);
  1198. }
  1199.     static void
  1200. gui_w32_get_valid_dimensions(
  1201.     int w,
  1202.     int h,
  1203.     int *valid_w,
  1204.     int *valid_h)
  1205. {
  1206.     int     base_width, base_height;
  1207.     base_width = gui_get_base_width()
  1208. + GetSystemMetrics(SM_CXSIZEFRAME) * 2;
  1209.     base_height = gui_get_base_height()
  1210. + GetSystemMetrics(SM_CYSIZEFRAME) * 2
  1211. + GetSystemMetrics(SM_CYCAPTION)
  1212. + gui_w32_get_menu_height(FALSE);
  1213.     *valid_w = base_width +
  1214.     ((w - base_width) / gui.char_width) * gui.char_width;
  1215.     *valid_h = base_height +
  1216.     ((h - base_height) / gui.char_height) * gui.char_height;
  1217. }
  1218. /*
  1219.  * Even though we have _DuringSizing() which makes the rubber band a valid
  1220.  * size, we need this for when the user maximises the window.
  1221.  * TODO: Doesn't seem to adjust the width though for some reason.
  1222.  */
  1223.     static BOOL
  1224. _OnWindowPosChanging(
  1225.     HWND hwnd,
  1226.     LPWINDOWPOS lpwpos)
  1227. {
  1228.     if (!(lpwpos->flags & SWP_NOSIZE))
  1229.     {
  1230. gui_w32_get_valid_dimensions(lpwpos->cx, lpwpos->cy,
  1231.      &lpwpos->cx, &lpwpos->cy);
  1232.     }
  1233.     return 0;
  1234. }
  1235.     static int
  1236. _DuringSizing(
  1237.     HWND hwnd,
  1238.     UINT fwSide,
  1239.     LPRECT lprc)
  1240. {
  1241.     int     w, h;
  1242.     int     valid_w, valid_h;
  1243.     int     w_offset, h_offset;
  1244.     w = lprc->right - lprc->left;
  1245.     h = lprc->bottom - lprc->top;
  1246.     gui_w32_get_valid_dimensions(w, h, &valid_w, &valid_h);
  1247.     w_offset = w - valid_w;
  1248.     h_offset = h - valid_h;
  1249.     if (fwSide == WMSZ_LEFT || fwSide == WMSZ_TOPLEFT
  1250.     || fwSide == WMSZ_BOTTOMLEFT)
  1251. lprc->left += w_offset;
  1252.     else if (fwSide == WMSZ_RIGHT || fwSide == WMSZ_TOPRIGHT
  1253.     || fwSide == WMSZ_BOTTOMRIGHT)
  1254. lprc->right -= w_offset;
  1255.     if (fwSide == WMSZ_TOP || fwSide == WMSZ_TOPLEFT
  1256.     || fwSide == WMSZ_TOPRIGHT)
  1257. lprc->top += h_offset;
  1258.     else if (fwSide == WMSZ_BOTTOM || fwSide == WMSZ_BOTTOMLEFT
  1259.     || fwSide == WMSZ_BOTTOMRIGHT)
  1260. lprc->bottom -= h_offset;
  1261.     return TRUE;
  1262. }
  1263. /*
  1264.  * Erase parts of the window that are not redrawn.
  1265.  * Draw the rectangle just under the left and/or right scrollbars.
  1266.  */
  1267.     static void
  1268. _OnEraseBG(HWND hwnd)
  1269. {
  1270.     HDC hdc =  GetDC(hwnd);
  1271.     RECT rect, drect;
  1272.     WIN *wp;
  1273.     GetClientRect(hwnd, &rect);
  1274.     /* Draw blank rectangles for hidden scrollbars */
  1275.     for (wp = firstwin; wp; wp = wp->w_next)
  1276.     {
  1277. if (wp->w_height == 0)
  1278. {
  1279.     drect.top = rect.bottom - gui.char_height * (Rows - wp->w_winpos);
  1280.     if (gui.which_scrollbars[SBAR_BOTTOM])
  1281. drect.top -= gui.scrollbar_height;
  1282.     drect.bottom = drect.top + gui.char_height;
  1283.     if (gui.which_scrollbars[SBAR_LEFT])
  1284.     {
  1285. drect.left = 0;
  1286. drect.right = gui.scrollbar_width;
  1287. FillRect(hdc, &drect, GetSysColorBrush(COLOR_BTNFACE));
  1288.     }
  1289.     if (gui.which_scrollbars[SBAR_RIGHT])
  1290.     {
  1291. drect.left = rect.right - gui.scrollbar_width;
  1292. drect.right = rect.right;
  1293. FillRect(hdc, &drect, GetSysColorBrush(COLOR_BTNFACE));
  1294.     }
  1295. }
  1296.     }
  1297.     /* draw the rectangle below vertical scrollbars */
  1298.     /* top of the rectangle is just below the last window */
  1299.     drect.top = rect.bottom - gui.char_height
  1300.    * (Rows - (lastwin->w_winpos + lastwin->w_height));
  1301.     drect.top += lastwin->w_status_height * gui.char_height;
  1302.     if (gui.which_scrollbars[SBAR_BOTTOM])
  1303. drect.top -= gui.scrollbar_height;
  1304.     drect.bottom = rect.bottom;
  1305.     if (gui.which_scrollbars[SBAR_LEFT])
  1306.     {
  1307. drect.left = 0;
  1308. drect.right = gui.scrollbar_width;
  1309. FillRect(hdc, &drect, GetSysColorBrush(COLOR_BTNFACE));
  1310.     }
  1311.     if (gui.which_scrollbars[SBAR_RIGHT])
  1312.     {
  1313. drect.left = rect.right - gui.scrollbar_width;
  1314. drect.right = rect.right;
  1315. FillRect(hdc, &drect, GetSysColorBrush(COLOR_BTNFACE));
  1316.     }
  1317.     ReleaseDC(hwnd, hdc);
  1318. }
  1319.     static BOOL
  1320. _OnCreate (HWND hwnd, LPCREATESTRUCT lpcs)
  1321. {
  1322. #ifdef MULTI_BYTE
  1323.     /* get system fixed font size*/
  1324.     static const char ach[] = {'W', 'f', 'g', 'M'};
  1325.     HDC     hdc = GetWindowDC(hwnd);
  1326.     HFONT   hfntOld = SelectFont(hdc, GetStockObject(SYSTEM_FIXED_FONT));
  1327.     SIZE    siz;
  1328.     GetTextExtentPoint(hdc, ach, sizeof(ach), &siz);
  1329.     sysfixed_width = siz.cx / sizeof(ach);
  1330.     /*
  1331.      * Make characters one pixel higher, so that italic and bold fonts don't
  1332.      * draw off the bottom of their character space.  Also means that we can
  1333.      * underline an underscore for normal text.
  1334.      */
  1335.     sysfixed_height = siz.cy + 1;
  1336.     /* TRACE("GetFontSize: h %d, w %dn", gui.char_height, gui.char_width); */
  1337.     SelectFont(hdc, hfntOld);
  1338.     ReleaseDC(hwnd, hdc);
  1339. #endif
  1340.     return 0;
  1341. }
  1342. #ifdef WIN32_FIND_REPLACE
  1343. /*
  1344.  * Handle a Find/Replace window message.
  1345.  */
  1346.     static void
  1347. _OnFindRepl(void)
  1348. {
  1349.     char_u cmd[600]; //XXX kludge
  1350.     /* Add a char before the command if needed */
  1351.     if (State & INSERT)
  1352. cmd[0] = Ctrl('O');
  1353.     else if ((State | NORMAL) == 0 && State != CONFIRM)
  1354. cmd[0] = ESC;
  1355.     else
  1356. cmd[0] = NUL;
  1357.     cmd[1] = NUL;
  1358.     if (s_findrep_struct.Flags & FR_DIALOGTERM)
  1359.     {
  1360. if (State == CONFIRM)
  1361. {
  1362.     add_to_input_buf("q", 1);
  1363. }
  1364. return;
  1365.     }
  1366.     if (s_findrep_struct.Flags & FR_FINDNEXT)
  1367.     {
  1368. if (State == CONFIRM)
  1369. {
  1370.     STRCAT(cmd, "n");
  1371. }
  1372. else
  1373. {
  1374.     if (s_findrep_struct.Flags & FR_DOWN)
  1375. STRCAT(cmd, "/");
  1376.     else
  1377. STRCAT(cmd, "?");
  1378.     if (s_findrep_struct.Flags & FR_WHOLEWORD)
  1379. STRCAT(cmd, "\<");
  1380.     STRCAT(cmd, s_findrep_struct.lpstrFindWhat);
  1381.     if (s_findrep_struct.Flags & FR_WHOLEWORD)
  1382. STRCAT(cmd, "\>");
  1383.     STRCAT(cmd, "r");
  1384. }
  1385. /*
  1386.  * Give main window the focus back: this is so
  1387.  * the cursor isn't hollow.
  1388.  */
  1389. (void)SetFocus(s_hwnd);
  1390.     }
  1391.     else if (s_findrep_struct.Flags & FR_REPLACE)
  1392.     {
  1393. if (State == CONFIRM)
  1394. {
  1395.     STRCAT(cmd, "y");
  1396. }
  1397. else
  1398. {
  1399.     STRCAT(cmd, ":%sno/");
  1400.     STRCAT(cmd, s_findrep_struct.lpstrFindWhat);
  1401.     STRCAT(cmd, "/");
  1402.     STRCAT(cmd, s_findrep_struct.lpstrReplaceWith);
  1403.     STRCAT(cmd, "/gcr");
  1404. }
  1405. /*
  1406.  * Give main window the focus back: this is to allow
  1407.  * handling of the confirmation y/n/a/q stuff.
  1408.  */
  1409. (void)SetFocus(s_hwnd);
  1410.     }
  1411.     else if (s_findrep_struct.Flags & FR_REPLACEALL)
  1412.     {
  1413. if (State == CONFIRM)
  1414. {
  1415.     STRCAT(cmd, "a");
  1416. }
  1417. else
  1418. {
  1419.     STRCAT(cmd, ":%sno/");
  1420.     STRCAT(cmd, s_findrep_struct.lpstrFindWhat);
  1421.     STRCAT(cmd, "/");
  1422.     STRCAT(cmd, s_findrep_struct.lpstrReplaceWith);
  1423.     STRCAT(cmd, "/gr");
  1424. }
  1425.     }
  1426.     if (*cmd)
  1427. add_to_input_buf(cmd, STRLEN(cmd));
  1428. }
  1429. #endif
  1430.     static void
  1431. HandleMouseHide(UINT uMsg, LPARAM lParam)
  1432. {
  1433.     static LPARAM last_lParam = 0L;
  1434.     /* We sometimes get a mousemove when the mouse didn't move... */
  1435.     if (uMsg == WM_MOUSEMOVE)
  1436.     {
  1437. if (lParam == last_lParam)
  1438.     return;
  1439. last_lParam = lParam;
  1440.     }
  1441.     /* Handle specially, to centralise coding. We need to be sure we catch all
  1442.      * possible events which should cause us to restore the cursor (as it is a
  1443.      * shared resource, we take full responsibility for it).
  1444.      */
  1445.     switch (uMsg)
  1446.     {
  1447.     // Omit these, because a shift or control key should not hide the pointer
  1448.     // case WM_KEYDOWN:
  1449.     // case WM_SYSKEYDOWN:
  1450.     case WM_KEYUP:
  1451.     case WM_SYSKEYUP:
  1452.     case WM_CHAR:
  1453.     case WM_SYSCHAR:
  1454. /*
  1455.  * blank out the pointer if necessary
  1456.  */
  1457. if (p_mh)
  1458.     gui_mch_mousehide(TRUE);
  1459. break;
  1460.     case WM_MOUSEMOVE:
  1461.     case WM_LBUTTONDOWN:
  1462.     case WM_LBUTTONUP:
  1463.     case WM_MBUTTONDOWN:
  1464.     case WM_MBUTTONUP:
  1465.     case WM_RBUTTONDOWN:
  1466.     case WM_RBUTTONUP:
  1467.     case WM_NCMOUSEMOVE:
  1468.     case WM_NCLBUTTONDOWN:
  1469.     case WM_NCLBUTTONUP:
  1470.     case WM_NCMBUTTONDOWN:
  1471.     case WM_NCMBUTTONUP:
  1472.     case WM_NCRBUTTONDOWN:
  1473.     case WM_NCRBUTTONUP:
  1474.     case WM_KILLFOCUS:
  1475. /*
  1476.  * if the pointer is currently hidden, then we should show it.
  1477.  */
  1478. gui_mch_mousehide(FALSE);
  1479. break;
  1480.     }
  1481. }
  1482.     static LRESULT CALLBACK
  1483. _WndProc(
  1484.     HWND hwnd,
  1485.     UINT uMsg,
  1486.     WPARAM wParam,
  1487.     LPARAM lParam)
  1488. {
  1489.     /*
  1490.     TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %xn",
  1491.   hwnd, uMsg, wParam, lParam);
  1492.     */
  1493.     HandleMouseHide(uMsg, lParam);
  1494.     s_uMsg = uMsg;
  1495.     s_wParam = wParam;
  1496.     s_lParam = lParam;
  1497.     switch (uMsg)
  1498.     {
  1499. HANDLE_MSG(hwnd, WM_DEADCHAR, _OnDeadChar);
  1500. HANDLE_MSG(hwnd, WM_SYSDEADCHAR, _OnDeadChar);
  1501. /* HANDLE_MSG(hwnd, WM_ACTIVATE,    _OnActivate); */
  1502. HANDLE_MSG(hwnd, WM_CHAR, _OnChar);
  1503. HANDLE_MSG(hwnd, WM_CLOSE, _OnClose);
  1504. /* HANDLE_MSG(hwnd, WM_COMMAND, _OnCommand); */
  1505. HANDLE_MSG(hwnd, WM_DESTROY, _OnDestroy);
  1506. HANDLE_MSG(hwnd, WM_DROPFILES, _OnDropFiles);
  1507. HANDLE_MSG(hwnd, WM_HSCROLL, _OnScroll);
  1508. HANDLE_MSG(hwnd, WM_KILLFOCUS, _OnKillFocus);
  1509. HANDLE_MSG(hwnd, WM_COMMAND, _OnMenu);
  1510. /* HANDLE_MSG(hwnd, WM_MOVE,     _OnMove); */
  1511. /* HANDLE_MSG(hwnd, WM_NCACTIVATE,  _OnNCActivate); */
  1512. HANDLE_MSG(hwnd, WM_SETFOCUS, _OnSetFocus);
  1513. HANDLE_MSG(hwnd, WM_SIZE, _OnSize);
  1514. /* HANDLE_MSG(hwnd, WM_SYSCOMMAND,  _OnSysCommand); */
  1515. /* HANDLE_MSG(hwnd, WM_SYSKEYDOWN,  _OnAltKey); */
  1516. /* HANDLE_MSG(hwnd, WM_SYSKEYUP,    _OnAltKey); */
  1517. HANDLE_MSG(hwnd, WM_VSCROLL, _OnScroll);
  1518. HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, _OnWindowPosChanging);
  1519. HANDLE_MSG(hwnd, WM_ACTIVATEAPP, _OnActivateApp);
  1520. /* HANDLE_MSG(hwnd, WM_SYSCHAR, _OnSysChar); */
  1521.     case WM_SYSCHAR:
  1522. /*
  1523.  * if 'winaltkeys' is "no", or it's "menu" and it's not a menu
  1524.  * shortcut key, handle like a typed ALT key, otherwise call Windows
  1525.  * ALT key handling.
  1526.  */
  1527. if (p_wak[0] == 'n'
  1528. || (p_wak[0] == 'm' && !gui_is_menu_shortcut((int)wParam)))
  1529.     return HANDLE_WM_SYSCHAR((hwnd), (wParam), (lParam), (_OnSysChar));
  1530. else
  1531.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1532.     case WM_ERASEBKGND:
  1533. _OnEraseBG(hwnd);
  1534. break;
  1535.     case WM_CREATE: /* HANDLE_MSG doesn't seem to handle this one */
  1536. return _OnCreate (hwnd, (LPCREATESTRUCT)lParam);
  1537.     case WM_SIZING: /* HANDLE_MSG doesn't seem to handle this one */
  1538. return _DuringSizing(hwnd, wParam, (LPRECT)lParam);
  1539.     case WM_MOUSEWHEEL:
  1540. _OnMouseWheel(hwnd, HIWORD(wParam));
  1541. break;
  1542. #ifdef USE_GUI_WIN32_TOOLBAR
  1543.     case WM_NOTIFY:
  1544. switch (((LPNMHDR) lParam)->code)
  1545. {
  1546.     case TTN_NEEDTEXT:
  1547. {
  1548.     LPTOOLTIPTEXT lpttt;
  1549.     UINT idButton;
  1550.     int idx;
  1551.     GuiMenu *pMenu;
  1552.     lpttt = (LPTOOLTIPTEXT)lParam;
  1553.     idButton = lpttt->hdr.idFrom;
  1554.     pMenu = gui_w32_find_menu(gui.root_menu, idButton);
  1555.     if (pMenu)
  1556.     {
  1557. idx = MENU_INDEX_TIP;
  1558. if (pMenu->strings[idx])
  1559. {
  1560.     lpttt->hinst = NULL;  /* string, not resource*/
  1561.     lpttt->lpszText = pMenu->strings[idx];
  1562. }
  1563.     }
  1564. }
  1565. break;
  1566.     default:
  1567. break;
  1568. }
  1569. break;
  1570. #endif
  1571. #ifdef  MENUHINTS
  1572.     case WM_MENUSELECT:
  1573. if ((((UINT) HIWORD(wParam) &
  1574.     (0xffff ^ (MF_MOUSESELECT + MF_BITMAP))) == MF_HILITE) &
  1575.     ((State & CMDLINE) == 0))
  1576. {
  1577.     UINT idButton;
  1578.     int idx;
  1579.     GuiMenu *pMenu;
  1580.     idButton = (UINT)LOWORD(wParam);
  1581.     pMenu = gui_w32_find_menu(gui.root_menu, idButton);
  1582.     if (pMenu)
  1583.     {
  1584. idx = MENU_INDEX_TIP;
  1585. if (pMenu->strings[idx])
  1586.     msg(pMenu->strings[idx]);
  1587. else
  1588.     msg("");
  1589. setcursor();
  1590. out_flush();
  1591.     }
  1592. }
  1593. break;
  1594. #endif
  1595.     default:
  1596. if (uMsg == msh_msgmousewheel && msh_msgmousewheel != 0)
  1597. {   /* handle MSH_MOUSEWHEEL messages for Intellimouse */
  1598.     _OnMouseWheel(hwnd, HIWORD(wParam));
  1599.     break;
  1600. }
  1601. #ifdef WIN32_FIND_REPLACE
  1602. else if (uMsg == s_findrep_msg && s_findrep_msg != 0)
  1603. {
  1604.     _OnFindRepl();
  1605. }
  1606. #endif
  1607. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1608.     }
  1609.     return 1;
  1610. }
  1611.     static LRESULT CALLBACK
  1612. _TextAreaWndProc(
  1613.     HWND hwnd,
  1614.     UINT uMsg,
  1615.     WPARAM wParam,
  1616.     LPARAM lParam)
  1617. {
  1618.     /*
  1619.     TRACE("TextAreaWndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %xn",
  1620.   hwnd, uMsg, wParam, lParam);
  1621.     */
  1622.     HandleMouseHide(uMsg, lParam);
  1623.     s_uMsg = uMsg;
  1624.     s_wParam = wParam;
  1625.     s_lParam = lParam;
  1626.     switch (uMsg)
  1627.     {
  1628. HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK,_OnMouseButtonDown);
  1629. HANDLE_MSG(hwnd, WM_LBUTTONDOWN,_OnMouseButtonDown);
  1630. HANDLE_MSG(hwnd, WM_LBUTTONUP, _OnMouseMoveOrRelease);
  1631. HANDLE_MSG(hwnd, WM_MBUTTONDBLCLK,_OnMouseButtonDown);
  1632. HANDLE_MSG(hwnd, WM_MBUTTONDOWN,_OnMouseButtonDown);
  1633. HANDLE_MSG(hwnd, WM_MBUTTONUP, _OnMouseMoveOrRelease);
  1634. HANDLE_MSG(hwnd, WM_MOUSEMOVE, _OnMouseMoveOrRelease);
  1635. HANDLE_MSG(hwnd, WM_PAINT, _OnPaint);
  1636. HANDLE_MSG(hwnd, WM_RBUTTONDBLCLK,_OnMouseButtonDown);
  1637. HANDLE_MSG(hwnd, WM_RBUTTONDOWN,_OnMouseButtonDown);
  1638. HANDLE_MSG(hwnd, WM_RBUTTONUP, _OnMouseMoveOrRelease);
  1639.     default:
  1640. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1641.     }
  1642. }
  1643. /*
  1644.  * End of call-back routines
  1645.  */
  1646. /*
  1647.  * Parse the GUI related command-line arguments.  Any arguments used are
  1648.  * deleted from argv, and *argc is decremented accordingly.  This is called
  1649.  * when vim is started, whether or not the GUI has been started.
  1650.  */
  1651.     void
  1652. gui_mch_prepare(int *argc, char **argv)
  1653. {
  1654.     /* We don't have any command line arguments for the Windows GUI yet */
  1655.     /* get the OS version info */
  1656.     os_version.dwOSVersionInfoSize = sizeof(os_version);
  1657.     GetVersionEx(&os_version); /* this call works on Win32s, Win95 and WinNT */
  1658. }
  1659. /*
  1660.  * Initialise the GUI. Create all the windows, set up all the call-backs
  1661.  * etc.
  1662.  */
  1663.     int
  1664. gui_mch_init(void)
  1665. {
  1666.     const char szVimWndClass[] = VIM_CLASS;
  1667.     const char szTextAreaClass[] = "VimTextArea";
  1668.     WNDCLASS wndclass;
  1669.     /* Display any pending error messages */
  1670.     mch_display_error();
  1671.     /*
  1672.      * Load the tearoff bitmap
  1673.      */
  1674.     s_htearbitmap = LoadBitmap(s_hinst, "IDB_TEAROFF");
  1675.     gui.scrollbar_width = GetSystemMetrics(SM_CXVSCROLL);
  1676.     gui.scrollbar_height = GetSystemMetrics(SM_CYHSCROLL);
  1677.     gui.menu_height = 0; /* Windows takes care of this */
  1678.     gui.border_width = 0;
  1679.     wndclass.style = CS_HREDRAW | CS_VREDRAW;
  1680.     wndclass.lpfnWndProc = _WndProc;
  1681.     wndclass.cbClsExtra = 0;
  1682.     wndclass.cbWndExtra = 0;
  1683.     wndclass.hInstance = s_hinst;
  1684.     wndclass.hIcon = LoadIcon(wndclass.hInstance, "IDR_VIM");
  1685.     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  1686.     wndclass.hbrBackground = GetStockBrush(LTGRAY_BRUSH);
  1687.     wndclass.lpszMenuName = NULL;
  1688.     wndclass.lpszClassName = szVimWndClass;
  1689.     if (RegisterClass(&wndclass) == 0)
  1690. return FAIL;
  1691.     s_hwnd = CreateWindow(
  1692. szVimWndClass, "Vim W32 GUI",
  1693. WS_OVERLAPPEDWINDOW,
  1694. CW_USEDEFAULT, CW_USEDEFAULT,
  1695. 100, /* Any value will do */
  1696. 100, /* Any value will do */
  1697. NULL, NULL,
  1698. s_hinst, NULL);
  1699.     if (s_hwnd == NULL)
  1700. return FAIL;
  1701.     /* Create the text area window */
  1702.     wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  1703.     wndclass.lpfnWndProc = _TextAreaWndProc;
  1704.     wndclass.cbClsExtra = 0;
  1705.     wndclass.cbWndExtra = 0;
  1706.     wndclass.hInstance = s_hinst;
  1707.     wndclass.hIcon = NULL;
  1708.     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  1709.     wndclass.hbrBackground = NULL;
  1710.     wndclass.lpszMenuName = NULL;
  1711.     wndclass.lpszClassName = szTextAreaClass;
  1712.     if (RegisterClass(&wndclass) == 0)
  1713. return FAIL;
  1714.     s_textArea = CreateWindow(
  1715. szTextAreaClass, "Vim text area",
  1716. WS_CHILD | WS_VISIBLE, 0, 0,
  1717. 100, /* Any value will do for now */
  1718. 100, /* Any value will do for now */
  1719. s_hwnd, NULL,
  1720. s_hinst, NULL);
  1721.     if (s_textArea == NULL)
  1722. return FAIL;
  1723.     s_menuBar = CreateMenu();
  1724.     s_hdc = GetDC(s_textArea);
  1725.     DragAcceptFiles(s_hwnd, TRUE);
  1726.     /* Do we need to bother with this? */
  1727.     /* m_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT); */
  1728.     /* Get background/foreground colors from system */
  1729.     gui.norm_pixel = GetSysColor(COLOR_WINDOWTEXT);
  1730.     gui.back_pixel = GetSysColor(COLOR_WINDOW);
  1731.     gui.def_norm_pixel = gui.norm_pixel;
  1732.     gui.def_back_pixel = gui.back_pixel;
  1733.     /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
  1734.      * file) */
  1735.     set_normal_colors();
  1736.     /*
  1737.      * Check that none of the colors are the same as the background color.
  1738.      * Then store the current values as the defaults.
  1739.      */
  1740.     gui_check_colors();
  1741.     gui.def_norm_pixel = gui.norm_pixel;
  1742.     gui.def_back_pixel = gui.back_pixel;
  1743.     /* Get the colors for the highlight groups (gui_check_colors() might have
  1744.      * changed them) */
  1745.     highlight_gui_started();
  1746.     /*
  1747.      * Start out by adding the configured border width into the border offset
  1748.      */
  1749.     gui.border_offset = gui.border_width;
  1750.     /*
  1751.      * Set up for Intellimouse processing
  1752.      */
  1753.     init_mouse_wheel();
  1754.     /*
  1755.      * compute a couple of metrics used for the dialogs
  1756.      */
  1757.     get_dialog_font_metrics();
  1758. #ifdef USE_GUI_WIN32_TOOLBAR
  1759.     /*
  1760.      * Create the toolbar
  1761.      */
  1762.     initialise_toolbar();
  1763. #endif
  1764. #ifdef WIN32_FIND_REPLACE
  1765.     /*
  1766.      * Initialise the dialog box stuff
  1767.      */
  1768.     s_findrep_msg = RegisterWindowMessage(FINDMSGSTRING);
  1769.     /* Initialise the struct */
  1770.     s_findrep_struct.lStructSize = sizeof(s_findrep_struct);
  1771.     s_findrep_struct.lpstrFindWhat = alloc(256);
  1772.     s_findrep_struct.lpstrFindWhat[0] = NUL;
  1773.     s_findrep_struct.lpstrReplaceWith = alloc(256);
  1774.     s_findrep_struct.lpstrReplaceWith[0] = NUL;
  1775.     s_findrep_struct.wFindWhatLen = 256;
  1776.     s_findrep_struct.wReplaceWithLen = 256;
  1777. #endif
  1778.     return OK;
  1779. }
  1780. /*
  1781.  * Called when the foreground or background color has been changed.
  1782.  */
  1783.     void
  1784. gui_mch_new_colors(void)
  1785. {
  1786.     /* nothing to do? */
  1787. }
  1788. /*
  1789.  * Open the GUI window which was created by a call to gui_mch_init().
  1790.  */
  1791.     int
  1792. gui_mch_open(void)
  1793. {
  1794.     /* Actually open the window */
  1795.     ShowWindow(s_hwnd, SW_SHOWNORMAL);
  1796.     return OK;
  1797. }
  1798.     void
  1799. gui_mch_exit(int rc)
  1800. {
  1801.     ReleaseDC(s_textArea, s_hdc);
  1802.     /*
  1803.      * Unload the tearoff bitmap
  1804.      */
  1805.     (void)DeleteObject((HGDIOBJ) s_htearbitmap);
  1806.     /* Destroy our window (if we have one). */
  1807.     if (s_hwnd != NULL)
  1808.     {
  1809. destroying = TRUE; /* ignore WM_DESTROY message now */
  1810. DestroyWindow(s_hwnd);
  1811.     }
  1812. }
  1813. /*
  1814.  * Set the size of the window to the given width and height in pixels.
  1815.  */
  1816.     void
  1817. gui_mch_set_winsize(int width, int height, int min_width, int min_height,
  1818.     int base_width, int base_height)
  1819. {
  1820.     RECT    workarea_rect;
  1821.     int     win_width, win_height;
  1822.     int     win_xpos, win_ypos;
  1823.     WINDOWPLACEMENT wndpl;
  1824.     /* try to keep window completely on screen */
  1825.     /* get size of the screen work area (excludes taskbar, appbars) */
  1826.     SystemParametersInfo(SPI_GETWORKAREA, 0, &workarea_rect, 0);
  1827.     /* get current posision of our window */
  1828.     wndpl.length = sizeof(WINDOWPLACEMENT);
  1829.     GetWindowPlacement(s_hwnd, &wndpl);
  1830.     if (wndpl.showCmd == SW_SHOWNORMAL)
  1831.     {
  1832. win_xpos = wndpl.rcNormalPosition.left;
  1833. win_ypos = wndpl.rcNormalPosition.top;
  1834.     }
  1835.     else
  1836.     {
  1837. win_xpos = workarea_rect.left;
  1838. win_ypos = workarea_rect.top;
  1839.     }
  1840.     /* compute the size of the outside of the window */
  1841.     win_width = width + GetSystemMetrics(SM_CXSIZEFRAME) * 2;
  1842.     win_height = height + GetSystemMetrics(SM_CYSIZEFRAME) * 2
  1843. + GetSystemMetrics(SM_CYCAPTION)
  1844. + gui_w32_get_menu_height(FALSE);
  1845.     /* if the window is going off the screen, move it on to the screen */
  1846.     if (win_xpos + win_width > workarea_rect.right)
  1847. win_xpos = workarea_rect.right - win_width;
  1848.     if (win_xpos < workarea_rect.left)
  1849. win_xpos = workarea_rect.left;
  1850.     if (win_ypos + win_height > workarea_rect.bottom)
  1851. win_ypos = workarea_rect.bottom - win_height;
  1852.     if (win_ypos < workarea_rect.top)
  1853. win_ypos = workarea_rect.top;
  1854.     /* set window position */
  1855.     SetWindowPos(s_hwnd, NULL, win_xpos, win_ypos, win_width, win_height,
  1856.  SWP_NOZORDER | SWP_NOACTIVATE);
  1857.     /* Menu may wrap differently now */
  1858.     gui_w32_get_menu_height(!gui.starting);
  1859. }
  1860.     void
  1861. gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
  1862. {
  1863.     RECT    workarea_rect;
  1864.     /* get size of the screen work area (excludes taskbar, appbars) */
  1865.     SystemParametersInfo(SPI_GETWORKAREA, 0, &workarea_rect, 0);
  1866.     *screen_w = workarea_rect.right - workarea_rect.left
  1867.       - GetSystemMetrics(SM_CXSIZEFRAME) * 2;
  1868.     *screen_h = workarea_rect.bottom - workarea_rect.top
  1869.       - GetSystemMetrics(SM_CYSIZEFRAME) * 2
  1870.       - GetSystemMetrics(SM_CYCAPTION)
  1871.       - gui_w32_get_menu_height(FALSE);
  1872. }
  1873.     void
  1874. gui_mch_set_text_area_pos(int x, int y, int w, int h)
  1875. {
  1876.     SetWindowPos(s_textArea, NULL, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE);
  1877. #ifdef USE_GUI_WIN32_TOOLBAR
  1878.     if (vim_strchr(p_guioptions, GO_TOOLBAR) != NULL)
  1879. SendMessage(s_toolbarhwnd, WM_SIZE,
  1880. (WPARAM)0, (LPARAM)(w + (long)(TOOLBAR_BUTTON_HEIGHT+8)<<16));
  1881. #endif
  1882. }
  1883. /*
  1884.  * Scrollbar stuff:
  1885.  */
  1886.     void
  1887. gui_mch_enable_scrollbar(
  1888.     GuiScrollbar    *sb,
  1889.     int     flag)
  1890. {
  1891.     ShowScrollBar(sb->id, SB_CTL, flag);
  1892. }
  1893.     void
  1894. gui_mch_set_scrollbar_thumb(
  1895.     GuiScrollbar    *sb,
  1896.     int     val,
  1897.     int     size,
  1898.     int     max)
  1899. {
  1900.     SCROLLINFO info;
  1901.     scroll_shift = 0;
  1902.     while (max > 32767)
  1903.     {
  1904. max = max + 1 >> 1;
  1905. val  >>= 1;
  1906. size >>= 1;
  1907. ++scroll_shift;
  1908.     }
  1909.     if (scroll_shift > 0)
  1910. ++size;
  1911.     info.cbSize = sizeof(info);
  1912.     info.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
  1913.     info.nPos = val;
  1914.     info.nMin = 0;
  1915.     info.nMax = max;
  1916.     info.nPage = size;
  1917.     SetScrollInfo(sb->id, SB_CTL, &info, TRUE);
  1918. }
  1919.     void
  1920. gui_mch_set_scrollbar_pos(
  1921.     GuiScrollbar    *sb,
  1922.     int     x,
  1923.     int     y,
  1924.     int     w,
  1925.     int     h)
  1926. {
  1927.     SetWindowPos(sb->id, NULL, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
  1928. }
  1929.     void
  1930. gui_mch_create_scrollbar(
  1931.     GuiScrollbar    *sb,
  1932.     int     orient) /* SBAR_VERT or SBAR_HORIZ */
  1933. {
  1934.     sb->id = CreateWindow(
  1935. "SCROLLBAR", "Scrollbar",
  1936. WS_CHILD | ((orient == SBAR_VERT) ? SBS_VERT : SBS_HORZ), 0, 0,
  1937. 10, /* Any value will do for now */
  1938. 10, /* Any value will do for now */
  1939. s_hwnd, NULL,
  1940. s_hinst, NULL);
  1941. }
  1942.     void
  1943. gui_mch_destroy_scrollbar(GuiScrollbar *sb)
  1944. {
  1945.     DestroyWindow(sb->id);
  1946. }
  1947. /*
  1948.  * Get the character size of a font, by measuring the size of four characters.
  1949.  */
  1950.     static void
  1951. GetFontSize(GuiFont font)
  1952. {
  1953.     HWND    hwnd = GetDesktopWindow();
  1954.     HDC     hdc = GetWindowDC(hwnd);
  1955.     HFONT   hfntOld = SelectFont(hdc, (HFONT)font);
  1956.     TEXTMETRIC tm;
  1957.     /*
  1958.     static const char ach[] = {'W', 'f', 'g', 'M'};
  1959.     SIZE    siz;
  1960.     GetTextExtentPoint(hdc, ach, sizeof(ach), &siz);
  1961.     */
  1962.     GetTextMetrics(hdc, &tm);
  1963.     gui.char_width = tm.tmAveCharWidth + tm.tmOverhang;
  1964.     /*
  1965.      * Make characters one pixel higher, so that italic and bold fonts don't
  1966.      * draw off the bottom of their character space.  Also means that we can
  1967.      * underline an underscore for normal text.
  1968.      */
  1969.     gui.char_height = tm.tmHeight+1; /*siz.cy + 1;*/
  1970.     /* TRACE("GetFontSize: h %d, w %dn", gui.char_height, gui.char_width); */
  1971.     SelectFont(hdc, hfntOld);
  1972.     ReleaseDC(hwnd, hdc);
  1973. }
  1974.     static GuiFont
  1975. get_font_handle(LOGFONT *lf)
  1976. {
  1977.     HFONT   *font = NULL;
  1978.     /* Load the font */
  1979.     font = CreateFontIndirect(lf);
  1980.     if (font == NULL)
  1981. return (GuiFont)0;
  1982.     return (GuiFont)font;
  1983. }
  1984. /* Convert a string representing a point size into pixels. The string should
  1985.  * be a positive decimal number, with an optional decimal point (eg, "12", or
  1986.  * "10.5"). The pixel value is returned, and a pointer to the next unconverted
  1987.  * character is stored in *end. The flag "vertical" says whether this
  1988.  * calculation is for a vertical (height) size or a horizontal (width) one.
  1989.  */
  1990.     static int
  1991. points_to_pixels(char_u *str, char_u **end, int vertical)
  1992. {
  1993.     int pixels;
  1994.     int points = 0;
  1995.     int divisor = 0;
  1996.     HWND hwnd;
  1997.     HDC hdc;
  1998.     while (*str)
  1999.     {
  2000. if (*str == '.' && divisor == 0)
  2001. {
  2002.     /* Start keeping a divisor, for later */
  2003.     divisor = 1;
  2004.     continue;
  2005. }
  2006. if (!isdigit(*str))
  2007.     break;
  2008. points *= 10;
  2009. points += *str - '0';
  2010. divisor *= 10;
  2011. ++str;
  2012.     }
  2013.     if (divisor == 0)
  2014. divisor = 1;
  2015.     hwnd = GetDesktopWindow();
  2016.     hdc = GetWindowDC(hwnd);
  2017.     pixels = MulDiv(points,
  2018.     GetDeviceCaps(hdc, vertical ? LOGPIXELSY : LOGPIXELSX),
  2019.     72 * divisor);
  2020.     ReleaseDC(hwnd, hdc);
  2021.     *end = str;
  2022.     return pixels;
  2023. }
  2024.     static int
  2025. pixels_to_points(int pixels, int vertical)
  2026. {
  2027.     int points;
  2028.     HWND hwnd;
  2029.     HDC hdc;
  2030.     hwnd = GetDesktopWindow();
  2031.     hdc = GetWindowDC(hwnd);
  2032.     points = MulDiv(pixels, 72,
  2033.     GetDeviceCaps(hdc, vertical ? LOGPIXELSY : LOGPIXELSX));
  2034.     ReleaseDC(hwnd, hdc);
  2035.     return points;
  2036. }
  2037.     static int CALLBACK
  2038. font_enumproc(
  2039.     ENUMLOGFONT     *elf,
  2040.     NEWTEXTMETRIC   *ntm,
  2041.     int     type,
  2042.     LPARAM     lparam)
  2043. {
  2044.     /* Return value:
  2045.      *   0 = terminate now (monospace & ANSI)
  2046.      *   1 = continue, still no luck...
  2047.      *   2 = continue, but we have an acceptable LOGFONT
  2048.      *       (monospace, not ANSI)
  2049.      * We use these values, as EnumFontFamilies returns 1 if the
  2050.      * callback function is never called. So, we check the return as
  2051.      * 0 = perfect, 2 = OK, 1 = no good...
  2052.      * It's not pretty, but it works!
  2053.      */
  2054.     LOGFONT *lf = (LOGFONT *)(lparam);
  2055.     /* Ignore non-monospace fonts without further ado */
  2056.     if ((ntm->tmPitchAndFamily & 1) != 0)
  2057. return 1;
  2058.     /* Remember this LOGFONT as a "possible" */
  2059.     *lf = elf->elfLogFont;
  2060.     /* Terminate the scan as soon as we find an ANSI font */
  2061.     if (lf->lfCharSet == ANSI_CHARSET
  2062.     || lf->lfCharSet == OEM_CHARSET
  2063.     || lf->lfCharSet == DEFAULT_CHARSET)
  2064. return 0;
  2065.     /* Continue the scan - we have a non-ANSI font */
  2066.     return 2;
  2067. }
  2068.     static int
  2069. init_logfont(LOGFONT *lf)
  2070. {
  2071.     int n;
  2072.     HWND hwnd = GetDesktopWindow();
  2073.     HDC hdc = GetWindowDC(hwnd);
  2074.     n = EnumFontFamilies(hdc,
  2075.  lf->lfFaceName,
  2076.  (FONTENUMPROC)font_enumproc,
  2077.  (LPARAM)(lf));
  2078.     ReleaseDC(hwnd, hdc);
  2079.     /* If we couldn't find a useable font, return failure */
  2080.     if (n == 1)
  2081. return FAIL;
  2082.     /* Tidy up the rest of the LOGFONT structure. We set to a basic
  2083.      * font - get_logfont() sets bold, italic, etc based on the user's
  2084.      * input.
  2085.      */
  2086.     lf->lfHeight = current_font_height;
  2087.     lf->lfWidth = 0;
  2088.     lf->lfItalic = FALSE;
  2089.     lf->lfUnderline = FALSE;
  2090.     lf->lfStrikeOut = FALSE;
  2091.     lf->lfWeight = FW_NORMAL;
  2092.     /* Return success */
  2093.     return OK;
  2094. }
  2095.     static int
  2096. get_logfont(
  2097.     LOGFONT *lf,
  2098.     char_u  *name)
  2099. {
  2100.     char_u *p;
  2101.     CHOOSEFONT cf;
  2102.     int i;
  2103.     static LOGFONT *lastlf = NULL;
  2104.     *lf = s_lfDefault;
  2105.     if (name == NULL)
  2106. return 1;
  2107.     if (STRCMP(name, "*") == 0)
  2108.     {
  2109. /* ron: if name is "*", bring up std font dialog: */
  2110. memset(&cf, 0, sizeof(cf));
  2111. cf.lStructSize = sizeof(cf);
  2112. cf.hwndOwner = s_hwnd;
  2113. cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_INITTOLOGFONTSTRUCT;
  2114. if (lastlf != NULL)
  2115.     *lf = *lastlf;
  2116. cf.lpLogFont = lf;
  2117. cf.nFontType = 0 ; //REGULAR_FONTTYPE;
  2118. if (ChooseFont(&cf))
  2119.     goto theend;
  2120.     }
  2121.     /*
  2122.      * Split name up, it could be <name>:h<height>:w<width> etc.
  2123.      */
  2124.     for (p = name; *p && *p != ':'; p++)
  2125.     {
  2126. if (p - name + 1 > LF_FACESIZE)
  2127.     return 0; /* Name too long */
  2128. lf->lfFaceName[p - name] = *p;
  2129.     }
  2130.     if (p != name)
  2131. lf->lfFaceName[p - name] = NUL;
  2132.     /* First set defaults */
  2133.     lf->lfHeight = -12;
  2134.     lf->lfWidth = 0;
  2135.     lf->lfWeight = FW_NORMAL;
  2136.     lf->lfItalic = FALSE;
  2137.     lf->lfUnderline = FALSE;
  2138.     lf->lfStrikeOut = FALSE;
  2139.     /*
  2140.      * If the font can't be found, try replacing '_' by ' '.
  2141.      */
  2142.     if (init_logfont(lf) == FAIL)
  2143.     {
  2144. int did_replace = FALSE;
  2145. for (i = 0; lf->lfFaceName[i]; ++i)
  2146.     if (lf->lfFaceName[i] == '_')
  2147.     {
  2148. lf->lfFaceName[i] = ' ';
  2149. did_replace = TRUE;
  2150.     }
  2151. if (!did_replace || init_logfont(lf) == FAIL)
  2152.     return 0;
  2153.     }
  2154.     while (*p == ':')
  2155. p++;
  2156.     /* Set the values found after ':' */
  2157.     while (*p)
  2158.     {
  2159. switch (*p++)
  2160. {
  2161.     case 'h':
  2162. lf->lfHeight = - points_to_pixels(p, &p, TRUE);
  2163. break;
  2164.     case 'w':
  2165. lf->lfWidth = points_to_pixels(p, &p, FALSE);
  2166. break;
  2167.     case 'b':
  2168. lf->lfWeight = FW_BOLD;
  2169. break;
  2170.     case 'i':
  2171. lf->lfItalic = TRUE;
  2172. break;
  2173.     case 'u':
  2174. lf->lfUnderline = TRUE;
  2175. break;
  2176.     case 's':
  2177. lf->lfStrikeOut = TRUE;
  2178. break;
  2179.     default:
  2180. sprintf((char *)IObuff,
  2181. "Illegal char '%c' in font name "%s"",
  2182. p[-1], name);
  2183. EMSG(IObuff);
  2184. break;
  2185. }
  2186. while (*p == ':')
  2187.     p++;
  2188.     }
  2189. theend:
  2190.     /* ron: init lastlf */
  2191.     vim_free(lastlf);
  2192.     lastlf = (LOGFONT *)alloc(sizeof(LOGFONT));
  2193.     if (lastlf != NULL)
  2194. mch_memmove(lastlf, lf, sizeof(LOGFONT));
  2195.     return 1;
  2196. }
  2197. /*
  2198.  * Initialise vim to use the font with the given name. Return FAIL if the font
  2199.  * could not be loaded, OK otherwise.
  2200.  */
  2201.     int
  2202. gui_mch_init_font(char_u *font_name)
  2203. {
  2204.     LOGFONT lf;
  2205.     GuiFont font = (GuiFont)0;
  2206.     char *p;
  2207.     /* Load the font */
  2208.     if (get_logfont(&lf, font_name))
  2209. font = get_font_handle(&lf);
  2210.     if (font == (GuiFont)0)
  2211. return FAIL;
  2212.     if (font_name == NULL)
  2213. font_name = lf.lfFaceName;
  2214.     gui_mch_free_font(gui.norm_font);
  2215.     gui.norm_font = font;
  2216.     current_font_height = lf.lfHeight;
  2217.     GetFontSize(font);
  2218.     hl_set_font_name(lf.lfFaceName);
  2219.     if (STRCMP(font_name, "*") == 0)
  2220.     {
  2221. p = alloc((unsigned)(strlen(lf.lfFaceName) + 10));
  2222. if (p != NULL)
  2223. {
  2224.     /* make a normal font string out of the lf thing:*/
  2225.     sprintf(p, "%s:h%d", lf.lfFaceName, pixels_to_points(
  2226.  lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight, TRUE));
  2227.     vim_free(p_guifont);
  2228.     p_guifont = p;
  2229.     while (*p)
  2230.     {
  2231. if (*p == ' ')
  2232.     *p = '_';
  2233. ++p;
  2234.     }
  2235. }
  2236.     }
  2237.     if (!lf.lfItalic)
  2238.     {
  2239. lf.lfItalic = TRUE;
  2240. gui.ital_font = get_font_handle(&lf);
  2241. lf.lfItalic = FALSE;
  2242.     }
  2243.     if (lf.lfWeight < FW_BOLD)
  2244.     {
  2245. lf.lfWeight = FW_BOLD;
  2246. gui.bold_font = get_font_handle(&lf);
  2247. if (!lf.lfItalic)
  2248. {
  2249.     lf.lfItalic = TRUE;
  2250.     gui.boldital_font = get_font_handle(&lf);
  2251. }
  2252.     }
  2253.     return OK;
  2254. }
  2255.     GuiFont
  2256. gui_mch_get_font(
  2257.     char_u *name,
  2258.     int giveErrorIfMissing)
  2259. {
  2260.     LOGFONT lf;
  2261.     GuiFont font;
  2262.     get_logfont(&lf, name);
  2263.     font = get_font_handle(&lf);
  2264.     if (font == (GuiFont)0 && giveErrorIfMissing)
  2265. EMSG2("Unknown font: %s", name);
  2266.     return font;
  2267. }
  2268. /*
  2269.  * Set the current text font.
  2270.  */
  2271.     void
  2272. gui_mch_set_font(GuiFont font)
  2273. {
  2274.     gui.currFont = font;
  2275. }
  2276. /*
  2277.  * Return TRUE if the two fonts given are equivalent.
  2278.  */
  2279.     int
  2280. gui_mch_same_font(
  2281.     GuiFont f1,
  2282.     GuiFont f2)
  2283. {
  2284.     return f1 == f2;
  2285. }
  2286.     void
  2287. gui_mch_free_font(GuiFont font)
  2288. {
  2289.     if (font)
  2290. DeleteObject((HFONT)font);
  2291. }
  2292.     static int
  2293. hex_digit(int c)
  2294. {
  2295.     if (vim_isdigit(c))
  2296. return c - '0';
  2297.     c = TO_LOWER(c);
  2298.     if (c >= 'a' && c <= 'f')
  2299. return c - 'a' + 10;
  2300.     return -1000;
  2301. }
  2302. /*
  2303.  * Return the Pixel value (color) for the given color name.
  2304.  * Return -1 for error.
  2305.  */
  2306.     GuiColor
  2307. gui_mch_get_color(char_u *name)
  2308. {
  2309.     typedef struct GuiColorTable
  2310.     {
  2311. char     *name;
  2312. COLORREF    color;
  2313.     } GuiColorTable;
  2314.     static GuiColorTable table[] =
  2315.     {
  2316. {"Black", RGB(0x00, 0x00, 0x00)},
  2317. {"DarkGray", RGB(0x80, 0x80, 0x80)},
  2318. {"DarkGrey", RGB(0x80, 0x80, 0x80)},
  2319. {"Gray", RGB(0xC0, 0xC0, 0xC0)},
  2320. {"Grey", RGB(0xC0, 0xC0, 0xC0)},
  2321. {"LightGray", RGB(0xE0, 0xE0, 0xE0)},
  2322. {"LightGrey", RGB(0xE0, 0xE0, 0xE0)},
  2323. {"White", RGB(0xFF, 0xFF, 0xFF)},
  2324. {"DarkRed", RGB(0x80, 0x00, 0x00)},
  2325. {"Red", RGB(0xFF, 0x00, 0x00)},
  2326. {"LightRed", RGB(0xFF, 0xA0, 0xA0)},
  2327. {"DarkBlue", RGB(0x00, 0x00, 0x80)},
  2328. {"Blue", RGB(0x00, 0x00, 0xFF)},
  2329. {"LightBlue", RGB(0xA0, 0xA0, 0xFF)},
  2330. {"DarkGreen", RGB(0x00, 0x80, 0x00)},
  2331. {"Green", RGB(0x00, 0xFF, 0x00)},
  2332. {"LightGreen", RGB(0xA0, 0xFF, 0xA0)},
  2333. {"DarkCyan", RGB(0x00, 0x80, 0x80)},
  2334. {"Cyan", RGB(0x00, 0xFF, 0xFF)},
  2335. {"LightCyan", RGB(0xA0, 0xFF, 0xFF)},
  2336. {"DarkMagenta", RGB(0x80, 0x00, 0x80)},
  2337. {"Magenta", RGB(0xFF, 0x00, 0xFF)},
  2338. {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)},
  2339. {"Brown", RGB(0x80, 0x40, 0x40)},
  2340. {"Yellow", RGB(0xFF, 0xFF, 0x00)},
  2341. {"LightYellow", RGB(0xFF, 0xFF, 0xA0)},
  2342. {"SeaGreen", RGB(0x2E, 0x8B, 0x57)},
  2343. {"Orange", RGB(0xFF, 0xA5, 0x00)},
  2344. {"Purple", RGB(0xA0, 0x20, 0xF0)},
  2345. {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)},
  2346. {"Violet", RGB(0xEE, 0x82, 0xEE)},
  2347.     };
  2348.     typedef struct SysColorTable
  2349.     {
  2350. char     *name;
  2351. int     color;
  2352.     } SysColorTable;
  2353.     static SysColorTable sys_table[] =
  2354.     {
  2355. "SYS_3DDKSHADOW", COLOR_3DDKSHADOW,
  2356. "SYS_3DFACE", COLOR_3DFACE,
  2357. "SYS_BTNFACE", COLOR_BTNFACE,
  2358. "SYS_3DHILIGHT", COLOR_3DHILIGHT,
  2359. "SYS_3DHIGHLIGHT", COLOR_3DHIGHLIGHT,
  2360. "SYS_BTNHILIGHT", COLOR_BTNHILIGHT,
  2361. "SYS_BTNHIGHLIGHT", COLOR_BTNHIGHLIGHT,
  2362. "SYS_3DLIGHT", COLOR_3DLIGHT,
  2363. "SYS_3DSHADOW", COLOR_3DSHADOW,
  2364. "SYS_BTNSHADOW", COLOR_BTNSHADOW,
  2365. "SYS_ACTIVEBORDER", COLOR_ACTIVEBORDER,
  2366. "SYS_ACTIVECAPTION", COLOR_ACTIVECAPTION,
  2367. "SYS_APPWORKSPACE", COLOR_APPWORKSPACE,
  2368. "SYS_BACKGROUND", COLOR_BACKGROUND,
  2369. "SYS_DESKTOP", COLOR_DESKTOP,
  2370. "SYS_BTNTEXT", COLOR_BTNTEXT,
  2371. "SYS_CAPTIONTEXT", COLOR_CAPTIONTEXT,
  2372. "SYS_GRAYTEXT", COLOR_GRAYTEXT,
  2373. "SYS_HIGHLIGHT", COLOR_HIGHLIGHT,
  2374. "SYS_HIGHLIGHTTEXT", COLOR_HIGHLIGHTTEXT,
  2375. "SYS_INACTIVEBORDER", COLOR_INACTIVEBORDER,
  2376. "SYS_INACTIVECAPTION", COLOR_INACTIVECAPTION,
  2377. "SYS_INACTIVECAPTIONTEXT", COLOR_INACTIVECAPTIONTEXT,
  2378. "SYS_INFOBK", COLOR_INFOBK,
  2379. "SYS_INFOTEXT", COLOR_INFOTEXT,
  2380. "SYS_MENU", COLOR_MENU,
  2381. "SYS_MENUTEXT", COLOR_MENUTEXT,
  2382. "SYS_SCROLLBAR", COLOR_SCROLLBAR,
  2383. "SYS_WINDOW", COLOR_WINDOW,
  2384. "SYS_WINDOWFRAME", COLOR_WINDOWFRAME,
  2385. "SYS_WINDOWTEXT", COLOR_WINDOWTEXT,
  2386.     };
  2387.     int     r, g, b;
  2388.     int     i;
  2389.     if (name[0] == '#' && strlen(name) == 7)
  2390.     {
  2391. /* Name is in "#rrggbb" format */
  2392. r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
  2393. g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
  2394. b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
  2395. if (r < 0 || g < 0 || b < 0)
  2396.     return (GuiColor)-1;
  2397. return RGB(r, g, b);
  2398.     }
  2399.     else
  2400.     {
  2401. /* Check if the name is one of the colors we know */
  2402. for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
  2403.     if (STRICMP(name, table[i].name) == 0)
  2404. return table[i].color;
  2405.     }
  2406.     /*
  2407.      * Try to look up a system colour.
  2408.      */
  2409.     for (i = 0; i < sizeof(sys_table) / sizeof(sys_table[0]); i++)
  2410. if (STRICMP(name, sys_table[i].name) == 0)
  2411.     return GetSysColor(sys_table[i].color);
  2412.     /*
  2413.      * Last attempt. Look in the file "$VIM/rgb.txt".
  2414.      */
  2415.     {
  2416. #define LINE_LEN 100