home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tcltk805.zip / tcl805s.zip / tk8.0.5 / os2 / tkOS2Button.c < prev    next >
C/C++ Source or Header  |  2000-07-11  |  44KB  |  1,315 lines

  1. /* 
  2.  * tkOS2Button.c --
  3.  *
  4.  *    This file implements the OS/2 specific portion of the button
  5.  *    widgets.
  6.  *
  7.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  8.  * Copyright (c) 1999-2000 by Illya Vaes
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  */
  14.  
  15. #include "tkOS2Int.h"
  16. #include "tkResIDs.h"
  17. #include "tkButton.h"
  18.  
  19. #ifdef VERBOSE
  20. #include "tk3d.h"
  21. #endif
  22.  
  23. /*
  24.  * Declaration of OS/2 specific button structure.
  25.  */
  26.  
  27. typedef struct OS2Button {
  28.     TkButton info;        /* Generic button info. */
  29.     PFNWP oldProc;        /* Old window procedure. */
  30.     HWND hwnd;            /* Current window handle. */
  31.     Pixmap pixmap;        /* Bitmap for rendering the button. */
  32.     ULONG style;        /* Window style flags. */
  33. } OS2Button;
  34.  
  35.  
  36. /*
  37.  * The following macro reverses the order of RGB bytes to convert
  38.  * between RGBQUAD and LONG values.
  39.  */
  40.  
  41. /*
  42. #define FlipColor(rgb) (rgb)
  43. */
  44. #define FlipColor(rgb) (RGB(GetBValue(rgb),GetGValue(rgb),GetRValue(rgb)))
  45.  
  46. /*
  47.  * The following enumeration defines the meaning of the palette entries
  48.  * in the "buttons" image used to draw checkbox and radiobutton indicators.
  49.  */
  50.  
  51. enum {
  52.     PAL_CHECK = 7,
  53.     PAL_TOP_OUTER = 8,
  54.     PAL_BOTTOM_OUTER = 0,
  55.     PAL_BOTTOM_INNER = 14,
  56.     PAL_INTERIOR = 15,
  57.     PAL_TOP_INNER = 13,
  58.     PAL_BACKGROUND = 12
  59. };
  60.  
  61. /*
  62.  * Set to non-zero if this module is initialized.
  63.  */
  64.  
  65. static int initialized = 0;
  66.  
  67. /*
  68.  * Variables for the cached information about the boxes bitmap.
  69.  */
  70.  
  71. static HBITMAP hBoxes = NULLHANDLE;   /* Handle of the bitmap. */
  72. /*
  73. static ULONG palTable[16] = {0x1ffffff, 0x1ffffff, 0x1ffffff, 0x1ffffff,
  74.                              0x1ffffff, 0x1ffffff, 0x1ffffff, 0x1ffffff,
  75.                              0x1ffffff, 0x1ffffff, 0x1ffffff, 0x1ffffff,
  76.                              0x1ffffff, 0x1ffffff, 0x1ffffff, 0x1ffffff};
  77. */
  78. static ULONG *palTable;
  79. static HDC boxesDC;
  80. static HPS boxesPS;
  81. /*static RGB *boxesPalette = NULL;          /* Pointer to color palette. */
  82. static HPAL boxesPalette;
  83. static PBYTE boxesBits = NULL;              /* Pointer to bitmap data. */
  84. static ULONG boxHeight = 0, boxWidth = 0;    /* Size of each sub-image. */
  85. static BITMAPINFO2 *boxesPtr;        /* Information about the bitmap */
  86.  
  87. /*
  88.  * This variable holds the default border width for a button in string
  89.  * form for use in a Tk_ConfigSpec.
  90.  */
  91.  
  92. static char defWidth[8];
  93.  
  94. /*
  95.  * Use the lastCommandID variable in tkOS2Menu.c for the next available
  96.  * free ID.
  97.  */
  98. extern USHORT lastCommandID;    /* The last command ID we allocated. */
  99.  
  100. /*
  101.  * Declarations for functions defined in this file.
  102.  */
  103.  
  104. static MRESULT EXPENTRY    ButtonProc _ANSI_ARGS_((HWND hwnd, ULONG message,
  105.                 MPARAM param1, MPARAM param2));
  106. static Window        CreateProc _ANSI_ARGS_((Tk_Window tkwin,
  107.                 Window parent, ClientData instanceData));
  108. static void        InitBoxes _ANSI_ARGS_((void));
  109. static void        CleanupBoxes _ANSI_ARGS_((ClientData clientData));
  110. static void        UpdateButtonDefaults _ANSI_ARGS_((void));
  111.  
  112. /*
  113.  * The class procedure table for the button widgets.
  114.  */
  115.  
  116. TkClassProcs tkpButtonProcs = { 
  117.     CreateProc,            /* createProc. */
  118.     TkButtonWorldChanged,    /* geometryProc. */
  119.     NULL            /* modalProc. */ 
  120. };
  121.  
  122.  
  123. /*
  124.  *----------------------------------------------------------------------
  125.  *
  126.  * InitBoxes --
  127.  *
  128.  *    This function loads the Tk 3d button bitmap.  "buttons" is a 16 
  129.  *    color bitmap that is laid out such that the top row contains 
  130.  *    the 4 checkbox images, and the bottom row contains the radio 
  131.  *    button images. Note that the bitmap is stored in bottom-up 
  132.  *    format.  Also, the first seven palette entries are used to 
  133.  *    identify the different parts of the bitmaps so we can do the 
  134.  *    appropriate color mappings based on the current button colors.
  135.  *
  136.  * Results:
  137.  *    None.
  138.  *
  139.  * Side effects:
  140.  *    Loads the "buttons" resource.
  141.  *
  142.  *----------------------------------------------------------------------
  143.  */
  144.  
  145. static void
  146. InitBoxes()
  147. {
  148.     /*
  149.      * For DLLs like Tk, the HINSTANCE is the same as the HMODULE.
  150.      */
  151.  
  152. #define BOXROWS 3
  153. #define TKROWS 2
  154. #define BOXCOLS 4
  155.     DEVOPENSTRUC dop = {0L, (PSZ)"DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
  156.     SIZEL sizl = {0,0}; /* use same page size as device */
  157. #ifdef VERBOSE
  158.     int i;
  159. #endif
  160.  
  161.     if (hBoxes) {
  162.         return;
  163.     }
  164.  
  165.     boxesDC = DevOpenDC(TclOS2GetHAB(), OD_MEMORY, (PSZ)"*", 5L,
  166.                         (PDEVOPENDATA)&dop, NULLHANDLE);
  167.     if (boxesDC == DEV_ERROR) {
  168. #ifdef VERBOSE
  169.         printf("DevOpenDC ERROR in InitBoxes\n");
  170. #endif
  171.         return;
  172.     }
  173. #ifdef VERBOSE
  174.     printf("DevOpenDC in InitBoxes returns %x\n", boxesDC);
  175. #endif
  176.     boxesPS = GpiCreatePS(TclOS2GetHAB(), boxesDC, &sizl,
  177.                       PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
  178.     if (boxesPS == NULLHANDLE) {
  179. #ifdef VERBOSE
  180.         printf("InitBoxes, GpiCreatePS ERROR %x\n",
  181.                WinGetLastError(TclOS2GetHAB()));
  182. #endif
  183.         DevCloseDC(boxesDC);
  184.         return;
  185. #ifdef VERBOSE
  186.     } else {
  187.         printf("InitBoxes, GpiCreatePS OK %x\n", boxesPS);
  188. #endif
  189.     }
  190.     Tcl_CreateExitHandler(CleanupBoxes, (ClientData) NULL);
  191. /*
  192.     hBoxes = GpiLoadBitmap(boxesPS, Tk_GetHMODULE(), buttons, 0, 0);
  193. */
  194.     hBoxes = WinGetSysBitmap(HWND_DESKTOP, SBMP_CHECKBOXES);
  195. #ifdef VERBOSE
  196. /*
  197.     if (hBoxes == GPI_ERROR) {
  198. */
  199.     if (hBoxes == NULLHANDLE) {
  200.         printf("InitBoxes, GpiGetSysBitmap into boxesPS %x ERROR %x\n", boxesPS,
  201.                WinGetLastError(TclOS2GetHAB()));
  202.     } else {
  203.         printf("InitBoxes, GpiGetSysBitmap into boxesPS %x OK %x\n", boxesPS,
  204.                hBoxes);
  205.     }
  206. #endif
  207. /*
  208.     if (hBoxes == GPI_ERROR) {
  209.         hBoxes = NULLHANDLE;
  210.     }
  211. */
  212.  
  213.  
  214.     /*
  215.      * Copy the bitmap into writable memory.
  216.      */
  217.  
  218.     if (hBoxes != NULLHANDLE) {
  219.         BITMAPINFOHEADER bmpInfo;
  220.         rc = GpiQueryBitmapParameters(hBoxes, &bmpInfo);
  221.         if (rc == TRUE && !(bmpInfo.cx % BOXCOLS) && !(bmpInfo.cy % BOXROWS)) {
  222. #ifdef VERBOSE
  223.             printf("    cx %d, cy %d, cPlanes %d, cBitCount %d\n", bmpInfo.cx,
  224.                    bmpInfo.cy, bmpInfo.cPlanes, bmpInfo.cBitCount);
  225. #endif
  226.         boxWidth = bmpInfo.cx / BOXCOLS;
  227.         boxHeight = bmpInfo.cy / BOXROWS;
  228.             boxesPtr = (PBITMAPINFO2) ckalloc ( sizeof(BITMAPINFO2) +
  229.                                       (1 << bmpInfo.cBitCount) * sizeof(LONG) +
  230.                                       boxWidth * boxHeight * sizeof(ULONG));
  231.  
  232.             rc = GpiSetBitmap(boxesPS, hBoxes);
  233. #ifdef VERBOSE
  234.             if (rc == HBM_ERROR) {
  235.                 printf("    GpiSetBitmap %x %x ERROR %x\n", boxesPS, hBoxes,
  236.                        WinGetLastError(TclOS2GetHAB()));
  237.             } else {
  238.                 printf("    GpiSetBitmap %x %x returned %x\n", boxesPS, hBoxes, rc);
  239.             }
  240. #endif
  241.             boxesPtr->cbFix = sizeof(BITMAPINFOHEADER2);
  242.             rc = GpiQueryBitmapInfoHeader(hBoxes, (PBITMAPINFOHEADER2)boxesPtr);
  243. #ifdef VERBOSE
  244.             if (rc == GPI_ALTERROR) {
  245.                 printf("    GpiQueryBitmapInfoHeader %x ERROR %x\n", hBoxes,
  246.                        WinGetLastError(TclOS2GetHAB()));
  247.             } else {
  248.                 printf("    GpiQueryBitmapInfoHeader %x OK cy %d\n", hBoxes,
  249.                        boxesPtr->cy);
  250.             }
  251. #endif
  252.             boxesPtr->cbFix = sizeof(BITMAPINFO2) +
  253.                               (1 << boxesPtr->cBitCount) * sizeof(LONG);
  254.             /* Only use the top 2 rows (bottom is grayed checkbutton) */
  255.             boxesBits= (PBYTE)ckalloc(((boxesPtr->cBitCount*boxesPtr->cx+31)/32)
  256.                                       * boxesPtr->cPlanes * sizeof(ULONG)
  257.                                       * (boxesPtr->cy * TKROWS / BOXROWS));
  258. /*
  259.             boxesPalette = (RGB*)boxesPtr->argbColor;
  260. */
  261.             palTable = (PULONG) boxesPtr->argbColor;
  262.             /* Get default colors */
  263.             rc = GpiQueryPaletteInfo(NULLHANDLE, boxesPS, 0L, 0, 16L, palTable);
  264. #ifdef VERBOSE
  265.             if (rc == PAL_ERROR) {
  266.                 printf("GpiQueryPaletteInfo def. colors ERROR %x\n",
  267.                        WinGetLastError(TclOS2GetHAB()));
  268.             } else {
  269.                 printf("GpiQueryPaletteInfo def. colors returned %d entries\n",
  270.                        rc);
  271.             }
  272.             for (i= 0; i<16; i++) {
  273.                 printf("initial palTable[%d] [%x]\n", i, palTable[i]);
  274.             }
  275. #endif
  276.             /* Only use the top 2 rows (bottom is grayed checkbutton) */
  277.             rc = GpiQueryBitmapBits(boxesPS, boxesPtr->cy / BOXROWS,
  278.                                     boxesPtr->cy * TKROWS / BOXROWS, boxesBits,
  279.                                     boxesPtr);
  280. #ifdef VERBOSE
  281.             if (rc == GPI_ALTERROR) {
  282.                 printf("    GpiQueryBitmapBits %x %x ERROR %x fix %d bits %d\n",
  283.                        boxesPS, hBoxes, WinGetLastError(TclOS2GetHAB()),
  284.                        boxesPtr->cbFix,
  285.                        ((boxesPtr->cBitCount * boxesPtr->cx + 31)/32)
  286.                         * boxesPtr->cPlanes * sizeof(ULONG) * boxesPtr->cy);
  287.             } else {
  288.                 printf("    GpiQueryBitmapBits %x %x gave %d, fix %d bits %d\n",
  289.                        boxesPS, hBoxes, rc, boxesPtr->cbFix,
  290.                        ((boxesPtr->cBitCount * boxesPtr->cx + 31)/32)
  291.                         * boxesPtr->cPlanes * sizeof(ULONG) * boxesPtr->cy);
  292.             }
  293. #endif
  294.  
  295.             boxesPalette = GpiCreatePalette(TclOS2GetHAB(), 0L, LCOLF_CONSECRGB,
  296.                                             16L, palTable);
  297. #ifdef VERBOSE
  298.             if (boxesPalette == GPI_ERROR) {
  299.                 printf("    GpiCreatePalette ERROR %x\n",
  300.                        WinGetLastError(TclOS2GetHAB()));
  301.             } else {
  302.                 printf("    GpiCreatePalette OK: %x\n", boxesPalette);
  303.             }
  304. #endif
  305.             rc = GpiSelectPalette(boxesPS, boxesPalette);
  306. #ifdef VERBOSE
  307.             if (rc == PAL_ERROR) {
  308.                 printf("    GpiSelectPalette %x ERROR %x\n", boxesPalette,
  309.                        WinGetLastError(TclOS2GetHAB()));
  310.             } else {
  311.                 printf("    GpiSelectPalette %x OK: %x\n", boxesPalette, rc);
  312.             }
  313. #endif
  314.         } else {
  315.         hBoxes = NULLHANDLE;
  316.         }
  317.     }
  318. #undef BOXROWS
  319. #undef BOXCOLS
  320. }
  321.  
  322. /*
  323.  *----------------------------------------------------------------------
  324.  *
  325.  * CleanupBoxes --
  326.  *
  327.  *    This function frees the PS/DC combo for the boxes bitmap on exit.
  328.  *
  329.  * Results:
  330.  *    None.
  331.  *
  332.  * Side effects:
  333.  *    Destroys boxesPS and closes boxesDC.
  334.  *
  335.  *----------------------------------------------------------------------
  336.  */
  337.  
  338. static void
  339. CleanupBoxes(
  340.     ClientData clientData)    /* Not used */
  341. {
  342. #ifdef VERBOSE
  343.     printf("CleanupBoxes destroying PS %x and closing DC %x\n", boxesPS,
  344.            boxesDC);
  345.     fflush(stdout);
  346. #endif
  347.     GpiDestroyPS(boxesPS);
  348.     DevCloseDC(boxesDC);
  349. }
  350.  
  351. /*
  352.  *----------------------------------------------------------------------
  353.  *
  354.  * UpdateButtonDefaults --
  355.  *
  356.  *    This function retrieves the current system defaults for
  357.  *    the button widgets.
  358.  *
  359.  * Results:
  360.  *    None.
  361.  *
  362.  * Side effects:
  363.  *    Updates the configuration defaults for buttons.
  364.  *
  365.  *----------------------------------------------------------------------
  366.  */
  367.  
  368. void
  369. UpdateButtonDefaults()
  370. {
  371.     Tk_ConfigSpec *specPtr;
  372.     int width = WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
  373.  
  374.     if (width == 0) {
  375.     width = 1;
  376.     }
  377.     sprintf(defWidth, "%d", width);
  378.     for (specPtr = tkpButtonConfigSpecs; specPtr->type != TK_CONFIG_END;
  379.         specPtr++) {
  380.     if (specPtr->offset == Tk_Offset(TkButton, borderWidth)) {
  381.         specPtr->defValue = defWidth;
  382.     }
  383.     }
  384. }
  385.  
  386. /*
  387.  *----------------------------------------------------------------------
  388.  *
  389.  * TkpCreateButton --
  390.  *
  391.  *    Allocate a new TkButton structure.
  392.  *
  393.  * Results:
  394.  *    Returns a newly allocated TkButton structure.
  395.  *
  396.  * Side effects:
  397.  *    Registers an event handler for the widget.
  398.  *
  399.  *----------------------------------------------------------------------
  400.  */
  401.  
  402. TkButton *
  403. TkpCreateButton(tkwin)
  404.     Tk_Window tkwin;
  405. {
  406.     OS2Button *butPtr;
  407.  
  408.     if (!initialized) {
  409.     UpdateButtonDefaults();
  410.     initialized = 1;
  411.     }
  412.  
  413.     butPtr = (OS2Button *)ckalloc(sizeof(OS2Button));
  414.     butPtr->hwnd = NULLHANDLE;
  415.     return (TkButton *) butPtr;
  416. }
  417.  
  418. /*
  419.  *----------------------------------------------------------------------
  420.  *
  421.  * CreateProc --
  422.  *
  423.  *    This function creates a new Button control, subclasses
  424.  *    the instance, and generates a new Window object.
  425.  *
  426.  * Results:
  427.  *    Returns the newly allocated Window object, or None on failure.
  428.  *
  429.  * Side effects:
  430.  *    Causes a new Button control to come into existence.
  431.  *
  432.  *----------------------------------------------------------------------
  433.  */
  434.  
  435. static Window
  436. CreateProc(tkwin, parentWin, instanceData)
  437.     Tk_Window tkwin;        /* Token for window. */
  438.     Window parentWin;        /* Parent of new window. */
  439.     ClientData instanceData;    /* Button instance data. */
  440. {
  441.     Window window;
  442.     HWND parent;
  443.     char *class;
  444.     OS2Button *butPtr = (OS2Button *)instanceData;
  445.  
  446.     parent = Tk_GetHWND(parentWin);
  447.     if (parent == NULLHANDLE) {
  448.         parent = HWND_DESKTOP;
  449.     }
  450.     if (butPtr->info.type == TYPE_LABEL) {
  451. #ifdef VERBOSE
  452.         printf("CreateProc tkwin %x, butPtr %x, LABEL\n", tkwin, butPtr);
  453. #endif
  454.     class = WC_STATIC;
  455.         butPtr->style = WS_VISIBLE | WS_CLIPSIBLINGS;
  456.     } else {
  457. #ifdef VERBOSE
  458.         printf("CreateProc tkwin %x, butPtr %x, BUTTON\n", tkwin, butPtr);
  459. #endif
  460.     class = WC_BUTTON;
  461.         butPtr->style = BS_USERBUTTON | WS_VISIBLE | WS_CLIPSIBLINGS;
  462.     }
  463.     lastCommandID++;
  464.     butPtr->hwnd = WinCreateWindow(parent, class, "", butPtr->style,
  465.                                Tk_X(tkwin),
  466.                    TkOS2HwndHeight(parent) -
  467.                        (Tk_Y(tkwin) + Tk_Height(tkwin)),
  468.                    Tk_Width(tkwin), Tk_Height(tkwin),
  469.                    parent, HWND_TOP, lastCommandID,
  470.                    (PVOID)NULL, (PVOID)NULL);
  471.     if (butPtr->hwnd == NULLHANDLE) {
  472.         butPtr->oldProc = WinDefWindowProc;
  473. #ifdef VERBOSE
  474.         printf("WinCreateWindow button p %x (%d,%d) %dx%d id %x t%s ERROR %x\n",
  475.                parent, Tk_X(tkwin),
  476.            TkOS2HwndHeight(parent) - (Tk_Y(tkwin) + Tk_Height(tkwin)),
  477.                Tk_Width(tkwin), Tk_Height(tkwin), lastCommandID,
  478.                butPtr->info.type == TYPE_LABEL ? "LABEL" :
  479.                (butPtr->info.type == TYPE_BUTTON ? "BUTTON" :
  480.                (butPtr->info.type == TYPE_CHECK_BUTTON ? "CHECK_BUTTON" :
  481.                (butPtr->info.type == TYPE_RADIO_BUTTON ? "RADIO_BUTTON" :
  482.                 "UNKNOWN"))), WinGetLastError(TclOS2GetHAB()));
  483. #endif
  484.         return None;
  485. #ifdef VERBOSE
  486.     } else {
  487.         printf("WinCreateWindow button %x p %x (%d,%d) %dx%d id %x t %s\n",
  488.                butPtr->hwnd, parent, Tk_X(tkwin),
  489.            TkOS2HwndHeight(parent) - (Tk_Y(tkwin) + Tk_Height(tkwin)),
  490.                Tk_Width(tkwin), Tk_Height(tkwin), lastCommandID,
  491.                butPtr->info.type == TYPE_LABEL ? "LABEL" :
  492.                (butPtr->info.type == TYPE_BUTTON ? "BUTTON" :
  493.                (butPtr->info.type == TYPE_CHECK_BUTTON ? "CHECK_BUTTON" :
  494.                (butPtr->info.type == TYPE_RADIO_BUTTON ? "RADIO_BUTTON" :
  495.                 "UNKNOWN"))));
  496. #endif
  497.     }
  498.     butPtr->oldProc = WinSubclassWindow(butPtr->hwnd, (PFNWP)ButtonProc);
  499. #ifdef VERBOSE
  500.     printf("WinSubclassWindow %x (%s) returns %x\n", butPtr->hwnd,
  501.            butPtr->info.type == TYPE_LABEL ? "LABEL" :
  502.            (butPtr->info.type == TYPE_BUTTON ? "BUTTON" :
  503.            (butPtr->info.type == TYPE_CHECK_BUTTON ? "CHECK_BUTTON" :
  504.            (butPtr->info.type == TYPE_RADIO_BUTTON ? "RADIO_BUTTON" :
  505.            "UNKNOWN"))), butPtr->oldProc);
  506. #endif
  507.  
  508.     window = Tk_AttachHWND(tkwin, butPtr->hwnd);
  509.     return window;
  510. }
  511.  
  512. /*
  513.  *----------------------------------------------------------------------
  514.  *
  515.  * TkpDestroyButton --
  516.  *
  517.  *    Free data structures associated with the button control.
  518.  *
  519.  * Results:
  520.  *    None.
  521.  *
  522.  * Side effects:
  523.  *    Restores the default control state.
  524.  *
  525.  *----------------------------------------------------------------------
  526.  */
  527.  
  528. void
  529. TkpDestroyButton(butPtr)
  530.     TkButton *butPtr;
  531. {
  532.     OS2Button *os2ButPtr = (OS2Button *)butPtr;
  533.     HWND hwnd = os2ButPtr->hwnd;
  534. #ifdef VERBOSE
  535.     printf("TkpDestroyButton butPtr %x hwnd %x\n", butPtr, hwnd);
  536.     fflush(stdout);
  537. #endif
  538.     if (hwnd) {
  539.         WinSubclassWindow(hwnd, (PFNWP)os2ButPtr->oldProc);
  540.     }
  541.     /* Reset lastWinPtr etc. */
  542.     TkPointerDeadWindow((TkWindow *)butPtr->tkwin);
  543. }
  544.  
  545. /*
  546.  *----------------------------------------------------------------------
  547.  *
  548.  * TkpDisplayButton --
  549.  *
  550.  *    This procedure is invoked to display a button widget.  It is
  551.  *    normally invoked as an idle handler.
  552.  *
  553.  * Results:
  554.  *    None.
  555.  *
  556.  * Side effects:
  557.  *    Information appears on the screen.  The REDRAW_PENDING flag
  558.  *    is cleared.
  559.  *
  560.  *----------------------------------------------------------------------
  561.  */
  562.  
  563. void
  564. TkpDisplayButton(clientData)
  565.     ClientData clientData;    /* Information about widget. */
  566. {
  567.     TkOS2PSState state;
  568.     HPS hps;
  569.     register TkButton *butPtr = (TkButton *) clientData;
  570.     GC gc;
  571.     Tk_3DBorder border;
  572.     Pixmap pixmap;
  573.     int x = 0;            /* Initialization only needed to stop
  574.                  * compiler warning. */
  575.     int y, relief;
  576.     register Tk_Window tkwin = butPtr->tkwin;
  577.     int width, height;
  578.     int defaultWidth;        /* Width of default ring. */
  579.     int offset;            /* 0 means this is a label widget.  1 means
  580.                  * it is a flavor of button, so we offset
  581.                  * the text to make the button appear to
  582.                  * move up and down as the relief changes. */
  583.  
  584. #ifdef VERBOSE
  585.     printf("TkpDisplayButton type %x flags %x image %x bmp %x (%d,%d) %dx%d\n",
  586.            butPtr->type, butPtr->flags, butPtr->image, butPtr->bitmap,
  587.            Tk_X(tkwin), Tk_Y(tkwin), Tk_Width(tkwin), Tk_Height(tkwin));
  588. #endif
  589.  
  590.     butPtr->flags &= ~REDRAW_PENDING;
  591.     if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  592.     return;
  593.     }
  594.  
  595.     border = butPtr->normalBorder;
  596.     if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg != NULL)) {
  597.     gc = butPtr->disabledGC;
  598.     } else if ((butPtr->state == tkActiveUid)
  599.         && !Tk_StrictMotif(butPtr->tkwin)) {
  600.     gc = butPtr->activeTextGC;
  601.     border = butPtr->activeBorder;
  602.     } else {
  603.     gc = butPtr->normalTextGC;
  604.     }
  605.     if ((butPtr->flags & SELECTED) && (butPtr->state != tkActiveUid)
  606.         && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
  607.     border = butPtr->selectBorder;
  608.     }
  609.  
  610.     /*
  611.      * Override the relief specified for the button if this is a
  612.      * checkbutton or radiobutton and there's no indicator.
  613.      */
  614.  
  615.     relief = butPtr->relief;
  616.     if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) {
  617.     relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN
  618.         : TK_RELIEF_RAISED;
  619.     }
  620.  
  621.     /*
  622.      * Compute width of default ring and offset for pushed buttons.
  623.      */
  624.  
  625.     if (butPtr->type == TYPE_BUTTON) {
  626.     defaultWidth = ((butPtr->defaultState == tkActiveUid)
  627.         ? butPtr->highlightWidth : 0);
  628.     offset = 1;
  629.     } else {
  630.     defaultWidth = 0;
  631.     if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) {
  632.         offset = 1;
  633.     } else {
  634.         offset = 0;
  635.     }
  636.     }
  637.  
  638.     /*
  639.      * In order to avoid screen flashes, this procedure redraws
  640.      * the button in a pixmap, then copies the pixmap to the
  641.      * screen in a single operation.  This means that there's no
  642.      * point in time where the on-sreen image has been cleared.
  643.      */
  644.  
  645.     pixmap = Tk_GetPixmap(butPtr->display, Tk_WindowId(tkwin),
  646.         Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  647.     Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
  648.         Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
  649.  
  650.     /*
  651.      * Display image or bitmap or text for button.
  652.      */
  653.  
  654.     if (butPtr->image != None) {
  655.     Tk_SizeOfImage(butPtr->image, &width, &height);
  656.  
  657.     imageOrBitmap:
  658.     TkComputeAnchor(butPtr->anchor, tkwin, 0, 0,
  659.         butPtr->indicatorSpace + width, height, &x, &y);
  660.     x += butPtr->indicatorSpace;
  661.  
  662.     if (relief == TK_RELIEF_SUNKEN) {
  663.         x += offset;
  664.         y += offset;
  665.     }
  666.     if (butPtr->image != NULL) {
  667.         if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
  668.         Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height,
  669.             pixmap, x, y);
  670.         } else {
  671.         Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap,
  672.             x, y);
  673.         }
  674.     } else {
  675.         XSetClipOrigin(butPtr->display, gc, x, y);
  676.         XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
  677.             (unsigned int) width, (unsigned int) height, x, y, 1);
  678.         XSetClipOrigin(butPtr->display, gc, 0, 0);
  679.     }
  680.     y += height/2;
  681.     } else if (butPtr->bitmap != None) {
  682.     Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
  683.     goto imageOrBitmap;
  684.     } else {
  685.     LONG xCursor, yCursor, cxCursor, cyCursor;
  686.     CHARBUNDLE cBundle;
  687.         AREABUNDLE aBundle;
  688.         LONG oldColor, oldBackColor;
  689.  
  690.     TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
  691.         butPtr->indicatorSpace + butPtr->textWidth, butPtr->textHeight,
  692.         &x, &y);
  693.  
  694.     x += butPtr->indicatorSpace;
  695.  
  696.     if (relief == TK_RELIEF_SUNKEN) {
  697.         x += offset;
  698.         y += offset;
  699.     }
  700.     Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout,
  701.         x, y, 0, -1);
  702.     Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
  703.         butPtr->textLayout, x, y, butPtr->underline);
  704.  
  705.     /*
  706.      * Draw the focus ring.  If this is a push button then we need to put
  707.      * it around the inner edge of the border, otherwise we put it around
  708.      * the text.
  709.      */
  710.  
  711.     if (butPtr->flags & GOT_FOCUS && butPtr->type != TYPE_LABEL) {
  712.         hps = TkOS2GetDrawablePS(butPtr->display, pixmap, &state);
  713.         if (butPtr->type == TYPE_BUTTON || !butPtr->indicatorOn) {
  714.                 yCursor = butPtr->borderWidth + 1 + defaultWidth;
  715.                 xCursor = yCursor;
  716.                 cxCursor = Tk_Width(tkwin) - xCursor - 2;
  717.                 cyCursor = Tk_Height(tkwin) - yCursor - 2;
  718.         } else {
  719.                 yCursor = y-2;
  720.                 xCursor = x-2;
  721.                 cxCursor = butPtr->textWidth + 4;
  722.                 cyCursor = butPtr->textHeight + 4;
  723.         }
  724.         GpiQueryAttrs(hps, PRIM_CHAR, LBB_COLOR, (PBUNDLE)&cBundle);
  725.         oldColor = cBundle.lColor;
  726.             cBundle.lColor = gc->foreground;
  727.             rc = GpiSetAttrs(hps, PRIM_CHAR, LBB_COLOR, 0L, (PBUNDLE)&cBundle);
  728. #ifdef VERBOSE
  729.             if (rc!=TRUE) {
  730.                 printf("GpiSetAttrs textColor %d ERROR %x\n", cBundle.lColor,
  731.                        WinGetLastError(TclOS2GetHAB()));
  732.             } else {
  733.                 printf("GpiSetAttrs textColor %d OK\n", cBundle.lColor);
  734.             }
  735. #endif
  736.         GpiQueryAttrs(hps, PRIM_AREA, LBB_BACK_COLOR, (PBUNDLE)&aBundle);
  737.             oldBackColor = aBundle.lBackColor;
  738.             aBundle.lBackColor = gc->background;
  739.             rc = GpiSetAttrs(hps, PRIM_AREA, LBB_BACK_COLOR, 0L, 
  740.                              (PBUNDLE)&aBundle);
  741. #ifdef VERBOSE
  742.             if (rc!=TRUE) {
  743.                 printf("GpiSetAttrs areaColor %d ERROR %x\n", aBundle.lColor,
  744.                        WinGetLastError(TclOS2GetHAB()));
  745.             } else {
  746.                 printf("GpiSetAttrs areaColor %d OK\n", aBundle.lColor);
  747.             }
  748. #endif
  749.             rc = WinCreateCursor(((OS2Button *)butPtr)->hwnd, xCursor,
  750.                         yCursor, cxCursor, cyCursor,
  751.                         CURSOR_HALFTONE | CURSOR_FRAME, NULL);
  752. #ifdef VERBOSE
  753. {
  754. SWP pos;
  755. WinQueryWindowPos(((OS2Button *)butPtr)->hwnd, &pos);
  756.             if (rc!=TRUE) {
  757.       printf("WinCreateCursor (%d,%d) %dx%d hwnd %x ((%d,%d) %dx%d) ERROR %x\n",
  758.                xCursor, yCursor, cxCursor, cyCursor,
  759.                        ((OS2Button *)butPtr)->hwnd,
  760.                        pos.x, pos.y, pos.cx, pos.cy,
  761.                        WinGetLastError(TclOS2GetHAB()));
  762.             } else {
  763.       printf("WinCreateCursor (%d,%d) %dx%d hwnd %x ((%d,%d) %dx%d) OK\n",
  764.                xCursor, yCursor, cxCursor, cyCursor,
  765.                ((OS2Button *)butPtr)->hwnd,
  766.                        pos.x, pos.y, pos.cx, pos.cy);
  767.             }
  768. }
  769. #endif
  770.             rc = WinShowCursor(((OS2Button *)butPtr)->hwnd, TRUE);
  771. #ifdef VERBOSE
  772.             if (rc!=TRUE) {
  773.                 printf("WinShowCursor hwnd %x ERROR %x\n",
  774.                ((OS2Button *)butPtr)->hwnd,
  775.                        WinGetLastError(TclOS2GetHAB()));
  776.             } else {
  777.                 printf("WinShowCursor hwnd %x OK\n",
  778.                ((OS2Button *)butPtr)->hwnd);
  779.             }
  780. #endif
  781.             cBundle.lColor = oldColor;
  782.             rc = GpiSetAttrs(hps, PRIM_CHAR, LBB_COLOR, 0L, (PBUNDLE)&cBundle);
  783.             aBundle.lBackColor = oldBackColor;
  784.             rc = GpiSetAttrs(hps, PRIM_AREA, LBB_BACK_COLOR, 0L, 
  785.                              (PBUNDLE)&aBundle);
  786.         TkOS2ReleaseDrawablePS(pixmap, hps, &state);
  787.     }
  788.     y += butPtr->textHeight/2;
  789.     }
  790.  
  791.     /*
  792.      * Draw the indicator for check buttons and radio buttons.  At this
  793.      * point x and y refer to the top-left corner of the text or image
  794.      * or bitmap.
  795.      */
  796.  
  797.     if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn
  798.         && hBoxes) {
  799.     int xSrc, ySrc;
  800.     POINTL points[4];
  801. #ifdef VERBOSE
  802.         int i;
  803. #endif
  804.  
  805.     x -= butPtr->indicatorSpace;
  806.     y -= butPtr->indicatorDiameter / 2;
  807.  
  808.     xSrc = (butPtr->flags & SELECTED) ? boxWidth : 0;
  809.     if (butPtr->state == tkActiveUid) {
  810.         xSrc += boxWidth*2;
  811.     }
  812.     ySrc = (butPtr->type == TYPE_RADIO_BUTTON) ? 0 : boxHeight;
  813.         
  814.     /*
  815.      * Update the palette in the boxes bitmap to reflect the current
  816.      * button colors.  Note that this code relies on the layout of the
  817.      * bitmap's palette.  Also, all of the colors used to draw the
  818.      * bitmap must be in the palette that is selected into the DC of
  819.      * the offscreen pixmap.  This requires that the static colors
  820.      * be placed into the palette.
  821.      */
  822.  
  823.  
  824.     palTable[PAL_CHECK] =  gc->foreground;
  825.     palTable[PAL_TOP_OUTER] = TkOS2GetBorderPixels(tkwin, border,
  826.                                                        TK_3D_DARK_GC);
  827.     palTable[PAL_TOP_INNER] = TkOS2GetBorderPixels(tkwin, border,
  828.                                                        TK_3D_DARK2);
  829.     palTable[PAL_BOTTOM_INNER] = TkOS2GetBorderPixels(tkwin, border,
  830.                                                           TK_3D_LIGHT2);
  831.     palTable[PAL_BOTTOM_OUTER] = TkOS2GetBorderPixels(tkwin, border,
  832.                                                           TK_3D_LIGHT_GC);
  833.  
  834.     if (butPtr->state == tkDisabledUid) {
  835.         palTable[PAL_INTERIOR] = TkOS2GetBorderPixels(tkwin, border,
  836.                                                           TK_3D_LIGHT2);
  837.     } else if (butPtr->selectBorder != NULL) {
  838.         palTable[PAL_INTERIOR] = TkOS2GetBorderPixels(tkwin, border,
  839.                                                           TK_3D_FLAT_GC);
  840.     } else {
  841.             palTable[PAL_INTERIOR] = WinQuerySysColor(HWND_DESKTOP,
  842.                                                       SYSCLR_WINDOW, 0L);
  843.     }
  844.     palTable[PAL_BACKGROUND] = TkOS2GetBorderPixels(tkwin, border,
  845.                                                         TK_3D_FLAT_GC);
  846. #ifdef VERBOSE
  847.         printf("colors C %x fg %x TO %x TI %x BI %x BO %x I %x B %x\n",
  848.                palTable[PAL_CHECK], gc->foreground, palTable[PAL_TOP_OUTER],
  849.                palTable[PAL_TOP_INNER], palTable[PAL_BOTTOM_INNER],
  850.                palTable[PAL_BOTTOM_OUTER], palTable[PAL_INTERIOR],
  851.                palTable[PAL_BACKGROUND]);
  852. #endif
  853.  
  854.         rc = GpiSetPaletteEntries(boxesPalette, LCOLF_CONSECRGB, 0L, 16L,
  855.                                   palTable);
  856. #ifdef VERBOSE
  857.         if (boxesPalette == GPI_ERROR) {
  858.             printf("    GpiSetPaletteEntries ERROR %x\n",
  859.                    WinGetLastError(TclOS2GetHAB()));
  860.         } else {
  861.             printf("    GpiSetPaletteEntries OK\n");
  862.         }
  863.         for (i= 0; i<16; i++) {
  864.             printf("palTable[%d] [%x]\n", i, palTable[i]);
  865.         }
  866. #endif
  867.  
  868.         /* Rewrite boxes bitmap with this palette info */
  869. boxesPtr->cbFix = sizeof(BITMAPINFOHEADER2);
  870.         rc = GpiSetBitmapBits(boxesPS, 0, boxesPtr->cy, boxesBits, boxesPtr);
  871. #ifdef VERBOSE
  872.         if (rc == GPI_ALTERROR) {
  873.         printf("GpiSetBitmapBits %x for %d lines ERROR %x\n", boxesPS,
  874.                    boxesPtr->cy, WinGetLastError(TclOS2GetHAB()));
  875.     } else {
  876.         printf("GpiSetBitmapBits OK set %d scanlines\n", rc);
  877.     }
  878. printf("boxesPtr->cx %d, boxesPtr->cy %d\n", boxesPtr->cx, boxesPtr->cy);
  879. #endif
  880. /*
  881. */
  882.  
  883.     hps = TkOS2GetDrawablePS(butPtr->display, pixmap, &state);
  884.  
  885.     /* Target, bottom left */
  886.     points[0].x = x;
  887.     points[0].y = y;
  888.     /* Target, top right */
  889.     points[1].x = x + boxWidth;
  890.     points[1].y = y + boxHeight;
  891.     /* Source, bottom left */
  892.     points[2].x = xSrc;
  893.     points[2].y = ySrc;
  894.     /* Source, top right */
  895.     points[3].x = xSrc + boxWidth;
  896.     points[3].y = ySrc + boxHeight;
  897.  
  898. /*
  899.     rc = GpiWCBitBlt(hps, hBoxes, 4, points, ROP_SRCCOPY, BBO_IGNORE);
  900. */
  901.     rc = GpiBitBlt(hps, boxesPS, 4, points, ROP_SRCCOPY, BBO_IGNORE);
  902. #ifdef VERBOSE
  903.         if (rc == GPI_ERROR) {
  904.         printf("GpiWCBitBlt (%d,%d)-(%d,%d) <= (%d,%d)-(%d,%d) ERROR %x\n",
  905.                points[0].x, points[0].y, points[1].x, points[1].y,
  906.                points[2].x, points[2].y, points[3].x, points[3].y,
  907.            WinGetLastError(TclOS2GetHAB()));
  908.     } else {
  909.         printf("GpiWCBitBlt (%d,%d)-(%d,%d) <= (%d,%d)-(%d,%d) OK/HIT %x\n",
  910.                points[0].x, points[0].y, points[1].x, points[1].y,
  911.                points[2].x, points[2].y, points[3].x, points[3].y,
  912.            rc);
  913.     }
  914. #endif
  915. /*
  916. */
  917.     TkOS2ReleaseDrawablePS(pixmap, hps, &state);
  918.     }
  919.  
  920.     /*
  921.      * If the button is disabled with a stipple rather than a special
  922.      * foreground color, generate the stippled effect.  If the widget
  923.      * is selected and we use a different background color when selected,
  924.      * must temporarily modify the GC.
  925.      */
  926.  
  927.     if ((butPtr->state == tkDisabledUid)
  928.         && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
  929.     if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
  930.         && (butPtr->selectBorder != NULL)) {
  931.         XSetForeground(butPtr->display, butPtr->disabledGC,
  932.             Tk_3DBorderColor(butPtr->selectBorder)->pixel);
  933.     }
  934.     XFillRectangle(butPtr->display, pixmap, butPtr->disabledGC,
  935.         butPtr->inset, butPtr->inset,
  936.         (unsigned) (Tk_Width(tkwin) - 2*butPtr->inset),
  937.         (unsigned) (Tk_Height(tkwin) - 2*butPtr->inset));
  938.     if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
  939.         && (butPtr->selectBorder != NULL)) {
  940.         XSetForeground(butPtr->display, butPtr->disabledGC,
  941.             Tk_3DBorderColor(butPtr->normalBorder)->pixel);
  942.     }
  943.     }
  944.  
  945.     /*
  946.      * Draw the border and traversal highlight last.  This way, if the
  947.      * button's contents overflow they'll be covered up by the border.
  948.      */
  949.  
  950.     if (relief != TK_RELIEF_FLAT) {
  951.     Tk_Draw3DRectangle(tkwin, pixmap, border,
  952.         defaultWidth, defaultWidth,
  953.         Tk_Width(tkwin) - 2*defaultWidth,
  954.         Tk_Height(tkwin) - 2*defaultWidth,
  955.         butPtr->borderWidth, relief);
  956.     }
  957.     if (defaultWidth != 0) {
  958.         LONG windowHeight = TkOS2WindowHeight((TkOS2Drawable *)pixmap);
  959. #ifdef VERBOSE
  960.         printf("TkpDisplayButton: wh %d (%d,%d),(%d,%d),(%d,%d),(%d,%d)\n",
  961.                windowHeight, 0, 0, 0, 0, 0, Tk_Height(tkwin) - defaultWidth,
  962.                Tk_Width(tkwin) - defaultWidth, 0);
  963. #endif
  964.     hps = TkOS2GetDrawablePS(butPtr->display, pixmap, &state);
  965.     TkOS2FillRect(hps, 0, windowHeight - defaultWidth,
  966.                       Tk_Width(tkwin), defaultWidth,
  967.               butPtr->highlightColorPtr->pixel);
  968.     TkOS2FillRect(hps, 0, windowHeight - Tk_Height(tkwin),
  969.                       defaultWidth, Tk_Height(tkwin),
  970.               butPtr->highlightColorPtr->pixel);
  971.     TkOS2FillRect(hps, 0, windowHeight - Tk_Height(tkwin) - defaultWidth,
  972.               Tk_Width(tkwin), defaultWidth,
  973.               butPtr->highlightColorPtr->pixel);
  974.     TkOS2FillRect(hps, Tk_Width(tkwin) - defaultWidth,
  975.                       windowHeight - Tk_Height(tkwin), defaultWidth,
  976.                       Tk_Height(tkwin), butPtr->highlightColorPtr->pixel);
  977.     TkOS2ReleaseDrawablePS(pixmap, hps, &state);
  978.     }
  979.  
  980.     /*
  981.      * Copy the information from the off-screen pixmap onto the screen,
  982.      * then delete the pixmap.
  983.      */
  984.  
  985.     XCopyArea(butPtr->display, pixmap, Tk_WindowId(tkwin),
  986.         butPtr->copyGC, 0, 0, (unsigned) Tk_Width(tkwin),
  987.         (unsigned) Tk_Height(tkwin), 0, 0);
  988. WinDestroyCursor(((OS2Button *)butPtr)->hwnd);
  989.     Tk_FreePixmap(butPtr->display, pixmap);
  990. }
  991.  
  992. /*
  993.  *----------------------------------------------------------------------
  994.  *
  995.  * TkpComputeButtonGeometry --
  996.  *
  997.  *    After changes in a button's text or bitmap, this procedure
  998.  *    recomputes the button's geometry and passes this information
  999.  *    along to the geometry manager for the window.
  1000.  *
  1001.  * Results:
  1002.  *    None.
  1003.  *
  1004.  * Side effects:
  1005.  *    The button's window may change size.
  1006.  *
  1007.  *----------------------------------------------------------------------
  1008.  */
  1009.  
  1010. void
  1011. TkpComputeButtonGeometry(butPtr)
  1012.     register TkButton *butPtr;    /* Button whose geometry may have changed. */
  1013. {
  1014.     int width, height, avgWidth;
  1015.     Tk_FontMetrics fm;
  1016.  
  1017.     if (butPtr->highlightWidth < 0) {
  1018.     butPtr->highlightWidth = 0;
  1019.     }
  1020.     butPtr->inset = butPtr->highlightWidth + butPtr->borderWidth;
  1021.     butPtr->indicatorSpace = 0;
  1022.  
  1023.     if (!hBoxes) {
  1024.     InitBoxes();
  1025.     }
  1026.  
  1027.     if (butPtr->image != NULL) {
  1028.     Tk_SizeOfImage(butPtr->image, &width, &height);
  1029.     imageOrBitmap:
  1030.     if (butPtr->width > 0) {
  1031.         width = butPtr->width;
  1032.     }
  1033.     if (butPtr->height > 0) {
  1034.         height = butPtr->height;
  1035.     }
  1036.     if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
  1037.         butPtr->indicatorSpace = boxWidth * 2;
  1038.         butPtr->indicatorDiameter = boxHeight;
  1039.     }
  1040.     } else if (butPtr->bitmap != None) {
  1041.     Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
  1042.     goto imageOrBitmap;
  1043.     } else {
  1044.     Tk_FreeTextLayout(butPtr->textLayout);
  1045.     butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
  1046.         butPtr->text, -1, butPtr->wrapLength, butPtr->justify, 0,
  1047.         &butPtr->textWidth, &butPtr->textHeight);
  1048.  
  1049.     width = butPtr->textWidth;
  1050.     height = butPtr->textHeight;
  1051.     avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
  1052.     Tk_GetFontMetrics(butPtr->tkfont, &fm);
  1053.  
  1054.     if (butPtr->width > 0) {
  1055.         width = butPtr->width * avgWidth;
  1056.     }
  1057.     if (butPtr->height > 0) {
  1058.         height = butPtr->height * fm.linespace;
  1059.     }
  1060.  
  1061.     if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
  1062.         butPtr->indicatorDiameter = boxHeight;
  1063.         butPtr->indicatorSpace = butPtr->indicatorDiameter + avgWidth;
  1064.     }
  1065.  
  1066.     /*
  1067.      * Increase the inset to allow for the focus ring.
  1068.      */
  1069.  
  1070.     if (butPtr->type != TYPE_LABEL) {
  1071.         butPtr->inset += 3;
  1072.     }
  1073.     }
  1074.  
  1075.     /*
  1076.      * When issuing the geometry request, add extra space for the indicator,
  1077.      * if any, and for the border and padding, plus an extra pixel so the
  1078.      * display can be offset by 1 pixel in either direction for the raised
  1079.      * or lowered effect.
  1080.      */
  1081.  
  1082.     if ((butPtr->image == NULL) && (butPtr->bitmap == None)) {
  1083.     width += 2*butPtr->padX;
  1084.     height += 2*butPtr->padY;
  1085.     }
  1086.     if ((butPtr->type == TYPE_BUTTON)
  1087.         || ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn)) {
  1088.     width += 1;
  1089.     height += 1;
  1090.     }
  1091.     Tk_GeometryRequest(butPtr->tkwin, (int) (width + butPtr->indicatorSpace
  1092.         + 2*butPtr->inset), (int) (height + 2*butPtr->inset));
  1093.     Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
  1094. }
  1095.  
  1096. /*
  1097.  *----------------------------------------------------------------------
  1098.  *
  1099.  * ButtonProc --
  1100.  *
  1101.  *    This function is called by OS/2 PM whenever an event occurs on
  1102.  *    a button control created by Tk.
  1103.  *
  1104.  * Results:
  1105.  *    Standard OS/2 PM return value.
  1106.  *
  1107.  * Side effects:
  1108.  *    May generate events.
  1109.  *
  1110.  *----------------------------------------------------------------------
  1111.  */
  1112.  
  1113. static MRESULT EXPENTRY
  1114. ButtonProc(hwnd, message, param1, param2)
  1115.     HWND hwnd;
  1116.     ULONG message;
  1117.     MPARAM param1;
  1118.     MPARAM param2;
  1119. {
  1120.     MRESULT result;
  1121.     OS2Button *butPtr;
  1122.     Tk_Window tkwin = Tk_HWNDToWindow(hwnd);
  1123.  
  1124. #ifdef VERBOSE
  1125.     printf("ButtonProc hwnd %x (tkwin %x), msg %x, p1 %x, p2 %x\n", hwnd, tkwin,
  1126.            message, param1, param2);
  1127.     switch (message) {
  1128.         case BM_QUERYCHECK: printf("Btn: BM_QUERYCHECK\n"); break;
  1129.         case BM_QUERYHILITE: printf("Btn: BM_QUERYHILITE\n"); break;
  1130.         case WM_ACTIVATE: printf("Btn: WM_ACTIVATE\n"); break;
  1131.         case WM_ADJUSTFRAMEPOS: printf("Btn: WM_ADJUSTFRAMEPOS\n"); break;
  1132.         case WM_ADJUSTWINDOWPOS: printf("Btn: WM_ADJUSTWINDOWPOS\n"); break;
  1133.         case WM_BUTTON1DOWN: printf("Btn: WM_BUTTON1DOWN\n"); break;
  1134.         case WM_BUTTON1UP: printf("Btn: WM_BUTTON1UP\n"); break;
  1135.         case WM_BUTTON1DBLCLK: printf("Btn: WM_BUTTON1DBLCLK\n"); break;
  1136.         case WM_BUTTON2DOWN: printf("Btn: WM_BUTTON2DOWN\n"); break;
  1137.         case WM_BUTTON2UP: printf("Btn: WM_BUTTON2UP\n"); break;
  1138.         case WM_BUTTON2DBLCLK: printf("Btn: WM_BUTTON2DBLCLK\n"); break;
  1139.         case WM_BUTTON3DOWN: printf("Btn: WM_BUTTON3DOWN\n"); break;
  1140.         case WM_BUTTON3UP: printf("Btn: WM_BUTTON3UP\n"); break;
  1141.         case WM_BUTTON3DBLCLK: printf("Btn: WM_BUTTON3DBLCLK\n"); break;
  1142.         case WM_CALCFRAMERECT: printf("Btn: WM_CALCFRAMERECT\n"); break;
  1143.         case WM_CALCVALIDRECTS: printf("Btn: WM_CALCVALIDRECTS\n"); break;
  1144.         case WM_CLOSE: printf("Btn: WM_CLOSE\n"); break;
  1145.         case WM_COMMAND: printf("Btn: WM_COMMAND\n"); break;
  1146.         case WM_CREATE: printf("Btn: WM_CREATE\n"); break;
  1147.         case WM_ERASEBACKGROUND: printf("Btn: WM_ERASEBACKGROUND\n"); break;
  1148.         case WM_FOCUSCHANGE: printf("Btn: WM_FOCUSCHANGE\n"); break;
  1149.         case WM_FORMATFRAME: printf("Btn: WM_FORMATFRAME\n"); break;
  1150.         case WM_MINMAXFRAME: printf("Btn: WM_MINMAXFRAME\n"); break;
  1151.         case WM_MOUSEMOVE: printf("Btn: WM_MOUSEMOVE\n"); break;
  1152.         case WM_MOVE: printf("Btn: WM_MOVE\n"); break;
  1153.         case WM_OWNERPOSCHANGE: printf("Btn: WM_OWNERPOSCHANGE\n"); break;
  1154.         case WM_PAINT: printf("Btn: WM_PAINT\n"); break;
  1155.         case WM_QUERYBORDERSIZE: printf("Btn: WM_QUERYBORDERSIZE\n"); break;
  1156.         case WM_QUERYDLGCODE: printf("Btn: WM_QUERYDLGCODE\n"); break;
  1157.         case WM_QUERYFRAMECTLCOUNT: printf("Btn: WM_QUERYFRAMECTLCOUNT\n"); break;
  1158.         case WM_QUERYFOCUSCHAIN: printf("Btn: WM_QUERYFOCUSCHAIN\n"); break;
  1159.         case WM_QUERYICON: printf("Btn: WM_QUERYICON\n"); break;
  1160.         case WM_QUERYTRACKINFO: printf("Btn: WM_QUERYTRACKINFO\n"); break;
  1161.         case WM_REALIZEPALETTE: printf("Btn: WM_REALIZEPALETTE\n"); break;
  1162.         case WM_SETFOCUS: printf("Btn: WM_SETFOCUS\n"); break;
  1163.         case WM_SETSELECTION: printf("Btn: WM_SETSELECTION\n"); break;
  1164.         case WM_UPDATEFRAME: printf("Btn: WM_UPDATEFRAME\n"); break;
  1165.         case WM_WINDOWPOSCHANGED: printf("Btn: WM_WINDOWPOSCHANGED\n"); break;
  1166.     }
  1167. #endif
  1168.  
  1169.     /* tkwin can be NULL for WM_DESTROY due to the order of messages */
  1170.     if (message == WM_DESTROY) {
  1171. #ifdef VERBOSE
  1172.         printf("ButtonProc: WM_DESTROY\n");
  1173. #endif
  1174.         return WinDefWindowProc(hwnd, message, param1, param2);
  1175.     }
  1176.     if (tkwin == NULL) {
  1177. #ifdef VERBOSE
  1178.         printf("panicking...\n");
  1179.     fflush(stdout);
  1180. #endif
  1181.     panic("ButtonProc called on an invalid HWND");
  1182.     }
  1183.     butPtr = (OS2Button *)((TkWindow*)tkwin)->instanceData;
  1184.  
  1185.     switch(message) {
  1186.  
  1187.         case WM_COMMAND: {
  1188.         USHORT usCmd, usSource, usPointer;
  1189.         usCmd = SHORT1FROMMP(param1);
  1190.         usSource = SHORT1FROMMP(param2);
  1191.         usPointer = SHORT2FROMMP(param2);
  1192. #ifdef VERBOSE
  1193.             printf("    WM_COMMAND usCmd 0x%x, usSource 0x%x, usPointer 0x%x\n",
  1194.                    usCmd, usSource, usPointer);
  1195. #endif
  1196.             break;
  1197.         }
  1198.  
  1199.         case WM_CONTROL: {
  1200.         USHORT id, usNotify;
  1201.         id = SHORT1FROMMP(param1);
  1202.         usNotify = SHORT2FROMMP(param1);
  1203. #ifdef VERBOSE
  1204.             printf("    WM_CONTROL id 0x%x usNotify 0x%x\n", id, usNotify);
  1205. #endif
  1206.             switch (usNotify) {
  1207.                 /* BN_PAINT -> redraw button */
  1208.             case BN_PAINT: {
  1209. #ifdef VERBOSE
  1210.             PUSERBUTTON ubPtr = (PUSERBUTTON) LONGFROMMP(param2);
  1211.                     printf("    BN_PAINT, hwnd %x, hps %x, state %x, old %x\n",
  1212.                            ubPtr->hwnd, ubPtr->hps, ubPtr->fsState,
  1213.                            ubPtr->fsStateOld);
  1214. #endif
  1215.                 TkpDisplayButton((ClientData)butPtr);
  1216.                 return 0;
  1217.             }
  1218.  
  1219.             case BN_CLICKED: {
  1220.                 int code;
  1221.                 Tcl_Interp *interp = butPtr->info.interp;
  1222. #ifdef VERBOSE
  1223.                     printf("    BN_CLICKED\n");
  1224. #endif
  1225.                 if (butPtr->info.state != tkDisabledUid) {
  1226.                 Tcl_Preserve((ClientData)interp);
  1227.                 code = TkInvokeButton((TkButton*)butPtr);
  1228.                 if (code != TCL_OK && code != TCL_CONTINUE
  1229.                     && code != TCL_BREAK) {
  1230.                     Tcl_AddErrorInfo(interp, "\n    (button invoke)");
  1231.                     Tcl_BackgroundError(interp);
  1232.                 }
  1233.                 Tcl_Release((ClientData)interp);
  1234.                 }
  1235.                 Tcl_ServiceAll();
  1236.                 return 0;
  1237.             }
  1238.  
  1239.             case BN_DBLCLICKED: {
  1240. #ifdef VERBOSE
  1241.                     printf("    BN_DBLCLICKED\n");
  1242. #endif
  1243.                 if (Tk_TranslateOS2Event(hwnd, message, param1, param2,
  1244.                                      &result)) {
  1245.                 return result;
  1246.                 }
  1247.             }
  1248.         }
  1249.     }
  1250.  
  1251.     case WM_ERASEBACKGROUND:
  1252.         /*
  1253.          * Return FALSE if the application processes the message.
  1254.          * If TRUE is returned the client area is filled with the
  1255.          * window background color.
  1256.          */
  1257.         return 0;
  1258.  
  1259.     case BM_QUERYHILITE: {
  1260.         BOOL hasFocus = FALSE;
  1261.         if (butPtr->info.flags & GOT_FOCUS) {
  1262.         hasFocus = BST_FOCUS;
  1263.         }
  1264.         return (MRESULT)hasFocus;
  1265.     }
  1266.      
  1267.     case BM_QUERYCHECK: {
  1268.         ULONG state = BST_INDETERMINATE;
  1269.         if (((butPtr->info.type == TYPE_CHECK_BUTTON)
  1270.             || (butPtr->info.type == TYPE_RADIO_BUTTON))
  1271.             && butPtr->info.indicatorOn) {
  1272.         state = (butPtr->info.flags & SELECTED)
  1273.             ? BST_CHECKED : BST_UNCHECKED;
  1274.         }
  1275.         return (MRESULT)state;
  1276.     }
  1277.      
  1278.     case WM_ENABLE:
  1279.         break;
  1280.  
  1281.         case WM_FOCUSCHANGE:
  1282.             if (SHORT1FROMMP(param2) != TRUE) {
  1283.                 WinDestroyCursor(hwnd);
  1284. #ifdef VERBOSE
  1285.                 printf("BtnProc: WM_FOCUSCHANGE FALSE hwnd %x\n", hwnd);
  1286. #endif
  1287.             }
  1288.             break;
  1289. /*
  1290. */
  1291.  
  1292.     case WM_PAINT: {
  1293.         HPS hps;
  1294. #ifdef VERBOSE
  1295.             RECTL rectl;
  1296. #endif
  1297.  
  1298.         hps = WinBeginPaint(hwnd, NULLHANDLE, NULL);
  1299. #ifdef VERBOSE
  1300.             printf("BtnProc: WM_PAINT\n");
  1301. WinFillRect(hps, &rectl, CLR_BLUE);
  1302. #endif
  1303.         WinEndPaint(hps);
  1304.         TkpDisplayButton((ClientData)butPtr);
  1305.         return 0;
  1306.     }
  1307.  
  1308.     default:
  1309.         if (Tk_TranslateOS2Event(hwnd, message, param1, param2, &result)) {
  1310.         return result;
  1311.         }
  1312.     }
  1313.     return butPtr->oldProc(hwnd, message, param1, param2);
  1314. }
  1315.