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