• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
103static 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
869CleanUp:
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
913CleanUp:
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.
1003static 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*)&rect;
1042      }
1043
1044      return retRect;
1045}
1046
1047@end // implementation CarbonWindowAdapter
1048
1049#endif
1050