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

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkMacOSXMenubutton.c --
  3.  *
  4.  * This file implements the Macintosh specific portion of the
  5.  * menubutton widget.
  6.  *
  7.  * Copyright (c) 1996 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: tkMacOSXMenubutton.c,v 1.2.2.12 2007/11/09 06:26:56 das Exp $
  15.  */
  16. #include "tkMacOSXPrivate.h"
  17. #include "tkMenu.h"
  18. #include "tkMenubutton.h"
  19. #include "tkMacOSXFont.h"
  20. #include "tkMacOSXDebug.h"
  21. #define kShadowOffset (3) /* amount to offset shadow from frame */
  22. #define kTriangleWidth (11) /* width of the triangle */
  23. #define kTriangleHeight (6) /* height of the triangle */
  24. #define kTriangleMargin (5) /* margin around triangle */
  25. #define TK_POPUP_OFFSET 32 /* size of popup marker */
  26. #define FIRST_DRAW     2
  27. #define ACTIVE     4
  28. MODULE_SCOPE int TkMacOSXGetNewMenuID(Tcl_Interp *interp, TkMenu *menuInstPtr,
  29. int cascade, short *menuIDPtr);
  30. MODULE_SCOPE void TkMacOSXFreeMenuID(short menuID);
  31. typedef struct {
  32.     SInt16 initialValue;
  33.     SInt16 minValue;
  34.     SInt16 maxValue;
  35.     SInt16 procID;
  36.     int isBevel;
  37. } MenuButtonControlParams;
  38. typedef struct {
  39.     int len;
  40.     Str255 title;
  41.     ControlFontStyleRec style;
  42. } ControlTitleParams;
  43. /*
  44.  * Declaration of Mac specific button structure.
  45.  */
  46. typedef struct MacMenuButton {
  47.     TkMenuButton info; /* Generic button info. */
  48.     WindowRef windowRef;
  49.     ControlRef userPane;
  50.     ControlRef control;
  51.     MenuRef menuRef;
  52.     unsigned long userPaneBackground;
  53.     int flags;
  54.     MenuButtonControlParams params;
  55.     ControlTitleParams titleParams;
  56.     ControlButtonContentInfo bevelButtonContent;
  57.     OpenCPicParams picParams;
  58. } MacMenuButton;
  59. /*
  60.  * Forward declarations for procedures defined later in this file:
  61.  */
  62. static OSStatus SetUserPaneDrawProc(ControlRef control,
  63. ControlUserPaneDrawProcPtr upp);
  64. static OSStatus SetUserPaneSetUpSpecialBackgroundProc(ControlRef control,
  65. ControlUserPaneBackgroundProcPtr upp);
  66. static void UserPaneDraw(ControlRef control, ControlPartCode cpc);
  67. static void UserPaneBackgroundProc(ControlHandle,
  68. ControlBackgroundPtr info);
  69. static int MenuButtonInitControl (MacMenuButton *mbPtr, Rect *paneRect,
  70. Rect *cntrRect );
  71. static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr);
  72. static int UpdateControlColors(MacMenuButton *mbPtr);
  73. static void ComputeMenuButtonControlParams(TkMenuButton *mbPtr,
  74. MenuButtonControlParams * paramsPtr);
  75. static void ComputeControlTitleParams(TkMenuButton *mbPtr,
  76. ControlTitleParams *paramsPtr);
  77. static void CompareControlTitleParams(ControlTitleParams *p1Ptr,
  78. ControlTitleParams *p2Ptr, int *titleChanged, int *styleChanged);
  79. /*
  80.  * The structure below defines menubutton class behavior by means of
  81.  * procedures that can be invoked from generic window code.
  82.  */
  83. Tk_ClassProcs tkpMenubuttonClass = {
  84.     sizeof(Tk_ClassProcs), /* size */
  85.     TkMenuButtonWorldChanged, /* worldChangedProc */
  86. };
  87. /*
  88.  *----------------------------------------------------------------------
  89.  *
  90.  * TkpCreateMenuButton --
  91.  *
  92.  * Allocate a new TkMenuButton structure.
  93.  *
  94.  * Results:
  95.  * Returns a newly allocated TkMenuButton structure.
  96.  *
  97.  * Side effects:
  98.  * Registers an event handler for the widget.
  99.  *
  100.  *----------------------------------------------------------------------
  101.  */
  102. TkMenuButton *
  103. TkpCreateMenuButton(
  104.     Tk_Window tkwin)
  105. {
  106.     MacMenuButton *mbPtr = (MacMenuButton *) ckalloc(sizeof(MacMenuButton));
  107.     Tk_CreateEventHandler(tkwin, ActivateMask,
  108.     MenuButtonEventProc, (ClientData) mbPtr);
  109.     mbPtr->flags = 0;
  110.     mbPtr->userPaneBackground = PIXEL_MAGIC << 24;
  111.     mbPtr->userPane = NULL;
  112.     mbPtr->control = NULL;
  113.     mbPtr->menuRef = NULL;
  114.     bzero(&mbPtr->params, sizeof(mbPtr->params));
  115.     bzero(&mbPtr->titleParams, sizeof(mbPtr->titleParams));
  116.     return (TkMenuButton *) mbPtr;
  117. }
  118. /*
  119.  *----------------------------------------------------------------------
  120.  *
  121.  * TkpDisplayMenuButton --
  122.  *
  123.  * This procedure is invoked to display a menubutton widget.
  124.  *
  125.  * Results:
  126.  * None.
  127.  *
  128.  * Side effects:
  129.  * Commands are output to X to display the menubutton in its
  130.  * current mode.
  131.  *
  132.  *----------------------------------------------------------------------
  133.  */
  134. void
  135. TkpDisplayMenuButton(
  136.     ClientData clientData) /* Information about widget. */
  137. {
  138.     TkMenuButton *butPtr = (TkMenuButton *) clientData;
  139.     Tk_Window tkwin = butPtr->tkwin;
  140.     TkWindow *winPtr;
  141.     Pixmap pixmap;
  142.     MacMenuButton *mbPtr = (MacMenuButton *) butPtr;
  143.     CGrafPtr destPort, savePort;
  144.     Boolean portChanged = false;
  145.     int hasImageOrBitmap = 0, width, height;
  146.     OSStatus err;
  147.     ControlButtonGraphicAlignment theAlignment;
  148.     Rect paneRect, cntrRect;
  149.     int active, enabled;
  150.     butPtr->flags &= ~REDRAW_PENDING;
  151.     if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  152. return;
  153.     }
  154.     pixmap = (Pixmap) Tk_WindowId(tkwin);
  155.     TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin));
  156.     winPtr = (TkWindow *)butPtr->tkwin;
  157.     paneRect.left = winPtr->privatePtr->xOff;
  158.     paneRect.top = winPtr->privatePtr->yOff;
  159.     paneRect.right = paneRect.left+Tk_Width(butPtr->tkwin);
  160.     paneRect.bottom = paneRect.top+Tk_Height(butPtr->tkwin);
  161.     cntrRect = paneRect;
  162.     cntrRect.left += butPtr->inset;
  163.     cntrRect.top += butPtr->inset;
  164.     cntrRect.right -= butPtr->inset;
  165.     cntrRect.bottom -= butPtr->inset;
  166.     if (mbPtr->userPane) {
  167. MenuButtonControlParams params;
  168. bzero(&params, sizeof(params));
  169. ComputeMenuButtonControlParams(butPtr, &params);
  170. if (
  171. #if 0
  172.     (winPtr->flags & TK_REBUILD_TOPLEVEL) ||
  173. #endif
  174.     bcmp(&params,&mbPtr->params,sizeof(params))) {
  175.     if (mbPtr->userPane) {
  176. DisposeControl(mbPtr->userPane);
  177. mbPtr->userPane = NULL;
  178. mbPtr->control = NULL;
  179.     }
  180. }
  181.     }
  182.     if (!mbPtr->userPane) {
  183. if (MenuButtonInitControl(mbPtr, &paneRect, &cntrRect)) {
  184.     TkMacOSXDbgMsg("Init Control failed");
  185.     return;
  186. }
  187.     }
  188.     SetControlBounds(mbPtr->userPane, &paneRect);
  189.     SetControlBounds(mbPtr->control, &cntrRect);
  190.     if (butPtr->image != None) {
  191. Tk_SizeOfImage(butPtr->image, &width, &height);
  192. hasImageOrBitmap = 1;
  193.     } else if (butPtr->bitmap != None) {
  194. Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
  195. hasImageOrBitmap = 1;
  196.     }
  197.     /*
  198.      * We need to cache the title and its style
  199.      */
  200.     if (!(mbPtr->flags & FIRST_DRAW)) {
  201. ControlTitleParams titleParams;
  202. int titleChanged;
  203. int styleChanged;
  204. ComputeControlTitleParams(butPtr, &titleParams);
  205. CompareControlTitleParams(&titleParams, &mbPtr->titleParams,
  206. &titleChanged, &styleChanged);
  207. if (titleChanged) {
  208.     CFStringRef cf = CFStringCreateWithCString(NULL,
  209.   (char*) titleParams.title, kCFStringEncodingUTF8);
  210.     if (hasImageOrBitmap) {
  211. SetControlTitleWithCFString(mbPtr->control, cf);
  212.     } else {
  213. SetMenuItemTextWithCFString(mbPtr->menuRef, 1, cf);
  214.     }
  215.     CFRelease(cf);
  216.     bcopy(titleParams.title, mbPtr->titleParams.title,
  217.     titleParams.len + 1);
  218.     mbPtr->titleParams.len = titleParams.len;
  219. }
  220. if ((titleChanged||styleChanged) && titleParams .len) {
  221.     if (hasImageOrBitmap) {
  222. err = ChkErr(SetControlFontStyle, mbPtr->control,
  223. &titleParams.style);
  224. if (err != noErr) {
  225.     return;
  226. }
  227.     }
  228.     bcopy(&titleParams.style, &mbPtr->titleParams.style,
  229.     sizeof(titleParams.style));
  230. }
  231.     }
  232.     if (hasImageOrBitmap) {
  233. {
  234.     destPort = TkMacOSXGetDrawablePort(Tk_WindowId(tkwin));
  235.     portChanged = QDSwapPort(destPort, &savePort);
  236.     mbPtr->picParams.version = -2;
  237.     mbPtr->picParams.hRes = 0x00480000;
  238.     mbPtr->picParams.vRes = 0x00480000;
  239.     mbPtr->picParams.srcRect.top = 0;
  240.     mbPtr->picParams.srcRect.left = 0;
  241.     mbPtr->picParams.srcRect.bottom = height;
  242.     mbPtr->picParams.srcRect.right = width;
  243.     mbPtr->picParams.reserved1 = 0;
  244.     mbPtr->picParams.reserved2 = 0;
  245.     mbPtr->bevelButtonContent.contentType = kControlContentPictHandle;
  246.     mbPtr->bevelButtonContent.u.picture = OpenCPicture(&mbPtr->picParams);
  247.     if (!mbPtr->bevelButtonContent.u.picture) {
  248. TkMacOSXDbgMsg("OpenCPicture failed");
  249.     }
  250.     tkPictureIsOpen = 1;
  251.     /*
  252.      * TO DO - There is one case where XCopyPlane calls CopyDeepMask,
  253.      * which does not get recorded in the picture. So the bitmap code
  254.      * will fail in that case.
  255.      */
  256. }
  257. if (butPtr->image != NULL) {
  258.     Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, 0, 0);
  259. } else {
  260.     GC gc;
  261.     
  262.     if (butPtr->state == STATE_DISABLED) {
  263. gc = butPtr->disabledGC;
  264.     } else if (butPtr->state == STATE_ACTIVE) {
  265. gc = butPtr->activeTextGC;
  266.     } else {
  267. gc = butPtr->normalTextGC;
  268.     }
  269.     XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
  270.     width, height, 0, 0, 1);
  271. }
  272. {
  273.     ClosePicture();
  274.     tkPictureIsOpen = 0;
  275.     if (portChanged) {
  276. QDSwapPort(savePort, NULL);
  277.     }
  278. }
  279. ChkErr(SetControlData, mbPtr->control, kControlButtonPart,
  280. kControlBevelButtonContentTag,
  281. sizeof(ControlButtonContentInfo),
  282. (char *) &mbPtr->bevelButtonContent);
  283. switch (butPtr->anchor) {
  284.     case TK_ANCHOR_N:
  285. theAlignment = kControlBevelButtonAlignTop;
  286. break;
  287.     case TK_ANCHOR_NE:
  288. theAlignment = kControlBevelButtonAlignTopRight;
  289. break;
  290.     case TK_ANCHOR_E:
  291. theAlignment = kControlBevelButtonAlignRight;
  292. break;
  293.     case TK_ANCHOR_SE:
  294. theAlignment = kControlBevelButtonAlignBottomRight;
  295. break;
  296.     case TK_ANCHOR_S:
  297. theAlignment = kControlBevelButtonAlignBottom;
  298. break;
  299.     case TK_ANCHOR_SW:
  300. theAlignment = kControlBevelButtonAlignBottomLeft;
  301. break;
  302.     case TK_ANCHOR_W:
  303. theAlignment = kControlBevelButtonAlignLeft;
  304. break;
  305.     case TK_ANCHOR_NW:
  306. theAlignment = kControlBevelButtonAlignTopLeft;
  307. break;
  308.     case TK_ANCHOR_CENTER:
  309. theAlignment = kControlBevelButtonAlignCenter;
  310. break;
  311. }
  312. ChkErr(SetControlData, mbPtr->control, kControlButtonPart,
  313. kControlBevelButtonGraphicAlignTag,
  314. sizeof(ControlButtonGraphicAlignment), (char *) &theAlignment);
  315.     }
  316.     active = ((mbPtr->flags & ACTIVE) != 0);
  317.     if (active != IsControlActive(mbPtr->control)) {
  318. if (active) {
  319.     ChkErr(ActivateControl, mbPtr->control);
  320. } else {
  321.     ChkErr(DeactivateControl, mbPtr->control);
  322. }
  323.     }
  324.     enabled = !(butPtr->state == STATE_DISABLED);
  325.     if (enabled != IsControlEnabled(mbPtr->control)) {
  326. if (enabled) {
  327.     ChkErr(EnableControl, mbPtr->control);
  328. } else {
  329.     ChkErr(DisableControl, mbPtr->control);
  330. }
  331.     }
  332.     if (active && enabled) {
  333. if (butPtr->state == STATE_ACTIVE) {
  334.     if (hasImageOrBitmap) {
  335. HiliteControl(mbPtr->control, kControlButtonPart);
  336.     } else {
  337. HiliteControl(mbPtr->control, kControlLabelPart);
  338.     }
  339. } else {
  340.     HiliteControl(mbPtr->control, kControlNoPart);
  341. }
  342.     }
  343.     UpdateControlColors(mbPtr);
  344.     if (mbPtr->flags & FIRST_DRAW) {
  345. ShowControl(mbPtr->control);
  346. ShowControl(mbPtr->userPane);
  347. mbPtr->flags ^= FIRST_DRAW;
  348.     } else {
  349. SetControlVisibility(mbPtr->control, true, true);
  350. Draw1Control(mbPtr->userPane);
  351.     }
  352.     if (hasImageOrBitmap) {
  353. if (mbPtr->bevelButtonContent.contentType ==
  354. kControlContentPictHandle) {
  355.     KillPicture(mbPtr->bevelButtonContent.u.picture);
  356. }
  357.     }
  358. }
  359. /*
  360.  *----------------------------------------------------------------------
  361.  *
  362.  * TkpDestroyMenuButton --
  363.  *
  364.  * Free data structures associated with the menubutton control.
  365.  *
  366.  * Results:
  367.  * None.
  368.  *
  369.  * Side effects:
  370.  * Restores the default control state.
  371.  *
  372.  *----------------------------------------------------------------------
  373.  */
  374. void
  375. TkpDestroyMenuButton(
  376.     TkMenuButton *mbPtr)
  377. {
  378.     MacMenuButton *macMbPtr = (MacMenuButton *) mbPtr;
  379.     if (macMbPtr->userPane) {
  380. DisposeControl(macMbPtr->userPane);
  381. macMbPtr->userPane = NULL;
  382.     }
  383.     if (macMbPtr->menuRef) {
  384. short menuID = GetMenuID(macMbPtr->menuRef);
  385. TkMacOSXFreeMenuID(menuID);
  386. DisposeMenu(macMbPtr->menuRef);
  387. macMbPtr->menuRef = NULL;
  388.     }
  389. }
  390. /*
  391.  *----------------------------------------------------------------------
  392.  *
  393.  * TkpComputeMenuButtonGeometry --
  394.  *
  395.  * After changes in a menu button's text or bitmap, this procedure
  396.  * recomputes the menu button's geometry and passes this information
  397.  * along to the geometry manager for the window.
  398.  *
  399.  * Results:
  400.  * None.
  401.  *
  402.  * Side effects:
  403.  * The menu button's window may change size.
  404.  *
  405.  *----------------------------------------------------------------------
  406.  */
  407. void
  408. TkpComputeMenuButtonGeometry(mbPtr)
  409.     register TkMenuButton *mbPtr; /* Widget record for menu button. */
  410. {
  411.     int width, height, mm, pixels;
  412.     int hasImageOrBitmap = 0;
  413.     mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth;
  414.     if (mbPtr->image != None) {
  415. Tk_SizeOfImage(mbPtr->image, &width, &height);
  416. hasImageOrBitmap = 1;
  417.     } else if (mbPtr->bitmap != None) {
  418. Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
  419. hasImageOrBitmap = 1;
  420.     } else {
  421. hasImageOrBitmap = 0;
  422. Tk_FreeTextLayout(mbPtr->textLayout);
  423. mbPtr->textLayout = Tk_ComputeTextLayout(mbPtr->tkfont, mbPtr->text,
  424. -1, mbPtr->wrapLength, mbPtr->justify, 0, &mbPtr->textWidth,
  425. &mbPtr->textHeight);
  426. width = mbPtr->textWidth;
  427. height = mbPtr->textHeight;
  428. if (mbPtr->width > 0) {
  429.     width = mbPtr->width * Tk_TextWidth(mbPtr->tkfont, "0", 1);
  430. }
  431. if (mbPtr->height > 0) {
  432.     Tk_FontMetrics fm;
  433.     Tk_GetFontMetrics(mbPtr->tkfont, &fm);
  434.     height = mbPtr->height * fm.linespace;
  435. }
  436. width += 2*mbPtr->padX;
  437. height += 2*mbPtr->padY;
  438.     }
  439.     if (hasImageOrBitmap) {
  440. if (mbPtr->width > 0) {
  441.     width = mbPtr->width;
  442. }
  443. if (mbPtr->height > 0) {
  444.     height = mbPtr->height;
  445. }
  446. mbPtr->inset = mbPtr->highlightWidth + 2;
  447. width += (2 * mbPtr->borderWidth + 4);
  448. height += (2 * mbPtr->borderWidth + 4);
  449.     } else {
  450. width += TK_POPUP_OFFSET;
  451.     }
  452.     if (mbPtr->indicatorOn) {
  453. mm = WidthMMOfScreen(Tk_Screen(mbPtr->tkwin));
  454. pixels = WidthOfScreen(Tk_Screen(mbPtr->tkwin));
  455. mbPtr->indicatorHeight = kTriangleHeight;
  456. mbPtr->indicatorWidth = kTriangleWidth + kTriangleMargin;
  457. width += mbPtr->indicatorWidth;
  458.     } else {
  459. mbPtr->indicatorHeight = 0;
  460. mbPtr->indicatorWidth = 0;
  461.     }
  462.     Tk_GeometryRequest(mbPtr->tkwin, (int) (width + 2*mbPtr->inset),
  463.     (int) (height + 2*mbPtr->inset));
  464.     Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset);
  465. }
  466. /*
  467.  *----------------------------------------------------------------------
  468.  *
  469.  * ComputeMenuButtonControlParams --
  470.  *
  471.  * This procedure computes the various parameters used
  472.  * when creating a Carbon control (NewControl)
  473.  * These are determined by the various tk menu button parameters
  474.  *
  475.  * Results:
  476.  * None.
  477.  *
  478.  * Side effects:
  479.  * Sets the control initialisation parameters
  480.  *
  481.  *----------------------------------------------------------------------
  482.  */
  483. static void
  484. ComputeMenuButtonControlParams(
  485.     TkMenuButton *mbPtr,
  486.     MenuButtonControlParams *paramsPtr)
  487. {
  488.     int fakeMenuID = 256;
  489.     /*
  490.      * Determine ProcID based on button type and dimensions
  491.      *
  492.      * We need to set minValue to some non-zero value,
  493.      * Otherwise, the markers do not show up
  494.      */
  495.     paramsPtr->minValue = kControlBehaviorMultiValueMenu;
  496.     paramsPtr->maxValue = 0;
  497.     if (mbPtr->image || mbPtr->bitmap) {
  498. paramsPtr->isBevel = 1;
  499. if (mbPtr->borderWidth <= 2) {
  500.     paramsPtr->procID = kControlBevelButtonSmallBevelProc;
  501. } else if (mbPtr->borderWidth == 3) {
  502.     paramsPtr->procID = kControlBevelButtonNormalBevelProc;
  503. } else {
  504.     paramsPtr->procID = kControlBevelButtonLargeBevelProc;
  505. }
  506. if (mbPtr->indicatorOn) {
  507.     paramsPtr->initialValue = fakeMenuID;
  508. } else {
  509.     paramsPtr->initialValue = 0;
  510. }
  511.     } else {
  512. paramsPtr->isBevel = 0;
  513. paramsPtr->procID = kControlPopupButtonProc
  514. + kControlPopupVariableWidthVariant;
  515. paramsPtr->minValue = -12345;
  516. paramsPtr->maxValue = -1;
  517. paramsPtr->initialValue = 0;
  518.     }
  519. }
  520. /*
  521.  *----------------------------------------------------------------------
  522.  *
  523.  * returns 0 if same, 1 otherwise
  524.  *
  525.  *----------------------------------------------------------------------
  526.  */
  527. static void
  528. CompareControlTitleParams(
  529.     ControlTitleParams *p1Ptr,
  530.     ControlTitleParams *p2Ptr,
  531.     int *titleChanged,
  532.     int *styleChanged)
  533. {
  534.     if (p1Ptr->len != p2Ptr->len) {
  535. *titleChanged = 1;
  536.     } else if (bcmp(p1Ptr->title,p2Ptr->title,p1Ptr->len)) {
  537. *titleChanged = 1;
  538.     } else {
  539. *titleChanged = 0;
  540.     }
  541.     if (p1Ptr->len && p2Ptr->len) {
  542. *styleChanged = bcmp(&p1Ptr->style, &p2Ptr->style,
  543. sizeof(p2Ptr->style));
  544.     } else {
  545. *styleChanged = p1Ptr->len||p2Ptr->len;
  546.     }
  547. }
  548. static void
  549. ComputeControlTitleParams(
  550.     TkMenuButton *butPtr,
  551.     ControlTitleParams *paramsPtr)
  552. {
  553.     Tk_Font font;
  554.     paramsPtr->len = TkFontGetFirstTextLayout(butPtr->textLayout, &font,
  555.     (char*) paramsPtr->title);
  556.     paramsPtr->title[paramsPtr->len] = 0;
  557.     if (paramsPtr->len) {
  558. TkMacOSXInitControlFontStyle(font,&paramsPtr->style);
  559.     }
  560. }
  561. /*
  562.  *----------------------------------------------------------------------
  563.  *
  564.  * MenuButtonInitControl --
  565.  *
  566.  * This procedure initialises a Carbon control
  567.  *
  568.  * Results:
  569.  * 0 on success, 1 on failure.
  570.  *
  571.  * Side effects:
  572.  * A background pane control and the control itself is created
  573.  * The contol is embedded in the background control
  574.  * The background control is embedded in the root control
  575.  * of the containing window
  576.  * The creation parameters for the control are also computed
  577.  *
  578.  *----------------------------------------------------------------------
  579.  */
  580. int
  581. MenuButtonInitControl(
  582.     MacMenuButton *mbPtr, /* Mac button. */
  583.     Rect *paneRect,
  584.     Rect *cntrRect)
  585. {
  586.     OSStatus err;
  587.     TkMenuButton *butPtr = (TkMenuButton *) mbPtr;
  588.     SInt16 procID, initialValue, minValue, maxValue;
  589.     Boolean initiallyVisible;
  590.     SInt32 controlReference;
  591.     short menuID;
  592.     ControlRef rootControl =
  593.     TkMacOSXGetRootControl(Tk_WindowId(butPtr->tkwin));
  594.     mbPtr->windowRef = TkMacOSXDrawableWindow(Tk_WindowId(butPtr->tkwin));
  595.     /*
  596.      * Set up the user pane
  597.      */
  598.     initiallyVisible = false;
  599.     initialValue = kControlSupportsEmbedding | kControlHasSpecialBackground;
  600.     minValue = 0;
  601.     maxValue = 1;
  602.     procID = kControlUserPaneProc;
  603.     controlReference = (SInt32)mbPtr;
  604.     mbPtr->userPane = NewControl(mbPtr->windowRef, paneRect, "p",
  605.     initiallyVisible, initialValue, minValue, maxValue, procID,
  606.     controlReference);
  607.     if (!mbPtr->userPane) {
  608. TkMacOSXDbgMsg("Failed to create user pane control");
  609. return 1;
  610.     }
  611.     err = ChkErr(EmbedControl, mbPtr->userPane, rootControl);
  612.     if (err != noErr) {
  613. return 1;
  614.     }
  615.     SetUserPaneSetUpSpecialBackgroundProc(mbPtr->userPane,
  616.     UserPaneBackgroundProc);
  617.     SetUserPaneDrawProc(mbPtr->userPane,UserPaneDraw);
  618.     initiallyVisible = false;
  619.     ComputeMenuButtonControlParams(butPtr,&mbPtr->params);
  620.     /*
  621.      * Do this only if we are using bevel buttons.
  622.      */
  623.     ComputeControlTitleParams(butPtr, &mbPtr->titleParams);
  624.     mbPtr->control = NewControl(mbPtr->windowRef,
  625.     cntrRect, "p" /* mbPtr->titleParams.title */,
  626.     initiallyVisible, mbPtr->params.initialValue,
  627.     mbPtr->params.minValue, mbPtr->params.maxValue,
  628.     mbPtr->params.procID, controlReference);
  629.     if (!mbPtr->control) {
  630. TkMacOSXDbgMsg("Failed to create control of type %d",
  631. mbPtr->params.procID);
  632. return 1;
  633.     }
  634.     err = ChkErr(EmbedControl, mbPtr->control, mbPtr->userPane);
  635.     if (err != noErr ) {
  636. return 1;
  637.     }
  638.     if (mbPtr->params.isBevel) {
  639. CFStringRef cf = CFStringCreateWithCString(NULL,
  640. (char*) mbPtr->titleParams.title, kCFStringEncodingUTF8);
  641. SetControlTitleWithCFString(mbPtr->control, cf);
  642. CFRelease(cf);
  643. if (mbPtr->titleParams.len) {
  644.     err = ChkErr(SetControlFontStyle, mbPtr->control,
  645.     &mbPtr->titleParams.style);
  646.     if (err != noErr) {
  647. return 1;
  648.     }
  649. }
  650.     } else {
  651. CFStringRef cfStr;
  652. err = TkMacOSXGetNewMenuID(mbPtr->info.interp, (TkMenu *) mbPtr, 0,
  653. &menuID);
  654. if (err != TCL_OK) {
  655.     return 1;
  656. }
  657. err = ChkErr(CreateNewMenu, menuID, kMenuAttrDoNotUseUserCommandKeys,
  658. &(mbPtr->menuRef));
  659. if (err != noErr) {
  660.     return 1;
  661. }
  662. cfStr = CFStringCreateWithCString(NULL, Tk_PathName(mbPtr->info.tkwin),
  663. kCFStringEncodingUTF8);
  664. if (!cfStr) {
  665.     TkMacOSXDbgMsg("CFStringCreateWithCString failed");
  666.     return 1;
  667. }
  668. err = ChkErr(SetMenuTitleWithCFString, mbPtr->menuRef, cfStr);
  669. CFRelease(cfStr);
  670. if (err != noErr) {
  671.     return 1;
  672. }
  673. cfStr = CFStringCreateWithCString(NULL,
  674. (char*) mbPtr->titleParams.title, kCFStringEncodingUTF8);
  675. AppendMenuItemText(mbPtr->menuRef, "px");
  676. if (cfStr) {
  677.     SetMenuItemTextWithCFString(mbPtr->menuRef, 1, cfStr);
  678.     CFRelease(cfStr);
  679. }
  680. ChkErr(SetControlData, mbPtr->control, kControlNoPart,
  681. kControlPopupButtonMenuRefTag, sizeof(mbPtr->menuRef),
  682. &mbPtr->menuRef);
  683. SetControlMinimum(mbPtr->control, 1);
  684. SetControlMaximum(mbPtr->control, 1);
  685. SetControlValue(mbPtr->control, 1);
  686.     }
  687.     mbPtr->flags |= FIRST_DRAW;
  688.     if (IsWindowActive(mbPtr->windowRef)) {
  689. mbPtr->flags |= ACTIVE;
  690.     }
  691.     return 0;
  692. }
  693. /*
  694.  *--------------------------------------------------------------
  695.  *
  696.  * SetUserPane
  697.  *
  698.  * Utility function to add a UserPaneDrawProc
  699.  * to a userPane control. From MoreControls code
  700.  * from Apple DTS.
  701.  *
  702.  * Results:
  703.  * MacOS system error.
  704.  *
  705.  * Side effects:
  706.  * The user pane gets a new UserPaneDrawProc.
  707.  *
  708.  *--------------------------------------------------------------
  709.  */
  710. OSStatus
  711. SetUserPaneDrawProc(
  712.     ControlRef control,
  713.     ControlUserPaneDrawProcPtr upp)
  714. {
  715.     ControlUserPaneDrawUPP myControlUserPaneDrawUPP =
  716.     NewControlUserPaneDrawUPP(upp);
  717.     return SetControlData(control, kControlNoPart,kControlUserPaneDrawProcTag,
  718.     sizeof(myControlUserPaneDrawUPP), (Ptr)&myControlUserPaneDrawUPP);
  719. }
  720. /*
  721.  *--------------------------------------------------------------
  722.  *
  723.  * SetUserPaneSetUpSpecialBackgroundProc --
  724.  *
  725.  * Utility function to add a UserPaneBackgroundProc
  726.  * to a userPane control
  727.  *
  728.  * Results:
  729.  * MacOS system error.
  730.  *
  731.  * Side effects:
  732.  * The user pane gets a new UserPaneBackgroundProc.
  733.  *
  734.  *--------------------------------------------------------------
  735.  */
  736. OSStatus
  737. SetUserPaneSetUpSpecialBackgroundProc(
  738.     ControlRef control,
  739.     ControlUserPaneBackgroundProcPtr upp)
  740. {
  741.     ControlUserPaneBackgroundUPP myControlUserPaneBackgroundUPP =
  742.     NewControlUserPaneBackgroundUPP(upp);
  743.     return SetControlData(control, kControlNoPart,
  744. kControlUserPaneBackgroundProcTag,
  745. sizeof(myControlUserPaneBackgroundUPP),
  746. (Ptr) &myControlUserPaneBackgroundUPP);
  747. }
  748. /*
  749.  *--------------------------------------------------------------
  750.  *
  751.  * UserPaneDraw --
  752.  *
  753.  * This function draws the background of the user pane that will
  754.  * lie under checkboxes and radiobuttons.
  755.  *
  756.  * Results:
  757.  * None.
  758.  *
  759.  * Side effects:
  760.  * The user pane gets updated to the current color.
  761.  *
  762.  *--------------------------------------------------------------
  763.  */
  764. void
  765. UserPaneDraw(
  766.     ControlRef control,
  767.     ControlPartCode cpc)
  768. {
  769.     Rect contrlRect;
  770.     MacMenuButton * mbPtr =
  771.     (MacMenuButton *)(intptr_t)GetControlReference(control);
  772.     CGrafPtr port;
  773.     GetPort(&port);
  774.     GetControlBounds(control,&contrlRect);
  775.     TkMacOSXSetColorInPort(mbPtr->userPaneBackground, 0, NULL, port);
  776.     EraseRect (&contrlRect);
  777. }
  778. /*
  779.  *--------------------------------------------------------------
  780.  *
  781.  * UserPaneBackgroundProc --
  782.  *
  783.  * This function sets up the background of the user pane that will
  784.  * lie under checkboxes and radiobuttons.
  785.  *
  786.  * Results:
  787.  * None.
  788.  *
  789.  * Side effects:
  790.  * The user pane background gets set to the current color.
  791.  *
  792.  *--------------------------------------------------------------
  793.  */
  794. void
  795. UserPaneBackgroundProc(
  796.     ControlHandle control,
  797.     ControlBackgroundPtr info)
  798. {
  799.     MacMenuButton *mbPtr =
  800.     (MacMenuButton *)(intptr_t)GetControlReference(control);
  801.     if (info->colorDevice) {
  802. CGrafPtr port;
  803. GetPort(&port);
  804. TkMacOSXSetColorInPort(mbPtr->userPaneBackground, 0, NULL, port);
  805.     }
  806. }
  807. /*
  808.  *--------------------------------------------------------------
  809.  *
  810.  * UpdateControlColors --
  811.  *
  812.  * This function will review the colors used to display
  813.  * a Macintosh button. If any non-standard colors are
  814.  * used we create a custom palette for the button, populate
  815.  * with the colors for the button and install the palette.
  816.  *
  817.  * Under Appearance, we just set the pointer that will be
  818.  * used by the UserPaneDrawProc.
  819.  *
  820.  * Results:
  821.  * None.
  822.  *
  823.  * Side effects:
  824.  * The Macintosh control may get a custom palette installed.
  825.  *
  826.  *--------------------------------------------------------------
  827.  */
  828. static int
  829. UpdateControlColors(
  830.     MacMenuButton *mbPtr)
  831. {
  832.     XColor *xcolor;
  833.     TkMenuButton * butPtr = (TkMenuButton *) mbPtr;
  834.     /*
  835.      * Under Appearance we cannot change the background of the
  836.      * button itself. However, the color we are setting is the color
  837.      * of the containing userPane. This will be the color that peeks
  838.      * around the rounded corners of the button.
  839.      * We make this the highlightbackground rather than the background,
  840.      * because if you color the background of a frame containing a
  841.      * button, you usually also color the highlightbackground as well,
  842.      * or you will get a thin grey ring around the button.
  843.      */
  844.     xcolor = Tk_3DBorderColor(butPtr->normalBorder);
  845.     mbPtr->userPaneBackground = xcolor->pixel;
  846.     return false;
  847. }
  848. /*
  849.  *--------------------------------------------------------------
  850.  *
  851.  * MenuButtonEventProc --
  852.  *
  853.  * This procedure is invoked by the Tk dispatcher for various
  854.  * events on buttons.
  855.  *
  856.  * Results:
  857.  * None.
  858.  *
  859.  * Side effects:
  860.  * When it gets exposed, it is redisplayed.
  861.  *
  862.  *--------------------------------------------------------------
  863.  */
  864. static void
  865. MenuButtonEventProc(
  866.     ClientData clientData, /* Information about window. */
  867.     XEvent *eventPtr) /* Information about event. */
  868. {
  869.     TkMenuButton *buttonPtr = (TkMenuButton *) clientData;
  870.     MacMenuButton *mbPtr = (MacMenuButton *) clientData;
  871.     if (eventPtr->type == ActivateNotify
  872.     || eventPtr->type == DeactivateNotify) {
  873. if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) {
  874.     return;
  875. }
  876. if (eventPtr->type == ActivateNotify) {
  877.     mbPtr->flags |= ACTIVE;
  878. } else {
  879.     mbPtr->flags &= ~ACTIVE;
  880. }
  881. if ((buttonPtr->flags & REDRAW_PENDING) == 0) {
  882.     Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) buttonPtr);
  883.     buttonPtr->flags |= REDRAW_PENDING;
  884. }
  885.     }
  886. }