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