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 <WebCore/RunLoop.h>
77#import <runtime/InitializeThreading.h>
78#import <wtf/MainThread.h>
79
80#import "WebKitLogging.h"
81#import "WebNSObjectExtras.h"
82#import "WebTypesInternal.h"
83
84@interface NSWindow(HIWebFrameView)
85- (id)_initContent:(const NSRect *)contentRect styleMask:(unsigned int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag contentView:aView;
86- (void)_oldPlaceWindow:(NSRect)frameRect;
87- (void)_windowMovedToRect:(NSRect)actualFrame;
88- (void)_setWindowNumber:(NSInteger)nativeWindow;
89- (NSGraphicsContext *)_threadContext;
90- (void)_setFrame:(NSRect)newWindowFrameRect;
91- (void)_setVisible:(BOOL)flag;
92@end
93
94@interface NSApplication(HIWebFrameView)
95- (void)setIsActive:(BOOL)aFlag;
96- (id)_setMouseActivationInProgress:(BOOL)flag;
97- (BOOL)_handleKeyEquivalent:(NSEvent*)theEvent;
98@end
99
100@interface NSInputContext
101- (BOOL)processInputKeyBindings:(NSEvent *)event;
102@end
103
104// Forward declarations.
105static OSStatus NSCarbonWindowHandleEvent(EventHandlerCallRef inEventHandlerCallRef, EventRef inEventRef, void *inUserData);
106
107@implementation CarbonWindowAdapter
108
109
110// Return an appropriate window frame class.
111+ (Class)frameViewClassForStyleMask:(unsigned int)style {
112
113    // There's only one appropriate window style, and only one appropriate window frame class.
114    assert(style & WKCarbonWindowMask());
115    return [CarbonWindowFrame class];
116
117}
118
119
120// Overriding of the parent class' designated initializer, just for safety's sake.
121- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)style backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag {
122
123    // Do the standard Cocoa thing.
124    self = [super initWithContentRect:contentRect styleMask:style backing:bufferingType defer:flag];
125    if (self==nil) return nil;
126
127    // Simple.
128    _windowRef = NULL;
129    _windowRefIsOwned = NO;
130    _eventHandler = NULL;
131
132    // Done.
133    return self;
134
135}
136
137// 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.
138- (id)initWithCarbonWindowRef:(WindowRef)inWindowRef takingOwnership:(BOOL)inWindowRefIsOwned disableOrdering:(BOOL)inDisableOrdering carbon:(BOOL)inCarbon {
139
140    NSBackingStoreType backingStoreType;
141    CarbonWindowContentView *carbonWindowContentView;
142    NSWindow *windowAsProperty;
143    OSStatus osStatus;
144    UInt32 windowFeatures;
145    WindowAttributes windowAttributes;
146    unsigned int styleMask;
147    void *nativeWindow;
148    WindowModality windowModality;
149	ControlRef		contentView;
150
151    // Simple.
152    // 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
153    _windowRef = inWindowRef;
154    //_auxiliaryStorage->_windowRef = inWindowRef;
155    _windowRefIsOwned = inWindowRefIsOwned;
156	_carbon = inCarbon;
157
158    // Find out the window's CoreGraphics window reference.
159    nativeWindow = WKGetNativeWindowFromWindowRef(inWindowRef);
160
161    // Find out the window's Carbon window attributes.
162    GetWindowAttributes(inWindowRef, &windowAttributes);
163
164    // Find out the window's Carbon window features.
165    GetWindowFeatures(inWindowRef, &windowFeatures);
166
167    // Figure out the window's backing store type.
168    // At one time, this had code stolen from CreatePlatformWindow in HIToolbox/Windows/Platform/CGSPlatform.c
169	// But now the non-retained window class is a Carbon secret that's not even in
170	// WindowsPriv.h; maybe we'll have to revisit this if someone needs to use WebKit
171	// in a non-retained window.
172    backingStoreType = NSBackingStoreRetained;
173
174    // Figure out the window's style mask.
175    styleMask = WKCarbonWindowMask();
176    if (windowAttributes & kWindowCloseBoxAttribute) styleMask |= NSClosableWindowMask;
177    if (windowAttributes & kWindowResizableAttribute) styleMask |= NSResizableWindowMask;
178    if (windowFeatures & kWindowCanCollapse) styleMask |= NSMiniaturizableWindowMask;
179    if (windowFeatures & kWindowHasTitleBar) styleMask |= NSTitledWindowMask;
180
181    osStatus = GetWindowModality(_windowRef, &windowModality, NULL);
182    if (osStatus != noErr) {
183        NSLog(@"Couldn't get window modality: error=%ld", osStatus);
184        return nil;
185    }
186
187    // Create one of our special content views.
188    carbonWindowContentView = [[[CarbonWindowContentView alloc] init] autorelease];
189
190    // 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.
191    self = (CarbonWindowAdapter*)[super _initContent:NULL styleMask:styleMask backing:backingStoreType defer:YES contentView:carbonWindowContentView];
192    if (!self) return nil;
193    assert(_contentView);
194
195    // Record accurately whether or not this window has a shadow, in case someone asks.
196 //   _auxiliaryStorage->_auxWFlags.hasShadow = (windowAttributes & kWindowNoShadowAttribute) ? NO : YES;
197
198    // Record the window number.
199    [self _setWindowNumber:(NSInteger)nativeWindow];
200
201    // Set up from the frame rectangle.
202    // 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
203    [self reconcileToCarbonWindowBounds];
204
205    // Install an event handler for the Carbon window events in which we're interested.
206    const EventTypeSpec kEvents[] = {
207            { kEventClassWindow, kEventWindowActivated },
208            { kEventClassWindow, kEventWindowDeactivated },
209            { kEventClassWindow, kEventWindowBoundsChanged },
210            { kEventClassWindow, kEventWindowShown },
211            { kEventClassWindow, kEventWindowHidden }
212    };
213
214    const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged };
215
216    osStatus = InstallEventHandler( GetWindowEventTarget(_windowRef), NSCarbonWindowHandleEvent, GetEventTypeCount( kEvents ), kEvents, (void*)self, &_eventHandler);
217    if (osStatus!=noErr) {
218            [self release];
219            return nil;
220    }
221
222    osStatus = InstallEventHandler( GetControlEventTarget( HIViewGetRoot( _windowRef ) ), NSCarbonWindowHandleEvent, 1, &kControlBoundsChangedEvent, (void*)self, &_eventHandler);
223    if (osStatus!=noErr) {
224            [self release];
225            return nil;
226    }
227
228    HIViewFindByID( HIViewGetRoot( _windowRef ), kHIViewWindowContentID, &contentView );
229    osStatus = InstallEventHandler( GetControlEventTarget( contentView ), NSCarbonWindowHandleEvent, 1, &kControlBoundsChangedEvent, (void*)self, &_eventHandler);
230    if (osStatus!=noErr) {
231            [self release];
232            return nil;
233    }
234
235    // Put a pointer to this Cocoa NSWindow in a Carbon window property tag.
236    // Right now, this is just used by NSViewCarbonControl.  M.P. Notice - 10/9/00
237    windowAsProperty = self;
238    osStatus = SetWindowProperty(_windowRef, WKCarbonWindowPropertyCreator(), WKCarbonWindowPropertyTag(), sizeof(NSWindow *), &windowAsProperty);
239    if (osStatus!=noErr) {
240        [self release];
241        return nil;
242    }
243
244    // 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.
245    _passingCarbonWindowActivationEvents = NO;
246
247    // Be sure to sync up visibility
248    [self _setVisible:(BOOL)IsWindowVisible( _windowRef )];
249
250    // Done.
251    return self;
252
253}
254
255- (void)setViewsNeedDisplay:(BOOL)wellDoThey {
256	// Make sure we can flush anything that needs it.
257
258	// We need to sync the context here. I was hoping I didn't need to do this,
259	// but apparently when scrolling, the AppKit view system draws directly.
260	// When this occurs, I cannot intercept it to make it draw in my HIView
261	// context. What ends up happening is that it draws, but nothing ever
262	// flushes it.
263
264	if ( [self windowNumber] != -1 )
265	{
266		CGContextRef cgContext = (CGContextRef)[[self _threadContext] graphicsPort];
267		CGContextSynchronize( cgContext );
268	}
269}
270
271+ (void)initialize
272{
273    JSC::initializeThreading();
274    WTF::initializeMainThreadToProcessMainThread();
275    WebCore::RunLoop::initializeMainRunLoop();
276    WebCoreObjCFinalizeOnMainThread(self);
277}
278
279// 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.
280- (id)initWithCarbonWindowRef:(WindowRef)inWindowRef takingOwnership:(BOOL)inWindowRefIsOwned {
281    // 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.
282    return [self initWithCarbonWindowRef:inWindowRef takingOwnership:inWindowRefIsOwned disableOrdering:YES carbon:NO];
283}
284
285
286// Clean up.
287- (void)dealloc {
288    if (WebCoreObjCScheduleDeallocateOnMainThread([CarbonWindowAdapter class], self))
289        return;
290
291    // Clean up, if necessary.
292    // 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
293    if (_eventHandler) RemoveEventHandler(_eventHandler);
294
295    // Do the standard Cocoa thing.
296    [super dealloc];
297}
298
299- (void)finalize {
300    ASSERT_MAIN_THREAD();
301    if (_eventHandler) RemoveEventHandler(_eventHandler);
302    [super finalize];
303}
304
305- (WindowRef)windowRef {
306
307    // Simple.
308    return _windowRef;
309
310}
311
312// should always be YES, but check in order to avoid initialization or deallocation surprises
313- (BOOL)_hasWindowRef {
314    return (_windowRef != NULL);
315}
316
317// an NSCarbonWindow does not manage the windowRef.  The windowRef manages the NSCarbonWindow
318- (BOOL)_managesWindowRef {
319    return NO;
320}
321
322- (void)_removeWindowRef {
323    _windowRef = NULL;
324
325    if (_eventHandler) RemoveEventHandler(_eventHandler);
326
327	_eventHandler = NULL;
328}
329
330- (WindowClass)_carbonWindowClass {
331    WindowClass windowClass = kDocumentWindowClass;
332    OSStatus osStatus;
333
334    if ([self _hasWindowRef]) {
335        osStatus = GetWindowClass([self windowRef], &windowClass);
336        if (osStatus != noErr) {
337            NSLog(@"Couldn't get window class: error=%ld", osStatus);
338        }
339    }
340    return windowClass;
341}
342
343// 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.
344- (BOOL)reconcileToCarbonWindowBounds {
345
346    OSStatus osStatus;
347    NSRect newContentFrameRect;
348    NSRect newWindowFrameRect;
349    NSRect oldContentFrameRect;
350    Rect windowContentBoundsRect;
351    Rect windowStructureBoundsRect;
352
353    // Initialize for safe returning.
354    BOOL reconciliationWasNecessary = NO;
355
356    // Precondition check.
357    assert(_contentView);
358
359    // Get the Carbon window's bounds, which are expressed in global screen coordinates, with (0,0) at the top-left of the main screen.
360    osStatus = GetWindowBounds(_windowRef, kWindowStructureRgn, &windowStructureBoundsRect);
361    if (osStatus!=noErr) NSLog(@"A Carbon window's structure bounds couldn't be gotten.");
362    osStatus = GetWindowBounds(_windowRef, kWindowContentRgn, &windowContentBoundsRect);
363    if (osStatus!=noErr) NSLog(@"A Carbon window's content bounds couldn't be gotten.");
364
365    // Set the frame rectangle of the border view and this window from the Carbon window's structure region bounds.
366    newWindowFrameRect.origin.x = windowStructureBoundsRect.left;
367    newWindowFrameRect.origin.y = NSMaxY([(NSScreen *)[[NSScreen screens] objectAtIndex:0] frame]) - windowStructureBoundsRect.bottom;
368    newWindowFrameRect.size.width = windowStructureBoundsRect.right - windowStructureBoundsRect.left;
369    newWindowFrameRect.size.height = windowStructureBoundsRect.bottom - windowStructureBoundsRect.top;
370    if (!NSEqualRects(newWindowFrameRect, _frame)) {
371        [self _setFrame:newWindowFrameRect];
372        [_borderView setFrameSize:newWindowFrameRect.size];
373        reconciliationWasNecessary = YES;
374    }
375
376    // Set the content view's frame rect from the Carbon window's content region bounds.
377    newContentFrameRect.origin.x = windowContentBoundsRect.left - windowStructureBoundsRect.left;
378    newContentFrameRect.origin.y = windowStructureBoundsRect.bottom - windowContentBoundsRect.bottom;
379    newContentFrameRect.size.width = windowContentBoundsRect.right - windowContentBoundsRect.left;
380    newContentFrameRect.size.height = windowContentBoundsRect.bottom - windowContentBoundsRect.top;
381    oldContentFrameRect = [(NSView *)_contentView frame];
382    if (!NSEqualRects(newContentFrameRect, oldContentFrameRect)) {
383        [(NSView *)_contentView setFrame:newContentFrameRect];
384        reconciliationWasNecessary = YES;
385    }
386
387    // Done.
388    return reconciliationWasNecessary;
389
390}
391
392
393// Handle an event just like an NSWindow would.
394- (void)sendSuperEvent:(NSEvent *)inEvent {
395
396    // Filter out a few events that just result in complaints in the log.
397    // Ignore some unknown event that gets sent when NSTextViews in printing accessory views are focused.  M.P. Notice - 12/7/00
398    BOOL ignoreEvent = NO;
399    NSEventType eventType = [inEvent type];
400    if (eventType==NSSystemDefined) {
401        short eventSubtype = [inEvent subtype];
402        if (eventSubtype==7) {
403            ignoreEvent = YES;
404        }
405    } else if (eventType == NSKeyDown) {
406        // Handle command-space as [NSApp sendEvent:] does.
407        if ([NSInputContext processInputKeyBindings:inEvent]) {
408            return;
409        }
410    }
411
412    // Simple.
413    if (!ignoreEvent) [super sendEvent:inEvent];
414}
415
416- (void)relinquishFocus
417{
418    NSResponder*  firstResponder;
419
420    // Carbon thinks that a control has the keyboard focus,
421    // or we wouldn't be being asked to relinquish focus.
422
423	firstResponder = [self firstResponder];
424	if ([firstResponder isKindOfClass:[NSView class]] ){
425		// Make the window the first responder, so that no view is the key view.
426        [self makeFirstResponder:self];
427    }
428}
429
430- (BOOL)makeFirstResponder:(NSResponder *)aResponder
431{
432    // Let NSWindow focus the appropriate NSView.
433    if (![super makeFirstResponder:aResponder])
434        return NO;
435
436    // Now, if the view we're focusing is in a HIWebView, find the
437    // corresponding HIWebView for the NSView, and tell carbon to
438    // clear any focused control.
439    HIViewRef viewRef = 0;
440    NSResponder *firstResponder = [self firstResponder];
441    if ([firstResponder isKindOfClass:[NSView class]]) {
442        NSView *view = (NSView *)firstResponder;
443        while (view) {
444            viewRef = [HIViewAdapter getHIViewForNSView:view];
445            if (viewRef)
446                break;
447            view = [view superview];
448        }
449    }
450
451    HIViewRef focus;
452    GetKeyboardFocus (_windowRef, &focus);
453    if (focus != viewRef) {
454        SetKeyboardFocus (_windowRef, viewRef, kControlIndicatorPart );
455    }
456
457    return YES;
458}
459
460// 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.
461
462
463// 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.
464
465
466// 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
467/*
468// Do the right thing for a Carbon window.
469- (void)_blockHeartBeat:(BOOL)flag {
470
471    ControlRef defaultButton;
472    OSStatus osStatus;
473
474    // Do the standard Cocoa thing.
475    [super _blockHeartBeat:flag];
476
477    // If there's a default Carbon button in this Carbon window, make it stop pulsing, the Carbon way.
478    // This is inspired by HIToolbox/Controls/Definitions/ButtonCDEF.c's ButtonEventHandler().  M.P. Notice - 12/5/00
479    osStatus = GetWindowDefaultButton(_windowRef, &defaultButton);
480    if (osStatus==noErr && defaultButton) {
481        Boolean anotherButtonIsTracking = flag ? TRUE : FALSE;
482        osStatus = SetControlData(defaultButton, kControlNoPart, kControlPushButtonAnotherButtonTrackingTag, sizeof(Boolean), &anotherButtonIsTracking);
483        if (osStatus==noErr) DrawOneControl(defaultButton);
484        else NSLog(@"Some data couldn't be set in a Carbon control.");
485    }
486
487}
488*/
489
490
491// Do the right thing for a Carbon window.
492- (void)_cancelKey:(id)sender {
493
494    // 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.
495    ControlRef cancelButton;
496    GetWindowCancelButton(_windowRef, &cancelButton);
497    if (cancelButton) {
498        if (IsControlActive(cancelButton)) {
499            HIViewSimulateClick(cancelButton, kControlButtonPart, 0, NULL);
500        }
501    }
502
503}
504
505
506
507// Do the right thing for a Carbon window.
508- (void)_commonAwake {
509
510    // 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.
511    NSLog(@"-[NSCarbonWindow _commonAwake] is not implemented.");
512
513}
514
515
516// 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:].
517
518
519// Do the right thing for a Carbon window.
520- (id)_destroyRealWindow:(BOOL)orderingOut {
521
522    // Complain, because this should never be called.  We don't support one-shot NSCarbonWindows.
523    NSLog(@"-[NSCarbonWindow _destroyRealWindow:] is not implemented.");
524    return self;
525
526}
527
528
529// 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.
530
531
532// 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.
533
534
535// 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.
536
537
538// 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.
539
540
541// 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:].
542
543
544// 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:].
545
546
547// Do what NSWindow would do, but then sychronize the Carbon window structures.
548- (void)_oldPlaceWindow:(NSRect)frameRect {
549
550    OSStatus osStatus;
551
552    // Do the standard Cocoa thing.
553    [super _oldPlaceWindow:frameRect];
554
555    // Tell Carbon to update its various regions.
556    // 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
557    osStatus = WKSyncWindowWithCGAfterMove(_windowRef);
558    if (osStatus!=noErr) NSLog(@"A Carbon window's bounds couldn't be synchronized (%i).", (int)osStatus);
559
560}
561
562
563// 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.
564
565
566// 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.
567
568
569// 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.
570
571
572// 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.
573
574
575// 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.
576
577
578// 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:.
579
580
581// 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.
582
583
584// 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.
585
586
587// Do what NSWindow would do, but for a Carbon window.
588// This function is mostly cut-and-pasted from -[NSWindow _termWindowIfOwner].  M.P. Notice - 8/7/00
589- (void)_termWindowIfOwner {
590    [self _setWindowNumber:-1];
591    _wFlags.isTerminating = YES;
592    if (_windowRef && _windowRefIsOwned) DisposeWindow(_windowRef);
593    // KW - need to clear window shadow state so it gets reset correctly when new window created
594//    if ([_borderView respondsToSelector:@selector(setShadowState:)]) {
595//        [_borderView setShadowState:kFrameShadowNone];
596//    }
597    _wFlags.isTerminating = NO;
598}
599
600
601// 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.
602
603
604// 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.
605
606
607// Do what NSWindow would do, but then sychronize the Carbon window structures.
608- (void)_windowMovedToRect:(NSRect)actualFrame {
609
610    OSStatus osStatus;
611
612    // Do the standard Cocoa thing.
613    [super _windowMovedToRect:actualFrame];
614
615    // Let Carbon know that the window has been moved, unless this method is being called "early."
616    if (_wFlags.visible) {
617        osStatus = WKSyncWindowWithCGAfterMove(_windowRef);
618        if (osStatus!=noErr) NSLog(@"A Carbon window's bounds couldn't be synchronized (%i).", (int)osStatus);
619    }
620
621}
622
623- (NSRect)constrainFrameRect:(NSRect)actualFrame toScreen:(NSScreen *)screen {
624    // let Carbon decide window size and position
625    return actualFrame;
626}
627
628- (void)selectKeyViewFollowingView:(NSView *)aView {
629	HIViewRef	view = NULL;
630
631	view = [HIViewAdapter getHIViewForNSView:aView];
632
633	if ( view )
634	{
635		HIViewRef	contentView;
636
637		GetRootControl( GetControlOwner( view ), &contentView );
638		HIViewAdvanceFocus( contentView, 0 );
639	}
640	else
641	{
642		[super selectKeyViewFollowingView:aView];
643	}
644}
645
646- (void)selectKeyViewPrecedingView:(NSView *)aView {
647	HIViewRef	view = NULL;
648
649	view = [HIViewAdapter getHIViewForNSView:aView];
650
651	if ( view )
652	{
653		HIViewRef	contentView;
654
655		GetRootControl( GetControlOwner( view ), &contentView );
656		HIViewAdvanceFocus( contentView, shiftKey );
657	}
658	else
659	{
660		[super selectKeyViewPrecedingView:aView];
661	}
662}
663
664- (void)makeKeyWindow {
665	[NSApp _setMouseActivationInProgress:NO];
666	[NSApp setIsActive:YES];
667	[super makeKeyWindow];
668	WKShowKeyAndMain();
669}
670
671
672// Do the right thing for a Carbon window.
673- (BOOL)canBecomeKeyWindow {
674
675    return YES;
676}
677
678// Do the right thing for a Carbon window.
679- (BOOL)canBecomeMainWindow {
680    OSStatus osStatus;
681    WindowClass windowClass;
682    // By default, Carbon windows cannot become the main window.
683    // What about when the default isn't right?  Requiring subclassing seems harsh.  M.P. Warning - 9/17/01
684    // KW -  modify this to allow document windows to become main
685    // 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
686    osStatus = GetWindowClass(_windowRef, &windowClass);
687    return (osStatus == noErr && windowClass == kDocumentWindowClass);
688
689}
690
691
692// 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.
693
694
695// 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.
696
697
698
699// 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.
700
701
702// Do the right thing for a Carbon window.
703- (void)encodeWithCoder:(NSCoder *)coder {
704
705    // Actually, this will probably never be implemented.  M.P. Notice - 8/2/00
706    NSLog(@"-[NSCarbonWindow encodeWithCoder:] is not implemented.");
707
708}
709
710
711// 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.
712
713
714// Do the right thing for a Carbon window.
715- (id)initWithCoder:(NSCoder *)coder {
716
717    // Actually, this will probably never be implemented.  M.P. Notice - 8/2/00
718    NSLog(@"-[NSCarbonWindow initWithCoder:] is not implemented.");
719    [self release];
720    return nil;
721
722}
723
724
725// 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.
726
727
728// 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.
729
730
731// There's no override of resizeToScreenWithEvent:, despite the fact that NSWindow's operates on _windowNum.
732// 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.
733
734/*
735// Do the right thing for a Carbon Window.
736- (void)sendEvent:(NSEvent *)theEvent {
737
738    // Not all events are handled in the same manner.
739    NSEventType eventType = [theEvent type];
740    if (eventType==NSAppKitDefined) {
741
742        // Handle the event the Cocoa way.  Carbon won't understand it anyway.
743        [super sendEvent:theEvent];
744
745    }
746}
747*/
748
749// 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.
750
751
752// 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().
753
754
755// Do what NSWindow would do, but for a Carbon window.
756- (void)setContentView:(NSView *)aView {
757
758    NSRect contentFrameRect;
759    OSStatus osStatus;
760    Rect windowContentBoundsRect;
761
762    // Precondition check.
763    assert(_borderView);
764    assert([_borderView isKindOfClass:[CarbonWindowFrame class]]);
765    assert(_windowRef);
766
767    // Parameter check.
768    assert(aView);
769    assert([aView isKindOfClass:[CarbonWindowContentView class]]);
770
771    // Find out the window's Carbon window structure region (content) bounds.
772    osStatus = GetWindowBounds(_windowRef, kWindowContentRgn, &windowContentBoundsRect);
773    if (osStatus!=noErr) NSLog(@"A Carbon window's content bounds couldn't be gotten.");
774    contentFrameRect.origin = NSZeroPoint;
775    contentFrameRect.size.width = windowContentBoundsRect.right - windowContentBoundsRect.left;
776    contentFrameRect.size.height = windowContentBoundsRect.bottom - windowContentBoundsRect.top;
777
778    // If the content view is still in some other view hierarchy, pry it free.
779    [_contentView removeFromSuperview];
780    assert(![_contentView superview]);
781
782    // Record the content view, and size it to this window's content frame.
783    _contentView = aView;
784    [(NSView *)_contentView setFrame:contentFrameRect];
785
786    // Make the content view a subview of the border view.
787    [_borderView addSubview:_contentView];
788
789    // Tell the content view it's new place in the responder chain.
790    [_contentView setNextResponder:self];
791
792}
793
794
795// 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.
796
797
798- (BOOL)worksWhenModal {
799    WindowClass windowClass = [self _carbonWindowClass];
800    return (windowClass == kFloatingWindowClass || windowClass == kUtilityWindowClass);
801}
802
803- (void)_setModalWindowLevel {
804    return;
805}
806
807- (id)_clearModalWindowLevel {
808    return nil;
809}
810
811// 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.
812// 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
813
814
815// 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.
816
817
818- (UInt32)carbonHICommandIDFromActionSelector:(SEL)inActionSelector {
819
820    // Initialize with the default return value.
821    UInt32 hiCommandID = 0;
822
823    // Pretty simple, if tedious.
824    if (inActionSelector==@selector(clear:)) hiCommandID = kHICommandClear;
825    else if (inActionSelector==@selector(copy:)) hiCommandID = kHICommandCopy;
826    else if (inActionSelector==@selector(cut:)) hiCommandID = kHICommandCut;
827    else if (inActionSelector==@selector(paste:)) hiCommandID = kHICommandPaste;
828    else if (inActionSelector==@selector(redo:)) hiCommandID = kHICommandRedo;
829    else if (inActionSelector==@selector(selectAll:)) hiCommandID = kHICommandSelectAll;
830    else if (inActionSelector==@selector(undo:)) hiCommandID = kHICommandUndo;
831
832    // Done.
833    return hiCommandID;
834
835}
836
837
838- (void)sendCarbonProcessHICommandEvent:(UInt32)inHICommandID {
839
840    EventTargetRef eventTargetRef;
841    HICommand hiCommand;
842    OSStatus osStatus;
843
844    // Initialize for safe error handling.
845    EventRef eventRef = NULL;
846
847    // 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.
848    hiCommand.attributes = 0;
849    hiCommand.commandID = inHICommandID;
850    hiCommand.menu.menuRef = 0;
851    hiCommand.menu.menuItemIndex = 0;
852    osStatus = CreateEvent(NULL, kEventClassCommand, kEventCommandProcess, GetCurrentEventTime(), kEventAttributeNone, &eventRef);
853    if (osStatus!=noErr) {
854        NSLog(@"CreateEvent() returned %i.", (int)osStatus);
855        goto CleanUp;
856    }
857    osStatus = SetEventParameter(eventRef, kEventParamDirectObject, typeHICommand, sizeof(HICommand), &hiCommand);
858    if (osStatus!=noErr) {
859        NSLog(@"SetEventParameter() returned %i.", (int)osStatus);
860        goto CleanUp;
861    }
862
863    // Send a Carbon event to whatever has the Carbon user focus.
864    eventTargetRef = GetUserFocusEventTarget();
865    osStatus = SendEventToEventTarget(eventRef, eventTargetRef);
866    if (osStatus!=noErr) {
867        NSLog(@"SendEventToEventTarget() returned %i.", (int)osStatus);
868        goto CleanUp;
869    }
870
871CleanUp:
872
873    // Clean up.
874    if (eventRef) ReleaseEvent(eventRef);
875
876}
877
878
879- (Boolean)sendCarbonUpdateHICommandStatusEvent:(UInt32)inHICommandID withMenuRef:(MenuRef)inMenuRef andMenuItemIndex:(UInt16)inMenuItemIndex {
880
881    EventTargetRef eventTargetRef;
882    HICommand hiCommand;
883    OSStatus osStatus;
884
885    // Initialize for safe error handling and flag returning.
886    Boolean eventWasHandled = FALSE;
887    EventRef eventRef = NULL;
888
889    // 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.
890    hiCommand.attributes = kHICommandFromMenu;
891    hiCommand.commandID = inHICommandID;
892    hiCommand.menu.menuRef = inMenuRef;
893    hiCommand.menu.menuItemIndex = inMenuItemIndex;
894    osStatus = CreateEvent(NULL, kEventClassCommand, kEventCommandUpdateStatus, GetCurrentEventTime(), kEventAttributeNone, &eventRef);
895    if (osStatus!=noErr) {
896        NSLog(@"CreateEvent() returned %i.", (int)osStatus);
897        goto CleanUp;
898    }
899    osStatus = SetEventParameter(eventRef, kEventParamDirectObject, typeHICommand, sizeof(HICommand), &hiCommand);
900    if (osStatus!=noErr) {
901        NSLog(@"SetEventParameter() returned %i.", (int)osStatus);
902        goto CleanUp;
903    }
904
905    // Send a Carbon event to whatever has the Carbon user focus.
906    eventTargetRef = GetUserFocusEventTarget();
907    osStatus = SendEventToEventTarget(eventRef, eventTargetRef);
908    if (osStatus==noErr) {
909        eventWasHandled = TRUE;
910    } else if (osStatus!=eventNotHandledErr) {
911        NSLog(@"SendEventToEventTarget() returned %i.", (int)osStatus);
912        goto CleanUp;
913    }
914
915CleanUp:
916
917    // Clean up.
918    if (eventRef) ReleaseEvent(eventRef);
919
920    // Done.
921    return eventWasHandled;
922
923}
924
925- (void)_handleRootBoundsChanged
926{
927	HIViewRef	root = HIViewGetRoot( _windowRef );
928	HIRect		frame;
929
930	HIViewGetFrame( root, &frame );
931	[_borderView setFrameSize:*(NSSize*)&frame.size];
932}
933
934- (void)_handleContentBoundsChanged
935{
936	HIViewRef	root, contentView;
937	HIRect		rootBounds, contentFrame;
938	NSRect		oldContentFrameRect;
939
940	root = HIViewGetRoot( _windowRef );
941	HIViewFindByID( root, kHIViewWindowContentID, &contentView );
942	HIViewGetFrame( contentView, &contentFrame );
943	HIViewGetBounds( root, &rootBounds );
944
945    // Set the content view's frame rect from the Carbon window's content region bounds.
946    contentFrame.origin.y = rootBounds.size.height - CGRectGetMaxY( contentFrame );
947
948    oldContentFrameRect = [(NSView *)_contentView frame];
949    if ( !NSEqualRects( *(NSRect*)&contentFrame, oldContentFrameRect ) ) {
950        [(NSView *)_contentView setFrame:*(NSRect*)&contentFrame];
951    }
952}
953
954- (OSStatus)_handleCarbonEvent:(EventRef)inEvent callRef:(EventHandlerCallRef)inCallRef {
955    OSStatus result = eventNotHandledErr;
956
957    switch ( GetEventClass( inEvent ) )
958    {
959		case kEventClassControl:
960			{
961				ControlRef		control;
962
963				check( GetEventKind( inEvent ) == kEventControlBoundsChanged );
964
965				GetEventParameter( inEvent, kEventParamDirectObject, typeControlRef, NULL,
966						sizeof( ControlRef ), NULL, &control );
967
968				if ( control == HIViewGetRoot( _windowRef ) )
969					[self _handleRootBoundsChanged];
970				else
971					[self _handleContentBoundsChanged];
972			}
973			break;
974
975    	case kEventClassWindow:
976    		switch ( GetEventKind( inEvent ) )
977    		{
978    			case kEventWindowShown:
979					[self _setVisible:YES];
980    				break;
981
982    			case kEventWindowHidden:
983					[self _setVisible:NO];
984    				break;
985
986    			case kEventWindowActivated:
987					[self makeKeyWindow];
988					break;
989
990    			case kEventWindowDeactivated:
991					[self resignKeyWindow];
992					break;
993
994				case kEventWindowBoundsChanged:
995					[self reconcileToCarbonWindowBounds];
996					break;
997			}
998    		break;
999   	}
1000
1001    return result;
1002}
1003
1004// Handle various events that Carbon is sending to our window.
1005static OSStatus NSCarbonWindowHandleEvent(EventHandlerCallRef inEventHandlerCallRef, EventRef inEventRef, void *inUserData) {
1006
1007    // default action is to send event to next handler.  We modify osStatus as necessary where we don't want this behavior
1008    OSStatus osStatus = eventNotHandledErr;
1009
1010    // We do different things for different event types.
1011    CarbonWindowAdapter *carbonWindow = (CarbonWindowAdapter *)inUserData;
1012
1013	osStatus = [carbonWindow _handleCarbonEvent: inEventRef callRef: inEventHandlerCallRef];
1014
1015    // Done.  If we want to propagate the event, we return eventNotHandledErr to send it to the next handler
1016    return osStatus;
1017
1018}
1019
1020// [3364117] We need to make sure this does not fall through to the AppKit implementation! bad things happen.
1021- (void)_reallyDoOrderWindow:(NSWindowOrderingMode)place relativeTo:(int)otherWin findKey:(BOOL)doKeyCalc forCounter:(BOOL)isACounter force:(BOOL)doForce isModal:(BOOL)isModal {
1022}
1023
1024- (NSRect) _growBoxRect
1025{
1026      WindowAttributes                attrs;
1027      NSRect                                  retRect = NSZeroRect;
1028
1029      GetWindowAttributes( _windowRef, &attrs );
1030
1031      if ( attrs & kWindowResizableAttribute )
1032      {
1033              HIRect          bounds, rect;
1034              HIViewRef   view;
1035
1036              HIViewGetBounds( HIViewGetRoot( _windowRef ), &bounds );
1037              HIViewFindByID( HIViewGetRoot( _windowRef ), kHIViewWindowGrowBoxID, &view );
1038              HIViewGetFrame( view, &rect );
1039
1040              rect.origin.y = bounds.size.height - CGRectGetMaxY( rect ) - 1;
1041              rect.origin.x++;
1042
1043              retRect = *(NSRect*)&rect;
1044      }
1045
1046      return retRect;
1047}
1048
1049@end // implementation CarbonWindowAdapter
1050
1051#endif
1052