home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tcltk805.zip / tcl805s.zip / tk8.0.5 / os2 / tkOS2Menu.c < prev    next >
C/C++ Source or Header  |  2001-09-08  |  113KB  |  3,515 lines

  1. /*
  2.  * tkOS2Menu.c --
  3.  *
  4.  *    This module implements the OS/2 platform-specific features of menus.
  5.  *
  6.  * Copyright (c) 1999-2000 by Illya Vaes
  7.  * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  */
  13.  
  14. #include <string.h>
  15. #include "tkMenu.h"
  16. #include "default.h"
  17. #include "tkOS2Int.h"
  18.  
  19. /*
  20.  * The class of the window for popup menus.
  21.  */
  22.  
  23. #define MENU_CLASS_NAME "MenuWindowClass"
  24.  
  25. /*
  26.  * Used to align an OS/2 bitmap inside a rectangle
  27.  */
  28.  
  29. #define ALIGN_BITMAP_LEFT   0x00000001
  30. #define ALIGN_BITMAP_RIGHT  0x00000002
  31. #define ALIGN_BITMAP_TOP    0x00000004
  32. #define ALIGN_BITMAP_BOTTOM 0x00000008
  33.  
  34. /*
  35.  * Platform-specific menu flags:
  36.  *
  37.  * MENU_SYSTEM_MENU    Non-zero means that the OS/2 menu handle
  38.  *            was retrieved with GetSystemMenu and needs
  39.  *            to be disposed of specially.
  40.  * MENU_RECONFIGURE_PENDING
  41.  *            Non-zero means that an idle handler has
  42.  *            been set up to reconfigure the OS/2 menu
  43.  *            handle for this menu.
  44.  */
  45.  
  46. #define MENU_SYSTEM_MENU        MENU_PLATFORM_FLAG1
  47. #define MENU_RECONFIGURE_PENDING    MENU_PLATFORM_FLAG2
  48.  
  49. static PFNWP oldMenuProc = WinDefWindowProc; /* window proc of MENU controls */
  50.  
  51. static int indicatorDimensions[2] = { 0, 0};
  52.                 /* The dimensions of the indicator space
  53.                  * in a menu entry. Calculated at init
  54.                  * time to save time. */
  55. static Tcl_HashTable commandTable;
  56.                 /* A map of command ids to menu entries */
  57. static int inPostMenu;        /* We cannot be re-entrant like X Windows. */
  58. /*static*/ USHORT lastCommandID;    /* The last command ID we allocated. */
  59. static HWND menuHWND;        /* A window to service popup-menu messages
  60.                  * in. */
  61. static int oldServiceMode;    /* Used while processing a menu; we need
  62.                  * to set the event mode specially when we
  63.                  * enter the menu processing modal loop
  64.                  * and reset it when menus go away. */
  65. static TkMenu *modalMenuPtr;    /* The menu we are processing inside the modal
  66.                  * loop. We need this to reset all of the
  67.                  * active items when menus go away since
  68.                  * OS/2 does not see fit to give this
  69.                  * to us when it sends its WM_MENUSELECT. */
  70. static Tcl_HashTable os2MenuTable;
  71.                 /* Need this to map HWNDs back to menuPtrs */
  72.  
  73. /*
  74.  * The following are default menu value strings.
  75.  */
  76.  
  77. static char borderString[5];    /* The string indicating how big the border is */
  78. static Tcl_DString menuFontDString;
  79.                 /* A buffer to store the default menu font
  80.                  * string. */
  81.  
  82. /*
  83.  * Forward declarations for procedures defined later in this file:
  84.  * y coordinates are X11 not PM.
  85.  */
  86.  
  87. static void        DrawMenuEntryAccelerator _ANSI_ARGS_((
  88.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  89.                 Drawable d, GC gc, Tk_Font tkfont,
  90.                 CONST Tk_FontMetrics *fmPtr,
  91.                 Tk_3DBorder activeBorder, int x, int y,
  92.                 int width, int height, int drawArrow));
  93. static void        DrawMenuEntryBackground _ANSI_ARGS_((
  94.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  95.                 Drawable d, Tk_3DBorder activeBorder,
  96.                 Tk_3DBorder bgBorder, int x, int y,
  97.                 int width, int heigth));
  98. static void        DrawMenuEntryIndicator _ANSI_ARGS_((
  99.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  100.                 Drawable d, GC gc, GC indicatorGC,
  101.                 Tk_Font tkfont,
  102.                 CONST Tk_FontMetrics *fmPtr, int x, int y,
  103.                 int width, int height));
  104. static void        DrawMenuEntryLabel _ANSI_ARGS_((
  105.                 TkMenu * menuPtr, TkMenuEntry *mePtr, Drawable d,
  106.                 GC gc, Tk_Font tkfont,
  107.                 CONST Tk_FontMetrics *fmPtr, int x, int y,
  108.                 int width, int height));
  109. static void        DrawMenuSeparator _ANSI_ARGS_((TkMenu *menuPtr,
  110.                 TkMenuEntry *mePtr, Drawable d, GC gc,
  111.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  112.                 int x, int y, int width, int height));
  113. static void        DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr,
  114.                 TkMenuEntry *mePtr, Drawable d, GC gc,
  115.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  116.                 int x, int y, int width, int height));
  117. static void        DrawMenuUnderline _ANSI_ARGS_((TkMenu *menuPtr,
  118.                 TkMenuEntry *mePtr, Drawable d, GC gc,
  119.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x,
  120.                 int y, int width, int height));
  121. /*
  122. static void        DrawOS2SystemBitmap _ANSI_ARGS_((
  123.                 Display *display, Drawable drawable,
  124.                 GC gc, CONST RECTL *rectPtr, int bitmapID,
  125.                 int alignFlags));
  126. */
  127. static void        FreeID _ANSI_ARGS_((int commandID));
  128. static char *        GetEntryText _ANSI_ARGS_((TkMenuEntry *mePtr));
  129. static void        GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr,
  130.                 TkMenuEntry *mePtr, Tk_Font tkfont,
  131.                 CONST Tk_FontMetrics *fmPtr, int *widthPtr,
  132.                 int *heightPtr));
  133. static void        GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr,
  134.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  135.                 int *widthPtr, int *heightPtr));
  136. static void        GetMenuIndicatorGeometry _ANSI_ARGS_((
  137.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  138.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  139.                 int *widthPtr, int *heightPtr));
  140. static void        GetMenuSeparatorGeometry _ANSI_ARGS_((
  141.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  142.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  143.                 int *widthPtr, int *heightPtr));
  144. static void        GetTearoffEntryGeometry _ANSI_ARGS_((TkMenu *menuPtr,
  145.                 TkMenuEntry *mePtr, Tk_Font tkfont,
  146.                 CONST Tk_FontMetrics *fmPtr, int *widthPtr,
  147.                 int *heightPtr));
  148. static int        GetNewID _ANSI_ARGS_((TkMenuEntry *mePtr,
  149.                 int *menuIDPtr));
  150. static void        MenuSelectEvent _ANSI_ARGS_((TkMenu *menuPtr));
  151. static void        ReconfigureOS2Menu _ANSI_ARGS_((
  152.                 ClientData clientData));
  153. static void        RecursivelyClearActiveMenu _ANSI_ARGS_((
  154.                 TkMenu *menuPtr));
  155. static MRESULT EXPENTRY    TkOS2MenuProc _ANSI_ARGS_((HWND hwnd,
  156.                 ULONG message, MPARAM param1,
  157.                 MPARAM param2));
  158.  
  159.  
  160.  
  161. /*
  162.  *----------------------------------------------------------------------
  163.  *
  164.  * GetNewID --
  165.  *
  166.  *    Allocates a new menu id and marks it in use.
  167.  *
  168.  * Results:
  169.  *    Returns TCL_OK if succesful; TCL_ERROR if there are no more
  170.  *    ids of the appropriate type to allocate. menuIDPtr contains
  171.  *    the new id if succesful.
  172.  *
  173.  * Side effects:
  174.  *    An entry is created for the menu in the command hash table,
  175.  *    and the hash entry is stored in the appropriate field in the
  176.  *    menu data structure.
  177.  *
  178.  *----------------------------------------------------------------------
  179.  */
  180.  
  181. static int
  182. GetNewID(mePtr, menuIDPtr)
  183.     TkMenuEntry *mePtr;        /* The menu we are working with */
  184.     int *menuIDPtr;        /* The resulting id */
  185. {
  186.     int found = 0;
  187.     int newEntry;
  188.     Tcl_HashEntry *commandEntryPtr = (Tcl_HashEntry *) NULL;
  189.     USHORT returnID = 0;
  190.  
  191.     USHORT curID = lastCommandID + 1;
  192.  
  193. #ifdef VERBOSE
  194.     printf("GetNewID\n");
  195.             fflush(stdout);
  196. #endif
  197.  
  198.     /*
  199.      * The following code relies on USHORT wrapping when the highest value is
  200.      * incremented.
  201.      */
  202.  
  203.     while (curID != lastCommandID) {
  204.     /*
  205.      * Extra cast to ULONG to prevent warning by GCC about casting from
  206.      * integer of different size.
  207.      */
  208.         commandEntryPtr = Tcl_CreateHashEntry(&commandTable,
  209.         (char *)(ULONG) curID, &newEntry);
  210.         if (newEntry == 1) {
  211.             found = 1;
  212.             returnID = curID;
  213.             break;
  214.         }
  215.         curID++;
  216.     }
  217.  
  218.     if (found) {
  219.         Tcl_SetHashValue(commandEntryPtr, (char *) mePtr);
  220.         *menuIDPtr = (int) returnID;
  221.         lastCommandID = returnID;
  222. #ifdef VERBOSE
  223.         printf("GetNewID TCL_OK returning id %d (mePtr %x, hwnd %x)\n",
  224.                returnID, mePtr, mePtr->menuPtr->platformData);
  225.             fflush(stdout);
  226. #endif
  227.         return TCL_OK;
  228.     } else {
  229. #ifdef VERBOSE
  230.         printf("GetNewID TCL_ERROR\n");
  231.             fflush(stdout);
  232. #endif
  233.         return TCL_ERROR;
  234.     }
  235. }
  236.  
  237. /*
  238.  *----------------------------------------------------------------------
  239.  *
  240.  * FreeID --
  241.  *
  242.  *    Marks the itemID as free.
  243.  *
  244.  * Results:
  245.  *    None.
  246.  *
  247.  * Side effects:
  248.  *    The hash table entry for the ID is cleared.
  249.  *
  250.  *----------------------------------------------------------------------
  251.  */
  252.  
  253. static void
  254. FreeID(commandID)
  255.     int commandID;
  256. {
  257.     Tcl_HashEntry *entryPtr = Tcl_FindHashEntry(&commandTable,
  258.         (char *) commandID);
  259.  
  260. #ifdef VERBOSE
  261.     printf("FreeID %d\n", commandID);
  262.             fflush(stdout);
  263. #endif
  264.     if (entryPtr != NULL) {
  265.          Tcl_DeleteHashEntry(entryPtr);
  266.     }
  267. }
  268.  
  269. /*
  270.  *----------------------------------------------------------------------
  271.  *
  272.  * TkpNewMenu --
  273.  *
  274.  *    Gets a new blank menu. Only the platform specific options are filled
  275.  *    in.
  276.  *
  277.  * Results:
  278.  *    Standard TCL error.
  279.  *
  280.  * Side effects:
  281.  *    Allocates an OS/2 menu handle and places it in the platformData
  282.  *    field of the menuPtr.
  283.  *
  284.  *----------------------------------------------------------------------
  285.  */
  286.  
  287. int
  288. TkpNewMenu(menuPtr)
  289.     TkMenu *menuPtr;    /* The common structure we are making the
  290.              * platform structure for. */
  291. {
  292.     HWND os2MenuHdl;
  293.     Tcl_HashEntry *hashEntryPtr;
  294.     int newEntry;
  295.     FRAMECDATA fcdata;
  296.  
  297. #ifdef VERBOSE
  298.     printf("TkpNewMenu typeName %s title %s totWidth %d totHeight %d type %d\n",
  299.            menuPtr->menuTypeName, menuPtr->title, menuPtr->totalWidth,
  300.            menuPtr->totalHeight, menuPtr->menuType);
  301.     fflush(stdout);
  302. #endif
  303.     fcdata.cb = sizeof(FRAMECDATA);
  304.     fcdata.flCreateFlags = 0L;
  305.     fcdata.hmodResources = 0L;
  306.     fcdata.idResources = 0;
  307.     os2MenuHdl = WinCreateWindow(HWND_DESKTOP, WC_MENU, NULL,
  308.                                  WS_CLIPSIBLINGS | WS_SAVEBITS, 0, 0, 0, 0,
  309.                                  HWND_DESKTOP, HWND_BOTTOM, FID_MENU, &fcdata,
  310.                                  NULL);
  311. /*
  312.     os2MenuHdl = WinCreateWindow(HWND_OBJECT, WC_MENU, NULL,
  313.                                  WS_CLIPSIBLINGS | WS_SAVEBITS, 0, 0, 0, 0,
  314.                                  HWND_OBJECT, HWND_BOTTOM, FID_MENU, &fcdata,
  315.                                  NULL);
  316. */
  317.  
  318.     if (os2MenuHdl == NULLHANDLE) {
  319. #ifdef VERBOSE
  320.         printf("WinCreateWindow menu ERROR %x\n",
  321.            WinGetLastError(TclOS2GetHAB()));
  322.             fflush(stdout);
  323. #endif
  324.         Tcl_AppendResult(menuPtr->interp, "No more menus can be allocated.",
  325.             (char *) NULL);
  326.         return TCL_ERROR;
  327.     }
  328. #ifdef VERBOSE
  329.     printf("WinCreateWindow menu OK: %x\n", os2MenuHdl);
  330.             fflush(stdout);
  331. #endif
  332.     oldMenuProc = WinSubclassWindow(os2MenuHdl, TkOS2MenuProc);
  333. #ifdef VERBOSE
  334.     printf("WinSubclassWindow os2MenuHdl %x, oldMenuProc %x\n", os2MenuHdl,
  335.            oldMenuProc);
  336.     fflush(stdout);
  337. #endif
  338. /*
  339. */
  340.  
  341.     /*
  342.      * We hash all of the HWND's so that we can get their menu ptrs
  343.      * back when dispatch messages.
  344.      */
  345.  
  346.     hashEntryPtr = Tcl_CreateHashEntry(&os2MenuTable, (char *) os2MenuHdl,
  347.         &newEntry);
  348. #ifdef VERBOSE
  349.     printf("Tcl_CreateHashEntry hwnd %x for menuPtr %x: hashEntryPtr %x\n",
  350.                os2MenuHdl, menuPtr, hashEntryPtr);
  351. #endif
  352.     Tcl_SetHashValue(hashEntryPtr, (char *) menuPtr);
  353.  
  354.     menuPtr->platformData = (TkMenuPlatformData) os2MenuHdl;
  355.     return TCL_OK;
  356. }
  357.  
  358. /*
  359.  *----------------------------------------------------------------------
  360.  *
  361.  * TkpDestroyMenu --
  362.  *
  363.  *    Destroys platform-specific menu structures.
  364.  *
  365.  * Results:
  366.  *    None.
  367.  *
  368.  * Side effects:
  369.  *    All platform-specific allocations are freed up.
  370.  *
  371.  *----------------------------------------------------------------------
  372.  */
  373.  
  374. void
  375. TkpDestroyMenu(menuPtr)
  376.     TkMenu *menuPtr;        /* The common menu structure */
  377. {
  378.     HWND os2MenuHdl = (HWND) menuPtr->platformData;
  379. #ifdef VERBOSE
  380.     printf("TkpDestroyMenu %x\n", os2MenuHdl);
  381.             fflush(stdout);
  382. #endif
  383.  
  384.     if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) {
  385.     Tcl_CancelIdleCall(ReconfigureOS2Menu, (ClientData) menuPtr);
  386.     }
  387.  
  388.     if (os2MenuHdl == NULLHANDLE) {
  389.     return;
  390.     }
  391.  
  392.     if (menuPtr->menuFlags & MENU_SYSTEM_MENU) {
  393.     TkMenuEntry *searchEntryPtr;
  394.     Tcl_HashTable *tablePtr = TkGetMenuHashTable(menuPtr->interp);
  395.     char *menuName = Tcl_GetHashKey(tablePtr,
  396.         menuPtr->menuRefPtr->hashEntryPtr);
  397.  
  398.     /*
  399.      * Search for the menu in the menubar, if it is present, get the
  400.      * wrapper window associated with the toplevel and reset its
  401.      * system menu to the default menu.
  402.      */
  403.  
  404.     for (searchEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
  405.          searchEntryPtr != NULL;
  406.          searchEntryPtr = searchEntryPtr->nextCascadePtr) {
  407.         if (strcmp(searchEntryPtr->name, menuName) == 0) {
  408.         Tk_Window parentTopLevelPtr = searchEntryPtr
  409.             ->menuPtr->parentTopLevelPtr;
  410.  
  411.         if (parentTopLevelPtr != NULL) {
  412.             /*
  413.              * According to SMART, there is no documented way to
  414.              * reset the system menu to the default state...
  415.              * Windows uses:
  416.             GetSystemMenu(TkOS2GetWrapperWindow(parentTopLevelPtr),
  417.                 TRUE);
  418.              */
  419.         }
  420.         break;
  421.         }
  422.     }
  423.     } else {
  424.     Tcl_HashEntry *hashEntryPtr;
  425.  
  426.     /*
  427.      * Remove the menu from the menu hash table, then destroy the handle.
  428.      */
  429.  
  430.     hashEntryPtr = Tcl_FindHashEntry(&os2MenuTable, (char *) os2MenuHdl);
  431.     if (hashEntryPtr != NULL) {
  432.         Tcl_DeleteHashEntry(hashEntryPtr);
  433.     }
  434.     WinDestroyWindow(os2MenuHdl);
  435.     }
  436.     menuPtr->platformData = NULL;
  437.     /* Reset lastWinPtr etc. */
  438.     TkPointerDeadWindow((TkWindow *)menuPtr->tkwin);
  439. }
  440.  
  441. /*
  442.  *----------------------------------------------------------------------
  443.  *
  444.  * TkpDestroyMenuEntry --
  445.  *
  446.  *    Cleans up platform-specific menu entry items.
  447.  *
  448.  * Results:
  449.  *    None
  450.  *
  451.  * Side effects:
  452.  *    All platform-specific allocations are freed up.
  453.  *
  454.  *----------------------------------------------------------------------
  455.  */
  456.  
  457. void
  458. TkpDestroyMenuEntry(mePtr)
  459.     TkMenuEntry *mePtr;            /* The entry to destroy */
  460. {
  461.     TkMenu *menuPtr = mePtr->menuPtr;
  462.     HWND os2MenuHdl = (HWND) menuPtr->platformData;
  463. #ifdef VERBOSE
  464.     printf("TkpDestroyMenuEntry %x (mePtr %x, menuPtr %x)\n", os2MenuHdl, mePtr,
  465.            menuPtr);
  466.             fflush(stdout);
  467. #endif
  468.  
  469.     if (NULLHANDLE != os2MenuHdl) {
  470.         if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
  471.         menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  472.         Tcl_DoWhenIdle(ReconfigureOS2Menu, (ClientData) menuPtr);
  473.     }
  474.     }
  475.     FreeID((int) mePtr->platformEntryData);
  476.     mePtr->platformEntryData = NULL;
  477. }
  478.  
  479. /*
  480.  *----------------------------------------------------------------------
  481.  *
  482.  * GetEntryText --
  483.  *
  484.  *    Given a menu entry, gives back the text that should go in it.
  485.  *    Separators should be done by the caller, as they have to be
  486.  *    handled specially. Allocates the memory with alloc. The caller
  487.  *    should free the memory.
  488.  *
  489.  * Results:
  490.  *    itemText points to the new text for the item.
  491.  *
  492.  * Side effects:
  493.  *    None.
  494.  *
  495.  *----------------------------------------------------------------------
  496.  */
  497.  
  498. static char *
  499. GetEntryText(mePtr)
  500.     TkMenuEntry *mePtr;        /* A pointer to the menu entry. */
  501. {
  502.     char *itemText;
  503. #ifdef VERBOSE
  504.     printf("GetEntryText mePtr %x\n", mePtr);
  505.             fflush(stdout);
  506. #endif
  507.  
  508.     if (mePtr->type == TEAROFF_ENTRY) {
  509.     itemText = ckalloc(sizeof("(Tear-off)"));
  510.     strcpy(itemText, "(Tear-off)");
  511.     } else if (mePtr->imageString != NULL) {
  512.     itemText = ckalloc(sizeof("(Image)"));
  513.     strcpy(itemText, "(Image)");
  514.     } else if (mePtr->bitmap != None) {
  515.     itemText = ckalloc(sizeof("(Pixmap)"));
  516.     strcpy(itemText, "(Pixmap)");
  517.     } else if (mePtr->label == NULL || mePtr->labelLength == 0) {
  518.     itemText = ckalloc(sizeof("( )"));
  519.     strcpy(itemText, "( )");
  520.     } else {
  521.     int size = mePtr->labelLength + 1;
  522.     int i, j;
  523.  
  524.     /*
  525.      * We have to construct the string with a tilde (~)
  526.      * preceeding the underline character (to get OS/2 PM to underline it),
  527.          * and a tab seperating the text and the accel text. We have to be
  528.          * careful with tildes in the string.
  529.      */
  530.  
  531.     for (i = 0; i < mePtr->labelLength; i++) {
  532.         if (mePtr->label[i] == '~') {
  533.         size++;
  534. #ifdef VERBOSE
  535.                 printf("mePtr->label[%d] == ~ ==> size = %d\n", i, size);
  536. #endif
  537.         }
  538.     }
  539.  
  540.     if (mePtr->underline >= 0) {
  541.         size++;
  542. #ifdef VERBOSE
  543.             printf("mePtr->underline (%d) >= 0 ==> size = %d\n",
  544.                    mePtr->underline, size);
  545. #endif
  546.         if (mePtr->label[mePtr->underline] == '~') {
  547.         size++;
  548. #ifdef VERBOSE
  549.                 printf("mePtr->label[%d] == ~ ==> size = %d\n",
  550.                        mePtr->underline, size);
  551. #endif
  552.         }
  553.     }
  554.  
  555.     if (mePtr->accelLength > 0) {
  556.         size += mePtr->accelLength + 1;
  557. #ifdef VERBOSE
  558.             printf("mePtr->accelLength (%d) > 0 ==> size = %d\n",
  559.                    mePtr->accelLength, size);
  560. #endif
  561.     }
  562.  
  563.     for (i = 0; i < mePtr->accelLength; i++) {
  564.         if (mePtr->accel[i] == '~') {
  565.         size++;
  566. #ifdef VERBOSE
  567.                 printf("mePtr->accel[%d] == '~' ==> size = %d\n", i, size);
  568. #endif
  569.         }
  570.     }
  571.  
  572.     itemText = ckalloc(size);
  573.     
  574.     if (mePtr->labelLength == 0) {
  575.         itemText[0] = '\0';
  576.     } else {
  577.             /*
  578.              * Escaping the tilde is done by another tilde, but ONLY if the
  579.              * literal tilde comes for any 'underline' / 'mnemonic' tilde.
  580.              * Every tilde after that is taken literally by the menu control.
  581.              */
  582.             BOOL beforeTilde = TRUE;
  583.         for (i = 0, j = 0; i < mePtr->labelLength; i++, j++) {
  584.         if (mePtr->label[i] == '~' && beforeTilde) {
  585.             itemText[j++] = '~';
  586.         }
  587.         if (i == mePtr->underline) {
  588.             itemText[j++] = '~';
  589.                     beforeTilde = FALSE;
  590.         }
  591.         itemText[j] = mePtr->label[i];
  592.         }
  593.         itemText[j] = '\0';
  594.     }
  595.  
  596.     if (mePtr->accelLength > 0) {
  597.         strcat(itemText, "\t");
  598.         for (i = 0, j = strlen(itemText); i < mePtr->accelLength;
  599.             i++, j++) {
  600.         if (mePtr->accel[i] == '~') {
  601.             itemText[j++] = '~';
  602.         }
  603.         itemText[j] = mePtr->accel[i];
  604.         }
  605.         itemText[j] = '\0';
  606.     }
  607.     }
  608. #ifdef VERBOSE
  609.     printf("GetEntryText returning [%s]\n", itemText);
  610.             fflush(stdout);
  611. #endif
  612.     return itemText;
  613. }
  614.  
  615. /*
  616.  *----------------------------------------------------------------------
  617.  *
  618.  * ReconfigureOS2Menu --
  619.  *
  620.  *    Tears down and rebuilds the platform-specific part of this menu.
  621.  *
  622.  * Results:
  623.  *    None.
  624.  *
  625.  * Side effects:
  626.  *    Configuration information get set for mePtr; old resources
  627.  *    get freed, if any need it.
  628.  *
  629.  *----------------------------------------------------------------------
  630.  */
  631.  
  632. static void
  633. ReconfigureOS2Menu(
  634.     ClientData clientData)        /* The menu we are rebuilding */
  635. {
  636.     TkMenu *menuPtr = (TkMenu *) clientData;
  637.     TkMenuEntry *mePtr;
  638.     HWND os2MenuHdl = (HWND) menuPtr->platformData;
  639.     char *itemText = NULL;
  640.     PSZ pszNewItem;
  641.     USHORT flags, attrs;
  642.     USHORT itemID, base;
  643.     int i, count, systemMenu = 0;
  644.     int width = 0, height = 0;
  645.     MENUITEM menuItem;
  646.  
  647.  
  648. #ifdef VERBOSE
  649.     printf("ReconfigureOS2Menu %x (menuPtr %x)\n", os2MenuHdl, menuPtr);
  650.             fflush(stdout);
  651. #endif
  652.     if (os2MenuHdl == NULLHANDLE) {
  653.         return;
  654.     }
  655.  
  656.     /*
  657.      * Reconstruct the entire menu. Takes care of nasty system menu and index
  658.      * problem.
  659.      *
  660.      */
  661.  
  662.     if ((menuPtr->menuType == MENUBAR)
  663.         && (menuPtr->parentTopLevelPtr != NULL)) {
  664.     width = Tk_Width(menuPtr->parentTopLevelPtr);
  665.     height = Tk_Height(menuPtr->parentTopLevelPtr);
  666.     }
  667.  
  668.     base = (menuPtr->menuFlags & MENU_SYSTEM_MENU) ? 8 : 0;
  669.     count = (int) WinSendMsg(os2MenuHdl, MM_QUERYITEMCOUNT,
  670.                              MPFROMLONG(0), MPFROMLONG(0));
  671. #ifdef VERBOSE
  672.     printf("ReconfigureOS2Menu %x: base %d, count %d\n", os2MenuHdl,base,count);
  673.             fflush(stdout);
  674. #endif
  675.     for (i = base; i < count; i++) {
  676.         /*
  677.          * Extra cast to ULONG to prevent warning by GCC about casting
  678.          * from integer of different size.
  679.          */
  680.     SHORT id = (SHORT)(ULONG) WinSendMsg(os2MenuHdl, MM_ITEMIDFROMPOSITION,
  681.                                          MPFROMSHORT(base), MPFROMLONG(0));
  682.     rc = (LONG) WinSendMsg(os2MenuHdl, MM_REMOVEITEM,
  683.                                MPFROM2SHORT(id, FALSE), MPVOID);
  684. #ifdef VERBOSE
  685.         printf("ReconfigureOS2Menu %x MM_REMOVEITEM item %d id %d returns %d\n",
  686.                os2MenuHdl, i, id, rc);
  687.         fflush(stdout);
  688. #endif
  689.     }
  690.  
  691.     count = menuPtr->numEntries;
  692. #ifdef VERBOSE
  693.     printf("ReconfigureOS2Menu %x: count now %d\n", os2MenuHdl, count);
  694.             fflush(stdout);
  695. #endif
  696.     for (i = 0; i < count; i++) {
  697.     mePtr = menuPtr->entries[i];
  698.     pszNewItem = NULL;
  699.     flags = 0;
  700.     attrs = 0;
  701.     itemID = 0;
  702.     menuItem.hwndSubMenu = NULLHANDLE;
  703. #ifdef VERBOSE
  704.         printf("ReconfigureOS2Menu %x ID %d menuPtr %x mePtr %x %s %s\n",
  705.                os2MenuHdl, i, menuPtr, mePtr,
  706.                menuPtr->menuType == MENUBAR ? "MENUBAR" :
  707.                (menuPtr->menuType == TEAROFF_MENU ? "TEAROFF_MENU" :
  708.                (menuPtr->menuType == MASTER_MENU ? "MASTER_MENU": "OTHER")),
  709.                mePtr->type == COMMAND_ENTRY ? "COMMAND_ENTRY" :
  710.                (mePtr->type == SEPARATOR_ENTRY ? "SEPARATOR_ENTRY" :
  711.                (mePtr->type == CHECK_BUTTON_ENTRY ? "CHECK_BUTTON_ENTRY" :
  712.                (mePtr->type == RADIO_BUTTON_ENTRY ? "RADIO_BUTTON_ENTRY" :
  713.                (mePtr->type == CASCADE_ENTRY ? "CASCADE_ENTRY" :
  714.                (mePtr->type == TEAROFF_ENTRY ? "TEAROFF_ENTRY" : "TEXT"))))));
  715.             fflush(stdout);
  716. #endif
  717.  
  718.     if ((menuPtr->menuType == MENUBAR) && (mePtr->type == TEAROFF_ENTRY)) {
  719.         continue;
  720.     }
  721.  
  722.     if (mePtr->type == SEPARATOR_ENTRY) {
  723. #ifdef VERBOSE
  724.             printf("MIS_SEPARATOR\n");
  725.             fflush(stdout);
  726. #endif
  727.         flags |= MIS_SEPARATOR;
  728.     } else {
  729.         itemText = GetEntryText(mePtr);
  730.         if ((menuPtr->menuType == MENUBAR)
  731.             || (menuPtr->menuFlags & MENU_SYSTEM_MENU)) {
  732. #ifdef VERBOSE
  733.                 printf("%s pszNewItem = itemText [%s] MIS_TEXT\n",
  734.                        menuPtr->menuType == MENUBAR ? "MENUBAR" :
  735.                        "MENU_SYSTEM_MENU", itemText);
  736.                 fflush(stdout);
  737. #endif
  738.         flags |= MIS_TEXT;
  739.         pszNewItem = itemText;
  740.         } else {
  741. #ifdef VERBOSE
  742.                 printf("pszNewItem = mePtr (%x) itemText [%s] MIS_OWNERDRAW\n",
  743.                        mePtr, itemText);
  744.                 fflush(stdout);
  745. #endif
  746.         pszNewItem = (PSZ) mePtr;
  747.         flags |= MIS_OWNERDRAW;
  748.         }
  749.  
  750.             /*
  751.              * Set enabling and disabling correctly.
  752.              */
  753.  
  754.         if (mePtr->state == tkDisabledUid) {
  755. #ifdef VERBOSE
  756.                 printf("MIA_DISABLED\n");
  757.                 fflush(stdout);
  758. #endif
  759.         attrs |= MIA_DISABLED;
  760.         }
  761.         
  762.             /*
  763.              * Set the check mark for check entries and radio entries.
  764.              */
  765.     
  766.         if (((mePtr->type == CHECK_BUTTON_ENTRY)
  767.             || (mePtr->type == RADIO_BUTTON_ENTRY))
  768.             && (mePtr->entryFlags & ENTRY_SELECTED)) {
  769. #ifdef VERBOSE
  770.                 printf("MIA_CHECKED\n");
  771.                 fflush(stdout);
  772. #endif
  773.         attrs |= MIA_CHECKED;
  774.         }
  775.  
  776.         if (mePtr->columnBreak) {
  777. #ifdef VERBOSE
  778.                 printf("MIS_BREAK\n");
  779.                 fflush(stdout);
  780. #endif
  781.         flags |= MIS_BREAK;
  782.         }
  783.  
  784.             /*
  785.              * Extra cast to ULONG to prevent warning by GCC about casting
  786.              * from integer of different size.
  787.              */
  788.         itemID = (USHORT)(ULONG) mePtr->platformEntryData;
  789. #ifdef VERBOSE
  790.             printf("itemID %x\n", itemID);
  791.             fflush(stdout);
  792. #endif
  793.         if ((mePtr->type == CASCADE_ENTRY)
  794.             && (mePtr->childMenuRefPtr != NULL)
  795.             && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
  796.         HWND childMenuHdl = (HWND) mePtr->childMenuRefPtr->menuPtr
  797.                                         ->platformData;
  798. #ifdef VERBOSE
  799.                 printf("CASCADE_ENTRY %x\n", childMenuHdl);
  800.                 fflush(stdout);
  801. #endif
  802.             menuItem.hwndSubMenu = NULLHANDLE;
  803.         if (childMenuHdl != NULLHANDLE) {
  804. /*
  805.             itemID = (USHORT) childMenuHdl;
  806. */
  807.                 menuItem.hwndSubMenu = childMenuHdl;
  808. #ifdef VERBOSE
  809.                     printf("MIS_SUBMENU itemID %x childMenuHdl %x\n",
  810.                            itemID, childMenuHdl);
  811.                     fflush(stdout);
  812. #endif
  813.             flags |= MIS_SUBMENU;
  814.         }
  815.         if ((menuPtr->menuType == MENUBAR)
  816.             && !(mePtr->childMenuRefPtr->menuPtr->menuFlags
  817.                 & MENU_SYSTEM_MENU)) {
  818.             TkMenuReferences *menuRefPtr;
  819.             TkMenu *systemMenuPtr = mePtr->childMenuRefPtr
  820.             ->menuPtr;
  821.             char *systemMenuName = ckalloc(strlen(
  822.             Tk_PathName(menuPtr->masterMenuPtr->tkwin))
  823.                 + strlen(".system") + 1);
  824.  
  825.             strcpy(systemMenuName,
  826.                 Tk_PathName(menuPtr->masterMenuPtr->tkwin));
  827.             strcat(systemMenuName, ".system");
  828.             menuRefPtr = TkFindMenuReferences(menuPtr->interp,
  829.                 systemMenuName);
  830.             if ((menuRefPtr != NULL)
  831.                 && (menuRefPtr->menuPtr != NULL)
  832.                 && (menuPtr->parentTopLevelPtr != NULL)
  833.                 && (systemMenuPtr->masterMenuPtr
  834.                     == menuRefPtr->menuPtr)) {
  835.             HWND systemMenuHdl =
  836.                 (HWND) systemMenuPtr->platformData;
  837.             HWND wrapper = TkOS2GetWrapperWindow(menuPtr
  838.                 ->parentTopLevelPtr);
  839.             if (wrapper != NULLHANDLE) {
  840.                 MENUITEM sysMenu;
  841.  
  842.                 WinDestroyWindow(systemMenuHdl);
  843.                             systemMenuHdl = WinWindowFromID(wrapper,
  844.                                                 FID_SYSMENU);
  845.                 /* systemMenuHdl now handle of bitmap button item */
  846.                             rc = (LONG) WinSendMsg(systemMenuHdl, MM_QUERYITEM,
  847.                                             MPFROM2SHORT(SC_SYSMENU, TRUE),
  848.                                             MPFROMP(&sysMenu));
  849.                     if (rc != TRUE) {
  850.                         ckfree(systemMenuName);
  851. #ifdef VERBOSE
  852.                                 printf("WinSendMsg(%x, MM_QI SYSMENU failed\n",
  853.                                        systemMenuHdl);
  854.                                 fflush(stdout);
  855. #endif
  856.                 return;
  857.                 }
  858.                 /* sysMenu.hwndSubMenu is the real SM handle */
  859.                 systemMenuPtr->menuFlags |= MENU_SYSTEM_MENU;
  860.                 systemMenuPtr->platformData =
  861.                 (TkMenuPlatformData) sysMenu.hwndSubMenu;
  862.                 if (!(systemMenuPtr->menuFlags
  863.                     & MENU_RECONFIGURE_PENDING)) {
  864.                 systemMenuPtr->menuFlags
  865.                     |= MENU_RECONFIGURE_PENDING;
  866.                 Tcl_DoWhenIdle(ReconfigureOS2Menu,
  867.                     (ClientData) systemMenuPtr);
  868.                 }
  869.             }
  870.             }
  871.             ckfree(systemMenuName);
  872.         }
  873.         if (mePtr->childMenuRefPtr->menuPtr->menuFlags
  874.             & MENU_SYSTEM_MENU) {
  875.             systemMenu++;
  876.         }
  877.         }
  878.     }
  879.     if (!systemMenu) {
  880.         menuItem.iPosition = MIT_END;
  881.         menuItem.afStyle = flags;
  882.         menuItem.afAttribute = attrs;
  883.         menuItem.id = itemID;
  884. /*
  885.         menuItem.hItem = (ULONG)pszNewItem;
  886. */
  887.         menuItem.hItem = (ULONG)mePtr;
  888. #ifdef VERBOSE
  889.             printf("Inserting [%s] (%x) itemID %x, flags %x, attrs %x\n",
  890.                    pszNewItem, pszNewItem, itemID, flags, attrs);
  891.             fflush(stdout);
  892. #endif
  893.         rc = (LONG) WinSendMsg(os2MenuHdl, MM_INSERTITEM,
  894.                                    MPFROMP(&menuItem), MPFROMP(pszNewItem));
  895. #ifdef VERBOSE
  896.             printf("MM_INSERTITEM returns %d [%s]\n", rc,
  897.                    rc == MIT_MEMERROR ? "MIT_MEMERROR" :
  898.                    rc == MIT_ERROR ? "MIT_ERROR" : "zero-based index");
  899.             fflush(stdout);
  900. #endif
  901.     }
  902.     if (itemText != NULL) {
  903.         ckfree(itemText);
  904.         itemText = NULL;
  905.     }
  906.     }
  907.  
  908.     if ((menuPtr->menuType == MENUBAR)
  909.         && (menuPtr->parentTopLevelPtr != NULL)) {
  910.     WinSendMsg(TkOS2GetWrapperWindow(menuPtr->parentTopLevelPtr),
  911.                WM_UPDATEFRAME, MPFROMLONG(FCF_MENU), MPVOID);
  912.     Tk_GeometryRequest(menuPtr->parentTopLevelPtr, width, height);
  913.     }
  914.  
  915.     menuPtr->menuFlags &= ~(MENU_RECONFIGURE_PENDING);
  916. }
  917.  
  918. /*
  919.  *----------------------------------------------------------------------
  920.  *
  921.  * TkpPostMenu --
  922.  *
  923.  *    Posts a menu on the screen
  924.  *
  925.  * Results:
  926.  *    None.
  927.  *
  928.  * Side effects:
  929.  *    The menu is posted and handled.
  930.  *
  931.  *----------------------------------------------------------------------
  932.  */
  933.  
  934. int
  935. TkpPostMenu(interp, menuPtr, x, y)
  936.     Tcl_Interp *interp;
  937.     TkMenu *menuPtr;
  938.     int x;
  939.     int y;
  940. {
  941.     HWND os2MenuHdl = (HWND) menuPtr->platformData;
  942.     int result, flags;
  943.     RECTL rectl;
  944. /*
  945.     Tk_Window parentWindow = Tk_Parent(menuPtr->tkwin);
  946. */
  947.     int oldServiceMode = Tcl_GetServiceMode();
  948. #ifdef VERBOSE
  949.     printf("TkpPostMenu (%d,%d) => (%d,%d)\n", x, y, x,
  950.            yScreen - menuPtr->totalHeight - y);
  951.     fflush(stdout);
  952. #endif
  953.  
  954.     inPostMenu++;
  955.  
  956.     if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) {
  957.     Tcl_CancelIdleCall(ReconfigureOS2Menu, (ClientData) menuPtr);
  958.     ReconfigureOS2Menu((ClientData) menuPtr);
  959.     }
  960.  
  961.     result = TkPreprocessMenu(menuPtr);
  962.     if (result != TCL_OK) {
  963.     inPostMenu--;
  964.     return result;
  965.     }
  966.  
  967.     /*
  968.      * The post commands could have deleted the menu, which means
  969.      * we are dead and should go away.
  970.      */
  971.  
  972.     if (menuPtr->tkwin == NULL) {
  973.     inPostMenu--;
  974.         return TCL_OK;
  975.     }
  976.  
  977.     Tcl_SetServiceMode(TCL_SERVICE_NONE);
  978.  
  979.     /*
  980.      * Make an assumption here. If the right button is down,
  981.      * then we want to track it. Otherwise, track the left mouse button.
  982.      */
  983.  
  984.     flags = PU_KEYBOARD;
  985.     if (WinQuerySysValue(HWND_DESKTOP, SV_SWAPBUTTON)) {
  986.     if (WinGetPhysKeyState(HWND_DESKTOP, VK_BUTTON1) == 0x8000) {
  987.         flags |= PU_MOUSEBUTTON2DOWN | PU_MOUSEBUTTON2;
  988. #ifdef VERBOSE
  989.             printf("Popup: swapped, PU_MOUSEBUTTON2\n");
  990. #endif
  991.     } else {
  992.         flags |= PU_MOUSEBUTTON1DOWN | PU_MOUSEBUTTON1;
  993. #ifdef VERBOSE
  994.             printf("Popup: swapped, PU_MOUSEBUTTON1\n");
  995. #endif
  996.     }
  997.     } else {
  998.     if (WinGetPhysKeyState(HWND_DESKTOP, VK_BUTTON2) == 0x8000) {
  999.         flags |= PU_MOUSEBUTTON2DOWN | PU_MOUSEBUTTON2;
  1000. #ifdef VERBOSE
  1001.             printf("Popup: not swapped, PU_MOUSEBUTTON2\n");
  1002. #endif
  1003.     } else {
  1004.         flags |= PU_MOUSEBUTTON1DOWN | PU_MOUSEBUTTON1;
  1005. #ifdef VERBOSE
  1006.             printf("Popup: not swapped, PU_MOUSEBUTTON1\n");
  1007. #endif
  1008.     }
  1009.     }
  1010.  
  1011.     /*
  1012.      * WinPopupMenu returns immediately and doesn't wait for the popup menu
  1013.      * to be dismissed as in Windows. When it is dismissed, the window gets
  1014.      * a WM_MENUEND message => postpone "after dismissed" handling to the
  1015.      * receipt of that message.
  1016.      * It turns out that menuPtr->totalHeight is not quite correct (must be
  1017.      * something font-related), causing the translation of the X coordinate
  1018.      * tot the PM coordinate to give a wrong result. OTOH, the first time
  1019.      * the menu is being posted, WinQueryWindowRect doesn't give a correct
  1020.      * value either (always 3 for the height).
  1021.      * So for now resort to a hack: WinPopupMenu above the screen (don't
  1022.      * forget to remove the PU_HCONSTRAIN and PU_VCONSTRAIN), then query the
  1023.      * height (now this give correct output) and reposition the window.
  1024.      */
  1025. /*
  1026.     rc = WinPopupMenu(HWND_DESKTOP, menuHWND, os2MenuHdl, x,
  1027.                       yScreen - menuPtr->totalHeight - y, 0L, flags);
  1028. */
  1029.     rc = WinPopupMenu(HWND_DESKTOP, menuHWND, os2MenuHdl, x,
  1030.                       yScreen, 0L, flags);
  1031. #ifdef VERBOSE
  1032.     if (rc != TRUE) {
  1033.         printf("WinPopupMenu %x %x %x (%d,%d) fl %x ERROR %x\n", HWND_DESKTOP,
  1034.                menuHWND, os2MenuHdl, x, yScreen, flags,
  1035.                WinGetLastError(TclOS2GetHAB()));
  1036.     } else {
  1037.         printf("WinPopupMenu %x %x %x (%d,%d) fl %x OK\n", HWND_DESKTOP,
  1038.                menuHWND, os2MenuHdl, x, yScreen, flags);
  1039.     }
  1040. #endif
  1041.     rc = WinQueryWindowRect(os2MenuHdl, &rectl);
  1042. #ifdef VERBOSE
  1043.     if (rc != TRUE) {
  1044.         printf("WinQueryWindowRect %x ERROR %x\n", os2MenuHdl,
  1045.                WinGetLastError(TclOS2GetHAB()));
  1046.     } else {
  1047.         printf("WinQueryWindowRect %x OK (%d,%d)(%d,%d)\n", os2MenuHdl,
  1048.                rectl.xLeft, rectl.yBottom, rectl.xRight, rectl.yTop);
  1049.     }
  1050. #endif
  1051.     rc = WinSetWindowPos(os2MenuHdl, HWND_TOP, x, yScreen - rectl.yTop - y, 0,
  1052.                          0, SWP_MOVE | SWP_NOADJUST);
  1053. #ifdef VERBOSE
  1054.     if (rc != TRUE) {
  1055.         printf("WinSetWindowPos %x -> (%d,%d) ERROR %x\n", os2MenuHdl, x,
  1056.                yScreen - rectl.yTop - y, WinGetLastError(TclOS2GetHAB()));
  1057.     } else {
  1058.         printf("WinSetWindowPos %x -> (%d,%d) OK\n", os2MenuHdl, x,
  1059.                yScreen - rectl.yTop - y);
  1060.     }
  1061. #endif
  1062.     Tcl_SetServiceMode(oldServiceMode);
  1063.  
  1064.     return TCL_OK;
  1065. }
  1066.  
  1067. /*
  1068.  *----------------------------------------------------------------------
  1069.  *
  1070.  * TkpMenuNewEntry --
  1071.  *
  1072.  *    Adds a pointer to a new menu entry structure with the platform-
  1073.  *    specific fields filled in.
  1074.  *
  1075.  * Results:
  1076.  *    Standard TCL error.
  1077.  *
  1078.  * Side effects:
  1079.  *    A new command ID is allocated and stored in the platformEntryData
  1080.  *    field of mePtr.
  1081.  *
  1082.  *----------------------------------------------------------------------
  1083.  */
  1084.  
  1085. int
  1086. TkpMenuNewEntry(mePtr)
  1087.     TkMenuEntry *mePtr;
  1088. {
  1089.     int commandID;
  1090.     TkMenu *menuPtr = mePtr->menuPtr;
  1091. #ifdef VERBOSE
  1092.     printf("TkpMenuNewEntry\n");
  1093.             fflush(stdout);
  1094. #endif
  1095.  
  1096.     if (GetNewID(mePtr, &commandID) != TCL_OK) {
  1097.         return TCL_ERROR;
  1098.     }
  1099.  
  1100.     if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
  1101.         menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  1102.         Tcl_DoWhenIdle(ReconfigureOS2Menu, (ClientData) menuPtr);
  1103.     }
  1104.  
  1105.     mePtr->platformEntryData = (TkMenuPlatformEntryData) commandID;
  1106. #ifdef VERBOSE
  1107.     printf("TkpMenuNewEntry returning %d for mePtr %x\n", commandID, mePtr);
  1108.             fflush(stdout);
  1109. #endif
  1110.  
  1111.     return TCL_OK;
  1112. }
  1113.  
  1114. /*
  1115.  *----------------------------------------------------------------------
  1116.  *
  1117.  * TkOS2MenuProc --
  1118.  *
  1119.  *    The window proc for the dummy window we put popups in. This allows
  1120.  *    us to post a popup whether or not we know what the parent window
  1121.  *    is.
  1122.  *
  1123.  * Results:
  1124.  *    Returns whatever is appropriate for the message in question.
  1125.  *
  1126.  * Side effects:
  1127.  *    Normal side-effect for OS/2 messages.
  1128.  *
  1129.  *----------------------------------------------------------------------
  1130.  */
  1131.  
  1132. static MRESULT EXPENTRY
  1133. TkOS2MenuProc(hwnd, message, param1, param2)
  1134.     HWND hwnd;
  1135.     ULONG message;
  1136.     MPARAM param1;
  1137.     MPARAM param2;
  1138. {
  1139.     MRESULT mResult;
  1140. #ifdef VERBOSE
  1141.     printf("TkOS2MenuProc msg %x\n", message);
  1142.             fflush(stdout);
  1143. #endif
  1144.  
  1145.     /*
  1146.      * WinPopupMenu returns immediately and doesn't wait for the popup menu
  1147.      * to be dismissed as in Windows. When it is dismissed, the window gets
  1148.      * a WM_MENUEND message.
  1149.      */
  1150.     if (message == WM_MENUEND) {
  1151. #ifdef VERBOSE
  1152.         USHORT usMenuId = SHORT1FROMMP(param1);
  1153.         HWND hwndMenu = HWNDFROMMP(param2);
  1154.             printf("MenuProc WM_MENUEND, usMenuId %d, hwnd %x\n", usMenuId,
  1155.                    hwndMenu);
  1156.             fflush(stdout);
  1157. #endif
  1158.         if (inPostMenu) {
  1159.         inPostMenu = 0;
  1160.         }
  1161.     }
  1162.     if (!TkOS2HandleMenuEvent(&hwnd, &message, ¶m1, ¶m2, &mResult)) {
  1163.     mResult = oldMenuProc(hwnd, message, param1, param2);
  1164. #ifdef VERBOSE
  1165.         printf("TkOS2MenuProc called oldMenuProc %x for msg %x: %x\n",
  1166.                oldMenuProc, message, mResult);
  1167.         fflush(stdout);
  1168. #endif
  1169.     }
  1170.     return mResult;
  1171. }
  1172.  
  1173. /*
  1174.  *----------------------------------------------------------------------
  1175.  *
  1176.  * TkOS2HandleMenuEvent --
  1177.  *
  1178.  *    Filters out menu messages from messages passed to a top-level.
  1179.  *    Will respond appropriately to WM_COMMAND, WM_MENUSELECT,
  1180.  *    WM_MEASUREITEM, WM_DRAWITEM
  1181.  *
  1182.  * Result:
  1183.  *    Returns 1 if this handled the message; 0 if it did not.
  1184.  *
  1185.  * Side effects:
  1186.  *    All of the parameters may be modified so that the caller can
  1187.  *    think it is getting a different message. pmResult points to
  1188.  *    the result that should be returned to OS/2 from this message.
  1189.  *
  1190.  *----------------------------------------------------------------------
  1191.  */
  1192.  
  1193. int
  1194. TkOS2HandleMenuEvent(pHwnd, pMessage, pParam1, pParam2, pmResult)
  1195.     HWND *pHwnd;
  1196.     ULONG *pMessage;
  1197.     MPARAM *pParam1;
  1198.     MPARAM *pParam2;
  1199.     MRESULT *pmResult;
  1200. {
  1201.     Tcl_HashEntry *hashEntryPtr;
  1202.     int returnResult = 0;
  1203.     TkMenu *menuPtr;
  1204.     TkMenuEntry *mePtr;
  1205. #ifdef VERBOSE
  1206.     printf("TkOS2HandleMenuEvent msg %x, p1 %x, p2 %x\n", *pMessage, *pParam1,
  1207.            *pParam2);
  1208.             fflush(stdout);
  1209. #endif
  1210.  
  1211.     switch (*pMessage) {
  1212. #ifdef VERBOSE
  1213.     case WM_QUERYWINDOWPARAMS: {
  1214.             printf("WM_QUERYWINDOWPARAMS p1 %x p2 %x\n", *pParam1, *pParam2);
  1215.             fflush(stdout);
  1216.             break;
  1217.         }
  1218.     case MM_QUERYITEMATTR: {
  1219.             printf("MM_QUERYITEMATTR p1 %x p2 %x\n", *pParam1, *pParam2);
  1220.             fflush(stdout);
  1221.             break;
  1222.         }
  1223.     case MM_SETITEMATTR: {
  1224.             printf("MM_SETITEMATTR p1 %x p2 %x\n", *pParam1, *pParam2);
  1225.             fflush(stdout);
  1226.             break;
  1227.         }
  1228.     case WM_CHAR: {
  1229.             printf("WM_CHAR menu p1 %x p2 %x\n", *pParam1, *pParam2);
  1230.             fflush(stdout);
  1231.             break;
  1232.         }
  1233.     case WM_TRANSLATEACCEL: {
  1234.             PQMSG pqmsg = PVOIDFROMMP(*pParam1);
  1235.             USHORT flags = (USHORT) SHORT1FROMMP(pqmsg->mp1);
  1236.             UCHAR krepeat = (UCHAR) SHORT2FROMMP(pqmsg->mp1);
  1237.             USHORT charcode = (USHORT) SHORT1FROMMP(pqmsg->mp2);
  1238.             USHORT vkeycode = (USHORT) SHORT2FROMMP(pqmsg->mp2);
  1239.             printf("WM_TRANSLATEACCEL menu p1 %x p2 %x\n", *pParam1, *pParam2);
  1240.             printf("WM_TRANSLATEACCEL menu h %x m %x mp1 %x mp2 %x\n",
  1241.                    ((PQMSG)(*pParam1))->hwnd, ((PQMSG)(*pParam1))->msg,
  1242.                    ((PQMSG)(*pParam1))->mp1, ((PQMSG)(*pParam1))->mp2);
  1243.             printf("WM_TRANSLATEACCEL menu vk %x repeat %x char %x fl %x\n",
  1244.                    vkeycode, krepeat, charcode, flags);
  1245.             fflush(stdout);
  1246.             break;
  1247.         }
  1248. #endif
  1249.  
  1250.     case WM_INITMENU:
  1251. #ifdef VERBOSE
  1252.             printf("WM_INITMENU id %x hwnd %x\n", SHORT1FROMMP(*pParam1),
  1253.                    HWNDFROMMP(*pParam2));
  1254.             fflush(stdout);
  1255. #endif
  1256.             *pmResult = 0;
  1257.         /* Sent for every menu, even popup menus */
  1258.         TkMenuInit();
  1259.         hashEntryPtr = Tcl_FindHashEntry(&os2MenuTable, (char *) *pParam2);
  1260.         if (hashEntryPtr != NULL) {
  1261.         oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
  1262.         menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr);
  1263.         modalMenuPtr = menuPtr;
  1264.         if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) {
  1265.             Tcl_CancelIdleCall(ReconfigureOS2Menu,
  1266.                 (ClientData) menuPtr);
  1267.             ReconfigureOS2Menu((ClientData) menuPtr);
  1268.         }
  1269.         if (!inPostMenu) {
  1270.             Tcl_Interp *interp;
  1271.             int code;
  1272.  
  1273.             interp = menuPtr->interp;
  1274.             Tcl_Preserve((ClientData)interp);
  1275.             code = TkPreprocessMenu(menuPtr);
  1276.             if ((code != TCL_OK) && (code != TCL_CONTINUE)
  1277.                 && (code != TCL_BREAK)) {
  1278.             Tcl_AddErrorInfo(interp, "\n    (menu preprocess)");
  1279.             Tcl_BackgroundError(interp);
  1280.             }
  1281.             Tcl_Release((ClientData)interp);
  1282.         }
  1283.         TkActivateMenuEntry(menuPtr, -1);
  1284.         returnResult = 1;
  1285.         } else {
  1286.         modalMenuPtr = NULL;
  1287.         }
  1288.         break;
  1289.  
  1290.     case WM_COMMAND: {
  1291.         /* Windows: item from menu chosen, control passes a message to its
  1292.            parent window or accelerator key translated */
  1293.         /* param1 menu item/control ID/accelerator ID; param2 HIWORD 0 =>
  1294.            from menu, HIWORD 1=> accel., from control => HIWORD notification
  1295.            code, LOWORD hwnd of sending control */
  1296.         /*
  1297.          * OS/2: param1 LOWORD control specific
  1298.          * param2 HIWORD source              LOWORD param1
  1299.          *               CMDSRC_PUSHBUTTON   windowID PB
  1300.          *               CMDSRC_MENU         windowID menu
  1301.          *               CMDSRC_ACCELERATOR  accel.command value
  1302.          *               CMDSRC_FONTDLG      font dialog identity
  1303.          *               CMDSRC_FILEDLG      file dialog identity
  1304.          *               CMDSRC_OTHER        control specific
  1305.          *        LOWORD TRUE => result of pointing-device operation
  1306.          *               FALSE => result of keyboard operation
  1307.          * Sent to owner of control.
  1308.          */
  1309.         USHORT usSource = (USHORT)SHORT1FROMMP(*pParam2);
  1310.         USHORT usCmd = (USHORT)SHORT1FROMMP(*pParam1);
  1311. #ifdef VERBOSE
  1312.             USHORT pointer = (USHORT)SHORT2FROMMP(*pParam2);
  1313.             printf("WM_COMMAND cmd %x, usSource %s, pointer %d\n", usCmd,
  1314.                    usSource == CMDSRC_OTHER ? "CMDSRC_OTHER" :
  1315.                    (usSource == CMDSRC_PUSHBUTTON ? "CMDSRC_PUSHBUTTON" :
  1316.                    (usSource == CMDSRC_ACCELERATOR ? "CMDSRC_ACCELERATOR" :
  1317.                    (usSource == CMDSRC_FONTDLG ? "CMDSRC_FONTDLG" :
  1318.                    (usSource == CMDSRC_FILEDLG ? "CMDSRC_FILEDLG" :
  1319.                    (usSource == CMDSRC_PRINTDLG ? "CMDSRC_PRINTDLG" :
  1320.                    (usSource == CMDSRC_COLORDLG ? "CMDSRC_COLORDLG" :
  1321.                    (usSource == CMDSRC_MENU ? "CMDSRC_MENU" : "UNKNOWN"))))))),
  1322.                    pointer);
  1323.             fflush(stdout);
  1324. #endif
  1325.             *pmResult = 0;
  1326.  
  1327.         switch (usSource) {
  1328.             case CMDSRC_MENU:
  1329. #ifdef VERBOSE
  1330.                 printf("CMDSRC_MENU\n");
  1331.                 fflush(stdout);
  1332. #endif
  1333.                 TkMenuInit();
  1334.                 /*
  1335.                  * Extra cast to ULONG to prevent warning by GCC about casting
  1336.                  * from integer of different size.
  1337.                  */
  1338.                 hashEntryPtr = Tcl_FindHashEntry(&commandTable,
  1339.                         (char *)(LONG)SHORT1FROMMP(*pParam1));
  1340.                 if (hashEntryPtr == NULL) {
  1341.                     break;
  1342.                 }
  1343.                 mePtr = (TkMenuEntry *) Tcl_GetHashValue(hashEntryPtr);
  1344.                 if (mePtr != NULL) {
  1345.                     TkMenuReferences *menuRefPtr;
  1346.                     TkMenuEntry *parentEntryPtr;
  1347.                     Tcl_Interp *interp;
  1348.                     int code;
  1349.  
  1350.                     /*
  1351.                      * We have to set the parent of this menu to be active
  1352.                      * if this is a submenu so that tearoffs will get the
  1353.                      * correct title.
  1354.                      */
  1355.  
  1356.                     menuPtr = mePtr->menuPtr;
  1357.                     menuRefPtr = TkFindMenuReferences(menuPtr->interp,
  1358.                             Tk_PathName(menuPtr->tkwin));
  1359.                     if ((menuRefPtr != NULL) && (menuRefPtr->parentEntryPtr
  1360.                             != NULL)) {
  1361.                         for (parentEntryPtr = menuRefPtr->parentEntryPtr;
  1362.                              strcmp(parentEntryPtr->name,
  1363.                                      Tk_PathName(menuPtr->tkwin)) != 0;
  1364.                              parentEntryPtr = parentEntryPtr->nextCascadePtr) {
  1365.  
  1366.                             /*
  1367.                              * Empty loop body.
  1368.                              */
  1369.  
  1370.                         }
  1371.                         if (parentEntryPtr->menuPtr
  1372.                                 ->entries[parentEntryPtr->index]->state
  1373.                                 != tkDisabledUid) {
  1374.                             TkActivateMenuEntry(parentEntryPtr->menuPtr,
  1375.                                     parentEntryPtr->index);
  1376.                         }
  1377.                     }
  1378.  
  1379.                     interp = menuPtr->interp;
  1380.                     Tcl_Preserve((ClientData)interp);
  1381.                     code = TkInvokeMenu(interp, menuPtr, mePtr->index);
  1382.                     if ((code != TCL_OK) && (code != TCL_CONTINUE)
  1383.                             && (code != TCL_BREAK)) {
  1384.                         Tcl_AddErrorInfo(interp, "\n    (menu invoke)");
  1385.                         Tcl_BackgroundError(interp);
  1386.                     }
  1387.                     Tcl_Release((ClientData)interp);
  1388.                 }
  1389.                 *pmResult = 0;
  1390.                 returnResult = 1;
  1391.                 break;
  1392.  
  1393.         case CMDSRC_ACCELERATOR: {
  1394.             unsigned char menuChar = (unsigned char) SHORT1FROMMP(*pParam1);
  1395.                 TkWindow *winPtr = (TkWindow *) WinQueryWindowULong(*pHwnd,
  1396.                                                                     QWL_USER);
  1397. #ifdef VERBOSE
  1398.                 printf("CMDSRC_ACCELERATOR, winPtr %x\n", winPtr);
  1399.                 printf("display %x (screens %x), screenNum %d, screen %x\n",
  1400.                        winPtr ? winPtr->display : 0,
  1401.                        winPtr ? winPtr->display->screens : 0,
  1402.                        winPtr ? winPtr->screenNum : 0,
  1403.                        winPtr && winPtr->display->screens != NULL ?
  1404.                        RootWindow(winPtr->display, winPtr->screenNum) : 0L);
  1405.                 fflush(stdout);
  1406. #endif
  1407.                 if (!winPtr || !winPtr->wmInfoPtr) {
  1408.                     break;
  1409.                 }
  1410.         /* Message comes from frame window */
  1411.             hashEntryPtr = Tcl_FindHashEntry(&os2MenuTable,
  1412.                                    (char *) winPtr->wmInfoPtr->wrapper);
  1413.             if (hashEntryPtr != NULL) {
  1414.             int i;
  1415.  
  1416.             *pmResult = 0;
  1417.             menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr);
  1418.             for (i = 0; i < menuPtr->numEntries; i++) {
  1419.                 int underline = menuPtr->entries[i]->underline;
  1420.                 if ((-1 != underline)
  1421.                     && (NULL != menuPtr->entries[i]->label)
  1422.                     && (toupper( menuChar)
  1423.                     == toupper( (unsigned char) menuPtr
  1424.                     ->entries[i]->label[underline]))) {
  1425.                 *pmResult = (MRESULT) ((2 << 16) | i);
  1426.                 returnResult = 1;
  1427.                 break;
  1428.                 }
  1429.             }
  1430.             }
  1431.             break;
  1432.         }
  1433.  
  1434.         case CMDSRC_PUSHBUTTON: {
  1435.                 HWND buttonHwnd = WinWindowFromID(*pHwnd, usCmd);
  1436.                 POINTL msgPos;
  1437.                 WinQueryMsgPos(TclOS2GetHAB(), &msgPos);
  1438.                 buttonHwnd = WinWindowFromPoint(HWND_DESKTOP, &msgPos, TRUE);
  1439. #ifdef VERBOSE
  1440.                 printf("TkOS2HandleMenuEvent: CMDSRC_PUSHBUTTON id %x hwnd %x\n", usCmd, buttonHwnd);
  1441.                 fflush(stdout);
  1442. #endif
  1443.                 if (buttonHwnd != NULLHANDLE && buttonHwnd != *pHwnd) {
  1444.                     *pmResult = WinSendMsg(buttonHwnd, *pMessage, *pParam1,
  1445.                                            *pParam2);
  1446.                     returnResult = 1;
  1447.                 }
  1448.             break;
  1449.             }
  1450. #ifdef VERBOSE
  1451.         case CMDSRC_FONTDLG:
  1452.                 printf("TkOS2HandleMenuEvent: CMDSRC_FONTDLG\n");
  1453.                 fflush(stdout);
  1454.             break;
  1455.         case CMDSRC_FILEDLG:
  1456.                 printf("TkOS2HandleMenuEvent: CMDSRC_FILEDLG\n");
  1457.                 fflush(stdout);
  1458.             break;
  1459.         case CMDSRC_OTHER:
  1460.                 printf("TkOS2HandleMenuEvent: CMDSRC_OTHER\n");
  1461.                 fflush(stdout);
  1462.             break;
  1463. #endif
  1464.         } /* switch */
  1465.         break;
  1466.     }
  1467.  
  1468.     case WM_MEASUREITEM: {
  1469.         POWNERITEM itemPtr = (POWNERITEM) *pParam2;
  1470.             *pmResult = (MRESULT) 0;
  1471.  
  1472.         if (itemPtr != NULL) {
  1473.         mePtr = (TkMenuEntry *) itemPtr->hItem;
  1474. #ifdef VERBOSE
  1475.             printf("WM_MEASUREITEM h %x id %d hI %x hps %x mePtr: (%d,%d) %dx%d\n",
  1476.                    *pHwnd, itemPtr->idItem, itemPtr->hItem, itemPtr->hps,
  1477.                    mePtr->x, mePtr->y, mePtr->width, mePtr->height);
  1478.             fflush(stdout);
  1479. #endif
  1480.         menuPtr = mePtr->menuPtr;
  1481.  
  1482.         TkRecomputeMenu(menuPtr);
  1483. #ifdef VERBOSE
  1484.                 printf("WM_MEASUREITEM, after TkRecomputeMenu: (%d,%d) %dx%d\n",
  1485.                        mePtr->x, mePtr->y, mePtr->width, mePtr->height);
  1486.                 fflush(stdout);
  1487. #endif
  1488.         itemPtr->rclItem.xLeft = 0;
  1489.         itemPtr->rclItem.yBottom = 0;
  1490.         itemPtr->rclItem.xRight = mePtr->width;
  1491.         itemPtr->rclItem.yTop = mePtr->height;
  1492.         if (mePtr->hideMargin) {
  1493.             itemPtr->rclItem.xRight += 2 - indicatorDimensions[0];
  1494.         } else {
  1495.             itemPtr->rclItem.xRight += 2 * menuPtr->activeBorderWidth;
  1496.         }
  1497. #ifdef VERBOSE
  1498.                 printf("WM_MEASUREITEM, returning %d-%d (rectl %d,%d-%d,%d)\n",
  1499.                        itemPtr->rclItem.yTop, itemPtr->rclItem.yBottom,
  1500.                        itemPtr->rclItem.xLeft, itemPtr->rclItem.yBottom,
  1501.                        itemPtr->rclItem.xRight, itemPtr->rclItem.yTop);
  1502.                 fflush(stdout);
  1503. #endif
  1504.                 *pmResult = (MRESULT) itemPtr->rclItem.yTop
  1505.                                       - itemPtr->rclItem.yBottom;
  1506.         returnResult = 1;
  1507.         }
  1508.         break;
  1509.     }
  1510.     
  1511.     case WM_DRAWITEM: {
  1512.         TkOS2Drawable *todPtr;
  1513.         POWNERITEM itemPtr = (POWNERITEM) *pParam2;
  1514.         Tk_FontMetrics fontMetrics;
  1515. #ifdef VERBOSE
  1516.             printf("WM_DRAWITEM hwnd %x, idItem %d, hItem %x, hps %x\n",
  1517.                    *pHwnd, itemPtr->idItem, itemPtr->hItem, itemPtr->hps);
  1518.             fflush(stdout);
  1519. #endif
  1520.         *pmResult = (MRESULT) FALSE;
  1521.  
  1522.         if (itemPtr != NULL) {
  1523.                 SWP pos;
  1524.         mePtr = (TkMenuEntry *) itemPtr->hItem;
  1525.         menuPtr = mePtr->menuPtr;
  1526. #ifdef VERBOSE
  1527.                 printf("WM_DRAWITEM menuPtr %x mePtr %x (%d,%d) %dx%d [%s]\n",
  1528.                        menuPtr, mePtr, mePtr->x, mePtr->y, mePtr->width,
  1529.                        mePtr->height, mePtr->label);
  1530.                 fflush(stdout);
  1531. #endif
  1532.         todPtr = (TkOS2Drawable *) ckalloc(sizeof(TkOS2Drawable));
  1533. #ifdef VERBOSE
  1534.                 printf("    new todPtr (drawable) %x\n", todPtr);
  1535.                 printf("Attr %x AttrOld %x State %x StateOld %x (%d,%d)-(%d,%d)\n",
  1536.                        itemPtr->fsAttribute, itemPtr->fsAttributeOld,
  1537.                        itemPtr->fsState, itemPtr->fsStateOld,
  1538.                        itemPtr->rclItem.xLeft, itemPtr->rclItem.yBottom,
  1539.                        itemPtr->rclItem.xRight, itemPtr->rclItem.yTop);
  1540.                 fflush(stdout);
  1541. #endif
  1542.         todPtr->type = TOD_OS2PS;
  1543.         todPtr->os2PS.hwnd = itemPtr->hwnd;
  1544.         todPtr->os2PS.hps = itemPtr->hps;
  1545.                 if (aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER) {
  1546.                     TkOS2SelectPalette(itemPtr->hps, itemPtr->hwnd,
  1547.                                     Tk_Colormap(menuPtr->masterMenuPtr->tkwin));
  1548.                 } else {
  1549.                     /* Recreate the color table in RGB mode */
  1550.                     rc = GpiCreateLogColorTable(todPtr->os2PS.hps,0L, LCOLF_RGB,
  1551.                                                 0L, nextColor, logColorTable);
  1552. #ifdef VERBOSE
  1553.                     if (rc==FALSE) {
  1554.                         printf("  GpiCreateLogColorTable ERROR %x\n",
  1555.                                WinGetLastError(TclOS2GetHAB()));
  1556.                     } else {
  1557.                         printf("  GpiCreateLogColorTable OK (%d elements)\n",
  1558.                                nextColor);
  1559.                     }
  1560. #endif
  1561.                 }
  1562.  
  1563.         /*
  1564.          * There are two possibilities when getting this message:
  1565.          * 1. The item must be redrawn completely.
  1566.          *    This is the case when fsState and fsStateOld fields are
  1567.          *    the same. Drawing needs to be done considering the
  1568.          *    attributes it has (MIA_CHECKED, MIA_FRAMED, MIA_DISABLED).
  1569.          *    Attributes you draw yourself need to be cleared in both
  1570.          *    the fsAttribute and fsAttributeOld fields to prevent the
  1571.          *    system from drawing them.
  1572.                  * 2. An attribute has changed.
  1573.                  * Since Tk handles this all itself, we just determine if the
  1574.          * item must be highlighted or unhighlighted.
  1575.          * This is the case when the fsAttribute and fsAttributeOld
  1576.          * fields are not the same (an attribute has changed, case 2)
  1577.                  * and the MIA_HILITED bit has changed.
  1578.                  * If the MIA_HILITED bit of the fsAttribute field is set the
  1579.                  * item needs to be highlighted, if it's not set it needs to
  1580.                  * be unhighlighted.
  1581.          */
  1582.  
  1583.         if (mePtr->state != tkDisabledUid) {
  1584.                     if (itemPtr->fsAttribute & MIA_HILITED) {
  1585.                         /* Activate this entry */
  1586.                         TkActivateMenuEntry(menuPtr, mePtr->index);
  1587.                     } else {
  1588.                         /* Deactivate this entry */
  1589.                         TkActivateMenuEntry(menuPtr, -1);
  1590.                     }
  1591.                 }
  1592. if (itemPtr->fsAttribute == itemPtr->fsAttributeOld) {
  1593.                 /* Redraw the entire item. */
  1594.                 Tk_GetFontMetrics(menuPtr->tkfont, &fontMetrics);
  1595.                 rc = WinQueryWindowPos(itemPtr->hwnd, &pos);
  1596.                 TkpDrawMenuEntry(mePtr, (Drawable) todPtr, menuPtr->tkfont,
  1597.                                  &fontMetrics, itemPtr->rclItem.xLeft,
  1598.                                  pos.cy - itemPtr->rclItem.yTop,
  1599.                                  itemPtr->rclItem.xRight-itemPtr->rclItem.xLeft,
  1600.                                  itemPtr->rclItem.yTop-itemPtr->rclItem.yBottom,
  1601.                                  0, 0);
  1602. /*
  1603. #ifdef VERBOSE
  1604.                 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1605.                               "After TkpDrawMenuEntry", "DEBUG", 1L, MB_OK);
  1606.                 printf("After WinMessageBox\n");
  1607.                 fflush(stdout);
  1608. #endif
  1609.                 itemPtr->fsAttributeOld = itemPtr->fsAttribute = 0;
  1610. if (itemPtr->fsAttribute & MIA_CHECKED) {
  1611.                 itemPtr->fsAttributeOld = itemPtr->fsAttribute = MIA_CHECKED;
  1612. } else {
  1613.                 itemPtr->fsAttributeOld = itemPtr->fsAttribute = 0;
  1614. }
  1615. */
  1616.  
  1617.                 *pmResult = (MRESULT) TRUE; /* TRUE -> Item has been drawn */
  1618. } else {
  1619.                 *pmResult = (MRESULT) FALSE; /* TRUE -> Item has been drawn */
  1620. }
  1621. #ifdef VERBOSE
  1622.                 printf("Now Attr %x AttrOld %x State %x StateOld %x (%d,%d)-(%d,%d)\n",
  1623.                        itemPtr->fsAttribute, itemPtr->fsAttributeOld,
  1624.                        itemPtr->fsState, itemPtr->fsStateOld,
  1625.                        itemPtr->rclItem.xLeft, itemPtr->rclItem.yBottom,
  1626.                        itemPtr->rclItem.xRight, itemPtr->rclItem.yTop);
  1627.                 fflush(stdout);
  1628. #endif
  1629.          /*
  1630.          */
  1631.                 ckfree((char *) todPtr);
  1632.                 returnResult = 1;
  1633.             }
  1634.             break;
  1635.         }
  1636.  
  1637.     case WM_MENUSELECT: {
  1638.         /*
  1639.              * Win32 -> OS/2:
  1640.              * Replace with WM_MENUSELECT and MM_QUERYITEM messages.
  1641.              * The menu window handle is in the second parameter.  The
  1642.              * menu identifier is in SHORT1FROMMP(mp1).  Send MM_QUERYITEM
  1643.              * to query the menu flags for the menu item identified in
  1644.              * SHORT2FROMMP(mp1).  A menu identifier of -1 in OS/2
  1645.              * indicates that the submenu is being closed, but does not
  1646.              * necessarily indicate that menu processing is complete.
  1647. Windows:
  1648. flags = HIWORD(wParam)  MIA_CHECKED etc.
  1649. item = LOWORD(wParam)
  1650. hMenu = lParam
  1651. process this message => should return 0
  1652. flags 0xFFFF and hMenu NULL => closed menu
  1653.          */
  1654.         USHORT usItemId = SHORT1FROMMP(*pParam1);
  1655.         USHORT usPostCmd = SHORT2FROMMP(*pParam1);
  1656.         HWND hwndMenu = HWNDFROMMP(*pParam2);
  1657. #ifdef VERBOSE
  1658.             printf("WM_MENUSELECT usItem %x usPostC %x hwnd %x modalMenu %x\n",
  1659.                usItemId, usPostCmd, hwndMenu, modalMenuPtr);
  1660.             fflush(stdout);
  1661. #endif
  1662.         *pmResult = (MRESULT) FALSE;
  1663.  
  1664.         TkMenuInit();
  1665.  
  1666.         if (usItemId == 0xFFFF) {
  1667.                 /* Menu was closed */
  1668. #ifdef VERBOSE
  1669.                 printf("WM_MENUSELECT closing\n");
  1670.                 fflush(stdout);
  1671. #endif
  1672.         Tcl_SetServiceMode(oldServiceMode);
  1673.         if (modalMenuPtr != NULL) {
  1674.             RecursivelyClearActiveMenu(modalMenuPtr);
  1675.         }
  1676.         } else {
  1677.         menuPtr = NULL;
  1678.         if (hwndMenu != NULLHANDLE) {
  1679.             hashEntryPtr = Tcl_FindHashEntry(&os2MenuTable,
  1680.                 (char *) hwndMenu);
  1681. #ifdef VERBOSE
  1682.                     printf("hashEntryPtr %x for hwnd %x\n", hashEntryPtr,
  1683.                            hwndMenu);
  1684.                     fflush(stdout);
  1685. #endif
  1686.             if (hashEntryPtr != NULL) {
  1687.             menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr);
  1688. #ifdef VERBOSE
  1689.                         printf("menuPtr %x\n", menuPtr);
  1690.                         fflush(stdout);
  1691. #endif
  1692.             }
  1693.         }
  1694.  
  1695.  
  1696.                 if (menuPtr != NULL) {
  1697.                     HWND os2MenuHdl = (HWND) menuPtr->platformData;
  1698.                     MENUITEM menuItem;
  1699. #ifdef VERBOSE
  1700.                     printf("menuPtr %x os2MenuHdl %x\n",menuPtr, os2MenuHdl);
  1701.                     fflush(stdout);
  1702. #endif
  1703.                     mePtr = NULL;
  1704.                     if (usPostCmd != 0) {
  1705.                         rc = (LONG) WinSendMsg(os2MenuHdl, MM_QUERYITEM,
  1706.                                                MPFROM2SHORT(usItemId,TRUE),
  1707.                                                MPFROMP(&menuItem));
  1708.                         if (rc != TRUE) {
  1709. #ifdef VERBOSE
  1710.                            printf("WinSendMsg MM_QI %x, %d returned ERROR %x\n",
  1711.                                    os2MenuHdl, usItemId,
  1712.                                    WinGetLastError(TclOS2GetHAB()));
  1713.                             fflush(stdout);
  1714. #endif
  1715.                             return returnResult;
  1716.                         }
  1717. #ifdef VERBOSE
  1718.         printf("WinSendMsg MM_QI h %x id %d style %x pos %d hSub %x hItem %x\n",
  1719.                            os2MenuHdl, usItemId, menuItem.afStyle,
  1720.                            menuItem.iPosition, menuItem.hwndSubMenu,
  1721.                            menuItem.hItem);
  1722.                     fflush(stdout);
  1723. #endif
  1724. /*
  1725.                         if (menuItem.afStyle & MIS_SUBMENU ||
  1726.                             menuItem.afStyle & MIS_MULTMENU) {
  1727.                             mePtr = menuPtr->entries[menuItem.iPosition];
  1728. #ifdef VERBOSE
  1729.                             printf("menuItem %d afStyle (%x) & MIS_SUBMENU: %x\n",
  1730.                                    usItemId, menuItem.afStyle, mePtr);
  1731.                             fflush(stdout);
  1732. #endif
  1733.                         } else {
  1734. */
  1735.                             /*
  1736.                              * Extra cast to ULONG to prevent warning by GCC
  1737.                              * about casting from integer of different size.
  1738.                             hashEntryPtr = Tcl_FindHashEntry(&commandTable,
  1739.                                     (char *)(ULONG) usItemId);
  1740.                             if (hashEntryPtr != NULL) {
  1741.                                 mePtr = (TkMenuEntry *)
  1742.                                         Tcl_GetHashValue(hashEntryPtr);
  1743.                             }
  1744.                          */
  1745.                             mePtr = menuPtr->entries[menuItem.iPosition];
  1746. /*
  1747.                         }
  1748. */
  1749. #ifdef VERBOSE
  1750.                         printf("mePtr %x, index %d\n", mePtr, mePtr->index);
  1751.                         fflush(stdout);
  1752. #endif
  1753.                     }
  1754. /*
  1755. */
  1756.  
  1757.             if ((mePtr == NULL) || (mePtr->state == tkDisabledUid)) {
  1758. #ifdef VERBOSE
  1759.                         printf("calling TkActivateMenuEntry(%x, -1)\n", mePtr);
  1760. #endif
  1761.             TkActivateMenuEntry(menuPtr, -1);
  1762.             } else {
  1763.             TkActivateMenuEntry(menuPtr, mePtr->index);
  1764. #ifdef VERBOSE
  1765.                         printf("calling TkActivateMenuEntry(%x, %d)\n", mePtr,
  1766.                                mePtr->index);
  1767. #endif
  1768.             }
  1769.             MenuSelectEvent(menuPtr);
  1770.             Tcl_ServiceAll();
  1771.         }
  1772.         }
  1773.             *pmResult = (MRESULT)1;
  1774.             returnResult = 1;
  1775.             break;
  1776.     }
  1777.  
  1778.         case WM_HELP: {
  1779. #ifdef VERBOSE
  1780.             printf("menu WM_HELP\n");
  1781.             fflush(stdout);
  1782. #endif
  1783.             break;
  1784.         }
  1785.  
  1786.         case WM_MENUEND: {
  1787.         /*
  1788.              * The menu window handle is in the second parameter.  The
  1789.              * menu identifier is in SHORT1FROMMP(mp1).  Send MM_QUERYITEM
  1790.              * to query the menu flags for the menu item identified in
  1791.              * SHORT2FROMMP(mp1).  A menu identifier of -1 in OS/2
  1792.              * indicates that the submenu is being closed, but does not
  1793.              * necessarily indicate that menu processing is complete.
  1794.          */
  1795. #ifdef VERBOSE
  1796.         USHORT usMenuId = SHORT1FROMMP(*pParam1);
  1797.         HWND hwndMenu = HWNDFROMMP(*pParam2);
  1798.             printf("WM_MENUEND, usMenuId %d, hwnd %x\n", usMenuId, hwndMenu);
  1799.             fflush(stdout);
  1800. #endif
  1801.         *pmResult = (MRESULT) FALSE;
  1802.  
  1803.         TkMenuInit();
  1804.  
  1805.             /* Menu was closed */
  1806.             Tcl_SetServiceMode(oldServiceMode);
  1807.             if (modalMenuPtr != NULL) {
  1808.                 RecursivelyClearActiveMenu(modalMenuPtr);
  1809.             }
  1810.             break;
  1811.         }
  1812.  
  1813.         case WM_NEXTMENU: {
  1814. #ifdef VERBOSE
  1815.             printf("menu WM_NEXTMENU\n");
  1816.             fflush(stdout);
  1817. #endif
  1818.             *pmResult = oldMenuProc(*pHwnd, *pMessage, *pParam1, *pParam2);
  1819.             break;
  1820.         }
  1821.  
  1822.     }
  1823.     return returnResult;
  1824. }
  1825.  
  1826. /*
  1827.  *----------------------------------------------------------------------
  1828.  *
  1829.  * RecursivelyClearActiveMenu --
  1830.  *
  1831.  *    Recursively clears the active entry in the menu's cascade hierarchy.
  1832.  *
  1833.  * Results:
  1834.  *    None.
  1835.  *
  1836.  * Side effects:
  1837.  *    Generates <<MenuSelect>> virtual events.
  1838.  *
  1839.  *----------------------------------------------------------------------
  1840.  */
  1841.  
  1842. void
  1843. RecursivelyClearActiveMenu(
  1844.     TkMenu *menuPtr)        /* The menu to reset. */
  1845. {
  1846.     int i;
  1847.     TkMenuEntry *mePtr;
  1848. #ifdef VERBOSE
  1849.     printf("RecursivelyClearActiveMenu\n");
  1850.             fflush(stdout);
  1851. #endif
  1852.  
  1853.     TkActivateMenuEntry(menuPtr, -1);
  1854.     MenuSelectEvent(menuPtr);
  1855.     for (i = 0; i < menuPtr->numEntries; i++) {
  1856.         mePtr = menuPtr->entries[i];
  1857.         if (mePtr->type == CASCADE_ENTRY) {
  1858.             if ((mePtr->childMenuRefPtr != NULL)
  1859.                     && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
  1860.                 RecursivelyClearActiveMenu(mePtr->childMenuRefPtr->menuPtr);
  1861.             }
  1862.         }
  1863.     }
  1864. }
  1865.  
  1866. /*
  1867.  *----------------------------------------------------------------------
  1868.  *
  1869.  * TkpSetWindowMenuBar --
  1870.  *
  1871.  *    Associates a given menu with a window.
  1872.  *
  1873.  * Results:
  1874.  *    None.
  1875.  *
  1876.  * Side effects:
  1877.  *    On OS/2, Windows and UNIX, associates the platform menu with the
  1878.  *    platform window.
  1879.  *
  1880.  *----------------------------------------------------------------------
  1881.  */
  1882.  
  1883. void
  1884. TkpSetWindowMenuBar(tkwin, menuPtr)
  1885.     Tk_Window tkwin;        /* The window we are putting the menubar into.*/
  1886.     TkMenu *menuPtr;        /* The menu we are inserting */
  1887. {
  1888.     HWND os2MenuHdl;
  1889. #ifdef VERBOSE
  1890.     printf("TkpSetWindowMenuBar tkwin %x\n", tkwin);
  1891.             fflush(stdout);
  1892. #endif
  1893.  
  1894.     if (menuPtr != NULL) {
  1895.     Tcl_HashEntry *hashEntryPtr;
  1896.     int newEntry;
  1897.  
  1898.     os2MenuHdl = (HWND) menuPtr->platformData;
  1899.     hashEntryPtr = Tcl_FindHashEntry(&os2MenuTable, (char *) os2MenuHdl);
  1900.     Tcl_DeleteHashEntry(hashEntryPtr);
  1901.     WinDestroyWindow(os2MenuHdl);
  1902.     os2MenuHdl = WinCreateMenu(HWND_DESKTOP, NULL);
  1903. #ifdef VERBOSE
  1904.         if (os2MenuHdl == NULLHANDLE) {
  1905.             printf("TkpSetWindowMenuBar WinCreateMenu NULL ERROR %x\n",
  1906.                    WinGetLastError(TclOS2GetHAB()));
  1907.         } else {
  1908.             printf("TkpSetWindowMenuBar WinCreateMenu NULL OK %x\n",os2MenuHdl);
  1909.         }
  1910.         fflush(stdout);
  1911. #endif
  1912.     hashEntryPtr = Tcl_CreateHashEntry(&os2MenuTable, (char *) os2MenuHdl,
  1913.         &newEntry);
  1914. #ifdef VERBOSE
  1915.         printf("Tcl_CreateHashEntry hwnd %x for menuPtr %x: hashEntryPtr %x\n",
  1916.                os2MenuHdl, menuPtr, hashEntryPtr);
  1917. #endif
  1918.     Tcl_SetHashValue(hashEntryPtr, (char *) menuPtr);
  1919.     menuPtr->platformData = (TkMenuPlatformData) os2MenuHdl;
  1920.     TkOS2SetMenu(tkwin, os2MenuHdl);
  1921.     if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) {
  1922.         Tcl_DoWhenIdle(ReconfigureOS2Menu, (ClientData) menuPtr);
  1923.         menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  1924.     }
  1925.     } else {
  1926.     TkOS2SetMenu(tkwin, NULLHANDLE);
  1927.     }
  1928. }
  1929.  
  1930.  
  1931. /*
  1932.  *----------------------------------------------------------------------
  1933.  *
  1934.  * TkpSetMainMenubar --
  1935.  *
  1936.  *    Puts the menu associated with a window into the menubar. Should
  1937.  *    only be called when the window is in front.
  1938.  *
  1939.  * Results:
  1940.  *    None.
  1941.  *
  1942.  * Side effects:
  1943.  *    The menubar is changed.
  1944.  *
  1945.  *----------------------------------------------------------------------
  1946.  */
  1947. void
  1948. TkpSetMainMenubar(
  1949.     Tcl_Interp *interp,        /* The interpreter of the application */
  1950.     Tk_Window tkwin,        /* The frame we are setting up */
  1951.     char *menuName)        /* The name of the menu to put in front.
  1952.                      * If NULL, use the default menu bar.
  1953.                      */
  1954. {
  1955. #ifdef VERBOSE
  1956.     printf("superfluous TkpSetMainMenuBar tkwin %x, [%s]\n", tkwin, menuName);
  1957.             fflush(stdout);
  1958. #endif
  1959.     /*
  1960.      * Nothing to do.
  1961.      */
  1962. }
  1963.  
  1964. /*
  1965.  *----------------------------------------------------------------------
  1966.  *
  1967.  * GetMenuIndicatorGeometry --
  1968.  *
  1969.  *    Gets the width and height of the indicator area of a menu.
  1970.  *
  1971.  * Results:
  1972.  *    widthPtr and heightPtr are set.
  1973.  *
  1974.  * Side effects:
  1975.  *    None.
  1976.  *
  1977.  *----------------------------------------------------------------------
  1978.  */
  1979.  
  1980. void
  1981. GetMenuIndicatorGeometry (
  1982.     TkMenu *menuPtr,            /* The menu we are measuring */
  1983.     TkMenuEntry *mePtr,            /* The entry we are measuring */
  1984.     Tk_Font tkfont,            /* Precalculated font */
  1985.     CONST Tk_FontMetrics *fmPtr,    /* Precalculated font metrics */
  1986.     int *widthPtr,            /* The resulting width */
  1987.     int *heightPtr)            /* The resulting height */
  1988. {
  1989. #ifdef VERBOSE
  1990.     printf("GetMenuIndicatorGeometry\n");
  1991.             fflush(stdout);
  1992. #endif
  1993.     *heightPtr = indicatorDimensions[0];
  1994.     if (mePtr->hideMargin) {
  1995.     *widthPtr = 0;
  1996.     } else {
  1997.     *widthPtr = indicatorDimensions[1] - menuPtr->borderWidth;
  1998.     }
  1999. }
  2000.  
  2001. /*
  2002.  *----------------------------------------------------------------------
  2003.  *
  2004.  * GetMenuAccelGeometry --
  2005.  *
  2006.  *    Gets the width and height of the indicator area of a menu.
  2007.  *
  2008.  * Results:
  2009.  *    widthPtr and heightPtr are set.
  2010.  *
  2011.  * Side effects:
  2012.  *    None.
  2013.  *
  2014.  *----------------------------------------------------------------------
  2015.  */
  2016.  
  2017. void
  2018. GetMenuAccelGeometry (
  2019.     TkMenu *menuPtr,            /* The menu we are measuring */
  2020.     TkMenuEntry *mePtr,            /* The entry we are measuring */
  2021.     Tk_Font tkfont,            /* The precalculated font */
  2022.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
  2023.     int *widthPtr,            /* The resulting width */
  2024.     int *heightPtr)            /* The resulting height */
  2025. {
  2026. #ifdef VERBOSE
  2027.     printf("GetMenuAccelGeometry\n");
  2028.             fflush(stdout);
  2029. #endif
  2030.     *heightPtr = fmPtr->linespace;
  2031.     if (mePtr->type == CASCADE_ENTRY) {
  2032.     *widthPtr = 0;
  2033.     } else if (mePtr->accel == NULL) {
  2034.     *widthPtr = 0;
  2035.     } else {
  2036.     *widthPtr = Tk_TextWidth(tkfont, mePtr->accel, mePtr->accelLength);
  2037.     }
  2038. }
  2039.  
  2040. /*
  2041.  *----------------------------------------------------------------------
  2042.  *
  2043.  * GetTearoffEntryGeometry --
  2044.  *
  2045.  *    Gets the width and height of the indicator area of a menu.
  2046.  *
  2047.  * Results:
  2048.  *    widthPtr and heightPtr are set.
  2049.  *
  2050.  * Side effects:
  2051.  *    None.
  2052.  *
  2053.  *----------------------------------------------------------------------
  2054.  */
  2055.  
  2056. void
  2057. GetTearoffEntryGeometry (
  2058.     TkMenu *menuPtr,            /* The menu we are measuring */
  2059.     TkMenuEntry *mePtr,            /* The entry we are measuring */
  2060.     Tk_Font tkfont,            /* The precalculated font */
  2061.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
  2062.     int *widthPtr,            /* The resulting width */
  2063.     int *heightPtr)            /* The resulting height */
  2064. {
  2065. #ifdef VERBOSE
  2066.     printf("GetTearoffEntryGeometry\n");
  2067.             fflush(stdout);
  2068. #endif
  2069.     if (menuPtr->menuType != MASTER_MENU) {
  2070.     *heightPtr = 0;
  2071.     } else {
  2072.     *heightPtr = fmPtr->linespace;
  2073.     }
  2074.     *widthPtr = 0;
  2075. }
  2076.  
  2077. /*
  2078.  *----------------------------------------------------------------------
  2079.  *
  2080.  * GetMenuSeparatorGeometry --
  2081.  *
  2082.  *    Gets the width and height of the indicator area of a menu.
  2083.  *
  2084.  * Results:
  2085.  *    widthPtr and heightPtr are set.
  2086.  *
  2087.  * Side effects:
  2088.  *    None.
  2089.  *
  2090.  *----------------------------------------------------------------------
  2091.  */
  2092.  
  2093. void
  2094. GetMenuSeparatorGeometry (
  2095.     TkMenu *menuPtr,            /* The menu we are measuring */
  2096.     TkMenuEntry *mePtr,            /* The entry we are measuring */
  2097.     Tk_Font tkfont,            /* The precalculated font */
  2098.     CONST Tk_FontMetrics *fmPtr,    /* The precalcualted font metrics */
  2099.     int *widthPtr,            /* The resulting width */
  2100.     int *heightPtr)            /* The resulting height */
  2101. {
  2102. #ifdef VERBOSE
  2103.     printf("GetMenuSeparatorGeometry\n");
  2104.             fflush(stdout);
  2105. #endif
  2106.     *widthPtr = 0;
  2107.     *heightPtr = fmPtr->linespace;
  2108. }
  2109.  
  2110. /*
  2111.  *----------------------------------------------------------------------
  2112.  *
  2113.  * DrawOS2SystemBitmap -- NOT NEEDED
  2114.  *
  2115.  *    Draws the OS/2 system bitmap given by bitmapID into the rect
  2116.  *    given by rectPtr in the drawable. The bitmap is centered in the
  2117.  *    rectangle. It is not clipped, so if the bitmap is bigger than
  2118.  *    the rect it will bleed.
  2119.  *
  2120.  * Results:
  2121.  *    None.
  2122.  *
  2123.  * Side effects:
  2124.  *    Drawing occurs. Some storage is allocated and released.
  2125.  *
  2126.  *----------------------------------------------------------------------
  2127.  */
  2128.  
  2129. static void
  2130. DrawOS2SystemBitmap(display, drawable, gc, rectPtr, bitmapID, alignFlags)
  2131.     Display *display;            /* The display we are drawing into */
  2132.     Drawable drawable;            /* The drawable we are working with */
  2133.     GC gc;                /* The GC to draw with */
  2134.     CONST RECTL *rectPtr;        /* The rectangle to draw into
  2135.                                          * in PM coordinates */            
  2136.     int bitmapID;            /* The OS/2 index value of the system
  2137.                      * bitmap to draw. */
  2138.     int alignFlags;            /* How to align the bitmap inside the
  2139.                      * rectangle. */
  2140. {
  2141.     TkOS2PSState state;
  2142.     HPS hps = TkOS2GetDrawablePS(display, drawable, &state);
  2143.     HBITMAP bitmap;
  2144.     CHARBUNDLE cBundle;
  2145.     POINTL aPoints[4] = {
  2146.         {0,0},
  2147.         {0,0},
  2148.         {0,0},
  2149.         {0,0}
  2150.     }; /* Lower-left dst, upper-right dst, lower-left src */
  2151.     int botOffset, leftOffset;
  2152.     BITMAPINFOHEADER2 info;
  2153. return;
  2154.  
  2155. #ifdef VERBOSE
  2156.     printf("DrawOS2SystemBitmap d %x bitmapID %x (%d,%d)->(%d,%d), align %x\n",
  2157.            drawable, bitmapID, rectPtr->xLeft, rectPtr->yBottom,
  2158.            rectPtr->xRight, rectPtr->yTop, alignFlags);
  2159.             fflush(stdout);
  2160. #endif
  2161.  
  2162.     GpiSetBackColor(hps, gc->background);
  2163.     cBundle.lColor = gc->foreground;
  2164.     rc = GpiSetAttrs(hps, PRIM_CHAR, LBB_COLOR, 0L, (PBUNDLE)&cBundle);
  2165.  
  2166.     bitmap = WinGetSysBitmap(HWND_DESKTOP, bitmapID);
  2167.     info.cbFix = sizeof(BITMAPINFOHEADER2);
  2168.     rc = GpiQueryBitmapInfoHeader(bitmap, &info);
  2169.     aPoints[3].x = info.cx;
  2170.     aPoints[3].y = info.cy;
  2171. #ifdef VERBOSE
  2172.     if (rc == FALSE) {
  2173.         printf("    GpiQueryBitmapInfoHeader ERROR %x bitmapdimensions %dx%d\n",
  2174.                WinGetLastError(TclOS2GetHAB()), aPoints[3].x, aPoints[3].y);
  2175.     } else {
  2176.         printf("    GpiQueryBitmapInfoHeader OK bitmapdimensions %dx%d\n",
  2177.                aPoints[3].x, aPoints[3].y);
  2178.     }
  2179. #endif
  2180.  
  2181.     if (alignFlags & ALIGN_BITMAP_TOP) {
  2182.     botOffset = (rectPtr->yTop - rectPtr->yBottom) - aPoints[3].y;
  2183.     } else if (alignFlags & ALIGN_BITMAP_BOTTOM) {
  2184.     botOffset = 0;
  2185.     } else {
  2186.     botOffset = (rectPtr->yTop - rectPtr->yBottom) / 2 - (aPoints[3].y / 2);
  2187.     }
  2188.  
  2189.     if (alignFlags & ALIGN_BITMAP_LEFT) {
  2190.     leftOffset = 0;
  2191.     } else if (alignFlags & ALIGN_BITMAP_RIGHT) {
  2192.     leftOffset = (rectPtr->xRight - rectPtr->xLeft) - aPoints[3].x;
  2193.     } else {
  2194.     leftOffset = (rectPtr->xRight - rectPtr->xLeft) / 2 - (aPoints[3].x/2);
  2195. #ifdef VERBOSE
  2196.         printf("    leftOffset = (%d-%d) / 2 (=%d) - %d/2 (=%d)  = %d\n",
  2197.                rectPtr->xRight, rectPtr->xLeft,
  2198.                (rectPtr->xRight - rectPtr->xLeft) / 2, aPoints[3].x,
  2199.                aPoints[3].x/2, leftOffset);
  2200. #endif
  2201.     }
  2202. #ifdef VERBOSE
  2203.     printf("    leftOffset %d botOffset %d\n", leftOffset, botOffset);
  2204. #endif
  2205.  
  2206.     aPoints[0].x = rectPtr->xLeft + leftOffset;
  2207.     aPoints[0].y = rectPtr->yBottom + botOffset;
  2208.     aPoints[1].x = aPoints[3].x + aPoints[0].x;
  2209.     aPoints[1].y = aPoints[3].y + aPoints[0].y;
  2210.     rc = GpiWCBitBlt(hps, bitmap, 4, aPoints, ROP_SRCCOPY, BBO_OR);
  2211. #ifdef VERBOSE
  2212.     if (rc == TRUE) {
  2213.         printf("GpiWCBitBlt hps %x bmp %x (%d,%d)(%d,%d)-> (%d,%d)(%d,%d) OK\n",
  2214.                hps, bitmap, aPoints[2].x, aPoints[2].y, aPoints[3].x,
  2215.                aPoints[3].y, aPoints[0].x, aPoints[0].y, aPoints[1].x,
  2216.                aPoints[1].y);
  2217.     } else {
  2218.         printf("GpiWCBitBlt hps %x bmp %x (%d,%d) -> (%d,%d)(%d,%d) ERROR %x\n",
  2219.                hps, bitmap, aPoints[2].x, aPoints[2].y, aPoints[0].x,
  2220.                aPoints[0].y, aPoints[1].x, aPoints[1].y,
  2221.                WinGetLastError(TclOS2GetHAB()));
  2222.     }
  2223. #endif
  2224.     GpiDeleteBitmap(bitmap);
  2225.  
  2226.     TkOS2ReleaseDrawablePS(drawable, hps, &state);
  2227. }
  2228.  
  2229. /*
  2230.  *----------------------------------------------------------------------
  2231.  *
  2232.  * DrawMenuEntryIndicator --
  2233.  *
  2234.  *    This procedure draws the indicator part of a menu.
  2235.  *
  2236.  * Results:
  2237.  *    None.
  2238.  *
  2239.  * Side effects:
  2240.  *    Commands are output to X to display the menu in its
  2241.  *    current mode.
  2242.  *
  2243.  *----------------------------------------------------------------------
  2244.  */
  2245. void
  2246. DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr, x,
  2247.     y, width, height)
  2248.     TkMenu *menuPtr;            /* The menu we are drawing */
  2249.     TkMenuEntry *mePtr;            /* The entry we are drawing */
  2250.     Drawable d;                /* What we are drawing into */
  2251.     GC gc;                /* The gc we are drawing with */
  2252.     GC indicatorGC;            /* The gc for indicator objects */
  2253.     Tk_Font tkfont;            /* The precalculated font */
  2254.     CONST Tk_FontMetrics *fmPtr;    /* The precalculated font metrics */
  2255.     int x;                /* Left edge */
  2256.     int y;                /* Top edge */
  2257.     int width;
  2258.     int height;
  2259. {
  2260. #ifdef VERBOSE
  2261.     printf("DrawMenuEntryIndicator d %x, (%d,%d) %dx%d\n", d, x, y, width,
  2262.            height);
  2263.             fflush(stdout);
  2264. #endif
  2265.     if ((mePtr->type == CHECK_BUTTON_ENTRY ||
  2266.             mePtr->type == RADIO_BUTTON_ENTRY)
  2267.             && mePtr->indicatorOn
  2268.         && mePtr->entryFlags & ENTRY_SELECTED) {
  2269.     RECTL rect;
  2270.     GC whichGC;
  2271.  
  2272.     if (mePtr->state != tkNormalUid) {
  2273.         whichGC = gc;
  2274.     } else {
  2275.         whichGC = indicatorGC;
  2276.     }
  2277.  
  2278.         /* PM coordinates reversed */
  2279.     rect.yTop = TkOS2WindowHeight((TkOS2Drawable *)d) - y;
  2280.     rect.yBottom = rect.yTop - mePtr->height;
  2281.     rect.xLeft = menuPtr->borderWidth + menuPtr->activeBorderWidth + x;
  2282.     rect.xRight = mePtr->indicatorSpace + x;
  2283.  
  2284. #ifdef VERBOSE
  2285.         printf("Drawing MENUCHECK (Indicator) %d,%d -> %d,%d\n", rect.xLeft,
  2286.                rect.yBottom, rect.xRight, rect.yTop);
  2287.             fflush(stdout);
  2288. #endif
  2289.     DrawOS2SystemBitmap(menuPtr->display, d, whichGC, &rect,
  2290.                     SBMP_MENUCHECK, 0);    /* PM coordinates */
  2291.  
  2292.     if ((mePtr->state == tkDisabledUid)
  2293.         && (menuPtr->disabledImageGC != None)) {
  2294.         XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
  2295.             rect.xLeft, y, rect.xRight, y + mePtr->height);
  2296.     }
  2297.     }
  2298. }
  2299.  
  2300. /*
  2301.  *----------------------------------------------------------------------
  2302.  *
  2303.  * DrawMenuEntryAccelerator --
  2304.  *
  2305.  *    This procedure draws the accelerator part of a menu. We
  2306.  *    need to decide what to draw here. Should we replace strings
  2307.  *    like "Control", "Command", etc?
  2308.  *
  2309.  * Results:
  2310.  *    None.
  2311.  *
  2312.  * Side effects:
  2313.  *    Commands are output to X to display the menu in its
  2314.  *    current mode.
  2315.  *
  2316.  *----------------------------------------------------------------------
  2317.  */
  2318.  
  2319. void
  2320. DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr,
  2321.     activeBorder, x, y, width, height, drawArrow)
  2322.     TkMenu *menuPtr;            /* The menu we are drawing */
  2323.     TkMenuEntry *mePtr;            /* The entry we are drawing */
  2324.     Drawable d;                /* What we are drawing into */
  2325.     GC gc;                /* The gc we are drawing with */
  2326.     Tk_Font tkfont;            /* The precalculated font */
  2327.     CONST Tk_FontMetrics *fmPtr;    /* The precalculated font metrics */
  2328.     Tk_3DBorder activeBorder;        /* The border when an item is active */
  2329.     int x;                /* left edge */
  2330.     int y;                /* top edge */
  2331.     int width;                /* Width of menu entry */
  2332.     int height;                /* Height of menu entry */
  2333.     int drawArrow;            /* For cascade menus, whether of not
  2334.                      * to draw the arraw. I cannot figure
  2335.                      * out Windows' algorithm for where
  2336.                      * to draw this. */
  2337. {
  2338.     int baseline;
  2339.     int leftEdge = x + mePtr->indicatorSpace + mePtr->labelWidth;
  2340.     /* Translate Y coordinate to PM */
  2341.     LONG pmy =  TkOS2WindowHeight((TkOS2Drawable *)d) - y - height;
  2342.  
  2343.     /* Use X Window System coordinate for baseline! */
  2344.     baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
  2345. #ifdef VERBOSE
  2346.     printf("DrawMenuEntryAccelerator d %x (%d,%d) %dx%d baseline %d t %s\n",
  2347.            d, x, y, width, height, baseline,
  2348.            mePtr->type == SEPARATOR_ENTRY ? "SEPARATOR_ENTRY" :
  2349.            (mePtr->type == TEAROFF_ENTRY ? "TEAROFF_ENTRY" :
  2350.            (mePtr->type == COMMAND_ENTRY ? "COMMAND_ENTRY" :
  2351.            (mePtr->type == CHECK_BUTTON_ENTRY ? "CHECK_BUTTON_ENTRY" :
  2352.            (mePtr->type == RADIO_BUTTON_ENTRY ? "RADIO_BUTTON_ENTRY" :
  2353.            (mePtr->type == CASCADE_ENTRY ? "CASCADE_ENTRY" : "OTHER"))))));
  2354.     printf("mePtr->state == tkDisabledUid %s\nmenuPtr->disabledFg != NULL %s
  2355. mePtr->accel != NULL %s\nmePtr->type == CASCADE_ENTRY %s\ndrawArrow %s\n",
  2356.            (mePtr->state == tkDisabledUid) ? "TRUE" : "FALSE",
  2357.            (menuPtr->disabledFg != NULL) ? "TRUE" : "FALSE",
  2358.            (mePtr->accel != NULL) ? "TRUE" : "FALSE",
  2359.            (mePtr->type == CASCADE_ENTRY) ? "TRUE" : "FALSE",
  2360.            drawArrow ? "TRUE" : "FALSE");
  2361.     fflush(stdout);
  2362. #endif
  2363.     if ((mePtr->state == tkDisabledUid) && (menuPtr->disabledFg != NULL)
  2364.         &&
  2365.         ((mePtr->accel != NULL) || ((mePtr->type == CASCADE_ENTRY)))) {
  2366.         LONG oldFgColor = gc->foreground;
  2367.  
  2368.         gc->foreground = WinQuerySysColor(HWND_DESKTOP,
  2369.                                           SYSCLR_ACTIVETITLETEXTBGND, 0L);
  2370. #ifdef VERBOSE
  2371.         printf("DrawMenuEntryAccelerator Windows95-part, fore %x\n",
  2372.                gc->foreground);
  2373.         fflush(stdout);
  2374. #endif
  2375.         if (mePtr->accel != NULL) {
  2376.             Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel,
  2377.                     mePtr->accelLength, leftEdge + 1, baseline + 1);
  2378.         }
  2379.  
  2380. /*
  2381.         if (mePtr->type == CASCADE_ENTRY) {
  2382.             RECTL rect;
  2383.  
  2384.             rect.yBottom = pmy + yBorder;
  2385.             rect.yTop = pmy + height - yBorder + 1;
  2386.             rect.xLeft = leftEdge;
  2387.             rect.xRight = x + width - 1;
  2388.             DrawOS2SystemBitmap(menuPtr->display, d, gc, &rect,
  2389.                     SBMP_MENUATTACHED, ALIGN_BITMAP_RIGHT);
  2390.         }
  2391. */
  2392.         gc->foreground = oldFgColor;
  2393.     }
  2394.  
  2395.     if (mePtr->accel != NULL) {
  2396.     Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel,
  2397.         mePtr->accelLength, leftEdge, baseline);
  2398.     }
  2399.  
  2400.     if ((mePtr->state == tkDisabledUid)
  2401.         && (menuPtr->disabledImageGC != None)) {
  2402.     XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
  2403.         leftEdge, pmy, width - mePtr->labelWidth
  2404.         - mePtr->indicatorSpace, height);
  2405.     }
  2406.  
  2407. #ifdef VERBOSE
  2408.     printf("mePtr->type == CASCADE_ENTRY %d, drawArrow %d\n",
  2409.            (mePtr->type == CASCADE_ENTRY), drawArrow);
  2410.     fflush(stdout);
  2411. #endif
  2412.     if ((mePtr->type == CASCADE_ENTRY) && drawArrow) {
  2413.     RECTL rect;
  2414.         LONG yBorder = WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
  2415.  
  2416.     rect.yBottom = pmy + yBorder;
  2417.     rect.yTop = pmy + height - yBorder;
  2418.     rect.xLeft = x + mePtr->indicatorSpace + mePtr->labelWidth;
  2419.     rect.xRight = x + width - 1;
  2420. #ifdef VERBOSE
  2421.         printf("Drawing CASCADE %d,%d -> %d,%d\n", rect.xLeft, rect.yBottom,
  2422.                rect.xRight, rect.yTop);
  2423.         fflush(stdout);
  2424. #endif
  2425. /*
  2426.     DrawOS2SystemBitmap(menuPtr->display, d, gc, &rect, SBMP_MENUATTACHED,
  2427.         ALIGN_BITMAP_RIGHT);    /* PM coordinates */
  2428.     if ((mePtr->state == tkDisabledUid)
  2429.         && (menuPtr->disabledImageGC != None)) {
  2430.         XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
  2431.                    rect.xLeft, pmy + yBorder,
  2432.                            rect.xRight, pmy + height - yBorder);
  2433.     }
  2434.     }
  2435. }
  2436.  
  2437. /*
  2438.  *----------------------------------------------------------------------
  2439.  *
  2440.  * DrawMenuSeparator --
  2441.  *
  2442.  *    The menu separator is drawn.
  2443.  *
  2444.  * Results:
  2445.  *    None.
  2446.  *
  2447.  * Side effects:
  2448.  *    Commands are output to X to display the menu in its
  2449.  *    current mode.
  2450.  *
  2451.  *----------------------------------------------------------------------
  2452.  */
  2453. void
  2454. DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
  2455.     TkMenu *menuPtr;            /* The menu we are drawing */
  2456.     TkMenuEntry *mePtr;            /* The entry we are drawing */
  2457.     Drawable d;                /* What we are drawing into */
  2458.     GC gc;                /* The gc we are drawing with */
  2459.     Tk_Font tkfont;            /* The precalculated font */
  2460.     CONST Tk_FontMetrics *fmPtr;    /* The precalculated font metrics */
  2461.     int x;                /* left edge */
  2462.     int y;                /* top edge */
  2463.     int width;                /* width of item */
  2464.     int height;                /* height of item */
  2465. {
  2466.     XPoint points[2];
  2467. #ifdef VERBOSE
  2468.     printf("DrawMenuSeparator d %x, (%d,%d) %dx%d\n", d, x, y, width, height);
  2469.             fflush(stdout);
  2470. #endif
  2471.  
  2472.     points[0].x = x;
  2473.     points[0].y = y + height / 2;
  2474.     points[1].x = x + width - 1;
  2475.     points[1].y = points[0].y;
  2476.     Tk_Draw3DPolygon(menuPtr->tkwin, d,
  2477.         menuPtr->border, points, 2, 1, TK_RELIEF_RAISED);
  2478. }
  2479.  
  2480. /*
  2481.  *----------------------------------------------------------------------
  2482.  *
  2483.  * DrawMenuUnderline --
  2484.  *
  2485.  *    On appropriate platforms, draw the underline character for the
  2486.  *    menu.
  2487.  *
  2488.  * Results:
  2489.  *    None.
  2490.  *
  2491.  * Side effects:
  2492.  *    Commands are output to X to display the menu in its
  2493.  *    current mode.
  2494.  *
  2495.  *----------------------------------------------------------------------
  2496.  */
  2497. static void
  2498. DrawMenuUnderline(
  2499.     TkMenu *menuPtr,            /* The menu to draw into */
  2500.     TkMenuEntry *mePtr,            /* The entry we are drawing */
  2501.     Drawable d,                /* What we are drawing into */
  2502.     GC gc,                /* The gc to draw into */
  2503.     Tk_Font tkfont,            /* The precalculated font */
  2504.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
  2505.     int x,                /* Left Edge */
  2506.     int y,                /* Top Edge */
  2507.     int width,                /* Width of entry */
  2508.     int height)                /* Height of entry */
  2509. {
  2510. #ifdef VERBOSE
  2511.     printf("DrawMenuUnderline d %x, (%d,%d) %dx%d\n", d, x, y, width, height);
  2512.             fflush(stdout);
  2513. #endif
  2514.     if (mePtr->underline >= 0) {
  2515.         Tk_UnderlineChars(menuPtr->display, d,
  2516.             gc, tkfont, mePtr->label, x + mePtr->indicatorSpace,
  2517.             y + (height + fmPtr->ascent - fmPtr->descent) / 2,
  2518.         mePtr->underline, mePtr->underline + 1);
  2519.     }        
  2520. }
  2521.  
  2522. /*
  2523.  *--------------------------------------------------------------
  2524.  *
  2525.  * TkpInitializeMenuBindings --
  2526.  *
  2527.  *    For every interp, initializes the bindings for OS/2
  2528.  *    menus. Does nothing on Mac or XWindows.
  2529.  *
  2530.  * Results:
  2531.  *    None.
  2532.  *
  2533.  * Side effects:
  2534.  *    C-level bindings are setup for the interp which will
  2535.  *    handle Alt-key sequences for menus without beeping
  2536.  *    or interfering with user-defined Alt-key bindings.
  2537.  *
  2538.  *--------------------------------------------------------------
  2539.  */
  2540.  
  2541. void
  2542. TkpInitializeMenuBindings(interp, bindingTable)
  2543.     Tcl_Interp *interp;            /* The interpreter to set. */
  2544.     Tk_BindingTable bindingTable;   /* The table to add to. */
  2545. {
  2546. }
  2547.  
  2548. /*
  2549.  *----------------------------------------------------------------------
  2550.  *
  2551.  * DrawMenuEntryLabel --
  2552.  *
  2553.  *    This procedure draws the label part of a menu.
  2554.  *
  2555.  * Results:
  2556.  *    None.
  2557.  *
  2558.  * Side effects:
  2559.  *    Commands are output to X to display the menu in its
  2560.  *    current mode.
  2561.  *
  2562.  *----------------------------------------------------------------------
  2563.  */
  2564.  
  2565. static void
  2566. DrawMenuEntryLabel(
  2567.     TkMenu *menuPtr,            /* The menu we are drawing */
  2568.     TkMenuEntry *mePtr,            /* The entry we are drawing */
  2569.     Drawable d,                /* What we are drawing into */
  2570.     GC gc,                /* The gc we are drawing into */
  2571.     Tk_Font tkfont,            /* The precalculated font */
  2572.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
  2573.     int x,                /* left edge */
  2574.     int y,                /* right edge */
  2575.     int width,                /* width of entry */
  2576.     int height)                /* height of entry */
  2577. {
  2578.     int baseline;
  2579.     int indicatorSpace =  mePtr->indicatorSpace;
  2580.     int leftEdge = x + indicatorSpace + menuPtr->activeBorderWidth;
  2581.     int imageHeight, imageWidth;
  2582.  
  2583.     /*
  2584.      * Draw label or bitmap or image for entry.
  2585.      */
  2586.  
  2587.     baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
  2588. #ifdef VERBOSE
  2589.     printf("DrawMenuEntryLabel d %x, (%d,%d) %dx%d, baseline %d\n", d, x, y,
  2590.            width, height, baseline);
  2591.             fflush(stdout);
  2592. #endif
  2593.     if (mePtr->image != NULL) {
  2594.         Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
  2595.         if ((mePtr->selectImage != NULL)
  2596.             && (mePtr->entryFlags & ENTRY_SELECTED)) {
  2597.         Tk_RedrawImage(mePtr->selectImage, 0, 0,
  2598.             imageWidth, imageHeight, d, leftEdge,
  2599.                 (int) (y + (mePtr->height - imageHeight)/2));
  2600.         } else {
  2601.         Tk_RedrawImage(mePtr->image, 0, 0, imageWidth,
  2602.             imageHeight, d, leftEdge,
  2603.             (int) (y + (mePtr->height - imageHeight)/2));
  2604.         }
  2605.     } else if (mePtr->bitmap != None) {
  2606.         int width, height;
  2607.  
  2608.         Tk_SizeOfBitmap(menuPtr->display,
  2609.             mePtr->bitmap, &width, &height);
  2610.         XCopyPlane(menuPtr->display,
  2611.             mePtr->bitmap, d,
  2612.             gc, 0, 0, (unsigned) width, (unsigned) height, leftEdge,
  2613.             (int) (y + (mePtr->height - height)/2), 1);
  2614.     } else {
  2615.         if (mePtr->labelLength > 0) {
  2616.         Tk_DrawChars(menuPtr->display, d, gc,
  2617.             tkfont, mePtr->label, mePtr->labelLength,
  2618.             leftEdge, baseline);
  2619.         DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y,
  2620.             width, height);
  2621.         }
  2622.     }
  2623.  
  2624.     if (mePtr->state == tkDisabledUid) {
  2625.     if (menuPtr->disabledFg == NULL) {
  2626.         XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y,
  2627.             (unsigned) width, (unsigned) height);
  2628.     } else if ((mePtr->image != NULL)
  2629.         && (menuPtr->disabledImageGC != None)) {
  2630.         XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
  2631.             leftEdge,
  2632.             (int) (y + (mePtr->height - imageHeight)/2),
  2633.             (unsigned) imageWidth, (unsigned) imageHeight);
  2634.     }
  2635.     }
  2636. }
  2637.  
  2638. /*
  2639.  *--------------------------------------------------------------
  2640.  *
  2641.  * TkpComputeMenubarGeometry --
  2642.  *
  2643.  *    This procedure is invoked to recompute the size and
  2644.  *    layout of a menu that is a menubar clone.
  2645.  *
  2646.  * Results:
  2647.  *    None.
  2648.  *
  2649.  * Side effects:
  2650.  *    Fields of menu entries are changed to reflect their
  2651.  *    current positions, and the size of the menu window
  2652.  *    itself may be changed.
  2653.  *
  2654.  *--------------------------------------------------------------
  2655.  */
  2656.  
  2657. void
  2658. TkpComputeMenubarGeometry(menuPtr)
  2659.     TkMenu *menuPtr;        /* Structure describing menu. */
  2660. {
  2661. #ifdef VERBOSE
  2662.     printf("TkpComputeMenubarGeometry\n");
  2663.             fflush(stdout);
  2664. #endif
  2665.     TkpComputeStandardMenuGeometry(menuPtr);
  2666. }
  2667.  
  2668. /*
  2669.  *----------------------------------------------------------------------
  2670.  *
  2671.  * DrawTearoffEntry --
  2672.  *
  2673.  *    This procedure draws the background part of a menu.
  2674.  *
  2675.  * Results:
  2676.  *    None.
  2677.  *
  2678.  * Side effects:
  2679.  *    Commands are output to X to display the menu in its
  2680.  *    current mode.
  2681.  *
  2682.  *----------------------------------------------------------------------
  2683.  */
  2684.  
  2685. void
  2686. DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
  2687.     TkMenu *menuPtr;            /* The menu we are drawing */
  2688.     TkMenuEntry *mePtr;            /* The entry we are drawing */
  2689.     Drawable d;                /* The drawable we are drawing into */
  2690.     GC gc;                /* The gc we are drawing with */
  2691.     Tk_Font tkfont;            /* The font we are drawing with */
  2692.     CONST Tk_FontMetrics *fmPtr;    /* The metrics we are drawing with */
  2693.     int x;
  2694.     int y;
  2695.     int width;
  2696.     int height;
  2697. {
  2698.     XPoint points[2];
  2699.     int segmentWidth, maxX;
  2700. #ifdef VERBOSE
  2701.     printf("DrawTearoffEntry d %x, (%d,%d) %dx%d\n", d, x, y, width, height);
  2702.             fflush(stdout);
  2703. #endif
  2704.  
  2705.     if (menuPtr->menuType != MASTER_MENU) {
  2706.     return;
  2707.     }
  2708.  
  2709.     points[0].x = x;
  2710.     points[0].y = y + height/2;
  2711.     points[1].y = points[0].y;
  2712.     segmentWidth = 6;
  2713.     maxX  = width - 1;
  2714.  
  2715.     while (points[0].x < maxX) {
  2716.     points[1].x = points[0].x + segmentWidth;
  2717.     if (points[1].x > maxX) {
  2718.         points[1].x = maxX;
  2719.     }
  2720.     Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 2, 1,
  2721.         TK_RELIEF_RAISED);
  2722.     points[0].x += 2*segmentWidth;
  2723.     }
  2724. }
  2725.  
  2726. /*
  2727.  *----------------------------------------------------------------------
  2728.  *
  2729.  * TkpConfigureMenuEntry --
  2730.  *
  2731.  *    Processes configurations for menu entries.
  2732.  *
  2733.  * Results:
  2734.  *    Returns standard TCL result. If TCL_ERROR is returned, then
  2735.  *    interp->result contains an error message.
  2736.  *
  2737.  * Side effects:
  2738.  *    Configuration information get set for mePtr; old resources
  2739.  *    get freed, if any need it.
  2740.  *
  2741.  *----------------------------------------------------------------------
  2742.  */
  2743.  
  2744. int
  2745. TkpConfigureMenuEntry(mePtr)
  2746.     register TkMenuEntry *mePtr;    /* Information about menu entry;  may
  2747.                      * or may not already have values for
  2748.                      * some fields. */
  2749. {
  2750.     TkMenu *menuPtr = mePtr->menuPtr;
  2751. #ifdef VERBOSE
  2752.     printf("TkpConfigureMenuEntry\n");
  2753.             fflush(stdout);
  2754. #endif
  2755.  
  2756.     if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
  2757.     menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  2758.     Tcl_DoWhenIdle(ReconfigureOS2Menu, (ClientData) menuPtr);
  2759.     }
  2760.     return TCL_OK;
  2761. }
  2762.  
  2763. /*
  2764.  *----------------------------------------------------------------------
  2765.  *
  2766.  * TkpDrawMenuEntry --
  2767.  *
  2768.  *    Draws the given menu entry at the given coordinates with the
  2769.  *    given attributes.
  2770.  *
  2771.  * Results:
  2772.  *    None.
  2773.  *
  2774.  * Side effects:
  2775.  *    X Server commands are executed to display the menu entry.
  2776.  *
  2777.  *----------------------------------------------------------------------
  2778.  */
  2779.  
  2780. void
  2781. TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height,
  2782.     strictMotif, drawArrow)
  2783.     TkMenuEntry *mePtr;            /* The entry to draw */
  2784.     Drawable d;                /* What to draw into */
  2785.     Tk_Font tkfont;            /* Precalculated font for menu */
  2786.     CONST Tk_FontMetrics *menuMetricsPtr;
  2787.                     /* Precalculated metrics for menu */
  2788.     int x;                /* X-coordinate of topleft of entry */
  2789.     int y;                /* Y-coordinate of topleft of entry */
  2790.     int width;                /* Width of the entry rectangle */
  2791.     int height;                /* Height of the current rectangle */
  2792.     int strictMotif;            /* Boolean flag */
  2793.     int drawArrow;            /* Whether or not to draw the cascade
  2794.                      * arrow for cascade items. Only applies
  2795.                      * to Windows and OS/2. */
  2796. {
  2797.     GC gc, indicatorGC;
  2798.     TkMenu *menuPtr = mePtr->menuPtr;
  2799.     Tk_3DBorder bgBorder, activeBorder;
  2800.     CONST Tk_FontMetrics *fmPtr;
  2801.     Tk_FontMetrics entryMetrics;
  2802.     int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0;
  2803.     int adjustedY = y + padY;
  2804.     int adjustedHeight = height - 2 * padY;
  2805. #ifdef VERBOSE
  2806.     printf("TkpDrawMenuEntry d %x (%d,%d) %dx%d aY %d aH %d pY %d dA %d %s a%d\n",
  2807.            d, x, y, width, height, adjustedY, adjustedHeight, padY, drawArrow,
  2808.            mePtr->type == SEPARATOR_ENTRY ? "SEPARATOR_ENTRY" :
  2809.            (mePtr->type == TEAROFF_ENTRY ? "TEAROFF_ENTRY" :
  2810.            (mePtr->type == COMMAND_ENTRY ? "COMMAND_ENTRY" :
  2811.            (mePtr->type == CHECK_BUTTON_ENTRY ? "CHECK_BUTTON_ENTRY" :
  2812.            (mePtr->type == RADIO_BUTTON_ENTRY ? "RADIO_BUTTON_ENTRY" :
  2813.            (mePtr->type == CASCADE_ENTRY ? "CASCADE_ENTRY" : "OTHER"))))),
  2814.            (mePtr->state == tkActiveUid));
  2815.             fflush(stdout);
  2816. #endif
  2817.  
  2818.     /*
  2819.      * Choose the gc for drawing the foreground part of the entry.
  2820.      */
  2821.  
  2822.     if ((mePtr->state == tkActiveUid)
  2823.         && !strictMotif) {
  2824.     gc = mePtr->activeGC;
  2825.     if (gc == NULL) {
  2826.         gc = menuPtr->activeGC;
  2827.     }
  2828.     } else {
  2829.         TkMenuEntry *cascadeEntryPtr;
  2830.         int parentDisabled = 0;
  2831.         
  2832.         for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
  2833.             cascadeEntryPtr != NULL;
  2834.             cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
  2835.             if (strcmp(cascadeEntryPtr->name,
  2836.                     Tk_PathName(menuPtr->tkwin)) == 0) {
  2837.                 if (cascadeEntryPtr->state == tkDisabledUid) {
  2838.                     parentDisabled = 1;
  2839.                 }
  2840.                 break;
  2841.             }
  2842.         }
  2843.  
  2844.     if (((parentDisabled || (mePtr->state == tkDisabledUid)))
  2845.         && (menuPtr->disabledFg != NULL)) {
  2846.         gc = mePtr->disabledGC;
  2847.         if (gc == NULL) {
  2848.         gc = menuPtr->disabledGC;
  2849.         }
  2850.     } else {
  2851.         gc = mePtr->textGC;
  2852.         if (gc == NULL) {
  2853.         gc = menuPtr->textGC;
  2854.         }
  2855.     }
  2856.     }
  2857.     indicatorGC = mePtr->indicatorGC;
  2858.     if (indicatorGC == NULL) {
  2859.     indicatorGC = menuPtr->indicatorGC;
  2860.     }
  2861.     
  2862.     bgBorder = mePtr->border;
  2863.     if (bgBorder == NULL) {
  2864.     bgBorder = menuPtr->border;
  2865.     }
  2866.     if (strictMotif) {
  2867.     activeBorder = bgBorder;
  2868.     } else {
  2869.     activeBorder = mePtr->activeBorder;
  2870.     if (activeBorder == NULL) {
  2871.         activeBorder = menuPtr->activeBorder;
  2872.     }
  2873.     }
  2874.  
  2875.     if (mePtr->tkfont == NULL) {
  2876.     fmPtr = menuMetricsPtr;
  2877.     } else {
  2878.     tkfont = mePtr->tkfont;
  2879.     Tk_GetFontMetrics(tkfont, &entryMetrics);
  2880.     fmPtr = &entryMetrics;
  2881.     }
  2882.  
  2883.     /*
  2884.      * Need to draw the entire background, including padding. On Unix,
  2885.      * for menubars, we have to draw the rest of the entry taking
  2886.      * into account the padding.
  2887.      */
  2888.  
  2889.     DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder,
  2890.         bgBorder, x, y, width, height);
  2891.  
  2892.     if (mePtr->type == SEPARATOR_ENTRY) {
  2893.     DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont,
  2894.         fmPtr, x, adjustedY, width, adjustedHeight);
  2895.     } else if (mePtr->type == TEAROFF_ENTRY) {
  2896.     DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
  2897.         width, adjustedHeight);
  2898.     } else {
  2899.     DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
  2900.         width, adjustedHeight);
  2901.     DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr,
  2902.         activeBorder, x, adjustedY, width, adjustedHeight, drawArrow);
  2903.     if (!mePtr->hideMargin) {
  2904.         DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont,
  2905.             fmPtr, x, adjustedY, width, adjustedHeight);
  2906.     }
  2907.     }
  2908. }
  2909.  
  2910. /*
  2911.  *----------------------------------------------------------------------
  2912.  *
  2913.  * GetMenuLabelGeometry --
  2914.  *
  2915.  *    Figures out the size of the label portion of a menu item.
  2916.  *
  2917.  * Results:
  2918.  *    widthPtr and heightPtr are filled in with the correct geometry
  2919.  *    information.
  2920.  *
  2921.  * Side effects:
  2922.  *    None.
  2923.  *
  2924.  *----------------------------------------------------------------------
  2925.  */
  2926.  
  2927. static void
  2928. GetMenuLabelGeometry(mePtr, tkfont, fmPtr, widthPtr, heightPtr)
  2929.     TkMenuEntry *mePtr;            /* The entry we are computing */
  2930.     Tk_Font tkfont;            /* The precalculated font */
  2931.     CONST Tk_FontMetrics *fmPtr;    /* The precalculated metrics */
  2932.     int *widthPtr;            /* The resulting width of the label
  2933.                      * portion */
  2934.     int *heightPtr;            /* The resulting height of the label
  2935.                      * portion */
  2936. {
  2937.     TkMenu *menuPtr = mePtr->menuPtr;
  2938.  
  2939.     if (mePtr->image != NULL) {
  2940. #ifdef VERBOSE
  2941.         printf("GetMenuLabelGeometry: TkSizeOfImage\n");
  2942.             fflush(stdout);
  2943. #endif
  2944.         Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr);
  2945.     } else if (mePtr->bitmap != (Pixmap) NULL) {
  2946. #ifdef VERBOSE
  2947.         printf("GetMenuLabelGeometry: TkSizeOfBitmap\n");
  2948.             fflush(stdout);
  2949. #endif
  2950.         Tk_SizeOfBitmap(menuPtr->display, mePtr->bitmap, widthPtr, heightPtr);
  2951.     } else {
  2952.         *heightPtr = fmPtr->linespace;
  2953.         
  2954.         if (mePtr->label != NULL) {
  2955.             *widthPtr = Tk_TextWidth(tkfont, mePtr->label, mePtr->labelLength);
  2956.         } else {
  2957.             *widthPtr = 0;
  2958.         }
  2959. #ifdef VERBOSE
  2960.         printf("GetMenuLabelGeometry: width %d, height %d (+1)\n", *widthPtr,
  2961.                *heightPtr);
  2962.             fflush(stdout);
  2963. #endif
  2964.     }
  2965.     *heightPtr += 1;
  2966. }
  2967.  
  2968. /*
  2969.  *----------------------------------------------------------------------
  2970.  *
  2971.  * DrawMenuEntryBackground --
  2972.  *
  2973.  *    This procedure draws the background part of a menu.
  2974.  *
  2975.  * Results:
  2976.  *    None.
  2977.  *
  2978.  * Side effects:
  2979.  *    Commands are output to X to display the menu in its
  2980.  *    current mode.
  2981.  *
  2982.  *----------------------------------------------------------------------
  2983.  */
  2984.  
  2985. static void
  2986. DrawMenuEntryBackground(
  2987.     TkMenu *menuPtr,            /* The menu we are drawing. */
  2988.     TkMenuEntry *mePtr,            /* The entry we are drawing. */
  2989.     Drawable d,                /* What we are drawing into */
  2990.     Tk_3DBorder activeBorder,        /* Border for active items */
  2991.     Tk_3DBorder bgBorder,        /* Border for the background */
  2992.     int x,                /* left edge */
  2993.     int y,                /* top edge */
  2994.     int width,                /* width of rectangle to draw */
  2995.     int height)                /* height of rectangle to draw */
  2996. {
  2997. #ifdef VERBOSE
  2998. #include "tk3d.h"
  2999.     TkBorder *activePtr = (TkBorder *) activeBorder;
  3000.     TkBorder *bgPtr = (TkBorder *) bgBorder;
  3001.     printf("DrawMenuEntryBackground d %x actbg %x bg %x act %d => %d (%d,%d) %dx%d\n",
  3002.            d, activePtr->bgGC->foreground, bgPtr->bgGC->foreground,
  3003.            mePtr->state == tkActiveUid,
  3004.            mePtr->state == tkActiveUid ? activePtr->bgGC->foreground :
  3005.            bgPtr->bgGC->foreground, x, y, width, height);
  3006.            fflush(stdout);
  3007. #endif
  3008.     if (mePtr->state == tkActiveUid) {
  3009.     bgBorder = activeBorder;
  3010.     }
  3011.     Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder,
  3012.             x, y, width, height, 0, TK_RELIEF_FLAT);
  3013. }
  3014.  
  3015. /*
  3016.  *--------------------------------------------------------------
  3017.  *
  3018.  * TkpComputeStandardMenuGeometry --
  3019.  *
  3020.  *    This procedure is invoked to recompute the size and
  3021.  *    layout of a menu that is not a menubar clone.
  3022.  *
  3023.  * Results:
  3024.  *    None.
  3025.  *
  3026.  * Side effects:
  3027.  *    Fields of menu entries are changed to reflect their
  3028.  *    current positions, and the size of the menu window
  3029.  *    itself may be changed.
  3030.  *
  3031.  *--------------------------------------------------------------
  3032.  */
  3033.  
  3034. void
  3035. TkpComputeStandardMenuGeometry(
  3036.     TkMenu *menuPtr)        /* Structure describing menu. */
  3037. {
  3038.     Tk_Font tkfont;
  3039.     Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
  3040.     int x, y, height, width, indicatorSpace, labelWidth, accelWidth;
  3041.     int windowWidth, windowHeight, accelSpace;
  3042.     int i, j, lastColumnBreak = 0;
  3043. #ifdef VERBOSE
  3044.     printf("TkpComputeStandardMenuGeometry\n");
  3045.             fflush(stdout);
  3046. #endif
  3047.  
  3048.     if (menuPtr->tkwin == NULL) {
  3049.     return;
  3050.     }
  3051.  
  3052.     x = y = menuPtr->borderWidth;
  3053.     indicatorSpace = labelWidth = accelWidth = 0;
  3054.     windowHeight = 0;
  3055. #ifdef VERBOSE
  3056.     printf("windowHeight 0\n");
  3057.             fflush(stdout);
  3058. #endif
  3059.  
  3060.     /*
  3061.      * On the Mac especially, getting font metrics can be quite slow,
  3062.      * so we want to do it intelligently. We are going to precalculate
  3063.      * them and pass them down to all of the measuring and drawing
  3064.      * routines. We will measure the font metrics of the menu once.
  3065.      * If an entry does not have its own font set, then we give
  3066.      * the geometry/drawing routines the menu's font and metrics.
  3067.      * If an entry has its own font, we will measure that font and
  3068.      * give all of the geometry/drawing the entry's font and metrics.
  3069.      */
  3070.  
  3071.     Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics);
  3072.     accelSpace = Tk_TextWidth(menuPtr->tkfont, "M", 1);
  3073.  
  3074.     for (i = 0; i < menuPtr->numEntries; i++) {
  3075.         tkfont = menuPtr->entries[i]->tkfont;
  3076.         if (tkfont == NULL) {
  3077.             tkfont = menuPtr->tkfont;
  3078.             fmPtr = &menuMetrics;
  3079.         } else {
  3080.             Tk_GetFontMetrics(tkfont, &entryMetrics);
  3081.             fmPtr = &entryMetrics;
  3082.         }
  3083.         
  3084.     if ((i > 0) && menuPtr->entries[i]->columnBreak) {
  3085.         if (accelWidth != 0) {
  3086.         labelWidth += accelSpace;
  3087.         }
  3088.         for (j = lastColumnBreak; j < i; j++) {
  3089.         menuPtr->entries[j]->indicatorSpace = indicatorSpace;
  3090.         menuPtr->entries[j]->labelWidth = labelWidth;
  3091.         menuPtr->entries[j]->width = indicatorSpace + labelWidth
  3092.             + accelWidth + 2 * menuPtr->activeBorderWidth;
  3093.         menuPtr->entries[j]->x = x;
  3094.         menuPtr->entries[j]->entryFlags &= ~ENTRY_LAST_COLUMN;
  3095.         }
  3096.         x += indicatorSpace + labelWidth + accelWidth
  3097.             + 2 * menuPtr->borderWidth;
  3098.         indicatorSpace = labelWidth = accelWidth = 0;
  3099.         lastColumnBreak = i;
  3100.         y = menuPtr->borderWidth;
  3101. #ifdef VERBOSE
  3102.             printf("y = menuPtr->borderWidth (%d)\n", y);
  3103.             fflush(stdout);
  3104. #endif
  3105.     }
  3106.  
  3107.     if (menuPtr->entries[i]->type == SEPARATOR_ENTRY) {
  3108.         GetMenuSeparatorGeometry(menuPtr, menuPtr->entries[i], tkfont,
  3109.                 fmPtr, &width, &height);
  3110.         menuPtr->entries[i]->height = height;
  3111.     } else if (menuPtr->entries[i]->type == TEAROFF_ENTRY) {
  3112.         GetTearoffEntryGeometry(menuPtr, menuPtr->entries[i], tkfont,
  3113.                 fmPtr, &width, &height);
  3114.         menuPtr->entries[i]->height = height;
  3115.     } else {
  3116.     
  3117.         /*
  3118.          * For each entry, compute the height required by that
  3119.          * particular entry, plus three widths:  the width of the
  3120.          * label, the width to allow for an indicator to be displayed
  3121.          * to the left of the label (if any), and the width of the
  3122.          * accelerator to be displayed to the right of the label
  3123.          * (if any).  These sizes depend, of course, on the type
  3124.          * of the entry.
  3125.          */
  3126.     
  3127.         GetMenuLabelGeometry(menuPtr->entries[i], tkfont, fmPtr, &width,
  3128.                 &height);
  3129.         menuPtr->entries[i]->height = height;
  3130.         if (width > labelWidth) {
  3131.             labelWidth = width;
  3132.         }
  3133.     
  3134.         GetMenuAccelGeometry(menuPtr, menuPtr->entries[i], tkfont,
  3135.             fmPtr, &width, &height);
  3136.         if (height > menuPtr->entries[i]->height) {
  3137.             menuPtr->entries[i]->height = height;
  3138.         }
  3139.         if (width > accelWidth) {
  3140.             accelWidth = width;
  3141.         }
  3142.  
  3143.         GetMenuIndicatorGeometry(menuPtr, menuPtr->entries[i], tkfont,
  3144.                 fmPtr, &width, &height);
  3145.         if (height > menuPtr->entries[i]->height) {
  3146.             menuPtr->entries[i]->height = height;
  3147.         }
  3148.         if (width > indicatorSpace) {
  3149.             indicatorSpace = width;
  3150.         }
  3151.  
  3152.         menuPtr->entries[i]->height += 2 * menuPtr->activeBorderWidth + 1;
  3153.         }
  3154.         menuPtr->entries[i]->y = y;
  3155.     y += menuPtr->entries[i]->height;
  3156.     if (y > windowHeight) {
  3157.         windowHeight = y;
  3158. #ifdef VERBOSE
  3159.             printf("menuPtr->entries[%d]->y = %d, y += %d, windowHeight = %d\n",
  3160.                    i, menuPtr->entries[i]->y, menuPtr->entries[i]->height, y);
  3161.             fflush(stdout);
  3162.         } else {
  3163.             printf("menuPtr->entries[%d]->y = %d, y += %d\n",
  3164.                    i, menuPtr->entries[i]->y, menuPtr->entries[i]->height);
  3165.             fflush(stdout);
  3166. #endif
  3167.     }
  3168.     }
  3169.  
  3170.     if (accelWidth != 0) {
  3171.     labelWidth += accelSpace;
  3172.     }
  3173.     for (j = lastColumnBreak; j < menuPtr->numEntries; j++) {
  3174.     menuPtr->entries[j]->indicatorSpace = indicatorSpace;
  3175.     menuPtr->entries[j]->labelWidth = labelWidth;
  3176.     menuPtr->entries[j]->width = indicatorSpace + labelWidth
  3177.         + accelWidth + 2 * menuPtr->activeBorderWidth;
  3178.     menuPtr->entries[j]->x = x;
  3179.     menuPtr->entries[j]->entryFlags |= ENTRY_LAST_COLUMN;
  3180.     }
  3181.     windowWidth = x + indicatorSpace + labelWidth + accelWidth + accelSpace
  3182.         + 2 * menuPtr->activeBorderWidth
  3183.         + 2 * menuPtr->borderWidth;
  3184.  
  3185.     windowHeight += menuPtr->borderWidth;
  3186. #ifdef VERBOSE
  3187.     printf("windowHeight += menuPtr->borderWidth (%d)\n", menuPtr->borderWidth);
  3188.             fflush(stdout);
  3189. #endif
  3190.  
  3191.     /*
  3192.      * The X server doesn't like zero dimensions, so round up to at least
  3193.      * 1 (a zero-sized menu should never really occur, anyway).
  3194.      */
  3195.  
  3196.     if (windowWidth <= 0) {
  3197.     windowWidth = 1;
  3198.     }
  3199.     if (windowHeight <= 0) {
  3200. #ifdef VERBOSE
  3201.         printf("windowHeight <= 0 (%d) => 1\n", windowHeight);
  3202.             fflush(stdout);
  3203. #endif
  3204.     windowHeight = 1;
  3205.     }
  3206.     menuPtr->totalWidth = windowWidth;
  3207. #ifdef VERBOSE
  3208.     printf("totalHeight %d\n", windowHeight);
  3209.             fflush(stdout);
  3210. #endif
  3211.     menuPtr->totalHeight = windowHeight;
  3212. }
  3213.  
  3214. /*
  3215.  *----------------------------------------------------------------------
  3216.  *
  3217.  * MenuSelectEvent --
  3218.  *
  3219.  *    Generates a "MenuSelect" virtual event. This can be used to
  3220.  *    do context-sensitive menu help.
  3221.  *
  3222.  * Results:
  3223.  *    None.
  3224.  *
  3225.  * Side effects:
  3226.  *    Places a virtual event on the event queue.
  3227.  *
  3228.  *----------------------------------------------------------------------
  3229.  */
  3230.  
  3231. static void
  3232. MenuSelectEvent(
  3233.     TkMenu *menuPtr)        /* the menu we have selected. */
  3234. {
  3235.     XVirtualEvent event;
  3236.     POINTL rootPoint;
  3237. #ifdef VERBOSE
  3238.     printf("MenuSelectEvent\n");
  3239.             fflush(stdout);
  3240. #endif
  3241.  
  3242.     if (menuPtr->tkwin == NULL) {
  3243.         return;
  3244.     }
  3245.     event.type = VirtualEvent;
  3246.     event.serial = menuPtr->display->request;
  3247.     event.send_event = 0;
  3248.     event.display = menuPtr->display;
  3249.     Tk_MakeWindowExist(menuPtr->tkwin);
  3250.     event.event = Tk_WindowId(menuPtr->tkwin);
  3251.     event.root = XRootWindow(menuPtr->display, 0);
  3252.     event.subwindow = None;
  3253.     event.time = TkpGetMS();
  3254.  
  3255.     WinQueryMsgPos(TclOS2GetHAB(), &rootPoint);
  3256.     event.x_root = rootPoint.x;
  3257.     /* Translate y coordinate */
  3258.     event.y_root = yScreen - rootPoint.y;
  3259.     event.state = TkOS2GetModifierState();
  3260.     event.same_screen = 1;
  3261.     event.name = Tk_GetUid("MenuSelect");
  3262.     Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
  3263. }
  3264.  
  3265. /*
  3266.  *----------------------------------------------------------------------
  3267.  *
  3268.  * TkpMenuNotifyToplevelCreate --
  3269.  *
  3270.  *    This routine reconfigures the menu and the clones indicated by
  3271.  *    menuName becuase a toplevel has been created and any system
  3272.  *    menus need to be created.
  3273.  *
  3274.  * Results:
  3275.  *    None.
  3276.  *
  3277.  * Side effects:
  3278.  *    An idle handler is set up to do the reconfiguration.
  3279.  *
  3280.  *----------------------------------------------------------------------
  3281.  */
  3282.  
  3283. void
  3284. TkpMenuNotifyToplevelCreate(
  3285.     Tcl_Interp *interp,            /* The interp the menu lives in. */
  3286.     char *menuName)            /* The name of the menu to
  3287.                      * reconfigure. */
  3288. {
  3289.     TkMenuReferences *menuRefPtr;
  3290.     TkMenu *menuPtr;
  3291. #ifdef VERBOSE
  3292.     printf("TkpMenuNotifyToplevelCreate [%s]\n", menuName);
  3293.             fflush(stdout);
  3294. #endif
  3295.  
  3296.     if ((menuName != NULL) && (menuName[0] != '\0')) {
  3297.     menuRefPtr = TkFindMenuReferences(interp, menuName);
  3298.     if ((menuRefPtr != NULL) && (menuRefPtr->menuPtr != NULL)) {
  3299.         for (menuPtr = menuRefPtr->menuPtr->masterMenuPtr; menuPtr != NULL;
  3300.             menuPtr = menuPtr->nextInstancePtr) {
  3301.         if ((menuPtr->menuType == MENUBAR)
  3302.             && !(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
  3303.             menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  3304.             Tcl_DoWhenIdle(ReconfigureOS2Menu,
  3305.                 (ClientData) menuPtr);
  3306.         }
  3307.         }
  3308.     }
  3309.     }
  3310. }
  3311.  
  3312. /*
  3313.  *----------------------------------------------------------------------
  3314.  *
  3315.  * MenuExitHandler --
  3316.  *
  3317.  *    Throws away the utility window needed for menus and unregisters
  3318.  *    the class.
  3319.  *
  3320.  * Results:
  3321.  *    None.
  3322.  *
  3323.  * Side effects:
  3324.  *    Menus have to be reinitialized next time.
  3325.  *
  3326.  *----------------------------------------------------------------------
  3327.  */
  3328.  
  3329. static void
  3330. MenuExitHandler(
  3331.     ClientData clientData)        /* Not used */
  3332. {
  3333. #ifdef VERBOSE
  3334.     printf("MenuExitHandler menuHWND %x\n", menuHWND);
  3335.             fflush(stdout);
  3336. #endif
  3337.     WinDestroyWindow(menuHWND);
  3338. }
  3339.  
  3340. /*
  3341.  *----------------------------------------------------------------------
  3342.  *
  3343.  * TkpMenuInit --
  3344.  *
  3345.  *    Sets up the hash tables and the variables used by the menu package.
  3346.  *
  3347.  * Results:
  3348.  *    None.
  3349.  *
  3350.  * Side effects:
  3351.  *    lastMenuID gets initialized, and the parent hash and the command hash
  3352.  *    are allocated.
  3353.  *
  3354.  *----------------------------------------------------------------------
  3355.  */
  3356.  
  3357. void
  3358. TkpMenuInit()
  3359. {
  3360.     int i;
  3361.     FRAMECDATA fcdata;
  3362.     HBITMAP checkMarkBitmap;
  3363.     BITMAPINFOHEADER info;
  3364. #ifdef VERBOSE
  3365.     printf("TkpMenuInit\n");
  3366.     fflush(stdout);
  3367. #endif
  3368.  
  3369.     Tcl_InitHashTable(&os2MenuTable, TCL_ONE_WORD_KEYS);
  3370.     Tcl_InitHashTable(&commandTable, TCL_ONE_WORD_KEYS);
  3371.  
  3372.     /*
  3373.     WinRegisterClass(TclOS2GetHAB(), MENU_CLASS_NAME, TkOS2MenuProc, 0L, 0L);
  3374.     */
  3375.  
  3376.     fcdata.cb = sizeof(FRAMECDATA);
  3377.     fcdata.flCreateFlags = 0L;
  3378.     fcdata.hmodResources = 0L;
  3379.     fcdata.idResources = 0;
  3380.     menuHWND = WinCreateWindow(HWND_DESKTOP, WC_MENU, "MenuWindow",
  3381.                                0L, 0, 0, 10, 10, NULLHANDLE, HWND_BOTTOM,
  3382.                    FID_MENU, &fcdata, NULL);
  3383. /*
  3384.     menuHWND = WinCreateWindow(HWND_DESKTOP, WC_MENU, "MenuWindow",
  3385.                                WS_CLIPSIBLINGS | WS_SAVEBITS, 0, 0, 0, 0,
  3386.                                HWND_DESKTOP, HWND_TOP, FID_MENU, NULL, NULL);
  3387. */
  3388.     oldMenuProc = WinSubclassWindow(menuHWND, TkOS2MenuProc);
  3389. #ifdef VERBOSE
  3390.     printf("WinCreateWindow menuHWND %x, oldMenuProc %x\n", menuHWND,
  3391.            oldMenuProc);
  3392.     fflush(stdout);
  3393. #endif
  3394.  
  3395.     Tcl_CreateExitHandler(MenuExitHandler, (ClientData) NULL);
  3396.  
  3397.     /*
  3398.      * Set all of the default options. The loop will terminate when we run
  3399.      * out of options via a break statement.
  3400.      */
  3401.  
  3402.     for (i = 0; ; i++) {
  3403.     if (tkMenuConfigSpecs[i].type == TK_CONFIG_END) {
  3404.         break;
  3405.     }
  3406.  
  3407.     if ((strcmp(tkMenuConfigSpecs[i].dbName,
  3408.         "activeBorderWidth") == 0) ||
  3409.         (strcmp(tkMenuConfigSpecs[i].dbName, "borderWidth") == 0)) {
  3410.         int borderWidth;
  3411.  
  3412.         borderWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
  3413.         if (WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER) > borderWidth) {
  3414.         borderWidth = WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
  3415.         }
  3416.         sprintf(borderString, "%d", borderWidth);
  3417.         tkMenuConfigSpecs[i].defValue = borderString;
  3418.     } else if ((strcmp(tkMenuConfigSpecs[i].dbName, "font") == 0)) {
  3419.         int pointSize;
  3420.             char sizeString[4];
  3421.             HPS hps;
  3422.             Tcl_DString boldItalicDString;
  3423.             int bold = 0;
  3424.             int italic = 0;
  3425.             FONTMETRICS fm;
  3426.  
  3427.             /*
  3428.          * System font is in OS2.INI, application "PM_SystemFonts",
  3429.          * key "Menus" (eg. on Warp 4 "9.WarpSans Bold").
  3430.              * We don't need to query that though, since the menu control
  3431.              * handles this for us, so just query the font of its hps.
  3432.          */
  3433.  
  3434.         hps = WinGetPS(menuHWND);
  3435. #ifdef VERBOSE
  3436.             printf("WinGetPS menuHWND %x returns %x\n", menuHWND, hps);
  3437.             fflush(stdout);
  3438. #endif
  3439.  
  3440.         Tcl_DStringInit(&menuFontDString);
  3441.  
  3442.         rc = GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm);
  3443. #ifdef VERBOSE
  3444.             if (rc == TRUE) {
  3445.                 printf("GpiQueryFontMetrics %x OK: [%s] %dpt wt %d it %d l%d\n",
  3446.                        hps, fm.szFacename, fm.lEmHeight, fm.usWeightClass > 5,
  3447.                        fm.fsSelection & FM_SEL_ITALIC, fm.lMaxBaselineExt);
  3448.             } else {
  3449.                 printf("GpiQueryFontMetrics %x ERROR %x\n", hps,
  3450.                        WinGetLastError(TclOS2GetHAB()));
  3451.             }
  3452.             fflush(stdout);
  3453. #endif
  3454.         WinReleasePS(hps);
  3455.  
  3456.             /*
  3457.              * For a bitmap font, lEmHeight contains the height in pixels
  3458.              * For an outline font it contains the intended point size in
  3459.              * decipoints.
  3460.              */
  3461.             if (fm.fsType & FM_TYPE_FIXED) {
  3462.             pointSize = -fm.sNominalPointSize;
  3463. #ifdef VERBOSE
  3464.                 printf("FM_TYPE_FIXED, pointSize %d\n", pointSize);
  3465.             fflush(stdout);
  3466. #endif
  3467.             } else {
  3468.             pointSize = fm.sNominalPointSize / 10;
  3469. #ifdef VERBOSE
  3470.                 printf("not FM_TYPE_FIXED, pointSize %d\n", pointSize);
  3471.             fflush(stdout);
  3472. #endif
  3473.             }
  3474.         if (fm.usWeightClass > 5) {
  3475.         bold = 1;
  3476.         }
  3477.         if (fm.fsSelection & FM_SEL_ITALIC) {
  3478.         italic = 1;
  3479.         }
  3480.  
  3481.         Tcl_DStringAppendElement(&menuFontDString, fm.szFacename);
  3482.         sprintf(sizeString, "%d", pointSize);
  3483.         Tcl_DStringAppendElement(&menuFontDString, sizeString);
  3484.  
  3485.         if (bold == 1 || italic == 1) {
  3486.         Tcl_DStringInit(&boldItalicDString);
  3487.         if (bold == 1) {
  3488.             Tcl_DStringAppendElement(&boldItalicDString, "bold");
  3489.         }
  3490.         if (italic == 1) {
  3491.             Tcl_DStringAppendElement(&boldItalicDString, "italic");
  3492.         }
  3493.         Tcl_DStringAppendElement(&menuFontDString,
  3494.             Tcl_DStringValue(&boldItalicDString));
  3495.         }
  3496.  
  3497.         tkMenuConfigSpecs[i].defValue = Tcl_DStringValue(&menuFontDString);
  3498.     }
  3499.     }
  3500.  
  3501.     checkMarkBitmap = WinGetSysBitmap(HWND_DESKTOP, SBMP_MENUCHECK);
  3502.     if (checkMarkBitmap == NULLHANDLE) {
  3503.     return;
  3504.     }
  3505.     info.cbFix = sizeof(BITMAPINFOHEADER);    /* Must be set first */
  3506.     rc = GpiQueryBitmapParameters(checkMarkBitmap, &info);
  3507.     GpiDeleteBitmap(checkMarkBitmap);
  3508.     if (rc != TRUE) {
  3509.     return;
  3510.     }
  3511.     indicatorDimensions[0] = info.cy;        /* height */
  3512.     indicatorDimensions[1] = info.cx;        /* width */
  3513.  
  3514. }
  3515.