diff options
Diffstat (limited to 'carbon/tkMacOSXMenubutton.c')
-rw-r--r-- | carbon/tkMacOSXMenubutton.c | 962 |
1 files changed, 962 insertions, 0 deletions
diff --git a/carbon/tkMacOSXMenubutton.c b/carbon/tkMacOSXMenubutton.c new file mode 100644 index 0000000..7eb513e --- /dev/null +++ b/carbon/tkMacOSXMenubutton.c @@ -0,0 +1,962 @@ +/* + * tkMacOSXMenubutton.c -- + * + * This file implements the Macintosh specific portion of the + * menubutton widget. + * + * Copyright (c) 1996 by Sun Microsystems, Inc. + * Copyright 2001, Apple Computer, Inc. + * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net> + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkMacOSXMenubutton.c,v 1.1 2009/06/26 01:42:47 das Exp $ + */ + +#include "tkMacOSXPrivate.h" +#include "tkMenu.h" +#include "tkMenubutton.h" +#include "tkMacOSXFont.h" +#include "tkMacOSXDebug.h" + +#define kShadowOffset (3) /* amount to offset shadow from frame */ +#define kTriangleWidth (11) /* width of the triangle */ +#define kTriangleHeight (6) /* height of the triangle */ +#define kTriangleMargin (5) /* margin around triangle */ + +#define TK_POPUP_OFFSET 32 /* size of popup marker */ + +#define FIRST_DRAW 2 +#define ACTIVE 4 + +MODULE_SCOPE int TkMacOSXGetNewMenuID(Tcl_Interp *interp, TkMenu *menuInstPtr, + int cascade, short *menuIDPtr); +MODULE_SCOPE void TkMacOSXFreeMenuID(short menuID); + +typedef struct { + SInt16 initialValue; + SInt16 minValue; + SInt16 maxValue; + SInt16 procID; + int isBevel; +} MenuButtonControlParams; + +typedef struct { + int len; + Str255 title; + ControlFontStyleRec style; +} ControlTitleParams; + +/* + * Declaration of Mac specific button structure. + */ + +typedef struct MacMenuButton { + TkMenuButton info; /* Generic button info. */ + WindowRef windowRef; + ControlRef userPane; + ControlRef control; + MenuRef menuRef; + unsigned long userPaneBackground; + int flags; + MenuButtonControlParams params; + ControlTitleParams titleParams; + ControlButtonContentInfo bevelButtonContent; + OpenCPicParams picParams; +} MacMenuButton; + +/* + * Forward declarations for procedures defined later in this file: + */ + +static OSStatus SetUserPaneDrawProc(ControlRef control, + ControlUserPaneDrawProcPtr upp); +static OSStatus SetUserPaneSetUpSpecialBackgroundProc(ControlRef control, + ControlUserPaneBackgroundProcPtr upp); +static void UserPaneDraw(ControlRef control, ControlPartCode cpc); +static void UserPaneBackgroundProc(ControlHandle, + ControlBackgroundPtr info); +static int MenuButtonInitControl (MacMenuButton *mbPtr, Rect *paneRect, + Rect *cntrRect ); +static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr); +static int UpdateControlColors(MacMenuButton *mbPtr); +static void ComputeMenuButtonControlParams(TkMenuButton *mbPtr, + MenuButtonControlParams * paramsPtr); +static void ComputeControlTitleParams(TkMenuButton *mbPtr, + ControlTitleParams *paramsPtr); +static void CompareControlTitleParams(ControlTitleParams *p1Ptr, + ControlTitleParams *p2Ptr, int *titleChanged, int *styleChanged); + +/* + * The structure below defines menubutton class behavior by means of + * procedures that can be invoked from generic window code. + */ + +Tk_ClassProcs tkpMenubuttonClass = { + sizeof(Tk_ClassProcs), /* size */ + TkMenuButtonWorldChanged, /* worldChangedProc */ +}; + + +/* + *---------------------------------------------------------------------- + * + * TkpCreateMenuButton -- + * + * Allocate a new TkMenuButton structure. + * + * Results: + * Returns a newly allocated TkMenuButton structure. + * + * Side effects: + * Registers an event handler for the widget. + * + *---------------------------------------------------------------------- + */ + +TkMenuButton * +TkpCreateMenuButton( + Tk_Window tkwin) +{ + MacMenuButton *mbPtr = (MacMenuButton *) ckalloc(sizeof(MacMenuButton)); + + Tk_CreateEventHandler(tkwin, ActivateMask, + MenuButtonEventProc, (ClientData) mbPtr); + mbPtr->flags = 0; + mbPtr->userPaneBackground = PIXEL_MAGIC << 24; + mbPtr->userPane = NULL; + mbPtr->control = NULL; + mbPtr->menuRef = NULL; + bzero(&mbPtr->params, sizeof(mbPtr->params)); + bzero(&mbPtr->titleParams, sizeof(mbPtr->titleParams)); + + return (TkMenuButton *) mbPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkpDisplayMenuButton -- + * + * This procedure is invoked to display a menubutton widget. + * + * Results: + * None. + * + * Side effects: + * Commands are output to X to display the menubutton in its + * current mode. + * + *---------------------------------------------------------------------- + */ + +void +TkpDisplayMenuButton( + ClientData clientData) /* Information about widget. */ +{ + TkMenuButton *butPtr = (TkMenuButton *) clientData; + Tk_Window tkwin = butPtr->tkwin; + TkWindow *winPtr; + Pixmap pixmap; + MacMenuButton *mbPtr = (MacMenuButton *) butPtr; + CGrafPtr destPort, savePort; + Boolean portChanged = false; + int hasImageOrBitmap = 0, width, height; + OSStatus err; + ControlButtonGraphicAlignment theAlignment; + Rect paneRect, cntrRect; + int active, enabled; + + butPtr->flags &= ~REDRAW_PENDING; + if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { + return; + } + pixmap = (Pixmap) Tk_WindowId(tkwin); + TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin)); + + winPtr = (TkWindow *)butPtr->tkwin; + paneRect.left = winPtr->privatePtr->xOff; + paneRect.top = winPtr->privatePtr->yOff; + paneRect.right = paneRect.left+Tk_Width(butPtr->tkwin); + paneRect.bottom = paneRect.top+Tk_Height(butPtr->tkwin); + + cntrRect = paneRect; + + cntrRect.left += butPtr->inset; + cntrRect.top += butPtr->inset; + cntrRect.right -= butPtr->inset; + cntrRect.bottom -= butPtr->inset; + + if (mbPtr->userPane) { + MenuButtonControlParams params; + bzero(¶ms, sizeof(params)); + ComputeMenuButtonControlParams(butPtr, ¶ms); + if ( +#ifdef TK_REBUILD_TOPLEVEL + (winPtr->flags & TK_REBUILD_TOPLEVEL) || +#endif + bcmp(¶ms,&mbPtr->params,sizeof(params))) { + if (mbPtr->userPane) { + DisposeControl(mbPtr->userPane); + mbPtr->userPane = NULL; + mbPtr->control = NULL; + } + } + } + if (!mbPtr->userPane) { + if (MenuButtonInitControl(mbPtr, &paneRect, &cntrRect)) { + TkMacOSXDbgMsg("Init Control failed"); + return; + } + } + SetControlBounds(mbPtr->userPane, &paneRect); + SetControlBounds(mbPtr->control, &cntrRect); + + if (butPtr->image != None) { + Tk_SizeOfImage(butPtr->image, &width, &height); + hasImageOrBitmap = 1; + } else if (butPtr->bitmap != None) { + Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); + hasImageOrBitmap = 1; + } + + /* + * We need to cache the title and its style + */ + + if (!(mbPtr->flags & FIRST_DRAW)) { + ControlTitleParams titleParams; + int titleChanged; + int styleChanged; + + ComputeControlTitleParams(butPtr, &titleParams); + CompareControlTitleParams(&titleParams, &mbPtr->titleParams, + &titleChanged, &styleChanged); + if (titleChanged) { + CFStringRef cf = CFStringCreateWithCString(NULL, + (char*) titleParams.title, kCFStringEncodingUTF8); + + if (hasImageOrBitmap) { + SetControlTitleWithCFString(mbPtr->control, cf); + } else { + SetMenuItemTextWithCFString(mbPtr->menuRef, 1, cf); + } + CFRelease(cf); + bcopy(titleParams.title, mbPtr->titleParams.title, + titleParams.len + 1); + mbPtr->titleParams.len = titleParams.len; + } + if ((titleChanged||styleChanged) && titleParams .len) { + if (hasImageOrBitmap) { + err = ChkErr(SetControlFontStyle, mbPtr->control, + &titleParams.style); + if (err != noErr) { + return; + } + } + bcopy(&titleParams.style, &mbPtr->titleParams.style, + sizeof(titleParams.style)); + } + } + if (hasImageOrBitmap) { + { + destPort = TkMacOSXGetDrawablePort(Tk_WindowId(tkwin)); + portChanged = QDSwapPort(destPort, &savePort); + mbPtr->picParams.version = -2; + mbPtr->picParams.hRes = 0x00480000; + mbPtr->picParams.vRes = 0x00480000; + mbPtr->picParams.srcRect.top = 0; + mbPtr->picParams.srcRect.left = 0; + mbPtr->picParams.srcRect.bottom = height; + mbPtr->picParams.srcRect.right = width; + mbPtr->picParams.reserved1 = 0; + mbPtr->picParams.reserved2 = 0; + mbPtr->bevelButtonContent.contentType = kControlContentPictHandle; + mbPtr->bevelButtonContent.u.picture = OpenCPicture(&mbPtr->picParams); + if (!mbPtr->bevelButtonContent.u.picture) { + TkMacOSXDbgMsg("OpenCPicture failed"); + } + tkPictureIsOpen = 1; + + /* + * TO DO - There is one case where XCopyPlane calls CopyDeepMask, + * which does not get recorded in the picture. So the bitmap code + * will fail in that case. + */ + } + if (butPtr->image != NULL) { + Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, 0, 0); + } else { + GC gc; + + if (butPtr->state == STATE_DISABLED) { + gc = butPtr->disabledGC; + } else if (butPtr->state == STATE_ACTIVE) { + gc = butPtr->activeTextGC; + } else { + gc = butPtr->normalTextGC; + } + XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0, + width, height, 0, 0, 1); + } + { + ClosePicture(); + tkPictureIsOpen = 0; + if (portChanged) { + QDSwapPort(savePort, NULL); + } + } + ChkErr(SetControlData, mbPtr->control, kControlButtonPart, + kControlBevelButtonContentTag, + sizeof(ControlButtonContentInfo), + (char *) &mbPtr->bevelButtonContent); + switch (butPtr->anchor) { + case TK_ANCHOR_N: + theAlignment = kControlBevelButtonAlignTop; + break; + case TK_ANCHOR_NE: + theAlignment = kControlBevelButtonAlignTopRight; + break; + case TK_ANCHOR_E: + theAlignment = kControlBevelButtonAlignRight; + break; + case TK_ANCHOR_SE: + theAlignment = kControlBevelButtonAlignBottomRight; + break; + case TK_ANCHOR_S: + theAlignment = kControlBevelButtonAlignBottom; + break; + case TK_ANCHOR_SW: + theAlignment = kControlBevelButtonAlignBottomLeft; + break; + case TK_ANCHOR_W: + theAlignment = kControlBevelButtonAlignLeft; + break; + case TK_ANCHOR_NW: + theAlignment = kControlBevelButtonAlignTopLeft; + break; + case TK_ANCHOR_CENTER: + theAlignment = kControlBevelButtonAlignCenter; + break; + } + + ChkErr(SetControlData, mbPtr->control, kControlButtonPart, + kControlBevelButtonGraphicAlignTag, + sizeof(ControlButtonGraphicAlignment), (char *) &theAlignment); + } + active = ((mbPtr->flags & ACTIVE) != 0); + if (active != IsControlActive(mbPtr->control)) { + if (active) { + ChkErr(ActivateControl, mbPtr->control); + } else { + ChkErr(DeactivateControl, mbPtr->control); + } + } + enabled = !(butPtr->state == STATE_DISABLED); + if (enabled != IsControlEnabled(mbPtr->control)) { + if (enabled) { + ChkErr(EnableControl, mbPtr->control); + } else { + ChkErr(DisableControl, mbPtr->control); + } + } + if (active && enabled) { + if (butPtr->state == STATE_ACTIVE) { + if (hasImageOrBitmap) { + HiliteControl(mbPtr->control, kControlButtonPart); + } else { + HiliteControl(mbPtr->control, kControlLabelPart); + } + } else { + HiliteControl(mbPtr->control, kControlNoPart); + } + } + UpdateControlColors(mbPtr); + if (mbPtr->flags & FIRST_DRAW) { + ShowControl(mbPtr->control); + ShowControl(mbPtr->userPane); + mbPtr->flags ^= FIRST_DRAW; + } else { + SetControlVisibility(mbPtr->control, true, true); + Draw1Control(mbPtr->userPane); + } + if (hasImageOrBitmap) { + if (mbPtr->bevelButtonContent.contentType == + kControlContentPictHandle) { + KillPicture(mbPtr->bevelButtonContent.u.picture); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpDestroyMenuButton -- + * + * Free data structures associated with the menubutton control. + * + * Results: + * None. + * + * Side effects: + * Restores the default control state. + * + *---------------------------------------------------------------------- + */ + +void +TkpDestroyMenuButton( + TkMenuButton *mbPtr) +{ + MacMenuButton *macMbPtr = (MacMenuButton *) mbPtr; + + if (macMbPtr->userPane) { + DisposeControl(macMbPtr->userPane); + macMbPtr->userPane = NULL; + } + if (macMbPtr->menuRef) { + short menuID = GetMenuID(macMbPtr->menuRef); + + TkMacOSXFreeMenuID(menuID); + DisposeMenu(macMbPtr->menuRef); + macMbPtr->menuRef = NULL; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpComputeMenuButtonGeometry -- + * + * After changes in a menu button's text or bitmap, this procedure + * recomputes the menu button's geometry and passes this information + * along to the geometry manager for the window. + * + * Results: + * None. + * + * Side effects: + * The menu button's window may change size. + * + *---------------------------------------------------------------------- + */ + +void +TkpComputeMenuButtonGeometry( + register TkMenuButton *mbPtr) /* Widget record for menu button. */ +{ + int width, height; + int hasImageOrBitmap = 0; + + mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth; + if (mbPtr->image != None) { + Tk_SizeOfImage(mbPtr->image, &width, &height); + hasImageOrBitmap = 1; + } else if (mbPtr->bitmap != None) { + Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height); + hasImageOrBitmap = 1; + } else { + hasImageOrBitmap = 0; + Tk_FreeTextLayout(mbPtr->textLayout); + mbPtr->textLayout = Tk_ComputeTextLayout(mbPtr->tkfont, mbPtr->text, + -1, mbPtr->wrapLength, mbPtr->justify, 0, &mbPtr->textWidth, + &mbPtr->textHeight); + width = mbPtr->textWidth; + height = mbPtr->textHeight; + if (mbPtr->width > 0) { + width = mbPtr->width * Tk_TextWidth(mbPtr->tkfont, "0", 1); + } + if (mbPtr->height > 0) { + Tk_FontMetrics fm; + + Tk_GetFontMetrics(mbPtr->tkfont, &fm); + height = mbPtr->height * fm.linespace; + } + width += 2*mbPtr->padX; + height += 2*mbPtr->padY; + } + if (hasImageOrBitmap) { + if (mbPtr->width > 0) { + width = mbPtr->width; + } + if (mbPtr->height > 0) { + height = mbPtr->height; + } + mbPtr->inset = mbPtr->highlightWidth + 2; + width += (2 * mbPtr->borderWidth + 4); + height += (2 * mbPtr->borderWidth + 4); + } else { + width += TK_POPUP_OFFSET; + } + if (mbPtr->indicatorOn) { + mbPtr->indicatorHeight = kTriangleHeight; + mbPtr->indicatorWidth = kTriangleWidth + kTriangleMargin; + width += mbPtr->indicatorWidth; + } else { + mbPtr->indicatorHeight = 0; + mbPtr->indicatorWidth = 0; + } + + Tk_GeometryRequest(mbPtr->tkwin, (int) (width + 2*mbPtr->inset), + (int) (height + 2*mbPtr->inset)); + Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset); +} + +/* + *---------------------------------------------------------------------- + * + * ComputeMenuButtonControlParams -- + * + * This procedure computes the various parameters used + * when creating a Carbon control (NewControl) + * These are determined by the various tk menu button parameters + * + * Results: + * None. + * + * Side effects: + * Sets the control initialisation parameters + * + *---------------------------------------------------------------------- + */ + +static void +ComputeMenuButtonControlParams( + TkMenuButton *mbPtr, + MenuButtonControlParams *paramsPtr) +{ + int fakeMenuID = 256; + + /* + * Determine ProcID based on button type and dimensions + * + * We need to set minValue to some non-zero value, + * Otherwise, the markers do not show up + */ + + paramsPtr->minValue = kControlBehaviorMultiValueMenu; + paramsPtr->maxValue = 0; + if (mbPtr->image || mbPtr->bitmap) { + paramsPtr->isBevel = 1; + if (mbPtr->borderWidth <= 2) { + paramsPtr->procID = kControlBevelButtonSmallBevelProc; + } else if (mbPtr->borderWidth == 3) { + paramsPtr->procID = kControlBevelButtonNormalBevelProc; + } else { + paramsPtr->procID = kControlBevelButtonLargeBevelProc; + } + if (mbPtr->indicatorOn) { + paramsPtr->initialValue = fakeMenuID; + } else { + paramsPtr->initialValue = 0; + } + } else { + paramsPtr->isBevel = 0; + paramsPtr->procID = kControlPopupButtonProc + + kControlPopupVariableWidthVariant; + paramsPtr->minValue = -12345; + paramsPtr->maxValue = -1; + paramsPtr->initialValue = 0; + } +} + +/* + *---------------------------------------------------------------------- + * + * returns 0 if same, 1 otherwise + * + *---------------------------------------------------------------------- + */ + +static void +CompareControlTitleParams( + ControlTitleParams *p1Ptr, + ControlTitleParams *p2Ptr, + int *titleChanged, + int *styleChanged) +{ + if (p1Ptr->len != p2Ptr->len) { + *titleChanged = 1; + } else if (bcmp(p1Ptr->title,p2Ptr->title,p1Ptr->len)) { + *titleChanged = 1; + } else { + *titleChanged = 0; + } + + if (p1Ptr->len && p2Ptr->len) { + *styleChanged = bcmp(&p1Ptr->style, &p2Ptr->style, + sizeof(p2Ptr->style)); + } else { + *styleChanged = p1Ptr->len||p2Ptr->len; + } +} + +static void +ComputeControlTitleParams( + TkMenuButton *butPtr, + ControlTitleParams *paramsPtr) +{ + Tk_Font font; + + paramsPtr->len = TkFontGetFirstTextLayout(butPtr->textLayout, &font, + (char*) paramsPtr->title); + paramsPtr->title[paramsPtr->len] = 0; + if (paramsPtr->len) { + TkMacOSXInitControlFontStyle(font,¶msPtr->style); + } +} + +/* + *---------------------------------------------------------------------- + * + * MenuButtonInitControl -- + * + * This procedure initialises a Carbon control + * + * Results: + * 0 on success, 1 on failure. + * + * Side effects: + * A background pane control and the control itself is created + * The contol is embedded in the background control + * The background control is embedded in the root control + * of the containing window + * The creation parameters for the control are also computed + * + *---------------------------------------------------------------------- + */ +int +MenuButtonInitControl( + MacMenuButton *mbPtr, /* Mac button. */ + Rect *paneRect, + Rect *cntrRect) +{ + OSStatus err; + TkMenuButton *butPtr = (TkMenuButton *) mbPtr; + SInt16 procID, initialValue, minValue, maxValue; + Boolean initiallyVisible; + SInt32 controlReference; + short menuID; + ControlRef rootControl = + TkMacOSXGetRootControl(Tk_WindowId(butPtr->tkwin)); + + mbPtr->windowRef = TkMacOSXDrawableWindow(Tk_WindowId(butPtr->tkwin)); + + /* + * Set up the user pane + */ + + initiallyVisible = false; + initialValue = kControlSupportsEmbedding | kControlHasSpecialBackground; + minValue = 0; + maxValue = 1; + procID = kControlUserPaneProc; + controlReference = (SInt32)mbPtr; + mbPtr->userPane = NewControl(mbPtr->windowRef, paneRect, "\p", + initiallyVisible, initialValue, minValue, maxValue, procID, + controlReference); + if (!mbPtr->userPane) { + TkMacOSXDbgMsg("Failed to create user pane control"); + return 1; + } + err = ChkErr(EmbedControl, mbPtr->userPane, rootControl); + if (err != noErr) { + return 1; + } + SetUserPaneSetUpSpecialBackgroundProc(mbPtr->userPane, + UserPaneBackgroundProc); + SetUserPaneDrawProc(mbPtr->userPane,UserPaneDraw); + initiallyVisible = false; + ComputeMenuButtonControlParams(butPtr,&mbPtr->params); + + /* + * Do this only if we are using bevel buttons. + */ + + ComputeControlTitleParams(butPtr, &mbPtr->titleParams); + mbPtr->control = NewControl(mbPtr->windowRef, + cntrRect, "\p" /* mbPtr->titleParams.title */, + initiallyVisible, mbPtr->params.initialValue, + mbPtr->params.minValue, mbPtr->params.maxValue, + mbPtr->params.procID, controlReference); + if (!mbPtr->control) { + TkMacOSXDbgMsg("Failed to create control of type %d", + mbPtr->params.procID); + return 1; + } + err = ChkErr(EmbedControl, mbPtr->control, mbPtr->userPane); + if (err != noErr ) { + return 1; + } + if (mbPtr->params.isBevel) { + CFStringRef cf = CFStringCreateWithCString(NULL, + (char*) mbPtr->titleParams.title, kCFStringEncodingUTF8); + + SetControlTitleWithCFString(mbPtr->control, cf); + CFRelease(cf); + if (mbPtr->titleParams.len) { + err = ChkErr(SetControlFontStyle, mbPtr->control, + &mbPtr->titleParams.style); + if (err != noErr) { + return 1; + } + } + } else { + CFStringRef cfStr; + + err = TkMacOSXGetNewMenuID(mbPtr->info.interp, (TkMenu *) mbPtr, 0, + &menuID); + if (err != TCL_OK) { + return 1; + } + err = ChkErr(CreateNewMenu, menuID, kMenuAttrDoNotUseUserCommandKeys, + &(mbPtr->menuRef)); + if (err != noErr) { + return 1; + } + cfStr = CFStringCreateWithCString(NULL, Tk_PathName(mbPtr->info.tkwin), + kCFStringEncodingUTF8); + if (!cfStr) { + TkMacOSXDbgMsg("CFStringCreateWithCString failed"); + return 1; + } + err = ChkErr(SetMenuTitleWithCFString, mbPtr->menuRef, cfStr); + CFRelease(cfStr); + if (err != noErr) { + return 1; + } + cfStr = CFStringCreateWithCString(NULL, + (char*) mbPtr->titleParams.title, kCFStringEncodingUTF8); + AppendMenuItemText(mbPtr->menuRef, "\px"); + if (cfStr) { + SetMenuItemTextWithCFString(mbPtr->menuRef, 1, cfStr); + CFRelease(cfStr); + } + ChkErr(SetControlData, mbPtr->control, kControlNoPart, + kControlPopupButtonMenuRefTag, sizeof(mbPtr->menuRef), + &mbPtr->menuRef); + SetControlMinimum(mbPtr->control, 1); + SetControlMaximum(mbPtr->control, 1); + SetControlValue(mbPtr->control, 1); + } + mbPtr->flags |= FIRST_DRAW; + if (IsWindowActive(mbPtr->windowRef)) { + mbPtr->flags |= ACTIVE; + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * SetUserPane + * + * Utility function to add a UserPaneDrawProc + * to a userPane control. From MoreControls code + * from Apple DTS. + * + * Results: + * MacOS system error. + * + * Side effects: + * The user pane gets a new UserPaneDrawProc. + * + *-------------------------------------------------------------- + */ +OSStatus +SetUserPaneDrawProc( + ControlRef control, + ControlUserPaneDrawProcPtr upp) +{ + ControlUserPaneDrawUPP myControlUserPaneDrawUPP = + NewControlUserPaneDrawUPP(upp); + + return SetControlData(control, kControlNoPart,kControlUserPaneDrawProcTag, + sizeof(myControlUserPaneDrawUPP), (Ptr)&myControlUserPaneDrawUPP); +} + +/* + *-------------------------------------------------------------- + * + * SetUserPaneSetUpSpecialBackgroundProc -- + * + * Utility function to add a UserPaneBackgroundProc + * to a userPane control + * + * Results: + * MacOS system error. + * + * Side effects: + * The user pane gets a new UserPaneBackgroundProc. + * + *-------------------------------------------------------------- + */ + +OSStatus +SetUserPaneSetUpSpecialBackgroundProc( + ControlRef control, + ControlUserPaneBackgroundProcPtr upp) +{ + ControlUserPaneBackgroundUPP myControlUserPaneBackgroundUPP = + NewControlUserPaneBackgroundUPP(upp); + + return SetControlData(control, kControlNoPart, + kControlUserPaneBackgroundProcTag, + sizeof(myControlUserPaneBackgroundUPP), + (Ptr) &myControlUserPaneBackgroundUPP); +} + +/* + *-------------------------------------------------------------- + * + * UserPaneDraw -- + * + * This function draws the background of the user pane that will + * lie under checkboxes and radiobuttons. + * + * Results: + * None. + * + * Side effects: + * The user pane gets updated to the current color. + * + *-------------------------------------------------------------- + */ + +void +UserPaneDraw( + ControlRef control, + ControlPartCode cpc) +{ + Rect contrlRect; + MacMenuButton * mbPtr = + (MacMenuButton *)(intptr_t)GetControlReference(control); + CGrafPtr port; + + GetPort(&port); + GetControlBounds(control,&contrlRect); + TkMacOSXSetColorInPort(mbPtr->userPaneBackground, 0, NULL, port); + EraseRect (&contrlRect); +} + +/* + *-------------------------------------------------------------- + * + * UserPaneBackgroundProc -- + * + * This function sets up the background of the user pane that will + * lie under checkboxes and radiobuttons. + * + * Results: + * None. + * + * Side effects: + * The user pane background gets set to the current color. + * + *-------------------------------------------------------------- + */ + +void +UserPaneBackgroundProc( + ControlHandle control, + ControlBackgroundPtr info) +{ + MacMenuButton *mbPtr = + (MacMenuButton *)(intptr_t)GetControlReference(control); + + if (info->colorDevice) { + CGrafPtr port; + + GetPort(&port); + TkMacOSXSetColorInPort(mbPtr->userPaneBackground, 0, NULL, port); + } +} + +/* + *-------------------------------------------------------------- + * + * UpdateControlColors -- + * + * This function will review the colors used to display + * a Macintosh button. If any non-standard colors are + * used we create a custom palette for the button, populate + * with the colors for the button and install the palette. + * + * Under Appearance, we just set the pointer that will be + * used by the UserPaneDrawProc. + * + * Results: + * None. + * + * Side effects: + * The Macintosh control may get a custom palette installed. + * + *-------------------------------------------------------------- + */ + +static int +UpdateControlColors( + MacMenuButton *mbPtr) +{ + XColor *xcolor; + TkMenuButton * butPtr = (TkMenuButton *) mbPtr; + + /* + * Under Appearance we cannot change the background of the + * button itself. However, the color we are setting is the color + * of the containing userPane. This will be the color that peeks + * around the rounded corners of the button. + * We make this the highlightbackground rather than the background, + * because if you color the background of a frame containing a + * button, you usually also color the highlightbackground as well, + * or you will get a thin grey ring around the button. + */ + + xcolor = Tk_3DBorderColor(butPtr->normalBorder); + mbPtr->userPaneBackground = xcolor->pixel; + + return false; +} + +/* + *-------------------------------------------------------------- + * + * MenuButtonEventProc -- + * + * This procedure is invoked by the Tk dispatcher for various + * events on buttons. + * + * Results: + * None. + * + * Side effects: + * When it gets exposed, it is redisplayed. + * + *-------------------------------------------------------------- + */ + +static void +MenuButtonEventProc( + ClientData clientData, /* Information about window. */ + XEvent *eventPtr) /* Information about event. */ +{ + TkMenuButton *buttonPtr = (TkMenuButton *) clientData; + MacMenuButton *mbPtr = (MacMenuButton *) clientData; + + if (eventPtr->type == ActivateNotify + || eventPtr->type == DeactivateNotify) { + if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) { + return; + } + if (eventPtr->type == ActivateNotify) { + mbPtr->flags |= ACTIVE; + } else { + mbPtr->flags &= ~ACTIVE; + } + if ((buttonPtr->flags & REDRAW_PENDING) == 0) { + Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) buttonPtr); + buttonPtr->flags |= REDRAW_PENDING; + } + } +} |