1/* 2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#ifndef __LP64__ 30 31#import "HIWebView.h" 32 33#import "CarbonWindowAdapter.h" 34#import "HIViewAdapter.h" 35#import "QuickDrawCompatibility.h" 36#import "WebHTMLViewInternal.h" 37#import "WebKit.h" 38#import <WebKitSystemInterface.h> 39#import <wtf/ObjcRuntimeExtras.h> 40 41@interface NSWindow (AppKitSecretsHIWebViewKnows) 42- (void)_removeWindowRef; 43@end 44 45@interface NSView (AppKitSecretsHIWebViewKnows) 46- (void)_clearDirtyRectsForTree; 47@end 48 49extern "C" void HIWebViewRegisterClass(); 50 51@interface MenuItemProxy : NSObject <NSValidatedUserInterfaceItem> 52{ 53 int _tag; 54 SEL _action; 55} 56 57- (id)initWithAction:(SEL)action; 58- (SEL)action; 59- (int)tag; 60 61@end 62 63@implementation MenuItemProxy 64 65- (id)initWithAction:(SEL)action 66{ 67 [super init]; 68 if (self == nil) return nil; 69 70 _action = action; 71 72 return self; 73} 74 75- (SEL)action 76{ 77 return _action; 78} 79 80- (int)tag 81{ 82 return 0; 83} 84 85@end 86 87struct HIWebView 88{ 89 HIViewRef fViewRef; 90 91 WebView* fWebView; 92 NSView* fFirstResponder; 93 CarbonWindowAdapter * fKitWindow; 94 bool fIsComposited; 95 CFRunLoopObserverRef fUpdateObserver; 96}; 97typedef struct HIWebView HIWebView; 98 99static const OSType NSAppKitPropertyCreator = 'akit'; 100/* 101These constants are not used. Commented out to make the compiler happy. 102static const OSType NSViewCarbonControlViewPropertyTag = 'view'; 103static const OSType NSViewCarbonControlAutodisplayPropertyTag = 'autd'; 104static const OSType NSViewCarbonControlFirstResponderViewPropertyTag = 'frvw'; 105*/ 106static const OSType NSCarbonWindowPropertyTag = 'win '; 107 108 109static SEL _NSSelectorForHICommand( const HICommand* hiCommand ); 110 111static const EventTypeSpec kEvents[] = { 112 { kEventClassHIObject, kEventHIObjectConstruct }, 113 { kEventClassHIObject, kEventHIObjectDestruct }, 114 115 { kEventClassMouse, kEventMouseUp }, 116 { kEventClassMouse, kEventMouseMoved }, 117 { kEventClassMouse, kEventMouseDragged }, 118 { kEventClassMouse, kEventMouseWheelMoved }, 119 120 { kEventClassKeyboard, kEventRawKeyDown }, 121 { kEventClassKeyboard, kEventRawKeyRepeat }, 122 123 { kEventClassCommand, kEventCommandProcess }, 124 { kEventClassCommand, kEventCommandUpdateStatus }, 125 126 { kEventClassControl, kEventControlInitialize }, 127 { kEventClassControl, kEventControlDraw }, 128 { kEventClassControl, kEventControlHitTest }, 129 { kEventClassControl, kEventControlGetPartRegion }, 130 { kEventClassControl, kEventControlGetData }, 131 { kEventClassControl, kEventControlBoundsChanged }, 132 { kEventClassControl, kEventControlActivate }, 133 { kEventClassControl, kEventControlDeactivate }, 134 { kEventClassControl, kEventControlOwningWindowChanged }, 135 { kEventClassControl, kEventControlClick }, 136 { kEventClassControl, kEventControlContextualMenuClick }, 137 { kEventClassControl, kEventControlSetFocusPart } 138}; 139 140#define kHIViewBaseClassID CFSTR( "com.apple.hiview" ) 141#define kHIWebViewClassID CFSTR( "com.apple.HIWebView" ) 142 143static HIWebView* HIWebViewConstructor( HIViewRef inView ); 144static void HIWebViewDestructor( HIWebView* view ); 145 146static OSStatus HIWebViewEventHandler( 147 EventHandlerCallRef inCallRef, 148 EventRef inEvent, 149 void * inUserData ); 150 151static UInt32 GetBehaviors(); 152static ControlKind GetKind(); 153static void Draw( HIWebView* inView, RgnHandle limitRgn, CGContextRef inContext ); 154static ControlPartCode HitTest( HIWebView* view, const HIPoint* where ); 155static OSStatus GetRegion( HIWebView* view, ControlPartCode inPart, RgnHandle outRgn ); 156static void BoundsChanged( 157 HIWebView* inView, 158 UInt32 inOptions, 159 const HIRect* inOriginalBounds, 160 const HIRect* inCurrentBounds ); 161static void OwningWindowChanged( 162 HIWebView* view, 163 WindowRef oldWindow, 164 WindowRef newWindow ); 165static void ActiveStateChanged( HIWebView* view ); 166 167static OSStatus Click( HIWebView* inView, EventRef inEvent ); 168static OSStatus ContextMenuClick( HIWebView* inView, EventRef inEvent ); 169static OSStatus MouseUp( HIWebView* inView, EventRef inEvent ); 170static OSStatus MouseMoved( HIWebView* inView, EventRef inEvent ); 171static OSStatus MouseDragged( HIWebView* inView, EventRef inEvent ); 172static OSStatus MouseWheelMoved( HIWebView* inView, EventRef inEvent ); 173 174static OSStatus ProcessCommand( HIWebView* inView, const HICommand* inCommand ); 175static OSStatus UpdateCommandStatus( HIWebView* inView, const HICommand* inCommand ); 176 177static OSStatus SetFocusPart( 178 HIWebView* view, 179 ControlPartCode desiredFocus, 180 RgnHandle invalidRgn, 181 Boolean focusEverything, 182 ControlPartCode* actualFocus ); 183static NSView* AdvanceFocus( HIWebView* view, bool forward ); 184static void RelinquishFocus( HIWebView* view, bool inAutodisplay ); 185 186static WindowRef GetWindowRef( HIWebView* inView ); 187static void SyncFrame( HIWebView* inView ); 188 189static OSStatus WindowHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ); 190 191static void StartUpdateObserver( HIWebView* view ); 192static void StopUpdateObserver( HIWebView* view ); 193 194static inline void HIRectToQDRect( const HIRect* inRect, Rect* outRect ) 195{ 196 outRect->top = (SInt16)CGRectGetMinY( *inRect ); 197 outRect->left = (SInt16)CGRectGetMinX( *inRect ); 198 outRect->bottom = (SInt16)CGRectGetMaxY( *inRect ); 199 outRect->right = (SInt16)CGRectGetMaxX( *inRect ); 200} 201 202//---------------------------------------------------------------------------------- 203// HIWebViewCreate 204//---------------------------------------------------------------------------------- 205// 206OSStatus 207HIWebViewCreate(HIViewRef* outControl) 208{ 209 HIWebViewRegisterClass(); 210 return HIObjectCreate(kHIWebViewClassID, NULL, (HIObjectRef*)outControl); 211} 212 213//---------------------------------------------------------------------------------- 214// HIWebViewGetWebView 215//---------------------------------------------------------------------------------- 216// 217WebView* 218HIWebViewGetWebView( HIViewRef inView ) 219{ 220 HIWebView* view = (HIWebView*)HIObjectDynamicCast( (HIObjectRef)inView, kHIWebViewClassID ); 221 WebView* result = NULL; 222 223 if ( view ) 224 result = view->fWebView; 225 226 return result; 227} 228 229//---------------------------------------------------------------------------------- 230// HIWebViewConstructor 231//---------------------------------------------------------------------------------- 232// 233 234static HIWebView* 235HIWebViewConstructor( HIViewRef inView ) 236{ 237 HIWebView* view = (HIWebView*)malloc( sizeof( HIWebView ) ); 238 239 if ( view ) 240 { 241 NSRect frame = { { 0, 0 }, { 400, 400 } }; 242 243 view->fViewRef = inView; 244 245 WebView *webView = [[WebView alloc] initWithFrame: frame]; 246 CFRetain(webView); 247 [webView release]; 248 view->fWebView = webView; 249 [HIViewAdapter bindHIViewToNSView:inView nsView:view->fWebView]; 250 251 view->fFirstResponder = NULL; 252 view->fKitWindow = NULL; 253 view->fIsComposited = false; 254 view->fUpdateObserver = NULL; 255 } 256 257 return view; 258} 259 260//---------------------------------------------------------------------------------- 261// HIWebViewDestructor 262//---------------------------------------------------------------------------------- 263// 264static void 265HIWebViewDestructor( HIWebView* inView ) 266{ 267 [HIViewAdapter unbindNSView:inView->fWebView]; 268 CFRelease(inView->fWebView); 269 270 free(inView); 271} 272 273//---------------------------------------------------------------------------------- 274// HIWebViewRegisterClass 275//---------------------------------------------------------------------------------- 276// 277void 278HIWebViewRegisterClass() 279{ 280 static bool sRegistered; 281 282 if ( !sRegistered ) 283 { 284 HIObjectRegisterSubclass( kHIWebViewClassID, kHIViewBaseClassID, 0, HIWebViewEventHandler, 285 GetEventTypeCount( kEvents ), kEvents, 0, NULL ); 286 sRegistered = true; 287 } 288} 289 290//---------------------------------------------------------------------------------- 291// GetBehaviors 292//---------------------------------------------------------------------------------- 293// 294static UInt32 295GetBehaviors() 296{ 297 return kControlSupportsDataAccess | kControlSupportsGetRegion | kControlGetsFocusOnClick; 298} 299 300//---------------------------------------------------------------------------------- 301// Draw 302//---------------------------------------------------------------------------------- 303// 304static void 305Draw( HIWebView* inView, RgnHandle limitRgn, CGContextRef inContext ) 306{ 307 HIRect bounds; 308 Rect drawRect; 309 HIRect hiRect; 310 bool createdContext = false; 311 312 if (!inView->fIsComposited) 313 { 314 GrafPtr port; 315 Rect portRect; 316 317 GetPort( &port ); 318 GetPortBounds( port, &portRect ); 319 CreateCGContextForPort( port, &inContext ); 320 SyncCGContextOriginWithPort( inContext, port ); 321 CGContextTranslateCTM( inContext, 0, (portRect.bottom - portRect.top) ); 322 CGContextScaleCTM( inContext, 1, -1 ); 323 createdContext = true; 324 } 325 326 HIViewGetBounds( inView->fViewRef, &bounds ); 327 328 CGContextRef savedContext = WKNSWindowOverrideCGContext(inView->fKitWindow, inContext); 329 [NSGraphicsContext setCurrentContext:[inView->fKitWindow graphicsContext]]; 330 331 GetRegionBounds( limitRgn, &drawRect ); 332 333 if ( !inView->fIsComposited ) 334 OffsetRect( &drawRect, (SInt16)-bounds.origin.x, (SInt16)-bounds.origin.y ); 335 336 hiRect.origin.x = drawRect.left; 337 hiRect.origin.y = bounds.size.height - drawRect.bottom; // flip y 338 hiRect.size.width = drawRect.right - drawRect.left; 339 hiRect.size.height = drawRect.bottom - drawRect.top; 340 341// printf( "Drawing: drawRect is (%g %g) (%g %g)\n", hiRect.origin.x, hiRect.origin.y, 342// hiRect.size.width, hiRect.size.height ); 343 344 // FIXME: We need to do layout before Carbon has decided what region needs drawn. 345 // In Cocoa we make sure to do layout and invalidate any new regions before draw, so everything 346 // can be drawn in one pass. Doing a layout here will cause new regions to be invalidated, but they 347 // will not all be drawn in this pass since we already have a fixed rect we are going to display. 348 349 NSView <WebDocumentView> *documentView = [[[inView->fWebView mainFrame] frameView] documentView]; 350 if ([documentView isKindOfClass:[WebHTMLView class]]) 351 [(WebHTMLView *)documentView _web_updateLayoutAndStyleIfNeededRecursive]; 352 353 if ( inView->fIsComposited ) 354 [inView->fWebView displayIfNeededInRect: *(NSRect*)&hiRect]; 355 else 356 [inView->fWebView displayRect:*(NSRect*)&hiRect]; 357 358 WKNSWindowRestoreCGContext(inView->fKitWindow, savedContext); 359 360 if ( !inView->fIsComposited ) 361 { 362 HIViewRef view; 363 HIViewFindByID( HIViewGetRoot( GetControlOwner( inView->fViewRef ) ), kHIViewWindowGrowBoxID, &view ); 364 if ( view ) 365 { 366 HIRect frame; 367 368 HIViewGetBounds( view, &frame ); 369 HIViewConvertRect( &frame, view, NULL ); 370 371 hiRect.origin.x = drawRect.left; 372 hiRect.origin.y = drawRect.top; 373 hiRect.size.width = drawRect.right - drawRect.left; 374 hiRect.size.height = drawRect.bottom - drawRect.top; 375 376 HIViewConvertRect( &hiRect, inView->fViewRef, NULL ); 377 378 if ( CGRectIntersectsRect( frame, hiRect ) ) 379 HIViewSetNeedsDisplay( view, true ); 380 } 381 } 382 383 if ( createdContext ) 384 { 385 CGContextSynchronize( inContext ); 386 CGContextRelease( inContext ); 387 } 388} 389 390//---------------------------------------------------------------------------------- 391// HitTest 392//---------------------------------------------------------------------------------- 393// 394static ControlPartCode 395HitTest( HIWebView* view, const HIPoint* where ) 396{ 397 HIRect bounds; 398 399 HIViewGetBounds( view->fViewRef, &bounds ); 400 401 if ( CGRectContainsPoint( bounds, *where ) ) 402 return 1; 403 else 404 return kControlNoPart; 405} 406 407//---------------------------------------------------------------------------------- 408// GetRegion 409//---------------------------------------------------------------------------------- 410// 411static OSStatus 412GetRegion( 413 HIWebView* inView, 414 ControlPartCode inPart, 415 RgnHandle outRgn ) 416{ 417 OSStatus err = eventNotHandledErr; 418 419 if ( inPart == -3 ) // kControlOpaqueMetaPart: 420 { 421 if ( [inView->fWebView isOpaque] ) 422 { 423 HIRect bounds; 424 Rect temp; 425 426 HIViewGetBounds( inView->fViewRef, &bounds ); 427 428 temp.top = (SInt16)bounds.origin.y; 429 temp.left = (SInt16)bounds.origin.x; 430 temp.bottom = (SInt16)CGRectGetMaxY( bounds ); 431 temp.right = (SInt16)CGRectGetMaxX( bounds ); 432 433 RectRgn( outRgn, &temp ); 434 err = noErr; 435 } 436 } 437 438 return err; 439} 440 441static WindowRef 442GetWindowRef( HIWebView* inView ) 443{ 444 return GetControlOwner( inView->fViewRef ); 445} 446 447//---------------------------------------------------------------------------------- 448// Click 449//---------------------------------------------------------------------------------- 450// 451static OSStatus 452Click(HIWebView* inView, EventRef inEvent) 453{ 454 NSEvent *kitEvent = WKCreateNSEventWithCarbonClickEvent(inEvent, GetWindowRef(inView)); 455 456 if (!inView->fIsComposited) 457 StartUpdateObserver(inView); 458 459 [inView->fKitWindow sendEvent:kitEvent]; 460 461 if (!inView->fIsComposited) 462 StopUpdateObserver(inView); 463 464 [kitEvent release]; 465 466 return noErr; 467} 468 469//---------------------------------------------------------------------------------- 470// MouseUp 471//---------------------------------------------------------------------------------- 472// 473static OSStatus 474MouseUp( HIWebView* inView, EventRef inEvent ) 475{ 476 NSEvent* kitEvent = WKCreateNSEventWithCarbonEvent(inEvent); 477 478 [inView->fKitWindow sendEvent:kitEvent]; 479 480 [kitEvent release]; 481 482 return noErr; 483} 484 485//---------------------------------------------------------------------------------- 486// MouseMoved 487//---------------------------------------------------------------------------------- 488// 489static OSStatus 490MouseMoved( HIWebView* inView, EventRef inEvent ) 491{ 492 NSEvent *kitEvent = WKCreateNSEventWithCarbonMouseMoveEvent(inEvent, inView->fKitWindow); 493 [inView->fKitWindow sendEvent:kitEvent]; 494 [kitEvent release]; 495 496 return noErr; 497} 498 499//---------------------------------------------------------------------------------- 500// MouseDragged 501//---------------------------------------------------------------------------------- 502// 503static OSStatus 504MouseDragged( HIWebView* inView, EventRef inEvent ) 505{ 506 NSEvent* kitEvent = WKCreateNSEventWithCarbonEvent(inEvent); 507 508 [inView->fKitWindow sendEvent:kitEvent]; 509 510 [kitEvent release]; 511 512 return noErr; 513} 514 515//---------------------------------------------------------------------------------- 516// MouseDragged 517//---------------------------------------------------------------------------------- 518// 519static OSStatus 520MouseWheelMoved( HIWebView* inView, EventRef inEvent ) 521{ 522 NSEvent* kitEvent = WKCreateNSEventWithCarbonEvent(inEvent); 523 524 [inView->fKitWindow sendEvent:kitEvent]; 525 526 [kitEvent release]; 527 528 return noErr; 529} 530 531//---------------------------------------------------------------------------------- 532// ContextMenuClick 533//---------------------------------------------------------------------------------- 534// 535static OSStatus 536ContextMenuClick( HIWebView* inView, EventRef inEvent ) 537{ 538 NSView *webView = inView->fWebView; 539 NSWindow *window = [webView window]; 540 541 // Get the point out of the event. 542 HIPoint point; 543 GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(point), NULL, &point); 544 HIViewConvertPoint(&point, inView->fViewRef, NULL); 545 546 // Flip the Y coordinate, since Carbon is flipped relative to the AppKit. 547 NSPoint location = NSMakePoint(point.x, [window frame].size.height - point.y); 548 549 // Make up an event with the point and send it to the window. 550 NSEvent *kitEvent = [NSEvent mouseEventWithType:NSRightMouseDown 551 location:location 552 modifierFlags:0 553 timestamp:GetEventTime(inEvent) 554 windowNumber:[window windowNumber] 555 context:0 556 eventNumber:0 557 clickCount:1 558 pressure:0]; 559 [inView->fKitWindow sendEvent:kitEvent]; 560 return noErr; 561} 562 563//---------------------------------------------------------------------------------- 564// GetKind 565//---------------------------------------------------------------------------------- 566// 567static ControlKind 568GetKind() 569{ 570 const ControlKind kMyKind = { 'appl', 'wbvw' }; 571 572 return kMyKind; 573} 574 575//---------------------------------------------------------------------------------- 576// BoundsChanged 577//---------------------------------------------------------------------------------- 578// 579static void 580BoundsChanged( 581 HIWebView* inView, 582 UInt32 inOptions, 583 const HIRect* inOriginalBounds, 584 const HIRect* inCurrentBounds ) 585{ 586 if ( inView->fWebView ) 587 { 588 SyncFrame( inView ); 589 } 590} 591 592//---------------------------------------------------------------------------------- 593// OwningWindowChanged 594//---------------------------------------------------------------------------------- 595// 596static void 597OwningWindowChanged( 598 HIWebView* view, 599 WindowRef oldWindow, 600 WindowRef newWindow ) 601{ 602 if ( newWindow ){ 603 WindowAttributes attrs; 604 605 OSStatus err = GetWindowProperty(newWindow, NSAppKitPropertyCreator, NSCarbonWindowPropertyTag, sizeof(NSWindow *), NULL, &view->fKitWindow); 606 if ( err != noErr ) 607 { 608 const EventTypeSpec kWindowEvents[] = { 609 { kEventClassWindow, kEventWindowClosed }, 610 { kEventClassMouse, kEventMouseMoved }, 611 { kEventClassMouse, kEventMouseUp }, 612 { kEventClassMouse, kEventMouseDragged }, 613 { kEventClassMouse, kEventMouseWheelMoved }, 614 { kEventClassKeyboard, kEventRawKeyDown }, 615 { kEventClassKeyboard, kEventRawKeyRepeat }, 616 { kEventClassKeyboard, kEventRawKeyUp }, 617 { kEventClassControl, kEventControlClick }, 618 }; 619 620 view->fKitWindow = [[CarbonWindowAdapter alloc] initWithCarbonWindowRef: newWindow takingOwnership: NO disableOrdering:NO carbon:YES]; 621 SetWindowProperty(newWindow, NSAppKitPropertyCreator, NSCarbonWindowPropertyTag, sizeof(NSWindow *), &view->fKitWindow); 622 623 InstallWindowEventHandler( newWindow, WindowHandler, GetEventTypeCount( kWindowEvents ), kWindowEvents, newWindow, NULL ); 624 } 625 626 [[view->fKitWindow contentView] addSubview:view->fWebView]; 627 628 GetWindowAttributes( newWindow, &attrs ); 629 view->fIsComposited = ( ( attrs & kWindowCompositingAttribute ) != 0 ); 630 631 SyncFrame( view ); 632 } 633 else 634 { 635 // Be sure to detach the cocoa view, too. 636 if ( view->fWebView ) 637 [view->fWebView removeFromSuperview]; 638 639 view->fKitWindow = NULL; // break the ties that bind 640 } 641} 642 643//------------------------------------------------------------------------------------- 644// WindowHandler 645//------------------------------------------------------------------------------------- 646// Redirect mouse events to the views beneath them. This is required for WebKit to work 647// properly. We install it once per window. We also tap into window close to release 648// the NSWindow that shadows our Carbon window. 649// 650static OSStatus 651WindowHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ) 652{ 653 WindowRef window = (WindowRef)inUserData; 654 OSStatus result = eventNotHandledErr; 655 656 switch( GetEventClass( inEvent ) ) 657 { 658 case kEventClassControl: 659 { 660 switch( GetEventKind( inEvent ) ) 661 { 662 case kEventControlClick: 663 { 664 CarbonWindowAdapter *kitWindow; 665 OSStatus err; 666 667 err = GetWindowProperty( window, NSAppKitPropertyCreator, NSCarbonWindowPropertyTag, sizeof(NSWindow *), NULL, &kitWindow); 668 669 // We must be outside the HIWebView, relinquish focus. 670 [kitWindow relinquishFocus]; 671 } 672 break; 673 } 674 } 675 break; 676 677 case kEventClassKeyboard: 678 { 679 NSWindow* kitWindow; 680 OSStatus err; 681 NSEvent* kitEvent; 682 683 // if the first responder in the kit window is something other than the 684 // window, we assume a subview of the webview is focused. we must send 685 // the event to the window so that it goes through the kit's normal TSM 686 // logic, and -- more importantly -- allows any delegates associated 687 // with the first responder to have a chance at the event. 688 689 err = GetWindowProperty( window, NSAppKitPropertyCreator, NSCarbonWindowPropertyTag, sizeof(NSWindow *), NULL, &kitWindow); 690 if ( err == noErr ) 691 { 692 NSResponder* responder = [kitWindow firstResponder]; 693 if ( responder != kitWindow ) 694 { 695 kitEvent = WKCreateNSEventWithCarbonEvent(inEvent); 696 697 [kitWindow sendEvent:kitEvent]; 698 [kitEvent release]; 699 700 result = noErr; 701 } 702 } 703 } 704 break; 705 706 case kEventClassWindow: 707 { 708 NSWindow* kitWindow; 709 OSStatus err; 710 711 err = GetWindowProperty( window, NSAppKitPropertyCreator, NSCarbonWindowPropertyTag, sizeof(NSWindow *), NULL, &kitWindow); 712 if ( err == noErr ) 713 { 714 [kitWindow _removeWindowRef]; 715 [kitWindow close]; 716 } 717 718 result = noErr; 719 } 720 break; 721 722 case kEventClassMouse: 723 switch (GetEventKind(inEvent)) 724 { 725 case kEventMouseMoved: 726 { 727 Point where; 728 GetEventParameter(inEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &where); 729 730 WindowRef temp; 731 FindWindow(where, &temp); 732 if (temp == window) 733 { 734 Rect bounds; 735 GetWindowBounds(window, kWindowStructureRgn, &bounds); 736 where.h -= bounds.left; 737 where.v -= bounds.top; 738 SetEventParameter(inEvent, kEventParamWindowRef, typeWindowRef, sizeof(WindowRef), &window); 739 SetEventParameter(inEvent, kEventParamWindowMouseLocation, typeQDPoint, sizeof(Point), &where); 740 741 OSStatus err = noErr; 742 HIViewRef view = NULL; 743 744 err = HIViewGetViewForMouseEvent(HIViewGetRoot(window), inEvent, &view); 745 if (err == noErr && view && HIObjectIsOfClass((HIObjectRef)view, kHIWebViewClassID)) 746 result = SendEventToEventTargetWithOptions(inEvent, HIObjectGetEventTarget((HIObjectRef)view), kEventTargetDontPropagate); 747 } 748 } 749 break; 750 751 case kEventMouseUp: 752 case kEventMouseDragged: 753 case kEventMouseWheelMoved: 754 { 755 OSStatus err = noErr; 756 HIViewRef view = NULL; 757 758 err = HIViewGetViewForMouseEvent(HIViewGetRoot(window), inEvent, &view); 759 if (err == noErr && view && HIObjectIsOfClass((HIObjectRef)view, kHIWebViewClassID)) 760 result = SendEventToEventTargetWithOptions(inEvent, HIObjectGetEventTarget((HIObjectRef)view), kEventTargetDontPropagate); 761 } 762 break; 763 } 764 break; 765 } 766 767 return result; 768} 769 770 771//---------------------------------------------------------------------------------- 772// SyncFrame 773//---------------------------------------------------------------------------------- 774// 775static void 776SyncFrame( HIWebView* inView ) 777{ 778 HIViewRef parent = HIViewGetSuperview( inView->fViewRef ); 779 780 if ( parent ) 781 { 782 if ( inView->fIsComposited ) 783 { 784 HIRect frame; 785 HIRect parentBounds; 786 NSPoint origin; 787 788 HIViewGetFrame( inView->fViewRef, &frame ); 789 HIViewGetBounds( parent, &parentBounds ); 790 791 origin.x = frame.origin.x; 792 origin.y = parentBounds.size.height - CGRectGetMaxY( frame ); 793// printf( "syncing to (%g %g) (%g %g)\n", origin.x, origin.y, 794// frame.size.width, frame.size.height ); 795 [inView->fWebView setFrameOrigin: origin]; 796 [inView->fWebView setFrameSize: *(NSSize*)&frame.size]; 797 } 798 else 799 { 800 GrafPtr port = GetWindowPort( GetControlOwner( inView->fViewRef ) ); 801 PixMapHandle portPix = GetPortPixMap( port ); 802 Rect bounds; 803 HIRect rootFrame; 804 HIRect frame; 805 806 GetControlBounds( inView->fViewRef, &bounds ); 807 OffsetRect( &bounds, -(**portPix).bounds.left, -(**portPix).bounds.top ); 808 809// printf( "control lives at %d %d %d %d in window-coords\n", bounds.top, bounds.left, 810// bounds.bottom, bounds.right ); 811 812 HIViewGetFrame( HIViewGetRoot( GetControlOwner( inView->fViewRef ) ), &rootFrame ); 813 814 frame.origin.x = bounds.left; 815 frame.origin.y = rootFrame.size.height - bounds.bottom; 816 frame.size.width = bounds.right - bounds.left; 817 frame.size.height = bounds.bottom - bounds.top; 818 819// printf( " before frame convert (%g %g) (%g %g)\n", frame.origin.x, frame.origin.y, 820// frame.size.width, frame.size.height ); 821 822 [inView->fWebView convertRect:*(NSRect*)&frame fromView:nil]; 823 824// printf( " moving web view to (%g %g) (%g %g)\n", frame.origin.x, frame.origin.y, 825// frame.size.width, frame.size.height ); 826 827 [inView->fWebView setFrameOrigin: *(NSPoint*)&frame.origin]; 828 [inView->fWebView setFrameSize: *(NSSize*)&frame.size]; 829 } 830 } 831} 832 833//---------------------------------------------------------------------------------- 834// SetFocusPart 835//---------------------------------------------------------------------------------- 836// 837static OSStatus 838SetFocusPart( 839 HIWebView* view, 840 ControlPartCode desiredFocus, 841 RgnHandle invalidRgn, 842 Boolean focusEverything, 843 ControlPartCode* actualFocus ) 844{ 845 NSView * freshlyMadeFirstResponderView; 846 SInt32 partCodeToReturn; 847 848 // Do what Carbon is telling us to do. 849 if ( desiredFocus == kControlFocusNoPart ) 850 { 851 // Relinquish the keyboard focus. 852 RelinquishFocus( view, true ); //(autodisplay ? YES : NO)); 853 freshlyMadeFirstResponderView = nil; 854 partCodeToReturn = kControlFocusNoPart; 855 //NSLog(@"Relinquished the key focus because we have no choice."); 856 } 857 else if ( desiredFocus == kControlFocusNextPart || desiredFocus == kControlFocusPrevPart ) 858 { 859 BOOL goForward = (desiredFocus == kControlFocusNextPart ); 860 861 // Advance the keyboard focus, maybe right off of this view. Maybe a subview of this one already has the keyboard focus, maybe not. 862 freshlyMadeFirstResponderView = AdvanceFocus( view, goForward ); 863 if (freshlyMadeFirstResponderView) 864 partCodeToReturn = desiredFocus; 865 else 866 partCodeToReturn = kControlFocusNoPart; 867 //NSLog(freshlyMadeFirstResponderView ? @"Advanced the key focus." : @"Relinquished the key focus."); 868 } 869 else 870 { 871 // What's this? 872 if (desiredFocus != kControlIndicatorPart) { 873 check(false); 874 } 875 freshlyMadeFirstResponderView = nil; 876 partCodeToReturn = desiredFocus; 877 } 878 879 view->fFirstResponder = freshlyMadeFirstResponderView; 880 881 *actualFocus = partCodeToReturn; 882 883 // Done. 884 return noErr; 885} 886 887//---------------------------------------------------------------------------------- 888// AdvanceFocus 889//---------------------------------------------------------------------------------- 890// 891static NSView* 892AdvanceFocus( HIWebView* view, bool forward ) 893{ 894 NSResponder* oldFirstResponder; 895 NSView* currentKeyView; 896 NSView* viewWeMadeFirstResponder; 897 898 // Focus on some part (subview) of this control (view). Maybe 899 // a subview of this one already has the keyboard focus, maybe not. 900 901 oldFirstResponder = [view->fKitWindow firstResponder]; 902 903 // If we tab out of our NSView, it will no longer be the responder 904 // when we get here. We'll try this trick for now. We might need to 905 // tag the view appropriately. 906 907 if ( view->fFirstResponder && ( (NSResponder*)view->fFirstResponder != oldFirstResponder ) ) 908 { 909 return NULL; 910 } 911 912 if ( [oldFirstResponder isKindOfClass:[NSView class]] ) 913 { 914 NSView* tentativeNewKeyView; 915 916 // Some view in this window already has the keyboard focus. It better at least be a subview of this one. 917 NSView* oldFirstResponderView = (NSView *)oldFirstResponder; 918 check( [oldFirstResponderView isDescendantOf:view->fWebView] ); 919 920 if ( oldFirstResponderView != view->fFirstResponder 921 && ![oldFirstResponderView isDescendantOf:view->fFirstResponder] ) 922 { 923 // Despite our efforts to record what view we made the first responder 924 // (for use in the next paragraph) we couldn't keep up because the user 925 // has clicked in a text field to make it the key focus, instead of using 926 // the tab key. Find a control on which it's reasonable to invoke 927 // -[NSView nextValidKeyView], taking into account the fact that 928 // NSTextFields always pass on first-respondership to a temporarily- 929 // contained NSTextView. 930 931 NSView *viewBeingTested; 932 currentKeyView = oldFirstResponderView; 933 viewBeingTested = currentKeyView; 934 while ( viewBeingTested != view->fWebView ) 935 { 936 if ( [viewBeingTested isKindOfClass:[NSTextField class]] ) 937 { 938 currentKeyView = viewBeingTested; 939 break; 940 } 941 else 942 { 943 viewBeingTested = [viewBeingTested superview]; 944 } 945 } 946 } 947 else 948 { 949 // We recorded which view we made into the first responder the 950 // last time the user hit the tab key, and nothing has invalidated 951 // our recorded value since. 952 953 currentKeyView = view->fFirstResponder; 954 } 955 956 // Try to move on to the next or previous key view. We use the laboriously 957 // recorded/figured currentKeyView instead of just oldFirstResponder as the 958 // jumping-off-point when searching for the next valid key view. This is so 959 // we don't get fooled if we recently made some view the first responder, but 960 // it passed on first-responder-ness to some temporary subview. 961 962 // You can't put normal views in a window with Carbon-control-wrapped views. 963 // Stuff like this would break. M.P. Notice - 12/2/00 964 965 tentativeNewKeyView = forward ? [currentKeyView nextValidKeyView] : [currentKeyView previousValidKeyView]; 966 if ( tentativeNewKeyView && [tentativeNewKeyView isDescendantOf:view->fWebView] ) 967 { 968 // The user has tabbed to another subview of this control view. Change the keyboard focus. 969 //NSLog(@"Tabbed to the next or previous key view."); 970 971 [view->fKitWindow makeFirstResponder:tentativeNewKeyView]; 972 viewWeMadeFirstResponder = tentativeNewKeyView; 973 } 974 else 975 { 976 // The user has tabbed past the subviews of this control view. The window is the first responder now. 977 //NSLog(@"Tabbed past the first or last key view."); 978 [view->fKitWindow makeFirstResponder:view->fKitWindow]; 979 viewWeMadeFirstResponder = nil; 980 } 981 } 982 else 983 { 984 // No view in this window has the keyboard focus. This view should 985 // try to select one of its key subviews. We're not interested in 986 // the subviews of sibling views here. 987 988 //NSLog(@"No keyboard focus in window. Attempting to set..."); 989 990 NSView *tentativeNewKeyView; 991 check(oldFirstResponder==fKitWindow); 992 if ( [view->fWebView acceptsFirstResponder] ) 993 tentativeNewKeyView = view->fWebView; 994 else 995 tentativeNewKeyView = [view->fWebView nextValidKeyView]; 996 if ( tentativeNewKeyView && [tentativeNewKeyView isDescendantOf:view->fWebView] ) 997 { 998 // This control view has at least one subview that can take the keyboard focus. 999 if ( !forward ) 1000 { 1001 // The user has tabbed into this control view backwards. Find 1002 // and select the last subview of this one that can take the 1003 // keyboard focus. Watch out for loops of valid key views. 1004 1005 NSView *firstTentativeNewKeyView = tentativeNewKeyView; 1006 NSView *nextTentativeNewKeyView = [tentativeNewKeyView nextValidKeyView]; 1007 while ( nextTentativeNewKeyView 1008 && [nextTentativeNewKeyView isDescendantOf:view->fWebView] 1009 && nextTentativeNewKeyView!=firstTentativeNewKeyView) 1010 { 1011 tentativeNewKeyView = nextTentativeNewKeyView; 1012 nextTentativeNewKeyView = [tentativeNewKeyView nextValidKeyView]; 1013 } 1014 1015 } 1016 1017 // Set the keyboard focus. 1018 //NSLog(@"Tabbed into the first or last key view."); 1019 [view->fKitWindow makeFirstResponder:tentativeNewKeyView]; 1020 viewWeMadeFirstResponder = tentativeNewKeyView; 1021 } 1022 else 1023 { 1024 // This control view has no subviews that can take the keyboard focus. 1025 //NSLog(@"Can't tab into this view."); 1026 viewWeMadeFirstResponder = nil; 1027 } 1028 } 1029 1030 // Done. 1031 return viewWeMadeFirstResponder; 1032} 1033 1034 1035//---------------------------------------------------------------------------------- 1036// RelinquishFocus 1037//---------------------------------------------------------------------------------- 1038// 1039static void 1040RelinquishFocus( HIWebView* view, bool inAutodisplay ) 1041{ 1042 NSResponder* firstResponder; 1043 1044 // Apparently Carbon thinks that some subview of this control view has the keyboard focus, 1045 // or we wouldn't be being asked to relinquish focus. 1046 1047 firstResponder = [view->fKitWindow firstResponder]; 1048 if ( [firstResponder isKindOfClass:[NSView class]] ) 1049 { 1050 // Some subview of this control view really is the first responder right now. 1051 check( [(NSView *)firstResponder isDescendantOf:view->fWebView] ); 1052 1053 // Make the window the first responder, so that no view is the key view. 1054 [view->fKitWindow makeFirstResponder:view->fKitWindow]; 1055 1056 // If this control is not allowed to do autodisplay, don't let 1057 // it autodisplay any just-changed focus rings or text on the 1058 // next go around the event loop. I'm probably clearing more 1059 // dirty rects than I have to, but it doesn't seem to hurt in 1060 // the print panel accessory view case, and I don't have time 1061 // to figure out exactly what -[NSCell _setKeyboardFocusRingNeedsDisplay] 1062 // is doing when invoked indirectly from -makeFirstResponder up above. M.P. Notice - 12/4/00 1063 1064 if ( !inAutodisplay ) 1065 [[view->fWebView opaqueAncestor] _clearDirtyRectsForTree]; 1066 } 1067 else 1068 { 1069 // The Cocoa first responder does not correspond to the Carbon 1070 // control that has the keyboard focus. This can happen when 1071 // you've closed a dialog by hitting return in an NSTextView 1072 // that's a subview of this one; Cocoa closed the window, and 1073 // now Carbon is telling this control to relinquish the focus 1074 // as it's being disposed. There's nothing to do. 1075 1076 check(firstResponder==window); 1077 } 1078} 1079 1080//---------------------------------------------------------------------------------- 1081// ActiveStateChanged 1082//---------------------------------------------------------------------------------- 1083// 1084static void 1085ActiveStateChanged( HIWebView* view ) 1086{ 1087 if ( [view->fWebView respondsToSelector:@selector(setEnabled)] ) 1088 { 1089 [(NSControl*)view->fWebView setEnabled: IsControlEnabled( view->fViewRef )]; 1090 HIViewSetNeedsDisplay( view->fViewRef, true ); 1091 } 1092} 1093 1094 1095//---------------------------------------------------------------------------------- 1096// ProcessCommand 1097//---------------------------------------------------------------------------------- 1098// 1099static OSStatus 1100ProcessCommand( HIWebView* inView, const HICommand* inCommand ) 1101{ 1102 OSStatus result = eventNotHandledErr; 1103 NSResponder* resp; 1104 1105 resp = [inView->fKitWindow firstResponder]; 1106 1107 if ( [resp isKindOfClass:[NSView class]] ) 1108 { 1109 NSView* respView = (NSView*)resp; 1110 1111 if ( respView == inView->fWebView 1112 || [respView isDescendantOf: inView->fWebView] ) 1113 { 1114 switch ( inCommand->commandID ) 1115 { 1116 case kHICommandCut: 1117 case kHICommandCopy: 1118 case kHICommandPaste: 1119 case kHICommandClear: 1120 case kHICommandSelectAll: 1121 { 1122 SEL selector = _NSSelectorForHICommand( inCommand ); 1123 if ( [respView respondsToSelector:selector] ) 1124 { 1125 [respView performSelector:selector withObject:nil]; 1126 result = noErr; 1127 } 1128 } 1129 break; 1130 } 1131 } 1132 } 1133 1134 return result; 1135} 1136 1137//---------------------------------------------------------------------------------- 1138// UpdateCommandStatus 1139//---------------------------------------------------------------------------------- 1140// 1141static OSStatus 1142UpdateCommandStatus( HIWebView* inView, const HICommand* inCommand ) 1143{ 1144 OSStatus result = eventNotHandledErr; 1145 MenuItemProxy* proxy = NULL; 1146 NSResponder* resp; 1147 1148 resp = [inView->fKitWindow firstResponder]; 1149 1150 if ( [resp isKindOfClass:[NSView class]] ) 1151 { 1152 NSView* respView = (NSView*)resp; 1153 1154 if ( respView == inView->fWebView 1155 || [respView isDescendantOf: inView->fWebView] ) 1156 { 1157 if ( inCommand->attributes & kHICommandFromMenu ) 1158 { 1159 SEL selector = _NSSelectorForHICommand( inCommand ); 1160 1161 if ( selector ) 1162 { 1163 if ( [resp respondsToSelector: selector] ) 1164 { 1165 proxy = [[MenuItemProxy alloc] initWithAction: selector]; 1166 1167 // Can't use -performSelector:withObject: here because the method we're calling returns BOOL, while 1168 // -performSelector:withObject:'s return value is assumed to be an id. 1169 if (wtfObjcMsgSend<BOOL>(resp, @selector(validateUserInterfaceItem:), proxy)) 1170 EnableMenuItem( inCommand->menu.menuRef, inCommand->menu.menuItemIndex ); 1171 else 1172 DisableMenuItem( inCommand->menu.menuRef, inCommand->menu.menuItemIndex ); 1173 1174 result = noErr; 1175 } 1176 } 1177 } 1178 } 1179 } 1180 1181 if ( proxy ) 1182 [proxy release]; 1183 1184 return result; 1185} 1186 1187// Blatantly stolen from AppKit and cropped a bit 1188 1189//---------------------------------------------------------------------------------- 1190// _NSSelectorForHICommand 1191//---------------------------------------------------------------------------------- 1192// 1193static SEL 1194_NSSelectorForHICommand( const HICommand* inCommand ) 1195{ 1196 switch ( inCommand->commandID ) 1197 { 1198 case kHICommandUndo: return @selector(undo:); 1199 case kHICommandRedo: return @selector(redo:); 1200 case kHICommandCut : return @selector(cut:); 1201 case kHICommandCopy : return @selector(copy:); 1202 case kHICommandPaste: return @selector(paste:); 1203 case kHICommandClear: return @selector(delete:); 1204 case kHICommandSelectAll: return @selector(selectAll:); 1205 default: return NULL; 1206 } 1207 1208 return NULL; 1209} 1210 1211 1212//----------------------------------------------------------------------------------- 1213// HIWebViewEventHandler 1214//----------------------------------------------------------------------------------- 1215// Our object's virtual event handler method. I'm not sure if we need this these days. 1216// We used to do various things with it, but those days are long gone... 1217// 1218static OSStatus 1219HIWebViewEventHandler( 1220 EventHandlerCallRef inCallRef, 1221 EventRef inEvent, 1222 void * inUserData ) 1223{ 1224 OSStatus result = eventNotHandledErr; 1225 HIPoint where; 1226 OSType tag; 1227 void * ptr; 1228 Size size; 1229 UInt32 features; 1230 RgnHandle region = NULL; 1231 ControlPartCode part; 1232 HIWebView* view = (HIWebView*)inUserData; 1233 1234 // [NSApp setWindowsNeedUpdate:YES] must be called before events so that ActivateTSMDocument is called to set an active document. 1235 // Without an active document, TSM will use a default document which uses a bottom-line input window which we don't want. 1236 [NSApp setWindowsNeedUpdate:YES]; 1237 1238 switch ( GetEventClass( inEvent ) ) 1239 { 1240 case kEventClassHIObject: 1241 switch ( GetEventKind( inEvent ) ) 1242 { 1243 case kEventHIObjectConstruct: 1244 { 1245 HIObjectRef object; 1246 1247 result = GetEventParameter( inEvent, kEventParamHIObjectInstance, 1248 typeHIObjectRef, NULL, sizeof( HIObjectRef ), NULL, &object ); 1249 require_noerr( result, MissingParameter ); 1250 1251 // on entry for our construct event, we're passed the 1252 // creation proc we registered with for this class. 1253 // we use it now to create the instance, and then we 1254 // replace the instance parameter data with said instance 1255 // as type void. 1256 1257 view = HIWebViewConstructor( (HIViewRef)object ); 1258 1259 if ( view ) 1260 { 1261 SetEventParameter( inEvent, kEventParamHIObjectInstance, 1262 typeVoidPtr, sizeof( void * ), &view ); 1263 } 1264 } 1265 break; 1266 1267 case kEventHIObjectDestruct: 1268 HIWebViewDestructor( view ); 1269 // result is unimportant 1270 break; 1271 } 1272 break; 1273 1274 case kEventClassKeyboard: 1275 { 1276 NSEvent* kitEvent = WKCreateNSEventWithCarbonEvent(inEvent); 1277 [view->fKitWindow sendSuperEvent:kitEvent]; 1278 [kitEvent release]; 1279 result = noErr; 1280 } 1281 break; 1282 1283 case kEventClassMouse: 1284 switch ( GetEventKind( inEvent ) ) 1285 { 1286 case kEventMouseUp: 1287 result = MouseUp( view, inEvent ); 1288 break; 1289 1290 case kEventMouseWheelMoved: 1291 result = MouseWheelMoved( view, inEvent ); 1292 break; 1293 1294 case kEventMouseMoved: 1295 result = MouseMoved( view, inEvent ); 1296 break; 1297 1298 case kEventMouseDragged: 1299 result = MouseDragged( view, inEvent ); 1300 break; 1301 } 1302 break; 1303 1304 case kEventClassCommand: 1305 { 1306 HICommand command; 1307 1308 result = GetEventParameter( inEvent, kEventParamDirectObject, typeHICommand, NULL, 1309 sizeof( HICommand ), NULL, &command ); 1310 require_noerr( result, MissingParameter ); 1311 1312 switch ( GetEventKind( inEvent ) ) 1313 { 1314 case kEventCommandProcess: 1315 result = ProcessCommand( view, &command ); 1316 break; 1317 1318 case kEventCommandUpdateStatus: 1319 result = UpdateCommandStatus( view, &command ); 1320 break; 1321 } 1322 } 1323 break; 1324 1325 case kEventClassControl: 1326 switch ( GetEventKind( inEvent ) ) 1327 { 1328 case kEventControlInitialize: 1329 features = GetBehaviors(); 1330 SetEventParameter( inEvent, kEventParamControlFeatures, typeUInt32, 1331 sizeof( UInt32 ), &features ); 1332 result = noErr; 1333 break; 1334 1335 case kEventControlDraw: 1336 { 1337 CGContextRef context = NULL; 1338 1339 GetEventParameter( inEvent, kEventParamRgnHandle, typeQDRgnHandle, NULL, 1340 sizeof( RgnHandle ), NULL, ®ion ); 1341 GetEventParameter( inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, 1342 sizeof( CGContextRef ), NULL, &context ); 1343 1344 Draw( view, region, context ); 1345 1346 result = noErr; 1347 } 1348 break; 1349 1350 case kEventControlHitTest: 1351 GetEventParameter( inEvent, kEventParamMouseLocation, typeHIPoint, NULL, 1352 sizeof( HIPoint ), NULL, &where ); 1353 part = HitTest( view, &where ); 1354 SetEventParameter( inEvent, kEventParamControlPart, typeControlPartCode, sizeof( ControlPartCode ), &part ); 1355 result = noErr; 1356 break; 1357 1358 case kEventControlGetPartRegion: 1359 GetEventParameter( inEvent, kEventParamControlPart, typeControlPartCode, NULL, 1360 sizeof( ControlPartCode ), NULL, &part ); 1361 GetEventParameter( inEvent, kEventParamControlRegion, typeQDRgnHandle, NULL, 1362 sizeof( RgnHandle ), NULL, ®ion ); 1363 result = GetRegion( view, part, region ); 1364 break; 1365 1366 case kEventControlGetData: 1367 GetEventParameter(inEvent, kEventParamControlPart, typeControlPartCode, NULL, sizeof(ControlPartCode), NULL, &part); 1368 GetEventParameter(inEvent, kEventParamControlDataTag, typeEnumeration, NULL, sizeof(OSType), NULL, &tag); 1369 GetEventParameter(inEvent, kEventParamControlDataBuffer, typePtr, NULL, sizeof(Ptr), NULL, &ptr); 1370 GetEventParameter(inEvent, kEventParamControlDataBufferSize, typeByteCount, NULL, sizeof(Size), NULL, &size); 1371 1372 if (tag == kControlKindTag) { 1373 Size outSize; 1374 result = noErr; 1375 1376 if (ptr) { 1377 if (size != sizeof(ControlKind)) 1378 result = errDataSizeMismatch; 1379 else 1380 (*(ControlKind *)ptr) = GetKind(); 1381 } 1382 1383 outSize = sizeof(ControlKind); 1384 SetEventParameter(inEvent, kEventParamControlDataBufferSize, typeByteCount, sizeof(Size), &outSize); 1385 } 1386 1387 break; 1388 1389 case kEventControlBoundsChanged: 1390 { 1391 HIRect prevRect, currRect; 1392 UInt32 attrs; 1393 1394 GetEventParameter( inEvent, kEventParamAttributes, typeUInt32, NULL, 1395 sizeof( UInt32 ), NULL, &attrs ); 1396 GetEventParameter( inEvent, kEventParamOriginalBounds, typeHIRect, NULL, 1397 sizeof( HIRect ), NULL, &prevRect ); 1398 GetEventParameter( inEvent, kEventParamCurrentBounds, typeHIRect, NULL, 1399 sizeof( HIRect ), NULL, &currRect ); 1400 1401 BoundsChanged( view, attrs, &prevRect, &currRect ); 1402 result = noErr; 1403 } 1404 break; 1405 1406 case kEventControlActivate: 1407 ActiveStateChanged( view ); 1408 result = noErr; 1409 break; 1410 1411 case kEventControlDeactivate: 1412 ActiveStateChanged( view ); 1413 result = noErr; 1414 break; 1415 1416 case kEventControlOwningWindowChanged: 1417 { 1418 WindowRef fromWindow, toWindow; 1419 1420 result = GetEventParameter( inEvent, kEventParamControlOriginalOwningWindow, typeWindowRef, NULL, 1421 sizeof( WindowRef ), NULL, &fromWindow ); 1422 require_noerr( result, MissingParameter ); 1423 1424 result = GetEventParameter( inEvent, kEventParamControlCurrentOwningWindow, typeWindowRef, NULL, 1425 sizeof( WindowRef ), NULL, &toWindow ); 1426 require_noerr( result, MissingParameter ); 1427 1428 OwningWindowChanged( view, fromWindow, toWindow ); 1429 1430 result = noErr; 1431 } 1432 break; 1433 1434 case kEventControlClick: 1435 result = Click( view, inEvent ); 1436 break; 1437 1438 case kEventControlContextualMenuClick: 1439 result = ContextMenuClick( view, inEvent ); 1440 break; 1441 1442 case kEventControlSetFocusPart: 1443 { 1444 ControlPartCode desiredFocus; 1445 RgnHandle invalidRgn; 1446 Boolean focusEverything; 1447 ControlPartCode actualFocus; 1448 1449 result = GetEventParameter( inEvent, kEventParamControlPart, typeControlPartCode, NULL, 1450 sizeof( ControlPartCode ), NULL, &desiredFocus ); 1451 require_noerr( result, MissingParameter ); 1452 1453 GetEventParameter( inEvent, kEventParamControlInvalRgn, typeQDRgnHandle, NULL, 1454 sizeof( RgnHandle ), NULL, &invalidRgn ); 1455 1456 focusEverything = false; // a good default in case the parameter doesn't exist 1457 1458 GetEventParameter( inEvent, kEventParamControlFocusEverything, typeBoolean, NULL, 1459 sizeof( Boolean ), NULL, &focusEverything ); 1460 1461 result = SetFocusPart( view, desiredFocus, invalidRgn, focusEverything, &actualFocus ); 1462 1463 if ( result == noErr ) 1464 verify_noerr( SetEventParameter( inEvent, kEventParamControlPart, typeControlPartCode, 1465 sizeof( ControlPartCode ), &actualFocus ) ); 1466 } 1467 break; 1468 1469 // some other kind of Control event 1470 default: 1471 break; 1472 } 1473 break; 1474 1475 // some other event class 1476 default: 1477 break; 1478 } 1479 1480MissingParameter: 1481 return result; 1482} 1483 1484 1485static void UpdateObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); 1486 1487static void 1488StartUpdateObserver( HIWebView* view ) 1489{ 1490 CFRunLoopObserverContext context; 1491 CFRunLoopObserverRef observer; 1492 CFRunLoopRef mainRunLoop; 1493 1494 check( view->fIsComposited == false ); 1495 check( view->fUpdateObserver == NULL ); 1496 1497 context.version = 0; 1498 context.info = view; 1499 context.retain = NULL; 1500 context.release = NULL; 1501 context.copyDescription = NULL; 1502 1503 mainRunLoop = (CFRunLoopRef)GetCFRunLoopFromEventLoop( GetMainEventLoop() ); 1504 observer = CFRunLoopObserverCreate( NULL, kCFRunLoopEntry | kCFRunLoopBeforeWaiting, true, 0, UpdateObserver, &context ); 1505 CFRunLoopAddObserver( mainRunLoop, observer, kCFRunLoopCommonModes ); 1506 1507 view->fUpdateObserver = observer; 1508 1509// printf( "Update observer started\n" ); 1510} 1511 1512static void 1513StopUpdateObserver( HIWebView* view ) 1514{ 1515 check( view->fIsComposited == false ); 1516 check( view->fUpdateObserver != NULL ); 1517 1518 CFRunLoopObserverInvalidate( view->fUpdateObserver ); 1519 CFRelease( view->fUpdateObserver ); 1520 view->fUpdateObserver = NULL; 1521 1522// printf( "Update observer removed\n" ); 1523} 1524 1525static void 1526UpdateObserver( CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info ) 1527{ 1528 HIWebView* view = (HIWebView*)info; 1529 RgnHandle region = NewRgn(); 1530 1531// printf( "Update observer called\n" ); 1532 1533 if ( region ) 1534 { 1535 GetWindowRegion( GetControlOwner( view->fViewRef ), kWindowUpdateRgn, region ); 1536 1537 if ( !EmptyRgn( region ) ) 1538 { 1539 RgnHandle ourRgn = NewRgn(); 1540 Rect rect; 1541 1542 GetWindowBounds( GetControlOwner( view->fViewRef ), kWindowStructureRgn, &rect ); 1543 1544// printf( "Update region is non-empty\n" ); 1545 1546 if ( ourRgn ) 1547 { 1548 Rect rect; 1549 GrafPtr savePort, port; 1550 Point offset = { 0, 0 }; 1551 1552 port = GetWindowPort( GetControlOwner( view->fViewRef ) ); 1553 1554 GetPort( &savePort ); 1555 SetPort( port ); 1556 1557 GlobalToLocal( &offset ); 1558 OffsetRgn( region, offset.h, offset.v ); 1559 1560 GetControlBounds( view->fViewRef, &rect ); 1561 RectRgn( ourRgn, &rect ); 1562 1563// printf( "our control is at %d %d %d %d\n", 1564// rect.top, rect.left, rect.bottom, rect.right ); 1565 1566 GetRegionBounds( region, &rect ); 1567// printf( "region is at %d %d %d %d\n", 1568// rect.top, rect.left, rect.bottom, rect.right ); 1569 1570 SectRgn( ourRgn, region, ourRgn ); 1571 1572 GetRegionBounds( ourRgn, &rect ); 1573// printf( "intersection is %d %d %d %d\n", 1574// rect.top, rect.left, rect.bottom, rect.right ); 1575 if ( !EmptyRgn( ourRgn ) ) 1576 { 1577 RgnHandle saveVis = NewRgn(); 1578 1579// printf( "looks like we should draw\n" ); 1580 1581 if ( saveVis ) 1582 { 1583// RGBColor kRedColor = { 0xffff, 0, 0 }; 1584 1585 GetPortVisibleRegion( GetWindowPort( GetControlOwner( view->fViewRef ) ), saveVis ); 1586 SetPortVisibleRegion( GetWindowPort( GetControlOwner( view->fViewRef ) ), ourRgn ); 1587 1588// RGBForeColor( &kRedColor ); 1589// PaintRgn( ourRgn ); 1590// QDFlushPortBuffer( port, NULL ); 1591// Delay( 15, NULL ); 1592 1593 Draw1Control( view->fViewRef ); 1594 ValidWindowRgn( GetControlOwner( view->fViewRef ), ourRgn ); 1595 1596 SetPortVisibleRegion( GetWindowPort( GetControlOwner( view->fViewRef ) ), saveVis ); 1597 DisposeRgn( saveVis ); 1598 } 1599 } 1600 1601 SetPort( savePort ); 1602 1603 DisposeRgn( ourRgn ); 1604 } 1605 } 1606 1607 DisposeRgn( region ); 1608 } 1609} 1610 1611#endif 1612