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