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

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkMacOSXButton.c --
  3.  *
  4.  * This file implements the Macintosh specific portion of the
  5.  * button widgets.
  6.  *
  7.  * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
  8.  * Copyright 2001, Apple Computer, Inc.
  9.  * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tkMacOSXButton.c,v 1.2.2.20 2007/11/09 07:36:45 das Exp $
  15.  */
  16. #include "tkMacOSXPrivate.h"
  17. #include "tkButton.h"
  18. #include "tkMacOSXFont.h"
  19. #include "tkMacOSXDebug.h"
  20. #define DEFAULT_USE_TK_TEXT 0
  21. #define CONTROL_INITIALIZED 1
  22. #define FIRST_DRAW     2
  23. #define ACTIVE     4
  24. #define MAX_VALUE     1
  25. /*
  26.  * Default insets for controls
  27.  */
  28. #define DEF_INSET_LEFT 2
  29. #define DEF_INSET_RIGHT 2
  30. #define DEF_INSET_TOP 2
  31. #define DEF_INSET_BOTTOM 4
  32. /*
  33.  * Some defines used to control what type of control is drawn.
  34.  */
  35. #define DRAW_LABEL 0 /* Labels are treated genericly. */
  36. #define DRAW_CONTROL 1 /* Draw using the Native control. */
  37. #define DRAW_CUSTOM 2 /* Make our own button drawing. */
  38. #define DRAW_BEVEL 3
  39. /*
  40.  * Declaration of Mac specific button structure.
  41.  */
  42. typedef struct {
  43.     SInt16 initialValue;
  44.     SInt16 minValue;
  45.     SInt16 maxValue;
  46.     SInt16 procID;
  47.     int isBevel;
  48. } MacControlParams;
  49. typedef struct {
  50.     int drawType;
  51.     Tk_3DBorder border;
  52.     int relief;
  53.     int offset; /* 0 means this is a normal widget. 1 means
  54.  * it is an image button, so we offset the
  55.  * image to make the button appear to move
  56.  * up and down as the relief changes. */
  57.     GC gc;
  58.     int hasImageOrBitmap;
  59. } DrawParams;
  60. typedef struct {
  61.     TkButton info; /* Generic button info */
  62.     int id;
  63.     int usingControl;
  64.     int useTkText;
  65.     int flags; /* Initialisation status */
  66.     MacControlParams params;
  67.     WindowRef windowRef;
  68.     unsigned long userPaneBackground;
  69.     ControlRef userPane; /* Carbon control */
  70.     ControlRef control; /* Carbon control */
  71.     Str255 controlTitle;
  72.     ControlFontStyleRec fontStyle;
  73.     /*
  74.      * The following are used to store the image content for
  75.      * beveled buttons, i.e. buttons with images.
  76.      */
  77.     ControlButtonContentInfo bevelButtonContent;
  78.     OpenCPicParams picParams;
  79. } MacButton;
  80. /*
  81.  * Forward declarations for procedures defined later in this file:
  82.  */
  83. static OSStatus SetUserPaneDrawProc(ControlRef control,
  84. ControlUserPaneDrawProcPtr upp);
  85. static OSStatus SetUserPaneSetUpSpecialBackgroundProc(ControlRef control,
  86. ControlUserPaneBackgroundProcPtr upp);
  87. static void UserPaneDraw(ControlRef control, ControlPartCode cpc);
  88. static void UserPaneBackgroundProc(ControlHandle,
  89. ControlBackgroundPtr info);
  90. static void ButtonEventProc(ClientData clientData, XEvent *eventPtr);
  91. static int UpdateControlColors(MacButton *mbPtr);
  92. static void TkMacOSXComputeControlParams(TkButton *butPtr,
  93. MacControlParams *paramsPtr);
  94. static int TkMacOSXComputeDrawParams(TkButton *butPtr, DrawParams *dpPtr);
  95. static void TkMacOSXDrawControl(MacButton *butPtr, GWorldPtr destPort, GC gc,
  96. Pixmap pixmap);
  97. static void SetupBevelButton(MacButton *butPtr, ControlRef controlHandle,
  98. GWorldPtr destPort, GC gc, Pixmap pixmap);
  99. /*
  100.  * The class procedure table for the button widgets.
  101.  */
  102. Tk_ClassProcs tkpButtonProcs = {
  103.     sizeof(Tk_ClassProcs), /* size */
  104.     TkButtonWorldChanged, /* worldChangedProc */
  105. };
  106. static int bCount;
  107. /*
  108.  *----------------------------------------------------------------------
  109.  *
  110.  * TkpCreateButton --
  111.  *
  112.  * Allocate a new TkButton structure.
  113.  *
  114.  * Results:
  115.  * Returns a newly allocated TkButton structure.
  116.  *
  117.  * Side effects:
  118.  * Registers an event handler for the widget.
  119.  *
  120.  *----------------------------------------------------------------------
  121.  */
  122. TkButton *
  123. TkpCreateButton(
  124.     Tk_Window tkwin)
  125. {
  126.     MacButton *macButtonPtr = (MacButton *) ckalloc(sizeof(MacButton));
  127.     Tk_CreateEventHandler(tkwin, ActivateMask,
  128.     ButtonEventProc, (ClientData) macButtonPtr);
  129.     macButtonPtr->id = bCount++;
  130.     macButtonPtr->usingControl = 0;
  131.     macButtonPtr->flags = 0;
  132.     macButtonPtr->userPaneBackground = PIXEL_MAGIC << 24;
  133.     macButtonPtr->userPane = NULL;
  134.     macButtonPtr->control = NULL;
  135.     macButtonPtr->controlTitle[0] = 0;
  136.     macButtonPtr->controlTitle[1] = 0;
  137.     bzero(&macButtonPtr->params, sizeof(macButtonPtr->params));
  138.     bzero(&macButtonPtr->fontStyle, sizeof(macButtonPtr->fontStyle));
  139.     return (TkButton *)macButtonPtr;
  140. }
  141. /*
  142.  *----------------------------------------------------------------------
  143.  *
  144.  * TkpDisplayButton --
  145.  *
  146.  * This procedure is invoked to display a button widget. It is
  147.  * normally invoked as an idle handler.
  148.  *
  149.  * Results:
  150.  * None.
  151.  *
  152.  * Side effects:
  153.  * Commands are output to X to display the button in its
  154.  * current mode. The REDRAW_PENDING flag is cleared.
  155.  *
  156.  *----------------------------------------------------------------------
  157.  */
  158. void
  159. TkpDisplayButton(
  160.     ClientData clientData) /* Information about widget. */
  161. {
  162.     MacButton *macButtonPtr = (MacButton *) clientData;
  163.     TkButton *butPtr = (TkButton *) clientData;
  164.     Tk_Window tkwin = butPtr->tkwin;
  165.     CGrafPtr destPort, savePort;
  166.     Boolean portChanged;
  167.     Pixmap pixmap;
  168.     int width, height, fullWidth, fullHeight, textXOffset, textYOffset;
  169.     int borderWidth, wasUsingControl;
  170.     int haveImage = 0, haveText = 0, imageWidth = 0, imageHeight = 0;
  171.     int imageXOffset = 0, imageYOffset = 0; /* image information that will
  172.      * be used to restrict disabled
  173.      * pixmap as well */
  174.     DrawParams drawParams, *dpPtr = &drawParams;
  175.     butPtr->flags &= ~REDRAW_PENDING;
  176.     if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  177. return;
  178.     }
  179.     pixmap = (Pixmap) Tk_WindowId(tkwin);
  180.     wasUsingControl = macButtonPtr->usingControl;
  181.     if (TkMacOSXComputeDrawParams(butPtr, &drawParams) ) {
  182. macButtonPtr->usingControl = 1;
  183. if (butPtr->type == TYPE_BUTTON) {
  184.     macButtonPtr->useTkText = 0;
  185. } else {
  186.     macButtonPtr->useTkText = 1;
  187. }
  188.     } else {
  189. macButtonPtr->usingControl = 0;
  190. macButtonPtr->useTkText = 1;
  191.     }
  192.     /*
  193.      * See the comment in UpdateControlColors as to why we use the
  194.      * highlightbackground for the border of Macintosh buttons.
  195.      */
  196.     if (macButtonPtr->useTkText) {
  197. if (butPtr->type == TYPE_BUTTON) {
  198.     Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0,
  199.     Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
  200. } else {
  201.     Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
  202.     Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
  203. }
  204.     }
  205.     /*
  206.      * Set up clipping region. Make sure the we are using the port
  207.      * for this button, or we will set the wrong window's clip.
  208.      */
  209.     destPort = TkMacOSXGetDrawablePort(pixmap);
  210.     portChanged = QDSwapPort(destPort, &savePort);
  211.     TkMacOSXSetUpClippingRgn(pixmap);
  212.     /*
  213.      * Draw the native portion of the buttons. Start by creating the control
  214.      * if it doesn't already exist. Then configure the Macintosh control from
  215.      * the Tk info. Finally, we call Draw1Control to draw to the screen.
  216.      */
  217.     if (macButtonPtr->usingControl) {
  218. borderWidth = 0;
  219. TkMacOSXDrawControl(macButtonPtr, destPort, dpPtr->gc, pixmap);
  220.     } else if (wasUsingControl && macButtonPtr->userPane) {
  221. DisposeControl(macButtonPtr->userPane);
  222. macButtonPtr->userPane = NULL;
  223. macButtonPtr->control = NULL;
  224. macButtonPtr->flags = 0;
  225.     }
  226.     if ((dpPtr->drawType == DRAW_CUSTOM) || (dpPtr->drawType == DRAW_LABEL)) {
  227. borderWidth = butPtr->borderWidth;
  228.     }
  229.     /*
  230.      * Display image or bitmap or text for button. This has
  231.      * already been done under Appearance with the Bevel
  232.      * button types.
  233.      */
  234.     if (dpPtr->drawType == DRAW_BEVEL) {
  235. goto applyStipple;
  236.     }
  237.     if (butPtr->image != None) {
  238. Tk_SizeOfImage(butPtr->image, &width, &height);
  239. haveImage = 1;
  240.     } else if (butPtr->bitmap != None) {
  241. Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
  242. haveImage = 1;
  243.     }
  244.     imageWidth = width;
  245.     imageHeight = height;
  246.     haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
  247.     if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
  248. int x, y;
  249. textXOffset = 0;
  250. textYOffset = 0;
  251. fullWidth = 0;
  252. fullHeight = 0;
  253. switch ((enum compound) butPtr->compound) {
  254.     case COMPOUND_TOP:
  255.     case COMPOUND_BOTTOM:
  256. /*
  257.  * Image is above or below text.
  258.  */
  259. if (butPtr->compound == COMPOUND_TOP) {
  260.     textYOffset = height + butPtr->padY;
  261. } else {
  262.     imageYOffset = butPtr->textHeight + butPtr->padY;
  263. }
  264. fullHeight = height + butPtr->textHeight + butPtr->padY;
  265. fullWidth = (width > butPtr->textWidth ? width :
  266. butPtr->textWidth);
  267. textXOffset = (fullWidth - butPtr->textWidth)/2;
  268. imageXOffset = (fullWidth - width)/2;
  269. break;
  270.     case COMPOUND_LEFT:
  271.     case COMPOUND_RIGHT:
  272. /*
  273.  * Image is left or right of text.
  274.  */
  275. if (butPtr->compound == COMPOUND_LEFT) {
  276.     textXOffset = width + butPtr->padX;
  277. } else {
  278.     imageXOffset = butPtr->textWidth + butPtr->padX;
  279. }
  280. fullWidth = butPtr->textWidth + butPtr->padX + width;
  281. fullHeight = (height > butPtr->textHeight ? height :
  282. butPtr->textHeight);
  283. textYOffset = (fullHeight - butPtr->textHeight)/2;
  284. imageYOffset = (fullHeight - height)/2;
  285. break;
  286.     case COMPOUND_CENTER:
  287. /*
  288.  * Image and text are superimposed.
  289.  */
  290. fullWidth = (width > butPtr->textWidth ? width :
  291. butPtr->textWidth);
  292. fullHeight = (height > butPtr->textHeight ? height :
  293. butPtr->textHeight);
  294. textXOffset = (fullWidth - butPtr->textWidth)/2;
  295. imageXOffset = (fullWidth - width)/2;
  296. textYOffset = (fullHeight - butPtr->textHeight)/2;
  297. imageYOffset = (fullHeight - height)/2;
  298. break;
  299.     case COMPOUND_NONE:
  300. break;
  301. }
  302. TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
  303. butPtr->indicatorSpace + fullWidth, fullHeight, &x, &y);
  304. x += butPtr->indicatorSpace;
  305. x += dpPtr->offset;
  306. y += dpPtr->offset;
  307. if (dpPtr->relief == TK_RELIEF_RAISED) {
  308.     x -= dpPtr->offset;
  309.     y -= dpPtr->offset;
  310. } else if (dpPtr->relief == TK_RELIEF_SUNKEN) {
  311.     x += dpPtr->offset;
  312.     y += dpPtr->offset;
  313. }
  314. imageXOffset += x;
  315. imageYOffset += y;
  316. if (butPtr->image != NULL) {
  317.     if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
  318. Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height,
  319. pixmap, imageXOffset, imageYOffset);
  320. #if 0
  321.     } else if ((butPtr->tristateImage != NULL) &&
  322.     (butPtr->flags & TRISTATED)) {
  323. Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, height,
  324. pixmap, imageXOffset, imageYOffset);
  325. #endif
  326.     } else {
  327. Tk_RedrawImage(butPtr->image, 0, 0, width, height,
  328. pixmap, imageXOffset, imageYOffset);
  329.     }
  330. } else {
  331.     XSetClipOrigin(butPtr->display, dpPtr->gc, imageXOffset,
  332.     imageYOffset);
  333.     XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc,
  334.     0, 0, width, height, imageXOffset, imageYOffset, 1);
  335.     XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
  336. }
  337. if (macButtonPtr->useTkText) {
  338.     Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc,
  339.     butPtr->textLayout, x + textXOffset, y + textYOffset, 0,
  340.     -1);
  341.     Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc,
  342.     butPtr->textLayout, x + textXOffset, y + textYOffset,
  343.     butPtr->underline);
  344. }
  345. y += fullHeight/2;
  346.     } else if (haveImage) {
  347. int x = 0, y;
  348. TkComputeAnchor(butPtr->anchor, tkwin, 0, 0,
  349. butPtr->indicatorSpace + width, height, &x, &y);
  350. x += butPtr->indicatorSpace;
  351. x += dpPtr->offset;
  352. y += dpPtr->offset;
  353. if (dpPtr->relief == TK_RELIEF_RAISED) {
  354.     x -= dpPtr->offset;
  355.     y -= dpPtr->offset;
  356. } else if (dpPtr->relief == TK_RELIEF_SUNKEN) {
  357.     x += dpPtr->offset;
  358.     y += dpPtr->offset;
  359. }
  360. imageXOffset += x;
  361. imageYOffset += y;
  362. if (butPtr->image != NULL) {
  363.     if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
  364. Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height,
  365. pixmap, imageXOffset, imageYOffset);
  366. #if 0
  367.     } else if ((butPtr->tristateImage != NULL) &&
  368.     (butPtr->flags & TRISTATED)) {
  369. Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, height,
  370. pixmap, imageXOffset, imageYOffset);
  371. #endif
  372.     } else {
  373. Tk_RedrawImage(butPtr->image, 0, 0, width, height,
  374. pixmap, imageXOffset, imageYOffset);
  375.     }
  376. } else {
  377.     XSetClipOrigin(butPtr->display, dpPtr->gc, x, y);
  378.     XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc,
  379.     0, 0, width, height, x, y, 1);
  380.     XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
  381. }
  382. y += height/2;
  383.     } else if (macButtonPtr->useTkText) {
  384. int x = 0, y;
  385. TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
  386. butPtr->indicatorSpace + butPtr->textWidth,
  387. butPtr->textHeight, &x, &y);
  388. x += butPtr->indicatorSpace;
  389. Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc,
  390. butPtr->textLayout, x, y, 0, -1);
  391.     }
  392.     /*
  393.      * If the button is disabled with a stipple rather than a special
  394.      * foreground color, generate the stippled effect. If the widget
  395.      * is selected and we use a different background color when selected,
  396.      * must temporarily modify the GC so the stippling is the right color.
  397.      */
  398.   applyStipple:
  399.     if (macButtonPtr->useTkText) {
  400. if ((butPtr->state == STATE_DISABLED)
  401. && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
  402.     if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
  403.     && (butPtr->selectBorder != NULL)) {
  404. XSetForeground(butPtr->display, butPtr->stippleGC,
  405. Tk_3DBorderColor(butPtr->selectBorder)->pixel);
  406.     }
  407.     /*
  408.      * Stipple the whole button if no disabledFg was specified,
  409.      * otherwise restrict stippling only to displayed image
  410.      */
  411.     if (butPtr->disabledFg == NULL) {
  412. XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
  413. 0, 0, (unsigned) Tk_Width(tkwin),
  414. (unsigned) Tk_Height(tkwin));
  415.     } else {
  416. XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
  417. imageXOffset, imageYOffset,
  418. (unsigned) imageWidth, (unsigned) imageHeight);
  419.     }
  420.     if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
  421.     && (butPtr->selectBorder != NULL)) {
  422. XSetForeground(butPtr->display, butPtr->stippleGC,
  423. Tk_3DBorderColor(butPtr->normalBorder)->pixel);
  424.     }
  425. }
  426. /*
  427.  * Draw the border and traversal highlight last. This way, if the
  428.  * button's contents overflow they'll be covered up by the border.
  429.  */
  430. if (dpPtr->relief != TK_RELIEF_FLAT) {
  431.     int inset = butPtr->highlightWidth;
  432.     Tk_Draw3DRectangle(tkwin, pixmap, dpPtr->border, inset, inset,
  433.     Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset,
  434.     butPtr->borderWidth, dpPtr->relief);
  435. }
  436.     }
  437.     if (portChanged) {
  438. QDSwapPort(savePort, NULL);
  439.     }
  440. }
  441. /*
  442.  *----------------------------------------------------------------------
  443.  *
  444.  * TkpComputeButtonGeometry --
  445.  *
  446.  * After changes in a button's text or bitmap, this procedure
  447.  * recomputes the button's geometry and passes this information
  448.  * along to the geometry manager for the window.
  449.  *
  450.  * Results:
  451.  * None.
  452.  *
  453.  * Side effects:
  454.  * The button's window may change size.
  455.  *
  456.  *----------------------------------------------------------------------
  457.  */
  458. void
  459. TkpComputeButtonGeometry(
  460.     TkButton *butPtr) /* Button whose geometry may have changed. */
  461. {
  462.     int width, height, avgWidth, haveImage = 0, haveText = 0;
  463.     int xInset, yInset, txtWidth, txtHeight;
  464.     Tk_FontMetrics fm;
  465.     DrawParams drawParams;
  466.     /*
  467.      * First figure out the size of the contents of the button.
  468.      */
  469.     width = 0;
  470.     height = 0;
  471.     txtWidth = 0;
  472.     txtHeight = 0;
  473.     avgWidth = 0;
  474.     butPtr->indicatorSpace = 0;
  475.     if (butPtr->image != NULL) {
  476. Tk_SizeOfImage(butPtr->image, &width, &height);
  477. haveImage = 1;
  478.     } else if (butPtr->bitmap != None) {
  479. Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
  480. haveImage = 1;
  481.     }
  482.     if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
  483. Tk_FreeTextLayout(butPtr->textLayout);
  484. butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
  485. Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength,
  486. butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
  487. txtWidth = butPtr->textWidth;
  488. txtHeight = butPtr->textHeight;
  489. avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
  490. Tk_GetFontMetrics(butPtr->tkfont, &fm);
  491. haveText = (txtWidth != 0 && txtHeight != 0);
  492.     }
  493.     /*
  494.      * If the button is compound (ie, it shows both an image and text),
  495.      * the new geometry is a combination of the image and text geometry.
  496.      * We only honor the compound bit if the button has both text and an
  497.      * image, because otherwise it is not really a compound button.
  498.      */
  499.     if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
  500. switch ((enum compound) butPtr->compound) {
  501.     case COMPOUND_TOP:
  502.     case COMPOUND_BOTTOM:
  503. /*
  504.  * Image is above or below text.
  505.  */
  506. height += txtHeight + butPtr->padY;
  507. width = (width > txtWidth ? width : txtWidth);
  508. break;
  509.     case COMPOUND_LEFT:
  510.     case COMPOUND_RIGHT:
  511. /*
  512.  * Image is left or right of text.
  513.  */
  514. width += txtWidth + butPtr->padX;
  515. height = (height > txtHeight ? height : txtHeight);
  516. break;
  517.     case COMPOUND_CENTER:
  518. /*
  519.  * Image and text are superimposed.
  520.  */
  521. width = (width > txtWidth ? width : txtWidth);
  522. height = (height > txtHeight ? height : txtHeight);
  523. break;
  524.     case COMPOUND_NONE:
  525. break;
  526. }
  527. if (butPtr->width > 0) {
  528.     width = butPtr->width;
  529. }
  530. if (butPtr->height > 0) {
  531.     height = butPtr->height;
  532. }
  533. if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
  534.     butPtr->indicatorSpace = height;
  535.     if (butPtr->type == TYPE_CHECK_BUTTON) {
  536. butPtr->indicatorDiameter = (65 * height)/100;
  537.     } else {
  538. butPtr->indicatorDiameter = (75 * height)/100;
  539.     }
  540. }
  541. width += 2 * butPtr->padX;
  542. height += 2 * butPtr->padY;
  543.     } else if (haveImage) {
  544. if (butPtr->width > 0) {
  545.     width = butPtr->width;
  546. }
  547. if (butPtr->height > 0) {
  548.     height = butPtr->height;
  549. }
  550. if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
  551.     butPtr->indicatorSpace = height;
  552.     if (butPtr->type == TYPE_CHECK_BUTTON) {
  553. butPtr->indicatorDiameter = (65 * height)/100;
  554.     } else {
  555. butPtr->indicatorDiameter = (75 * height)/100;
  556.     }
  557. }
  558.     } else {
  559. width = txtWidth;
  560. height = txtHeight;
  561. if (butPtr->width > 0) {
  562.     width = butPtr->width * avgWidth;
  563. }
  564. if (butPtr->height > 0) {
  565.     height = butPtr->height * fm.linespace;
  566. }
  567. if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
  568.     butPtr->indicatorDiameter = fm.linespace;
  569.     if (butPtr->type == TYPE_CHECK_BUTTON) {
  570. butPtr->indicatorDiameter =
  571. (80 * butPtr->indicatorDiameter)/100;
  572.     }
  573.     butPtr->indicatorSpace = butPtr->indicatorDiameter + avgWidth;
  574. }
  575.     }
  576.     /*
  577.      * Now figure out the size of the border decorations for the button.
  578.      */
  579.     if (butPtr->highlightWidth < 0) {
  580. butPtr->highlightWidth = 0;
  581.     }
  582.     /*
  583.      * The width and height calculation for Appearance buttons with images &
  584.      * non-Appearance buttons with images is different. In the latter case,
  585.      * we add the borderwidth to the inset, since we are going to stamp a
  586.      * 3-D border over the image. In the former, we add it to the height,
  587.      * directly, since Appearance will draw the border as part of our control.
  588.      *
  589.      * When issuing the geometry request, add extra space for the indicator,
  590.      * if any, and for the border and padding, plus if this is an image two
  591.      * extra pixels so the display can be offset by 1 pixel in either
  592.      * direction for the raised or lowered effect.
  593.      *
  594.      * The highlight width corresponds to the default ring on the Macintosh.
  595.      * As such, the highlight width is only added if the button is the default
  596.      * button. The actual width of the default ring is one less than the
  597.      * highlight width as there is also one pixel of spacing.
  598.      * Appearance buttons with images do not have a highlight ring, because the
  599.      * Bevel button type does not support one.
  600.      */
  601.     if ((butPtr->image == None) && (butPtr->bitmap == None)) {
  602. width += 2*butPtr->padX;
  603. height += 2*butPtr->padY;
  604.     }
  605.     if ((butPtr->type == TYPE_BUTTON)) {
  606. if ((butPtr->image == None) && (butPtr->bitmap == None)) {
  607.     butPtr->inset = 0;
  608.     if (butPtr->defaultState != STATE_DISABLED) {
  609. butPtr->inset += butPtr->highlightWidth;
  610.     }
  611. } else {
  612.     butPtr->inset = 0;
  613.     width += (2 * butPtr->borderWidth + 4);
  614.     height += (2 * butPtr->borderWidth + 4);
  615. }
  616.     } else if (butPtr->type == TYPE_LABEL) {
  617. butPtr->inset = butPtr->borderWidth;
  618.     } else if (butPtr->indicatorOn) {
  619. butPtr->inset = 0;
  620.     } else {
  621. /*
  622.  * Under Appearance, the Checkbutton or radiobutton with an image
  623.  * is represented by a BevelButton with the Sticky defProc...
  624.  * So we must set its height in the same way as the Button
  625.  * with an image or bitmap.
  626.  */
  627. if (butPtr->image != None || butPtr->bitmap != None) {
  628.     int border;
  629.     butPtr->inset = 0;
  630.     if (butPtr->borderWidth <= 2) {
  631. border = 6;
  632.     } else {
  633. border = 2 * butPtr->borderWidth + 2;
  634.     }
  635.     width += border;
  636.     height += border;
  637. } else {
  638.     butPtr->inset = butPtr->borderWidth;
  639. }
  640.     }
  641.     if (TkMacOSXComputeDrawParams(butPtr, &drawParams)) {
  642. xInset = butPtr->indicatorSpace + DEF_INSET_LEFT + DEF_INSET_RIGHT;
  643. yInset = DEF_INSET_TOP + DEF_INSET_BOTTOM;
  644.     } else {
  645. xInset = butPtr->indicatorSpace+butPtr->inset*2;
  646. yInset = butPtr->inset*2;
  647.     }
  648.     Tk_GeometryRequest(butPtr->tkwin, width + xInset, height + yInset);
  649.     Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
  650. }
  651. /*
  652.  *----------------------------------------------------------------------
  653.  *
  654.  * TkpDestroyButton --
  655.  *
  656.  * Free data structures associated with the button control.
  657.  *
  658.  * Results:
  659.  * None.
  660.  *
  661.  * Side effects:
  662.  * Restores the default control state.
  663.  *
  664.  *----------------------------------------------------------------------
  665.  */
  666. void
  667. TkpDestroyButton(
  668.     TkButton *butPtr)
  669. {
  670.     MacButton *mbPtr = (MacButton *) butPtr; /* Mac button. */
  671.     if (mbPtr->userPane) {
  672. DisposeControl(mbPtr->userPane);
  673. mbPtr->userPane = NULL;
  674.     }
  675. }
  676. /*
  677.  *----------------------------------------------------------------------
  678.  *
  679.  * TkMacOSXInitControl --
  680.  *
  681.  * This procedure initialises a Carbon control.
  682.  *
  683.  * Results:
  684.  * 0 on success, 1 on failure.
  685.  *
  686.  * Side effects:
  687.  * A background pane control and the control itself is created
  688.  * The contol is embedded in the background control
  689.  * The background control is embedded in the root control
  690.  * of the containing window
  691.  * The creation parameters for the control are also computed
  692.  *
  693.  *----------------------------------------------------------------------
  694.  */
  695. static int
  696. TkMacOSXInitControl(
  697.     MacButton *mbPtr, /* Mac button. */
  698.     GWorldPtr destPort,
  699.     GC gc,
  700.     Pixmap pixmap,
  701.     Rect *paneRect,
  702.     Rect *cntrRect)
  703. {
  704.     TkButton *butPtr = (TkButton *) mbPtr;
  705.     ControlRef rootControl;
  706.     SInt16 procID, initialValue, minValue, maxValue;
  707.     Boolean initiallyVisible;
  708.     SInt32 controlReference;
  709.     rootControl = TkMacOSXGetRootControl(Tk_WindowId(butPtr->tkwin));
  710.     mbPtr->windowRef = TkMacOSXDrawableWindow(Tk_WindowId(butPtr->tkwin));
  711.     /*
  712.      * Set up the user pane.
  713.      */
  714.     initiallyVisible = false;
  715.     initialValue = kControlSupportsEmbedding|kControlHasSpecialBackground;
  716.     minValue = 0;
  717.     maxValue = 1;
  718.     procID = kControlUserPaneProc;
  719.     controlReference = (SInt32)mbPtr;
  720.     mbPtr->userPane = NewControl(mbPtr->windowRef, paneRect, "p",
  721.     initiallyVisible, initialValue, minValue, maxValue, procID,
  722.     controlReference);
  723.     if (!mbPtr->userPane) {
  724. TkMacOSXDbgMsg("Failed to create user pane control");
  725. return 1;
  726.     }
  727.     if (ChkErr(EmbedControl, mbPtr->userPane,rootControl) != noErr) {
  728. return 1;
  729.     }
  730.     SetUserPaneSetUpSpecialBackgroundProc(mbPtr->userPane,
  731.     UserPaneBackgroundProc);
  732.     SetUserPaneDrawProc(mbPtr->userPane,UserPaneDraw);
  733.     initiallyVisible = false;
  734.     TkMacOSXComputeControlParams(butPtr,&mbPtr->params);
  735.     mbPtr->control = NewControl(mbPtr->windowRef, cntrRect, "p",
  736.     initiallyVisible, mbPtr->params.initialValue,
  737.     mbPtr->params.minValue, mbPtr->params.maxValue,
  738.     mbPtr->params.procID, controlReference);
  739.     if (!mbPtr->control) {
  740. TkMacOSXDbgMsg("Failed to create control of type %dn", procID);
  741. return 1;
  742.     }
  743.     if (ChkErr(EmbedControl, mbPtr->control,mbPtr->userPane) != noErr ) {
  744. return 1;
  745.     }
  746.     mbPtr->flags |= (CONTROL_INITIALIZED | FIRST_DRAW);
  747.     if (IsWindowActive(mbPtr->windowRef)) {
  748. mbPtr->flags |= ACTIVE;
  749.     }
  750.     return 0;
  751. }
  752. /*
  753.  *--------------------------------------------------------------
  754.  *
  755.  * TkMacOSXDrawControl --
  756.  *
  757.  * This function draws the tk button using Mac controls
  758.  * In addition, this code may apply custom colors passed
  759.  * in the TkButton.
  760.  *
  761.  * Results:
  762.  * None.
  763.  *
  764.  * Side effects:
  765.  * The control is created, or reinitialised as needed.
  766.  *
  767.  *--------------------------------------------------------------
  768.  */
  769. static void
  770. TkMacOSXDrawControl(
  771.     MacButton *mbPtr, /* Mac button. */
  772.     GWorldPtr destPort, /* Off screen GWorld. */
  773.     GC gc, /* The GC we are drawing into - needed for the
  774.  * bevel button */
  775.     Pixmap pixmap) /* The pixmap we are drawing into - needed for
  776.  * the bevel button */
  777. {
  778.     TkButton *butPtr = (TkButton *) mbPtr;
  779.     TkWindow *winPtr;
  780.     Rect paneRect, cntrRect;
  781.     int active, enabled;
  782.     int rebuild;
  783.     winPtr = (TkWindow *) butPtr->tkwin;
  784.     paneRect.left = winPtr->privatePtr->xOff;
  785.     paneRect.top = winPtr->privatePtr->yOff;
  786.     paneRect.right = paneRect.left + Tk_Width(butPtr->tkwin);
  787.     paneRect.bottom = paneRect.top + Tk_Height(butPtr->tkwin);
  788.     cntrRect = paneRect;
  789. /*
  790.     cntrRect.left += butPtr->inset;
  791.     cntrRect.top += butPtr->inset;
  792.     cntrRect.right -= butPtr->inset;
  793.     cntrRect.bottom -= butPtr->inset;
  794. */
  795.     cntrRect.left += DEF_INSET_LEFT;
  796.     cntrRect.top += DEF_INSET_TOP;
  797.     cntrRect.right -= DEF_INSET_RIGHT;
  798.     cntrRect.bottom -= DEF_INSET_BOTTOM;
  799.     /*
  800.      * The control has been previously initialised.
  801.      * It may need to be re-initialised
  802.      */
  803. #if 0
  804.     rebuild = (winPtr->flags & TK_REBUILD_TOPLEVEL);
  805.     winPtr->flags &= ~TK_REBUILD_TOPLEVEL;
  806. #else
  807.     rebuild = 0;
  808. #endif
  809.     if (mbPtr->flags) {
  810. MacControlParams params;
  811. TkMacOSXComputeControlParams(butPtr, &params);
  812. if (rebuild || bcmp(&params, &mbPtr->params, sizeof(params))) {
  813.     /*
  814.      * The type of control has changed.
  815.      * Clean it up and clear the flag.
  816.      */
  817.     if (mbPtr->userPane) {
  818. DisposeControl(mbPtr->userPane);
  819. mbPtr->userPane = NULL;
  820. mbPtr->control = NULL;
  821.     }
  822.     mbPtr->flags = 0;
  823. }
  824.     }
  825.     if (!(mbPtr->flags & CONTROL_INITIALIZED)) {
  826. if (TkMacOSXInitControl(mbPtr, destPort, gc, pixmap, &paneRect,
  827. &cntrRect)) {
  828.     return;
  829. }
  830.     }
  831.     SetControlBounds(mbPtr->userPane, &paneRect);
  832.     SetControlBounds(mbPtr->control, &cntrRect);
  833.     if (!mbPtr->useTkText) {
  834. Str255 controlTitle;
  835. ControlFontStyleRec fontStyle;
  836. Tk_Font font;
  837. int len;
  838. if (((mbPtr->info.image == NULL) && (mbPtr->info.bitmap == None))
  839. || (mbPtr->info.compound != COMPOUND_NONE)) {
  840.     len = TkFontGetFirstTextLayout(butPtr->textLayout,
  841.     &font, (char*) controlTitle);
  842.     controlTitle[len] = 0;
  843. } else {
  844.     len = 0;
  845.     controlTitle[0] = 0;
  846. }
  847. if (rebuild || bcmp(mbPtr->controlTitle, controlTitle, len+1)) {
  848.     CFStringRef cf = CFStringCreateWithCString(NULL,
  849.     (char*) controlTitle, kCFStringEncodingUTF8);
  850.     if (cf != NULL) {
  851. SetControlTitleWithCFString(mbPtr->control, cf);
  852. CFRelease(cf);
  853.     }
  854.     bcopy(controlTitle, mbPtr->controlTitle, len+1);
  855. }
  856. if (len) {
  857.     TkMacOSXInitControlFontStyle(font, &fontStyle);
  858.     if (bcmp(&mbPtr->fontStyle, &fontStyle, sizeof(fontStyle)) ) {
  859. ChkErr(SetControlFontStyle, mbPtr->control, &fontStyle);
  860. bcopy(&fontStyle, &mbPtr->fontStyle, sizeof(fontStyle));
  861.     }
  862. }
  863.     }
  864.     if (mbPtr->params.isBevel) {
  865. /*
  866.  * Initialiase the image/button parameters.
  867.  */
  868. SetupBevelButton(mbPtr, mbPtr->control, destPort, gc, pixmap);
  869.     }
  870.     if (butPtr->flags & SELECTED) {
  871. SetControlValue(mbPtr->control, 1);
  872. #if 0
  873.     } else if (butPtr->flags & TRISTATED) {
  874. SetControlValue(mbPtr->control, 2);
  875. #endif
  876.     } else {
  877. SetControlValue(mbPtr->control, 0);
  878.     }
  879.     active = ((mbPtr->flags & ACTIVE) != 0);
  880.     if (active != IsControlActive(mbPtr->control)) {
  881. if (active) {
  882.     ChkErr(ActivateControl, mbPtr->control);
  883. } else {
  884.     ChkErr(DeactivateControl, mbPtr->control);
  885. }
  886.     }
  887.     enabled = !(butPtr->state == STATE_DISABLED);
  888.     if (enabled != IsControlEnabled(mbPtr->control)) {
  889. if (enabled) {
  890.     ChkErr(EnableControl, mbPtr->control);
  891. } else {
  892.     ChkErr(DisableControl, mbPtr->control);
  893. }
  894.     }
  895.     if (active && enabled) {
  896. if (butPtr->state == STATE_ACTIVE) {
  897.     if (mbPtr->params.isBevel) {
  898. HiliteControl(mbPtr->control, kControlButtonPart);
  899.     } else {
  900. switch (butPtr->type) {
  901.     case TYPE_BUTTON:
  902. HiliteControl(mbPtr->control, kControlButtonPart);
  903. break;
  904.     case TYPE_RADIO_BUTTON:
  905. HiliteControl(mbPtr->control, kControlRadioButtonPart);
  906. break;
  907.     case TYPE_CHECK_BUTTON:
  908. HiliteControl(mbPtr->control, kControlCheckBoxPart);
  909. break;
  910. }
  911.     }
  912. } else {
  913.     HiliteControl(mbPtr->control, kControlNoPart);
  914. }
  915.     }
  916.     UpdateControlColors(mbPtr);
  917.     if (butPtr->type == TYPE_BUTTON && !mbPtr->params.isBevel) {
  918. Boolean isDefault;
  919. if (butPtr->defaultState == STATE_ACTIVE) {
  920.     isDefault = true;
  921. } else {
  922.     isDefault = false;
  923. }
  924. ChkErr(SetControlData, mbPtr->control, kControlNoPart,
  925. kControlPushButtonDefaultTag, sizeof(isDefault), &isDefault);
  926.     }
  927.     if (mbPtr->flags & FIRST_DRAW) {
  928. ShowControl(mbPtr->userPane);
  929. ShowControl(mbPtr->control);
  930. mbPtr->flags ^= FIRST_DRAW;
  931.     } else {
  932. SetControlVisibility(mbPtr->control, true, true);
  933. Draw1Control(mbPtr->userPane);
  934.     }
  935.     if (mbPtr->params.isBevel) {
  936. if (mbPtr->bevelButtonContent.contentType ==
  937. kControlContentPictHandle) {
  938.     KillPicture(mbPtr->bevelButtonContent.u.picture);
  939. }
  940.     }
  941. }
  942. /*
  943.  *--------------------------------------------------------------
  944.  *
  945.  * SetupBevelButton --
  946.  *
  947.  * Sets up the Bevel Button with image by copying the
  948.  * source image onto the PicHandle for the button.
  949.  *
  950.  * Results:
  951.  * None
  952.  *
  953.  * Side effects:
  954.  * The image or bitmap for the button is copied over to a picture.
  955.  *
  956.  *--------------------------------------------------------------
  957.  */
  958. void
  959. SetupBevelButton(
  960.     MacButton *mbPtr, /* Mac button. */
  961.     ControlRef controlHandle, /* The control to set this picture to. */
  962.     GWorldPtr destPort, /* Off screen GWorld. */
  963.     GC gc, /* The GC we are drawing into - needed for the
  964.  * bevel button. */
  965.     Pixmap pixmap) /* The pixmap we are drawing into - needed for
  966.  * the bevel button. */
  967. {
  968.     TkButton *butPtr = (TkButton *) mbPtr;
  969.     int height, width;
  970.     ControlButtonGraphicAlignment theAlignment;
  971.     CGrafPtr savePort;
  972.     Boolean portChanged = false;
  973.     if (butPtr->image != None) {
  974. Tk_SizeOfImage(butPtr->image, &width, &height);
  975.     } else {
  976. Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
  977.     }
  978.     if ((butPtr->width > 0) && (butPtr->width < width)) {
  979. width = butPtr->width;
  980.     }
  981.     if ((butPtr->height > 0) && (butPtr->height < height)) {
  982. height = butPtr->height;
  983.     }
  984.     {
  985. portChanged = QDSwapPort(destPort, &savePort);
  986. mbPtr->picParams.version = -2;
  987. mbPtr->picParams.hRes = 0x00480000;
  988. mbPtr->picParams.vRes = 0x00480000;
  989. mbPtr->picParams.srcRect.top = 0;
  990. mbPtr->picParams.srcRect.left = 0;
  991. mbPtr->picParams.srcRect.bottom = height;
  992. mbPtr->picParams.srcRect.right = width;
  993. mbPtr->picParams.reserved1 = 0;
  994. mbPtr->picParams.reserved2 = 0;
  995. mbPtr->bevelButtonContent.contentType = kControlContentPictHandle;
  996. mbPtr->bevelButtonContent.u.picture = OpenCPicture(&mbPtr->picParams);
  997. if (!mbPtr->bevelButtonContent.u.picture) {
  998.     TkMacOSXDbgMsg("OpenCPicture failed");
  999. }
  1000. tkPictureIsOpen = 1;
  1001. /*
  1002.  * TO DO - There is one case where XCopyPlane calls CopyDeepMask,
  1003.  * which does not get recorded in the picture. So the bitmap code
  1004.  * will fail in that case.
  1005.  */
  1006.      }
  1007.     if (butPtr->selectImage != NULL && (butPtr->flags & SELECTED)) {
  1008. Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, 0, 0);
  1009. #if 0
  1010.     } else if (butPtr->tristateImage != NULL && (butPtr->flags & TRISTATED)) {
  1011. Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, height, pixmap, 0,
  1012. 0);
  1013. #endif
  1014.     } else if (butPtr->image != NULL) {
  1015. Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, 0, 0);
  1016.     } else {
  1017. XSetClipOrigin(butPtr->display, gc, 0, 0);
  1018. XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0, width,
  1019. height, 0, 0, 1);
  1020.     }
  1021.     {
  1022. ClosePicture();
  1023. tkPictureIsOpen = 0;
  1024. if (portChanged) {
  1025.     QDSwapPort(savePort, NULL);
  1026. }
  1027.     }
  1028.     ChkErr(SetControlData, controlHandle, kControlButtonPart,
  1029.     kControlBevelButtonContentTag,
  1030.     sizeof(ControlButtonContentInfo),
  1031.     (char *) &mbPtr->bevelButtonContent);
  1032.     if (butPtr->anchor == TK_ANCHOR_N) {
  1033. theAlignment = kControlBevelButtonAlignTop;
  1034.     } else if (butPtr->anchor == TK_ANCHOR_NE) {
  1035. theAlignment = kControlBevelButtonAlignTopRight;
  1036.     } else if (butPtr->anchor == TK_ANCHOR_E) {
  1037. theAlignment = kControlBevelButtonAlignRight;
  1038.     } else if (butPtr->anchor == TK_ANCHOR_SE) {
  1039. theAlignment = kControlBevelButtonAlignBottomRight;
  1040.     } else if (butPtr->anchor == TK_ANCHOR_S) {
  1041. theAlignment = kControlBevelButtonAlignBottom;
  1042.     } else if (butPtr->anchor == TK_ANCHOR_SW) {
  1043. theAlignment = kControlBevelButtonAlignBottomLeft;
  1044.     } else if (butPtr->anchor == TK_ANCHOR_W) {
  1045. theAlignment = kControlBevelButtonAlignLeft;
  1046.     } else if (butPtr->anchor == TK_ANCHOR_NW) {
  1047. theAlignment = kControlBevelButtonAlignTopLeft;
  1048.     } else if (butPtr->anchor == TK_ANCHOR_CENTER) {
  1049. theAlignment = kControlBevelButtonAlignCenter;
  1050.     }
  1051.     ChkErr(SetControlData, controlHandle, kControlButtonPart,
  1052.     kControlBevelButtonGraphicAlignTag,
  1053.     sizeof(ControlButtonGraphicAlignment), (char *) &theAlignment);
  1054.     if (butPtr->compound != COMPOUND_NONE) {
  1055. ControlButtonTextPlacement thePlacement =
  1056. kControlBevelButtonPlaceNormally;
  1057. if (butPtr->compound == COMPOUND_TOP) {
  1058.     thePlacement = kControlBevelButtonPlaceBelowGraphic;
  1059. } else if (butPtr->compound == COMPOUND_BOTTOM) {
  1060.     thePlacement = kControlBevelButtonPlaceAboveGraphic;
  1061. } else if (butPtr->compound == COMPOUND_LEFT) {
  1062.     thePlacement = kControlBevelButtonPlaceToRightOfGraphic;
  1063. } else if (butPtr->compound == COMPOUND_RIGHT) {
  1064.     thePlacement = kControlBevelButtonPlaceToLeftOfGraphic;
  1065. }
  1066. ChkErr(SetControlData, controlHandle, kControlButtonPart,
  1067. kControlBevelButtonTextPlaceTag,
  1068. sizeof(ControlButtonTextPlacement), (char *) &thePlacement);
  1069.     }
  1070. }
  1071. /*
  1072.  *--------------------------------------------------------------
  1073.  *
  1074.  * SetUserPaneDrawProc --
  1075.  *
  1076.  * Utility function to add a UserPaneDrawProc
  1077.  * to a userPane control. From MoreControls code
  1078.  * from Apple DTS.
  1079.  *
  1080.  * Results:
  1081.  * MacOS system error.
  1082.  *
  1083.  * Side effects:
  1084.  * The user pane gets a new UserPaneDrawProc.
  1085.  *
  1086.  *--------------------------------------------------------------
  1087.  */
  1088. OSStatus
  1089. SetUserPaneDrawProc(
  1090.     ControlRef control,
  1091.     ControlUserPaneDrawProcPtr upp)
  1092. {
  1093.     ControlUserPaneDrawUPP myControlUserPaneDrawUPP;
  1094.     myControlUserPaneDrawUPP = NewControlUserPaneDrawUPP(upp);
  1095.     return SetControlData(control, kControlNoPart,
  1096.     kControlUserPaneDrawProcTag, sizeof(myControlUserPaneDrawUPP),
  1097.     (Ptr) &myControlUserPaneDrawUPP);
  1098. }
  1099. /*
  1100.  *--------------------------------------------------------------
  1101.  *
  1102.  * SetUserPaneSetUpSpecialBackgroundProc --
  1103.  *
  1104.  * Utility function to add a UserPaneBackgroundProc
  1105.  * to a userPane control
  1106.  *
  1107.  * Results:
  1108.  * MacOS system error.
  1109.  *
  1110.  * Side effects:
  1111.  * The user pane gets a new UserPaneBackgroundProc.
  1112.  *
  1113.  *--------------------------------------------------------------
  1114.  */
  1115. OSStatus
  1116. SetUserPaneSetUpSpecialBackgroundProc(
  1117.     ControlRef control,
  1118.     ControlUserPaneBackgroundProcPtr upp)
  1119. {
  1120.     ControlUserPaneBackgroundUPP myControlUserPaneBackgroundUPP;
  1121.     myControlUserPaneBackgroundUPP = NewControlUserPaneBackgroundUPP(upp);
  1122.     return SetControlData(control, kControlNoPart,
  1123.     kControlUserPaneBackgroundProcTag,
  1124.     sizeof(myControlUserPaneBackgroundUPP),
  1125.     (Ptr) &myControlUserPaneBackgroundUPP);
  1126. }
  1127. /*
  1128.  *--------------------------------------------------------------
  1129.  *
  1130.  * UserPaneDraw --
  1131.  *
  1132.  * This function draws the background of the user pane that will
  1133.  * lie under checkboxes and radiobuttons.
  1134.  *
  1135.  * Results:
  1136.  * None.
  1137.  *
  1138.  * Side effects:
  1139.  * The user pane gets updated to the current color.
  1140.  *
  1141.  *--------------------------------------------------------------
  1142.  */
  1143. void
  1144. UserPaneDraw(
  1145.     ControlRef control,
  1146.     ControlPartCode cpc)
  1147. {
  1148.     MacButton *mbPtr = (MacButton *)(intptr_t)GetControlReference(control);
  1149.     Rect contrlRect;
  1150.     CGrafPtr port;
  1151.     
  1152.     GetPort(&port);
  1153.     GetControlBounds(control,&contrlRect);
  1154.     TkMacOSXSetColorInPort(mbPtr->userPaneBackground, 0, NULL, port);
  1155.     EraseRect(&contrlRect);
  1156. }
  1157. /*
  1158.  *--------------------------------------------------------------
  1159.  *
  1160.  * UserPaneBackgroundProc --
  1161.  *
  1162.  * This function sets up the background of the user pane that will
  1163.  * lie under checkboxes and radiobuttons.
  1164.  *
  1165.  * Results:
  1166.  * None.
  1167.  *
  1168.  * Side effects:
  1169.  * The user pane background gets set to the current color.
  1170.  *
  1171.  *--------------------------------------------------------------
  1172.  */
  1173. void
  1174. UserPaneBackgroundProc(
  1175.     ControlHandle control,
  1176.     ControlBackgroundPtr info)
  1177. {
  1178.     MacButton * mbPtr = (MacButton *)(intptr_t)GetControlReference(control);
  1179.     if (info->colorDevice) {
  1180. CGrafPtr port;
  1181. GetPort(&port);
  1182. TkMacOSXSetColorInPort(mbPtr->userPaneBackground, 0, NULL, port);
  1183.     }
  1184. }
  1185. /*
  1186.  *--------------------------------------------------------------
  1187.  *
  1188.  * UpdateControlColors --
  1189.  *
  1190.  * This function will review the colors used to display
  1191.  * a Macintosh button. If any non-standard colors are
  1192.  * used we create a custom palette for the button, populate
  1193.  * with the colors for the button and install the palette.
  1194.  *
  1195.  * Under Appearance, we just set the pointer that will be
  1196.  * used by the UserPaneDrawProc.
  1197.  *
  1198.  * Results:
  1199.  * None.
  1200.  *
  1201.  * Side effects:
  1202.  * The Macintosh control may get a custom palette installed.
  1203.  *
  1204.  *--------------------------------------------------------------
  1205.  */
  1206. static int
  1207. UpdateControlColors(
  1208.     MacButton *mbPtr)
  1209. {
  1210.     XColor *xcolor;
  1211.     TkButton *butPtr = (TkButton *) mbPtr;
  1212.     /*
  1213.      * Under Appearance we cannot change the background of the
  1214.      * button itself. However, the color we are setting is the color
  1215.      * of the containing userPane. This will be the color that peeks
  1216.      * around the rounded corners of the button.
  1217.      * We make this the highlightbackground rather than the background,
  1218.      * because if you color the background of a frame containing a
  1219.      * button, you usually also color the highlightbackground as well,
  1220.      * or you will get a thin grey ring around the button.
  1221.      */
  1222.     if (butPtr->type == TYPE_BUTTON) {
  1223. xcolor = Tk_3DBorderColor(butPtr->highlightBorder);
  1224.     } else {
  1225. xcolor = Tk_3DBorderColor(butPtr->normalBorder);
  1226.     }
  1227.     mbPtr->userPaneBackground = xcolor->pixel;
  1228.     return false;
  1229. }
  1230. /*
  1231.  *--------------------------------------------------------------
  1232.  *
  1233.  * ButtonEventProc --
  1234.  *
  1235.  * This procedure is invoked by the Tk dispatcher for various
  1236.  * events on buttons.
  1237.  *
  1238.  * Results:
  1239.  * None.
  1240.  *
  1241.  * Side effects:
  1242.  * When it gets exposed, it is redisplayed.
  1243.  *
  1244.  *--------------------------------------------------------------
  1245.  */
  1246. static void
  1247. ButtonEventProc(
  1248.     ClientData clientData, /* Information about window. */
  1249.     XEvent *eventPtr) /* Information about event. */
  1250. {
  1251.     TkButton *buttonPtr = (TkButton *) clientData;
  1252.     MacButton *mbPtr = (MacButton *) clientData;
  1253.     if (eventPtr->type == ActivateNotify
  1254.     || eventPtr->type == DeactivateNotify) {
  1255. if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) {
  1256.     return;
  1257. }
  1258. if (eventPtr->type == ActivateNotify) {
  1259.     mbPtr->flags |= ACTIVE;
  1260. } else {
  1261.     mbPtr->flags &= ~ACTIVE;
  1262. }
  1263. if ((buttonPtr->flags & REDRAW_PENDING) == 0) {
  1264.     Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) buttonPtr);
  1265.     buttonPtr->flags |= REDRAW_PENDING;
  1266. }
  1267.     }
  1268. }
  1269. /*
  1270.  *----------------------------------------------------------------------
  1271.  *
  1272.  * TkMacOSXComputeControlParams --
  1273.  *
  1274.  * This procedure computes the various parameters used
  1275.  * when creating a Carbon control (NewControl).
  1276.  * These are determined by the various tk button parameters
  1277.  *
  1278.  * Results:
  1279.  * None.
  1280.  *
  1281.  * Side effects:
  1282.  * Sets the control initialisation parameters
  1283.  *
  1284.  *----------------------------------------------------------------------
  1285.  */
  1286. static void
  1287. TkMacOSXComputeControlParams(
  1288.     TkButton *butPtr,
  1289.     MacControlParams *paramsPtr)
  1290. {
  1291.     paramsPtr->isBevel = 0;
  1292.     /*
  1293.      * Determine ProcID based on button type and dimensions.
  1294.      */
  1295.     switch (butPtr->type) {
  1296. case TYPE_BUTTON:
  1297.     if ((butPtr->image == None) && (butPtr->bitmap == None)) {
  1298. paramsPtr->initialValue = 1;
  1299. paramsPtr->minValue = 0;
  1300. paramsPtr->maxValue = 1;
  1301. paramsPtr->procID = kControlPushButtonProc;
  1302.     } else {
  1303. paramsPtr->initialValue = 0;
  1304. paramsPtr->minValue = kControlBehaviorOffsetContents |
  1305. kControlContentPictHandle;
  1306. paramsPtr->maxValue = 1;
  1307. if (butPtr->borderWidth <= 2) {
  1308.     paramsPtr->procID = kControlBevelButtonSmallBevelProc;
  1309. } else if (butPtr->borderWidth == 3) {
  1310.     paramsPtr->procID = kControlBevelButtonNormalBevelProc;
  1311. } else {
  1312.     paramsPtr->procID = kControlBevelButtonLargeBevelProc;
  1313. }
  1314. paramsPtr->isBevel = 1;
  1315.     }
  1316.     break;
  1317. case TYPE_RADIO_BUTTON:
  1318.     if (((butPtr->image == None) && (butPtr->bitmap == None))
  1319. || (butPtr->indicatorOn)) {
  1320. paramsPtr->initialValue = 1;
  1321. paramsPtr->minValue = 0;
  1322. paramsPtr->maxValue = MAX_VALUE;
  1323. paramsPtr->procID = kControlRadioButtonProc;
  1324.     } else {
  1325. paramsPtr->initialValue = 0;
  1326. paramsPtr->minValue = kControlBehaviorOffsetContents |
  1327. kControlBehaviorSticky | kControlContentPictHandle;
  1328. paramsPtr->maxValue = MAX_VALUE;
  1329. if (butPtr->borderWidth <= 2) {
  1330.     paramsPtr->procID = kControlBevelButtonSmallBevelProc;
  1331. } else if (butPtr->borderWidth == 3) {
  1332.     paramsPtr->procID = kControlBevelButtonNormalBevelProc;
  1333. } else {
  1334.     paramsPtr->procID = kControlBevelButtonLargeBevelProc;
  1335. }
  1336. paramsPtr->isBevel = 1;
  1337.     }
  1338.     break;
  1339. case TYPE_CHECK_BUTTON:
  1340.     if (((butPtr->image == None) && (butPtr->bitmap == None))
  1341.     || (butPtr->indicatorOn)) {
  1342. paramsPtr->initialValue = 1;
  1343. paramsPtr->minValue = 0;
  1344. paramsPtr->maxValue = MAX_VALUE;
  1345. paramsPtr->procID = kControlCheckBoxProc;
  1346.     } else {
  1347. paramsPtr->initialValue = 0;
  1348. paramsPtr->minValue = kControlBehaviorOffsetContents |
  1349. kControlBehaviorSticky | kControlContentPictHandle;
  1350. paramsPtr->maxValue = MAX_VALUE;
  1351. if (butPtr->borderWidth <= 2) {
  1352.     paramsPtr->procID = kControlBevelButtonSmallBevelProc;
  1353. } else if (butPtr->borderWidth == 3) {
  1354.     paramsPtr->procID = kControlBevelButtonNormalBevelProc;
  1355. } else {
  1356.     paramsPtr->procID = kControlBevelButtonLargeBevelProc;
  1357. }
  1358. paramsPtr->isBevel = 1;
  1359.     }
  1360.     break;
  1361.     }
  1362. }
  1363. /*
  1364.  *----------------------------------------------------------------------
  1365.  *
  1366.  * TkMacOSXComputeDrawParams --
  1367.  *
  1368.  * This procedure computes the various parameters used
  1369.  * when drawing a button
  1370.  * These are determined by the various tk button parameters
  1371.  *
  1372.  * Results:
  1373.  * 1 if control will be used, 0 otherwise.
  1374.  *
  1375.  * Side effects:
  1376.  * Sets the button draw parameters
  1377.  *
  1378.  *----------------------------------------------------------------------
  1379.  */
  1380. static int
  1381. TkMacOSXComputeDrawParams(
  1382.     TkButton *butPtr,
  1383.     DrawParams *dpPtr)
  1384. {
  1385.     dpPtr->hasImageOrBitmap = ((butPtr->image != NULL)
  1386.     || (butPtr->bitmap != None));
  1387.     dpPtr->offset = (butPtr->type == TYPE_BUTTON)
  1388.     && dpPtr->hasImageOrBitmap;
  1389.     dpPtr->border = butPtr->normalBorder;
  1390.     if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
  1391. dpPtr->gc = butPtr->disabledGC;
  1392.     } else if (butPtr->type == TYPE_BUTTON && butPtr->state == STATE_ACTIVE) {
  1393. dpPtr->gc = butPtr->activeTextGC;
  1394. dpPtr->border = butPtr->activeBorder;
  1395.     } else {
  1396. dpPtr->gc = butPtr->normalTextGC;
  1397.     }
  1398.     if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE)
  1399.     && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
  1400. dpPtr->border = butPtr->selectBorder;
  1401.     }
  1402.     /*
  1403.      * Override the relief specified for the button if this is a
  1404.      * checkbutton or radiobutton and there's no indicator.
  1405.      * However, don't do this in the presence of Appearance, since
  1406.      * then the bevel button will take care of the relief.
  1407.      */
  1408.     dpPtr->relief = butPtr->relief;
  1409.     if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) {
  1410. if (!dpPtr->hasImageOrBitmap) {
  1411.     dpPtr->relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN
  1412.     : TK_RELIEF_RAISED;
  1413. }
  1414.     }
  1415.     /*
  1416.      * Determine the draw type
  1417.      */
  1418.     if (butPtr->type == TYPE_LABEL) {
  1419. dpPtr->drawType = DRAW_LABEL;
  1420.     } else if (butPtr->type == TYPE_BUTTON) {
  1421. if (!dpPtr->hasImageOrBitmap) {
  1422.     dpPtr->drawType = DRAW_CONTROL;
  1423. } else if (butPtr->image != None) {
  1424.     dpPtr->drawType = DRAW_BEVEL;
  1425. } else {
  1426.     /*
  1427.      * TO DO - The current way the we draw bitmaps (XCopyPlane)
  1428.      * uses CopyDeepMask in this one case. The Picture recording
  1429.      * does not record this call, and so we can't use the
  1430.      * Appearance bevel button here. The only case that would
  1431.      * exercise this is if you use a bitmap, with
  1432.      * -data & -mask specified. We should probably draw the
  1433.      * appearance button and overprint the image in this case.
  1434.      * This just punts and draws the old-style, ugly, button.
  1435.      */
  1436.     if (dpPtr->gc->clip_mask == 0) {
  1437. dpPtr->drawType = DRAW_BEVEL;
  1438.     } else {
  1439. TkpClipMask *clipPtr = (TkpClipMask *) dpPtr->gc->clip_mask;
  1440. if ((clipPtr->type == TKP_CLIP_PIXMAP) &&
  1441. (clipPtr->value.pixmap != butPtr->bitmap)) {
  1442.     dpPtr->drawType = DRAW_CUSTOM;
  1443. } else {
  1444.     dpPtr->drawType = DRAW_BEVEL;
  1445. }
  1446.     }
  1447. }
  1448.     } else if (butPtr->indicatorOn) {
  1449. dpPtr->drawType = DRAW_CONTROL;
  1450.     } else if (dpPtr->hasImageOrBitmap) {
  1451. if (dpPtr->gc->clip_mask == 0) {
  1452.     dpPtr->drawType = DRAW_BEVEL;
  1453. } else {
  1454.     TkpClipMask *clipPtr = (TkpClipMask*) dpPtr->gc->clip_mask;
  1455.     if ((clipPtr->type == TKP_CLIP_PIXMAP) &&
  1456.     (clipPtr->value.pixmap != butPtr->bitmap)) {
  1457. dpPtr->drawType = DRAW_CUSTOM;
  1458.     } else {
  1459. dpPtr->drawType = DRAW_BEVEL;
  1460.     }
  1461. }
  1462.     } else {
  1463. dpPtr->drawType = DRAW_CUSTOM;
  1464.     }
  1465.     if ((dpPtr->drawType == DRAW_CONTROL) || (dpPtr->drawType == DRAW_BEVEL)) {
  1466. return 1;
  1467.     } else {
  1468. return 0;
  1469.     }
  1470. }