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