home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tk42r2s.zip / tk4.2 / os2 / tkOS2X.c < prev    next >
C/C++ Source or Header  |  1999-07-27  |  36KB  |  1,266 lines

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