home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tkisrc04.zip / tk / os2 / tkOS2X.c < prev    next >
C/C++ Source or Header  |  1998-08-10  |  39KB  |  1,352 lines

  1. /* 
  2.  * tkOS2X.c --
  3.  *
  4.  *    This file contains OS/2 PM emulation procedures for X routines. 
  5.  *
  6.  * Copyright (c) 1996-1997 Illya Vaes
  7.  * Copyright (c) 1995 Sun Microsystems, Inc.
  8.  * Copyright (c) 1994 Software Research Associates, Inc.
  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.  
  14.  
  15. #include "tkInt.h"
  16. #include "tkOS2Int.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             TclOS2FlushEvents _ANSI_ARGS_((void));
  25.  
  26. /*
  27.  * Declarations of static variables used in this file.
  28.  */
  29.  
  30. static Display *os2Display;    /* Display that represents OS/2 PM screen. */
  31. Tcl_HashTable windowTable;
  32.                 /* Table of child windows indexed by handle. */
  33. static char os2ScreenName[] = "PM:0";
  34.                                 /* Default name of OS2 display. */
  35.  
  36. /*
  37.  * Forward declarations of procedures used in this file.
  38.  */
  39.  
  40. static void             DeleteWindow _ANSI_ARGS_((HWND hwnd));
  41. static void         TranslateEvent (HWND hwnd, ULONG message,
  42.                 MPARAM param1, MPARAM param2);
  43.  
  44. /*
  45.  *----------------------------------------------------------------------
  46.  *
  47.  * TkGetServerInfo --
  48.  *
  49.  *    Given a window, this procedure returns information about
  50.  *    the window server for that window.  This procedure provides
  51.  *    the guts of the "winfo server" command.
  52.  *
  53.  * Results:
  54.  *    None.
  55.  *
  56.  * Side effects:
  57.  *    None.
  58.  *
  59.  *----------------------------------------------------------------------
  60.  */
  61.  
  62. void
  63. TkGetServerInfo(interp, tkwin)
  64.     Tcl_Interp *interp;        /* The server information is returned in
  65.                  * this interpreter's result. */
  66.     Tk_Window tkwin;        /* Token for window;  this selects a
  67.                  * particular display and server. */
  68. {
  69.     char buffer[50];
  70.     ULONG info[QSV_MAX]= {0};    /* System Information Data Buffer */
  71.     APIRET rc;
  72.  
  73.     /* Request all available system information */
  74.     rc= DosQuerySysInfo (1L, QSV_MAX, (PVOID)info, sizeof(info));
  75.     /* Hack for LX-versions above 2.11 */
  76.     if (info[QSV_VERSION_MINOR - 1] > 11) {
  77.         int major = (int) (info[QSV_VERSION_MINOR - 1] / 10);
  78.         sprintf(buffer, "%s %d.%d", "OS/2", major,
  79.                 (int) (info[QSV_VERSION_MINOR - 1] - major * 10));
  80.     } else {
  81.         sprintf(buffer, "%s %d.%d", "OS/2",
  82.                 (int)(info[QSV_VERSION_MINOR - 1] / 10),
  83.                 (int)info[QSV_VERSION_MINOR - 1]);
  84.     }
  85.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  86. }
  87.  
  88. /*
  89.  *----------------------------------------------------------------------
  90.  *
  91.  * TkOS2GetTkModule --
  92.  *
  93.  *      This function returns the module handle for the Tk DLL.
  94.  *
  95.  * Results:
  96.  *      Returns the library module handle.
  97.  *
  98.  * Side effects:
  99.  *      None.
  100.  *
  101.  *----------------------------------------------------------------------
  102.  */
  103.  
  104. HMODULE
  105. TkOS2GetTkModule()
  106. {
  107. #ifdef DEBUG
  108.     printf("TkOS2GetTkModule\n");
  109. #endif
  110.     return dllHandle;
  111. }
  112.  
  113. /*
  114.  *----------------------------------------------------------------------
  115.  *
  116.  * TkOS2GetAppInstance --
  117.  *
  118.  *    Retrieves the global application instance handle.
  119.  *
  120.  * Results:
  121.  *    Returns the global application instance handle.
  122.  *
  123.  * Side effects:
  124.  *    None.
  125.  *
  126.  *----------------------------------------------------------------------
  127.  */
  128.  
  129. HAB
  130. TkOS2GetAppInstance()
  131. {
  132.     return hab;
  133. }
  134.  
  135. /*
  136.  *----------------------------------------------------------------------
  137.  *
  138.  * TkOS2XInit --
  139.  *
  140.  *    Initialize Xlib emulation layer.
  141.  *
  142.  * Results:
  143.  *    None.
  144.  *
  145.  * Side effects:
  146.  *    Sets up various data structures.
  147.  *
  148.  *----------------------------------------------------------------------
  149.  */
  150.  
  151. void
  152. TkOS2XInit( hInstance )
  153.     HAB hInstance;
  154. {
  155.     BOOL success;
  156.     static initialized = 0;
  157.  
  158.     if (initialized != 0) {
  159.         return;
  160.     }
  161.     initialized = 1;
  162.  
  163.     /*
  164.      * Register the Child window class.
  165.      */
  166.  
  167.     /*
  168.      * Don't use CS_SIZEREDRAW for the child, this will make vertical resizing
  169.      * work incorrectly (keeping the same distance from the bottom instead of
  170.      * from the top when using Tk's "pack ... -side top").
  171.      */
  172.     success = WinRegisterClass(hab, TOC_CHILD, TkOS2ChildProc, 0,
  173.                                sizeof(ULONG));
  174.     if (!success) {
  175.         panic("Unable to register TkChild class");
  176.     }
  177. }
  178.  
  179. /*
  180.  *----------------------------------------------------------------------
  181.  *
  182.  * TkGetDefaultScreenName --
  183.  *
  184.  *      Returns the name of the screen that Tk should use during
  185.  *      initialization.
  186.  *
  187.  * Results:
  188.  *      Returns a statically allocated string.
  189.  *
  190.  * Side effects:
  191.  *      None.
  192.  *
  193.  *----------------------------------------------------------------------
  194.  */
  195.  
  196. char *
  197. TkGetDefaultScreenName(interp, screenName)
  198.     Tcl_Interp *interp;         /* Not used. */
  199.     char *screenName;           /* If NULL, use default string. */
  200. {
  201.     char *DISPLAY = NULL;
  202.  
  203. #ifdef DEBUG
  204.     printf("TkGetDefaultScreenName [%s] ", screenName);
  205. #endif
  206.     if ((screenName == NULL) || (screenName[0] == '\0')) {
  207.         DISPLAY = getenv("DISPLAY");
  208.         if (DISPLAY != NULL) {
  209.             screenName = DISPLAY;
  210.         } else {
  211.             screenName = os2ScreenName;
  212.         }
  213.     }
  214. #ifdef DEBUG
  215.     printf("returns [%s]\n", screenName);
  216. #endif
  217.     return screenName;
  218. }
  219.  
  220. /*
  221.  *----------------------------------------------------------------------
  222.  *
  223.  * XOpenDisplay --
  224.  *
  225.  *    Create the Display structure and fill it with device
  226.  *    specific information.
  227.  *
  228.  * Results:
  229.  *    Returns a Display structure on success or NULL on failure.
  230.  *
  231.  * Side effects:
  232.  *    Allocates a new Display structure.
  233.  *
  234.  *----------------------------------------------------------------------
  235.  */
  236.  
  237. Display *
  238. XOpenDisplay(display_name)
  239.     _Xconst char *display_name;
  240. {
  241.     Screen *screen;
  242.     TkOS2Drawable *todPtr;
  243.  
  244.     TkOS2PointerInit();
  245.  
  246.     Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS);
  247.  
  248.     if (os2Display != NULL) {
  249. #ifdef DEBUG
  250.         printf("XOpenDisplay display_name [%s], os2Display->display_name [%s]\n",
  251.                display_name, os2Display->display_name);
  252. #endif
  253.     if (strcmp(os2Display->display_name, display_name) == 0) {
  254.         return os2Display;
  255.     } else {
  256.         panic("XOpenDisplay: tried to open multiple displays");
  257.         return NULL;
  258.     }
  259.     }
  260.  
  261.     os2Display = (Display *) ckalloc(sizeof(Display));
  262.     if (!os2Display) {
  263.         return (Display *)None;
  264.     }
  265.     os2Display->display_name = (char *) ckalloc(strlen(display_name)+1);
  266.     if (!os2Display->display_name) {
  267.     ckfree((char *)os2Display);
  268.         return (Display *)None;
  269.     }
  270.     strcpy(os2Display->display_name, display_name);
  271.  
  272.     os2Display->cursor_font = 1;
  273.     os2Display->nscreens = 1;
  274.     os2Display->request = 1;
  275.     os2Display->qlen = 0;
  276.  
  277.     screen = (Screen *) ckalloc(sizeof(Screen));
  278.     if (!screen) {
  279.     ckfree((char *)os2Display->display_name);
  280.     ckfree((char *)os2Display);
  281.     return (Display *)None;
  282.     }
  283.     screen->display = os2Display;
  284.  
  285.     screen->width = aDevCaps[CAPS_WIDTH];
  286.     screen->height = yScreen;
  287.     screen->mwidth = (screen->width * 1000) / aDevCaps[CAPS_HORIZONTAL_RESOLUTION];
  288.     screen->mheight = (screen->width * 1000) / aDevCaps[CAPS_VERTICAL_RESOLUTION];
  289.  
  290.     /*
  291.      * Set up the root window.
  292.      */
  293.  
  294.     todPtr = (TkOS2Drawable*) ckalloc(sizeof(TkOS2Drawable));
  295.     if (!todPtr) {
  296.     ckfree((char *)os2Display->display_name);
  297.     ckfree((char *)os2Display);
  298.     ckfree((char *)screen);
  299.     return (Display *)None;
  300.     }
  301.     todPtr->type = TOD_WINDOW;
  302.     todPtr->window.winPtr = NULL;
  303.     todPtr->window.handle = HWND_DESKTOP;
  304.     screen->root = (Window)todPtr;
  305.  
  306.     screen->root_depth = aDevCaps[CAPS_COLOR_BITCOUNT];
  307.     screen->root_visual = (Visual *) ckalloc(sizeof(Visual));
  308.     if (!screen->root_visual) {
  309.     ckfree((char *)os2Display->display_name);
  310.     ckfree((char *)os2Display);
  311.     ckfree((char *)screen);
  312.     ckfree((char *)todPtr);
  313.     return (Display *)None;
  314.     }
  315.     screen->root_visual->visualid = 0;
  316.     if ( aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER ) {
  317.     screen->root_visual->map_entries = aDevCaps[CAPS_COLOR_INDEX]+1;
  318.     screen->root_visual->class = PseudoColor;
  319.     } else {
  320.     if (screen->root_depth == 4) {
  321.         screen->root_visual->class = StaticColor;
  322.         screen->root_visual->map_entries = 16;
  323.     } else if (screen->root_depth == 16) {
  324.         screen->root_visual->class = TrueColor;
  325.         screen->root_visual->map_entries = aDevCaps[CAPS_COLOR_INDEX]+1;
  326.         screen->root_visual->red_mask = 0xff;
  327.         screen->root_visual->green_mask = 0xff00;
  328.         screen->root_visual->blue_mask = 0xff0000;
  329.         /*
  330.         */
  331.     } else if (screen->root_depth >= 24) {
  332.         screen->root_visual->class = TrueColor;
  333.         screen->root_visual->map_entries = 256;
  334.         screen->root_visual->red_mask = 0xff;
  335.         screen->root_visual->green_mask = 0xff00;
  336.         screen->root_visual->blue_mask = 0xff0000;
  337.     }
  338.     }
  339.     screen->root_visual->bits_per_rgb = screen->root_depth;
  340.  
  341.     /*
  342.      * Note that these pixel values are not palette relative.
  343.      */
  344.  
  345.     screen->white_pixel = RGB(255, 255, 255);
  346.     screen->black_pixel = RGB(0, 0, 0);
  347.  
  348.     os2Display->screens = screen;
  349.     os2Display->nscreens = 1;
  350.     os2Display->default_screen = 0;
  351.     screen->cmap = XCreateColormap(os2Display, None, screen->root_visual,
  352.         AllocNone);
  353.  
  354.     return os2Display;
  355. }
  356.  
  357. /*
  358.  *----------------------------------------------------------------------
  359.  *
  360.  * XBell --
  361.  *
  362.  *    Generate a beep.
  363.  *
  364.  * Results:
  365.  *    None.
  366.  *
  367.  * Side effects:
  368.  *    Plays a sounds out the system speakers.
  369.  *
  370.  *----------------------------------------------------------------------
  371.  */
  372.  
  373. void
  374. XBell(display, percent)
  375.     Display* display;
  376.     int percent;
  377. {
  378.     rc = DosBeep (770L, 300L);
  379. }
  380.  
  381.  
  382. MRESULT EXPENTRY
  383. TkOS2FrameProc(hwnd, message, param1, param2)
  384.     HWND hwnd;
  385.     ULONG message;
  386.     MPARAM param1;
  387.     MPARAM param2;
  388. {
  389.     static inMoveSize = 0;
  390.  
  391.     if (inMoveSize) {
  392.         TclOS2FlushEvents();
  393.     }
  394.  
  395.     switch (message) {
  396.  
  397.     case WM_CREATE: {
  398.             TkOS2Drawable *todPtr = (TkOS2Drawable *) PVOIDFROMMP(param1);
  399.         Tcl_HashEntry *hPtr;
  400.         int new;
  401.         BOOL rc;
  402. #ifdef DEBUG
  403.             printf("FrameProc: WM_CREATE hwnd %x, tod %x\n", hwnd, todPtr);
  404. #endif
  405.  
  406.         /*
  407.          * Add the window and handle to the window table.
  408.          */
  409.  
  410.             todPtr->window.handle = hwnd;
  411.         hPtr = Tcl_CreateHashEntry(&windowTable, (char *)hwnd, &new);
  412.         if (!new) {
  413.         panic("Duplicate window handle: %p", hwnd);
  414.         }
  415.         Tcl_SetHashValue(hPtr, todPtr);
  416.  
  417.         /*
  418.          * Store the pointer to the drawable structure passed into
  419.          * WinCreateWindow in the user data slot of the window.
  420.          */
  421.  
  422.         rc= WinSetWindowULong(hwnd, QWL_USER, (ULONG)todPtr);
  423.             break;
  424.     }
  425.  
  426.     case WM_DESTROY: {
  427. #ifdef DEBUG
  428.             printf("FrameProc: WM_DESTROY hwnd %x\n", hwnd);
  429. #endif
  430.             DeleteWindow(hwnd);
  431.         return 0;
  432.     }
  433.         
  434.  
  435.     case WM_QUERYTRACKINFO: {
  436.         TRACKINFO *track = (TRACKINFO *)PVOIDFROMMP(param2);
  437.         SWP pos;
  438.         BOOL rc;
  439.  
  440. #ifdef DEBUG
  441.             printf("FrameProc: WM_QUERYTRACKINFO hwnd %x, trackinfo %x\n",
  442.                    hwnd, track);
  443. #endif
  444.             inMoveSize = 1;
  445.             /* Get present size as default max/min */
  446.             rc = WinQueryWindowPos(hwnd, &pos);
  447. #ifdef DEBUG
  448.             if (rc!=TRUE) {
  449.                 printf("   WinQueryWindowPos ERROR %x\n", WinGetLastError(hab));
  450.             } else {
  451.                 printf("   WinQueryWindowPos OK\n");
  452.             }
  453. #endif
  454.             /* Fill in defaults */
  455.             track->cxBorder = track->cyBorder = 4; /* 4 pixels tracking */
  456.             track->cxGrid = track->cyGrid = 1; /* smooth tracking */
  457.             track->cxKeyboard = track->cyKeyboard = 8; /* fast keyboardtracking */
  458.             rc = WinSetRect(hab, &track->rclTrack, pos.x, pos.y,
  459.                             pos.x + pos.cx, pos.y + pos.cy);
  460. #ifdef DEBUG
  461.             if (rc!=TRUE) {
  462.                 printf("    WinSetRect ERROR %x\n", WinGetLastError(hab));
  463.             } else {
  464.                 printf("    WinSetRect OK\n");
  465.             }
  466. #endif
  467.             rc = WinSetRect(hab, &track->rclBoundary, 0, 0, xScreen, yScreen);
  468. #ifdef DEBUG
  469.             if (rc!=TRUE) {
  470.                 printf("    WinSetRect ERROR %x\n", WinGetLastError(hab));
  471.             } else {
  472.                 printf("    WinSetRect OK\n");
  473.             }
  474. #endif
  475.             track->ptlMinTrackSize.x = 0;
  476.             track->ptlMaxTrackSize.x = xScreen;
  477.             track->ptlMinTrackSize.y = 0;
  478.             track->ptlMaxTrackSize.y = yScreen;
  479.             track->fs = SHORT1FROMMP(param1);
  480.             /* Determine what Tk will allow */
  481.             TkOS2WmSetLimits(hwnd, (TRACKINFO *) PVOIDFROMMP(param2));
  482.             inMoveSize = 0;
  483.             return (MRESULT)1;    /* continue sizing or moving */
  484.     }
  485.  
  486.     case WM_REALIZEPALETTE:
  487.         /* Notifies that the input focus window has realized its logical
  488.          * palette, so realize ours and update client area(s)
  489.          * Must return 0
  490.          */
  491. #ifdef DEBUG
  492.             printf("FrameProc: WM_REALIZEPALETTE hwnd %x\n", hwnd);
  493. #endif
  494.         TkOS2WmInstallColormaps(hwnd, WM_REALIZEPALETTE, FALSE);
  495.             break;
  496.  
  497.     case WM_SETFOCUS:
  498.         /* 
  499.              * If usfocus is true we translate the event *AND* install the
  500.              * colormap, otherwise we only translate the event.
  501.              */
  502. #ifdef DEBUG
  503.             printf("FrameProc: WM_SETFOCUS hwnd %x, usfocus %x\n", hwnd,
  504.                    param2);
  505. #endif
  506.         if ( LONGFROMMP(param2) == TRUE ) {
  507.                 HPS hps = WinGetPS(hwnd);
  508.                 ULONG colorsChanged;
  509.                 TkOS2Drawable *todPtr =
  510.                     (TkOS2Drawable *) WinQueryWindowULong(hwnd, QWL_USER);
  511.  
  512.                 if (TkOS2GetWinPtr(todPtr) != NULL) {
  513.                     GpiSelectPalette(hps,
  514.                        TkOS2GetPalette(TkOS2GetWinPtr(todPtr)->atts.colormap));
  515.                     WinRealizePalette(hwnd, hps, &colorsChanged);
  516.                     /*
  517.                 TkOS2WmInstallColormaps(hwnd, WM_SETFOCUS, FALSE);
  518.                     */
  519.                 }
  520.         }
  521.         TranslateEvent(hwnd, message, param1, param2);
  522.         break;
  523.  
  524.     case WM_WINDOWPOSCHANGED: {
  525.         SWP *pos = (SWP *) PVOIDFROMMP(param1);
  526.         TkOS2Drawable *todPtr = (TkOS2Drawable *)
  527.                                 WinQueryWindowULong(hwnd, QWL_USER);
  528. #ifdef DEBUG
  529.                 /*MM* add { */
  530.             printf("FrameProc: WM_WINDOWPOSCHANGED hwnd %x (%d,%d) %dx%d,fl%x,\
  531.                    Awp%x, tod %x\n", hwnd, pos->x, pos->y, pos->cx, pos->cy,
  532.                    pos->fl, LONGFROMMP(param2), todPtr);
  533.                 /*MM* } */
  534. /*MM* del            printf("FrameProc: WM_WINDOWPOSCHANGED hwnd %x (%d,%d) %dx%d,fl%x, */
  535. /*MM* del                   Awp%x, tod %x\n", hwnd, pos->x, pos->y, pos->cx, pos->cy, */
  536. /*MM* del                   pos->fl, LONGFROMMP(param2), todPtr); */
  537. #endif
  538.             TkOS2WmConfigure(TkOS2GetWinPtr(todPtr), pos);
  539.             break;
  540.     }
  541.  
  542.         /*
  543.          * The frame sends the WM_CLOSE to the client (child) if it exists,
  544.          * so we have to handle it there.
  545.          * Also hand off mouse/button stoff to default procedure.
  546.          */
  547.     case WM_CLOSE:
  548.     case WM_BUTTON1DOWN:
  549.     case WM_BUTTON2DOWN:
  550.     case WM_BUTTON3DOWN:
  551.     case WM_BUTTON1UP:
  552.     case WM_BUTTON2UP:
  553.     case WM_BUTTON3UP:
  554.     case WM_MOUSEMOVE:
  555.             break;
  556.  
  557.     case WM_CHAR:
  558. #ifdef DEBUG
  559.            printf("FrameProc: WM_CHAR (First one pertinent)\n");
  560. #endif
  561.         TranslateEvent(hwnd, message, param1, param2);
  562.             return 0;
  563.  
  564.     case WM_DESTROYCLIPBOARD:
  565. #ifdef DEBUG
  566.             printf("FrameProc: WM_DESTROYCLIPBOARD hwnd %x\n", hwnd);
  567. #endif
  568.         TranslateEvent(hwnd, message, param1, param2);
  569.  
  570.         /*
  571.          * We need to pass these messages to the default window
  572.          * procedure in order to get the system menu to work.
  573.          */
  574.  
  575.         break;
  576.         default:
  577.               ;                /*MM*/
  578.     }
  579.  
  580.     return oldFrameProc(hwnd, message, param1, param2);
  581. }
  582.  
  583. /*
  584.  *----------------------------------------------------------------------
  585.  *
  586.  * TkOS2ChildProc --
  587.  *
  588.  *    Callback from Presentation Manager whenever an event occurs on
  589.  *    a child window.
  590.  *
  591.  * Results:
  592.  *    Standard OS/2 PM return value.
  593.  *
  594.  * Side effects:
  595.  *    Default window behavior.
  596.  *
  597.  *----------------------------------------------------------------------
  598.  */
  599.  
  600. MRESULT EXPENTRY
  601. TkOS2ChildProc(hwnd, message, param1, param2)
  602.     HWND hwnd;
  603.     ULONG message;
  604.     MPARAM param1;
  605.     MPARAM param2;
  606. {
  607.     switch (message) {
  608.  
  609.     case WM_CREATE: {
  610.         CREATESTRUCT *info = (CREATESTRUCT *) PVOIDFROMMP(param2);
  611.         Tcl_HashEntry *hPtr;
  612.         int new;
  613. #ifdef DEBUG
  614.             printf("Child: WM_CREATE hwnd %x, info %x\n", hwnd, info);
  615. #endif
  616.  
  617.         /*
  618.          * Add the window and handle to the window table.
  619.          */
  620.  
  621.         hPtr = Tcl_CreateHashEntry(&windowTable, (char *)hwnd, &new);
  622.         if (!new) {
  623.         panic("Duplicate window handle: %p", hwnd);
  624.         }
  625.         Tcl_SetHashValue(hPtr, info->pCtlData);
  626.  
  627.         /*
  628.          * Store the pointer to the drawable structure passed into
  629.          * WinCreateWindow in the user data slot of the window.  Then
  630.          * set the Z stacking order so the window appears on top.
  631.          */
  632.         
  633.         WinSetWindowULong(hwnd, QWL_USER, (ULONG)info->pCtlData);
  634.         WinSetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
  635.         return 0;
  636.     }
  637.  
  638.     case WM_DESTROY:
  639. #ifdef DEBUG
  640.             printf("Child: WM_DESTROY hwnd %x\n", hwnd);
  641. #endif
  642.             DeleteWindow(hwnd);
  643.         return 0;
  644.         
  645.     case WM_RENDERFMT: {
  646.         TkOS2Drawable *todPtr;
  647.         todPtr = (TkOS2Drawable *) WinQueryWindowULong(hwnd, QWL_USER);
  648. #ifdef DEBUG
  649.             printf("Child: WM_RENDERFMT hwnd %x, tod %x\n", hwnd, todPtr);
  650. #endif
  651.         TkOS2ClipboardRender(TkOS2GetWinPtr(todPtr),
  652.                              (ULONG)(SHORT1FROMMP(param1)));
  653.         return 0;
  654.     }
  655.  
  656.     case WM_BUTTON1DOWN:
  657. #ifdef DEBUG
  658.             printf("Child: WM_BUTTON1DOWN %d,%d\n", (LONG) SHORT1FROMMP(param1),
  659.                    (LONG) SHORT2FROMMP(param1));
  660. #endif
  661.     case WM_BUTTON2DOWN:
  662.     case WM_BUTTON3DOWN:
  663.     case WM_BUTTON1UP:
  664. #ifdef DEBUG
  665.             printf("Child: WM_BUTTON1UP %d,%d\n", (LONG) SHORT1FROMMP(param1),
  666.                    (LONG) SHORT2FROMMP(param1));
  667. #endif
  668.     case WM_BUTTON2UP:
  669.     case WM_BUTTON3UP:
  670.         TranslateEvent(hwnd, message, param1, param2);
  671.         /*
  672.          * Pass on BUTTON stuff to default procedure, eg. for having the
  673.          * focus set to the frame window for us.
  674.          */
  675.         break;
  676.  
  677.     /*
  678.      * For double-clicks, generate a ButtonPress and ButtonRelease.
  679.      * Pass on BUTTON stuff to default procedure, eg. for having the
  680.      * focus set to the frame window for us.
  681.      */
  682.     case WM_BUTTON1DBLCLK:
  683.         TranslateEvent(hwnd, WM_BUTTON1DOWN, param1, param2);
  684.         TranslateEvent(hwnd, WM_BUTTON1UP, param1, param2);
  685.         break;
  686.     case WM_BUTTON2DBLCLK:
  687.         TranslateEvent(hwnd, WM_BUTTON2DOWN, param1, param2);
  688.         TranslateEvent(hwnd, WM_BUTTON2UP, param1, param2);
  689.         break;
  690.     case WM_BUTTON3DBLCLK:
  691.         TranslateEvent(hwnd, WM_BUTTON3DOWN, param1, param2);
  692.         TranslateEvent(hwnd, WM_BUTTON3UP, param1, param2);
  693.         break;
  694.  
  695.  
  696.     case WM_CLOSE:
  697.         /*
  698.          * The frame sends the WM_CLOSE to the client (child) if it exists,
  699.          * so we have to handle it here.
  700.          */
  701. #ifdef DEBUG
  702.             printf("Child: WM_CLOSE\n");
  703. #endif
  704.     case WM_PAINT:
  705. #ifdef DEBUG
  706.             printf("Child: WM_PAINT\n");
  707. #endif
  708.     case WM_DESTROYCLIPBOARD:
  709.     case WM_MOUSEMOVE:
  710.     case WM_CHAR:
  711.     case WM_SETFOCUS:
  712.         TranslateEvent(hwnd, message, param1, param2);
  713.         /* Do not pass on to PM */
  714.         return 0;
  715.     }
  716.  
  717.     return WinDefWindowProc(hwnd, message, param1, param2);
  718. }
  719.  
  720. /*
  721.  *----------------------------------------------------------------------
  722.  *
  723.  * TranslateEvent --
  724.  *
  725.  *    This function is called by the window procedures to handle
  726.  *    the translation from OS/2 PM events to Tk events.
  727.  *
  728.  * Results:
  729.  *    None.
  730.  *
  731.  * Side effects:
  732.  *    Queues a new Tk event.
  733.  *
  734.  *----------------------------------------------------------------------
  735.  */
  736.  
  737. static void
  738. TranslateEvent(hwnd, message, param1, param2)
  739.     HWND hwnd;
  740.     ULONG message;
  741.     MPARAM param1;
  742.     MPARAM param2;
  743. {
  744.     TkWindow *winPtr;
  745.     XEvent event;
  746.     TkOS2Drawable *todPtr;
  747.     HWND hwndTop;
  748.  
  749.     /*
  750.      * Retrieve the window information, and reset the hwnd pointer in
  751.      * case the original window was a toplevel decorative frame.
  752.      */
  753.  
  754.     todPtr = (TkOS2Drawable *) WinQueryWindowULong(hwnd, QWL_USER);
  755.     if (todPtr == NULL) {
  756. #ifdef DEBUG
  757.         printf("TranslateEvent: NULL todPtr\n");
  758. #endif
  759.     return;
  760.     }
  761.     winPtr = TkOS2GetWinPtr(todPtr);
  762.  
  763.     /*
  764.      * TranslateEvent may get called even after Tk has deleted the window.
  765.      * So we must check for a dead window before proceeding.
  766.      */
  767.  
  768.     if (winPtr == NULL || winPtr->window == None) {
  769. #ifdef DEBUG
  770.         printf("TranslateEvent: NULL winPtr or None Window (%x, %x)\n",
  771.                winPtr, winPtr ? winPtr->window : 0);
  772. #endif
  773.     return;
  774.     }
  775.  
  776.     hwndTop = hwnd;
  777.     hwnd = TkOS2GetHWND(winPtr->window);
  778.  
  779.     event.xany.serial = winPtr->display->request++;
  780.     event.xany.send_event = False;
  781. #ifdef DEBUG
  782.     printf("TranslateEvent display %x, hwnd %x\n", winPtr->display, hwnd);
  783. #endif
  784.     event.xany.display = winPtr->display;
  785.     event.xany.window = (Window) winPtr->window;
  786.  
  787.     switch (message) {
  788.     case WM_PAINT: {
  789.         HPS hps;
  790.         RECTL rectl;
  791.  
  792.         event.type = Expose;
  793.         hps= WinBeginPaint(hwnd, NULLHANDLE, &rectl);
  794. #ifdef DEBUG
  795.             if (hps==NULLHANDLE) {
  796.                 printf("WinBeginPaint hwnd %x ERROR %x\n", hwnd,
  797.                        WinGetLastError(hab));
  798.             } else {
  799.                 printf("WinBeginPaint hwnd %x is %x\n", hwnd, hps);
  800.             }
  801. #endif
  802.         WinEndPaint(hps);
  803. #ifdef DEBUG
  804.             printf("TranslateEvent WM_PAINT hwnd %x, xL=%d, xR=%d, yT=%d, yB=%d\n",
  805.                     hwnd, rectl.xLeft, rectl.xRight, rectl.yTop, rectl.yBottom);
  806. #endif
  807.  
  808.         event.xexpose.x = rectl.xLeft;
  809.         /* PM coordinates reversed (*/
  810.         event.xexpose.y = TkOS2WindowHeight(todPtr) - rectl.yTop;
  811.         event.xexpose.width = rectl.xRight - rectl.xLeft;
  812.         event.xexpose.height = rectl.yTop - rectl.yBottom;
  813. #ifdef DEBUG
  814.             printf("       event: x=%d, y=%d, w=%d, h=%d\n", event.xexpose.x,
  815.                    event.xexpose.y, event.xexpose.width, event.xexpose.height);
  816. #endif
  817.         event.xexpose.count = 0;
  818.         break;
  819.     }
  820.  
  821.     case WM_CLOSE:
  822. #ifdef DEBUG
  823.             printf("TranslateEvent WM_CLOSE hwnd %x\n", hwnd);
  824. #endif
  825.         event.type = ClientMessage;
  826.         event.xclient.message_type =
  827.         Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS");
  828.         event.xclient.format = 32;
  829.         event.xclient.data.l[0] =
  830.         Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW");
  831.         break;
  832.  
  833.     case WM_SETFOCUS:
  834. #ifdef DEBUG
  835.            printf("TranslateEvent WM_SETFOCUS hwnd %x\n", hwnd);
  836. #endif
  837.         if ( (LOUSHORT(param2)) == TRUE ) {
  838.             event.type = FocusIn;
  839.         } else {
  840.             event.type = FocusOut;
  841.         }
  842.         event.xfocus.mode = NotifyNormal;
  843.         event.xfocus.detail = NotifyAncestor;
  844.         break;
  845.         
  846.     case WM_DESTROYCLIPBOARD:
  847. #ifdef DEBUG
  848.            printf("TranslateEvent WM_DESTROYCLIPBOARD hwnd %x\n", hwnd);
  849. #endif
  850.         event.type = SelectionClear;
  851.         event.xselectionclear.selection =
  852.         Tk_InternAtom((Tk_Window)winPtr, "CLIPBOARD");
  853.         event.xselectionclear.time = WinGetCurrentTime(hab);
  854.         break;
  855.         
  856.     case WM_BUTTON1DOWN:
  857.     case WM_BUTTON2DOWN:
  858.     case WM_BUTTON3DOWN:
  859.     case WM_BUTTON1UP:
  860.     case WM_BUTTON2UP:
  861.     case WM_BUTTON3UP:
  862. #ifdef DEBUG
  863.            printf("TranslateEvent WM_BUTTON* %x hwnd %x fl %x (1D %x, 1U %x)\n",
  864.                   message, hwnd, SHORT2FROMMP(param2), WM_BUTTON1DOWN,
  865.                   WM_BUTTON1UP);
  866. #endif
  867.     case WM_MOUSEMOVE:
  868.     case WM_CHAR:
  869.             {
  870.         /*
  871.          * WM_CHAR and the others have different params, while the latter
  872.          * give only the flags of which keys were pressed (or none).
  873.          */
  874.         USHORT flags = (message == WM_CHAR) ? SHORT1FROMMP(param1)
  875.                                             : SHORT2FROMMP(param2);
  876.         unsigned int state = TkOS2GetModifierState(message, flags,
  877.             param1, param2);
  878.         Time time = WinGetCurrentTime(hab);
  879.         POINTL clientPoint;
  880.         POINTL rootPoint;
  881.         BOOL rc;
  882.  
  883.         /*
  884.          * Compute the screen and window coordinates of the event.
  885.          */
  886.         
  887.         rc = WinQueryMsgPos(hab, &rootPoint);
  888.         clientPoint.x = rootPoint.x;
  889.         clientPoint.y = rootPoint.y;
  890.         rc= WinMapWindowPoints (HWND_DESKTOP, hwnd, &clientPoint, 1);
  891. #ifdef DEBUG
  892.             if (rc != TRUE) {
  893.                 printf("WinMapWindowPoints %d,%d (root %d,%d) ERROR %x\n",
  894.                        clientPoint.x, clientPoint.y, rootPoint.x, rootPoint.y,
  895.                        WinGetLastError(hab));
  896.             } else {
  897.                 printf("WinMapWindowPoints %d,%d (root %d,%d) OK\n", clientPoint.x,
  898.                        clientPoint.y, rootPoint.x, rootPoint.y);
  899.             }
  900. #endif
  901.  
  902.         /*
  903.          * Set up the common event fields.
  904.          */
  905.  
  906.         event.xbutton.root = RootWindow(winPtr->display,
  907.             winPtr->screenNum);
  908.         event.xbutton.subwindow = None;
  909.         event.xbutton.x = clientPoint.x;
  910.         /* PM coordinates reversed */
  911.         event.xbutton.y = TkOS2WindowHeight((TkOS2Drawable *)todPtr)
  912.                           - clientPoint.y;
  913.         event.xbutton.x_root = rootPoint.x;
  914.         event.xbutton.y_root = yScreen - rootPoint.y;
  915.         event.xbutton.state = state;
  916.         event.xbutton.time = time;
  917.         event.xbutton.same_screen = True;
  918.  
  919.         /*
  920.          * Now set up event specific fields.
  921.          */
  922.  
  923.         switch (message) {
  924.         case WM_BUTTON1DOWN:
  925.             event.type = ButtonPress;
  926.             event.xbutton.button = Button1;
  927.             break;
  928.  
  929.         case WM_BUTTON2DOWN:
  930.             event.type = ButtonPress;
  931.             event.xbutton.button = Button2;
  932.             break;
  933.  
  934.         case WM_BUTTON3DOWN:
  935.             event.type = ButtonPress;
  936.             event.xbutton.button = Button3;
  937.             break;
  938.     
  939.         case WM_BUTTON1UP:
  940.             event.type = ButtonRelease;
  941.             event.xbutton.button = Button1;
  942.             break;
  943.     
  944.         case WM_BUTTON2UP:
  945.             event.type = ButtonRelease;
  946.             event.xbutton.button = Button2;
  947.             break;
  948.  
  949.         case WM_BUTTON3UP:
  950.             event.type = ButtonRelease;
  951.             event.xbutton.button = Button3;
  952.             break;
  953.     
  954.         case WM_MOUSEMOVE:
  955.             event.type = MotionNotify;
  956.             event.xmotion.is_hint = NotifyNormal;
  957. #ifdef DEBUG
  958.                     printf("WM_MOUSEMOVE %d,%d (root %d,%d)\n", clientPoint.x,
  959.                            clientPoint.y, rootPoint.x, rootPoint.y);
  960. #endif
  961.             break;
  962.  
  963.             /*
  964.              * We don't check for translated characters on keyup
  965.              * because Tk won't know what to do with them.  Instead, we
  966.              * wait for the WM_CHAR messages which will follow.
  967.              */
  968.         /*
  969.             event.type = KeyRelease;
  970.             event.xkey.keycode = param1;
  971.             event.xkey.nchars = 0;
  972.             break;
  973.         */
  974.  
  975.         case WM_CHAR: {
  976.             /*
  977.              * Careful: for each keypress, two of these messages are
  978.              * generated, one when pressed and one when released.
  979.              * When the keyboard-repeat is triggered, multiple key-
  980.              * down messages can be generated. If this goes faster
  981.              * than they are retrieved from the queue, they can be
  982.              * combined in one message.
  983.              */
  984.             USHORT flags= CHARMSG(&message)->fs;
  985.             UCHAR krepeat= CHARMSG(&message)->cRepeat;
  986.             USHORT charcode= CHARMSG(&message)->chr;
  987.             USHORT vkeycode= CHARMSG(&message)->vkey;
  988.             int loop;
  989.             /*
  990.              * Check for translated characters in the event queue.
  991.              * and more than 1 char in the message
  992.              */
  993.             if ( (flags & KC_ALT) && !(flags & KC_CTRL) &&
  994.                  (vkeycode != VK_CTRL) && (vkeycode != VK_F10) ) {
  995.                 /* Equivalent to Windows' WM_SYSKEY */
  996. #ifdef DEBUG
  997.                         printf("Equivalent of WM_SYSKEY...\n");
  998. #endif
  999.             }
  1000.             if ( flags & KC_KEYUP ) {
  1001.                 /* Key Up */
  1002. #ifdef DEBUG
  1003.                         printf("KeyUp\n");
  1004. #endif
  1005.                 event.type = KeyRelease;
  1006.             } else {
  1007.                 /* Key Down */
  1008. #ifdef DEBUG
  1009.                         printf("KeyDown\n");
  1010. #endif
  1011.                 event.type = KeyPress;
  1012.             }
  1013.             if ( flags & KC_VIRTUALKEY ) {
  1014.                 /* vkeycode is valid, should be given precedence */
  1015.                 event.xkey.keycode = vkeycode;
  1016. #ifdef DEBUG
  1017.                         printf("virtual keycode %x\n", vkeycode);
  1018. #endif
  1019.             } else {
  1020.                 event.xkey.keycode = 0;
  1021.             }
  1022.             if ( flags & KC_CHAR ) {
  1023.                 /* charcode is valid */
  1024.                 event.xkey.nchars = krepeat;
  1025.                 for ( loop=0; loop < krepeat; loop++ ) {
  1026.                     event.xkey.trans_chars[loop] = charcode;
  1027. #ifdef DEBUG
  1028.                         printf("charcode %x\n", charcode);
  1029. #endif
  1030.                 }
  1031.             } else {
  1032.                 /*
  1033.                  * No KC_CHAR, but char can be valid with KC_ALT,
  1034.                  * KC_CTRL when it is not 0.
  1035.                  */
  1036. #ifdef DEBUG
  1037.                         printf("no KC_CHAR\n");
  1038. #endif
  1039.                 if ( (flags & KC_ALT || flags & KC_CTRL)
  1040.                      && charcode != 0) {
  1041. #ifdef DEBUG
  1042.                             printf("KC_ALT/KC_CTRL and non-0 char %c (%x)\n",
  1043.                                    charcode, charcode);
  1044. #endif
  1045.                     event.xkey.keycode = charcode;
  1046.                 }
  1047.                 event.xkey.nchars = 0;
  1048.                event.xkey.trans_chars[0] = 0;
  1049.             }
  1050.                     /*
  1051.                      * Synthesize both a KeyPress and a KeyRelease.
  1052.                     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  1053.                     event.type = KeyRelease;
  1054.                      */
  1055.  
  1056.             break;
  1057.                 }
  1058.         }
  1059.  
  1060.         if ((event.type == MotionNotify)
  1061.             || (event.type == ButtonPress)
  1062.             || (event.type == ButtonRelease)) {
  1063.         TkOS2PointerEvent(&event, winPtr);
  1064.         return;
  1065.         }
  1066.         break;
  1067.     }
  1068.  
  1069.     default:
  1070.         return;
  1071.     }
  1072.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  1073. }
  1074.  
  1075. /*
  1076.  *----------------------------------------------------------------------
  1077.  *
  1078.  * TkOS2GetModifierState --
  1079.  *
  1080.  *    This function constructs a state mask for the mouse buttons 
  1081.  *    and modifier keys.
  1082.  *
  1083.  * Results:
  1084.  *    Returns a composite value of all the modifier and button state
  1085.  *    flags that were set at the time the event occurred.
  1086.  *
  1087.  * Side effects:
  1088.  *    None.
  1089.  *
  1090.  *----------------------------------------------------------------------
  1091.  */
  1092.  
  1093. unsigned int
  1094. TkOS2GetModifierState(message, flags, param1, param2)
  1095.     ULONG message;        /* OS/2 PM message type */
  1096.     USHORT flags;        /* Applicable flags (in different param for
  1097.                                  * different messages
  1098.                                  */
  1099.     MPARAM param1;        /* param1 of message, used if key message */
  1100.     MPARAM param2;        /* param2 of message, used if key message */
  1101. {
  1102.     unsigned int state = 0;    /* accumulated state flags */
  1103.     int isKeyEvent = 0;        /* 1 if message is a key press or release */
  1104.     int prevState = 0;        /* 1 if key was previously down */
  1105.     USHORT vkeycode= SHORT2FROMMP(param2); /* function key */
  1106.  
  1107. #ifdef DEBUG
  1108.     UCHAR krepeat= CHAR3FROMMP(param1);
  1109.     UCHAR scancode= CHAR4FROMMP(param1);
  1110.     USHORT charcode= SHORT1FROMMP(param2);
  1111.  
  1112.     printf("TkOS2GetModifierState fl %x, krepeat %d, scan %x, char %x, VK %x\n",
  1113.            flags, krepeat, scancode, charcode, vkeycode);
  1114.     if (flags & KC_COMPOSITE) printf("KC_COMPOSITE\n");
  1115.     if (flags & KC_VIRTUALKEY) printf("KC_VIRTUALKEY\n");
  1116.     if (flags & KC_PREVDOWN) printf("KC_PREVDOWN\n");
  1117.     if (flags & KC_SHIFT) printf("KC_SHIFT\n");
  1118.     if (flags & KC_CTRL) printf("KC_CTRL\n");
  1119.     if (flags & KC_ALT) printf("KC_ALT\n");
  1120.     if (flags & KC_NONE) printf("KC_NONE\n");
  1121.     switch (vkeycode) {
  1122.     case VK_SHIFT:
  1123.         printf("    VK_SHIFT %s\n", ((flags & KC_ALT) && (flags & KC_CTRL)) ?
  1124.                "with CTRL and ALT" : (flags & KC_ALT ? "with ALT" :
  1125.                (flags & KC_CTRL ? "with CTRL" : "")));
  1126.         break;
  1127.     case VK_CTRL:
  1128.         printf("    VK_CTRL %s\n", flags & KC_ALT ? "with ALT" : "");
  1129.         break;
  1130.     case VK_ALT:
  1131.         printf("    VK_ALT %s\n", flags & KC_CTRL ? "with CTRL" : "");
  1132.         break;
  1133.     case VK_MENU:
  1134.         printf("    VK_MENU\n");
  1135.         break;
  1136.     }
  1137. #endif
  1138.     /*
  1139.      * If the event is a key press or release, we check for autorepeat.
  1140.      */
  1141.     if ( (flags & KC_CHAR) || (flags & KC_VIRTUALKEY) ) {
  1142.     isKeyEvent = TRUE;
  1143.     prevState = flags & KC_PREVDOWN;
  1144. #ifdef DEBUG
  1145.         printf("    isKeyEvent, prevState %x\n", prevState);
  1146. #endif
  1147.     }
  1148.  
  1149.     /*
  1150.      * If the key being pressed or released is a modifier key, then
  1151.      * we use its previous state, otherwise we look at the current state.
  1152.      */
  1153.  
  1154.     if (isKeyEvent && (vkeycode == VK_SHIFT)) {
  1155.     state |= prevState ? ShiftMask : 0;
  1156.     } else {
  1157.     /*
  1158.     state |= (WinGetKeyState(HWND_DESKTOP, VK_SHIFT) & 0x8000)
  1159.     */
  1160.     state |= (flags & KC_SHIFT)
  1161.              ? ShiftMask : 0;
  1162.     }
  1163.     if (isKeyEvent && (vkeycode == VK_CTRL)) {
  1164.     state |= prevState ? ControlMask : 0;
  1165.     } else {
  1166.     /*
  1167.     state |= (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
  1168.     */
  1169.     state |= (flags & KC_CTRL)
  1170.              ? ControlMask : 0;
  1171.     }
  1172.     /* Do NOT handle ALTGRAF specially, since that will ignore its char */
  1173.     if (isKeyEvent && (vkeycode == VK_ALT)) {
  1174.     state |= prevState ? (AnyModifier << 2) : 0;
  1175.     } else {
  1176.     /*
  1177.     state |= (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000)
  1178.     */
  1179.     state |= (flags & KC_ALT)
  1180.              ? (AnyModifier << 2) : 0;
  1181.     }
  1182.     if (isKeyEvent && (vkeycode == VK_MENU)) {
  1183.     state |= prevState ? Mod2Mask : 0;
  1184.     } else {
  1185.     state |= (WinGetKeyState(HWND_DESKTOP, VK_MENU) & 0x8000)
  1186.              ? Mod2Mask : 0;
  1187.     }
  1188. #ifdef DEBUG
  1189.     if (state & ShiftMask) printf("ShiftMask\n");
  1190.     if (state & ControlMask) printf("ControlMask\n");
  1191.     if (state & (AnyModifier << 2)) printf("AltMask\n");
  1192. #endif
  1193.  
  1194.     /*
  1195.      * For toggle keys, we have to check both the previous key state
  1196.      * and the current toggle state.  The result is the state of the
  1197.      * toggle before the event.
  1198.      */
  1199.  
  1200.     if ((vkeycode == VK_CAPSLOCK) && !( flags & KC_KEYUP)) {
  1201.     state = (prevState ^ (WinGetKeyState(HWND_DESKTOP, VK_CAPSLOCK) & 0x0001))
  1202.             ? 0 : LockMask;
  1203.     } else {
  1204.     state |= (WinGetKeyState(HWND_DESKTOP, VK_CAPSLOCK) & 0x0001)
  1205.              ? LockMask : 0;
  1206.     }
  1207.     if ((vkeycode == VK_NUMLOCK) && !( flags & KC_KEYUP)) {
  1208.     state = (prevState ^ (WinGetKeyState(HWND_DESKTOP, VK_NUMLOCK) & 0x0001))
  1209.             ? 0 : Mod1Mask;
  1210.     } else {
  1211.     state |= (WinGetKeyState(HWND_DESKTOP, VK_NUMLOCK) & 0x0001)
  1212.              ? Mod1Mask : 0;
  1213.     }
  1214.     if ((vkeycode == VK_SCRLLOCK) && !( flags & KC_KEYUP)) {
  1215.     state = (prevState ^ (WinGetKeyState(HWND_DESKTOP, VK_SCRLLOCK) & 0x0001))
  1216.             ? 0 : Mod3Mask;
  1217.     } else {
  1218.     state |= (WinGetKeyState(HWND_DESKTOP, VK_SCRLLOCK) & 0x0001)
  1219.              ? Mod3Mask : 0;
  1220.     }
  1221.  
  1222.     /*
  1223.      * If a mouse button is being pressed or released, we use the previous
  1224.      * state of the button.
  1225.      */
  1226.  
  1227.     if (message == WM_BUTTON1UP || (message != WM_BUTTON1DOWN
  1228.         && WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000)) {
  1229.     state |= Button1Mask;
  1230.     }
  1231.     if (message == WM_BUTTON2UP || (message != WM_BUTTON2DOWN
  1232.         && WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000)) {
  1233.     state |= Button2Mask;
  1234.     }
  1235.     if (message == WM_BUTTON3UP || (message != WM_BUTTON3DOWN
  1236.         && WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000)) {
  1237.     state |= Button3Mask;
  1238.     }
  1239. #ifdef DEBUG
  1240.     printf("    returning state %x\n", state);
  1241. #endif
  1242.     return state;
  1243. }
  1244.  
  1245. /*
  1246.  *----------------------------------------------------------------------
  1247.  *
  1248.  * TkOS2GetDrawableFromHandle --
  1249.  *
  1250.  *    Find the drawable associated with the given window handle.
  1251.  *
  1252.  * Results:
  1253.  *    Returns a drawable pointer if the window is managed by Tk.
  1254.  *    Otherwise it returns NULL.
  1255.  *
  1256.  * Side effects:
  1257.  *    None.
  1258.  *
  1259.  *----------------------------------------------------------------------
  1260.  */
  1261.  
  1262. TkOS2Drawable *
  1263. TkOS2GetDrawableFromHandle(hwnd)
  1264.     HWND hwnd;            /* OS/2 PM window handle */
  1265. {
  1266.     Tcl_HashEntry *hPtr;
  1267.  
  1268.     hPtr = Tcl_FindHashEntry(&windowTable, (char *)hwnd);
  1269.     if (hPtr) {
  1270.     return (TkOS2Drawable *)Tcl_GetHashValue(hPtr);
  1271.     }
  1272. #ifdef DEBUG
  1273.     printf("TkOS2GetDrawableFromHandle %x: NULL\n", hwnd);
  1274. #endif
  1275.     return NULL;
  1276. }
  1277.  
  1278. /*
  1279.  *----------------------------------------------------------------------
  1280.  *
  1281.  * DeleteWindow --
  1282.  *
  1283.  *      Remove a window from the window table, and free the resources
  1284.  *      associated with the drawable.
  1285.  *
  1286.  * Results:
  1287.  *      None.
  1288.  *
  1289.  * Side effects:
  1290.  *      Frees the resources associated with a window handle.
  1291.  *
  1292.  *----------------------------------------------------------------------
  1293.  */
  1294.  
  1295. static void
  1296. DeleteWindow(hwnd)
  1297.     HWND hwnd;
  1298. {
  1299.     TkOS2Drawable *todPtr;
  1300.     Tcl_HashEntry *hPtr;
  1301.  
  1302.     /*
  1303.      * Remove the window from the window table.
  1304.      */
  1305.  
  1306.     hPtr = Tcl_FindHashEntry(&windowTable, (char *)hwnd);
  1307.     if (hPtr) {
  1308.         Tcl_DeleteHashEntry(hPtr);
  1309.     }
  1310.  
  1311.     /*
  1312.      * Free the drawable associated with this window, unless the drawable
  1313.      * is still in use by a TkWindow.  This only happens in the case of
  1314.      * a top level window, since the window gets destroyed when the
  1315.      * decorative frame is destroyed.
  1316.      */
  1317.  
  1318.     todPtr = (TkOS2Drawable *) WinQueryWindowULong(hwnd, QWL_USER);
  1319. #ifdef DEBUG
  1320.     printf("DeleteWindow: hwnd %x, todPtr %x\n", hwnd, todPtr);
  1321. #endif
  1322.     if (todPtr) {
  1323. #ifdef DEBUG
  1324.         printf("    todPtr->window.winPtr %x\n", todPtr->window.winPtr);
  1325. #endif
  1326.         if (todPtr->window.winPtr == NULL) {
  1327. #ifdef DEBUG
  1328.             printf("    DeleteWindow ckfree todPtr %x\n", todPtr);
  1329. #endif
  1330.             ckfree((char *) todPtr);
  1331.             todPtr= NULL;
  1332.         } else if (!(todPtr->window.winPtr->flags & TK_TOP_LEVEL)) {
  1333. #ifdef DEBUG
  1334.             printf("     PANIC    flags %x, todPtr->window.handle %x\n",
  1335.                    todPtr->window.winPtr->flags, todPtr->window.handle);
  1336. #endif
  1337. /*
  1338.  * We can get here because PM does a depth-first WM_DESTROY tree traversal
  1339.  * (children first, then the to-be-destroyed window, while Windows hands the
  1340.  * message first to the to-be-destroyed window, then to the children.
  1341.  * So don't panic
  1342.             panic("Non-toplevel window destroyed before its drawable");
  1343. */
  1344.         } else {
  1345. #ifdef DEBUG
  1346.             printf("    DeleteWindow case 3\n");
  1347. #endif
  1348.             todPtr->window.handle = NULLHANDLE;
  1349.         }
  1350.     }
  1351. }
  1352.