tkWinX.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:48k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkWinX.c --
  3.  *
  4.  * This file contains Windows emulation procedures for X routines. 
  5.  *
  6.  * Copyright (c) 1995-1996 Sun Microsystems, Inc.
  7.  * Copyright (c) 1994 Software Research Associates, Inc.
  8.  * Copyright (c) 1998-2000 by Scriptics Corporation.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * RCS: @(#) $Id: tkWinX.c,v 1.25.2.9 2007/12/05 19:18:09 hobbs Exp $
  14.  */
  15. #include "tkWinInt.h"
  16. /*
  17.  * The w32api 1.1 package (included in Mingw 1.1) does not define _WIN32_IE
  18.  * by default. Define it here to gain access to the InitCommonControlsEx API
  19.  * in commctrl.h.
  20.  */
  21. #ifndef _WIN32_IE
  22. #define _WIN32_IE 0x0300
  23. #endif
  24. #include <commctrl.h>
  25. /*
  26.  * The zmouse.h file includes the definition for WM_MOUSEWHEEL.
  27.  */
  28. #include <zmouse.h>
  29. /*
  30.  * imm.h is needed by HandleIMEComposition
  31.  */
  32. #include <imm.h>
  33. /*
  34.  * WM_UNICHAR is a message for Unicode input on all windows systems.
  35.  * Perhaps this definition should be moved in another file.
  36.  */
  37. #ifndef WM_UNICHAR
  38. #define WM_UNICHAR     0x0109
  39. #define UNICODE_NOCHAR 0xFFFF
  40. #endif
  41. static TkWinProcs asciiProcs = {
  42.     0,
  43.     (LRESULT (WINAPI *)(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg,
  44.     WPARAM wParam, LPARAM lParam)) CallWindowProcA,
  45.     (LRESULT (WINAPI *)(HWND hWnd, UINT Msg, WPARAM wParam,
  46.     LPARAM lParam)) DefWindowProcA,
  47.     (ATOM (WINAPI *)(CONST WNDCLASS *lpWndClass)) RegisterClassA,
  48.     (BOOL (WINAPI *)(HWND hWnd, LPCTSTR lpString)) SetWindowTextA,
  49.     (HWND (WINAPI *)(DWORD dwExStyle, LPCTSTR lpClassName,
  50.     LPCTSTR lpWindowName, DWORD dwStyle, int x, int y,
  51.     int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
  52.     HINSTANCE hInstance, LPVOID lpParam)) CreateWindowExA,
  53.     (BOOL (WINAPI *)(HMENU hMenu, UINT uPosition, UINT uFlags,
  54.     UINT uIDNewItem, LPCTSTR lpNewItem)) InsertMenuA,
  55. };
  56. static TkWinProcs unicodeProcs = {
  57.     1,
  58.     (LRESULT (WINAPI *)(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg,
  59.     WPARAM wParam, LPARAM lParam)) CallWindowProcW,
  60.     (LRESULT (WINAPI *)(HWND hWnd, UINT Msg, WPARAM wParam,
  61.     LPARAM lParam)) DefWindowProcW,
  62.     (ATOM (WINAPI *)(CONST WNDCLASS *lpWndClass)) RegisterClassW,
  63.     (BOOL (WINAPI *)(HWND hWnd, LPCTSTR lpString)) SetWindowTextW,
  64.     (HWND (WINAPI *)(DWORD dwExStyle, LPCTSTR lpClassName,
  65.     LPCTSTR lpWindowName, DWORD dwStyle, int x, int y,
  66.     int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
  67.     HINSTANCE hInstance, LPVOID lpParam)) CreateWindowExW,
  68.     (BOOL (WINAPI *)(HMENU hMenu, UINT uPosition, UINT uFlags,
  69.     UINT uIDNewItem, LPCTSTR lpNewItem)) InsertMenuW,
  70. };
  71. TkWinProcs *tkWinProcs;
  72. /*
  73.  * Declarations of static variables used in this file.
  74.  */
  75. static char winScreenName[] = ":0"; /* Default name of windows display. */
  76. static HINSTANCE tkInstance = NULL; /* Application instance handle. */
  77. static int childClassInitialized;   /* Registered child class? */
  78. static WNDCLASS childClass;     /* Window class for child windows. */
  79. static int tkPlatformId = 0;     /* version of Windows platform */
  80. static int tkWinTheme = 0;          /* See TkWinGetPlatformTheme */
  81. static Tcl_Encoding keyInputEncoding = NULL;/* The current character
  82.      * encoding for keyboard input */
  83. static int keyInputCharset = -1;    /* The Win32 CHARSET for the keyboard
  84.      * encoding */
  85. static Tcl_Encoding unicodeEncoding = NULL; /* unicode encoding */
  86. /*
  87.  * Thread local storage.  Notice that now each thread must have its
  88.  * own TkDisplay structure, since this structure contains most of
  89.  * the thread-specific date for threads.
  90.  */
  91. typedef struct ThreadSpecificData {
  92.     TkDisplay *winDisplay;       /* TkDisplay structure that *
  93.   *  represents Windows screen. */
  94.     int updatingClipboard; /* If 1, we are updating the clipboard */
  95. } ThreadSpecificData;
  96. static Tcl_ThreadDataKey dataKey;
  97. /*
  98.  * Forward declarations of procedures used in this file.
  99.  */
  100. static void GenerateXEvent _ANSI_ARGS_((HWND hwnd, UINT message,
  101.     WPARAM wParam, LPARAM lParam));
  102. static unsigned int GetState _ANSI_ARGS_((UINT message, WPARAM wParam,
  103.     LPARAM lParam));
  104. static void  GetTranslatedKey _ANSI_ARGS_((XKeyEvent *xkey));
  105. static void             UpdateInputLanguage _ANSI_ARGS_((int charset));
  106. static int              HandleIMEComposition _ANSI_ARGS_((HWND hwnd,
  107.     LPARAM lParam));
  108. /*
  109.  *----------------------------------------------------------------------
  110.  *
  111.  * TkGetServerInfo --
  112.  *
  113.  * Given a window, this procedure returns information about
  114.  * the window server for that window.  This procedure provides
  115.  * the guts of the "winfo server" command.
  116.  *
  117.  * Results:
  118.  * None.
  119.  *
  120.  * Side effects:
  121.  * None.
  122.  *
  123.  *----------------------------------------------------------------------
  124.  */
  125. void
  126. TkGetServerInfo(interp, tkwin)
  127.     Tcl_Interp *interp; /* The server information is returned in
  128.  * this interpreter's result. */
  129.     Tk_Window tkwin; /* Token for window;  this selects a
  130.  * particular display and server. */
  131. {
  132.     char buffer[60];
  133.     OSVERSIONINFO os;
  134.     os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  135.     GetVersionEx(&os);
  136.     sprintf(buffer, "Windows %d.%d %d %s", os.dwMajorVersion,
  137.     os.dwMinorVersion, os.dwBuildNumber,
  138. #ifdef _WIN64
  139.     "Win64"
  140. #else
  141.     "Win32"
  142. #endif
  143. );
  144.     Tcl_SetResult(interp, buffer, TCL_VOLATILE);
  145. }
  146. /*
  147.  *----------------------------------------------------------------------
  148.  *
  149.  * Tk_GetHINSTANCE --
  150.  *
  151.  * Retrieves the global instance handle used by the Tk library.
  152.  *
  153.  * Results:
  154.  * Returns the global instance handle.
  155.  *
  156.  * Side effects:
  157.  * None.
  158.  *
  159.  *----------------------------------------------------------------------
  160.  */
  161. HINSTANCE
  162. Tk_GetHINSTANCE()
  163. {
  164.     if (tkInstance == NULL) {
  165. tkInstance = GetModuleHandle(NULL);
  166.     }
  167.     return tkInstance;
  168. }
  169. /*
  170.  *----------------------------------------------------------------------
  171.  *
  172.  * TkWinSetHINSTANCE --
  173.  *
  174.  * Sets the global instance handle used by the Tk library.
  175.  * This should be called by DllMain.
  176.  *
  177.  * Results:
  178.  * None.
  179.  *
  180.  * Side effects:
  181.  * None.
  182.  *
  183.  *----------------------------------------------------------------------
  184.  */
  185. void
  186. TkWinSetHINSTANCE(hInstance)
  187.     HINSTANCE hInstance;
  188. {
  189.     tkInstance = hInstance;
  190. }
  191. /*
  192.  *----------------------------------------------------------------------
  193.  *
  194.  * TkWinXInit --
  195.  *
  196.  * Initialize Xlib emulation layer.
  197.  *
  198.  * Results:
  199.  * None.
  200.  *
  201.  * Side effects:
  202.  * Sets up various data structures.
  203.  *
  204.  *----------------------------------------------------------------------
  205.  */
  206. void
  207. TkWinXInit(hInstance)
  208.     HINSTANCE hInstance;
  209. {
  210.     CHARSETINFO lpCs;
  211.     DWORD lpCP;
  212.     if (childClassInitialized != 0) {
  213. return;
  214.     }
  215.     childClassInitialized = 1;
  216.     if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
  217. /*
  218.  * This is necessary to enable the use of themeable elements on XP,
  219.  * so we don't even try and call it for Win9*.
  220.  */
  221. INITCOMMONCONTROLSEX comctl;
  222. ZeroMemory(&comctl, sizeof(comctl));
  223. (void) InitCommonControlsEx(&comctl);
  224. tkWinProcs = &unicodeProcs;
  225.     } else {
  226. tkWinProcs = &asciiProcs;
  227.     }
  228.     childClass.style = CS_HREDRAW | CS_VREDRAW;
  229.     childClass.cbClsExtra = 0;
  230.     childClass.cbWndExtra = 0;
  231.     childClass.hInstance = hInstance;
  232.     childClass.hbrBackground = NULL;
  233.     childClass.lpszMenuName = NULL;
  234.     /*
  235.      * Register the Child window class.
  236.      */
  237.     childClass.lpszClassName = TK_WIN_CHILD_CLASS_NAME;
  238.     childClass.lpfnWndProc = TkWinChildProc;
  239.     childClass.hIcon = NULL;
  240.     childClass.hCursor = NULL;
  241.     if (!RegisterClass(&childClass)) {
  242. panic("Unable to register TkChild class");
  243.     }
  244.     /*
  245.      * Initialize input language info
  246.      */
  247.     if (GetLocaleInfo(LANGIDFROMLCID(GetKeyboardLayout(0)),
  248.        LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
  249.        (LPTSTR) &lpCP, sizeof(lpCP)/sizeof(TCHAR))
  250.     && TranslateCharsetInfo((DWORD *)lpCP, &lpCs, TCI_SRCCODEPAGE)) {
  251. UpdateInputLanguage(lpCs.ciCharset);
  252.     }
  253.     /*
  254.      * Make sure we cleanup on finalize.
  255.      */
  256.     TkCreateExitHandler(TkWinXCleanup, (ClientData) hInstance);
  257. }
  258. /*
  259.  *----------------------------------------------------------------------
  260.  *
  261.  * TkWinXCleanup --
  262.  *
  263.  * Removes the registered classes for Tk.
  264.  *
  265.  * Results:
  266.  * None.
  267.  *
  268.  * Side effects:
  269.  * Removes window classes from the system.
  270.  *
  271.  *----------------------------------------------------------------------
  272.  */
  273. void
  274. TkWinXCleanup(clientData)
  275.     ClientData clientData;
  276. {
  277.     HINSTANCE hInstance = (HINSTANCE) clientData;
  278.     /*
  279.      * Clean up our own class.
  280.      */
  281.     
  282.     if (childClassInitialized) {
  283.         childClassInitialized = 0;
  284.         UnregisterClass(TK_WIN_CHILD_CLASS_NAME, hInstance);
  285.     }
  286.     if (unicodeEncoding != NULL) {
  287. Tcl_FreeEncoding(unicodeEncoding);
  288. unicodeEncoding = NULL;
  289.     }
  290.     /*
  291.      * And let the window manager clean up its own class(es).
  292.      */
  293.     
  294.     TkWinWmCleanup(hInstance);
  295. }
  296. /*
  297.  *----------------------------------------------------------------------
  298.  *
  299.  * TkWinGetPlatformId --
  300.  *
  301.  * Determines whether running under NT, 95, or Win32s, to allow 
  302.  * runtime conditional code.  Win32s is no longer supported.
  303.  *
  304.  * Results:
  305.  * The return value is one of:
  306.  *     VER_PLATFORM_WIN32s Win32s on Windows 3.1. 
  307.  *     VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95.
  308.  *     VER_PLATFORM_WIN32_NT Win32 on Windows NT
  309.  *
  310.  * Side effects:
  311.  * None.
  312.  *
  313.  *----------------------------------------------------------------------
  314.  */
  315. int
  316. TkWinGetPlatformId()
  317. {
  318.     if (tkPlatformId == 0) {
  319. OSVERSIONINFO os;
  320. os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  321. GetVersionEx(&os);
  322. tkPlatformId = os.dwPlatformId;
  323.         
  324.         /* Set tkWinTheme to be TK_THEME_WIN_XP or TK_THEME_WIN_CLASSIC.
  325.          * The TK_THEME_WIN_CLASSIC could be set even when running
  326.          * under XP if the windows classic theme was selected. */
  327. if ((os.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
  328.         (os.dwMajorVersion == 5 && os.dwMinorVersion == 1)) {
  329.     HKEY   hKey;
  330.     LPCSTR szSubKey  = TEXT("Control Panel\Appearance");
  331.     LPCSTR szCurrent = TEXT("Current");
  332.     DWORD  dwSize = 200;
  333.     char pBuffer[200];
  334.     memset(pBuffer, 0, dwSize);
  335.     if (RegOpenKeyEx(HKEY_CURRENT_USER, szSubKey, 0L,
  336.                     KEY_READ, &hKey) != ERROR_SUCCESS) {
  337.                 tkWinTheme = TK_THEME_WIN_XP;
  338.     } else {
  339.         RegQueryValueEx(hKey, szCurrent, NULL, NULL, pBuffer, &dwSize);
  340.         RegCloseKey(hKey);
  341.         if (strcmp(pBuffer, "Windows Standard") == 0) {
  342.             tkWinTheme = TK_THEME_WIN_CLASSIC;
  343.         } else {
  344.             tkWinTheme = TK_THEME_WIN_XP;
  345.         }
  346.     }
  347. } else {
  348.     tkWinTheme = TK_THEME_WIN_CLASSIC;
  349. }
  350.     }
  351.     return tkPlatformId;
  352. }
  353. /*
  354.  *----------------------------------------------------------------------
  355.  *
  356.  * TkWinGetPlatformTheme --
  357.  *
  358.  * Return the Windows drawing style we should be using.
  359.  *
  360.  * Results:
  361.  * The return value is one of:
  362.  *     TK_THEME_WIN_CLASSIC 95/98/NT or XP in classic mode
  363.  *     TK_THEME_WIN_XP                 XP not in classic mode
  364.  *
  365.  * Side effects:
  366.  * Could invoke TkWinGetPlatformId.
  367.  *
  368.  *----------------------------------------------------------------------
  369.  */
  370. int
  371. TkWinGetPlatformTheme()
  372. {
  373.     if (tkPlatformId == 0) {
  374.         TkWinGetPlatformId();
  375.     }
  376.     return tkWinTheme;
  377. }
  378. /*
  379.  *----------------------------------------------------------------------
  380.  *
  381.  * TkGetDefaultScreenName --
  382.  *
  383.  * Returns the name of the screen that Tk should use during
  384.  * initialization.
  385.  *
  386.  * Results:
  387.  * Returns a statically allocated string.
  388.  *
  389.  * Side effects:
  390.  * None.
  391.  *
  392.  *----------------------------------------------------------------------
  393.  */
  394. CONST char *
  395. TkGetDefaultScreenName(interp, screenName)
  396.     Tcl_Interp *interp; /* Not used. */
  397.     CONST char *screenName; /* If NULL, use default string. */
  398. {
  399.     if ((screenName == NULL) || (screenName[0] == '')) {
  400. screenName = winScreenName;
  401.     }
  402.     return screenName;
  403. }
  404. /*
  405.  *----------------------------------------------------------------------
  406.  *
  407.  * TkWinDisplayChanged --
  408.  *
  409.  * Called to set up initial screen info or when an event indicated
  410.  * display (screen) change.
  411.  *
  412.  * Results:
  413.  * None.
  414.  *
  415.  * Side effects:
  416.  * May change info regarding the screen.
  417.  *
  418.  *----------------------------------------------------------------------
  419.  */
  420. void
  421. TkWinDisplayChanged(Display *display)
  422. {
  423.     HDC dc;
  424.     Screen *screen;
  425.     if (display == NULL || display->screens == NULL) {
  426. return;
  427.     }
  428.     screen = display->screens;
  429.     dc = GetDC(NULL);
  430.     screen->width = GetDeviceCaps(dc, HORZRES);
  431.     screen->height = GetDeviceCaps(dc, VERTRES);
  432.     screen->mwidth = MulDiv(screen->width, 254,
  433.     GetDeviceCaps(dc, LOGPIXELSX) * 10);
  434.     screen->mheight = MulDiv(screen->height, 254,
  435.     GetDeviceCaps(dc, LOGPIXELSY) * 10);
  436.     /*
  437.      * On windows, when creating a color bitmap, need two pieces of
  438.      * information: the number of color planes and the number of pixels per
  439.      * plane.  Need to remember both quantities so that when constructing an
  440.      * HBITMAP for offscreen rendering, we can specify the correct value for
  441.      * the number of planes.  Otherwise the HBITMAP won't be compatible with
  442.      * the HWND and we'll just get blank spots copied onto the screen.
  443.      */
  444.     screen->ext_data = (XExtData *) GetDeviceCaps(dc, PLANES);
  445.     screen->root_depth = GetDeviceCaps(dc, BITSPIXEL) * (int) screen->ext_data;
  446.     if (screen->root_visual != NULL) {
  447. ckfree((char *) screen->root_visual);
  448.     }
  449.     screen->root_visual = (Visual *) ckalloc(sizeof(Visual));
  450.     screen->root_visual->visualid = 0;
  451.     if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
  452. screen->root_visual->map_entries = GetDeviceCaps(dc, SIZEPALETTE);
  453. screen->root_visual->class = PseudoColor;
  454. screen->root_visual->red_mask = 0x0;
  455. screen->root_visual->green_mask = 0x0;
  456. screen->root_visual->blue_mask = 0x0;
  457.     } else if (screen->root_depth == 4) {
  458. screen->root_visual->class = StaticColor;
  459. screen->root_visual->map_entries = 16;
  460.     } else if (screen->root_depth == 8) {
  461. screen->root_visual->class = StaticColor;
  462. screen->root_visual->map_entries = 256;
  463.     } else if (screen->root_depth == 12) {
  464. screen->root_visual->class = TrueColor;
  465. screen->root_visual->map_entries = 32;
  466. screen->root_visual->red_mask = 0xf0;
  467. screen->root_visual->green_mask = 0xf000;
  468. screen->root_visual->blue_mask = 0xf00000;
  469.     } else if (screen->root_depth == 16) {
  470. screen->root_visual->class = TrueColor;
  471. screen->root_visual->map_entries = 64;
  472. screen->root_visual->red_mask = 0xf8;
  473. screen->root_visual->green_mask = 0xfc00;
  474. screen->root_visual->blue_mask = 0xf80000;
  475.     } else if (screen->root_depth >= 24) {
  476. screen->root_visual->class = TrueColor;
  477. screen->root_visual->map_entries = 256;
  478. screen->root_visual->red_mask = 0xff;
  479. screen->root_visual->green_mask = 0xff00;
  480. screen->root_visual->blue_mask = 0xff0000;
  481.     }
  482.     screen->root_visual->bits_per_rgb = screen->root_depth;
  483.     ReleaseDC(NULL, dc);
  484.     if (screen->cmap != None) {
  485. XFreeColormap(display, screen->cmap);
  486.     }
  487.     screen->cmap = XCreateColormap(display, None, screen->root_visual,
  488.     AllocNone);
  489. }
  490. /*
  491.  *----------------------------------------------------------------------
  492.  *
  493.  * TkpOpenDisplay --
  494.  *
  495.  * Create the Display structure and fill it with device
  496.  * specific information.
  497.  *
  498.  * Results:
  499.  * Returns a TkDisplay structure on success or NULL on failure.
  500.  *
  501.  * Side effects:
  502.  * Allocates a new TkDisplay structure.
  503.  *
  504.  *----------------------------------------------------------------------
  505.  */
  506. TkDisplay *
  507. TkpOpenDisplay(display_name)
  508.     CONST char *display_name;
  509. {
  510.     Screen *screen;
  511.     TkWinDrawable *twdPtr;
  512.     Display *display;
  513.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  514.     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  515.     if (tsdPtr->winDisplay != NULL) {
  516. if (strcmp(tsdPtr->winDisplay->display->display_name, display_name) 
  517.                 == 0) {
  518.     return tsdPtr->winDisplay;
  519. } else {
  520.     return NULL;
  521. }
  522.     }
  523.     display = (Display *) ckalloc(sizeof(Display));
  524.     ZeroMemory(display, sizeof(Display));
  525.     display->display_name = (char *) ckalloc(strlen(display_name)+1);
  526.     strcpy(display->display_name, display_name);
  527.     display->cursor_font = 1;
  528.     display->nscreens    = 1;
  529.     display->request     = 1;
  530.     display->qlen        = 0;
  531.     screen = (Screen *) ckalloc(sizeof(Screen));
  532.     ZeroMemory(screen, sizeof(Screen));
  533.     screen->display = display;
  534.     /*
  535.      * Set up the root window.
  536.      */
  537.     twdPtr = (TkWinDrawable*) ckalloc(sizeof(TkWinDrawable));
  538.     if (twdPtr == NULL) {
  539. return None;
  540.     }
  541.     twdPtr->type = TWD_WINDOW;
  542.     twdPtr->window.winPtr = NULL;
  543.     twdPtr->window.handle = NULL;
  544.     screen->root = (Window)twdPtr;
  545.     /*
  546.      * Note that these pixel values are not palette relative.
  547.      */
  548.     screen->white_pixel = RGB(255, 255, 255);
  549.     screen->black_pixel = RGB(0, 0, 0);
  550.     screen->cmap        = None;
  551.     display->screens = screen;
  552.     display->nscreens = 1;
  553.     display->default_screen = 0;
  554.     TkWinDisplayChanged(display);
  555.     tsdPtr->winDisplay = (TkDisplay *) ckalloc(sizeof(TkDisplay));
  556.     ZeroMemory(tsdPtr->winDisplay, sizeof(TkDisplay));
  557.     tsdPtr->winDisplay->display = display;
  558.     tsdPtr->updatingClipboard = FALSE;
  559.     return tsdPtr->winDisplay;
  560. }
  561. /*
  562.  *----------------------------------------------------------------------
  563.  *
  564.  * TkpCloseDisplay --
  565.  *
  566.  * Closes and deallocates a Display structure created with the
  567.  * TkpOpenDisplay function.
  568.  *
  569.  * Results:
  570.  * None.
  571.  *
  572.  * Side effects:
  573.  * Frees up memory.
  574.  *
  575.  *----------------------------------------------------------------------
  576.  */
  577. void
  578. TkpCloseDisplay(dispPtr)
  579.     TkDisplay *dispPtr;
  580. {
  581.     Display *display = dispPtr->display;
  582.     HWND hwnd;
  583.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  584.     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  585.     if (dispPtr != tsdPtr->winDisplay) {
  586.         panic("TkpCloseDisplay: tried to call TkpCloseDisplay on another display");
  587.         return;
  588.     }
  589.     /*
  590.      * Force the clipboard to be rendered if we are the clipboard owner.
  591.      */
  592.     
  593.     if (dispPtr->clipWindow) {
  594. hwnd = Tk_GetHWND(Tk_WindowId(dispPtr->clipWindow));
  595. if (GetClipboardOwner() == hwnd) {
  596.     OpenClipboard(hwnd);
  597.     EmptyClipboard();
  598.     TkWinClipboardRender(dispPtr, CF_TEXT);
  599.     CloseClipboard();
  600. }
  601.     }
  602.     tsdPtr->winDisplay = NULL;
  603.     if (display->display_name != (char *) NULL) {
  604.         ckfree(display->display_name);
  605.     }
  606.     if (display->screens != (Screen *) NULL) {
  607.         if (display->screens->root_visual != NULL) {
  608.             ckfree((char *) display->screens->root_visual);
  609.         }
  610.         if (display->screens->root != None) {
  611.             ckfree((char *) display->screens->root);
  612.         }
  613.         if (display->screens->cmap != None) {
  614.             XFreeColormap(display, display->screens->cmap);
  615.         }
  616.         ckfree((char *) display->screens);
  617.     }
  618.     ckfree((char *) display);
  619. }
  620. /*
  621.  *----------------------------------------------------------------------
  622.  *
  623.  * TkClipCleanup --
  624.  *
  625.  * This procedure is called to cleanup resources associated with
  626.  * claiming clipboard ownership and for receiving selection get
  627.  * results.  This function is called in tkWindow.c.  This has to be
  628.  * called by the display cleanup function because we still need the
  629.  * access display elements.
  630.  *
  631.  * Results:
  632.  * None.
  633.  *
  634.  * Side effects:
  635.  * Resources are freed - the clipboard may no longer be used.
  636.  *
  637.  *----------------------------------------------------------------------
  638.  */
  639. void
  640. TkClipCleanup(dispPtr)
  641.     TkDisplay *dispPtr; /* display associated with clipboard */
  642. {
  643.     if (dispPtr->clipWindow != NULL) {
  644. /*
  645.  * Force the clipboard to be rendered if we are the clipboard owner.
  646.  */
  647. HWND hwnd = Tk_GetHWND(Tk_WindowId(dispPtr->clipWindow));
  648. if (GetClipboardOwner() == hwnd) {
  649.     OpenClipboard(hwnd);
  650.     EmptyClipboard();
  651.     TkWinClipboardRender(dispPtr, CF_TEXT);
  652.     CloseClipboard();
  653. }
  654. Tk_DeleteSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
  655. dispPtr->applicationAtom);
  656. Tk_DeleteSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
  657. dispPtr->windowAtom);
  658. Tk_DestroyWindow(dispPtr->clipWindow);
  659. Tcl_Release((ClientData) dispPtr->clipWindow);
  660. dispPtr->clipWindow = NULL;
  661.     }
  662. }
  663. /*
  664.  *----------------------------------------------------------------------
  665.  *
  666.  * XBell --
  667.  *
  668.  * Generate a beep.
  669.  *
  670.  * Results:
  671.  * None.
  672.  *
  673.  * Side effects:
  674.  * Plays a sounds out the system speakers.
  675.  *
  676.  *----------------------------------------------------------------------
  677.  */
  678. void
  679. XBell(display, percent)
  680.     Display* display;
  681.     int percent;
  682. {
  683.     MessageBeep(MB_OK);
  684. }
  685. /*
  686.  *----------------------------------------------------------------------
  687.  *
  688.  * TkWinChildProc --
  689.  *
  690.  * Callback from Windows whenever an event occurs on a child
  691.  * window.
  692.  *
  693.  * Results:
  694.  * Standard Windows return value.
  695.  *
  696.  * Side effects:
  697.  * May process events off the Tk event queue.
  698.  *
  699.  *----------------------------------------------------------------------
  700.  */
  701. LRESULT CALLBACK
  702. TkWinChildProc(hwnd, message, wParam, lParam)
  703.     HWND hwnd;
  704.     UINT message;
  705.     WPARAM wParam;
  706.     LPARAM lParam;
  707. {
  708.     LRESULT result;
  709.     switch (message) {
  710.         case WM_INPUTLANGCHANGE:
  711.     UpdateInputLanguage(wParam);
  712.     result = 1;
  713.     break;
  714.         case WM_IME_COMPOSITION:
  715.             result = 0;
  716.             if (HandleIMEComposition(hwnd, lParam) == 0) {
  717.                 result = DefWindowProc(hwnd, message, wParam, lParam);
  718.             }
  719.             break;
  720. case WM_SETCURSOR:
  721.     /*
  722.      * Short circuit the WM_SETCURSOR message since we set
  723.      * the cursor elsewhere.
  724.      */
  725.     result = TRUE;
  726.     break;
  727. case WM_CREATE:
  728. case WM_ERASEBKGND:
  729.     result = 0;
  730.     break;
  731. case WM_PAINT:
  732.     GenerateXEvent(hwnd, message, wParam, lParam);
  733.     result = DefWindowProc(hwnd, message, wParam, lParam);
  734.     break;
  735.         case TK_CLAIMFOCUS:
  736. case TK_GEOMETRYREQ:
  737. case TK_ATTACHWINDOW:
  738. case TK_DETACHWINDOW:
  739.     result =  TkWinEmbeddedEventProc(hwnd, message, wParam, lParam);
  740.     break;
  741. case WM_UNICHAR: 
  742.     if (wParam == UNICODE_NOCHAR) {
  743. /* If wParam is UNICODE_NOCHAR and the application processes
  744.  * this message, then return TRUE. */
  745. result = 1;
  746.     } else {
  747. /* If the event was translated, we must return 0 */
  748. if (Tk_TranslateWinEvent(hwnd, message, wParam, lParam,
  749.     &result)) {
  750.     result = 0;
  751. } else {
  752.     result = 1;
  753. }
  754.     }
  755.     break;
  756. default:
  757.     if (!Tk_TranslateWinEvent(hwnd, message, wParam, lParam,
  758.     &result)) {
  759. result = DefWindowProc(hwnd, message, wParam, lParam);
  760.     }
  761.     break;
  762.     }
  763.     /*
  764.      * Handle any newly queued events before returning control to Windows.
  765.      */
  766.     Tcl_ServiceAll();
  767.     return result;
  768. }
  769. /*
  770.  *----------------------------------------------------------------------
  771.  *
  772.  * Tk_TranslateWinEvent --
  773.  *
  774.  * This function is called by widget window procedures to handle
  775.  * the translation from Win32 events to Tk events.
  776.  *
  777.  * Results:
  778.  * Returns 1 if the event was handled, else 0.
  779.  *
  780.  * Side effects:
  781.  * Depends on the event.
  782.  *
  783.  *----------------------------------------------------------------------
  784.  */
  785. int
  786. Tk_TranslateWinEvent(hwnd, message, wParam, lParam, resultPtr)
  787.     HWND hwnd;
  788.     UINT message;
  789.     WPARAM wParam;
  790.     LPARAM lParam;
  791.     LRESULT *resultPtr;
  792. {
  793.     *resultPtr = 0;
  794.     switch (message) {
  795. case WM_RENDERFORMAT: {
  796.     TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd);
  797.     if (winPtr) {
  798. TkWinClipboardRender(winPtr->dispPtr, wParam);
  799.     }
  800.     return 1;
  801. }
  802. case WM_COMMAND:
  803. case WM_NOTIFY:
  804. case WM_VSCROLL:
  805. case WM_HSCROLL: {
  806.     /*
  807.      * Reflect these messages back to the sender so that they
  808.      * can be handled by the window proc for the control.  Note
  809.      * that we need to be careful not to reflect a message that
  810.      * is targeted to this window, or we will loop.
  811.      */
  812.     HWND target = (message == WM_NOTIFY)
  813. ? ((NMHDR*)lParam)->hwndFrom : (HWND) lParam;
  814.     if (target && target != hwnd) {
  815. *resultPtr = SendMessage(target, message, wParam, lParam);
  816. return 1;
  817.     }
  818.     break;
  819. }
  820. case WM_LBUTTONDOWN:
  821. case WM_LBUTTONDBLCLK:
  822. case WM_MBUTTONDOWN:
  823. case WM_MBUTTONDBLCLK:
  824. case WM_RBUTTONDOWN:
  825. case WM_RBUTTONDBLCLK:
  826. case WM_LBUTTONUP:
  827. case WM_MBUTTONUP:
  828. case WM_RBUTTONUP:
  829. case WM_MOUSEMOVE:
  830.     Tk_PointerEvent(hwnd, (short) LOWORD(lParam),
  831.     (short) HIWORD(lParam));
  832.     return 1;
  833. case WM_CLOSE:
  834. case WM_SETFOCUS:
  835. case WM_KILLFOCUS:
  836. case WM_DESTROYCLIPBOARD:
  837. case WM_UNICHAR:
  838. case WM_CHAR:
  839. case WM_SYSKEYDOWN:
  840. case WM_SYSKEYUP:
  841. case WM_KEYDOWN:
  842. case WM_KEYUP:
  843. case WM_MOUSEWHEEL:
  844.       GenerateXEvent(hwnd, message, wParam, lParam);
  845.     return 1;
  846. case WM_MENUCHAR:
  847.     GenerateXEvent(hwnd, message, wParam, lParam);
  848.     /* MNC_CLOSE is the only one that looks right.  This is a hack. */
  849.     *resultPtr = MAKELONG (0, MNC_CLOSE);
  850.     return 1;
  851.     }
  852.     return 0;
  853. }
  854. /*
  855.  *----------------------------------------------------------------------
  856.  *
  857.  * GenerateXEvent --
  858.  *
  859.  * This routine generates an X event from the corresponding
  860.  *  Windows event.
  861.  *
  862.  * Results:
  863.  * None.
  864.  *
  865.  * Side effects:
  866.  * Queues one or more X events.
  867.  *
  868.  *----------------------------------------------------------------------
  869.  */
  870. static void
  871. GenerateXEvent(hwnd, message, wParam, lParam)
  872.     HWND hwnd;
  873.     UINT message;
  874.     WPARAM wParam;
  875.     LPARAM lParam;
  876. {
  877.     XEvent event;
  878.     TkWindow *winPtr = (TkWindow *)Tk_HWNDToWindow(hwnd);
  879.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  880.     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  881.     if (!winPtr || winPtr->window == None) {
  882. return;
  883.     }
  884.     event.xany.serial = winPtr->display->request++;
  885.     event.xany.send_event = False;
  886.     event.xany.display = winPtr->display;
  887.     event.xany.window = winPtr->window;
  888.     switch (message) {
  889. case WM_PAINT: {
  890.     PAINTSTRUCT ps;
  891.     event.type = Expose;
  892.     BeginPaint(hwnd, &ps);
  893.     event.xexpose.x = ps.rcPaint.left;
  894.     event.xexpose.y = ps.rcPaint.top;
  895.     event.xexpose.width = ps.rcPaint.right - ps.rcPaint.left;
  896.     event.xexpose.height = ps.rcPaint.bottom - ps.rcPaint.top;
  897.     EndPaint(hwnd, &ps);
  898.     event.xexpose.count = 0;
  899.     break;
  900. }
  901. case WM_CLOSE:
  902.     event.type = ClientMessage;
  903.     event.xclient.message_type =
  904. Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS");
  905.     event.xclient.format = 32;
  906.     event.xclient.data.l[0] =
  907. Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW");
  908.     break;
  909. case WM_SETFOCUS:
  910. case WM_KILLFOCUS: {
  911.     TkWindow *otherWinPtr = (TkWindow *)Tk_HWNDToWindow((HWND) wParam);
  912.     /*
  913.      * Compare toplevel windows to avoid reporting focus
  914.      * changes within the same toplevel.
  915.      */
  916.     while (!(winPtr->flags & TK_TOP_LEVEL)) {
  917. winPtr = winPtr->parentPtr;
  918. if (winPtr == NULL) {
  919.     return;
  920. }
  921.     }
  922.     while (otherWinPtr && !(otherWinPtr->flags & TK_TOP_LEVEL)) {
  923. otherWinPtr = otherWinPtr->parentPtr;
  924.     }
  925.     /*
  926.      * Do a catch-all Tk_SetCaretPos here to make sure that the
  927.      * window receiving focus sets the caret at least once.
  928.      */
  929.     if (message == WM_SETFOCUS) {
  930. Tk_SetCaretPos((Tk_Window) winPtr, 0, 0, 0);
  931.     }
  932.     if (otherWinPtr == winPtr) {
  933. return;
  934.     }
  935.     event.xany.window = winPtr->window;
  936.     event.type = (message == WM_SETFOCUS) ? FocusIn : FocusOut;
  937.     event.xfocus.mode = NotifyNormal;
  938.     event.xfocus.detail = NotifyNonlinear;
  939.     /*
  940.      * Destroy the caret if we own it.  If we are moving to another Tk
  941.      * window, it will reclaim and reposition it with Tk_SetCaretPos.
  942.      */
  943.     if (message == WM_KILLFOCUS) {
  944. DestroyCaret();
  945.     }
  946.     break;
  947. }
  948. case WM_DESTROYCLIPBOARD:
  949.     if (tsdPtr->updatingClipboard == TRUE) {
  950. /*
  951.  * We want to avoid this event if we are the ones that caused
  952.  * this event.
  953.  */
  954. return;
  955.     }
  956.     event.type = SelectionClear;
  957.     event.xselectionclear.selection =
  958. Tk_InternAtom((Tk_Window)winPtr, "CLIPBOARD");
  959.     event.xselectionclear.time = TkpGetMS();
  960.     break;
  961. case WM_MOUSEWHEEL:
  962.     /*
  963.      * The mouse wheel event is closer to a key event than a
  964.      * mouse event in that the message is sent to the window
  965.      * that has focus.
  966.      */
  967. case WM_CHAR:
  968. case WM_UNICHAR:
  969. case WM_SYSKEYDOWN:
  970. case WM_SYSKEYUP:
  971. case WM_KEYDOWN:
  972. case WM_KEYUP: {
  973.     unsigned int state = GetState(message, wParam, lParam);
  974.     Time time = TkpGetMS();
  975.     POINT clientPoint;
  976.     POINTS rootPoint; /* Note: POINT and POINTS are different */
  977.     DWORD msgPos;
  978.     /*
  979.      * Compute the screen and window coordinates of the event.
  980.      */
  981.     msgPos = GetMessagePos();
  982.     rootPoint = MAKEPOINTS(msgPos);
  983.     clientPoint.x = rootPoint.x;
  984.     clientPoint.y = rootPoint.y;
  985.     ScreenToClient(hwnd, &clientPoint);
  986.     /*
  987.      * Set up the common event fields.
  988.      */
  989.     event.xbutton.root = RootWindow(winPtr->display,
  990.     winPtr->screenNum);
  991.     event.xbutton.subwindow = None;
  992.     event.xbutton.x = clientPoint.x;
  993.     event.xbutton.y = clientPoint.y;
  994.     event.xbutton.x_root = rootPoint.x;
  995.     event.xbutton.y_root = rootPoint.y;
  996.     event.xbutton.state = state;
  997.     event.xbutton.time = time;
  998.     event.xbutton.same_screen = True;
  999.     /*
  1000.      * Now set up event specific fields.
  1001.      */
  1002.     switch (message) {
  1003. case WM_MOUSEWHEEL:
  1004.     /*
  1005.      * We have invented a new X event type to handle
  1006.      * this event.  It still uses the KeyPress struct.
  1007.      * However, the keycode field has been overloaded
  1008.      * to hold the zDelta of the wheel.  Set nbytes to 0
  1009.      * to prevent conversion of the keycode to a keysym
  1010.      * in TkpGetString. [Bug 1118340].
  1011.      */
  1012.     event.type = MouseWheelEvent;
  1013.     event.xany.send_event = -1;
  1014.     event.xkey.nbytes = 0;
  1015.     event.xkey.keycode = (short) HIWORD(wParam);
  1016.     break;
  1017. case WM_SYSKEYDOWN:
  1018. case WM_KEYDOWN:
  1019.     /*
  1020.      * Check for translated characters in the event queue.
  1021.      * Setting xany.send_event to -1 indicates to the
  1022.      * Windows implementation of TkpGetString() that this
  1023.      * event was generated by windows and that the Windows
  1024.      * extension xkey.trans_chars is filled with the
  1025.      * MBCS characters that came from the TranslateMessage
  1026.      * call.
  1027.      */
  1028.     event.type = KeyPress;
  1029.     event.xany.send_event = -1;
  1030.     event.xkey.keycode = wParam;
  1031.     GetTranslatedKey(&event.xkey);
  1032.     break;
  1033. case WM_SYSKEYUP:
  1034. case WM_KEYUP:
  1035.     /*
  1036.      * We don't check for translated characters on keyup
  1037.      * because Tk won't know what to do with them.  Instead, we
  1038.      * wait for the WM_CHAR messages which will follow.
  1039.      */
  1040.     event.type = KeyRelease;
  1041.     event.xkey.keycode = wParam;
  1042.     event.xkey.nbytes = 0;
  1043.     break;
  1044. case WM_CHAR:
  1045.     /*
  1046.      * Synthesize both a KeyPress and a KeyRelease.
  1047.      * Strings generated by Input Method Editor are handled
  1048.      * in the following manner:
  1049.      * 1. A series of WM_KEYDOWN & WM_KEYUP messages that 
  1050.      *    cause GetTranslatedKey() to be called and return
  1051.      *    immediately because the WM_KEYDOWNs have no 
  1052.      *   associated WM_CHAR messages -- the IME window is 
  1053.      *   accumulating the characters and translating them 
  1054.      *    itself.  In the "bind" command, you get an event
  1055.      *   with a mystery keysym and %A == "" for each 
  1056.      *   WM_KEYDOWN that actually was meant for the IME.
  1057.      * 2. A WM_KEYDOWN corresponding to the "confirm typing"
  1058.      *    character.  This causes GetTranslatedKey() to be 
  1059.      *   called.
  1060.      * 3. A WM_IME_NOTIFY message saying that the IME is 
  1061.      *   done.  A side effect of this message is that 
  1062.      *    GetTranslatedKey() thinks this means that there
  1063.      *   are no WM_CHAR messages and returns immediately.
  1064.      *    In the "bind" command, you get an another event
  1065.      *   with a mystery keysym and %A == "".
  1066.      * 4. A sequence of WM_CHAR messages that correspond to 
  1067.      *   the characters in the IME window.  A bunch of 
  1068.      *    simulated KeyPress/KeyRelease events will be 
  1069.      *    generated, one for each character.  Adjacent 
  1070.      *    WM_CHAR messages may actually specify the high
  1071.      *   and low bytes of a multi-byte character -- in that
  1072.      *    case the two WM_CHAR messages will be combined into
  1073.      *   one event.  It is the event-consumer's 
  1074.      *   responsibility to convert the string returned from
  1075.      *   XLookupString from system encoding to UTF-8.
  1076.      * 5. And finally we get the WM_KEYUP for the "confirm
  1077.      *    typing" character.
  1078.      */
  1079.     event.type = KeyPress;
  1080.     event.xany.send_event = -1;
  1081.     event.xkey.keycode = 0;
  1082.     event.xkey.nbytes = 1;
  1083.     event.xkey.trans_chars[0] = (char) wParam;
  1084.     if (IsDBCSLeadByte((BYTE) wParam)) {
  1085. MSG msg;
  1086. if ((PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) != 0)
  1087. && (msg.message == WM_CHAR)) {
  1088.     GetMessage(&msg, NULL, 0, 0);
  1089.     event.xkey.nbytes = 2;
  1090.     event.xkey.trans_chars[1] = (char) msg.wParam;
  1091. }
  1092.     }
  1093.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  1094.     event.type = KeyRelease;
  1095.     break;
  1096. case WM_UNICHAR: {
  1097.     char buffer[TCL_UTF_MAX+1];
  1098.     int i;
  1099.     event.type = KeyPress;
  1100.     event.xany.send_event = -3;
  1101.     event.xkey.keycode = wParam;
  1102.     event.xkey.nbytes = Tcl_UniCharToUtf(wParam, buffer);
  1103.     for (i=0; i<event.xkey.nbytes && i<TCL_UTF_MAX; ++i) {
  1104. event.xkey.trans_chars[i] = buffer[i];
  1105.     }
  1106.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  1107.     event.type = KeyRelease;
  1108.     break;
  1109. }
  1110.     }
  1111.     break;
  1112. }
  1113. default:
  1114.     return;
  1115.     }
  1116.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  1117. }
  1118. /*
  1119.  *----------------------------------------------------------------------
  1120.  *
  1121.  * GetState --
  1122.  *
  1123.  * This function constructs a state mask for the mouse buttons 
  1124.  * and modifier keys as they were before the event occured.
  1125.  *
  1126.  * Results:
  1127.  * Returns a composite value of all the modifier and button state
  1128.  * flags that were set at the time the event occurred.
  1129.  *
  1130.  * Side effects:
  1131.  * None.
  1132.  *
  1133.  *----------------------------------------------------------------------
  1134.  */
  1135. static unsigned int
  1136. GetState(message, wParam, lParam)
  1137.     UINT message; /* Win32 message type */
  1138.     WPARAM wParam; /* wParam of message, used if key message */
  1139.     LPARAM lParam; /* lParam of message, used if key message */
  1140. {
  1141.     int mask;
  1142.     int prevState; /* 1 if key was previously down */
  1143.     unsigned int state = TkWinGetModifierState();
  1144.     /*
  1145.      * If the event is a key press or release, we check for modifier
  1146.      * keys so we can report the state of the world before the event.
  1147.      */
  1148.     if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN
  1149.     || message == WM_SYSKEYUP || message == WM_KEYUP) {
  1150. mask = 0;
  1151. prevState = HIWORD(lParam) & KF_REPEAT;
  1152. switch(wParam) {
  1153.     case VK_SHIFT:
  1154. mask = ShiftMask;
  1155. break;
  1156.     case VK_CONTROL:
  1157. mask = ControlMask;
  1158. break;
  1159.     case VK_MENU:
  1160. mask = ALT_MASK;
  1161. break;
  1162.     case VK_CAPITAL:
  1163. if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) {
  1164.     mask = LockMask;
  1165.     prevState = ((state & mask) ^ prevState) ? 0 : 1;
  1166. }
  1167. break;
  1168.     case VK_NUMLOCK:
  1169. if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) {
  1170.     mask = Mod1Mask;
  1171.     prevState = ((state & mask) ^ prevState) ? 0 : 1;
  1172. }
  1173. break;
  1174.     case VK_SCROLL:
  1175. if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) {
  1176.     mask = Mod3Mask;
  1177.     prevState = ((state & mask) ^ prevState) ? 0 : 1;
  1178. }
  1179. break;
  1180. }
  1181. if (prevState) {
  1182.     state |= mask;
  1183. } else {
  1184.     state &= ~mask;
  1185. }
  1186.     }
  1187.     return state;
  1188. }
  1189. /*
  1190.  *----------------------------------------------------------------------
  1191.  *
  1192.  * GetTranslatedKey --
  1193.  *
  1194.  * Retrieves WM_CHAR messages that are placed on the system queue
  1195.  * by the TranslateMessage system call and places them in the
  1196.  * given KeyPress event.
  1197.  *
  1198.  * Results:
  1199.  * Sets the trans_chars and nbytes member of the key event.
  1200.  *
  1201.  * Side effects:
  1202.  * Removes any WM_CHAR messages waiting on the top of the system
  1203.  * event queue.
  1204.  *
  1205.  *----------------------------------------------------------------------
  1206.  */
  1207. static void
  1208. GetTranslatedKey(xkey)
  1209.     XKeyEvent *xkey;
  1210. {
  1211.     MSG msg;
  1212.     
  1213.     xkey->nbytes = 0;
  1214.     while ((xkey->nbytes < XMaxTransChars)
  1215.     && PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
  1216. if ((msg.message == WM_CHAR) || (msg.message == WM_SYSCHAR)) {
  1217.     GetMessage(&msg, NULL, 0, 0);
  1218.     /*
  1219.      * If this is a normal character message, we may need to strip
  1220.      * off the Alt modifier (e.g. Alt-digits).  Note that we don't
  1221.      * want to do this for system messages, because those were
  1222.      * presumably generated as an Alt-char sequence (e.g. accelerator
  1223.      * keys).
  1224.      */
  1225.     if ((msg.message == WM_CHAR) && (msg.lParam & 0x20000000)) {
  1226. xkey->state = 0;
  1227.     }
  1228.     xkey->trans_chars[xkey->nbytes] = (char) msg.wParam;
  1229.     xkey->nbytes++;
  1230.     if (((unsigned short) msg.wParam) > ((unsigned short) 0xff)) {
  1231.                 /*
  1232.                  * Some "addon" input devices, such as the popular
  1233.                  * PenPower Chinese writing pad, generate 16 bit
  1234.                  * values in WM_CHAR messages (instead of passing them
  1235.                  * in two separate WM_CHAR messages containing two
  1236.                  * 8-bit values.
  1237.                  */
  1238.         xkey->trans_chars[xkey->nbytes] = (char) (msg.wParam >> 8);
  1239.         xkey->nbytes ++;
  1240.     }
  1241. } else {
  1242.     break;
  1243. }
  1244.     }
  1245. }
  1246. /*
  1247.  *----------------------------------------------------------------------
  1248.  *
  1249.  * UpdateInputLanguage --
  1250.  *
  1251.  * Gets called when a WM_INPUTLANGCHANGE message is received by the Tk
  1252.  * child window procedure. This message is sent by the Input Method
  1253.  * Editor system when the user chooses a different input method. All
  1254.  * subsequent WM_CHAR messages will contain characters in the new
  1255.  * encoding. We record the new encoding so that TkpGetString() knows how
  1256.  * to correctly translate the WM_CHAR into unicode.
  1257.  *
  1258.  * Results:
  1259.  * Records the new encoding in keyInputEncoding.
  1260.  *
  1261.  * Side effects:
  1262.  * Old value of keyInputEncoding is freed.
  1263.  *
  1264.  *----------------------------------------------------------------------
  1265.  */
  1266. static void
  1267. UpdateInputLanguage(charset)
  1268.     int charset;
  1269. {
  1270.     CHARSETINFO charsetInfo;
  1271.     Tcl_Encoding encoding;
  1272.     char codepage[4 + TCL_INTEGER_SPACE];
  1273.     if (keyInputCharset == charset) {
  1274. return;
  1275.     }
  1276.     if (TranslateCharsetInfo((DWORD*)charset, &charsetInfo, TCI_SRCCHARSET)
  1277.             == 0) {
  1278. /*
  1279.  * Some mysterious failure.
  1280.  */
  1281. return;
  1282.     }
  1283.     wsprintfA(codepage, "cp%d", charsetInfo.ciACP);
  1284.     if ((encoding = Tcl_GetEncoding(NULL, codepage)) == NULL) {
  1285. /*
  1286.  * The encoding is not supported by Tcl.
  1287.  */
  1288. return;
  1289.     }
  1290.     if (keyInputEncoding != NULL) {
  1291. Tcl_FreeEncoding(keyInputEncoding);
  1292.     }
  1293.     keyInputEncoding = encoding;
  1294.     keyInputCharset = charset;
  1295. }
  1296. /*
  1297.  *----------------------------------------------------------------------
  1298.  *
  1299.  * TkWinGetKeyInputEncoding --
  1300.  *
  1301.  * Returns the current keyboard input encoding selected by the
  1302.  *      user (with WM_INPUTLANGCHANGE events).
  1303.  *
  1304.  * Results:
  1305.  * The current keyboard input encoding.
  1306.  *
  1307.  * Side effects:
  1308.  * None.
  1309.  *
  1310.  *----------------------------------------------------------------------
  1311.  */
  1312. Tcl_Encoding
  1313. TkWinGetKeyInputEncoding()
  1314. {
  1315.     return keyInputEncoding;
  1316. }
  1317. /*
  1318.  *----------------------------------------------------------------------
  1319.  *
  1320.  * TkWinGetUnicodeEncoding --
  1321.  *
  1322.  * Returns the cached unicode encoding.
  1323.  *
  1324.  * Results:
  1325.  * The unicode encoding.
  1326.  *
  1327.  * Side effects:
  1328.  * None.
  1329.  *
  1330.  *----------------------------------------------------------------------
  1331.  */
  1332. Tcl_Encoding
  1333. TkWinGetUnicodeEncoding()
  1334. {
  1335.     if (unicodeEncoding == NULL) {
  1336. unicodeEncoding = Tcl_GetEncoding(NULL, "unicode");
  1337.     }
  1338.     return unicodeEncoding;
  1339. }
  1340. /*
  1341.  *----------------------------------------------------------------------
  1342.  *
  1343.  * HandleIMEComposition --
  1344.  *
  1345.  *      This function works around a definciency in some versions
  1346.  *      of Windows 2000 to make it possible to entry multi-lingual
  1347.  *      characters under all versions of Windows 2000.
  1348.  *
  1349.  *      When an Input Method Editor (IME) is ready to send input
  1350.  *      characters to an application, it sends a WM_IME_COMPOSITION
  1351.  *      message with the GCS_RESULTSTR. However, The DefWindowProc()
  1352.  *      on English Windows 2000 arbitrarily converts all non-Latin-1
  1353.  *      characters in the composition to "?".
  1354.  *
  1355.  *      This function correctly processes the composition data and
  1356.  *      sends the UNICODE values of the composed characters to
  1357.  *      TK's event queue. 
  1358.  *
  1359.  * Results:
  1360.  * If this function has processed the composition data, returns 1.
  1361.  *      Otherwise returns 0.
  1362.  *
  1363.  * Side effects:
  1364.  * Key events are put into the TK event queue.
  1365.  *
  1366.  *----------------------------------------------------------------------
  1367.  */
  1368. static int
  1369. HandleIMEComposition(hwnd, lParam)
  1370.     HWND hwnd;                          /* Window receiving the message. */
  1371.     LPARAM lParam;                      /* Flags for the WM_IME_COMPOSITION
  1372.                                          * message */
  1373. {
  1374.     HIMC hIMC;
  1375.     int i, n;
  1376.     XEvent event;
  1377.     char * buff;
  1378.     TkWindow *winPtr;
  1379.     Tcl_Encoding unicodeEncoding = TkWinGetUnicodeEncoding();
  1380.     BOOL isWinNT = (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT);
  1381.     if ((lParam & GCS_RESULTSTR) == 0) {
  1382.         /*
  1383.          * Composition is not finished yet.
  1384.          */
  1385.         return 0;
  1386.     }
  1387.     hIMC = ImmGetContext(hwnd);
  1388.     if (hIMC) {
  1389. if (isWinNT) {
  1390.     n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
  1391. } else {
  1392.     n = ImmGetCompositionStringA(hIMC, GCS_RESULTSTR, NULL, 0);
  1393. }
  1394.         if ((n > 0) && ((buff = (char *) ckalloc(n)) != NULL)) {
  1395.     if (isWinNT) {
  1396. n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buff, n);
  1397.     } else {
  1398. Tcl_DString utfString, unicodeString;
  1399. n = ImmGetCompositionStringA(hIMC, GCS_RESULTSTR, buff, n);
  1400. Tcl_DStringInit(&utfString);
  1401. Tcl_ExternalToUtfDString(keyInputEncoding, buff, n,
  1402. &utfString);
  1403. Tcl_UtfToExternalDString(unicodeEncoding,
  1404. Tcl_DStringValue(&utfString), -1, &unicodeString);
  1405. i = Tcl_DStringLength(&unicodeString);
  1406. if (n < i) {
  1407.     /*
  1408.      * Only alloc more space if we need, otherwise just
  1409.      * use what we've created.  Don't realloc as that may
  1410.      * copy data we no longer need.
  1411.      */
  1412.     ckfree((char *) buff);
  1413.     buff = (char *) ckalloc(i);
  1414. }
  1415. n = i;
  1416. memcpy(buff, Tcl_DStringValue(&unicodeString), n);
  1417. Tcl_DStringFree(&utfString);
  1418. Tcl_DStringFree(&unicodeString);
  1419.     }
  1420.     /*
  1421.      * Set up the fields pertinent to key event.
  1422.              *
  1423.              * We set send_event to the special value of -2, so that
  1424.              * TkpGetString() in tkWinKey.c knows that trans_chars[]
  1425.              * already contains a UNICODE char and there's no need to
  1426.              * do encoding conversion.
  1427.      */
  1428.             winPtr = (TkWindow *)Tk_HWNDToWindow(hwnd);
  1429.             event.xkey.serial = winPtr->display->request++;
  1430.             event.xkey.send_event = -2;
  1431.             event.xkey.display = winPtr->display;
  1432.             event.xkey.window = winPtr->window;
  1433.     event.xkey.root = RootWindow(winPtr->display, winPtr->screenNum);
  1434.     event.xkey.subwindow = None;
  1435.     event.xkey.state = TkWinGetModifierState();
  1436.     event.xkey.time = TkpGetMS();
  1437.     event.xkey.same_screen = True;
  1438.             event.xkey.keycode = 0;
  1439.             event.xkey.nbytes = 2;
  1440.             for (i=0; i<n;) {
  1441.                 /*
  1442.                  * Simulate a pair of KeyPress and KeyRelease events
  1443.                  * for each UNICODE character in the composition.
  1444.                  */
  1445.                 event.xkey.trans_chars[0] = (char) buff[i++];
  1446.                 event.xkey.trans_chars[1] = (char) buff[i++];
  1447.                 event.type = KeyPress;
  1448.                 Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  1449.                 event.type = KeyRelease;
  1450.                 Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  1451.             }
  1452.             ckfree(buff);
  1453.         }
  1454.         ImmReleaseContext(hwnd, hIMC);
  1455.         return 1;
  1456.     }
  1457.     return 0;
  1458. }
  1459. /*
  1460.  *----------------------------------------------------------------------
  1461.  *
  1462.  * Tk_FreeXId --
  1463.  *
  1464.  * This interface is not needed under Windows.
  1465.  *
  1466.  * Results:
  1467.  * None.
  1468.  *
  1469.  * Side effects:
  1470.  * None.
  1471.  *
  1472.  *----------------------------------------------------------------------
  1473.  */
  1474. void
  1475. Tk_FreeXId(display, xid)
  1476.     Display *display;
  1477.     XID xid;
  1478. {
  1479. }
  1480. /*
  1481.  *----------------------------------------------------------------------
  1482.  *
  1483.  * TkWinResendEvent --
  1484.  *
  1485.  * This function converts an X event into a Windows event and
  1486.  * invokes the specified windo procedure.
  1487.  *
  1488.  * Results:
  1489.  * A standard Windows result.
  1490.  *
  1491.  * Side effects:
  1492.  * Invokes the window procedure
  1493.  *
  1494.  *----------------------------------------------------------------------
  1495.  */
  1496. LRESULT
  1497. TkWinResendEvent(wndproc, hwnd, eventPtr)
  1498.     WNDPROC wndproc;
  1499.     HWND hwnd;
  1500.     XEvent *eventPtr;
  1501. {
  1502.     UINT msg;
  1503.     WPARAM wparam;
  1504.     LPARAM lparam;
  1505.     if (eventPtr->type == ButtonPress) {
  1506. switch (eventPtr->xbutton.button) {
  1507.     case Button1:
  1508. msg = WM_LBUTTONDOWN;
  1509. wparam = MK_LBUTTON;
  1510. break;
  1511.     case Button2:
  1512. msg = WM_MBUTTONDOWN;
  1513. wparam = MK_MBUTTON;
  1514. break;
  1515.     case Button3:
  1516. msg = WM_RBUTTONDOWN;
  1517. wparam = MK_RBUTTON;
  1518. break;
  1519.     default:
  1520. return 0;
  1521. }
  1522. if (eventPtr->xbutton.state & Button1Mask) {
  1523.     wparam |= MK_LBUTTON;
  1524. }
  1525. if (eventPtr->xbutton.state & Button2Mask) {
  1526.     wparam |= MK_MBUTTON;
  1527. }
  1528. if (eventPtr->xbutton.state & Button3Mask) {
  1529.     wparam |= MK_RBUTTON;
  1530. }
  1531. if (eventPtr->xbutton.state & ShiftMask) {
  1532.     wparam |= MK_SHIFT;
  1533. }
  1534. if (eventPtr->xbutton.state & ControlMask) {
  1535.     wparam |= MK_CONTROL;
  1536. }
  1537. lparam = MAKELPARAM((short) eventPtr->xbutton.x,
  1538. (short) eventPtr->xbutton.y);
  1539.     } else {
  1540. return 0;
  1541.     }
  1542.     return CallWindowProc(wndproc, hwnd, msg, wparam, lparam);
  1543. }
  1544. /*
  1545.  *----------------------------------------------------------------------
  1546.  *
  1547.  * TkpGetMS --
  1548.  *
  1549.  * Return a relative time in milliseconds.  It doesn't matter
  1550.  * when the epoch was.
  1551.  *
  1552.  * Results:
  1553.  * Number of milliseconds.
  1554.  *
  1555.  * Side effects:
  1556.  * None.
  1557.  *
  1558.  *----------------------------------------------------------------------
  1559.  */
  1560. unsigned long
  1561. TkpGetMS()
  1562. {
  1563.     return GetTickCount();
  1564. }
  1565. /*
  1566.  *----------------------------------------------------------------------
  1567.  *
  1568.  * TkWinUpdatingClipboard --
  1569.  *
  1570.  *
  1571.  * Results:
  1572.  * Number of milliseconds.
  1573.  *
  1574.  * Side effects:
  1575.  * None.
  1576.  *
  1577.  *----------------------------------------------------------------------
  1578.  */
  1579. void
  1580. TkWinUpdatingClipboard(int mode)
  1581. {
  1582.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  1583.     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  1584.     tsdPtr->updatingClipboard = mode;
  1585. }
  1586. /*
  1587.  *----------------------------------------------------------------------
  1588.  *
  1589.  * Tk_SetCaretPos --
  1590.  *
  1591.  * This enables correct movement of focus in the MS Magnifier, as well
  1592.  * as allowing us to correctly position the IME Window.  The following
  1593.  * Win32 APIs are used to work with MS caret:
  1594.  *
  1595.  * CreateCaret DestroyCaret SetCaretPos GetCaretPos
  1596.  *
  1597.  * Only one instance of caret can be active at any time
  1598.  * (e.g. DestroyCaret API does not take any argument such as handle).
  1599.  * Since do-it-right approach requires to track the create/destroy
  1600.  * caret status all the time in a global scope among windows (or
  1601.  * widgets), we just implement this minimal setup to get the job done.
  1602.  *
  1603.  * Results:
  1604.  * None
  1605.  *
  1606.  * Side effects:
  1607.  * Sets the global Windows caret position.
  1608.  *
  1609.  *----------------------------------------------------------------------
  1610.  */
  1611. void
  1612. Tk_SetCaretPos(Tk_Window tkwin, int x, int y, int height)
  1613. {
  1614.     static HWND caretHWND = NULL;
  1615.     TkCaret *caretPtr = &(((TkWindow *) tkwin)->dispPtr->caret);
  1616.     Window win;
  1617.     /*
  1618.      * Prevent processing anything if the values haven't changed.
  1619.      * Windows only has one display, so we can do this with statics.
  1620.      */
  1621.     if ((caretPtr->winPtr == ((TkWindow *) tkwin))
  1622.     && (caretPtr->x == x) && (caretPtr->y == y)) {
  1623. return;
  1624.     }
  1625.     caretPtr->winPtr = ((TkWindow *) tkwin);
  1626.     caretPtr->x = x;
  1627.     caretPtr->y = y;
  1628.     caretPtr->height = height;
  1629.     /*
  1630.      * We adjust to the toplevel to get the coords right, as setting
  1631.      * the IME composition window is based on the toplevel hwnd, so
  1632.      * ignore height.
  1633.      */
  1634.     while (!Tk_IsTopLevel(tkwin)) {
  1635. x += Tk_X(tkwin);
  1636. y += Tk_Y(tkwin);
  1637. tkwin = Tk_Parent(tkwin);
  1638. if (tkwin == NULL) {
  1639.     return;
  1640. }
  1641.     }
  1642.     win = Tk_WindowId(tkwin);
  1643.     if (win) {
  1644. HIMC hIMC;
  1645. HWND hwnd = Tk_GetHWND(win);
  1646. if (hwnd != caretHWND) {
  1647.     DestroyCaret();
  1648.     if (CreateCaret(hwnd, NULL, 0, 0)) {
  1649. caretHWND = hwnd;
  1650.     }
  1651. }
  1652. if (!SetCaretPos(x, y) && CreateCaret(hwnd, NULL, 0, 0)) {
  1653.     caretHWND = hwnd;
  1654.     SetCaretPos(x, y);
  1655. }
  1656. /*
  1657.  * The IME composition window should be updated whenever the caret
  1658.  * position is changed because a clause of the composition string may
  1659.  * be converted to the final characters and the other clauses still
  1660.  * stay on the composition window.  -- yamamoto
  1661.  */
  1662. hIMC = ImmGetContext(hwnd);
  1663. if (hIMC) {
  1664.     COMPOSITIONFORM cform;
  1665.     cform.dwStyle = CFS_POINT;
  1666.     cform.ptCurrentPos.x = x;
  1667.     cform.ptCurrentPos.y = y;
  1668.     ImmSetCompositionWindow(hIMC, &cform);
  1669.     ImmReleaseContext(hwnd, hIMC);
  1670. }
  1671.     }
  1672. }