--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebKit/Carbon/HIWebView.m Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,1639 @@
+/*
+ * 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 "WebHTMLViewInternal.h"
+#import "WebKit.h"
+
+#import <objc/objc-runtime.h>
+#import <WebKitSystemInterface.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 );
+}
+
+static Class webViewClass;
+
+//----------------------------------------------------------------------------------
+// HIWebViewCreate
+//----------------------------------------------------------------------------------
+//
+OSStatus
+HIWebViewCreate( HIViewRef* outControl )
+{
+ OSStatus err;
+
+ HIWebViewRegisterClass();
+
+ webViewClass = [WebView class];
+ err = HIObjectCreate( kHIWebViewClassID, NULL, (HIObjectRef*)outControl );
+
+ return err;
+}
+
+//----------------------------------------------------------------------------------
+// HIWebViewCreateWithClass
+//----------------------------------------------------------------------------------
+//
+OSStatus HIWebViewCreateWithClass(Class aClass, HIViewRef * outControl)
+{
+ OSStatus err;
+
+ HIWebViewRegisterClass();
+
+ webViewClass = aClass;
+ err = HIObjectCreate( kHIWebViewClassID, NULL, (HIObjectRef*)outControl );
+
+ return err;
+}
+
+//----------------------------------------------------------------------------------
+// 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 = [[webViewClass 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_layoutIfNeededRecursive];
+
+ 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