home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / win / tkWinX.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-21  |  25.3 KB  |  1,050 lines

  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.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkWinX.c 1.27 96/04/11 17:50:13
  13.  */
  14.  
  15. #include "tkInt.h"
  16. #include "tkWinInt.h"
  17.  
  18. /*
  19.  * The following declaration is a special purpose backdoor into the
  20.  * Tcl notifier.  It is used to process events on the Tcl event queue,
  21.  * without reentering the system event queue.
  22.  */
  23.  
  24. extern void        TclWinFlushEvents _ANSI_ARGS_((void));
  25.  
  26. /*
  27.  * Declarations of static variables used in this file.
  28.  */
  29.  
  30. static HINSTANCE appInstance = (HINSTANCE) NULL;
  31.                 /* Global application instance handle. */
  32. static Display *winDisplay;    /* Display that represents Windows screen. */
  33. static Tcl_HashTable windowTable;
  34.                 /* Table of child windows indexed by handle. */
  35. static char winScreenName[] = ":0";
  36.                 /* Default name of windows display. */
  37. static ATOM topLevelAtom, childAtom;
  38.                 /* Atoms for the classes registered by Tk. */
  39.  
  40. /*
  41.  * Forward declarations of procedures used in this file.
  42.  */
  43.  
  44. static void        DeleteWindow _ANSI_ARGS_((HWND hwnd));
  45. static void         GetTranslatedKey _ANSI_ARGS_((XKeyEvent *xkey));
  46. static void         TranslateEvent _ANSI_ARGS_((HWND hwnd, UINT message,
  47.                 WPARAM wParam, LPARAM lParam));
  48.  
  49. /*
  50.  *----------------------------------------------------------------------
  51.  *
  52.  * TkGetServerInfo --
  53.  *
  54.  *    Given a window, this procedure returns information about
  55.  *    the window server for that window.  This procedure provides
  56.  *    the guts of the "winfo server" command.
  57.  *
  58.  * Results:
  59.  *    None.
  60.  *
  61.  * Side effects:
  62.  *    None.
  63.  *
  64.  *----------------------------------------------------------------------
  65.  */
  66.  
  67. void
  68. TkGetServerInfo(interp, tkwin)
  69.     Tcl_Interp *interp;        /* The server information is returned in
  70.                  * this interpreter's result. */
  71.     Tk_Window tkwin;        /* Token for window;  this selects a
  72.                  * particular display and server. */
  73. {
  74.     char buffer[50];
  75.     OSVERSIONINFO info;
  76.     int index = 0;
  77.     static char* os[] = {"Win32", "Win32s", "Win32c"};
  78.  
  79.     info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  80.     GetVersionEx(&info);
  81.     if (info.dwPlatformId == VER_PLATFORM_WIN32s) {
  82.     index = 1;
  83.     } else if (info.dwPlatformId == VER_PLATFORM_WIN32s) {
  84.     index = 2;
  85.     }
  86.     sprintf(buffer, "Windows %d.%d %d ", info.dwMajorVersion,
  87.         info.dwMinorVersion, info.dwBuildNumber);
  88.     Tcl_AppendResult(interp, buffer, os[index], (char *) NULL);
  89. }
  90.  
  91. /*
  92.  *----------------------------------------------------------------------
  93.  *
  94.  * TkWinGetTkModule --
  95.  *
  96.  *    This function returns the module handle for the Tk DLL.
  97.  *
  98.  * Results:
  99.  *    Returns the library module handle.
  100.  *
  101.  * Side effects:
  102.  *    None.
  103.  *
  104.  *----------------------------------------------------------------------
  105.  */
  106.  
  107. HMODULE
  108. TkWinGetTkModule()
  109. {
  110. #ifdef STk_CODE
  111.   return GetModuleHandle("stk.exe");
  112. #else
  113.     char libName[13];
  114.     sprintf(libName, "tk%d%d.dll", TK_MAJOR_VERSION, TK_MINOR_VERSION);
  115.     return GetModuleHandle(libName);
  116. #endif
  117. }
  118.  
  119. /*
  120.  *----------------------------------------------------------------------
  121.  *
  122.  * TkWinGetAppInstance --
  123.  *
  124.  *    Retrieves the global application instance handle.
  125.  *
  126.  * Results:
  127.  *    Returns the global application instance handle.
  128.  *
  129.  * Side effects:
  130.  *    None.
  131.  *
  132.  *----------------------------------------------------------------------
  133.  */
  134.  
  135. HINSTANCE
  136. TkWinGetAppInstance()
  137. {
  138.     return appInstance;
  139. }
  140.  
  141. /*
  142.  *----------------------------------------------------------------------
  143.  *
  144.  * TkWinXInit --
  145.  *
  146.  *    Initialize Xlib emulation layer.
  147.  *
  148.  * Results:
  149.  *    None.
  150.  *
  151.  * Side effects:
  152.  *    Sets up various data structures.
  153.  *
  154.  *----------------------------------------------------------------------
  155.  */
  156.  
  157. void
  158. TkWinXInit(hInstance)
  159.     HINSTANCE hInstance;
  160. {
  161.     WNDCLASS class;
  162.     static initialized = 0;
  163.  
  164.     if (initialized != 0) {
  165.     return;
  166.     }
  167.     initialized = 1;
  168.  
  169.     appInstance = hInstance;
  170.  
  171.     class.style = CS_HREDRAW | CS_VREDRAW;
  172.     class.cbClsExtra = 0;
  173.     class.cbWndExtra = 0;
  174.     class.hInstance = hInstance;
  175.     class.hbrBackground = NULL;
  176.     class.lpszMenuName = NULL;
  177.  
  178.     /*
  179.      * Register the TopLevel window class.
  180.      */
  181.  
  182.     class.lpszClassName = TK_WIN_TOPLEVEL_CLASS_NAME;
  183.     class.lpfnWndProc = TkWinTopLevelProc;
  184.     class.hIcon = LoadIcon(TkWinGetTkModule(), "tk");
  185.     class.hCursor = LoadCursor(NULL, IDC_ARROW);
  186.  
  187.     topLevelAtom = RegisterClass(&class);
  188.     if (topLevelAtom == 0) {
  189.     panic("Unable to register TkTopLevel class");
  190.     }
  191.     
  192.     /*
  193.      * Register the Child window class.
  194.      */
  195.  
  196.     class.lpszClassName = TK_WIN_CHILD_CLASS_NAME;
  197.     class.lpfnWndProc = TkWinChildProc;
  198.     class.hIcon = NULL;
  199.     class.hCursor = NULL;
  200.  
  201.     childAtom = RegisterClass(&class);
  202.     if (childAtom == 0) {
  203.     UnregisterClass((LPCTSTR)topLevelAtom, hInstance);
  204.     panic("Unable to register TkChild class");
  205.     }
  206. }
  207.  
  208. /*
  209.  *----------------------------------------------------------------------
  210.  *
  211.  * TkGetDefaultScreenName --
  212.  *
  213.  *    Returns the name of the screen that Tk should use during
  214.  *    initialization.
  215.  *
  216.  * Results:
  217.  *    Returns a statically allocated string.
  218.  *
  219.  * Side effects:
  220.  *    None.
  221.  *
  222.  *----------------------------------------------------------------------
  223.  */
  224.  
  225. char *
  226. TkGetDefaultScreenName(interp, screenName)
  227.     Tcl_Interp *interp;        /* Not used. */
  228.     char *screenName;        /* If NULL, use default string. */
  229. {
  230.     if ((screenName == NULL) || (screenName[0] == '\0')) {
  231.     screenName = winScreenName;
  232.     }
  233.     return screenName;
  234. }
  235.  
  236. /*
  237.  *----------------------------------------------------------------------
  238.  *
  239.  * XOpenDisplay --
  240.  *
  241.  *    Create the Display structure and fill it with device
  242.  *    specific information.
  243.  *
  244.  * Results:
  245.  *    Returns a Display structure on success or NULL on failure.
  246.  *
  247.  * Side effects:
  248.  *    Allocates a new Display structure.
  249.  *
  250.  *----------------------------------------------------------------------
  251.  */
  252.  
  253. Display *
  254. XOpenDisplay(display_name)
  255.     _Xconst char *display_name;
  256. {
  257.     Screen *screen;
  258.     HDC dc;
  259.     TkWinDrawable *twdPtr;
  260.  
  261.     TkWinPointerInit();
  262.  
  263.     Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS);
  264.  
  265.     if (winDisplay != NULL) {
  266.     if (strcmp(winDisplay->display_name, display_name) == 0) {
  267.         return winDisplay;
  268.     } else {
  269.         panic("XOpenDisplay: tried to open multiple displays");
  270.         return NULL;
  271.     }
  272.     }
  273.  
  274.     winDisplay = (Display *) ckalloc(sizeof(Display));
  275.     winDisplay->display_name = (char *) ckalloc(strlen(display_name)+1);
  276.     strcpy(winDisplay->display_name, display_name);
  277.  
  278.     winDisplay->cursor_font = 1;
  279.     winDisplay->nscreens = 1;
  280.     winDisplay->request = 1;
  281.     winDisplay->qlen = 0;
  282.  
  283.     screen = (Screen *) ckalloc(sizeof(Screen));
  284.     screen->display = winDisplay;
  285.  
  286.     dc = GetDC(NULL);
  287.     screen->width = GetDeviceCaps(dc, HORZRES);
  288.     screen->height = GetDeviceCaps(dc, VERTRES);
  289.     screen->mwidth = GetDeviceCaps(dc, HORZSIZE);
  290.     screen->mheight = GetDeviceCaps(dc, VERTSIZE);
  291.  
  292.     /*
  293.      * Set up the root window.
  294.      */
  295.  
  296.     twdPtr = (TkWinDrawable*) ckalloc(sizeof(TkWinDrawable));
  297.     if (twdPtr == NULL) {
  298.     return None;
  299.     }
  300.     twdPtr->type = TWD_WINDOW;
  301.     twdPtr->window.winPtr = NULL;
  302.     twdPtr->window.handle = NULL;
  303.     screen->root = (Window)twdPtr;
  304.  
  305.     screen->root_depth = GetDeviceCaps(dc, BITSPIXEL);
  306.     screen->root_visual = (Visual *) ckalloc(sizeof(Visual));
  307.     screen->root_visual->visualid = 0;
  308.     if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
  309.     screen->root_visual->map_entries = GetDeviceCaps(dc, SIZEPALETTE);
  310.     screen->root_visual->class = PseudoColor;
  311.     } else {
  312.     if (screen->root_depth == 4) {
  313.         screen->root_visual->class = StaticColor;
  314.         screen->root_visual->map_entries = 16;
  315.     } else if (screen->root_depth == 16) {
  316.         screen->root_visual->class = TrueColor;
  317.         screen->root_visual->map_entries = 64;
  318.         screen->root_visual->red_mask = 0xf8;
  319.         screen->root_visual->green_mask = 0xfc00;
  320.         screen->root_visual->blue_mask = 0xf80000;
  321.     } else if (screen->root_depth >= 24) {
  322.         screen->root_visual->class = TrueColor;
  323.         screen->root_visual->map_entries = 256;
  324.         screen->root_visual->red_mask = 0xff;
  325.         screen->root_visual->green_mask = 0xff00;
  326.         screen->root_visual->blue_mask = 0xff0000;
  327.     }
  328.     }
  329.     screen->root_visual->bits_per_rgb = screen->root_depth;
  330.     ReleaseDC(NULL, dc);
  331.  
  332.     /*
  333.      * Note that these pixel values are not palette relative.
  334.      */
  335.  
  336.     screen->white_pixel = RGB(255, 255, 255);
  337.     screen->black_pixel = RGB(0, 0, 0);
  338.  
  339.     winDisplay->screens = screen;
  340.     winDisplay->nscreens = 1;
  341.     winDisplay->default_screen = 0;
  342.     screen->cmap = XCreateColormap(winDisplay, None, screen->root_visual,
  343.         AllocNone);
  344.     return winDisplay;
  345. }
  346.  
  347. /*
  348.  *----------------------------------------------------------------------
  349.  *
  350.  * XBell --
  351.  *
  352.  *    Generate a beep.
  353.  *
  354.  * Results:
  355.  *    None.
  356.  *
  357.  * Side effects:
  358.  *    Plays a sounds out the system speakers.
  359.  *
  360.  *----------------------------------------------------------------------
  361.  */
  362.  
  363. void
  364. XBell(display, percent)
  365.     Display* display;
  366.     int percent;
  367. {
  368.     MessageBeep(MB_OK);
  369. }
  370.  
  371. /*
  372.  *----------------------------------------------------------------------
  373.  *
  374.  * TkWinTopLevelProc --
  375.  *
  376.  *    Callback from Windows whenever an event occurs on a top level
  377.  *    window.
  378.  *
  379.  * Results:
  380.  *    Standard Windows return value.
  381.  *
  382.  * Side effects:
  383.  *    Default window behavior.
  384.  *
  385.  *----------------------------------------------------------------------
  386.  */
  387.  
  388. LRESULT CALLBACK
  389. TkWinTopLevelProc(hwnd, message, wParam, lParam)
  390.     HWND hwnd;
  391.     UINT message;
  392.     WPARAM wParam;
  393.     LPARAM lParam;
  394. {
  395.     static inMoveSize = 0;
  396.     
  397.     if (inMoveSize) {
  398.     TclWinFlushEvents();
  399.     }
  400.  
  401.     switch (message) {
  402.     case WM_ENTERSIZEMOVE:
  403.         inMoveSize = 1;
  404.         break;
  405.  
  406.     case WM_EXITSIZEMOVE:
  407.         inMoveSize = 0;
  408.         break;
  409.  
  410.     case WM_CREATE: {
  411.         CREATESTRUCT *info = (CREATESTRUCT *) lParam;
  412.         TkWinDrawable *twdPtr = (TkWinDrawable *)info->lpCreateParams;
  413.         Tcl_HashEntry *hPtr;
  414.         int new;
  415.  
  416.         /*
  417.          * Add the window and handle to the window table.
  418.          */
  419.  
  420.         twdPtr->window.handle = hwnd;
  421.         hPtr = Tcl_CreateHashEntry(&windowTable, (char *)hwnd, &new);
  422.         if (!new) {
  423.         panic("Duplicate window handle: %p", hwnd);
  424.         }
  425.         Tcl_SetHashValue(hPtr, twdPtr);
  426.  
  427.         /*
  428.          * Store the pointer to the drawable structure passed into
  429.          * CreateWindow in the user data slot of the window.
  430.          */
  431.  
  432.         SetWindowLong(hwnd, GWL_USERDATA, (DWORD)twdPtr);
  433.         return 0;
  434.     }
  435.  
  436.     case WM_DESTROY:
  437.         DeleteWindow(hwnd);
  438.         return 0;
  439.         
  440.     case WM_GETMINMAXINFO: 
  441.         TkWinWmSetLimits(hwnd, (MINMAXINFO *) lParam);
  442.         return 0;
  443.  
  444.     case WM_PALETTECHANGED:
  445.         return TkWinWmInstallColormaps(hwnd, WM_PALETTECHANGED,
  446.             hwnd == (HWND)wParam);
  447.  
  448.     case WM_QUERYNEWPALETTE:
  449.         return TkWinWmInstallColormaps(hwnd, WM_QUERYNEWPALETTE, TRUE);
  450.  
  451.     case WM_WINDOWPOSCHANGED: {
  452.         WINDOWPOS *pos = (WINDOWPOS *) lParam;
  453.         TkWinDrawable *twdPtr =
  454.         (TkWinDrawable *) GetWindowLong(hwnd, GWL_USERDATA);
  455.  
  456.         TkWinWmConfigure(TkWinGetWinPtr(twdPtr), pos);
  457.         return 0;
  458.     }
  459.  
  460.     case WM_CLOSE:
  461.     case WM_LBUTTONDOWN:
  462.     case WM_MBUTTONDOWN:
  463.     case WM_RBUTTONDOWN:
  464.     case WM_LBUTTONUP:
  465.     case WM_MBUTTONUP:
  466.     case WM_RBUTTONUP:
  467.     case WM_MOUSEMOVE:
  468.     case WM_CHAR:
  469.     case WM_SYSCHAR:
  470.     case WM_KEYDOWN:
  471.     case WM_KEYUP:
  472.     case WM_SETFOCUS:
  473.     case WM_KILLFOCUS:
  474.         TranslateEvent(hwnd, message, wParam, lParam);
  475.         return 0;
  476.  
  477.     case WM_SYSKEYDOWN:
  478.     case WM_SYSKEYUP:
  479.     case WM_DESTROYCLIPBOARD:
  480.         TranslateEvent(hwnd, message, wParam, lParam);
  481.  
  482.         /*
  483.          * We need to pass these messages to the default window
  484.          * procedure in order to get the system menu to work.
  485.          */
  486.  
  487.         break;
  488.     }
  489.  
  490.     return DefWindowProc(hwnd, message, wParam, lParam);
  491. }
  492.  
  493. /*
  494.  *----------------------------------------------------------------------
  495.  *
  496.  * TkWinChildProc --
  497.  *
  498.  *    Callback from Windows whenever an event occurs on a child
  499.  *    window.
  500.  *
  501.  * Results:
  502.  *    Standard Windows return value.
  503.  *
  504.  * Side effects:
  505.  *    Default window behavior.
  506.  *
  507.  *----------------------------------------------------------------------
  508.  */
  509.  
  510. LRESULT CALLBACK
  511. TkWinChildProc(hwnd, message, wParam, lParam)
  512.     HWND hwnd;
  513.     UINT message;
  514.     WPARAM wParam;
  515.     LPARAM lParam;
  516. {
  517.     switch (message) {
  518.     case WM_CREATE: {
  519.         CREATESTRUCT *info = (CREATESTRUCT *) lParam;
  520.         Tcl_HashEntry *hPtr;
  521.         int new;
  522.  
  523.         /*
  524.          * Add the window and handle to the window table.
  525.          */
  526.  
  527.         hPtr = Tcl_CreateHashEntry(&windowTable, (char *)hwnd, &new);
  528.         if (!new) {
  529.         panic("Duplicate window handle: %p", hwnd);
  530.         }
  531.         Tcl_SetHashValue(hPtr, info->lpCreateParams);
  532.  
  533.         /*
  534.          * Store the pointer to the drawable structure passed into
  535.          * CreateWindow in the user data slot of the window.  Then set
  536.          * the Z stacking order so the window appears on top.
  537.          */
  538.         
  539.         SetWindowLong(hwnd, GWL_USERDATA, (DWORD)info->lpCreateParams);
  540.         SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
  541.             SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
  542.         return 0;
  543.     }
  544.  
  545.     case WM_DESTROY:
  546.         DeleteWindow(hwnd);
  547.         return 0;
  548.         
  549.     case WM_ERASEBKGND:
  550.     case WM_WINDOWPOSCHANGED:
  551.         return 0;
  552.  
  553.     case WM_RENDERFORMAT: {
  554.         TkWinDrawable *twdPtr;
  555.         twdPtr = (TkWinDrawable *) GetWindowLong(hwnd, GWL_USERDATA);
  556.         TkWinClipboardRender(TkWinGetWinPtr(twdPtr), wParam);
  557.         return 0;
  558.     }
  559.  
  560.     case WM_DESTROYCLIPBOARD:
  561.     case WM_PAINT:
  562.     case WM_LBUTTONDOWN:
  563.     case WM_MBUTTONDOWN:
  564.     case WM_RBUTTONDOWN:
  565.     case WM_LBUTTONUP:
  566.     case WM_MBUTTONUP:
  567.     case WM_RBUTTONUP:
  568.     case WM_MOUSEMOVE:
  569.     case WM_CHAR:
  570.     case WM_SYSCHAR:
  571.     case WM_SYSKEYDOWN:
  572.     case WM_SYSKEYUP:
  573.     case WM_KEYDOWN:
  574.     case WM_KEYUP:
  575.     case WM_SETFOCUS:
  576.     case WM_KILLFOCUS:
  577.         TranslateEvent(hwnd, message, wParam, lParam);
  578.         return 0;
  579.     }
  580.  
  581.     return DefWindowProc(hwnd, message, wParam, lParam);
  582. }
  583.  
  584. /*
  585.  *----------------------------------------------------------------------
  586.  *
  587.  * TranslateEvent --
  588.  *
  589.  *    This function is called by the window procedures to handle
  590.  *    the translation from Win32 events to Tk events.
  591.  *
  592.  * Results:
  593.  *    None.
  594.  *
  595.  * Side effects:
  596.  *    Queues a new Tk event.
  597.  *
  598.  *----------------------------------------------------------------------
  599.  */
  600.  
  601. static void
  602. TranslateEvent(hwnd, message, wParam, lParam)
  603.     HWND hwnd;
  604.     UINT message;
  605.     WPARAM wParam;
  606.     LPARAM lParam;
  607. {
  608.     TkWindow *winPtr;
  609.     XEvent event;
  610.     TkWinDrawable *twdPtr;
  611.  
  612.     /*
  613.      * Retrieve the window information, and reset the hwnd pointer in
  614.      * case the original window was a toplevel decorative frame.
  615.      */
  616.  
  617.     twdPtr = (TkWinDrawable *) GetWindowLong(hwnd, GWL_USERDATA);
  618.     if (twdPtr == NULL) {
  619.     return;
  620.     }
  621.     winPtr = TkWinGetWinPtr(twdPtr);
  622.  
  623.     /*
  624.      * TranslateEvent may get called even after Tk has deleted the window.
  625.      * So we must check for a dead window before proceeding.
  626.      */
  627.  
  628.     if (winPtr == NULL || winPtr->window == None) {
  629.     return;
  630.     }
  631.  
  632.     hwnd = TkWinGetHWND(winPtr->window);
  633.  
  634.     event.xany.serial = winPtr->display->request++;
  635.     event.xany.send_event = False;
  636.     event.xany.display = winPtr->display;
  637.     event.xany.window = (Window) winPtr->window;
  638.  
  639.     switch (message) {
  640.     case WM_PAINT: {
  641.         PAINTSTRUCT ps;
  642.  
  643.         event.type = Expose;
  644.         BeginPaint(hwnd, &ps);
  645.         event.xexpose.x = ps.rcPaint.left;
  646.         event.xexpose.y = ps.rcPaint.top;
  647.         event.xexpose.width = ps.rcPaint.right - ps.rcPaint.left;
  648.         event.xexpose.height = ps.rcPaint.bottom - ps.rcPaint.top;
  649.         EndPaint(hwnd, &ps);
  650.         event.xexpose.count = 0;
  651.         break;
  652.     }
  653.  
  654.     case WM_CLOSE:
  655.         event.type = ClientMessage;
  656.         event.xclient.message_type =
  657.         Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS");
  658.         event.xclient.format = 32;
  659.         event.xclient.data.l[0] =
  660.         Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW");
  661.         break;
  662.  
  663.     case WM_SETFOCUS:
  664.         event.type = FocusIn;
  665.         event.xfocus.mode = NotifyNormal;
  666.         event.xfocus.detail = NotifyAncestor;
  667.         break;
  668.  
  669.     case WM_KILLFOCUS:
  670.         event.type = FocusOut;
  671.         event.xfocus.mode = NotifyNormal;
  672.         event.xfocus.detail = NotifyAncestor;
  673.         break;
  674.         
  675.     case WM_DESTROYCLIPBOARD:
  676.         event.type = SelectionClear;
  677.         event.xselectionclear.selection =
  678.         Tk_InternAtom((Tk_Window)winPtr, "CLIPBOARD");
  679.         event.xselectionclear.time = GetCurrentTime();
  680.         break;
  681.         
  682.     case WM_LBUTTONDOWN:
  683.     case WM_MBUTTONDOWN:
  684.     case WM_RBUTTONDOWN:
  685.     case WM_LBUTTONUP:
  686.     case WM_MBUTTONUP:
  687.     case WM_RBUTTONUP:
  688.     case WM_MOUSEMOVE:
  689.     case WM_CHAR:
  690.     case WM_SYSCHAR:
  691.     case WM_SYSKEYDOWN:
  692.     case WM_SYSKEYUP:
  693.     case WM_KEYDOWN:
  694.     case WM_KEYUP: {
  695.         unsigned int state = TkWinGetModifierState(message,
  696.             wParam, lParam);
  697.         Time time = GetCurrentTime();
  698.         POINT clientPoint;
  699.         POINTS rootPoint;    /* Note: POINT and POINTS are different */
  700.         DWORD msgPos;
  701.  
  702.         /*
  703.          * Compute the screen and window coordinates of the event.
  704.          */
  705.         
  706.         msgPos = GetMessagePos();
  707.         rootPoint = MAKEPOINTS(msgPos);
  708.         clientPoint.x = rootPoint.x;
  709.         clientPoint.y = rootPoint.y;
  710.         ScreenToClient(hwnd, &clientPoint);
  711.  
  712.         /*
  713.          * Set up the common event fields.
  714.          */
  715.  
  716.         event.xbutton.root = RootWindow(winPtr->display,
  717.             winPtr->screenNum);
  718.         event.xbutton.subwindow = None;
  719.         event.xbutton.x = clientPoint.x;
  720.         event.xbutton.y = clientPoint.y;
  721.         event.xbutton.x_root = rootPoint.x;
  722.         event.xbutton.y_root = rootPoint.y;
  723.         event.xbutton.state = state;
  724.         event.xbutton.time = time;
  725.         event.xbutton.same_screen = True;
  726.  
  727.         /*
  728.          * Now set up event specific fields.
  729.          */
  730.  
  731.         switch (message) {
  732.         case WM_LBUTTONDOWN:
  733.             event.type = ButtonPress;
  734.             event.xbutton.button = Button1;
  735.             break;
  736.  
  737.         case WM_MBUTTONDOWN:
  738.             event.type = ButtonPress;
  739.             event.xbutton.button = Button2;
  740.             break;
  741.  
  742.         case WM_RBUTTONDOWN:
  743.             event.type = ButtonPress;
  744.             event.xbutton.button = Button3;
  745.             break;
  746.     
  747.         case WM_LBUTTONUP:
  748.             event.type = ButtonRelease;
  749.             event.xbutton.button = Button1;
  750.             break;
  751.     
  752.         case WM_MBUTTONUP:
  753.             event.type = ButtonRelease;
  754.             event.xbutton.button = Button2;
  755.             break;
  756.  
  757.         case WM_RBUTTONUP:
  758.             event.type = ButtonRelease;
  759.             event.xbutton.button = Button3;
  760.             break;
  761.     
  762.         case WM_MOUSEMOVE:
  763.             event.type = MotionNotify;
  764.             event.xmotion.is_hint = NotifyNormal;
  765.             break;
  766.  
  767.         case WM_SYSKEYDOWN:
  768.         case WM_KEYDOWN:
  769.             /*
  770.              * Check for translated characters in the event queue.
  771.              */
  772.  
  773.             event.type = KeyPress;
  774.             event.xkey.keycode = wParam;
  775.             GetTranslatedKey(&event.xkey);
  776.             break;
  777.  
  778.         case WM_SYSKEYUP:
  779.         case WM_KEYUP:
  780.             /*
  781.              * We don't check for translated characters on keyup
  782.              * because Tk won't know what to do with them.  Instead, we
  783.              * wait for the WM_CHAR messages which will follow.
  784.              */
  785.             event.type = KeyRelease;
  786.             event.xkey.keycode = wParam;
  787.             event.xkey.nchars = 0;
  788.             break;
  789.  
  790.         case WM_CHAR:
  791.         case WM_SYSCHAR:
  792.             /*
  793.              * Synthesize both a KeyPress and a KeyRelease.
  794.              */
  795.  
  796.             event.type = KeyPress;
  797.             event.xkey.keycode = 0;
  798.             event.xkey.nchars = 1;
  799.             event.xkey.trans_chars[0] = (char) wParam;
  800.             Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  801.             event.type = KeyRelease;
  802.             break;
  803.         }
  804.  
  805.         if ((event.type == MotionNotify)
  806.             || (event.type == ButtonPress)
  807.             || (event.type == ButtonRelease)) {
  808.         TkWinPointerEvent(&event, winPtr);
  809.         return;
  810.         }
  811.         break;
  812.     }
  813.  
  814.     default:
  815.         return;
  816.     }
  817.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  818. }
  819.  
  820. /*
  821.  *----------------------------------------------------------------------
  822.  *
  823.  * TkWinGetModifierState --
  824.  *
  825.  *    This function constructs a state mask for the mouse buttons 
  826.  *    and modifier keys.
  827.  *
  828.  * Results:
  829.  *    Returns a composite value of all the modifier and button state
  830.  *    flags that were set at the time the event occurred.
  831.  *
  832.  * Side effects:
  833.  *    None.
  834.  *
  835.  *----------------------------------------------------------------------
  836.  */
  837.  
  838. unsigned int
  839. TkWinGetModifierState(message, wParam, lParam)
  840.     UINT message;        /* Win32 message type */
  841.     WPARAM wParam;        /* wParam of message, used if key message */
  842.     LPARAM lParam;        /* lParam of message, used if key message */
  843. {
  844.     unsigned int state = 0;    /* accumulated state flags */
  845.     int isKeyEvent;        /* 1 if message is a key press or release */
  846.     int prevState;        /* 1 if key was previously down */
  847.  
  848.     /*
  849.      * If the event is a key press or release, we check for autorepeat.
  850.      */
  851.  
  852.     if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN
  853.         || message == WM_SYSKEYUP || message == WM_KEYUP) {
  854.     isKeyEvent = TRUE;
  855.     prevState = HIWORD(lParam) & KF_REPEAT;
  856.     }
  857.  
  858.     /*
  859.      * If the key being pressed or released is a modifier key, then
  860.      * we use its previous state, otherwise we look at the current state.
  861.      */
  862.  
  863.     if (isKeyEvent && (wParam == VK_SHIFT)) {
  864.     state |= prevState ? ShiftMask : 0;
  865.     } else {
  866.     state |= (GetKeyState(VK_SHIFT) & 0x8000) ? ShiftMask : 0;
  867.     }
  868.     if (isKeyEvent && (wParam == VK_CONTROL)) {
  869.     state |= prevState ? ControlMask : 0;
  870.     } else {
  871.     state |= (GetKeyState(VK_CONTROL) & 0x8000) ? ControlMask : 0;
  872.     }
  873.     if (isKeyEvent && (wParam == VK_MENU)) {
  874.     state |= prevState ? Mod2Mask : 0;
  875.     } else {
  876.     state |= (GetKeyState(VK_MENU) & 0x8000) ? Mod2Mask : 0;
  877.     }
  878.  
  879.     /*
  880.      * For toggle keys, we have to check both the previous key state
  881.      * and the current toggle state.  The result is the state of the
  882.      * toggle before the event.
  883.      */
  884.  
  885.     if ((wParam == VK_CAPITAL)
  886.         && (message == WM_SYSKEYDOWN || message == WM_KEYDOWN)) {
  887.     state = (prevState ^ (GetKeyState(VK_CAPITAL) & 0x0001))
  888.         ? 0 : LockMask;
  889.     } else {
  890.     state |= (GetKeyState(VK_CAPITAL) & 0x0001) ? LockMask : 0;
  891.     }
  892.     if ((wParam == VK_NUMLOCK)
  893.         && (message == WM_SYSKEYDOWN || message == WM_KEYDOWN)) {
  894.     state = (prevState ^ (GetKeyState(VK_NUMLOCK) & 0x0001))
  895.         ? 0 : Mod1Mask;
  896.     } else {
  897.     state |= (GetKeyState(VK_NUMLOCK) & 0x0001) ? Mod1Mask : 0;
  898.     }
  899.     if ((wParam == VK_SCROLL)
  900.         && (message == WM_SYSKEYDOWN || message == WM_KEYDOWN)) {
  901.     state = (prevState ^ (GetKeyState(VK_SCROLL) & 0x0001))
  902.         ? 0 : Mod3Mask;
  903.     } else {
  904.     state |= (GetKeyState(VK_SCROLL) & 0x0001) ? Mod3Mask : 0;
  905.     }
  906.  
  907.     /*
  908.      * If a mouse button is being pressed or released, we use the previous
  909.      * state of the button.
  910.      */
  911.  
  912.     if (message == WM_LBUTTONUP || (message != WM_LBUTTONDOWN
  913.         && GetKeyState(VK_LBUTTON) & 0x8000)) {
  914.     state |= Button1Mask;
  915.     }
  916.     if (message == WM_MBUTTONUP || (message != WM_MBUTTONDOWN
  917.         && GetKeyState(VK_MBUTTON) & 0x8000)) {
  918.     state |= Button2Mask;
  919.     }
  920.     if (message == WM_RBUTTONUP || (message != WM_RBUTTONDOWN
  921.         && GetKeyState(VK_RBUTTON) & 0x8000)) {
  922.     state |= Button3Mask;
  923.     }
  924.     return state;
  925. }
  926.  
  927. /*
  928.  *----------------------------------------------------------------------
  929.  *
  930.  * GetTranslatedKey --
  931.  *
  932.  *    Retrieves WM_CHAR messages that are placed on the system queue
  933.  *    by the TranslateMessage system call and places them in the
  934.  *    given KeyPress event.
  935.  *
  936.  * Results:
  937.  *    Sets the trans_chars and nchars member of the key event.
  938.  *
  939.  * Side effects:
  940.  *    Removes any WM_CHAR messages waiting on the top of the system
  941.  *    event queue.
  942.  *
  943.  *----------------------------------------------------------------------
  944.  */
  945.  
  946. static void
  947. GetTranslatedKey(xkey)
  948.     XKeyEvent *xkey;
  949. {
  950.     MSG msg;
  951.     
  952.     xkey->nchars = 0;
  953.  
  954.     while (xkey->nchars < XMaxTransChars
  955.         && PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
  956.     if ((msg.message == WM_CHAR) || (msg.message == WM_SYSCHAR)) {
  957.         xkey->trans_chars[xkey->nchars] = (char) msg.wParam;
  958.         xkey->nchars++;
  959.         GetMessage(&msg, NULL, 0, 0);
  960.         if ((msg.message == WM_CHAR) && (msg.lParam & 0x20000000)) {
  961.         xkey->state = 0;
  962.         }
  963.     } else {
  964.         break;
  965.     }
  966.     }
  967. }
  968.  
  969. /*
  970.  *----------------------------------------------------------------------
  971.  *
  972.  * TkWinGetDrawableFromHandle --
  973.  *
  974.  *    Find the drawable associated with the given window handle.
  975.  *
  976.  * Results:
  977.  *    Returns a drawable pointer if the window is managed by Tk.
  978.  *    Otherwise it returns NULL.
  979.  *
  980.  * Side effects:
  981.  *    None.
  982.  *
  983.  *----------------------------------------------------------------------
  984.  */
  985.  
  986. TkWinDrawable *
  987. TkWinGetDrawableFromHandle(hwnd)
  988.     HWND hwnd;            /* Win32 window handle */
  989. {
  990.     Tcl_HashEntry *hPtr;
  991.  
  992.     hPtr = Tcl_FindHashEntry(&windowTable, (char *)hwnd);
  993.     if (hPtr) {
  994.     return (TkWinDrawable *)Tcl_GetHashValue(hPtr);
  995.     }
  996.     return NULL;
  997. }
  998.  
  999. /*
  1000.  *----------------------------------------------------------------------
  1001.  *
  1002.  * DeleteWindow --
  1003.  *
  1004.  *    Remove a window from the window table, and free the resources
  1005.  *    associated with the drawable.
  1006.  *
  1007.  * Results:
  1008.  *    None.
  1009.  *
  1010.  * Side effects:
  1011.  *    Frees the resources associated with a window handle.
  1012.  *
  1013.  *----------------------------------------------------------------------
  1014.  */
  1015.  
  1016. static void
  1017. DeleteWindow(hwnd)
  1018.     HWND hwnd;
  1019. {
  1020.     TkWinDrawable *twdPtr;
  1021.     Tcl_HashEntry *hPtr;
  1022.  
  1023.     /*
  1024.      * Remove the window from the window table.
  1025.      */
  1026.  
  1027.     hPtr = Tcl_FindHashEntry(&windowTable, (char *)hwnd);
  1028.     if (hPtr) {
  1029.     Tcl_DeleteHashEntry(hPtr);
  1030.     }
  1031.  
  1032.     /*
  1033.      * Free the drawable associated with this window, unless the drawable
  1034.      * is still in use by a TkWindow.  This only happens in the case of
  1035.      * a top level window, since the window gets destroyed when the
  1036.      * decorative frame is destroyed.
  1037.      */
  1038.  
  1039.     twdPtr = (TkWinDrawable *) GetWindowLong(hwnd, GWL_USERDATA);
  1040.     if (twdPtr) {
  1041.     if (twdPtr->window.winPtr == NULL) {
  1042.         ckfree((char *) twdPtr);
  1043.     } else if (!(twdPtr->window.winPtr->flags & TK_TOP_LEVEL)) {
  1044.         panic("Non-toplevel window destroyed before its drawable");
  1045.     } else {
  1046.         twdPtr->window.handle = NULL;
  1047.     }
  1048.     }
  1049. }
  1050.