SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd), fAGLCtx(NULL) { OSStatus result; WindowRef wr = (WindowRef)hWnd; HIViewRef imageView, parent; HIViewRef rootView = HIViewGetRoot(wr); HIViewFindByID(rootView, kHIViewWindowContentID, &parent); result = HIImageViewCreate(NULL, &imageView); SkASSERT(result == noErr); result = HIViewAddSubview(parent, imageView); SkASSERT(result == noErr); fHVIEW = imageView; HIViewSetVisible(imageView, true); HIViewPlaceInSuperviewAt(imageView, 0, 0); if (true) { HILayoutInfo layout; layout.version = kHILayoutInfoVersionZero; set_bindingside(&layout.binding.left, parent, kHILayoutBindLeft); set_bindingside(&layout.binding.top, parent, kHILayoutBindTop); set_bindingside(&layout.binding.right, parent, kHILayoutBindRight); set_bindingside(&layout.binding.bottom, parent, kHILayoutBindBottom); set_axisscale(&layout.scale.x, parent); set_axisscale(&layout.scale.y, parent); set_axisposition(&layout.position.x, parent, kHILayoutPositionLeft); set_axisposition(&layout.position.y, rootView, kHILayoutPositionTop); HIViewSetLayoutInfo(imageView, &layout); } HIImageViewSetOpaque(imageView, true); HIImageViewSetScaleToFit(imageView, false); static const EventTypeSpec gTypes[] = { { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyUp }, { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseDragged }, { kEventClassMouse, kEventMouseMoved }, { kEventClassMouse, kEventMouseUp }, { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, { kEventClassWindow, kEventWindowBoundsChanged }, // { kEventClassWindow, kEventWindowDrawContent }, { SK_MacEventClass, SK_MacEventKind } }; EventHandlerUPP handlerUPP = NewEventHandlerUPP(SkOSWindow::EventHandler); int count = SK_ARRAY_COUNT(gTypes); result = InstallEventHandler(GetWindowEventTarget(wr), handlerUPP, count, gTypes, this, nil); SkASSERT(result == noErr); gCurrOSWin = this; gCurrEventQ = GetCurrentEventQueue(); gEventTarget = GetWindowEventTarget(wr); static bool gOnce = true; if (gOnce) { gOnce = false; gPrevNewHandler = set_new_handler(sk_new_handler); } }
/* Event handler for the content view that gets attached to the menu frame. The content view will (eventually) contain the menu view. */ OSStatus ContentViewEventHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void *refcon) { OSStatus retVal = eventNotHandledErr; if(GetEventClass(inEvent) == kEventClassMenu) { return noErr; } else if(GetEventClass(inEvent) == kEventClassControl) { HIViewRef hiSelf = NULL; verify_noerr(GetEventParameter(inEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof(hiSelf), NULL, &hiSelf)); if(hiSelf) { HIRect frame; HIViewGetFrame(hiSelf, &frame); switch(GetEventKind(inEvent)) { case kEventControlAddedSubControl : { HIViewRef subControl; ControlID subControlID; GetEventParameter(inEvent, kEventParamControlSubControl, typeControlRef, NULL, sizeof(subControl), NULL, &subControl ); GetControlID(subControl, &subControlID); // This should be comparing against kHIViewMenuContentID as shown inside the // #if 0. At the time of this writing, however, using that constant causes a // linker error (and a crash if you use ZeroLink). I extracted the signature // and id by determining the value at run-time the value I compare against. #if 0 if( kHIViewMenuContentID.signature == subControlID.signature && kHIViewMenuContentID.id == subControlID.id ) { #else if( 'menu' == subControlID.signature && 0 == subControlID.id ) { #endif // If we have the menu content view then set up some view bindings for it. HIRect bounds; HIViewGetBounds(hiSelf, &bounds); HIViewSetFrame(subControl, &bounds); HILayoutInfo contentLayout = { kHILayoutInfoVersionZero, { { NULL, kHILayoutBindTop }, { NULL, kHILayoutBindLeft }, { NULL, kHILayoutBindBottom }, { NULL, kHILayoutBindRight } }, { { NULL, kHILayoutScaleAbsolute, 0 }, { NULL, kHILayoutScaleAbsolute, 0 } }, { { NULL, kHILayoutPositionTop, 0 }, { NULL, kHILayoutPositionLeft, 0 } } }; verify_noerr(HIViewSetLayoutInfo(subControl, &contentLayout)); } retVal = noErr; } break; case kEventControlGetFrameMetrics : HIViewFrameMetrics metrics; // The offset from the frame view to the content view is // given by the kFrameOffset constant metrics.top = kFrameOffset; metrics.left = kFrameOffset; metrics.right = kFrameOffset; metrics.bottom = kFrameOffset; verify_noerr(SetEventParameter(inEvent, kEventParamControlFrameMetrics, typeControlFrameMetrics, sizeof(metrics), &metrics)); retVal = noErr; break; case kEventControlBoundsChanged : case kEventControlOwningWindowChanged : { // Maintain the QuickDraw port by changing its position to // match that of the content view. CGrafPtr windowPort = NULL; WindowRef window = GetControlOwner(hiSelf); if(window && (windowPort = GetWindowPort(window))) { CGrafPtr savePort; bool swapped = QDSwapPort(windowPort, &savePort); MovePortTo((short) frame.origin.x, (short) frame.origin.y); PortSize((short) frame.size.width, (short) frame.size.height); if(swapped) { QDSwapPort(savePort, NULL); } } retVal = noErr; } break; } // switch } // if (hiSelf) } return retVal; } /* ------------------------------------------ CreatePathForEntireStarMenu */ /* Create a path shape for the star frame. This looks an awful lot like CreatePathForEntireStarMenu in StarMenu.cpp but takes the radius to use as a parameter and then takes into account the kFrameOffest when creating the path. In true Core Foundation style, this is a CreateXXX routine and the caller is responsible for freeing the path that is returned. */ CGPathRef CreatePathForStarFrame(StarFrameData *menuData, float radius) { CGMutablePathRef retVal = CGPathCreateMutable(); MenuItemIndex numItems = CountMenuItems(menuData->menu); if(numItems > 0) { const CGPoint fullRadiusPoint = { radius, 0 }; const CGPoint halfRadiusPoint = { ((radius - kFrameOffset) / 2.0) + kFrameOffset , 0 }; float anglePerItem = 2 * pi / (float)numItems; // in radians naturally float halfAngle = anglePerItem / 2.0; CGPoint startPoint = halfRadiusPoint; CGAffineTransform midRotate = CGAffineTransformMakeRotation(halfAngle); CGPoint midPoint = CGPointApplyAffineTransform(fullRadiusPoint, midRotate); CGAffineTransform rotateToNext = CGAffineTransformMakeRotation(anglePerItem); CGPathMoveToPoint(retVal, NULL, startPoint.x, startPoint.y); CGPathAddLineToPoint(retVal, NULL, midPoint.x, midPoint.y); for(short ctr = 0; ctr < numItems; ctr++) { startPoint = CGPointApplyAffineTransform(startPoint, rotateToNext); midPoint = CGPointApplyAffineTransform(midPoint, rotateToNext); CGPathAddLineToPoint(retVal, NULL, startPoint.x, startPoint.y); CGPathAddLineToPoint(retVal, NULL, midPoint.x, midPoint.y); } CGPathCloseSubpath(retVal); } return retVal; }
/***************************************************** * * Do_NewWindow() * * Purpose: called to create a new window that has been constructed with Interface Builder * * Inputs: none * * Returns: OSStatus - error code (0 == no error) */ OSStatus Do_NewWindow(void) { OSStatus status; static IBNibRef gIBNibRef = NULL; WindowRef aWindowRef = NULL; CFStringRef theTitle = NULL; CFMutableStringRef theNewTitle = NULL; if (gIBNibRef == NULL) { // Create a Nib reference passing the name of the nib file (without the .nib extension) // CreateNibReference only searches into the application bundle. status = CreateNibReference(CFSTR("main"), &gIBNibRef); require_noerr(status, CantGetNibRef); } require(gIBNibRef != NULL, CantGetNibRef); // Create a window. "MainWindow" is the name of the window object. This name is set in // InterfaceBuilder when the nib is created. status = CreateWindowFromNib(gIBNibRef, CFSTR("MainWindow"), &aWindowRef); require_noerr(status, CantCreateWindow); require(NULL != aWindowRef, CantCreateWindow); // Grab the title of the window and add the window count to it status = CopyWindowTitleAsCFString(aWindowRef, &theTitle); require_noerr(status, CantGetSetTitle); theNewTitle = CFStringCreateMutableCopy(NULL, 0, theTitle); require(NULL != theNewTitle, CantGetSetTitle); CFStringAppendFormat(theNewTitle, NULL, CFSTR(" %ld"), ++gWindowCount); status = SetWindowTitleWithCFString(aWindowRef, theNewTitle); require_noerr(status, CantGetSetTitle); // Create the custom view to be tested and embed it in our group box control HIViewRef groupBox; status = HIViewFindByID(HIViewGetRoot(aWindowRef), kGroupBoxID, &groupBox); require_noerr(status, CantFindGroupBox); require(groupBox != NULL, CantFindGroupBox); HIViewRef customView; status = HICreateCustomView(NULL, &customView); require_noerr(status, CantCreateCustom); require(customView != NULL, CantCreateCustom); HIRect groupBoxBounds; HIViewGetBounds(groupBox, &groupBoxBounds); groupBoxBounds.origin.x += 20; groupBoxBounds.origin.y += 34; groupBoxBounds.size.width -= 40; groupBoxBounds.size.height -= 54; HIViewSetFrame(customView, &groupBoxBounds); HIViewSetLayoutInfo(customView, &kBindToParentLayout); status = HIViewAddSubview(groupBox, customView); require_noerr(status, CantAddSubview); HIViewSetVisible(customView, true); // Let's react to User's commands. EventTypeSpec eventTypeCP = {kEventClassCommand, kEventCommandProcess}; status = InstallWindowEventHandler(aWindowRef, Handle_WindowCommandProcess, 1, &eventTypeCP, (void *)customView, NULL); require_noerr(status, CantInstallEventHandler); // Let's update our static text field whenever the value or hilite of our tested custom view changes EventTypeSpec eventTypeCVFC[] = { {kEventClassControl, kEventControlValueFieldChanged}, {kEventClassControl, kEventControlHiliteChanged} }; status = InstallControlEventHandler(customView, Handle_ControlValueFieldOrHiliteChanged, 2, eventTypeCVFC, (void *)customView, NULL); require_noerr(status, CantInstallEventHandler); // We accept only numbers in our Edit text control HIViewRef editText; HIViewFindByID(HIViewGetRoot(GetControlOwner(customView)), kSetValueEditID, &editText); #ifdef MAC_OS_X_VERSION_10_4 // in Tiger, only 1 event handler is necessary for the key filtering EventTypeSpec eventTypeTSCIR = {kEventClassTextField, kEventTextShouldChangeInRange}; status = InstallControlEventHandler(editText, Handle_TextShouldChangeInRange, 1, &eventTypeTSCIR, (void *)editText, NULL); require_noerr(status, CantInstallEventHandler); #else // pre-Tiger, we need a different event handler and a validation proc to handle pastes and drops. ControlEditTextValidationUPP textValidation = MyValidationProc; SetControlData(editText, kControlEntireControl, kControlEditTextValidationProcTag, sizeof(textValidation), &textValidation); EventTypeSpec eventTypeTIUFKE = {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent}; status = InstallControlEventHandler(editText, Handle_TextInputEvent, 1, &eventTypeTIUFKE, (void *)editText, NULL); require_noerr(status, CantInstallEventHandler); #endif // Finishing the custom view setup SetControl32BitMinimum(customView, 0); SetControl32BitMaximum(customView, 36); SetControl32BitValue(customView, 2); // We want window and thus our custom view to be able to respond to drops status = SetAutomaticControlDragTrackingEnabledForWindow(aWindowRef, true); require_noerr(status, SetAutomaticControlDragTrackingEnabledForWindow); ShowWindow(aWindowRef); SetWindowModified(aWindowRef, false); SetAutomaticControlDragTrackingEnabledForWindow: SetControlDragTrackingEnabled: CantAddSubview: CantCreateCustom: CantFindGroupBox: CantInstallEventHandler: CantGetSetTitle: CantAllocateWindowData: CantCreateWindow: CantGetNibRef: if (theTitle != NULL) CFRelease(theTitle); if (theNewTitle != NULL) CFRelease(theNewTitle); return status; } // Do_NewWindow
/***************************************************** * * Handle_WindowCommandProcess(inHandlerCallRef, inEvent, inUserData) * * Purpose: called to handle of the events generated by the various controls of the HICustomView_Tester window * * Inputs: inHandlerCallRef - reference to the current handler call chain * inEvent - the event * inUserData - app-specified data you passed in the call to InstallEventHandler * * Returns: OSStatus - noErr indicates the event was handled * eventNotHandledErr indicates the event was not handled and the Toolbox should take over */ static pascal OSStatus Handle_WindowCommandProcess(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) { OSStatus status; HIViewRef customView = (HIViewRef)inUserData; // getting the command HICommandExtended aCommand; status = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(aCommand), NULL, &aCommand); require_noerr(status, ExitCommandProcess); status = eventNotHandledErr; // cheking that the command came from a control if ( ! (aCommand.attributes & kHICommandFromControl) ) goto ExitCommandProcess; switch (aCommand.commandID) { // // Asking for a refresh of the custom view // case 'SNDt': HIViewSetNeedsDisplay(customView, true); status = noErr; break; // // Setting the control value of the custom view // case 'SV00': SetControl32BitValue(customView, 0); status = noErr; break; case 'SV01': SetControl32BitValue(customView, 1); status = noErr; break; case 'SV17': SetControl32BitValue(customView, 17); status = noErr; break; case 'SVTH': SetControl32BitValue(customView, 1000); status = noErr; break; case 'SVet': { HIViewRef editText; HIViewFindByID(HIViewGetRoot(GetControlOwner(customView)), kSetValueEditID, &editText); char buffer[11]; Size actualSize; GetControlData(editText, kControlEntireControl, kControlEditTextTextTag, 10, buffer, &actualSize); if (actualSize > 10) actualSize = 10; buffer[actualSize] = 0; SetControl32BitValue(customView, atoi(buffer)); } status = noErr; break; // // Setting the state of the custom view // case 'CHlt': // setting the hilite to non-0 also stomps the previous hilite state if any // and we don't want that in our testing if (GetControl32BitValue(aCommand.source.control) == 1) HiliteControl(customView, 1); else HiliteControl(customView, 0); status = noErr; break; case 'CEnb': { HIViewRef hiliteControl; HIViewFindByID(HIViewGetRoot(GetControlOwner(customView)), kCheckHiliteID, &hiliteControl); if (GetControl32BitValue(aCommand.source.control) == 1) EnableControl(customView); else DisableControl(customView); UInt16 prevHilite = GetControlHilite(customView); if ((prevHilite == kControlInactivePart) || (prevHilite == kControlDisabledPart)) DisableControl(hiliteControl); else EnableControl(hiliteControl); HIViewSetNeedsDisplay(customView, true); } status = noErr; break; case 'CAct': { HIViewRef hiliteControl; HIViewFindByID(HIViewGetRoot(GetControlOwner(customView)), kCheckHiliteID, &hiliteControl); if (GetControl32BitValue(aCommand.source.control) == 1) ActivateControl(customView); else DeactivateControl(customView); UInt16 prevHilite = GetControlHilite(customView); if ((prevHilite == kControlInactivePart) || (prevHilite == kControlDisabledPart)) DisableControl(hiliteControl); else EnableControl(hiliteControl); HIViewSetNeedsDisplay(customView, true); } status = noErr; break; // // Testing the custom view in or as a scroller in a HIScrollView // case 'CTiS': case 'CTaS': if (GetControl32BitValue(aCommand.source.control) == 1) { // create a HIScrollView and install it where and as the custom view was HIViewRef scrollView; status = HIScrollViewCreate(kHIScrollViewValidOptions, &scrollView); require_noerr(status, ExitCommandProcess); HIRect frame; status = HIViewGetFrame(customView, &frame); require_noerr(status, ExitCommandProcess); status = HIViewSetFrame(scrollView, &frame); require_noerr(status, ExitCommandProcess); HIViewSetLayoutInfo(scrollView, &kBindToParentLayout); HIViewSetLayoutInfo(customView, &kNoBindLayout); status = HIViewAddSubview(HIViewGetSuperview(customView), scrollView); require_noerr(status, ExitCommandProcess); if (aCommand.commandID == 'CTiS') { // if we are testing the custom view in a scroller, we embed it in a scrolling User Pane // that we embed in the HIScrollView Rect boundsRect = {0, 0, 1000, 1000}; HIViewRef userPane; status = CreateUserPaneControl(NULL, &boundsRect, kControlSupportsEmbedding, &userPane); require_noerr(status, ExitCommandProcess); EventTypeSpec userPaneEvents[] = { {kEventClassScrollable, kEventScrollableGetInfo}, {kEventClassScrollable, kEventScrollableScrollTo} }; InstallControlEventHandler(userPane, UserPaneHandler, 2, userPaneEvents, userPane, NULL); status = HIViewAddSubview(scrollView, userPane); require_noerr(status, ExitCommandProcess); status = HIViewAddSubview(userPane, customView); require_noerr(status, ExitCommandProcess); HIViewSetVisible(userPane, true); } else { // else we just embed the custom view directly in the HIScrollView status = HIViewAddSubview(scrollView, customView); require_noerr(status, ExitCommandProcess); } HIViewSetVisible(scrollView, true); // the 2 modes are not compatible so we disable the other check box HIViewRef otherCheckToDisable; if (aCommand.commandID == 'CTiS') HIViewFindByID(HIViewGetRoot(GetControlOwner(customView)), kCheckTestAsScrollID, &otherCheckToDisable); else HIViewFindByID(HIViewGetRoot(GetControlOwner(customView)), kCheckTestInScrollID, &otherCheckToDisable); require_noerr(status, ExitCommandProcess); DisableControl(otherCheckToDisable); // if we reach here, status is already set to noErr so we don't set it again } else { // we remove the HIScrollView and set the custom view back to where and as it was HIViewRef scrollView; if (aCommand.commandID == 'CTiS') scrollView = HIViewGetSuperview(HIViewGetSuperview(customView)); else scrollView = HIViewGetSuperview(customView); status = HIViewAddSubview(HIViewGetSuperview(scrollView), customView); require_noerr(status, ExitCommandProcess); HIRect frame; status = HIViewGetFrame(scrollView, &frame); require_noerr(status, ExitCommandProcess); status = HIViewSetFrame(customView, &frame); require_noerr(status, ExitCommandProcess); HIViewSetLayoutInfo(customView, &kBindToParentLayout); // by releasing the HIScrollView, we also release the scrolling User Pane if any // which was embedded inside CFRelease(scrollView); // we renable the other check box HIViewRef otherCheckToEnable; if (aCommand.commandID == 'CTiS') HIViewFindByID(HIViewGetRoot(GetControlOwner(customView)), kCheckTestAsScrollID, &otherCheckToEnable); else HIViewFindByID(HIViewGetRoot(GetControlOwner(customView)), kCheckTestInScrollID, &otherCheckToEnable); require_noerr(status, ExitCommandProcess); EnableControl(otherCheckToEnable); // if we reach here, status is already set to noErr so we don't set it again } break; } ExitCommandProcess: return status; } // Handle_WindowCommandProcess
// --------------------------------------------------------------------------- // To make a TextView auto-size along with its parent view, use the following // code: HIViewRef textView; HILayoutInfo layoutInfo; HIRect parentFrame; //... // Bind the view to its parent on all sides (affects resize) layoutInfo.binding.left.kind = kHILayoutBindLeft; layoutInfo.binding.left.toView = NULL; layoutInfo.binding.left.offset = 0.0; layoutInfo.binding.top.kind = kHILayoutBindTop; layoutInfo.binding.top.toView = NULL; layoutInfo.binding.top.offset = 0.0; layoutInfo.binding.right.kind = kHILayoutBindRight; layoutInfo.binding.right.toView = NULL; layoutInfo.binding.right.offset = 0.0; layoutInfo.binding.bottom.kind = kHILayoutBindBottom; layoutInfo.binding.bottom.toView = NULL; layoutInfo.binding.bottom.offset = 0.0; status = HIViewSetLayoutInfo(textView, &layoutInfo); // Set the initial size to be the same as the parent status = HIViewGetFrame(HIViewGetSuperview(textView), &parentFrame); status = HIViewSetFrame(textView, &parentFrame);