tkUnixButton.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:22k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkUnixButton.c --
  3.  *
  4.  * This file implements the Unix specific portion of the button
  5.  * widgets.
  6.  *
  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.  * RCS: @(#) $Id: tkUnixButton.c,v 1.11.2.5 2004/12/02 02:07:43 hobbs Exp $
  13.  */
  14. #include "tkButton.h"
  15. /*
  16.  * Declaration of Unix specific button structure.
  17.  */
  18. typedef struct UnixButton {
  19.     TkButton info; /* Generic button info. */
  20. } UnixButton;
  21. /*
  22.  * The class procedure table for the button widgets.
  23.  */
  24. Tk_ClassProcs tkpButtonProcs = {
  25.     sizeof(Tk_ClassProcs), /* size */
  26.     TkButtonWorldChanged, /* worldChangedProc */
  27. };
  28. /*
  29.  *----------------------------------------------------------------------
  30.  *
  31.  * TkpCreateButton --
  32.  *
  33.  * Allocate a new TkButton structure.
  34.  *
  35.  * Results:
  36.  * Returns a newly allocated TkButton structure.
  37.  *
  38.  * Side effects:
  39.  * Registers an event handler for the widget.
  40.  *
  41.  *----------------------------------------------------------------------
  42.  */
  43. TkButton *
  44. TkpCreateButton(tkwin)
  45.     Tk_Window tkwin;
  46. {
  47.     UnixButton *butPtr = (UnixButton *)ckalloc(sizeof(UnixButton));
  48.     return (TkButton *) butPtr;
  49. }
  50. /*
  51.  *----------------------------------------------------------------------
  52.  *
  53.  * TkpDisplayButton --
  54.  *
  55.  * This procedure is invoked to display a button widget.  It is
  56.  * normally invoked as an idle handler.
  57.  *
  58.  * Results:
  59.  * None.
  60.  *
  61.  * Side effects:
  62.  * Commands are output to X to display the button in its
  63.  * current mode.  The REDRAW_PENDING flag is cleared.
  64.  *
  65.  *----------------------------------------------------------------------
  66.  */
  67. void
  68. TkpDisplayButton(clientData)
  69.     ClientData clientData; /* Information about widget. */
  70. {
  71.     register TkButton *butPtr = (TkButton *) clientData;
  72.     GC gc;
  73.     Tk_3DBorder border;
  74.     Pixmap pixmap;
  75.     int x = 0; /* Initialization only needed to stop
  76.  * compiler warning. */
  77.     int y, relief;
  78.     Tk_Window tkwin = butPtr->tkwin;
  79.     int width, height, fullWidth, fullHeight;
  80.     int textXOffset, textYOffset;
  81.     int haveImage = 0, haveText = 0;
  82.     int offset; /* 1 means this is a button widget, so we
  83.  * offset the text to make the button appear
  84.  * to move up and down as the relief changes.
  85.  */
  86.     int imageWidth, imageHeight;
  87.     int imageXOffset = 0, imageYOffset = 0; /* image information that will
  88.      * be used to restrict disabled
  89.      * pixmap as well */
  90.     butPtr->flags &= ~REDRAW_PENDING;
  91.     if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  92. return;
  93.     }
  94.     border = butPtr->normalBorder;
  95.     if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
  96. gc = butPtr->disabledGC;
  97.     } else if ((butPtr->state == STATE_ACTIVE)
  98.     && !Tk_StrictMotif(butPtr->tkwin)) {
  99. gc = butPtr->activeTextGC;
  100. border = butPtr->activeBorder;
  101.     } else {
  102. gc = butPtr->normalTextGC;
  103.     }
  104.     if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE)
  105.     && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
  106. border = butPtr->selectBorder;
  107.     }
  108.     /*
  109.      * Override the relief specified for the button if this is a
  110.      * checkbutton or radiobutton and there's no indicator.  The new
  111.      * relief is as follows:
  112.      *      If the button is select  --> "sunken"
  113.      *      If relief==overrelief    --> relief
  114.      *      Otherwise                --> overrelief
  115.      *
  116.      * The effect we are trying to achieve is as follows:
  117.      *
  118.      *      value    mouse-over?   -->   relief
  119.      *     -------  ------------        --------
  120.      *       off        no               flat
  121.      *       off        yes              raised
  122.      *       on         no               sunken
  123.      *       on         yes              sunken
  124.      *
  125.      * This is accomplished by configuring the checkbutton or radiobutton
  126.      * like this:
  127.      *
  128.      *     -indicatoron 0 -overrelief raised -offrelief flat
  129.      *
  130.      * Bindings (see library/button.tcl) will copy the -overrelief into
  131.      * -relief on mouseover.  Hence, we can tell if we are in mouse-over by
  132.      * comparing relief against overRelief.  This is an aweful kludge, but
  133.      * it gives use the desired behavior while keeping the code backwards
  134.      * compatible.
  135.      */
  136.     relief = butPtr->relief;
  137.     if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) {
  138. if (butPtr->flags & SELECTED) {
  139.     relief = TK_RELIEF_SUNKEN;
  140. } else if (butPtr->overRelief != relief) {
  141.     relief = butPtr->offRelief;
  142. }
  143.     }
  144.     offset = (butPtr->type == TYPE_BUTTON) && !Tk_StrictMotif(butPtr->tkwin);
  145.     /*
  146.      * In order to avoid screen flashes, this procedure redraws
  147.      * the button in a pixmap, then copies the pixmap to the
  148.      * screen in a single operation.  This means that there's no
  149.      * point in time where the on-sreen image has been cleared.
  150.      */
  151.     pixmap = Tk_GetPixmap(butPtr->display, Tk_WindowId(tkwin),
  152.     Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  153.     Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
  154.     Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
  155.     /*
  156.      * Display image or bitmap or text for button.
  157.      */
  158.     if (butPtr->image != NULL) {
  159. Tk_SizeOfImage(butPtr->image, &width, &height);
  160. haveImage = 1;
  161.     } else if (butPtr->bitmap != None) {
  162. Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
  163. haveImage = 1;
  164.     }
  165.     imageWidth  = width;
  166.     imageHeight = height;
  167.     haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
  168.     
  169.     if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
  170. textXOffset = 0;
  171. textYOffset = 0;
  172. fullWidth = 0;
  173. fullHeight = 0;
  174. switch ((enum compound) butPtr->compound) {
  175.     case COMPOUND_TOP: 
  176.     case COMPOUND_BOTTOM: {
  177. /* Image is above or below text */
  178. if (butPtr->compound == COMPOUND_TOP) {
  179.     textYOffset = height + butPtr->padY;
  180. } else {
  181.     imageYOffset = butPtr->textHeight + butPtr->padY;
  182. }
  183. fullHeight = height + butPtr->textHeight + butPtr->padY;
  184. fullWidth = (width > butPtr->textWidth ? width :
  185. butPtr->textWidth);
  186. textXOffset = (fullWidth - butPtr->textWidth)/2;
  187. imageXOffset = (fullWidth - width)/2;
  188. break;
  189.     }
  190.     case COMPOUND_LEFT:
  191.     case COMPOUND_RIGHT: {
  192. /* Image is left or right of text */
  193. if (butPtr->compound == COMPOUND_LEFT) {
  194.     textXOffset = width + butPtr->padX;
  195. } else {
  196.     imageXOffset = butPtr->textWidth + butPtr->padX;
  197. }
  198. fullWidth = butPtr->textWidth + butPtr->padX + width;
  199. fullHeight = (height > butPtr->textHeight ? height :
  200. butPtr->textHeight);
  201. textYOffset = (fullHeight - butPtr->textHeight)/2;
  202. imageYOffset = (fullHeight - height)/2;
  203. break;
  204.     }
  205.     case COMPOUND_CENTER: {
  206. /* Image and text are superimposed */
  207. fullWidth = (width > butPtr->textWidth ? width :
  208. butPtr->textWidth);
  209. fullHeight = (height > butPtr->textHeight ? height :
  210. butPtr->textHeight);
  211. textXOffset = (fullWidth - butPtr->textWidth)/2;
  212. imageXOffset = (fullWidth - width)/2;
  213. textYOffset = (fullHeight - butPtr->textHeight)/2;
  214. imageYOffset = (fullHeight - height)/2;
  215. break;
  216.     }
  217.     case COMPOUND_NONE: {break;}
  218. }
  219. TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
  220. butPtr->indicatorSpace + fullWidth, fullHeight, &x, &y);
  221. x += butPtr->indicatorSpace;
  222. x += offset;
  223. y += offset;
  224. if (relief == TK_RELIEF_RAISED) {
  225.     x -= offset;
  226.     y -= offset;
  227. } else if (relief == TK_RELIEF_SUNKEN) {
  228.     x += offset;
  229.     y += offset;
  230. }
  231. imageXOffset += x;
  232. imageYOffset += y;
  233. if (butPtr->image != NULL) {
  234.     /*
  235.      * Do boundary clipping, so that Tk_RedrawImage is passed
  236.      * valid coordinates. [Bug 979239]
  237.      */
  238.     if (imageXOffset < 0) {
  239. imageXOffset = 0;
  240.     }
  241.     if (imageYOffset < 0) {
  242. imageYOffset = 0;
  243.     }
  244.     if (width > Tk_Width(tkwin)) {
  245. width = Tk_Width(tkwin);
  246.     }
  247.     if (height > Tk_Height(tkwin)) {
  248. height = Tk_Height(tkwin);
  249.     }
  250.     if ((width + imageXOffset) > Tk_Width(tkwin)) {
  251. imageXOffset = Tk_Width(tkwin) - width;
  252.     }
  253.     if ((height + imageYOffset) > Tk_Height(tkwin)) {
  254. imageYOffset = Tk_Height(tkwin) - height;
  255.     }
  256.     if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
  257. Tk_RedrawImage(butPtr->selectImage, 0, 0,
  258. width, height, pixmap, imageXOffset, imageYOffset);
  259.     } else {
  260. Tk_RedrawImage(butPtr->image, 0, 0, width,
  261. height, pixmap, imageXOffset, imageYOffset);
  262.     }
  263. } else {
  264.     XSetClipOrigin(butPtr->display, gc, imageXOffset, imageYOffset);
  265.     XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc,
  266.     0, 0, (unsigned int) width, (unsigned int) height,
  267.     imageXOffset, imageYOffset, 1);
  268.     XSetClipOrigin(butPtr->display, gc, 0, 0);
  269. }
  270. Tk_DrawTextLayout(butPtr->display, pixmap, gc,
  271. butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1);
  272. Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
  273. butPtr->textLayout, x + textXOffset, y + textYOffset,
  274. butPtr->underline);
  275. y += fullHeight/2;
  276.     } else {
  277. if (haveImage) {
  278.     TkComputeAnchor(butPtr->anchor, tkwin, 0, 0,
  279.     butPtr->indicatorSpace + width, height, &x, &y);
  280.     x += butPtr->indicatorSpace;
  281.     
  282.     x += offset;
  283.     y += offset;
  284.     if (relief == TK_RELIEF_RAISED) {
  285. x -= offset;
  286. y -= offset;
  287.     } else if (relief == TK_RELIEF_SUNKEN) {
  288. x += offset;
  289. y += offset;
  290.     }
  291.     imageXOffset += x;
  292.     imageYOffset += y;
  293.     if (butPtr->image != NULL) {
  294. /*
  295.  * Do boundary clipping, so that Tk_RedrawImage is passed
  296.  * valid coordinates. [Bug 979239]
  297.  */
  298. if (imageXOffset < 0) {
  299.     imageXOffset = 0;
  300. }
  301. if (imageYOffset < 0) {
  302.     imageYOffset = 0;
  303. }
  304. if (width > Tk_Width(tkwin)) {
  305.     width = Tk_Width(tkwin);
  306. }
  307. if (height > Tk_Height(tkwin)) {
  308.     height = Tk_Height(tkwin);
  309. }
  310. if ((width + imageXOffset) > Tk_Width(tkwin)) {
  311.     imageXOffset = Tk_Width(tkwin) - width;
  312. }
  313. if ((height + imageYOffset) > Tk_Height(tkwin)) {
  314.     imageYOffset = Tk_Height(tkwin) - height;
  315. }
  316. if ((butPtr->selectImage != NULL) &&
  317. (butPtr->flags & SELECTED)) {
  318.     Tk_RedrawImage(butPtr->selectImage, 0, 0, width,
  319.     height, pixmap, imageXOffset, imageYOffset);
  320. } else {
  321.     Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap,
  322.     imageXOffset, imageYOffset);
  323. }
  324.     } else {
  325. XSetClipOrigin(butPtr->display, gc, x, y);
  326. XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
  327. (unsigned int) width, (unsigned int) height, x, y, 1);
  328. XSetClipOrigin(butPtr->display, gc, 0, 0);
  329.     }
  330.     y += height/2;
  331. } else {
  332.       TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
  333.     butPtr->indicatorSpace + butPtr->textWidth,
  334.     butPtr->textHeight, &x, &y);
  335.     
  336.     x += butPtr->indicatorSpace;
  337.     
  338.     x += offset;
  339.     y += offset;
  340.     if (relief == TK_RELIEF_RAISED) {
  341. x -= offset;
  342. y -= offset;
  343.     } else if (relief == TK_RELIEF_SUNKEN) {
  344. x += offset;
  345. y += offset;
  346.     }
  347.     Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout,
  348.     x, y, 0, -1);
  349.     Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
  350.     butPtr->textLayout, x, y, butPtr->underline);
  351.     y += butPtr->textHeight/2;
  352. }
  353.     }
  354.     
  355.     /*
  356.      * Draw the indicator for check buttons and radio buttons.  At this
  357.      * point x and y refer to the top-left corner of the text or image
  358.      * or bitmap.
  359.      */
  360.     if ((butPtr->type == TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
  361. int dim;
  362. dim = butPtr->indicatorDiameter;
  363. x -= butPtr->indicatorSpace;
  364. y -= dim/2;
  365. if (dim > 2*butPtr->borderWidth) {
  366.     Tk_Draw3DRectangle(tkwin, pixmap, border, x, y, dim, dim,
  367.     butPtr->borderWidth,
  368.     (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN :
  369.     TK_RELIEF_RAISED);
  370.     x += butPtr->borderWidth;
  371.     y += butPtr->borderWidth;
  372.     dim -= 2*butPtr->borderWidth;
  373.     if (butPtr->flags & SELECTED) {
  374. GC gc;
  375. if (butPtr->state != STATE_DISABLED) {
  376.     if (butPtr->selectBorder != NULL) {
  377. gc = Tk_3DBorderGC(tkwin, butPtr->selectBorder,
  378. TK_3D_FLAT_GC);
  379.     } else {
  380. gc = Tk_3DBorderGC(tkwin, butPtr->normalBorder,
  381. TK_3D_FLAT_GC);
  382.     }
  383. } else {
  384.     if (butPtr->disabledFg != NULL) {
  385. gc = butPtr->disabledGC;
  386.     } else {
  387. gc = butPtr->normalTextGC; 
  388. XSetForeground(butPtr->display, butPtr->disabledGC,
  389. Tk_3DBorderColor(butPtr->normalBorder)->pixel);
  390.     }
  391. }
  392. XFillRectangle(butPtr->display, pixmap, gc, x, y,
  393. (unsigned int) dim, (unsigned int) dim);
  394.     } else {
  395. Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, x, y,
  396. dim, dim, butPtr->borderWidth, TK_RELIEF_FLAT);
  397.     }
  398. }
  399.     } else if ((butPtr->type == TYPE_RADIO_BUTTON) && butPtr->indicatorOn) {
  400. XPoint points[4];
  401. int radius;
  402. radius = butPtr->indicatorDiameter/2;
  403. points[0].x = x - butPtr->indicatorSpace;
  404. points[0].y = y;
  405. points[1].x = points[0].x + radius;
  406. points[1].y = points[0].y + radius;
  407. points[2].x = points[1].x + radius;
  408. points[2].y = points[0].y;
  409. points[3].x = points[1].x;
  410. points[3].y = points[0].y - radius;
  411. if (butPtr->flags & SELECTED) {
  412.     GC gc;
  413.     if (butPtr->state != STATE_DISABLED) {
  414. if (butPtr->selectBorder != NULL) {
  415.     gc = Tk_3DBorderGC(tkwin, butPtr->selectBorder,
  416.     TK_3D_FLAT_GC);
  417. } else {
  418.     gc = Tk_3DBorderGC(tkwin, butPtr->normalBorder,
  419.     TK_3D_FLAT_GC);
  420. }
  421.     } else {
  422. if (butPtr->disabledFg != NULL) {
  423.     gc = butPtr->disabledGC;
  424. } else {
  425.     gc = butPtr->normalTextGC; 
  426.     XSetForeground(butPtr->display, butPtr->disabledGC,
  427.     Tk_3DBorderColor(butPtr->normalBorder)->pixel);
  428. }
  429.     }
  430.     XFillPolygon(butPtr->display, pixmap, gc, points, 4, Convex,
  431.     CoordModeOrigin);
  432. } else {
  433.     Tk_Fill3DPolygon(tkwin, pixmap, butPtr->normalBorder, points,
  434.     4, butPtr->borderWidth, TK_RELIEF_FLAT);
  435. }
  436. Tk_Draw3DPolygon(tkwin, pixmap, border, points, 4, butPtr->borderWidth,
  437. (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN :
  438. TK_RELIEF_RAISED);
  439.     }
  440.     /*
  441.      * If the button is disabled with a stipple rather than a special
  442.      * foreground color, generate the stippled effect.  If the widget
  443.      * is selected and we use a different background color when selected,
  444.      * must temporarily modify the GC so the stippling is the right color.
  445.      */
  446.     if ((butPtr->state == STATE_DISABLED)
  447.     && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
  448. if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
  449. && (butPtr->selectBorder != NULL)) {
  450.     XSetForeground(butPtr->display, butPtr->stippleGC,
  451.     Tk_3DBorderColor(butPtr->selectBorder)->pixel);
  452. }
  453. /*
  454.  * Stipple the whole button if no disabledFg was specified,
  455.  * otherwise restrict stippling only to displayed image
  456.  */
  457. if (butPtr->disabledFg == NULL) {
  458.     XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC, 0, 0,
  459.     (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin));
  460. } else {
  461.     XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
  462.     imageXOffset, imageYOffset,
  463.     (unsigned) imageWidth, (unsigned) imageHeight);
  464. }
  465. if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
  466. && (butPtr->selectBorder != NULL)) {
  467.     XSetForeground(butPtr->display, butPtr->stippleGC,
  468.     Tk_3DBorderColor(butPtr->normalBorder)->pixel);
  469. }
  470.     }
  471.     /*
  472.      * Draw the border and traversal highlight last.  This way, if the
  473.      * button's contents overflow they'll be covered up by the border.
  474.      * This code is complicated by the possible combinations of focus
  475.      * highlight and default rings.  We draw the focus and highlight rings
  476.      * using the highlight border and highlight foreground color.
  477.      */
  478.     if (relief != TK_RELIEF_FLAT) {
  479. int inset = butPtr->highlightWidth;
  480. if (butPtr->defaultState == DEFAULT_ACTIVE) {
  481.     /*
  482.      * Draw the default ring with 2 pixels of space between the
  483.      * default ring and the button and the default ring and the
  484.      * focus ring.  Note that we need to explicitly draw the space
  485.      * in the highlightBorder color to ensure that we overwrite any
  486.      * overflow text and/or a different button background color.
  487.      */
  488.     Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
  489.     inset, Tk_Width(tkwin) - 2*inset,
  490.     Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT);
  491.     inset += 2;
  492.     Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
  493.     inset, Tk_Width(tkwin) - 2*inset,
  494.     Tk_Height(tkwin) - 2*inset, 1, TK_RELIEF_SUNKEN);
  495.     inset++;
  496.     Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
  497.     inset, Tk_Width(tkwin) - 2*inset,
  498.     Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT);
  499.     inset += 2;
  500. } else if (butPtr->defaultState == DEFAULT_NORMAL) {
  501.     /*
  502.      * Leave room for the default ring and write over any text or
  503.      * background color.
  504.      */
  505.     Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0,
  506.     0, Tk_Width(tkwin), Tk_Height(tkwin), 5, TK_RELIEF_FLAT);
  507.     inset += 5;
  508. }
  509. /*
  510.  * Draw the button border.
  511.  */
  512. Tk_Draw3DRectangle(tkwin, pixmap, border, inset, inset,
  513. Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset,
  514. butPtr->borderWidth, relief);
  515.     }
  516.     if (butPtr->highlightWidth > 0) {
  517. GC gc;
  518. if (butPtr->flags & GOT_FOCUS) {
  519.     gc = Tk_GCForColor(butPtr->highlightColorPtr, pixmap);
  520. } else {
  521.     gc = Tk_GCForColor(Tk_3DBorderColor(butPtr->highlightBorder),
  522.     pixmap);
  523. }
  524. /*
  525.  * Make sure the focus ring shrink-wraps the actual button, not the
  526.  * padding space left for a default ring.
  527.  */
  528. if (butPtr->defaultState == DEFAULT_NORMAL) {
  529.     TkDrawInsetFocusHighlight(tkwin, gc, butPtr->highlightWidth,
  530.     pixmap, 5);
  531. } else {
  532.     Tk_DrawFocusHighlight(tkwin, gc, butPtr->highlightWidth, pixmap);
  533. }
  534.     }
  535.     /*
  536.      * Copy the information from the off-screen pixmap onto the screen,
  537.      * then delete the pixmap.
  538.      */
  539.     XCopyArea(butPtr->display, pixmap, Tk_WindowId(tkwin),
  540.     butPtr->copyGC, 0, 0, (unsigned) Tk_Width(tkwin),
  541.     (unsigned) Tk_Height(tkwin), 0, 0);
  542.     Tk_FreePixmap(butPtr->display, pixmap);
  543. }
  544. /*
  545.  *----------------------------------------------------------------------
  546.  *
  547.  * TkpComputeButtonGeometry --
  548.  *
  549.  * After changes in a button's text or bitmap, this procedure
  550.  * recomputes the button's geometry and passes this information
  551.  * along to the geometry manager for the window.
  552.  *
  553.  * Results:
  554.  * None.
  555.  *
  556.  * Side effects:
  557.  * The button's window may change size.
  558.  *
  559.  *----------------------------------------------------------------------
  560.  */
  561. void
  562. TkpComputeButtonGeometry(butPtr)
  563.     register TkButton *butPtr; /* Button whose geometry may have changed. */
  564. {
  565.     int width, height, avgWidth, txtWidth, txtHeight;
  566.     int haveImage = 0, haveText = 0;
  567.     Tk_FontMetrics fm;
  568.     butPtr->inset = butPtr->highlightWidth + butPtr->borderWidth;
  569.     /*
  570.      * Leave room for the default ring if needed.
  571.      */
  572.     if (butPtr->defaultState != DEFAULT_DISABLED) {
  573. butPtr->inset += 5;
  574.     }
  575.     butPtr->indicatorSpace = 0;
  576.     width = 0;
  577.     height = 0;
  578.     txtWidth = 0;
  579.     txtHeight = 0;
  580.     avgWidth = 0;
  581.     
  582.     if (butPtr->image != NULL) {
  583. Tk_SizeOfImage(butPtr->image, &width, &height);
  584. haveImage = 1;
  585.     } else if (butPtr->bitmap != None) {
  586. Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
  587. haveImage = 1;
  588.     }
  589.     
  590.     if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
  591. Tk_FreeTextLayout(butPtr->textLayout);
  592.     
  593. butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
  594. Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength,
  595. butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
  596. txtWidth = butPtr->textWidth;
  597. txtHeight = butPtr->textHeight;
  598. avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
  599. Tk_GetFontMetrics(butPtr->tkfont, &fm);
  600. haveText = (txtWidth != 0 && txtHeight != 0);
  601.     }
  602.     
  603.     /*
  604.      * If the button is compound (ie, it shows both an image and text),
  605.      * the new geometry is a combination of the image and text geometry.
  606.      * We only honor the compound bit if the button has both text and an
  607.      * image, because otherwise it is not really a compound button.
  608.      */
  609.     if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
  610. switch ((enum compound) butPtr->compound) {
  611.     case COMPOUND_TOP:
  612.     case COMPOUND_BOTTOM: {
  613. /* Image is above or below text */
  614. height += txtHeight + butPtr->padY;
  615. width = (width > txtWidth ? width : txtWidth);
  616. break;
  617.     }
  618.     case COMPOUND_LEFT:
  619.     case COMPOUND_RIGHT: {
  620. /* Image is left or right of text */
  621. width += txtWidth + butPtr->padX;
  622. height = (height > txtHeight ? height : txtHeight);
  623. break;
  624.     }
  625.     case COMPOUND_CENTER: {
  626. /* Image and text are superimposed */
  627. width = (width > txtWidth ? width : txtWidth);
  628. height = (height > txtHeight ? height : txtHeight);
  629. break;
  630.     }
  631.     case COMPOUND_NONE: {break;}
  632. }
  633. if (butPtr->width > 0) {
  634.     width = butPtr->width;
  635. }
  636. if (butPtr->height > 0) {
  637.     height = butPtr->height;
  638. }
  639. if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
  640.     butPtr->indicatorSpace = height;
  641.     if (butPtr->type == TYPE_CHECK_BUTTON) {
  642. butPtr->indicatorDiameter = (65*height)/100;
  643.     } else {
  644. butPtr->indicatorDiameter = (75*height)/100;
  645.     }
  646. }
  647. width += 2*butPtr->padX;
  648. height += 2*butPtr->padY;
  649.     } else {
  650. if (haveImage) {
  651.     if (butPtr->width > 0) {
  652. width = butPtr->width;
  653.     }
  654.     if (butPtr->height > 0) {
  655. height = butPtr->height;
  656.     }
  657.     
  658.     if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
  659. butPtr->indicatorSpace = height;
  660. if (butPtr->type == TYPE_CHECK_BUTTON) {
  661.     butPtr->indicatorDiameter = (65*height)/100;
  662. } else {
  663.     butPtr->indicatorDiameter = (75*height)/100;
  664. }
  665.     }
  666. } else {
  667.     width = txtWidth;
  668.     height = txtHeight;
  669.     
  670.     if (butPtr->width > 0) {
  671. width = butPtr->width * avgWidth;
  672.     }
  673.     if (butPtr->height > 0) {
  674. height = butPtr->height * fm.linespace;
  675.     }
  676.     if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
  677. butPtr->indicatorDiameter = fm.linespace;
  678. if (butPtr->type == TYPE_CHECK_BUTTON) {
  679.     butPtr->indicatorDiameter =
  680. (80*butPtr->indicatorDiameter)/100;
  681. }
  682. butPtr->indicatorSpace = butPtr->indicatorDiameter + avgWidth;
  683.     }
  684. }
  685.     }
  686.     /*
  687.      * When issuing the geometry request, add extra space for the indicator,
  688.      * if any, and for the border and padding, plus two extra pixels so the
  689.      * display can be offset by 1 pixel in either direction for the raised
  690.      * or lowered effect.
  691.      */
  692.     if ((butPtr->image == NULL) && (butPtr->bitmap == None)) {
  693. width += 2*butPtr->padX;
  694. height += 2*butPtr->padY;
  695.     }
  696.     if ((butPtr->type == TYPE_BUTTON) && !Tk_StrictMotif(butPtr->tkwin)) {
  697. width += 2;
  698. height += 2;
  699.     }
  700.     Tk_GeometryRequest(butPtr->tkwin, (int) (width + butPtr->indicatorSpace
  701.     + 2*butPtr->inset), (int) (height + 2*butPtr->inset));
  702.     Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
  703. }