| /* |
| * 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 |