diff options
Diffstat (limited to 'Source/WebKit/mac/Carbon')
| -rw-r--r-- | Source/WebKit/mac/Carbon/CarbonUtils.h | 62 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/CarbonUtils.m | 132 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/CarbonWindowAdapter.h | 66 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/CarbonWindowAdapter.mm | 1051 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/CarbonWindowContentView.h | 33 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/CarbonWindowContentView.m | 37 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/CarbonWindowFrame.h | 43 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/CarbonWindowFrame.m | 288 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/HIViewAdapter.h | 38 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/HIViewAdapter.m | 249 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/HIWebView.h | 103 | ||||
| -rw-r--r-- | Source/WebKit/mac/Carbon/HIWebView.mm | 1615 |
12 files changed, 3717 insertions, 0 deletions
diff --git a/Source/WebKit/mac/Carbon/CarbonUtils.h b/Source/WebKit/mac/Carbon/CarbonUtils.h new file mode 100644 index 0000000..166de7b --- /dev/null +++ b/Source/WebKit/mac/Carbon/CarbonUtils.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2004, 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HIWEBCARBONUTILS__ +#define __HIWEBCARBONUTILS__ + +#ifndef __LP64__ + +// These functions are only available for 32-bit. + +#include <JavaScriptCore/WebKitAvailability.h> + +#ifdef __OBJC__ +#import <ApplicationServices/ApplicationServices.h> +@class NSImage; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern void +WebInitForCarbon(void) AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0; + +#ifdef __OBJC__ + +extern CGImageRef +WebConvertNSImageToCGImageRef(NSImage * inImage) AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0; + +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif // __HIWEBCARBONUTILS__ diff --git a/Source/WebKit/mac/Carbon/CarbonUtils.m b/Source/WebKit/mac/Carbon/CarbonUtils.m new file mode 100644 index 0000000..be749c9 --- /dev/null +++ b/Source/WebKit/mac/Carbon/CarbonUtils.m @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LP64__ + +#include "CarbonUtils.h" +#import <WebKitSystemInterface.h> + +extern CGImageRef _NSCreateImageRef( unsigned char *const bitmapData[5], int pixelsWide, int pixelsHigh, int bitsPerSample, int samplesPerPixel, int bitsPerPixel, int bytesPerRow, BOOL isPlanar, BOOL hasAlpha, NSString *colorSpaceName, CGColorSpaceRef customColorSpace, id sourceObj); + +static void PoolCleaner( EventLoopTimerRef inTimer, EventLoopIdleTimerMessage inState, void *inUserData ); + +static NSAutoreleasePool* sPool; +static unsigned numPools; +static EventLoopRef poolLoop; + +void HIWebViewRegisterClass( void ); + +void +WebInitForCarbon() +{ + static bool sAppKitLoaded; + + if ( !sAppKitLoaded ) + { + ProcessSerialNumber process; + + // Force us to register with process server, this ensure that the process + // "flavour" is correctly established. + GetCurrentProcess( &process ); + NSApplicationLoad(); + + sPool = [[NSAutoreleasePool allocWithZone:NULL] init]; + numPools = WKGetNSAutoreleasePoolCount(); + + poolLoop = GetCurrentEventLoop (); + + InstallEventLoopIdleTimer( GetMainEventLoop(), 1.0, 0, PoolCleaner, 0, NULL ); + + sAppKitLoaded = true; + + HIWebViewRegisterClass(); + } +} + +/* + The pool cleaner is required because Carbon applications do not have + an autorelease pool provided by their event loops. Importantly, + carbon applications that nest event loops, using any of the various + techniques available to Carbon apps, MUST create their our pools around + their nested event loops. +*/ +static void +PoolCleaner( EventLoopTimerRef inTimer, EventLoopIdleTimerMessage inState, void *inUserData ) +{ + if ( inState == kEventLoopIdleTimerStarted ) { + CFStringRef mode = CFRunLoopCopyCurrentMode( (CFRunLoopRef)GetCFRunLoopFromEventLoop( GetCurrentEventLoop() )); + EventLoopRef thisLoop = GetCurrentEventLoop (); + if ( CFEqual( mode, kCFRunLoopDefaultMode ) && thisLoop == poolLoop) { + unsigned currentNumPools = WKGetNSAutoreleasePoolCount()-1; + if (currentNumPools == numPools){ + [sPool drain]; + + sPool = [[NSAutoreleasePool allocWithZone:NULL] init]; + numPools = WKGetNSAutoreleasePoolCount(); + } + } + CFRelease( mode ); + } +} + +CGImageRef +WebConvertNSImageToCGImageRef( + NSImage* inImage ) +{ + NSArray* reps = [inImage representations]; + NSBitmapImageRep* rep = NULL; + CGImageRef image = NULL; + unsigned i; + + for ( i=0; i < [reps count]; i++ ) + { + if ( [[reps objectAtIndex:i] isKindOfClass:[NSBitmapImageRep class]] ) + { + rep = [reps objectAtIndex:i]; + break; + } + } + + if ( rep ) + { + //CGColorSpaceRef csync = (CGColorSpaceRef)[rep valueForProperty:NSImageColorSyncProfileData]; + + unsigned char* planes[5]; + + [rep getBitmapDataPlanes:planes]; + + image = _NSCreateImageRef( planes, [rep pixelsWide], [rep pixelsHigh], + [rep bitsPerSample], [rep samplesPerPixel], [rep bitsPerPixel], + [rep bytesPerRow], [rep isPlanar], [rep hasAlpha], [rep colorSpaceName], + NULL, rep); + } + + return image; +} + +#endif diff --git a/Source/WebKit/mac/Carbon/CarbonWindowAdapter.h b/Source/WebKit/mac/Carbon/CarbonWindowAdapter.h new file mode 100644 index 0000000..87c50ea --- /dev/null +++ b/Source/WebKit/mac/Carbon/CarbonWindowAdapter.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Foundation/Foundation.h> +#import <AppKit/AppKit.h> +#import <HIToolbox/CarbonEvents.h> +#import <HIToolbox/MacWindows.h> + +@interface CarbonWindowAdapter : NSWindow +{ +@private + + // The Carbon window that's being encapsulated, and whether or not this object owns (has responsibility for disposing) it. + WindowRef _windowRef; + BOOL _windowRefIsOwned; + BOOL _carbon; + + // The UPP for the event handler that we use to deal with various Carbon events, and the event handler itself. + EventHandlerUPP _handleEventUPP; + EventHandlerRef _eventHandler; + + // Yes if this object should let Carbon handle kEventWindowActivated and kEventWindowDeactivated events. No otherwise. + BOOL _passingCarbonWindowActivationEvents; +} + +// Initializers. +- (id)initWithCarbonWindowRef:(WindowRef)inWindowRef takingOwnership:(BOOL)inWindowRefIsOwned; +- (id)initWithCarbonWindowRef:(WindowRef)inWindowRef takingOwnership:(BOOL)inWindowRefIsOwned disableOrdering:(BOOL)inDisableOrdering carbon:(BOOL)inCarbon; + +// Accessors. +- (WindowRef)windowRef; + +// Update this window's frame and content rectangles to match the Carbon window's structure and content bounds rectangles. Return yes if the update was really necessary, no otherwise. +- (BOOL)reconcileToCarbonWindowBounds; + +// Handle an event just like an NSWindow would. +- (void)sendSuperEvent:(NSEvent *)inEvent; + +- (void)relinquishFocus; + +@end diff --git a/Source/WebKit/mac/Carbon/CarbonWindowAdapter.mm b/Source/WebKit/mac/Carbon/CarbonWindowAdapter.mm new file mode 100644 index 0000000..7348304 --- /dev/null +++ b/Source/WebKit/mac/Carbon/CarbonWindowAdapter.mm @@ -0,0 +1,1051 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// I don't think this class belongs in WebKit. Lets move it out. + +// Things that I've never bothered working out: +// For non-sheet windows, handle Carbon WindowMove events so as to do the same things as -[NSWindow _windowMoved]. +// Check to see how this stuff deals with various screen size change scenarious. +// M.P. Warning - 9/17/01 + +// 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. +// _auxiliaryStorage->auxWFlags.hasShadow will always be false if the Carbon window has a kWindowNoShadowAttribute, and vice versa. +// _auxiliaryStorage->_auxWFlags.minimized will always reflect the window's Carbon collapsed state. +// _borderView will always point to an NSCarbonWindowFrame. +// _contentView will always point to an NSCarbonWindowContentView; +// _frame will always reflect the window's Carbon kWindowStructureRgn bounds. +// _styleMask will always have _NSCarbonWindowMask set, and will have NSClosableWindowMask, NSMiniaturizableWindowMask, NSResizableWindowMask, and/or NSTitledWindowMask set as appropriate. +// _wflags.oneShot and _wflags.delayedOneShot will always be false. +// _wFlags.visible will always reflect the window's Carbon visibility. +// _windowNum will always be greater than zero, and valid. +// 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 + +// Things that have to be worked on if NSCarbonWindows are ever used for something other than dialogs and sheets: +// Clicking on an NSCarbonWindow while a Cocoa app-modal dialog is shown does not beep, as it should [old bug, maybe fixed now]. +// Handling of mouse clicks or key presses for any window control (close, miniaturize, zoom) might not be all there. +// Handling of miniaturization of Carbon windows via title bar double-click might not be all there. +// The background on NSCarbonWindowTester's sample window (not sample dialog or sample sheet) might be wrong. +// The controls on NSCarbonWindowTester's sample window look inactive when the window is inactive, but have first-click behavior. +// M.P. Warning - 12/14/00 + +// 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 + +#ifndef __LP64__ + +#import "CarbonWindowAdapter.h" + +#import "CarbonWindowFrame.h" +#import "CarbonWindowContentView.h" +#import "HIViewAdapter.h" + +#import <WebKitSystemInterface.h> + +#import <AppKit/AppKit.h> +//#import <CoreGraphics/CGSWindow.h> +#import <HIToolbox/CarbonEvents.h> +#import <HIToolbox/Controls.h> +#import <HIToolbox/HIView.h> +#import <assert.h> + +#import <WebCore/WebCoreObjCExtras.h> +#import <runtime/InitializeThreading.h> +#import <wtf/Threading.h> + +#import "WebKitLogging.h" +#import "WebNSObjectExtras.h" +#import "WebTypesInternal.h" + +@interface NSWindow(HIWebFrameView) +- (id)_initContent:(const NSRect *)contentRect styleMask:(unsigned int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag contentView:aView; +- (void)_oldPlaceWindow:(NSRect)frameRect; +- (void)_windowMovedToRect:(NSRect)actualFrame; +- (void)_setWindowNumber:(NSInteger)nativeWindow; +- (NSGraphicsContext *)_threadContext; +- (void)_setFrame:(NSRect)newWindowFrameRect; +- (void)_setVisible:(BOOL)flag; +@end + +@interface NSApplication(HIWebFrameView) +- (void)setIsActive:(BOOL)aFlag; +- (id)_setMouseActivationInProgress:(BOOL)flag; +- (BOOL)_handleKeyEquivalent:(NSEvent*)theEvent; +@end + +@interface NSInputContext +- (BOOL)processInputKeyBindings:(NSEvent *)event; +@end + +// Forward declarations. +static OSStatus NSCarbonWindowHandleEvent(EventHandlerCallRef inEventHandlerCallRef, EventRef inEventRef, void *inUserData); + +@implementation CarbonWindowAdapter + + +// Return an appropriate window frame class. ++ (Class)frameViewClassForStyleMask:(unsigned int)style { + + // There's only one appropriate window style, and only one appropriate window frame class. + assert(style & WKCarbonWindowMask()); + return [CarbonWindowFrame class]; + +} + + +// Overriding of the parent class' designated initializer, just for safety's sake. +- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)style backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag { + + // Do the standard Cocoa thing. + self = [super initWithContentRect:contentRect styleMask:style backing:bufferingType defer:flag]; + if (self==nil) return nil; + + // Simple. + _windowRef = NULL; + _windowRefIsOwned = NO; + _eventHandler = NULL; + + // Done. + return self; + +} + +// 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. +- (id)initWithCarbonWindowRef:(WindowRef)inWindowRef takingOwnership:(BOOL)inWindowRefIsOwned disableOrdering:(BOOL)inDisableOrdering carbon:(BOOL)inCarbon { + + NSBackingStoreType backingStoreType; + CarbonWindowContentView *carbonWindowContentView; + NSWindow *windowAsProperty; + OSStatus osStatus; + UInt32 windowFeatures; + WindowAttributes windowAttributes; + unsigned int styleMask; + void *nativeWindow; + WindowModality windowModality; + ControlRef contentView; + + // Simple. + // 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 + _windowRef = inWindowRef; + //_auxiliaryStorage->_windowRef = inWindowRef; + _windowRefIsOwned = inWindowRefIsOwned; + _carbon = inCarbon; + + // Find out the window's CoreGraphics window reference. + nativeWindow = WKGetNativeWindowFromWindowRef(inWindowRef); + + // Find out the window's Carbon window attributes. + GetWindowAttributes(inWindowRef, &windowAttributes); + + // Find out the window's Carbon window features. + GetWindowFeatures(inWindowRef, &windowFeatures); + + // Figure out the window's backing store type. + // At one time, this had code stolen from CreatePlatformWindow in HIToolbox/Windows/Platform/CGSPlatform.c + // But now the non-retained window class is a Carbon secret that's not even in + // WindowsPriv.h; maybe we'll have to revisit this if someone needs to use WebKit + // in a non-retained window. + backingStoreType = NSBackingStoreRetained; + + // Figure out the window's style mask. + styleMask = WKCarbonWindowMask(); + if (windowAttributes & kWindowCloseBoxAttribute) styleMask |= NSClosableWindowMask; + if (windowAttributes & kWindowResizableAttribute) styleMask |= NSResizableWindowMask; + if (windowFeatures & kWindowCanCollapse) styleMask |= NSMiniaturizableWindowMask; + if (windowFeatures & kWindowHasTitleBar) styleMask |= NSTitledWindowMask; + + osStatus = GetWindowModality(_windowRef, &windowModality, NULL); + if (osStatus != noErr) { + NSLog(@"Couldn't get window modality: error=%ld", osStatus); + return nil; + } + + // Create one of our special content views. + carbonWindowContentView = [[[CarbonWindowContentView alloc] init] autorelease]; + + // 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. + self = (CarbonWindowAdapter*)[super _initContent:NULL styleMask:styleMask backing:backingStoreType defer:YES contentView:carbonWindowContentView]; + if (!self) return nil; + assert(_contentView); + + // Record accurately whether or not this window has a shadow, in case someone asks. + // _auxiliaryStorage->_auxWFlags.hasShadow = (windowAttributes & kWindowNoShadowAttribute) ? NO : YES; + + // Record the window number. + [self _setWindowNumber:(NSInteger)nativeWindow]; + + // Set up from the frame rectangle. + // 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 + [self reconcileToCarbonWindowBounds]; + + // Install an event handler for the Carbon window events in which we're interested. + const EventTypeSpec kEvents[] = { + { kEventClassWindow, kEventWindowActivated }, + { kEventClassWindow, kEventWindowDeactivated }, + { kEventClassWindow, kEventWindowBoundsChanged }, + { kEventClassWindow, kEventWindowShown }, + { kEventClassWindow, kEventWindowHidden } + }; + + const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged }; + + osStatus = InstallEventHandler( GetWindowEventTarget(_windowRef), NSCarbonWindowHandleEvent, GetEventTypeCount( kEvents ), kEvents, (void*)self, &_eventHandler); + if (osStatus!=noErr) { + [self release]; + return nil; + } + + osStatus = InstallEventHandler( GetControlEventTarget( HIViewGetRoot( _windowRef ) ), NSCarbonWindowHandleEvent, 1, &kControlBoundsChangedEvent, (void*)self, &_eventHandler); + if (osStatus!=noErr) { + [self release]; + return nil; + } + + HIViewFindByID( HIViewGetRoot( _windowRef ), kHIViewWindowContentID, &contentView ); + osStatus = InstallEventHandler( GetControlEventTarget( contentView ), NSCarbonWindowHandleEvent, 1, &kControlBoundsChangedEvent, (void*)self, &_eventHandler); + if (osStatus!=noErr) { + [self release]; + return nil; + } + + // Put a pointer to this Cocoa NSWindow in a Carbon window property tag. + // Right now, this is just used by NSViewCarbonControl. M.P. Notice - 10/9/00 + windowAsProperty = self; + osStatus = SetWindowProperty(_windowRef, WKCarbonWindowPropertyCreator(), WKCarbonWindowPropertyTag(), sizeof(NSWindow *), &windowAsProperty); + if (osStatus!=noErr) { + [self release]; + return nil; + } + + // 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. + _passingCarbonWindowActivationEvents = NO; + + // Be sure to sync up visibility + [self _setVisible:(BOOL)IsWindowVisible( _windowRef )]; + + // Done. + return self; + +} + +- (void)setViewsNeedDisplay:(BOOL)wellDoThey { + // Make sure we can flush anything that needs it. + + // We need to sync the context here. I was hoping I didn't need to do this, + // but apparently when scrolling, the AppKit view system draws directly. + // When this occurs, I cannot intercept it to make it draw in my HIView + // context. What ends up happening is that it draws, but nothing ever + // flushes it. + + if ( [self windowNumber] != -1 ) + { + CGContextRef cgContext = (CGContextRef)[[self _threadContext] graphicsPort]; + CGContextSynchronize( cgContext ); + } +} + ++ (void)initialize +{ + JSC::initializeThreading(); + WTF::initializeMainThreadToProcessMainThread(); +#ifndef BUILDING_ON_TIGER + WebCoreObjCFinalizeOnMainThread(self); +#endif +} + +// 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. +- (id)initWithCarbonWindowRef:(WindowRef)inWindowRef takingOwnership:(BOOL)inWindowRefIsOwned { + // 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. + return [self initWithCarbonWindowRef:inWindowRef takingOwnership:inWindowRefIsOwned disableOrdering:YES carbon:NO]; +} + + +// Clean up. +- (void)dealloc { + if (WebCoreObjCScheduleDeallocateOnMainThread([CarbonWindowAdapter class], self)) + return; + + // Clean up, if necessary. + // 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 + if (_eventHandler) RemoveEventHandler(_eventHandler); + + // Do the standard Cocoa thing. + [super dealloc]; +} + +- (void)finalize { + ASSERT_MAIN_THREAD(); + if (_eventHandler) RemoveEventHandler(_eventHandler); + [super finalize]; +} + +- (WindowRef)windowRef { + + // Simple. + return _windowRef; + +} + +// should always be YES, but check in order to avoid initialization or deallocation surprises +- (BOOL)_hasWindowRef { + return (_windowRef != NULL); +} + +// an NSCarbonWindow does not manage the windowRef. The windowRef manages the NSCarbonWindow +- (BOOL)_managesWindowRef { + return NO; +} + +- (void)_removeWindowRef { + _windowRef = NULL; + + if (_eventHandler) RemoveEventHandler(_eventHandler); + + _eventHandler = NULL; +} + +- (WindowClass)_carbonWindowClass { + WindowClass windowClass = kDocumentWindowClass; + OSStatus osStatus; + + if ([self _hasWindowRef]) { + osStatus = GetWindowClass([self windowRef], &windowClass); + if (osStatus != noErr) { + NSLog(@"Couldn't get window class: error=%ld", osStatus); + } + } + return windowClass; +} + +// 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. +- (BOOL)reconcileToCarbonWindowBounds { + + OSStatus osStatus; + NSRect newContentFrameRect; + NSRect newWindowFrameRect; + NSRect oldContentFrameRect; + Rect windowContentBoundsRect; + Rect windowStructureBoundsRect; + + // Initialize for safe returning. + BOOL reconciliationWasNecessary = NO; + + // Precondition check. + assert(_contentView); + + // Get the Carbon window's bounds, which are expressed in global screen coordinates, with (0,0) at the top-left of the main screen. + osStatus = GetWindowBounds(_windowRef, kWindowStructureRgn, &windowStructureBoundsRect); + if (osStatus!=noErr) NSLog(@"A Carbon window's structure bounds couldn't be gotten."); + osStatus = GetWindowBounds(_windowRef, kWindowContentRgn, &windowContentBoundsRect); + if (osStatus!=noErr) NSLog(@"A Carbon window's content bounds couldn't be gotten."); + + // Set the frame rectangle of the border view and this window from the Carbon window's structure region bounds. + newWindowFrameRect.origin.x = windowStructureBoundsRect.left; + newWindowFrameRect.origin.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - windowStructureBoundsRect.bottom; + newWindowFrameRect.size.width = windowStructureBoundsRect.right - windowStructureBoundsRect.left; + newWindowFrameRect.size.height = windowStructureBoundsRect.bottom - windowStructureBoundsRect.top; + if (!NSEqualRects(newWindowFrameRect, _frame)) { + [self _setFrame:newWindowFrameRect]; + [_borderView setFrameSize:newWindowFrameRect.size]; + reconciliationWasNecessary = YES; + } + + // Set the content view's frame rect from the Carbon window's content region bounds. + newContentFrameRect.origin.x = windowContentBoundsRect.left - windowStructureBoundsRect.left; + newContentFrameRect.origin.y = windowStructureBoundsRect.bottom - windowContentBoundsRect.bottom; + newContentFrameRect.size.width = windowContentBoundsRect.right - windowContentBoundsRect.left; + newContentFrameRect.size.height = windowContentBoundsRect.bottom - windowContentBoundsRect.top; + oldContentFrameRect = [_contentView frame]; + if (!NSEqualRects(newContentFrameRect, oldContentFrameRect)) { + [_contentView setFrame:newContentFrameRect]; + reconciliationWasNecessary = YES; + } + + // Done. + return reconciliationWasNecessary; + +} + + +// Handle an event just like an NSWindow would. +- (void)sendSuperEvent:(NSEvent *)inEvent { + + // Filter out a few events that just result in complaints in the log. + // Ignore some unknown event that gets sent when NSTextViews in printing accessory views are focused. M.P. Notice - 12/7/00 + BOOL ignoreEvent = NO; + NSEventType eventType = [inEvent type]; + if (eventType==NSSystemDefined) { + short eventSubtype = [inEvent subtype]; + if (eventSubtype==7) { + ignoreEvent = YES; + } + } else if (eventType == NSKeyDown) { + // Handle command-space as [NSApp sendEvent:] does. + if ([NSInputContext processInputKeyBindings:inEvent]) { + return; + } + } + + // Simple. + if (!ignoreEvent) [super sendEvent:inEvent]; +} + +- (void)relinquishFocus +{ + NSResponder* firstResponder; + + // Carbon thinks that a control has the keyboard focus, + // or we wouldn't be being asked to relinquish focus. + + firstResponder = [self firstResponder]; + if ([firstResponder isKindOfClass:[NSView class]] ){ + // Make the window the first responder, so that no view is the key view. + [self makeFirstResponder:self]; + } +} + +- (BOOL)makeFirstResponder:(NSResponder *)aResponder +{ + // Let NSWindow focus the appropriate NSView. + if (![super makeFirstResponder:aResponder]) + return NO; + + // Now, if the view we're focusing is in a HIWebView, find the + // corresponding HIWebView for the NSView, and tell carbon to + // clear any focused control. + HIViewRef viewRef = 0; + NSResponder *firstResponder = [self firstResponder]; + if ([firstResponder isKindOfClass:[NSView class]]) { + NSView *view = (NSView *)firstResponder; + while (view) { + viewRef = [HIViewAdapter getHIViewForNSView:view]; + if (viewRef) + break; + view = [view superview]; + } + } + + HIViewRef focus; + GetKeyboardFocus (_windowRef, &focus); + if (focus != viewRef) { + SetKeyboardFocus (_windowRef, viewRef, kControlIndicatorPart ); + } + + return YES; +} + +// 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. + + +// 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. + + +// 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 +/* +// Do the right thing for a Carbon window. +- (void)_blockHeartBeat:(BOOL)flag { + + ControlRef defaultButton; + OSStatus osStatus; + + // Do the standard Cocoa thing. + [super _blockHeartBeat:flag]; + + // If there's a default Carbon button in this Carbon window, make it stop pulsing, the Carbon way. + // This is inspired by HIToolbox/Controls/Definitions/ButtonCDEF.c's ButtonEventHandler(). M.P. Notice - 12/5/00 + osStatus = GetWindowDefaultButton(_windowRef, &defaultButton); + if (osStatus==noErr && defaultButton) { + Boolean anotherButtonIsTracking = flag ? TRUE : FALSE; + osStatus = SetControlData(defaultButton, kControlNoPart, kControlPushButtonAnotherButtonTrackingTag, sizeof(Boolean), &anotherButtonIsTracking); + if (osStatus==noErr) DrawOneControl(defaultButton); + else NSLog(@"Some data couldn't be set in a Carbon control."); + } + +} +*/ + + +// Do the right thing for a Carbon window. +- (void)_cancelKey:(id)sender { + + // 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. + ControlRef cancelButton; + GetWindowCancelButton(_windowRef, &cancelButton); + if (cancelButton) { + if (IsControlActive(cancelButton)) { + HIViewSimulateClick(cancelButton, kControlButtonPart, 0, NULL); + } + } + +} + + + +// Do the right thing for a Carbon window. +- (void)_commonAwake { + + // 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. + NSLog(@"-[NSCarbonWindow _commonAwake] is not implemented."); + +} + + +// 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:]. + + +// Do the right thing for a Carbon window. +- (id)_destroyRealWindow:(BOOL)orderingOut { + + // Complain, because this should never be called. We don't support one-shot NSCarbonWindows. + NSLog(@"-[NSCarbonWindow _destroyRealWindow:] is not implemented."); + return self; + +} + + +// 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. + + +// 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. + + +// 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. + + +// 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. + + +// 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:]. + + +// 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:]. + + +// Do what NSWindow would do, but then sychronize the Carbon window structures. +- (void)_oldPlaceWindow:(NSRect)frameRect { + + OSStatus osStatus; + + // Do the standard Cocoa thing. + [super _oldPlaceWindow:frameRect]; + + // Tell Carbon to update its various regions. + // 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 + osStatus = WKSyncWindowWithCGAfterMove(_windowRef); + if (osStatus!=noErr) NSLog(@"A Carbon window's bounds couldn't be synchronized (%i).", (int)osStatus); + +} + + +// 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. + + +// 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. + + +// 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. + + +// 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. + + +// 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. + + +// 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:. + + +// 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. + + +// 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. + + +// Do what NSWindow would do, but for a Carbon window. +// This function is mostly cut-and-pasted from -[NSWindow _termWindowIfOwner]. M.P. Notice - 8/7/00 +- (void)_termWindowIfOwner { + [self _setWindowNumber:-1]; + _wFlags.isTerminating = YES; + if (_windowRef && _windowRefIsOwned) DisposeWindow(_windowRef); + // KW - need to clear window shadow state so it gets reset correctly when new window created +// if ([_borderView respondsToSelector:@selector(setShadowState:)]) { +// [_borderView setShadowState:kFrameShadowNone]; +// } + _wFlags.isTerminating = NO; +} + + +// 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. + + +// 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. + + +// Do what NSWindow would do, but then sychronize the Carbon window structures. +- (void)_windowMovedToRect:(NSRect)actualFrame { + + OSStatus osStatus; + + // Do the standard Cocoa thing. + [super _windowMovedToRect:actualFrame]; + + // Let Carbon know that the window has been moved, unless this method is being called "early." + if (_wFlags.visible) { + osStatus = WKSyncWindowWithCGAfterMove(_windowRef); + if (osStatus!=noErr) NSLog(@"A Carbon window's bounds couldn't be synchronized (%i).", (int)osStatus); + } + +} + +- (NSRect)constrainFrameRect:(NSRect)actualFrame toScreen:(NSScreen *)screen { + // let Carbon decide window size and position + return actualFrame; +} + +- (void)selectKeyViewFollowingView:(NSView *)aView { + HIViewRef view = NULL; + + view = [HIViewAdapter getHIViewForNSView:aView]; + + if ( view ) + { + HIViewRef contentView; + + GetRootControl( GetControlOwner( view ), &contentView ); + HIViewAdvanceFocus( contentView, 0 ); + } + else + { + [super selectKeyViewFollowingView:aView]; + } +} + +- (void)selectKeyViewPrecedingView:(NSView *)aView { + HIViewRef view = NULL; + + view = [HIViewAdapter getHIViewForNSView:aView]; + + if ( view ) + { + HIViewRef contentView; + + GetRootControl( GetControlOwner( view ), &contentView ); + HIViewAdvanceFocus( contentView, shiftKey ); + } + else + { + [super selectKeyViewPrecedingView:aView]; + } +} + +- (void)makeKeyWindow { + [NSApp _setMouseActivationInProgress:NO]; + [NSApp setIsActive:YES]; + [super makeKeyWindow]; + WKShowKeyAndMain(); +} + + +// Do the right thing for a Carbon window. +- (BOOL)canBecomeKeyWindow { + + return YES; +} + +// Do the right thing for a Carbon window. +- (BOOL)canBecomeMainWindow { + OSStatus osStatus; + WindowClass windowClass; + // By default, Carbon windows cannot become the main window. + // What about when the default isn't right? Requiring subclassing seems harsh. M.P. Warning - 9/17/01 + // KW - modify this to allow document windows to become main + // 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 + osStatus = GetWindowClass(_windowRef, &windowClass); + return (osStatus == noErr && windowClass == kDocumentWindowClass); + +} + + +// 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. + + +// 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. + + + +// 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. + + +// Do the right thing for a Carbon window. +- (void)encodeWithCoder:(NSCoder *)coder { + + // Actually, this will probably never be implemented. M.P. Notice - 8/2/00 + NSLog(@"-[NSCarbonWindow encodeWithCoder:] is not implemented."); + +} + + +// 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. + + +// Do the right thing for a Carbon window. +- (id)initWithCoder:(NSCoder *)coder { + + // Actually, this will probably never be implemented. M.P. Notice - 8/2/00 + NSLog(@"-[NSCarbonWindow initWithCoder:] is not implemented."); + [self release]; + return nil; + +} + + +// 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. + + +// 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. + + +// There's no override of resizeToScreenWithEvent:, despite the fact that NSWindow's operates on _windowNum. +// 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. + +/* +// Do the right thing for a Carbon Window. +- (void)sendEvent:(NSEvent *)theEvent { + + // Not all events are handled in the same manner. + NSEventType eventType = [theEvent type]; + if (eventType==NSAppKitDefined) { + + // Handle the event the Cocoa way. Carbon won't understand it anyway. + [super sendEvent:theEvent]; + + } +} +*/ + +// 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. + + +// 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(). + + +// Do what NSWindow would do, but for a Carbon window. +- (void)setContentView:(NSView *)aView { + + NSRect contentFrameRect; + OSStatus osStatus; + Rect windowContentBoundsRect; + + // Precondition check. + assert(_borderView); + assert([_borderView isKindOfClass:[CarbonWindowFrame class]]); + assert(_windowRef); + + // Parameter check. + assert(aView); + assert([aView isKindOfClass:[CarbonWindowContentView class]]); + + // Find out the window's Carbon window structure region (content) bounds. + osStatus = GetWindowBounds(_windowRef, kWindowContentRgn, &windowContentBoundsRect); + if (osStatus!=noErr) NSLog(@"A Carbon window's content bounds couldn't be gotten."); + contentFrameRect.origin = NSZeroPoint; + contentFrameRect.size.width = windowContentBoundsRect.right - windowContentBoundsRect.left; + contentFrameRect.size.height = windowContentBoundsRect.bottom - windowContentBoundsRect.top; + + // If the content view is still in some other view hierarchy, pry it free. + [_contentView removeFromSuperview]; + assert(![_contentView superview]); + + // Record the content view, and size it to this window's content frame. + _contentView = aView; + [_contentView setFrame:contentFrameRect]; + + // Make the content view a subview of the border view. + [_borderView addSubview:_contentView]; + + // Tell the content view it's new place in the responder chain. + [_contentView setNextResponder:self]; + +} + + +// 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. + + +- (BOOL)worksWhenModal { + WindowClass windowClass = [self _carbonWindowClass]; + return (windowClass == kFloatingWindowClass || windowClass == kUtilityWindowClass); +} + +- (void)_setModalWindowLevel { + return; +} + +- (id)_clearModalWindowLevel { + return nil; +} + +// 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. +// 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 + + +// 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. + + +- (UInt32)carbonHICommandIDFromActionSelector:(SEL)inActionSelector { + + // Initialize with the default return value. + UInt32 hiCommandID = 0; + + // Pretty simple, if tedious. + if (inActionSelector==@selector(clear:)) hiCommandID = kHICommandClear; + else if (inActionSelector==@selector(copy:)) hiCommandID = kHICommandCopy; + else if (inActionSelector==@selector(cut:)) hiCommandID = kHICommandCut; + else if (inActionSelector==@selector(paste:)) hiCommandID = kHICommandPaste; + else if (inActionSelector==@selector(redo:)) hiCommandID = kHICommandRedo; + else if (inActionSelector==@selector(selectAll:)) hiCommandID = kHICommandSelectAll; + else if (inActionSelector==@selector(undo:)) hiCommandID = kHICommandUndo; + + // Done. + return hiCommandID; + +} + + +- (void)sendCarbonProcessHICommandEvent:(UInt32)inHICommandID { + + EventTargetRef eventTargetRef; + HICommand hiCommand; + OSStatus osStatus; + + // Initialize for safe error handling. + EventRef eventRef = NULL; + + // 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. + hiCommand.attributes = 0; + hiCommand.commandID = inHICommandID; + hiCommand.menu.menuRef = 0; + hiCommand.menu.menuItemIndex = 0; + osStatus = CreateEvent(NULL, kEventClassCommand, kEventCommandProcess, GetCurrentEventTime(), kEventAttributeNone, &eventRef); + if (osStatus!=noErr) { + NSLog(@"CreateEvent() returned %i.", (int)osStatus); + goto CleanUp; + } + osStatus = SetEventParameter(eventRef, kEventParamDirectObject, typeHICommand, sizeof(HICommand), &hiCommand); + if (osStatus!=noErr) { + NSLog(@"SetEventParameter() returned %i.", (int)osStatus); + goto CleanUp; + } + + // Send a Carbon event to whatever has the Carbon user focus. + eventTargetRef = GetUserFocusEventTarget(); + osStatus = SendEventToEventTarget(eventRef, eventTargetRef); + if (osStatus!=noErr) { + NSLog(@"SendEventToEventTarget() returned %i.", (int)osStatus); + goto CleanUp; + } + +CleanUp: + + // Clean up. + if (eventRef) ReleaseEvent(eventRef); + +} + + +- (Boolean)sendCarbonUpdateHICommandStatusEvent:(UInt32)inHICommandID withMenuRef:(MenuRef)inMenuRef andMenuItemIndex:(UInt16)inMenuItemIndex { + + EventTargetRef eventTargetRef; + HICommand hiCommand; + OSStatus osStatus; + + // Initialize for safe error handling and flag returning. + Boolean eventWasHandled = FALSE; + EventRef eventRef = NULL; + + // 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. + hiCommand.attributes = kHICommandFromMenu; + hiCommand.commandID = inHICommandID; + hiCommand.menu.menuRef = inMenuRef; + hiCommand.menu.menuItemIndex = inMenuItemIndex; + osStatus = CreateEvent(NULL, kEventClassCommand, kEventCommandUpdateStatus, GetCurrentEventTime(), kEventAttributeNone, &eventRef); + if (osStatus!=noErr) { + NSLog(@"CreateEvent() returned %i.", (int)osStatus); + goto CleanUp; + } + osStatus = SetEventParameter(eventRef, kEventParamDirectObject, typeHICommand, sizeof(HICommand), &hiCommand); + if (osStatus!=noErr) { + NSLog(@"SetEventParameter() returned %i.", (int)osStatus); + goto CleanUp; + } + + // Send a Carbon event to whatever has the Carbon user focus. + eventTargetRef = GetUserFocusEventTarget(); + osStatus = SendEventToEventTarget(eventRef, eventTargetRef); + if (osStatus==noErr) { + eventWasHandled = TRUE; + } else if (osStatus!=eventNotHandledErr) { + NSLog(@"SendEventToEventTarget() returned %i.", (int)osStatus); + goto CleanUp; + } + +CleanUp: + + // Clean up. + if (eventRef) ReleaseEvent(eventRef); + + // Done. + return eventWasHandled; + +} + +- (void)_handleRootBoundsChanged +{ + HIViewRef root = HIViewGetRoot( _windowRef ); + HIRect frame; + + HIViewGetFrame( root, &frame ); + [_borderView setFrameSize:*(NSSize*)&frame.size]; +} + +- (void)_handleContentBoundsChanged +{ + HIViewRef root, contentView; + HIRect rootBounds, contentFrame; + NSRect oldContentFrameRect; + + root = HIViewGetRoot( _windowRef ); + HIViewFindByID( root, kHIViewWindowContentID, &contentView ); + HIViewGetFrame( contentView, &contentFrame ); + HIViewGetBounds( root, &rootBounds ); + + // Set the content view's frame rect from the Carbon window's content region bounds. + contentFrame.origin.y = rootBounds.size.height - CGRectGetMaxY( contentFrame ); + + oldContentFrameRect = [_contentView frame]; + if ( !NSEqualRects( *(NSRect*)&contentFrame, oldContentFrameRect ) ) { + [_contentView setFrame:*(NSRect*)&contentFrame]; + } +} + +- (OSStatus)_handleCarbonEvent:(EventRef)inEvent callRef:(EventHandlerCallRef)inCallRef { + OSStatus result = eventNotHandledErr; + + switch ( GetEventClass( inEvent ) ) + { + case kEventClassControl: + { + ControlRef control; + + check( GetEventKind( inEvent ) == kEventControlBoundsChanged ); + + GetEventParameter( inEvent, kEventParamDirectObject, typeControlRef, NULL, + sizeof( ControlRef ), NULL, &control ); + + if ( control == HIViewGetRoot( _windowRef ) ) + [self _handleRootBoundsChanged]; + else + [self _handleContentBoundsChanged]; + } + break; + + case kEventClassWindow: + switch ( GetEventKind( inEvent ) ) + { + case kEventWindowShown: + [self _setVisible:YES]; + break; + + case kEventWindowHidden: + [self _setVisible:NO]; + break; + + case kEventWindowActivated: + [self makeKeyWindow]; + break; + + case kEventWindowDeactivated: + [self resignKeyWindow]; + break; + + case kEventWindowBoundsChanged: + [self reconcileToCarbonWindowBounds]; + break; + } + break; + } + + return result; +} + +// Handle various events that Carbon is sending to our window. +static OSStatus NSCarbonWindowHandleEvent(EventHandlerCallRef inEventHandlerCallRef, EventRef inEventRef, void *inUserData) { + + // default action is to send event to next handler. We modify osStatus as necessary where we don't want this behavior + OSStatus osStatus = eventNotHandledErr; + + // We do different things for different event types. + CarbonWindowAdapter *carbonWindow = (CarbonWindowAdapter *)inUserData; + + osStatus = [carbonWindow _handleCarbonEvent: inEventRef callRef: inEventHandlerCallRef]; + + // Done. If we want to propagate the event, we return eventNotHandledErr to send it to the next handler + return osStatus; + +} + +// [3364117] We need to make sure this does not fall through to the AppKit implementation! bad things happen. +- (void)_reallyDoOrderWindow:(NSWindowOrderingMode)place relativeTo:(int)otherWin findKey:(BOOL)doKeyCalc forCounter:(BOOL)isACounter force:(BOOL)doForce isModal:(BOOL)isModal { +} + +- (NSRect) _growBoxRect +{ + WindowAttributes attrs; + NSRect retRect = NSZeroRect; + + GetWindowAttributes( _windowRef, &attrs ); + + if ( attrs & kWindowResizableAttribute ) + { + HIRect bounds, rect; + HIViewRef view; + + HIViewGetBounds( HIViewGetRoot( _windowRef ), &bounds ); + HIViewFindByID( HIViewGetRoot( _windowRef ), kHIViewWindowGrowBoxID, &view ); + HIViewGetFrame( view, &rect ); + + rect.origin.y = bounds.size.height - CGRectGetMaxY( rect ) - 1; + rect.origin.x++; + + retRect = *(NSRect*)▭ + } + + return retRect; +} + +@end // implementation CarbonWindowAdapter + +#endif diff --git a/Source/WebKit/mac/Carbon/CarbonWindowContentView.h b/Source/WebKit/mac/Carbon/CarbonWindowContentView.h new file mode 100644 index 0000000..5ba0478 --- /dev/null +++ b/Source/WebKit/mac/Carbon/CarbonWindowContentView.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <AppKit/NSView.h> + +@interface CarbonWindowContentView : NSView { } + +@end // interface CarbonWindowContentView diff --git a/Source/WebKit/mac/Carbon/CarbonWindowContentView.m b/Source/WebKit/mac/Carbon/CarbonWindowContentView.m new file mode 100644 index 0000000..d49a6ac --- /dev/null +++ b/Source/WebKit/mac/Carbon/CarbonWindowContentView.m @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LP64__ + +#import "CarbonWindowContentView.h" + +@implementation CarbonWindowContentView + +@end + +#endif diff --git a/Source/WebKit/mac/Carbon/CarbonWindowFrame.h b/Source/WebKit/mac/Carbon/CarbonWindowFrame.h new file mode 100644 index 0000000..4bca98a --- /dev/null +++ b/Source/WebKit/mac/Carbon/CarbonWindowFrame.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <AppKit/AppKit.h> + +@interface CarbonWindowFrame : NSView + +// Instance variables. +{ + + @private + + // Something we keep around just to return when it's asked for. + unsigned int _styleMask; + +} + +@end // interface NSCarbonWindowFrame diff --git a/Source/WebKit/mac/Carbon/CarbonWindowFrame.m b/Source/WebKit/mac/Carbon/CarbonWindowFrame.m new file mode 100644 index 0000000..83f093a --- /dev/null +++ b/Source/WebKit/mac/Carbon/CarbonWindowFrame.m @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LP64__ + +#import "CarbonWindowFrame.h" +#import "CarbonWindowAdapter.h" +#import "CarbonWindowContentView.h" +#import <Foundation/NSGeometry.h> +#import <Foundation/NSString.h> +#import <HIToolbox/MacWindows.h> + +#import "WebTypesInternal.h" + +@interface NSView(Secret) +- (void)_setWindow:(NSWindow *)window; +@end + +@class NSButton; +/* + +@interface NSThemeFrame(NSHijackedClassMethods) + ++ (float)_titlebarHeight:(unsigned int)style; + +@end +*/ + +@implementation CarbonWindowFrame + + +- (NSRect)titlebarRect +{ + NSRect titlebarRect; + NSRect boundsRect; + + boundsRect = [self bounds]; + + CarbonWindowAdapter *carbonWindow; + carbonWindow = (CarbonWindowAdapter *)[self window]; + WindowRef windowRef = [carbonWindow windowRef]; + Rect globalBounds; + GetWindowBounds (windowRef, kWindowTitleBarRgn, &globalBounds); + + titlebarRect.origin.x = boundsRect.origin.x; + titlebarRect.size.width = boundsRect.size.width; + titlebarRect.size.height = globalBounds.bottom - globalBounds.top; + titlebarRect.origin.y = NSMaxY(boundsRect) - titlebarRect.size.height; + + return titlebarRect; +} + +// Given a content rectangle and style mask, return a corresponding frame rectangle. ++ (NSRect)frameRectForContentRect:(NSRect)contentRect styleMask:(NSUInteger)style { + + // We don't bother figuring out a good value, because content rects weren't so meaningful for NSCarbonWindows in the past, but this might not be a good assumption anymore. M.P. Warning - 12/5/00 + return contentRect; + +} + ++ (NSRect)contentRectForFrameRect:(NSRect)frameRect styleMask:(NSUInteger)style { + + // We don't bother figuring out a good value, because content rects weren't so meaningful for NSCarbonWindows in the past, but this might not be a good assumption anymore. KW - copied from +frameRectForContentRect:styleMask + return frameRect; + +} + ++ (NSSize)minFrameSizeForMinContentSize:(NSSize)cSize styleMask:(NSUInteger)style { + // See comments above. We don't make any assumptions about the relationship between content rects and frame rects + return cSize; +} + +- (NSRect)frameRectForContentRect:(NSRect)cRect styleMask:(NSUInteger)style { + return [[self class] frameRectForContentRect: cRect styleMask:style]; +} +- (NSRect)contentRectForFrameRect:(NSRect)fRect styleMask:(NSUInteger)style { + return [[self class] contentRectForFrameRect: fRect styleMask:style]; +} +- (NSSize)minFrameSizeForMinContentSize:(NSSize)cSize styleMask:(NSUInteger)style { + return [[self class] minFrameSizeForMinContentSize:cSize styleMask: style]; +} + +// Initialize. +- (id)initWithFrame:(NSRect)inFrameRect styleMask:(unsigned int)inStyleMask owner:(NSWindow *)inOwningWindow { + + // Parameter check. + if (![inOwningWindow isKindOfClass:[CarbonWindowAdapter class]]) NSLog(@"CarbonWindowFrames can only be owned by CarbonWindowAdapters."); + + // Do the standard Cocoa thing. + self = [super initWithFrame:inFrameRect]; + if (!self) return nil; + + // Record what we'll need later. + _styleMask = inStyleMask; + + // Do what NSFrameView's method of the same name does. + [self _setWindow:inOwningWindow]; + [self setNextResponder:inOwningWindow]; + + // Done. + return self; + +} + + +// Deallocate. +- (void)dealloc { + + // Simple. + [super dealloc]; + +} + + +// Sink a method invocation. +- (void)_setFrameNeedsDisplay:(BOOL)needsDisplay { + +} + + +// Sink a method invocation. +- (void)_setSheet:(BOOL)sheetFlag { + +} + + +// Sink a method invocation. +- (void)_updateButtonState { + +} + +#if 0 +// Sink a method invocation. +- (void)_windowChangedKeyState { +} +#endif + +// Toolbar methods that NSWindow expects to be there. +- (BOOL)_canHaveToolbar { return NO; } +- (BOOL)_toolbarIsInTransition { return NO; } +- (BOOL)_toolbarIsShown { return NO; } +- (BOOL)_toolbarIsHidden { return NO; } +- (void)_showToolbarWithAnimation:(BOOL)animate {} +- (void)_hideToolbarWithAnimation:(BOOL)animate {} +- (float)_distanceFromToolbarBaseToTitlebar { return 0; } + + +// Refuse to admit there's a close button on the window. +- (NSButton *)closeButton { + + // Simple. + return nil; +} + + +// Return what's asked for. +- (unsigned int)styleMask { + + // Simple. + return _styleMask; + +} + + +// Return what's asked for. +- (NSRect)dragRectForFrameRect:(NSRect)frameRect { + + // Do what NSThemeFrame would do. + // If we just return NSZeroRect here, _NXMakeWindowVisible() gets all befuddled in the sheet-showing case, a window-moving loop is entered, and the sheet gets moved right off of the screen. M.P. Warning - 3/23/01 + NSRect dragRect; + dragRect.size.height = 27;//[NSThemeFrame _titlebarHeight:[self styleMask]]; + dragRect.origin.y = NSMaxY(frameRect) - dragRect.size.height; + dragRect.size.width = frameRect.size.width; + dragRect.origin.x = frameRect.origin.x; + return dragRect; + +} + + +// Return what's asked for. +- (BOOL)isOpaque { + + // Return a value that will make -[NSWindow displayIfNeeded] on our Carbon window actually work. + return YES; + +} + + +// Refuse to admit there's a minimize button on the window. +- (NSButton *)minimizeButton { + + // Simple. + return nil; + +} + + +// Do the right thing for a Carbon window. +- (void)setTitle:(NSString *)title { + + CarbonWindowAdapter *carbonWindow; + OSStatus osStatus; + WindowRef windowRef; + + // Set the Carbon window's title. + carbonWindow = (CarbonWindowAdapter *)[self window]; + windowRef = [carbonWindow windowRef]; + osStatus = SetWindowTitleWithCFString(windowRef, (CFStringRef)title); + if (osStatus!=noErr) NSLog(@"A Carbon window's title couldn't be set."); + +} + + +// Return what's asked for. +- (NSString *)title { + + CFStringRef windowTitle; + CarbonWindowAdapter *carbonWindow; + NSString *windowTitleAsNSString; + OSStatus osStatus; + WindowRef windowRef; + + // Return the Carbon window's title. + carbonWindow = (CarbonWindowAdapter *)[self window]; + windowRef = [carbonWindow windowRef]; + osStatus = CopyWindowTitleAsCFString(windowRef, &windowTitle); + if (osStatus==noErr) { + windowTitleAsNSString = (NSString *)windowTitle; + } else { + NSLog(@"A Carbon window's title couldn't be gotten."); + windowTitleAsNSString = @""; + } + return [windowTitleAsNSString autorelease]; + +} + + +// Return what's asked for. +- (float)_sheetHeightAdjustment { + + // Do what NSThemeFrame would do. + return 22;//[NSThemeFrame _titlebarHeight:([self styleMask] & ~NSDocModalWindowMask)]; + +} + +// Return what's asked for. +- (float)_maxTitlebarTitleRect { + + // Do what NSThemeFrame would do. + return 22;//[NSThemeFrame _titlebarHeight:([self styleMask] & ~NSDocModalWindowMask)]; + +} + +- (void)_clearDragMargins { +} + +- (void)_resetDragMargins { +} + + +@end // implementation NSCarbonWindowFrame + +#endif diff --git a/Source/WebKit/mac/Carbon/HIViewAdapter.h b/Source/WebKit/mac/Carbon/HIViewAdapter.h new file mode 100644 index 0000000..875566d --- /dev/null +++ b/Source/WebKit/mac/Carbon/HIViewAdapter.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <WebKit/WebKit.h> +#include <HIToolbox/HIView.h> + +@interface HIViewAdapter : NSObject + ++ (void)bindHIViewToNSView:(HIViewRef)hiView nsView:(NSView*)nsView; ++ (void)unbindNSView:(NSView*)nsView; ++ (HIViewRef)getHIViewForNSView:(NSView*)inView; + +@end diff --git a/Source/WebKit/mac/Carbon/HIViewAdapter.m b/Source/WebKit/mac/Carbon/HIViewAdapter.m new file mode 100644 index 0000000..565be4f --- /dev/null +++ b/Source/WebKit/mac/Carbon/HIViewAdapter.m @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LP64__ + +#import "HIViewAdapter.h" + +#import "QuickDrawCompatibility.h" +#import "WebNSObjectExtras.h" +#import <wtf/Assertions.h> + +static void SetViewNeedsDisplay(HIViewRef inView, RgnHandle inRegion, Boolean inNeedsDisplay); + +#define WATCH_INVALIDATION 0 + +@interface NSView(ShhhhDontTell) +- (NSRect)_dirtyRect; +@end + +@implementation HIViewAdapter + +static CFMutableDictionaryRef sViewMap; + +static IMP oldNSViewSetNeedsDisplayIMP; +static IMP oldNSViewSetNeedsDisplayInRectIMP; +static IMP oldNSViewNextValidKeyViewIMP; + +static void _webkit_NSView_setNeedsDisplay(id self, SEL _cmd, BOOL flag); +static void _webkit_NSView_setNeedsDisplayInRect(id self, SEL _cmd, NSRect invalidRect); +static NSView *_webkit_NSView_nextValidKeyView(id self, SEL _cmd); + ++ (void)bindHIViewToNSView:(HIViewRef)hiView nsView:(NSView*)nsView +{ + if (sViewMap == NULL) { + sViewMap = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + + // Override -[NSView setNeedsDisplay:] + Method setNeedsDisplayMethod = class_getInstanceMethod(objc_getClass("NSView"), @selector(setNeedsDisplay:)); + ASSERT(setNeedsDisplayMethod); + ASSERT(!oldNSViewSetNeedsDisplayIMP); + oldNSViewSetNeedsDisplayIMP = method_setImplementation(setNeedsDisplayMethod, (IMP)_webkit_NSView_setNeedsDisplay); + + // Override -[NSView setNeedsDisplayInRect:] + Method setNeedsDisplayInRectMethod = class_getInstanceMethod(objc_getClass("NSView"), @selector(setNeedsDisplayInRect:)); + ASSERT(setNeedsDisplayInRectMethod); + ASSERT(!oldNSViewSetNeedsDisplayInRectIMP); + oldNSViewSetNeedsDisplayInRectIMP = method_setImplementation(setNeedsDisplayInRectMethod, (IMP)_webkit_NSView_setNeedsDisplayInRect); + + // Override -[NSView nextValidKeyView] + Method nextValidKeyViewMethod = class_getInstanceMethod(objc_getClass("NSView"), @selector(nextValidKeyView)); + ASSERT(nextValidKeyViewMethod); + ASSERT(!oldNSViewNextValidKeyViewIMP); + oldNSViewNextValidKeyViewIMP = method_setImplementation(nextValidKeyViewMethod, (IMP)_webkit_NSView_nextValidKeyView); + } + + CFDictionaryAddValue(sViewMap, nsView, hiView); +} + ++ (HIViewRef)getHIViewForNSView:(NSView*)inView +{ + return sViewMap ? (HIViewRef)CFDictionaryGetValue(sViewMap, inView) : NULL; +} + ++ (void)unbindNSView:(NSView*)inView +{ + CFDictionaryRemoveValue(sViewMap, inView); +} + +static void _webkit_NSView_setNeedsDisplay(id self, SEL _cmd, BOOL flag) +{ + oldNSViewSetNeedsDisplayIMP(self, _cmd, flag); + + if (!flag) { + HIViewRef hiView = NULL; + NSRect targetBounds = [self visibleRect]; + NSRect validRect = targetBounds; + NSView *view = self; + + while (view) { + targetBounds = [view visibleRect]; + if ((hiView = [HIViewAdapter getHIViewForNSView:view]) != NULL) + break; + validRect = [view convertRect:validRect toView:[view superview]]; + view = [view superview]; + } + + if (hiView) { + // Flip rect here and convert to region + HIRect rect; + rect.origin.x = validRect.origin.x; + rect.origin.y = targetBounds.size.height - NSMaxY(validRect); + rect.size.height = validRect.size.height; + rect.size.width = validRect.size.width; + + // For now, call the region-based API. + RgnHandle rgn = NewRgn(); + if (rgn) { + Rect qdRect; + qdRect.top = (SInt16)rect.origin.y; + qdRect.left = (SInt16)rect.origin.x; + qdRect.bottom = CGRectGetMaxY(rect); + qdRect.right = CGRectGetMaxX(rect); + + RectRgn(rgn, &qdRect); + SetViewNeedsDisplay(hiView, rgn, false); + DisposeRgn(rgn); + } + } + } +} + +static void _webkit_NSView_setNeedsDisplayInRect(id self, SEL _cmd, NSRect invalidRect) +{ + invalidRect = NSUnionRect(invalidRect, [self _dirtyRect]); + oldNSViewSetNeedsDisplayInRectIMP(self, _cmd, invalidRect); + + if (!NSIsEmptyRect(invalidRect)) { + HIViewRef hiView = NULL; + NSRect targetBounds = [self bounds]; + NSView *view = self; + + while (view) { + targetBounds = [view bounds]; + if ((hiView = [HIViewAdapter getHIViewForNSView:view]) != NULL) + break; + invalidRect = [view convertRect:invalidRect toView:[view superview]]; + view = [view superview]; + } + + if (hiView) { + if (NSWidth(invalidRect) > 0 && NSHeight(invalidRect)) { + // Flip rect here and convert to region + HIRect rect; + rect.origin.x = invalidRect.origin.x; + rect.origin.y = targetBounds.size.height - NSMaxY(invalidRect); + rect.size.height = invalidRect.size.height; + rect.size.width = invalidRect.size.width; + + // For now, call the region-based API. + RgnHandle rgn = NewRgn(); + if (rgn) { + Rect qdRect; + qdRect.top = (SInt16)rect.origin.y; + qdRect.left = (SInt16)rect.origin.x; + qdRect.bottom = CGRectGetMaxY(rect); + qdRect.right = CGRectGetMaxX(rect); + + RectRgn(rgn, &qdRect); + SetViewNeedsDisplay(hiView, rgn, true); + DisposeRgn(rgn); + } + } + } else + [[self window] setViewsNeedDisplay:YES]; + } +} + +static NSView *_webkit_NSView_nextValidKeyView(id self, SEL _cmd) +{ + if ([HIViewAdapter getHIViewForNSView:self]) + return [[self window] contentView]; + else + return oldNSViewNextValidKeyViewIMP(self, _cmd); +} + +@end + +static void SetViewNeedsDisplay(HIViewRef inHIView, RgnHandle inRegion, Boolean inNeedsDisplay) +{ + WindowAttributes attrs; + + GetWindowAttributes(GetControlOwner(inHIView), &attrs); + + if (attrs & kWindowCompositingAttribute) { +#if WATCH_INVALIDATION + Rect bounds; + GetRegionBounds(inRegion, &bounds); + printf("%s: rect on input %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", + bounds.top, bounds.left, bounds.bottom, bounds.right); +#endif + HIViewSetNeedsDisplayInRegion(inHIView, inRegion, inNeedsDisplay); + } else { + Rect bounds, cntlBounds; + GrafPtr port, savePort; + Rect portBounds; + +#if WATCH_INVALIDATION + printf("%s: rect on input %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", + bounds.top, bounds.left, bounds.bottom, bounds.right); +#endif + GetControlBounds(inHIView, &cntlBounds); + +#if WATCH_INVALIDATION + printf("%s: control bounds are %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", + cntlBounds.top, cntlBounds.left, cntlBounds.bottom, cntlBounds.right); +#endif + + port = GetWindowPort(GetControlOwner(inHIView)); + + GetPort(&savePort); + SetPort(port); + GetPortBounds(port, &portBounds); + SetOrigin(0, 0); + + OffsetRgn(inRegion, cntlBounds.left, cntlBounds.top); + + GetRegionBounds(inRegion, &bounds); + +#if WATCH_INVALIDATION + printf("%s: rect in port coords %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", + bounds.top, bounds.left, bounds.bottom, bounds.right); +#endif + + if (inNeedsDisplay) + InvalWindowRgn(GetControlOwner(inHIView), inRegion); + else + ValidWindowRgn(GetControlOwner(inHIView), inRegion); + + SetOrigin(portBounds.left, portBounds.top); + SetPort(savePort); + } +} + +#endif diff --git a/Source/WebKit/mac/Carbon/HIWebView.h b/Source/WebKit/mac/Carbon/HIWebView.h new file mode 100644 index 0000000..bc67453 --- /dev/null +++ b/Source/WebKit/mac/Carbon/HIWebView.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2004, 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HIWebView__ +#define __HIWebView__ + +#ifndef __LP64__ + +#include <Carbon/Carbon.h> + +#include <JavaScriptCore/WebKitAvailability.h> + +#if PRAGMA_ONCE +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __OBJC__ +@class WebView; +#endif + +/* + * HIWebViewCreate() + * + * Summary: + * Creates a new web view. + * + * Parameters: + * + * outControl: + * The new web view. + * + * Result: + * An operating system status code. + * + * Availability: + * Mac OS X: in version 10.2.7 and later [32-bit only] + * CarbonLib: not available + * Non-Carbon CFM: not available + */ +extern OSStatus +HIWebViewCreate(HIViewRef * outControl) AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0; + +#ifdef __OBJC__ + +/* + * HIWebViewGetWebView() + * + * Summary: + * Returns the WebKit WebView for a given HIWebView. + * + * Parameters: + * + * inView: + * The view to inspect. + * + * Result: + * A pointer to a web view object, or NULL. + * + * Availability: + * Mac OS X: in version 10.2.7 and later [32-bit only] + * CarbonLib: not available + * Non-Carbon CFM: not available + */ +extern WebView * +HIWebViewGetWebView(HIViewRef inView) AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0; + +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif /* __HIWebView__ */ diff --git a/Source/WebKit/mac/Carbon/HIWebView.mm b/Source/WebKit/mac/Carbon/HIWebView.mm new file mode 100644 index 0000000..a3cdc66 --- /dev/null +++ b/Source/WebKit/mac/Carbon/HIWebView.mm @@ -0,0 +1,1615 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LP64__ + +#import "HIWebView.h" + +#import "CarbonWindowAdapter.h" +#import "HIViewAdapter.h" +#import "QuickDrawCompatibility.h" +#import "WebHTMLViewInternal.h" +#import "WebKit.h" +#import <WebKitSystemInterface.h> +#import <objc/objc-runtime.h> + +@interface NSWindow (AppKitSecretsHIWebViewKnows) +- (void)_removeWindowRef; +@end + +@interface NSView (AppKitSecretsHIWebViewKnows) +- (void)_clearDirtyRectsForTree; +@end + +extern "C" void HIWebViewRegisterClass(); + +@interface MenuItemProxy : NSObject <NSValidatedUserInterfaceItem> +{ + int _tag; + SEL _action; +} + +- (id)initWithAction:(SEL)action; +- (SEL)action; +- (int)tag; + +@end + +@implementation MenuItemProxy + +- (id)initWithAction:(SEL)action +{ + [super init]; + if (self == nil) return nil; + + _action = action; + + return self; +} + +- (SEL)action +{ + return _action; +} + +- (int)tag +{ + return 0; +} + +@end + +struct HIWebView +{ + HIViewRef fViewRef; + + WebView* fWebView; + NSView* fFirstResponder; + CarbonWindowAdapter * fKitWindow; + bool fIsComposited; + CFRunLoopObserverRef fUpdateObserver; +}; +typedef struct HIWebView HIWebView; + +static const OSType NSAppKitPropertyCreator = 'akit'; +/* +These constants are not used. Commented out to make the compiler happy. +static const OSType NSViewCarbonControlViewPropertyTag = 'view'; +static const OSType NSViewCarbonControlAutodisplayPropertyTag = 'autd'; +static const OSType NSViewCarbonControlFirstResponderViewPropertyTag = 'frvw'; +*/ +static const OSType NSCarbonWindowPropertyTag = 'win '; + +#ifdef BUILDING_ON_TIGER +const int typeByteCount = typeSInt32; +#endif + +static SEL _NSSelectorForHICommand( const HICommand* hiCommand ); + +static const EventTypeSpec kEvents[] = { + { kEventClassHIObject, kEventHIObjectConstruct }, + { kEventClassHIObject, kEventHIObjectDestruct }, + + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassMouse, kEventMouseWheelMoved }, + + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + + { kEventClassCommand, kEventCommandProcess }, + { kEventClassCommand, kEventCommandUpdateStatus }, + + { kEventClassControl, kEventControlInitialize }, + { kEventClassControl, kEventControlDraw }, + { kEventClassControl, kEventControlHitTest }, + { kEventClassControl, kEventControlGetPartRegion }, + { kEventClassControl, kEventControlGetData }, + { kEventClassControl, kEventControlBoundsChanged }, + { kEventClassControl, kEventControlActivate }, + { kEventClassControl, kEventControlDeactivate }, + { kEventClassControl, kEventControlOwningWindowChanged }, + { kEventClassControl, kEventControlClick }, + { kEventClassControl, kEventControlContextualMenuClick }, + { kEventClassControl, kEventControlSetFocusPart } +}; + +#define kHIViewBaseClassID CFSTR( "com.apple.hiview" ) +#define kHIWebViewClassID CFSTR( "com.apple.HIWebView" ) + +static HIWebView* HIWebViewConstructor( HIViewRef inView ); +static void HIWebViewDestructor( HIWebView* view ); + +static OSStatus HIWebViewEventHandler( + EventHandlerCallRef inCallRef, + EventRef inEvent, + void * inUserData ); + +static UInt32 GetBehaviors(); +static ControlKind GetKind(); +static void Draw( HIWebView* inView, RgnHandle limitRgn, CGContextRef inContext ); +static ControlPartCode HitTest( HIWebView* view, const HIPoint* where ); +static OSStatus GetRegion( HIWebView* view, ControlPartCode inPart, RgnHandle outRgn ); +static void BoundsChanged( + HIWebView* inView, + UInt32 inOptions, + const HIRect* inOriginalBounds, + const HIRect* inCurrentBounds ); +static void OwningWindowChanged( + HIWebView* view, + WindowRef oldWindow, + WindowRef newWindow ); +static void ActiveStateChanged( HIWebView* view ); + +static OSStatus Click( HIWebView* inView, EventRef inEvent ); +static OSStatus ContextMenuClick( HIWebView* inView, EventRef inEvent ); +static OSStatus MouseUp( HIWebView* inView, EventRef inEvent ); +static OSStatus MouseMoved( HIWebView* inView, EventRef inEvent ); +static OSStatus MouseDragged( HIWebView* inView, EventRef inEvent ); +static OSStatus MouseWheelMoved( HIWebView* inView, EventRef inEvent ); + +static OSStatus ProcessCommand( HIWebView* inView, const HICommand* inCommand ); +static OSStatus UpdateCommandStatus( HIWebView* inView, const HICommand* inCommand ); + +static OSStatus SetFocusPart( + HIWebView* view, + ControlPartCode desiredFocus, + RgnHandle invalidRgn, + Boolean focusEverything, + ControlPartCode* actualFocus ); +static NSView* AdvanceFocus( HIWebView* view, bool forward ); +static void RelinquishFocus( HIWebView* view, bool inAutodisplay ); + +static WindowRef GetWindowRef( HIWebView* inView ); +static void SyncFrame( HIWebView* inView ); + +static OSStatus WindowHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ); + +static void StartUpdateObserver( HIWebView* view ); +static void StopUpdateObserver( HIWebView* view ); + +static inline void HIRectToQDRect( const HIRect* inRect, Rect* outRect ) +{ + outRect->top = (SInt16)CGRectGetMinY( *inRect ); + outRect->left = (SInt16)CGRectGetMinX( *inRect ); + outRect->bottom = (SInt16)CGRectGetMaxY( *inRect ); + outRect->right = (SInt16)CGRectGetMaxX( *inRect ); +} + +//---------------------------------------------------------------------------------- +// HIWebViewCreate +//---------------------------------------------------------------------------------- +// +OSStatus +HIWebViewCreate(HIViewRef* outControl) +{ + HIWebViewRegisterClass(); + return HIObjectCreate(kHIWebViewClassID, NULL, (HIObjectRef*)outControl); +} + +//---------------------------------------------------------------------------------- +// HIWebViewGetWebView +//---------------------------------------------------------------------------------- +// +WebView* +HIWebViewGetWebView( HIViewRef inView ) +{ + HIWebView* view = (HIWebView*)HIObjectDynamicCast( (HIObjectRef)inView, kHIWebViewClassID ); + WebView* result = NULL; + + if ( view ) + result = view->fWebView; + + return result; +} + +//---------------------------------------------------------------------------------- +// HIWebViewConstructor +//---------------------------------------------------------------------------------- +// + +static HIWebView* +HIWebViewConstructor( HIViewRef inView ) +{ + HIWebView* view = (HIWebView*)malloc( sizeof( HIWebView ) ); + + if ( view ) + { + NSRect frame = { { 0, 0 }, { 400, 400 } }; + + view->fViewRef = inView; + + WebView *webView = [[WebView alloc] initWithFrame: frame]; + CFRetain(webView); + [webView release]; + view->fWebView = webView; + [HIViewAdapter bindHIViewToNSView:inView nsView:view->fWebView]; + + view->fFirstResponder = NULL; + view->fKitWindow = NULL; + view->fIsComposited = false; + view->fUpdateObserver = NULL; + } + + return view; +} + +//---------------------------------------------------------------------------------- +// HIWebViewDestructor +//---------------------------------------------------------------------------------- +// +static void +HIWebViewDestructor( HIWebView* inView ) +{ + [HIViewAdapter unbindNSView:inView->fWebView]; + CFRelease(inView->fWebView); + + free(inView); +} + +//---------------------------------------------------------------------------------- +// HIWebViewRegisterClass +//---------------------------------------------------------------------------------- +// +void +HIWebViewRegisterClass() +{ + static bool sRegistered; + + if ( !sRegistered ) + { + HIObjectRegisterSubclass( kHIWebViewClassID, kHIViewBaseClassID, 0, HIWebViewEventHandler, + GetEventTypeCount( kEvents ), kEvents, 0, NULL ); + sRegistered = true; + } +} + +//---------------------------------------------------------------------------------- +// GetBehaviors +//---------------------------------------------------------------------------------- +// +static UInt32 +GetBehaviors() +{ + return kControlSupportsDataAccess | kControlSupportsGetRegion | kControlGetsFocusOnClick; +} + +//---------------------------------------------------------------------------------- +// Draw +//---------------------------------------------------------------------------------- +// +static void +Draw( HIWebView* inView, RgnHandle limitRgn, CGContextRef inContext ) +{ + HIRect bounds; + Rect drawRect; + HIRect hiRect; + bool createdContext = false; + + if (!inView->fIsComposited) + { + GrafPtr port; + Rect portRect; + + GetPort( &port ); + GetPortBounds( port, &portRect ); + CreateCGContextForPort( port, &inContext ); + SyncCGContextOriginWithPort( inContext, port ); + CGContextTranslateCTM( inContext, 0, (portRect.bottom - portRect.top) ); + CGContextScaleCTM( inContext, 1, -1 ); + createdContext = true; + } + + HIViewGetBounds( inView->fViewRef, &bounds ); + + CGContextRef savedContext = WKNSWindowOverrideCGContext(inView->fKitWindow, inContext); + [NSGraphicsContext setCurrentContext:[inView->fKitWindow graphicsContext]]; + + GetRegionBounds( limitRgn, &drawRect ); + + if ( !inView->fIsComposited ) + OffsetRect( &drawRect, (SInt16)-bounds.origin.x, (SInt16)-bounds.origin.y ); + + hiRect.origin.x = drawRect.left; + hiRect.origin.y = bounds.size.height - drawRect.bottom; // flip y + hiRect.size.width = drawRect.right - drawRect.left; + hiRect.size.height = drawRect.bottom - drawRect.top; + +// printf( "Drawing: drawRect is (%g %g) (%g %g)\n", hiRect.origin.x, hiRect.origin.y, +// hiRect.size.width, hiRect.size.height ); + + // FIXME: We need to do layout before Carbon has decided what region needs drawn. + // In Cocoa we make sure to do layout and invalidate any new regions before draw, so everything + // can be drawn in one pass. Doing a layout here will cause new regions to be invalidated, but they + // will not all be drawn in this pass since we already have a fixed rect we are going to display. + + NSView <WebDocumentView> *documentView = [[[inView->fWebView mainFrame] frameView] documentView]; + if ([documentView isKindOfClass:[WebHTMLView class]]) + [(WebHTMLView *)documentView _web_updateLayoutAndStyleIfNeededRecursive]; + + if ( inView->fIsComposited ) + [inView->fWebView displayIfNeededInRect: *(NSRect*)&hiRect]; + else + [inView->fWebView displayRect:*(NSRect*)&hiRect]; + + WKNSWindowRestoreCGContext(inView->fKitWindow, savedContext); + + if ( !inView->fIsComposited ) + { + HIViewRef view; + HIViewFindByID( HIViewGetRoot( GetControlOwner( inView->fViewRef ) ), kHIViewWindowGrowBoxID, &view ); + if ( view ) + { + HIRect frame; + + HIViewGetBounds( view, &frame ); + HIViewConvertRect( &frame, view, NULL ); + + hiRect.origin.x = drawRect.left; + hiRect.origin.y = drawRect.top; + hiRect.size.width = drawRect.right - drawRect.left; + hiRect.size.height = drawRect.bottom - drawRect.top; + + HIViewConvertRect( &hiRect, inView->fViewRef, NULL ); + + if ( CGRectIntersectsRect( frame, hiRect ) ) + HIViewSetNeedsDisplay( view, true ); + } + } + + if ( createdContext ) + { + CGContextSynchronize( inContext ); + CGContextRelease( inContext ); + } +} + +//---------------------------------------------------------------------------------- +// HitTest +//---------------------------------------------------------------------------------- +// +static ControlPartCode +HitTest( HIWebView* view, const HIPoint* where ) +{ + HIRect bounds; + + HIViewGetBounds( view->fViewRef, &bounds ); + + if ( CGRectContainsPoint( bounds, *where ) ) + return 1; + else + return kControlNoPart; +} + +//---------------------------------------------------------------------------------- +// GetRegion +//---------------------------------------------------------------------------------- +// +static OSStatus +GetRegion( + HIWebView* inView, + ControlPartCode inPart, + RgnHandle outRgn ) +{ + OSStatus err = eventNotHandledErr; + + if ( inPart == -3 ) // kControlOpaqueMetaPart: + { + if ( [inView->fWebView isOpaque] ) + { + HIRect bounds; + Rect temp; + + HIViewGetBounds( inView->fViewRef, &bounds ); + + temp.top = (SInt16)bounds.origin.y; + temp.left = (SInt16)bounds.origin.x; + temp.bottom = (SInt16)CGRectGetMaxY( bounds ); + temp.right = (SInt16)CGRectGetMaxX( bounds ); + + RectRgn( outRgn, &temp ); + err = noErr; + } + } + + return err; +} + +static WindowRef +GetWindowRef( HIWebView* inView ) +{ + return GetControlOwner( inView->fViewRef ); +} + +//---------------------------------------------------------------------------------- +// Click +//---------------------------------------------------------------------------------- +// +static OSStatus +Click(HIWebView* inView, EventRef inEvent) +{ + NSEvent *kitEvent = WKCreateNSEventWithCarbonClickEvent(inEvent, GetWindowRef(inView)); + + if (!inView->fIsComposited) + StartUpdateObserver(inView); + + [inView->fKitWindow sendEvent:kitEvent]; + + if (!inView->fIsComposited) + StopUpdateObserver(inView); + + [kitEvent release]; + + return noErr; +} + +//---------------------------------------------------------------------------------- +// MouseUp +//---------------------------------------------------------------------------------- +// +static OSStatus +MouseUp( HIWebView* inView, EventRef inEvent ) +{ + NSEvent* kitEvent = WKCreateNSEventWithCarbonEvent(inEvent); + + [inView->fKitWindow sendEvent:kitEvent]; + + [kitEvent release]; + + return noErr; +} + +//---------------------------------------------------------------------------------- +// MouseMoved +//---------------------------------------------------------------------------------- +// +static OSStatus +MouseMoved( HIWebView* inView, EventRef inEvent ) +{ + NSEvent *kitEvent = WKCreateNSEventWithCarbonMouseMoveEvent(inEvent, inView->fKitWindow); + [inView->fKitWindow sendEvent:kitEvent]; + [kitEvent release]; + + return noErr; +} + +//---------------------------------------------------------------------------------- +// MouseDragged +//---------------------------------------------------------------------------------- +// +static OSStatus +MouseDragged( HIWebView* inView, EventRef inEvent ) +{ + NSEvent* kitEvent = WKCreateNSEventWithCarbonEvent(inEvent); + + [inView->fKitWindow sendEvent:kitEvent]; + + [kitEvent release]; + + return noErr; +} + +//---------------------------------------------------------------------------------- +// MouseDragged +//---------------------------------------------------------------------------------- +// +static OSStatus +MouseWheelMoved( HIWebView* inView, EventRef inEvent ) +{ + NSEvent* kitEvent = WKCreateNSEventWithCarbonEvent(inEvent); + + [inView->fKitWindow sendEvent:kitEvent]; + + [kitEvent release]; + + return noErr; +} + +//---------------------------------------------------------------------------------- +// ContextMenuClick +//---------------------------------------------------------------------------------- +// +static OSStatus +ContextMenuClick( HIWebView* inView, EventRef inEvent ) +{ + NSView *webView = inView->fWebView; + NSWindow *window = [webView window]; + + // Get the point out of the event. + HIPoint point; + GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(point), NULL, &point); + HIViewConvertPoint(&point, inView->fViewRef, NULL); + + // Flip the Y coordinate, since Carbon is flipped relative to the AppKit. + NSPoint location = NSMakePoint(point.x, [window frame].size.height - point.y); + + // Make up an event with the point and send it to the window. + NSEvent *kitEvent = [NSEvent mouseEventWithType:NSRightMouseDown + location:location + modifierFlags:0 + timestamp:GetEventTime(inEvent) + windowNumber:[window windowNumber] + context:0 + eventNumber:0 + clickCount:1 + pressure:0]; + [inView->fKitWindow sendEvent:kitEvent]; + return noErr; +} + +//---------------------------------------------------------------------------------- +// GetKind +//---------------------------------------------------------------------------------- +// +static ControlKind +GetKind() +{ + const ControlKind kMyKind = { 'appl', 'wbvw' }; + + return kMyKind; +} + +//---------------------------------------------------------------------------------- +// BoundsChanged +//---------------------------------------------------------------------------------- +// +static void +BoundsChanged( + HIWebView* inView, + UInt32 inOptions, + const HIRect* inOriginalBounds, + const HIRect* inCurrentBounds ) +{ + if ( inView->fWebView ) + { + SyncFrame( inView ); + } +} + +//---------------------------------------------------------------------------------- +// OwningWindowChanged +//---------------------------------------------------------------------------------- +// +static void +OwningWindowChanged( + HIWebView* view, + WindowRef oldWindow, + WindowRef newWindow ) +{ + if ( newWindow ){ + WindowAttributes attrs; + + OSStatus err = GetWindowProperty(newWindow, NSAppKitPropertyCreator, NSCarbonWindowPropertyTag, sizeof(NSWindow *), NULL, &view->fKitWindow); + if ( err != noErr ) + { + const EventTypeSpec kWindowEvents[] = { + { kEventClassWindow, kEventWindowClosed }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassMouse, kEventMouseWheelMoved }, + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + { kEventClassKeyboard, kEventRawKeyUp }, + { kEventClassControl, kEventControlClick }, + }; + + view->fKitWindow = [[CarbonWindowAdapter alloc] initWithCarbonWindowRef: newWindow takingOwnership: NO disableOrdering:NO carbon:YES]; + SetWindowProperty(newWindow, NSAppKitPropertyCreator, NSCarbonWindowPropertyTag, sizeof(NSWindow *), &view->fKitWindow); + + InstallWindowEventHandler( newWindow, WindowHandler, GetEventTypeCount( kWindowEvents ), kWindowEvents, newWindow, NULL ); + } + + [[view->fKitWindow contentView] addSubview:view->fWebView]; + + GetWindowAttributes( newWindow, &attrs ); + view->fIsComposited = ( ( attrs & kWindowCompositingAttribute ) != 0 ); + + SyncFrame( view ); + } + else + { + // Be sure to detach the cocoa view, too. + if ( view->fWebView ) + [view->fWebView removeFromSuperview]; + + view->fKitWindow = NULL; // break the ties that bind + } +} + +//------------------------------------------------------------------------------------- +// WindowHandler +//------------------------------------------------------------------------------------- +// Redirect mouse events to the views beneath them. This is required for WebKit to work +// properly. We install it once per window. We also tap into window close to release +// the NSWindow that shadows our Carbon window. +// +static OSStatus +WindowHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ) +{ + WindowRef window = (WindowRef)inUserData; + OSStatus result = eventNotHandledErr; + + switch( GetEventClass( inEvent ) ) + { + case kEventClassControl: + { + switch( GetEventKind( inEvent ) ) + { + case kEventControlClick: + { + CarbonWindowAdapter *kitWindow; + OSStatus err; + + err = GetWindowProperty( window, NSAppKitPropertyCreator, NSCarbonWindowPropertyTag, sizeof(NSWindow *), NULL, &kitWindow); + + // We must be outside the HIWebView, relinquish focus. + [kitWindow relinquishFocus]; + } + break; + } + } + break; + + case kEventClassKeyboard: + { + NSWindow* kitWindow; + OSStatus err; + NSEvent* kitEvent; + + // if the first responder in the kit window is something other than the + // window, we assume a subview of the webview is focused. we must send + // the event to the window so that it goes through the kit's normal TSM + // logic, and -- more importantly -- allows any delegates associated + // with the first responder to have a chance at the event. + + err = GetWindowProperty( window, NSAppKitPropertyCreator, NSCarbonWindowPropertyTag, sizeof(NSWindow *), NULL, &kitWindow); + if ( err == noErr ) + { + NSResponder* responder = [kitWindow firstResponder]; + if ( responder != kitWindow ) + { + kitEvent = WKCreateNSEventWithCarbonEvent(inEvent); + + [kitWindow sendEvent:kitEvent]; + [kitEvent release]; + + result = noErr; + } + } + } + break; + + case kEventClassWindow: + { + NSWindow* kitWindow; + OSStatus err; + + err = GetWindowProperty( window, NSAppKitPropertyCreator, NSCarbonWindowPropertyTag, sizeof(NSWindow *), NULL, &kitWindow); + if ( err == noErr ) + { + [kitWindow _removeWindowRef]; + [kitWindow close]; + } + + result = noErr; + } + break; + + case kEventClassMouse: + switch (GetEventKind(inEvent)) + { + case kEventMouseMoved: + { + Point where; + GetEventParameter(inEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &where); + + WindowRef temp; + FindWindow(where, &temp); + if (temp == window) + { + Rect bounds; + GetWindowBounds(window, kWindowStructureRgn, &bounds); + where.h -= bounds.left; + where.v -= bounds.top; + SetEventParameter(inEvent, kEventParamWindowRef, typeWindowRef, sizeof(WindowRef), &window); + SetEventParameter(inEvent, kEventParamWindowMouseLocation, typeQDPoint, sizeof(Point), &where); + + OSStatus err = noErr; + HIViewRef view = NULL; + + err = HIViewGetViewForMouseEvent(HIViewGetRoot(window), inEvent, &view); + if (err == noErr && view && HIObjectIsOfClass((HIObjectRef)view, kHIWebViewClassID)) + result = SendEventToEventTargetWithOptions(inEvent, HIObjectGetEventTarget((HIObjectRef)view), kEventTargetDontPropagate); + } + } + break; + + case kEventMouseUp: + case kEventMouseDragged: + case kEventMouseWheelMoved: + { + OSStatus err = noErr; + HIViewRef view = NULL; + + err = HIViewGetViewForMouseEvent(HIViewGetRoot(window), inEvent, &view); + if (err == noErr && view && HIObjectIsOfClass((HIObjectRef)view, kHIWebViewClassID)) + result = SendEventToEventTargetWithOptions(inEvent, HIObjectGetEventTarget((HIObjectRef)view), kEventTargetDontPropagate); + } + break; + } + break; + } + + return result; +} + + +//---------------------------------------------------------------------------------- +// SyncFrame +//---------------------------------------------------------------------------------- +// +static void +SyncFrame( HIWebView* inView ) +{ + HIViewRef parent = HIViewGetSuperview( inView->fViewRef ); + + if ( parent ) + { + if ( inView->fIsComposited ) + { + HIRect frame; + HIRect parentBounds; + NSPoint origin; + + HIViewGetFrame( inView->fViewRef, &frame ); + HIViewGetBounds( parent, &parentBounds ); + + origin.x = frame.origin.x; + origin.y = parentBounds.size.height - CGRectGetMaxY( frame ); +// printf( "syncing to (%g %g) (%g %g)\n", origin.x, origin.y, +// frame.size.width, frame.size.height ); + [inView->fWebView setFrameOrigin: origin]; + [inView->fWebView setFrameSize: *(NSSize*)&frame.size]; + } + else + { + GrafPtr port = GetWindowPort( GetControlOwner( inView->fViewRef ) ); + PixMapHandle portPix = GetPortPixMap( port ); + Rect bounds; + HIRect rootFrame; + HIRect frame; + + GetControlBounds( inView->fViewRef, &bounds ); + OffsetRect( &bounds, -(**portPix).bounds.left, -(**portPix).bounds.top ); + +// printf( "control lives at %d %d %d %d in window-coords\n", bounds.top, bounds.left, +// bounds.bottom, bounds.right ); + + HIViewGetFrame( HIViewGetRoot( GetControlOwner( inView->fViewRef ) ), &rootFrame ); + + frame.origin.x = bounds.left; + frame.origin.y = rootFrame.size.height - bounds.bottom; + frame.size.width = bounds.right - bounds.left; + frame.size.height = bounds.bottom - bounds.top; + +// printf( " before frame convert (%g %g) (%g %g)\n", frame.origin.x, frame.origin.y, +// frame.size.width, frame.size.height ); + + [inView->fWebView convertRect:*(NSRect*)&frame fromView:nil]; + +// printf( " moving web view to (%g %g) (%g %g)\n", frame.origin.x, frame.origin.y, +// frame.size.width, frame.size.height ); + + [inView->fWebView setFrameOrigin: *(NSPoint*)&frame.origin]; + [inView->fWebView setFrameSize: *(NSSize*)&frame.size]; + } + } +} + +//---------------------------------------------------------------------------------- +// SetFocusPart +//---------------------------------------------------------------------------------- +// +static OSStatus +SetFocusPart( + HIWebView* view, + ControlPartCode desiredFocus, + RgnHandle invalidRgn, + Boolean focusEverything, + ControlPartCode* actualFocus ) +{ + NSView * freshlyMadeFirstResponderView; + SInt32 partCodeToReturn; + + // Do what Carbon is telling us to do. + if ( desiredFocus == kControlFocusNoPart ) + { + // Relinquish the keyboard focus. + RelinquishFocus( view, true ); //(autodisplay ? YES : NO)); + freshlyMadeFirstResponderView = nil; + partCodeToReturn = kControlFocusNoPart; + //NSLog(@"Relinquished the key focus because we have no choice."); + } + else if ( desiredFocus == kControlFocusNextPart || desiredFocus == kControlFocusPrevPart ) + { + BOOL goForward = (desiredFocus == kControlFocusNextPart ); + + // Advance the keyboard focus, maybe right off of this view. Maybe a subview of this one already has the keyboard focus, maybe not. + freshlyMadeFirstResponderView = AdvanceFocus( view, goForward ); + if (freshlyMadeFirstResponderView) + partCodeToReturn = desiredFocus; + else + partCodeToReturn = kControlFocusNoPart; + //NSLog(freshlyMadeFirstResponderView ? @"Advanced the key focus." : @"Relinquished the key focus."); + } + else + { + // What's this? + if (desiredFocus != kControlIndicatorPart) { + check(false); + } + freshlyMadeFirstResponderView = nil; + partCodeToReturn = desiredFocus; + } + + view->fFirstResponder = freshlyMadeFirstResponderView; + + *actualFocus = partCodeToReturn; + + // Done. + return noErr; +} + +//---------------------------------------------------------------------------------- +// AdvanceFocus +//---------------------------------------------------------------------------------- +// +static NSView* +AdvanceFocus( HIWebView* view, bool forward ) +{ + NSResponder* oldFirstResponder; + NSView* currentKeyView; + NSView* viewWeMadeFirstResponder; + + // Focus on some part (subview) of this control (view). Maybe + // a subview of this one already has the keyboard focus, maybe not. + + oldFirstResponder = [view->fKitWindow firstResponder]; + + // If we tab out of our NSView, it will no longer be the responder + // when we get here. We'll try this trick for now. We might need to + // tag the view appropriately. + + if ( view->fFirstResponder && ( (NSResponder*)view->fFirstResponder != oldFirstResponder ) ) + { + return NULL; + } + + if ( [oldFirstResponder isKindOfClass:[NSView class]] ) + { + NSView* tentativeNewKeyView; + + // Some view in this window already has the keyboard focus. It better at least be a subview of this one. + NSView* oldFirstResponderView = (NSView *)oldFirstResponder; + check( [oldFirstResponderView isDescendantOf:view->fWebView] ); + + if ( oldFirstResponderView != view->fFirstResponder + && ![oldFirstResponderView isDescendantOf:view->fFirstResponder] ) + { + // Despite our efforts to record what view we made the first responder + // (for use in the next paragraph) we couldn't keep up because the user + // has clicked in a text field to make it the key focus, instead of using + // the tab key. Find a control on which it's reasonable to invoke + // -[NSView nextValidKeyView], taking into account the fact that + // NSTextFields always pass on first-respondership to a temporarily- + // contained NSTextView. + + NSView *viewBeingTested; + currentKeyView = oldFirstResponderView; + viewBeingTested = currentKeyView; + while ( viewBeingTested != view->fWebView ) + { + if ( [viewBeingTested isKindOfClass:[NSTextField class]] ) + { + currentKeyView = viewBeingTested; + break; + } + else + { + viewBeingTested = [viewBeingTested superview]; + } + } + } + else + { + // We recorded which view we made into the first responder the + // last time the user hit the tab key, and nothing has invalidated + // our recorded value since. + + currentKeyView = view->fFirstResponder; + } + + // Try to move on to the next or previous key view. We use the laboriously + // recorded/figured currentKeyView instead of just oldFirstResponder as the + // jumping-off-point when searching for the next valid key view. This is so + // we don't get fooled if we recently made some view the first responder, but + // it passed on first-responder-ness to some temporary subview. + + // You can't put normal views in a window with Carbon-control-wrapped views. + // Stuff like this would break. M.P. Notice - 12/2/00 + + tentativeNewKeyView = forward ? [currentKeyView nextValidKeyView] : [currentKeyView previousValidKeyView]; + if ( tentativeNewKeyView && [tentativeNewKeyView isDescendantOf:view->fWebView] ) + { + // The user has tabbed to another subview of this control view. Change the keyboard focus. + //NSLog(@"Tabbed to the next or previous key view."); + + [view->fKitWindow makeFirstResponder:tentativeNewKeyView]; + viewWeMadeFirstResponder = tentativeNewKeyView; + } + else + { + // The user has tabbed past the subviews of this control view. The window is the first responder now. + //NSLog(@"Tabbed past the first or last key view."); + [view->fKitWindow makeFirstResponder:view->fKitWindow]; + viewWeMadeFirstResponder = nil; + } + } + else + { + // No view in this window has the keyboard focus. This view should + // try to select one of its key subviews. We're not interested in + // the subviews of sibling views here. + + //NSLog(@"No keyboard focus in window. Attempting to set..."); + + NSView *tentativeNewKeyView; + check(oldFirstResponder==fKitWindow); + if ( [view->fWebView acceptsFirstResponder] ) + tentativeNewKeyView = view->fWebView; + else + tentativeNewKeyView = [view->fWebView nextValidKeyView]; + if ( tentativeNewKeyView && [tentativeNewKeyView isDescendantOf:view->fWebView] ) + { + // This control view has at least one subview that can take the keyboard focus. + if ( !forward ) + { + // The user has tabbed into this control view backwards. Find + // and select the last subview of this one that can take the + // keyboard focus. Watch out for loops of valid key views. + + NSView *firstTentativeNewKeyView = tentativeNewKeyView; + NSView *nextTentativeNewKeyView = [tentativeNewKeyView nextValidKeyView]; + while ( nextTentativeNewKeyView + && [nextTentativeNewKeyView isDescendantOf:view->fWebView] + && nextTentativeNewKeyView!=firstTentativeNewKeyView) + { + tentativeNewKeyView = nextTentativeNewKeyView; + nextTentativeNewKeyView = [tentativeNewKeyView nextValidKeyView]; + } + + } + + // Set the keyboard focus. + //NSLog(@"Tabbed into the first or last key view."); + [view->fKitWindow makeFirstResponder:tentativeNewKeyView]; + viewWeMadeFirstResponder = tentativeNewKeyView; + } + else + { + // This control view has no subviews that can take the keyboard focus. + //NSLog(@"Can't tab into this view."); + viewWeMadeFirstResponder = nil; + } + } + + // Done. + return viewWeMadeFirstResponder; +} + + +//---------------------------------------------------------------------------------- +// RelinquishFocus +//---------------------------------------------------------------------------------- +// +static void +RelinquishFocus( HIWebView* view, bool inAutodisplay ) +{ + NSResponder* firstResponder; + + // Apparently Carbon thinks that some subview of this control view has the keyboard focus, + // or we wouldn't be being asked to relinquish focus. + + firstResponder = [view->fKitWindow firstResponder]; + if ( [firstResponder isKindOfClass:[NSView class]] ) + { + // Some subview of this control view really is the first responder right now. + check( [(NSView *)firstResponder isDescendantOf:view->fWebView] ); + + // Make the window the first responder, so that no view is the key view. + [view->fKitWindow makeFirstResponder:view->fKitWindow]; + + // If this control is not allowed to do autodisplay, don't let + // it autodisplay any just-changed focus rings or text on the + // next go around the event loop. I'm probably clearing more + // dirty rects than I have to, but it doesn't seem to hurt in + // the print panel accessory view case, and I don't have time + // to figure out exactly what -[NSCell _setKeyboardFocusRingNeedsDisplay] + // is doing when invoked indirectly from -makeFirstResponder up above. M.P. Notice - 12/4/00 + + if ( !inAutodisplay ) + [[view->fWebView opaqueAncestor] _clearDirtyRectsForTree]; + } + else + { + // The Cocoa first responder does not correspond to the Carbon + // control that has the keyboard focus. This can happen when + // you've closed a dialog by hitting return in an NSTextView + // that's a subview of this one; Cocoa closed the window, and + // now Carbon is telling this control to relinquish the focus + // as it's being disposed. There's nothing to do. + + check(firstResponder==window); + } +} + +//---------------------------------------------------------------------------------- +// ActiveStateChanged +//---------------------------------------------------------------------------------- +// +static void +ActiveStateChanged( HIWebView* view ) +{ + if ( [view->fWebView respondsToSelector:@selector(setEnabled)] ) + { + [(NSControl*)view->fWebView setEnabled: IsControlEnabled( view->fViewRef )]; + HIViewSetNeedsDisplay( view->fViewRef, true ); + } +} + + +//---------------------------------------------------------------------------------- +// ProcessCommand +//---------------------------------------------------------------------------------- +// +static OSStatus +ProcessCommand( HIWebView* inView, const HICommand* inCommand ) +{ + OSStatus result = eventNotHandledErr; + NSResponder* resp; + + resp = [inView->fKitWindow firstResponder]; + + if ( [resp isKindOfClass:[NSView class]] ) + { + NSView* respView = (NSView*)resp; + + if ( respView == inView->fWebView + || [respView isDescendantOf: inView->fWebView] ) + { + switch ( inCommand->commandID ) + { + case kHICommandCut: + case kHICommandCopy: + case kHICommandPaste: + case kHICommandClear: + case kHICommandSelectAll: + { + SEL selector = _NSSelectorForHICommand( inCommand ); + if ( [respView respondsToSelector:selector] ) + { + [respView performSelector:selector withObject:nil]; + result = noErr; + } + } + break; + } + } + } + + return result; +} + +//---------------------------------------------------------------------------------- +// UpdateCommandStatus +//---------------------------------------------------------------------------------- +// +static OSStatus +UpdateCommandStatus( HIWebView* inView, const HICommand* inCommand ) +{ + OSStatus result = eventNotHandledErr; + MenuItemProxy* proxy = NULL; + NSResponder* resp; + + resp = [inView->fKitWindow firstResponder]; + + if ( [resp isKindOfClass:[NSView class]] ) + { + NSView* respView = (NSView*)resp; + + if ( respView == inView->fWebView + || [respView isDescendantOf: inView->fWebView] ) + { + if ( inCommand->attributes & kHICommandFromMenu ) + { + SEL selector = _NSSelectorForHICommand( inCommand ); + + if ( selector ) + { + if ( [resp respondsToSelector: selector] ) + { + proxy = [[MenuItemProxy alloc] initWithAction: selector]; + + // Can't use -performSelector:withObject: here because the method we're calling returns BOOL, while + // -performSelector:withObject:'s return value is assumed to be an id. + BOOL (*validationFunction)(id, SEL, id) = (BOOL (*)(id, SEL, id))objc_msgSend; + if (validationFunction(resp, @selector(validateUserInterfaceItem:), proxy)) + EnableMenuItem( inCommand->menu.menuRef, inCommand->menu.menuItemIndex ); + else + DisableMenuItem( inCommand->menu.menuRef, inCommand->menu.menuItemIndex ); + + result = noErr; + } + } + } + } + } + + if ( proxy ) + [proxy release]; + + return result; +} + +// Blatantly stolen from AppKit and cropped a bit + +//---------------------------------------------------------------------------------- +// _NSSelectorForHICommand +//---------------------------------------------------------------------------------- +// +static SEL +_NSSelectorForHICommand( const HICommand* inCommand ) +{ + switch ( inCommand->commandID ) + { + case kHICommandUndo: return @selector(undo:); + case kHICommandRedo: return @selector(redo:); + case kHICommandCut : return @selector(cut:); + case kHICommandCopy : return @selector(copy:); + case kHICommandPaste: return @selector(paste:); + case kHICommandClear: return @selector(delete:); + case kHICommandSelectAll: return @selector(selectAll:); + default: return NULL; + } + + return NULL; +} + + +//----------------------------------------------------------------------------------- +// HIWebViewEventHandler +//----------------------------------------------------------------------------------- +// Our object's virtual event handler method. I'm not sure if we need this these days. +// We used to do various things with it, but those days are long gone... +// +static OSStatus +HIWebViewEventHandler( + EventHandlerCallRef inCallRef, + EventRef inEvent, + void * inUserData ) +{ + OSStatus result = eventNotHandledErr; + HIPoint where; + OSType tag; + void * ptr; + Size size; + UInt32 features; + RgnHandle region = NULL; + ControlPartCode part; + HIWebView* view = (HIWebView*)inUserData; + + // [NSApp setWindowsNeedUpdate:YES] must be called before events so that ActivateTSMDocument is called to set an active document. + // Without an active document, TSM will use a default document which uses a bottom-line input window which we don't want. + [NSApp setWindowsNeedUpdate:YES]; + + switch ( GetEventClass( inEvent ) ) + { + case kEventClassHIObject: + switch ( GetEventKind( inEvent ) ) + { + case kEventHIObjectConstruct: + { + HIObjectRef object; + + result = GetEventParameter( inEvent, kEventParamHIObjectInstance, + typeHIObjectRef, NULL, sizeof( HIObjectRef ), NULL, &object ); + require_noerr( result, MissingParameter ); + + // on entry for our construct event, we're passed the + // creation proc we registered with for this class. + // we use it now to create the instance, and then we + // replace the instance parameter data with said instance + // as type void. + + view = HIWebViewConstructor( (HIViewRef)object ); + + if ( view ) + { + SetEventParameter( inEvent, kEventParamHIObjectInstance, + typeVoidPtr, sizeof( void * ), &view ); + } + } + break; + + case kEventHIObjectDestruct: + HIWebViewDestructor( view ); + // result is unimportant + break; + } + break; + + case kEventClassKeyboard: + { + NSEvent* kitEvent = WKCreateNSEventWithCarbonEvent(inEvent); + [view->fKitWindow sendSuperEvent:kitEvent]; + [kitEvent release]; + result = noErr; + } + break; + + case kEventClassMouse: + switch ( GetEventKind( inEvent ) ) + { + case kEventMouseUp: + result = MouseUp( view, inEvent ); + break; + + case kEventMouseWheelMoved: + result = MouseWheelMoved( view, inEvent ); + break; + + case kEventMouseMoved: + result = MouseMoved( view, inEvent ); + break; + + case kEventMouseDragged: + result = MouseDragged( view, inEvent ); + break; + } + break; + + case kEventClassCommand: + { + HICommand command; + + result = GetEventParameter( inEvent, kEventParamDirectObject, typeHICommand, NULL, + sizeof( HICommand ), NULL, &command ); + require_noerr( result, MissingParameter ); + + switch ( GetEventKind( inEvent ) ) + { + case kEventCommandProcess: + result = ProcessCommand( view, &command ); + break; + + case kEventCommandUpdateStatus: + result = UpdateCommandStatus( view, &command ); + break; + } + } + break; + + case kEventClassControl: + switch ( GetEventKind( inEvent ) ) + { + case kEventControlInitialize: + features = GetBehaviors(); + SetEventParameter( inEvent, kEventParamControlFeatures, typeUInt32, + sizeof( UInt32 ), &features ); + result = noErr; + break; + + case kEventControlDraw: + { + CGContextRef context = NULL; + + GetEventParameter( inEvent, kEventParamRgnHandle, typeQDRgnHandle, NULL, + sizeof( RgnHandle ), NULL, ®ion ); + GetEventParameter( inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, + sizeof( CGContextRef ), NULL, &context ); + + Draw( view, region, context ); + + result = noErr; + } + break; + + case kEventControlHitTest: + GetEventParameter( inEvent, kEventParamMouseLocation, typeHIPoint, NULL, + sizeof( HIPoint ), NULL, &where ); + part = HitTest( view, &where ); + SetEventParameter( inEvent, kEventParamControlPart, typeControlPartCode, sizeof( ControlPartCode ), &part ); + result = noErr; + break; + + case kEventControlGetPartRegion: + GetEventParameter( inEvent, kEventParamControlPart, typeControlPartCode, NULL, + sizeof( ControlPartCode ), NULL, &part ); + GetEventParameter( inEvent, kEventParamControlRegion, typeQDRgnHandle, NULL, + sizeof( RgnHandle ), NULL, ®ion ); + result = GetRegion( view, part, region ); + break; + + case kEventControlGetData: + GetEventParameter(inEvent, kEventParamControlPart, typeControlPartCode, NULL, sizeof(ControlPartCode), NULL, &part); + GetEventParameter(inEvent, kEventParamControlDataTag, typeEnumeration, NULL, sizeof(OSType), NULL, &tag); + GetEventParameter(inEvent, kEventParamControlDataBuffer, typePtr, NULL, sizeof(Ptr), NULL, &ptr); + GetEventParameter(inEvent, kEventParamControlDataBufferSize, typeByteCount, NULL, sizeof(Size), NULL, &size); + + if (tag == kControlKindTag) { + Size outSize; + result = noErr; + + if (ptr) { + if (size != sizeof(ControlKind)) + result = errDataSizeMismatch; + else + (*(ControlKind *)ptr) = GetKind(); + } + + outSize = sizeof(ControlKind); + SetEventParameter(inEvent, kEventParamControlDataBufferSize, typeByteCount, sizeof(Size), &outSize); + } + + break; + + case kEventControlBoundsChanged: + { + HIRect prevRect, currRect; + UInt32 attrs; + + GetEventParameter( inEvent, kEventParamAttributes, typeUInt32, NULL, + sizeof( UInt32 ), NULL, &attrs ); + GetEventParameter( inEvent, kEventParamOriginalBounds, typeHIRect, NULL, + sizeof( HIRect ), NULL, &prevRect ); + GetEventParameter( inEvent, kEventParamCurrentBounds, typeHIRect, NULL, + sizeof( HIRect ), NULL, &currRect ); + + BoundsChanged( view, attrs, &prevRect, &currRect ); + result = noErr; + } + break; + + case kEventControlActivate: + ActiveStateChanged( view ); + result = noErr; + break; + + case kEventControlDeactivate: + ActiveStateChanged( view ); + result = noErr; + break; + + case kEventControlOwningWindowChanged: + { + WindowRef fromWindow, toWindow; + + result = GetEventParameter( inEvent, kEventParamControlOriginalOwningWindow, typeWindowRef, NULL, + sizeof( WindowRef ), NULL, &fromWindow ); + require_noerr( result, MissingParameter ); + + result = GetEventParameter( inEvent, kEventParamControlCurrentOwningWindow, typeWindowRef, NULL, + sizeof( WindowRef ), NULL, &toWindow ); + require_noerr( result, MissingParameter ); + + OwningWindowChanged( view, fromWindow, toWindow ); + + result = noErr; + } + break; + + case kEventControlClick: + result = Click( view, inEvent ); + break; + + case kEventControlContextualMenuClick: + result = ContextMenuClick( view, inEvent ); + break; + + case kEventControlSetFocusPart: + { + ControlPartCode desiredFocus; + RgnHandle invalidRgn; + Boolean focusEverything; + ControlPartCode actualFocus; + + result = GetEventParameter( inEvent, kEventParamControlPart, typeControlPartCode, NULL, + sizeof( ControlPartCode ), NULL, &desiredFocus ); + require_noerr( result, MissingParameter ); + + GetEventParameter( inEvent, kEventParamControlInvalRgn, typeQDRgnHandle, NULL, + sizeof( RgnHandle ), NULL, &invalidRgn ); + + focusEverything = false; // a good default in case the parameter doesn't exist + + GetEventParameter( inEvent, kEventParamControlFocusEverything, typeBoolean, NULL, + sizeof( Boolean ), NULL, &focusEverything ); + + result = SetFocusPart( view, desiredFocus, invalidRgn, focusEverything, &actualFocus ); + + if ( result == noErr ) + verify_noerr( SetEventParameter( inEvent, kEventParamControlPart, typeControlPartCode, + sizeof( ControlPartCode ), &actualFocus ) ); + } + break; + + // some other kind of Control event + default: + break; + } + break; + + // some other event class + default: + break; + } + +MissingParameter: + return result; +} + + +static void UpdateObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); + +static void +StartUpdateObserver( HIWebView* view ) +{ + CFRunLoopObserverContext context; + CFRunLoopObserverRef observer; + CFRunLoopRef mainRunLoop; + + check( view->fIsComposited == false ); + check( view->fUpdateObserver == NULL ); + + context.version = 0; + context.info = view; + context.retain = NULL; + context.release = NULL; + context.copyDescription = NULL; + + mainRunLoop = (CFRunLoopRef)GetCFRunLoopFromEventLoop( GetMainEventLoop() ); + observer = CFRunLoopObserverCreate( NULL, kCFRunLoopEntry | kCFRunLoopBeforeWaiting, true, 0, UpdateObserver, &context ); + CFRunLoopAddObserver( mainRunLoop, observer, kCFRunLoopCommonModes ); + + view->fUpdateObserver = observer; + +// printf( "Update observer started\n" ); +} + +static void +StopUpdateObserver( HIWebView* view ) +{ + check( view->fIsComposited == false ); + check( view->fUpdateObserver != NULL ); + + CFRunLoopObserverInvalidate( view->fUpdateObserver ); + CFRelease( view->fUpdateObserver ); + view->fUpdateObserver = NULL; + +// printf( "Update observer removed\n" ); +} + +static void +UpdateObserver( CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info ) +{ + HIWebView* view = (HIWebView*)info; + RgnHandle region = NewRgn(); + +// printf( "Update observer called\n" ); + + if ( region ) + { + GetWindowRegion( GetControlOwner( view->fViewRef ), kWindowUpdateRgn, region ); + + if ( !EmptyRgn( region ) ) + { + RgnHandle ourRgn = NewRgn(); + Rect rect; + + GetWindowBounds( GetControlOwner( view->fViewRef ), kWindowStructureRgn, &rect ); + +// printf( "Update region is non-empty\n" ); + + if ( ourRgn ) + { + Rect rect; + GrafPtr savePort, port; + Point offset = { 0, 0 }; + + port = GetWindowPort( GetControlOwner( view->fViewRef ) ); + + GetPort( &savePort ); + SetPort( port ); + + GlobalToLocal( &offset ); + OffsetRgn( region, offset.h, offset.v ); + + GetControlBounds( view->fViewRef, &rect ); + RectRgn( ourRgn, &rect ); + +// printf( "our control is at %d %d %d %d\n", +// rect.top, rect.left, rect.bottom, rect.right ); + + GetRegionBounds( region, &rect ); +// printf( "region is at %d %d %d %d\n", +// rect.top, rect.left, rect.bottom, rect.right ); + + SectRgn( ourRgn, region, ourRgn ); + + GetRegionBounds( ourRgn, &rect ); +// printf( "intersection is %d %d %d %d\n", +// rect.top, rect.left, rect.bottom, rect.right ); + if ( !EmptyRgn( ourRgn ) ) + { + RgnHandle saveVis = NewRgn(); + +// printf( "looks like we should draw\n" ); + + if ( saveVis ) + { +// RGBColor kRedColor = { 0xffff, 0, 0 }; + + GetPortVisibleRegion( GetWindowPort( GetControlOwner( view->fViewRef ) ), saveVis ); + SetPortVisibleRegion( GetWindowPort( GetControlOwner( view->fViewRef ) ), ourRgn ); + +// RGBForeColor( &kRedColor ); +// PaintRgn( ourRgn ); +// QDFlushPortBuffer( port, NULL ); +// Delay( 15, NULL ); + + Draw1Control( view->fViewRef ); + ValidWindowRgn( GetControlOwner( view->fViewRef ), ourRgn ); + + SetPortVisibleRegion( GetWindowPort( GetControlOwner( view->fViewRef ) ), saveVis ); + DisposeRgn( saveVis ); + } + } + + SetPort( savePort ); + + DisposeRgn( ourRgn ); + } + } + + DisposeRgn( region ); + } +} + +#endif |
