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