1 /* 2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 // I don't think this class belongs in WebKit. Lets move it out. 30 31 // Things that I've never bothered working out: 32 // For non-sheet windows, handle Carbon WindowMove events so as to do the same things as -[NSWindow _windowMoved]. 33 // Check to see how this stuff deals with various screen size change scenarious. 34 // M.P. Warning - 9/17/01 35 36 // There are some invariants I'm maintaining for objects of this class which have been successfully initialized but not deallocated. These all make it easier to not override every single method of NSWindow. 37 // _auxiliaryStorage->auxWFlags.hasShadow will always be false if the Carbon window has a kWindowNoShadowAttribute, and vice versa. 38 // _auxiliaryStorage->_auxWFlags.minimized will always reflect the window's Carbon collapsed state. 39 // _borderView will always point to an NSCarbonWindowFrame. 40 // _contentView will always point to an NSCarbonWindowContentView; 41 // _frame will always reflect the window's Carbon kWindowStructureRgn bounds. 42 // _styleMask will always have _NSCarbonWindowMask set, and will have NSClosableWindowMask, NSMiniaturizableWindowMask, NSResizableWindowMask, and/or NSTitledWindowMask set as appropriate. 43 // _wflags.oneShot and _wflags.delayedOneShot will always be false. 44 // _wFlags.visible will always reflect the window's Carbon visibility. 45 // _windowNum will always be greater than zero, and valid. 46 // The instance variables involved are ones that came to my attention during the initial writing of this class; I haven't methodically gone through NSWindow's ivar list or anything like that. M.P. Notice - 10/10/00 47 48 // Things that have to be worked on if NSCarbonWindows are ever used for something other than dialogs and sheets: 49 // Clicking on an NSCarbonWindow while a Cocoa app-modal dialog is shown does not beep, as it should [old bug, maybe fixed now]. 50 // Handling of mouse clicks or key presses for any window control (close, miniaturize, zoom) might not be all there. 51 // Handling of miniaturization of Carbon windows via title bar double-click might not be all there. 52 // The background on NSCarbonWindowTester's sample window (not sample dialog or sample sheet) might be wrong. 53 // The controls on NSCarbonWindowTester's sample window look inactive when the window is inactive, but have first-click behavior. 54 // M.P. Warning - 12/14/00 55 56 // Some things would have to be made public if someone wanted to subclass this so as to support more menu item commands. M.P. Warning - 9/19/00 57 58 #ifndef __LP64__ 59 60 #import "CarbonWindowAdapter.h" 61 62 #import "CarbonWindowFrame.h" 63 #import "CarbonWindowContentView.h" 64 #import "HIViewAdapter.h" 65 66 #import <WebKitSystemInterface.h> 67 68 #import <AppKit/AppKit.h> 69 //#import <CoreGraphics/CGSWindow.h> 70 #import <HIToolbox/CarbonEvents.h> 71 #import <HIToolbox/Controls.h> 72 #import <HIToolbox/HIView.h> 73 #import <assert.h> 74 75 #import <WebCore/WebCoreObjCExtras.h> 76 #import <runtime/InitializeThreading.h> 77 78 #import "WebKitLogging.h" 79 #import "WebNSObjectExtras.h" 80 #import "WebTypesInternal.h" 81 82 @interface NSWindow(HIWebFrameView) 83 - _initContent:(const NSRect *)contentRect styleMask:(unsigned int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag contentView:aView; 84 - (void)_oldPlaceWindow:(NSRect)frameRect; 85 - (void)_windowMovedToRect:(NSRect)actualFrame; 86 - (void)_setWindowNumber:(NSInteger)nativeWindow; 87 - (NSGraphicsContext *)_threadContext; 88 - (void)_setFrame:(NSRect)newWindowFrameRect; 89 - (void)_setVisible:(BOOL)flag; 90 @end 91 92 @interface NSApplication(HIWebFrameView) 93 - (void)setIsActive:(BOOL)aFlag; 94 - (id)_setMouseActivationInProgress:(BOOL)flag; 95 - (BOOL)_handleKeyEquivalent:(NSEvent*)theEvent; 96 @end 97 98 @interface NSInputContext 99 - (BOOL)processInputKeyBindings:(NSEvent *)event; 100 @end 101 102 // Forward declarations. 103 static OSStatus NSCarbonWindowHandleEvent(EventHandlerCallRef inEventHandlerCallRef, EventRef inEventRef, void *inUserData); 104 105 @implementation CarbonWindowAdapter 106 107 108 // Return an appropriate window frame class. 109 + (Class)frameViewClassForStyleMask:(unsigned int)style { 110 111 // There's only one appropriate window style, and only one appropriate window frame class. 112 assert(style & WKCarbonWindowMask()); 113 return [CarbonWindowFrame class]; 114 115 } 116 117 118 // Overriding of the parent class' designated initializer, just for safety's sake. 119 - (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)style backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag { 120 121 // Do the standard Cocoa thing. 122 self = [super initWithContentRect:contentRect styleMask:style backing:bufferingType defer:flag]; 123 if (self==nil) return nil; 124 125 // Simple. 126 _windowRef = NULL; 127 _windowRefIsOwned = NO; 128 _eventHandler = NULL; 129 130 // Done. 131 return self; 132 133 } 134 135 // Given a reference to a Carbon window that is to be encapsulated, an indicator of whether or not this object should take responsibility for disposing of the Carbon window, and an indicator of whether to disable Carbon window ordering, initialize. This is the class' designated initializer. 136 - (id)initWithCarbonWindowRef:(WindowRef)inWindowRef takingOwnership:(BOOL)inWindowRefIsOwned disableOrdering:(BOOL)inDisableOrdering carbon:(BOOL)inCarbon { 137 138 NSBackingStoreType backingStoreType; 139 CarbonWindowContentView *carbonWindowContentView; 140 NSWindow *windowAsProperty; 141 OSStatus osStatus; 142 UInt32 windowFeatures; 143 WindowAttributes windowAttributes; 144 unsigned int styleMask; 145 void *nativeWindow; 146 WindowModality windowModality; 147 ControlRef contentView; 148 149 // Simple. 150 // It's very weak to have to put this before the invocation of [super initWithContentRect:...], but -setContentView: is invoked from within that initializer. It turns out that the common admonition about not calling virtual functions from within C++ constructors makes sense in Objective-C too. M.P. Notice - 10/10/00 151 _windowRef = inWindowRef; 152 //_auxiliaryStorage->_windowRef = inWindowRef; 153 _windowRefIsOwned = inWindowRefIsOwned; 154 _carbon = inCarbon; 155 156 // Find out the window's CoreGraphics window reference. 157 nativeWindow = WKGetNativeWindowFromWindowRef(inWindowRef); 158 159 // Find out the window's Carbon window attributes. 160 GetWindowAttributes(inWindowRef, &windowAttributes); 161 162 // Find out the window's Carbon window features. 163 GetWindowFeatures(inWindowRef, &windowFeatures); 164 165 // Figure out the window's backing store type. 166 // At one time, this had code stolen from CreatePlatformWindow in HIToolbox/Windows/Platform/CGSPlatform.c 167 // But now the non-retained window class is a Carbon secret that's not even in 168 // WindowsPriv.h; maybe we'll have to revisit this if someone needs to use WebKit 169 // in a non-retained window. 170 backingStoreType = NSBackingStoreRetained; 171 172 // Figure out the window's style mask. 173 styleMask = WKCarbonWindowMask(); 174 if (windowAttributes & kWindowCloseBoxAttribute) styleMask |= NSClosableWindowMask; 175 if (windowAttributes & kWindowResizableAttribute) styleMask |= NSResizableWindowMask; 176 if (windowFeatures & kWindowCanCollapse) styleMask |= NSMiniaturizableWindowMask; 177 if (windowFeatures & kWindowHasTitleBar) styleMask |= NSTitledWindowMask; 178 179 osStatus = GetWindowModality(_windowRef, &windowModality, NULL); 180 if (osStatus != noErr) { 181 NSLog(@"Couldn't get window modality: error=%d", osStatus); 182 return nil; 183 } 184 185 // Create one of our special content views. 186 carbonWindowContentView = [[[CarbonWindowContentView alloc] init] autorelease]; 187 188 // Do some standard Cocoa initialization. The defer argument's value is YES because we don't want -[NSWindow _commonAwake] to get called. It doesn't appear that any relevant NSWindow code checks _wFlags.deferred, so we should be able to get away with the lie. 189 self = (CarbonWindowAdapter*)[super _initContent:NULL styleMask:styleMask backing:backingStoreType defer:YES contentView:carbonWindowContentView]; 190 if (!self) return nil; 191 assert(_contentView); 192 193 // Record accurately whether or not this window has a shadow, in case someone asks. 194 // _auxiliaryStorage->_auxWFlags.hasShadow = (windowAttributes & kWindowNoShadowAttribute) ? NO : YES; 195 196 // Record the window number. 197 [self _setWindowNumber:(NSInteger)nativeWindow]; 198 199 // Set up from the frame rectangle. 200 // We didn't even really try to get it right at _initContent:... time, because it's more trouble that it's worth to write a real +[NSCarbonWindow frameRectForContentRect:styleMask:]. M.P. Notice - 10/10/00 201 [self reconcileToCarbonWindowBounds]; 202 203 // Install an event handler for the Carbon window events in which we're interested. 204 const EventTypeSpec kEvents[] = { 205 { kEventClassWindow, kEventWindowActivated }, 206 { kEventClassWindow, kEventWindowDeactivated }, 207 { kEventClassWindow, kEventWindowBoundsChanged }, 208 { kEventClassWindow, kEventWindowShown }, 209 { kEventClassWindow, kEventWindowHidden } 210 }; 211 212 const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged }; 213 214 osStatus = InstallEventHandler( GetWindowEventTarget(_windowRef), NSCarbonWindowHandleEvent, GetEventTypeCount( kEvents ), kEvents, (void*)self, &_eventHandler); 215 if (osStatus!=noErr) { 216 [self release]; 217 return nil; 218 } 219 220 osStatus = InstallEventHandler( GetControlEventTarget( HIViewGetRoot( _windowRef ) ), NSCarbonWindowHandleEvent, 1, &kControlBoundsChangedEvent, (void*)self, &_eventHandler); 221 if (osStatus!=noErr) { 222 [self release]; 223 return nil; 224 } 225 226 HIViewFindByID( HIViewGetRoot( _windowRef ), kHIViewWindowContentID, &contentView ); 227 osStatus = InstallEventHandler( GetControlEventTarget( contentView ), NSCarbonWindowHandleEvent, 1, &kControlBoundsChangedEvent, (void*)self, &_eventHandler); 228 if (osStatus!=noErr) { 229 [self release]; 230 return nil; 231 } 232 233 // Put a pointer to this Cocoa NSWindow in a Carbon window property tag. 234 // Right now, this is just used by NSViewCarbonControl. M.P. Notice - 10/9/00 235 windowAsProperty = self; 236 osStatus = SetWindowProperty(_windowRef, WKCarbonWindowPropertyCreator(), WKCarbonWindowPropertyTag(), sizeof(NSWindow *), &windowAsProperty); 237 if (osStatus!=noErr) { 238 [self release]; 239 return nil; 240 } 241 242 // Ignore the Carbon window activation/deactivation events that Carbon sends to its windows at app activation/deactivation. We'll send such events when we think it's appropriate. 243 _passingCarbonWindowActivationEvents = NO; 244 245 // Be sure to sync up visibility 246 [self _setVisible:(BOOL)IsWindowVisible( _windowRef )]; 247 248 // Done. 249 return self; 250 251 } 252 253 - (void)setViewsNeedDisplay:(BOOL)wellDoThey { 254 // Make sure we can flush anything that needs it. 255 256 // We need to sync the context here. I was hoping I didn't need to do this, 257 // but apparently when scrolling, the AppKit view system draws directly. 258 // When this occurs, I cannot intercept it to make it draw in my HIView 259 // context. What ends up happening is that it draws, but nothing ever 260 // flushes it. 261 262 if ( [self windowNumber] != -1 ) 263 { 264 CGContextRef cgContext = (CGContextRef)[[self _threadContext] graphicsPort]; 265 CGContextSynchronize( cgContext ); 266 } 267 } 268 269 + (void)initialize 270 { 271 JSC::initializeThreading(); 272 #ifndef BUILDING_ON_TIGER 273 WebCoreObjCFinalizeOnMainThread(self); 274 #endif 275 } 276 277 // Given a reference to a Carbon window that is to be encapsulated, and an indicator of whether or not this object should take responsibility for disposing of the Carbon window, initialize. 278 - (id)initWithCarbonWindowRef:(WindowRef)inWindowRef takingOwnership:(BOOL)inWindowRefIsOwned { 279 // for now, set disableOrdering to YES because that is what we've been doing and is therefore lower risk. However, I think it would be correct to set it to NO. 280 return [self initWithCarbonWindowRef:inWindowRef takingOwnership:inWindowRefIsOwned disableOrdering:YES carbon:NO]; 281 } 282 283 284 // Clean up. 285 - (void)dealloc { 286 if (WebCoreObjCScheduleDeallocateOnMainThread([CarbonWindowAdapter class], self)) 287 return; 288 289 // Clean up, if necessary. 290 // if we didn't remove the event handler at dealloc time, we would risk getting sent events after the window has been deallocated. See 2702179. M.P. Notice - 6/1/01 291 if (_eventHandler) RemoveEventHandler(_eventHandler); 292 293 // Do the standard Cocoa thing. 294 [super dealloc]; 295 } 296 297 - (void)finalize { 298 ASSERT_MAIN_THREAD(); 299 if (_eventHandler) RemoveEventHandler(_eventHandler); 300 [super finalize]; 301 } 302 303 - (WindowRef)windowRef { 304 305 // Simple. 306 return _windowRef; 307 308 } 309 310 // should always be YES, but check in order to avoid initialization or deallocation surprises 311 - (BOOL)_hasWindowRef { 312 return (_windowRef != NULL); 313 } 314 315 // an NSCarbonWindow does not manage the windowRef. The windowRef manages the NSCarbonWindow 316 - (BOOL)_managesWindowRef { 317 return NO; 318 } 319 320 - (void)_removeWindowRef { 321 _windowRef = NULL; 322 323 if (_eventHandler) RemoveEventHandler(_eventHandler); 324 325 _eventHandler = NULL; 326 } 327 328 - (WindowClass)_carbonWindowClass { 329 WindowClass windowClass = kDocumentWindowClass; 330 OSStatus osStatus; 331 332 if ([self _hasWindowRef]) { 333 osStatus = GetWindowClass([self windowRef], &windowClass); 334 if (osStatus != noErr) { 335 NSLog(@"Couldn't get window class: error=%d", osStatus); 336 } 337 } 338 return windowClass; 339 } 340 341 // Update this window's frame and content frame rectangles to match the Carbon window's structure bounds and content bounds rectangles. Return yes if the update was really necessary, no otherwise. 342 - (BOOL)reconcileToCarbonWindowBounds { 343 344 OSStatus osStatus; 345 NSRect newContentFrameRect; 346 NSRect newWindowFrameRect; 347 NSRect oldContentFrameRect; 348 Rect windowContentBoundsRect; 349 Rect windowStructureBoundsRect; 350 351 // Initialize for safe returning. 352 BOOL reconciliationWasNecessary = NO; 353 354 // Precondition check. 355 assert(_contentView); 356 357 // Get the Carbon window's bounds, which are expressed in global screen coordinates, with (0,0) at the top-left of the main screen. 358 osStatus = GetWindowBounds(_windowRef, kWindowStructureRgn, &windowStructureBoundsRect); 359 if (osStatus!=noErr) NSLog(@"A Carbon window's structure bounds couldn't be gotten."); 360 osStatus = GetWindowBounds(_windowRef, kWindowContentRgn, &windowContentBoundsRect); 361 if (osStatus!=noErr) NSLog(@"A Carbon window's content bounds couldn't be gotten."); 362 363 // Set the frame rectangle of the border view and this window from the Carbon window's structure region bounds. 364 newWindowFrameRect.origin.x = windowStructureBoundsRect.left; 365 newWindowFrameRect.origin.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - windowStructureBoundsRect.bottom; 366 newWindowFrameRect.size.width = windowStructureBoundsRect.right - windowStructureBoundsRect.left; 367 newWindowFrameRect.size.height = windowStructureBoundsRect.bottom - windowStructureBoundsRect.top; 368 if (!NSEqualRects(newWindowFrameRect, _frame)) { 369 [self _setFrame:newWindowFrameRect]; 370 [_borderView setFrameSize:newWindowFrameRect.size]; 371 reconciliationWasNecessary = YES; 372 } 373 374 // Set the content view's frame rect from the Carbon window's content region bounds. 375 newContentFrameRect.origin.x = windowContentBoundsRect.left - windowStructureBoundsRect.left; 376 newContentFrameRect.origin.y = windowStructureBoundsRect.bottom - windowContentBoundsRect.bottom; 377 newContentFrameRect.size.width = windowContentBoundsRect.right - windowContentBoundsRect.left; 378 newContentFrameRect.size.height = windowContentBoundsRect.bottom - windowContentBoundsRect.top; 379 oldContentFrameRect = [_contentView frame]; 380 if (!NSEqualRects(newContentFrameRect, oldContentFrameRect)) { 381 [_contentView setFrame:newContentFrameRect]; 382 reconciliationWasNecessary = YES; 383 } 384 385 // Done. 386 return reconciliationWasNecessary; 387 388 } 389 390 391 // Handle an event just like an NSWindow would. 392 - (void)sendSuperEvent:(NSEvent *)inEvent { 393 394 // Filter out a few events that just result in complaints in the log. 395 // Ignore some unknown event that gets sent when NSTextViews in printing accessory views are focused. M.P. Notice - 12/7/00 396 BOOL ignoreEvent = NO; 397 NSEventType eventType = [inEvent type]; 398 if (eventType==NSSystemDefined) { 399 short eventSubtype = [inEvent subtype]; 400 if (eventSubtype==7) { 401 ignoreEvent = YES; 402 } 403 } else if (eventType == NSKeyDown) { 404 // Handle command-space as [NSApp sendEvent:] does. 405 if ([NSInputContext processInputKeyBindings:inEvent]) { 406 return; 407 } 408 } 409 410 // Simple. 411 if (!ignoreEvent) [super sendEvent:inEvent]; 412 } 413 414 - (void)relinquishFocus 415 { 416 NSResponder* firstResponder; 417 418 // Carbon thinks that a control has the keyboard focus, 419 // or we wouldn't be being asked to relinquish focus. 420 421 firstResponder = [self firstResponder]; 422 if ([firstResponder isKindOfClass:[NSView class]] ){ 423 // Make the window the first responder, so that no view is the key view. 424 [self makeFirstResponder:self]; 425 } 426 } 427 428 - (BOOL)makeFirstResponder:(NSResponder *)aResponder 429 { 430 // Let NSWindow focus the appropriate NSView. 431 if (![super makeFirstResponder:aResponder]) 432 return NO; 433 434 // Now, if the view we're focusing is in a HIWebView, find the 435 // corresponding HIWebView for the NSView, and tell carbon to 436 // clear any focused control. 437 HIViewRef viewRef = 0; 438 NSResponder *firstResponder = [self firstResponder]; 439 if ([firstResponder isKindOfClass:[NSView class]]) { 440 NSView *view = (NSView *)firstResponder; 441 while (view) { 442 viewRef = [HIViewAdapter getHIViewForNSView:view]; 443 if (viewRef) 444 break; 445 view = [view superview]; 446 } 447 } 448 449 HIViewRef focus; 450 GetKeyboardFocus (_windowRef, &focus); 451 if (focus != viewRef) { 452 SetKeyboardFocus (_windowRef, viewRef, kControlIndicatorPart ); 453 } 454 455 return YES; 456 } 457 458 // There's no override of _addCursorRect:cursor:forView:, despite the fact that NSWindow's invokes [self windowNumber], because Carbon windows won't have subviews, and therefore won't have cursor rects. 459 460 461 // There's no override of _autoResizeState, despite the fact that NSWindow's operates on _windowNum, because it looks like it might work on Carbon windows as is. 462 463 464 // Disappointingly, -_blockHeartBeat: is not immediately invoked to turn off heartbeating. Heartbeating is turned off by setting the gDefaultButtonPaused global variable, and then this method is invoked later, if that global is set (at heartbeating time I guess). Something has to change if we want to hook this up in Carbon windows. M.P. Warning - 9/17/01 465 /* 466 // Do the right thing for a Carbon window. 467 - (void)_blockHeartBeat:(BOOL)flag { 468 469 ControlRef defaultButton; 470 OSStatus osStatus; 471 472 // Do the standard Cocoa thing. 473 [super _blockHeartBeat:flag]; 474 475 // If there's a default Carbon button in this Carbon window, make it stop pulsing, the Carbon way. 476 // This is inspired by HIToolbox/Controls/Definitions/ButtonCDEF.c's ButtonEventHandler(). M.P. Notice - 12/5/00 477 osStatus = GetWindowDefaultButton(_windowRef, &defaultButton); 478 if (osStatus==noErr && defaultButton) { 479 Boolean anotherButtonIsTracking = flag ? TRUE : FALSE; 480 osStatus = SetControlData(defaultButton, kControlNoPart, kControlPushButtonAnotherButtonTrackingTag, sizeof(Boolean), &anotherButtonIsTracking); 481 if (osStatus==noErr) DrawOneControl(defaultButton); 482 else NSLog(@"Some data couldn't be set in a Carbon control."); 483 } 484 485 } 486 */ 487 488 489 // Do the right thing for a Carbon window. 490 - (void)_cancelKey:(id)sender { 491 492 // Most of the time the handling of the cancel key will be done by Carbon, but this method will be invoked if an NSCarbonWindow is wrapping a Carbon window that contains an NSViewCarbonControl, and the escape key or whatever is pressed with an NSTextView focused. Just do what Carbon would do. 493 ControlRef cancelButton; 494 GetWindowCancelButton(_windowRef, &cancelButton); 495 if (cancelButton) { 496 if (IsControlActive(cancelButton)) { 497 HIViewSimulateClick(cancelButton, kControlButtonPart, 0, NULL); 498 } 499 } 500 501 } 502 503 504 505 // Do the right thing for a Carbon window. 506 - (void)_commonAwake { 507 508 // Complain, because this should never be called. We insist that -[NSCarbonWindow initWithCarbonWindowRef] is the only valid initializer for instances of this class, and that there's no such thing as a one-shot NSCarbonWindow. 509 NSLog(@"-[NSCarbonWindow _commonAwake] is not implemented."); 510 511 } 512 513 514 // There's no override of _commonInitFrame:styleMask:backing:defer:, despite the fact that NSWindow's modifies quite a few instance variables, because it gets called in a harmless way if the class instance is properly initialized with -[NSCarbonWindow initWithCarbonWindowRef:takingOwnership:]. 515 516 517 // Do the right thing for a Carbon window. 518 - _destroyRealWindow:(BOOL)orderingOut { 519 520 // Complain, because this should never be called. We don't support one-shot NSCarbonWindows. 521 NSLog(@"-[NSCarbonWindow _destroyRealWindow:] is not implemented."); 522 return self; 523 524 } 525 526 527 // There's no override of _discardCursorRectsForView, despite the fact that NSWindow's invokes [self windowNumber], because Carbon windows won't have subviews, and therefore won't have cursor rects. 528 529 530 // There's no override of _forceFlushWindowToScreen, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 531 532 533 // There's no override of _getPositionFromServer, despite the fact that NSWindow's operates on _windowNum, because it's only called from -[NSApplication _activateWindows], which is hopefully about to become obsolete any second now. 534 535 536 // There's no override of _globalWindowNum, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 537 538 539 // There's no override of _initContent:styleMask:backing:defer:contentView:, despite the fact that NSWindow's modifies _auxiliaryStorage->_auxWFlags.hasShadow, because it will never get called if the class instance is properly initialized with -[NSCarbonWindow initWithCarbonWindowRef:takingOwnership:]. 540 541 542 // There's no override of _initContent:styleMask:backing:defer:counterpart:, despite the fact that NSWindow's modifies _auxiliaryStorage->_auxWFlags.hasShadow, because it will never get called if the class instance is properly initialized with -[NSCarbonWindow initWithCarbonWindowRef:takingOwnership:]. 543 544 545 // Do what NSWindow would do, but then sychronize the Carbon window structures. 546 - (void)_oldPlaceWindow:(NSRect)frameRect { 547 548 OSStatus osStatus; 549 550 // Do the standard Cocoa thing. 551 [super _oldPlaceWindow:frameRect]; 552 553 // Tell Carbon to update its various regions. 554 // Despite its name, this function should be called early and often, even if the window isn't visible yet. 2702648. M.P. Notice - 7/24/01 555 osStatus = WKSyncWindowWithCGAfterMove(_windowRef); 556 if (osStatus!=noErr) NSLog(@"A Carbon window's bounds couldn't be synchronized (%i).", (int)osStatus); 557 558 } 559 560 561 // There's no override of _orderOutAndCalcKeyWithCounter:, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 562 563 564 // There's no override of _realHeartBeatThreadContext, despite the fact that NSWindows's invokes [self windowNumber], because it looks like it might not do anything that will effect a Carbon window. 565 566 567 // There's no override of _registerWithDockIfNeeded, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 568 569 570 // There's no override of _removeCursorRect:cursor:forView:, despite the fact that NSWindow's invokes [self windowNumber], because Carbon windows won't have subviews, and therefore won't have cursor rects. 571 572 573 // There's no override of _setAvoidsActivation:, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 574 575 576 // There's no override of _setFrame:, despite the fact that NSWindow's modifies _frame, because it looks like it might work on Carbon windows as is. The synchronization of the Carbon window bounds rect to the Cocoa frame rect is done in the overrides of _oldPlaceWindow: and _windowMovedToRect:. 577 578 579 // There's no override of _setFrameCommon:display:stashSize:, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 580 581 582 // There's no override of _setWindowNumber:, despite the fact that NSWindow's modifies _windowNum and invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 583 584 585 // Do what NSWindow would do, but for a Carbon window. 586 // This function is mostly cut-and-pasted from -[NSWindow _termWindowIfOwner]. M.P. Notice - 8/7/00 587 - (void)_termWindowIfOwner { 588 [self _setWindowNumber:-1]; 589 _wFlags.isTerminating = YES; 590 if (_windowRef && _windowRefIsOwned) DisposeWindow(_windowRef); 591 // KW - need to clear window shadow state so it gets reset correctly when new window created 592 // if ([_borderView respondsToSelector:@selector(setShadowState:)]) { 593 // [_borderView setShadowState:kFrameShadowNone]; 594 // } 595 _wFlags.isTerminating = NO; 596 } 597 598 599 // There's no override of _threadContext, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might not do anything that will effect a Carbon window. 600 601 602 // There's no override of _windowMoved:, despite the fact that NSWindow's operates on _windowNum, because it looks like it might work on Carbon windows as is. 603 604 605 // Do what NSWindow would do, but then sychronize the Carbon window structures. 606 - (void)_windowMovedToRect:(NSRect)actualFrame { 607 608 OSStatus osStatus; 609 610 // Do the standard Cocoa thing. 611 [super _windowMovedToRect:actualFrame]; 612 613 // Let Carbon know that the window has been moved, unless this method is being called "early." 614 if (_wFlags.visible) { 615 osStatus = WKSyncWindowWithCGAfterMove(_windowRef); 616 if (osStatus!=noErr) NSLog(@"A Carbon window's bounds couldn't be synchronized (%i).", (int)osStatus); 617 } 618 619 } 620 621 - (NSRect)constrainFrameRect:(NSRect)actualFrame toScreen:(NSScreen *)screen { 622 // let Carbon decide window size and position 623 return actualFrame; 624 } 625 626 - (void)selectKeyViewFollowingView:(NSView *)aView { 627 HIViewRef view = NULL; 628 629 view = [HIViewAdapter getHIViewForNSView:aView]; 630 631 if ( view ) 632 { 633 HIViewRef contentView; 634 635 GetRootControl( GetControlOwner( view ), &contentView ); 636 HIViewAdvanceFocus( contentView, 0 ); 637 } 638 else 639 { 640 [super selectKeyViewFollowingView:aView]; 641 } 642 } 643 644 - (void)selectKeyViewPrecedingView:(NSView *)aView { 645 HIViewRef view = NULL; 646 647 view = [HIViewAdapter getHIViewForNSView:aView]; 648 649 if ( view ) 650 { 651 HIViewRef contentView; 652 653 GetRootControl( GetControlOwner( view ), &contentView ); 654 HIViewAdvanceFocus( contentView, shiftKey ); 655 } 656 else 657 { 658 [super selectKeyViewPrecedingView:aView]; 659 } 660 } 661 662 - (void)makeKeyWindow { 663 [NSApp _setMouseActivationInProgress:NO]; 664 [NSApp setIsActive:YES]; 665 [super makeKeyWindow]; 666 WKShowKeyAndMain(); 667 } 668 669 670 // Do the right thing for a Carbon window. 671 - (BOOL)canBecomeKeyWindow { 672 673 return YES; 674 } 675 676 // Do the right thing for a Carbon window. 677 - (BOOL)canBecomeMainWindow { 678 OSStatus osStatus; 679 WindowClass windowClass; 680 // By default, Carbon windows cannot become the main window. 681 // What about when the default isn't right? Requiring subclassing seems harsh. M.P. Warning - 9/17/01 682 // KW - modify this to allow document windows to become main 683 // This is primarily to get the right look, so that you don't have two windows that both look active - one Cocoa document and one Carbon document 684 osStatus = GetWindowClass(_windowRef, &windowClass); 685 return (osStatus == noErr && windowClass == kDocumentWindowClass); 686 687 } 688 689 690 // There's no override of deminiaturize:, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 691 692 693 // There's no override of disableCursorRects, despite the fact that NSWindow's invokes [self windowNumber], because Carbon windows won't have subviews, and therefore won't have cursor rects. 694 695 696 697 // There's no override of enableCursorRects, despite the fact that NSWindow's invokes [self windowNumber], because Carbon windows won't have subviews, and therefore won't have cursor rects. 698 699 700 // Do the right thing for a Carbon window. 701 - (void)encodeWithCoder:(NSCoder *)coder { 702 703 // Actually, this will probably never be implemented. M.P. Notice - 8/2/00 704 NSLog(@"-[NSCarbonWindow encodeWithCoder:] is not implemented."); 705 706 } 707 708 709 // There's no override of frame, despite the fact that NSWindow's returns _frame, because _frame is one of the instance variables whose value we're keeping synchronized with the Carbon window. 710 711 712 // Do the right thing for a Carbon window. 713 - (id)initWithCoder:(NSCoder *)coder { 714 715 // Actually, this will probably never be implemented. M.P. Notice - 8/2/00 716 NSLog(@"-[NSCarbonWindow initWithCoder:] is not implemented."); 717 [self release]; 718 return nil; 719 720 } 721 722 723 // There's no override of level, despite the fact that NSWindow's returns _level, because _level is one of the instance variables whose value we're keeping synchronized with the Carbon window. 724 725 726 // There's no override of miniaturize:, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 727 728 729 // There's no override of resizeToScreenWithEvent:, despite the fact that NSWindow's operates on _windowNum. 730 // It looks like it's only called when an _NSForceResizeEventType event is passed into -[NSWindow sendEvent:], and I can't find any instances of that happening. 731 732 /* 733 // Do the right thing for a Carbon Window. 734 - (void)sendEvent:(NSEvent *)theEvent { 735 736 // Not all events are handled in the same manner. 737 NSEventType eventType = [theEvent type]; 738 if (eventType==NSAppKitDefined) { 739 740 // Handle the event the Cocoa way. Carbon won't understand it anyway. 741 [super sendEvent:theEvent]; 742 743 } 744 } 745 */ 746 747 // There's no override of setAcceptsMouseMovedEvents:, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 748 749 750 // There's no override of setBackingType:, despite the fact that NSWindow's invokes [self windowNumber], because it's apparently not expected to do anything anyway, judging from the current implementation of PSsetwindowtype(). 751 752 753 // Do what NSWindow would do, but for a Carbon window. 754 - (void)setContentView:(NSView *)aView { 755 756 NSRect contentFrameRect; 757 OSStatus osStatus; 758 Rect windowContentBoundsRect; 759 760 // Precondition check. 761 assert(_borderView); 762 assert([_borderView isKindOfClass:[CarbonWindowFrame class]]); 763 assert(_windowRef); 764 765 // Parameter check. 766 assert(aView); 767 assert([aView isKindOfClass:[CarbonWindowContentView class]]); 768 769 // Find out the window's Carbon window structure region (content) bounds. 770 osStatus = GetWindowBounds(_windowRef, kWindowContentRgn, &windowContentBoundsRect); 771 if (osStatus!=noErr) NSLog(@"A Carbon window's content bounds couldn't be gotten."); 772 contentFrameRect.origin = NSZeroPoint; 773 contentFrameRect.size.width = windowContentBoundsRect.right - windowContentBoundsRect.left; 774 contentFrameRect.size.height = windowContentBoundsRect.bottom - windowContentBoundsRect.top; 775 776 // If the content view is still in some other view hierarchy, pry it free. 777 [_contentView removeFromSuperview]; 778 assert(![_contentView superview]); 779 780 // Record the content view, and size it to this window's content frame. 781 _contentView = aView; 782 [_contentView setFrame:contentFrameRect]; 783 784 // Make the content view a subview of the border view. 785 [_borderView addSubview:_contentView]; 786 787 // Tell the content view it's new place in the responder chain. 788 [_contentView setNextResponder:self]; 789 790 } 791 792 793 // There's no override of setDepthLimit:, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 794 795 796 - (BOOL)worksWhenModal { 797 WindowClass windowClass = [self _carbonWindowClass]; 798 return (windowClass == kFloatingWindowClass || windowClass == kUtilityWindowClass); 799 } 800 801 - (void)_setModalWindowLevel { 802 return; 803 } 804 805 - _clearModalWindowLevel { 806 return nil; 807 } 808 809 // There's no override of setLevel:, despite the fact that NSWindow's invokes [self windowNumber], because it looks like it might work on Carbon windows as is. 810 // I thought at first that there should be a mapping between Cocoa level and Carbon window class, but experiments convince me that such is not the case. M.P. Notice - 9/18/00 811 812 813 // There's no override of windowNumber, despite the fact that NSWindow's returns _windowNum, because _windowNum is one of the instance variables whose value we're keeping synchronized with the Carbon window. 814 815 816 - (UInt32)carbonHICommandIDFromActionSelector:(SEL)inActionSelector { 817 818 // Initialize with the default return value. 819 UInt32 hiCommandID = 0; 820 821 // Pretty simple, if tedious. 822 if (inActionSelector==@selector(clear:)) hiCommandID = kHICommandClear; 823 else if (inActionSelector==@selector(copy:)) hiCommandID = kHICommandCopy; 824 else if (inActionSelector==@selector(cut:)) hiCommandID = kHICommandCut; 825 else if (inActionSelector==@selector(paste:)) hiCommandID = kHICommandPaste; 826 else if (inActionSelector==@selector(redo:)) hiCommandID = kHICommandRedo; 827 else if (inActionSelector==@selector(selectAll:)) hiCommandID = kHICommandSelectAll; 828 else if (inActionSelector==@selector(undo:)) hiCommandID = kHICommandUndo; 829 830 // Done. 831 return hiCommandID; 832 833 } 834 835 836 - (void)sendCarbonProcessHICommandEvent:(UInt32)inHICommandID { 837 838 EventTargetRef eventTargetRef; 839 HICommand hiCommand; 840 OSStatus osStatus; 841 842 // Initialize for safe error handling. 843 EventRef eventRef = NULL; 844 845 // Create a Process Command event. Don't mention anything about the menu item, because we don't want the Carbon Event handler fiddling with it. 846 hiCommand.attributes = 0; 847 hiCommand.commandID = inHICommandID; 848 hiCommand.menu.menuRef = 0; 849 hiCommand.menu.menuItemIndex = 0; 850 osStatus = CreateEvent(NULL, kEventClassCommand, kEventCommandProcess, GetCurrentEventTime(), kEventAttributeNone, &eventRef); 851 if (osStatus!=noErr) { 852 NSLog(@"CreateEvent() returned %i.", (int)osStatus); 853 goto CleanUp; 854 } 855 osStatus = SetEventParameter(eventRef, kEventParamDirectObject, typeHICommand, sizeof(HICommand), &hiCommand); 856 if (osStatus!=noErr) { 857 NSLog(@"SetEventParameter() returned %i.", (int)osStatus); 858 goto CleanUp; 859 } 860 861 // Send a Carbon event to whatever has the Carbon user focus. 862 eventTargetRef = GetUserFocusEventTarget(); 863 osStatus = SendEventToEventTarget(eventRef, eventTargetRef); 864 if (osStatus!=noErr) { 865 NSLog(@"SendEventToEventTarget() returned %i.", (int)osStatus); 866 goto CleanUp; 867 } 868 869 CleanUp: 870 871 // Clean up. 872 if (eventRef) ReleaseEvent(eventRef); 873 874 } 875 876 877 - (Boolean)sendCarbonUpdateHICommandStatusEvent:(UInt32)inHICommandID withMenuRef:(MenuRef)inMenuRef andMenuItemIndex:(UInt16)inMenuItemIndex { 878 879 EventTargetRef eventTargetRef; 880 HICommand hiCommand; 881 OSStatus osStatus; 882 883 // Initialize for safe error handling and flag returning. 884 Boolean eventWasHandled = FALSE; 885 EventRef eventRef = NULL; 886 887 // Create a Process Command event. Don't mention anything about the menu item, because we don't want the Carbon Event handler fiddling with it. 888 hiCommand.attributes = kHICommandFromMenu; 889 hiCommand.commandID = inHICommandID; 890 hiCommand.menu.menuRef = inMenuRef; 891 hiCommand.menu.menuItemIndex = inMenuItemIndex; 892 osStatus = CreateEvent(NULL, kEventClassCommand, kEventCommandUpdateStatus, GetCurrentEventTime(), kEventAttributeNone, &eventRef); 893 if (osStatus!=noErr) { 894 NSLog(@"CreateEvent() returned %i.", (int)osStatus); 895 goto CleanUp; 896 } 897 osStatus = SetEventParameter(eventRef, kEventParamDirectObject, typeHICommand, sizeof(HICommand), &hiCommand); 898 if (osStatus!=noErr) { 899 NSLog(@"SetEventParameter() returned %i.", (int)osStatus); 900 goto CleanUp; 901 } 902 903 // Send a Carbon event to whatever has the Carbon user focus. 904 eventTargetRef = GetUserFocusEventTarget(); 905 osStatus = SendEventToEventTarget(eventRef, eventTargetRef); 906 if (osStatus==noErr) { 907 eventWasHandled = TRUE; 908 } else if (osStatus!=eventNotHandledErr) { 909 NSLog(@"SendEventToEventTarget() returned %i.", (int)osStatus); 910 goto CleanUp; 911 } 912 913 CleanUp: 914 915 // Clean up. 916 if (eventRef) ReleaseEvent(eventRef); 917 918 // Done. 919 return eventWasHandled; 920 921 } 922 923 - (void)_handleRootBoundsChanged 924 { 925 HIViewRef root = HIViewGetRoot( _windowRef ); 926 HIRect frame; 927 928 HIViewGetFrame( root, &frame ); 929 [_borderView setFrameSize:*(NSSize*)&frame.size]; 930 } 931 932 - (void)_handleContentBoundsChanged 933 { 934 HIViewRef root, contentView; 935 HIRect rootBounds, contentFrame; 936 NSRect oldContentFrameRect; 937 938 root = HIViewGetRoot( _windowRef ); 939 HIViewFindByID( root, kHIViewWindowContentID, &contentView ); 940 HIViewGetFrame( contentView, &contentFrame ); 941 HIViewGetBounds( root, &rootBounds ); 942 943 // Set the content view's frame rect from the Carbon window's content region bounds. 944 contentFrame.origin.y = rootBounds.size.height - CGRectGetMaxY( contentFrame ); 945 946 oldContentFrameRect = [_contentView frame]; 947 if ( !NSEqualRects( *(NSRect*)&contentFrame, oldContentFrameRect ) ) { 948 [_contentView setFrame:*(NSRect*)&contentFrame]; 949 } 950 } 951 952 - (OSStatus)_handleCarbonEvent:(EventRef)inEvent callRef:(EventHandlerCallRef)inCallRef { 953 OSStatus result = eventNotHandledErr; 954 955 switch ( GetEventClass( inEvent ) ) 956 { 957 case kEventClassControl: 958 { 959 ControlRef control; 960 961 check( GetEventKind( inEvent ) == kEventControlBoundsChanged ); 962 963 GetEventParameter( inEvent, kEventParamDirectObject, typeControlRef, NULL, 964 sizeof( ControlRef ), NULL, &control ); 965 966 if ( control == HIViewGetRoot( _windowRef ) ) 967 [self _handleRootBoundsChanged]; 968 else 969 [self _handleContentBoundsChanged]; 970 } 971 break; 972 973 case kEventClassWindow: 974 switch ( GetEventKind( inEvent ) ) 975 { 976 case kEventWindowShown: 977 [self _setVisible:YES]; 978 break; 979 980 case kEventWindowHidden: 981 [self _setVisible:NO]; 982 break; 983 984 case kEventWindowActivated: 985 [self makeKeyWindow]; 986 break; 987 988 case kEventWindowDeactivated: 989 [self resignKeyWindow]; 990 break; 991 992 case kEventWindowBoundsChanged: 993 [self reconcileToCarbonWindowBounds]; 994 break; 995 } 996 break; 997 } 998 999 return result; 1000 } 1001 1002 // Handle various events that Carbon is sending to our window. 1003 static OSStatus NSCarbonWindowHandleEvent(EventHandlerCallRef inEventHandlerCallRef, EventRef inEventRef, void *inUserData) { 1004 1005 // default action is to send event to next handler. We modify osStatus as necessary where we don't want this behavior 1006 OSStatus osStatus = eventNotHandledErr; 1007 1008 // We do different things for different event types. 1009 CarbonWindowAdapter *carbonWindow = (CarbonWindowAdapter *)inUserData; 1010 1011 osStatus = [carbonWindow _handleCarbonEvent: inEventRef callRef: inEventHandlerCallRef]; 1012 1013 // Done. If we want to propagate the event, we return eventNotHandledErr to send it to the next handler 1014 return osStatus; 1015 1016 } 1017 1018 // [3364117] We need to make sure this does not fall through to the AppKit implementation! bad things happen. 1019 - (void)_reallyDoOrderWindow:(NSWindowOrderingMode)place relativeTo:(int)otherWin findKey:(BOOL)doKeyCalc forCounter:(BOOL)isACounter force:(BOOL)doForce isModal:(BOOL)isModal { 1020 } 1021 1022 - (NSRect) _growBoxRect 1023 { 1024 WindowAttributes attrs; 1025 NSRect retRect = NSZeroRect; 1026 1027 GetWindowAttributes( _windowRef, &attrs ); 1028 1029 if ( attrs & kWindowResizableAttribute ) 1030 { 1031 HIRect bounds, rect; 1032 HIViewRef view; 1033 1034 HIViewGetBounds( HIViewGetRoot( _windowRef ), &bounds ); 1035 HIViewFindByID( HIViewGetRoot( _windowRef ), kHIViewWindowGrowBoxID, &view ); 1036 HIViewGetFrame( view, &rect ); 1037 1038 rect.origin.y = bounds.size.height - CGRectGetMaxY( rect ) - 1; 1039 rect.origin.x++; 1040 1041 retRect = *(NSRect*)▭ 1042 } 1043 1044 return retRect; 1045 } 1046 1047 @end // implementation CarbonWindowAdapter 1048 1049 #endif 1050