X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8907154c1a8a6882c6797d1f16393ddfb23e7f3a..04fa04d8067d235ab45b5bc05b65f0679634b541:/src/html/htmlctrl/webkit/webkit.mm diff --git a/src/html/htmlctrl/webkit/webkit.mm b/src/html/htmlctrl/webkit/webkit.mm old mode 100755 new mode 100644 index a47639efac..1152845843 --- a/src/html/htmlctrl/webkit/webkit.mm +++ b/src/html/htmlctrl/webkit/webkit.mm @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: webkit.mm +// Name: src/html/htmlctrl/webkit/webkit.mm // Purpose: wxWebKitCtrl - embeddable web kit control // Author: Jethro Grassie / Kevin Ollivier // Modified by: @@ -22,16 +22,18 @@ #ifdef __WXCOCOA__ #include "wx/cocoa/autorelease.h" #else -#include "wx/mac/uma.h" -#include +#include "wx/osx/private.h" + #include #include #include #endif #include "wx/html/webkit.h" -#include "wx/notebook.h" +#define DEBUG_WEBKIT_SIZING 0 + +extern WXDLLEXPORT_DATA(const char) wxWebKitCtrlNameStr[] = "webkitctrl"; // ---------------------------------------------------------------------------- // macros @@ -40,24 +42,299 @@ IMPLEMENT_DYNAMIC_CLASS(wxWebKitCtrl, wxControl) BEGIN_EVENT_TABLE(wxWebKitCtrl, wxControl) +#if defined(__WXMAC__) && wxOSX_USE_CARBON EVT_SIZE(wxWebKitCtrl::OnSize) +#endif END_EVENT_TABLE() +#if defined(__WXOSX__) && wxOSX_USE_CARBON + +// ---------------------------------------------------------------------------- +// Carbon Events handlers +// ---------------------------------------------------------------------------- + +// prototype for function in src/osx/carbon/nonownedwnd.cpp +void SetupMouseEvent( wxMouseEvent &wxevent , wxMacCarbonEvent &cEvent ); + +static const EventTypeSpec eventList[] = +{ + //{ kEventClassControl, kEventControlTrack } , + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, + + { kEventClassKeyboard, kEventRawKeyDown } , + { kEventClassKeyboard, kEventRawKeyRepeat } , + { kEventClassKeyboard, kEventRawKeyUp } , + { kEventClassKeyboard, kEventRawKeyModifiersChanged } , + + { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } , + { kEventClassTextInput, kEventTextInputUpdateActiveInputArea } , + +#if DEBUG_WEBKIT_SIZING == 1 + { kEventClassControl, kEventControlBoundsChanged } , +#endif +}; + +// mix this in from window.cpp +pascal OSStatus wxMacUnicodeTextEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) ; + +// NOTE: This is mostly taken from KeyboardEventHandler in toplevel.cpp, but +// that expects the data pointer is a top-level window, so I needed to change +// that in this case. However, once 2.8 is out, we should factor out the common logic +// among the two functions and merge them. +static pascal OSStatus wxWebKitKeyEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + wxMacCarbonEvent cEvent( event ) ; + + wxWebKitCtrl* thisWindow = (wxWebKitCtrl*) data ; + wxWindow* focus = thisWindow ; + + unsigned char charCode ; + wxChar uniChar[2] ; + uniChar[0] = 0; + uniChar[1] = 0; + + UInt32 keyCode ; + UInt32 modifiers ; + Point point ; + UInt32 when = EventTimeToTicks( GetEventTime( event ) ) ; + +#if wxUSE_UNICODE + ByteCount dataSize = 0 ; + if ( GetEventParameter( event, kEventParamKeyUnicodes, typeUnicodeText, NULL, 0 , &dataSize, NULL ) == noErr ) + { + UniChar buf[2] ; + int numChars = dataSize / sizeof( UniChar) + 1; + + UniChar* charBuf = buf ; + + if ( numChars * 2 > 4 ) + charBuf = new UniChar[ numChars ] ; + GetEventParameter( event, kEventParamKeyUnicodes, typeUnicodeText, NULL, dataSize , NULL , charBuf ) ; + charBuf[ numChars - 1 ] = 0; + +#if SIZEOF_WCHAR_T == 2 + uniChar = charBuf[0] ; +#else + wxMBConvUTF16 converter ; + converter.MB2WC( uniChar , (const char*)charBuf , 2 ) ; +#endif + + if ( numChars * 2 > 4 ) + delete[] charBuf ; + } +#endif + + GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &charCode ); + GetEventParameter( event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode ); + GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers ); + GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &point ); + + UInt32 message = (keyCode << 8) + charCode; + switch ( GetEventKind( event ) ) + { + case kEventRawKeyRepeat : + case kEventRawKeyDown : + { + WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ; + WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ; + wxTheApp->MacSetCurrentEvent( event , handler ) ; + if ( /* focus && */ wxTheApp->MacSendKeyDownEvent( + focus , message , modifiers , when , point.h , point.v , uniChar[0] ) ) + { + result = noErr ; + } + wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ; + } + break ; + + case kEventRawKeyUp : + if ( /* focus && */ wxTheApp->MacSendKeyUpEvent( + focus , message , modifiers , when , point.h , point.v , uniChar[0] ) ) + { + result = noErr ; + } + break ; + + case kEventRawKeyModifiersChanged : + { + wxKeyEvent event(wxEVT_KEY_DOWN); + + event.m_shiftDown = modifiers & shiftKey; + event.m_controlDown = modifiers & controlKey; + event.m_altDown = modifiers & optionKey; + event.m_metaDown = modifiers & cmdKey; + event.m_x = point.h; + event.m_y = point.v; + +#if wxUSE_UNICODE + event.m_uniChar = uniChar[0] ; +#endif + + event.SetTimestamp(when); + event.SetEventObject(focus); + + if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & controlKey ) + { + event.m_keyCode = WXK_CONTROL ; + event.SetEventType( ( modifiers & controlKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & shiftKey ) + { + event.m_keyCode = WXK_SHIFT ; + event.SetEventType( ( modifiers & shiftKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & optionKey ) + { + event.m_keyCode = WXK_ALT ; + event.SetEventType( ( modifiers & optionKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & cmdKey ) + { + event.m_keyCode = WXK_COMMAND ; + event.SetEventType( ( modifiers & cmdKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + + wxApp::s_lastModifiers = modifiers ; + } + break ; + + default: + break; + } + + return result ; +} + +static pascal OSStatus wxWebKitCtrlEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + + wxMacCarbonEvent cEvent( event ) ; + + ControlRef controlRef ; + wxWebKitCtrl* thisWindow = (wxWebKitCtrl*) data ; + wxNonOwnedWindow* tlw = NULL; + if (thisWindow) + tlw = thisWindow->MacGetTopLevelWindow(); + + cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ; + + wxWindow* currentMouseWindow = thisWindow ; + + if ( wxApp::s_captureWindow ) + currentMouseWindow = wxApp::s_captureWindow; + + switch ( GetEventClass( event ) ) + { + case kEventClassKeyboard: + { + result = wxWebKitKeyEventHandler(handler, event, data); + break; + } + + case kEventClassTextInput: + { + result = wxMacUnicodeTextEventHandler(handler, event, data); + break; + } + + case kEventClassMouse: + { + switch ( GetEventKind( event ) ) + { + case kEventMouseDragged : + case kEventMouseMoved : + case kEventMouseDown : + case kEventMouseUp : + { + wxMouseEvent wxevent(wxEVT_LEFT_DOWN); + SetupMouseEvent( wxevent , cEvent ) ; + + currentMouseWindow->ScreenToClient( &wxevent.m_x , &wxevent.m_y ) ; + wxevent.SetEventObject( currentMouseWindow ) ; + wxevent.SetId( currentMouseWindow->GetId() ) ; + + if ( currentMouseWindow->GetEventHandler()->ProcessEvent(wxevent) ) + { + result = noErr; + } + + break; // this should enable WebKit to fire mouse dragged and mouse up events... + } + default : + break ; + } + } + default: + break; + } + + result = CallNextEventHandler(handler, event); + return result ; +} + +DEFINE_ONE_SHOT_HANDLER_GETTER( wxWebKitCtrlEventHandler ) + +#endif + // ---------------------------------------------------------------------------- // wxWebKit Events // ---------------------------------------------------------------------------- IMPLEMENT_DYNAMIC_CLASS( wxWebKitStateChangedEvent, wxCommandEvent ) -DEFINE_EVENT_TYPE( wxEVT_WEBKIT_STATE_CHANGED ) +wxDEFINE_EVENT( wxEVT_WEBKIT_STATE_CHANGED, wxWebKitStateChangedEvent ); wxWebKitStateChangedEvent::wxWebKitStateChangedEvent( wxWindow* win ) { SetEventType( wxEVT_WEBKIT_STATE_CHANGED); - SetEventObject( win ); - SetId(win->GetId()); + if ( win ) + { + SetEventObject( win ); + SetId(win->GetId()); + } +} + +IMPLEMENT_DYNAMIC_CLASS( wxWebKitBeforeLoadEvent, wxCommandEvent ) + +wxDEFINE_EVENT( wxEVT_WEBKIT_BEFORE_LOAD, wxWebKitBeforeLoadEvent ); + +wxWebKitBeforeLoadEvent::wxWebKitBeforeLoadEvent( wxWindow* win ) +{ + m_cancelled = false; + SetEventType( wxEVT_WEBKIT_BEFORE_LOAD); + if ( win ) + { + SetEventObject( win ); + SetId(win->GetId()); + } +} + + +IMPLEMENT_DYNAMIC_CLASS( wxWebKitNewWindowEvent, wxCommandEvent ) + +wxDEFINE_EVENT( wxEVT_WEBKIT_NEW_WINDOW, wxWebKitNewWindowEvent ); + +wxWebKitNewWindowEvent::wxWebKitNewWindowEvent( wxWindow* win ) +{ + SetEventType( wxEVT_WEBKIT_NEW_WINDOW); + if ( win ) + { + SetEventObject( win ); + SetId(win->GetId()); + } } + + //--------------------------------------------------------- // helper functions for NSString<->wxString conversion //--------------------------------------------------------- @@ -80,12 +357,40 @@ inline NSString* wxNSStringWithWxString(const wxString &wxstring) #endif // wxUSE_UNICODE } +inline int wxNavTypeFromWebNavType(int type){ + if (type == WebNavigationTypeLinkClicked) + return wxWEBKIT_NAV_LINK_CLICKED; + + if (type == WebNavigationTypeFormSubmitted) + return wxWEBKIT_NAV_FORM_SUBMITTED; + + if (type == WebNavigationTypeBackForward) + return wxWEBKIT_NAV_BACK_NEXT; + + if (type == WebNavigationTypeReload) + return wxWEBKIT_NAV_RELOAD; + + if (type == WebNavigationTypeFormResubmitted) + return wxWEBKIT_NAV_FORM_RESUBMITTED; + + return wxWEBKIT_NAV_OTHER; +} + @interface MyFrameLoadMonitor : NSObject { - wxWindow* webKitWindow; + wxWebKitCtrl* webKitWindow; +} + +- initWithWxWindow: (wxWebKitCtrl*)inWindow; + +@end + +@interface MyPolicyDelegate : NSObject +{ + wxWebKitCtrl* webKitWindow; } -- initWithWxWindow: (wxWindow*)inWindow; +- initWithWxWindow: (wxWebKitCtrl*)inWindow; @end @@ -101,7 +406,6 @@ bool wxWebKitCtrl::Create(wxWindow *parent, const wxValidator& validator, const wxString& name) { - m_currentURL = strURL; //m_pageTitle = _("Untitled Page"); @@ -122,6 +426,7 @@ bool wxWebKitCtrl::Create(wxWindow *parent, } */ // now create and attach WebKit view... + DontCreatePeer(); #ifdef __WXCOCOA__ wxControl::Create(parent, m_windowID, pos, sizeInstance, style , validator , name); SetSize(pos.x, pos.y, sizeInstance.x, sizeInstance.y); @@ -140,33 +445,62 @@ bool wxWebKitCtrl::Create(wxWindow *parent, if(m_parent) m_parent->CocoaAddChild(this); SetInitialFrameRect(pos,sizeInstance); #else - m_macIsUserPane = false; + DontCreatePeer(); wxControl::Create(parent, winID, pos, size, style , validator , name); - m_peer = new wxMacControl(this); +#if wxOSX_USE_CARBON + wxMacControl* peer = new wxMacControl(this); WebInitForCarbon(); - HIWebViewCreate( m_peer->GetControlRefAddr() ); + HIWebViewCreate( peer->GetControlRefAddr() ); + + m_webView = (WebView*) HIWebViewGetWebView( peer->GetControlRef() ); - m_webView = (WebView*) HIWebViewGetWebView( m_peer->GetControlRef() ); - MacPostControlCreate(pos, size); - HIViewSetVisible( m_peer->GetControlRef(), true ); - [m_webView setHidden:false]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 if ( UMAGetSystemVersion() >= 0x1030 ) - HIViewChangeFeatures( m_peer->GetControlRef() , kHIViewIsOpaque , 0 ) ; + HIViewChangeFeatures( peer->GetControlRef() , kHIViewIsOpaque , 0 ) ; +#endif + InstallControlEventHandler( peer->GetControlRef() , GetwxWebKitCtrlEventHandlerUPP(), + GetEventTypeCount(eventList), eventList, this, + (EventHandlerRef *)&m_webKitCtrlEventHandler); + + SetPeer(peer); +#else + NSRect r = wxOSXGetFrameForControl( this, pos , size ) ; + m_webView = [[WebView alloc] initWithFrame:r frameName:@"webkitFrame" groupName:@"webkitGroup"]; + + SetPeer(new wxWidgetCocoaImpl( this, m_webView )); #endif + MacPostControlCreate(pos, size); +#if wxOSX_USE_CARBON + HIViewSetVisible( GetPeer()->GetControlRef(), true ); +#endif + [m_webView setHidden:false]; + #endif // Register event listener interfaces - MyFrameLoadMonitor* myFrameLoadMonitor = [[MyFrameLoadMonitor alloc] initWithWxWindow: (wxWindow*)this]; + MyFrameLoadMonitor* myFrameLoadMonitor = [[MyFrameLoadMonitor alloc] initWithWxWindow: this]; [m_webView setFrameLoadDelegate:myFrameLoadMonitor]; + // this is used to veto page loads, etc. + MyPolicyDelegate* myPolicyDelegate = [[MyPolicyDelegate alloc] initWithWxWindow: this]; + [m_webView setPolicyDelegate:myPolicyDelegate]; + LoadURL(m_currentURL); return true; } wxWebKitCtrl::~wxWebKitCtrl() { - + MyFrameLoadMonitor* myFrameLoadMonitor = [m_webView frameLoadDelegate]; + MyPolicyDelegate* myPolicyDelegate = [m_webView policyDelegate]; + [m_webView setFrameLoadDelegate: nil]; + [m_webView setPolicyDelegate: nil]; + + if (myFrameLoadMonitor) + [myFrameLoadMonitor release]; + + if (myPolicyDelegate) + [myPolicyDelegate release]; } // ---------------------------------------------------------------------------- @@ -245,17 +579,130 @@ wxString wxWebKitCtrl::GetPageSource(){ return wxEmptyString; } -void wxWebKitCtrl::SetPageSource(wxString& source, const wxString& baseUrl){ +wxString wxWebKitCtrl::GetSelection(){ + if ( !m_webView ) + return wxEmptyString; + + NSString* selectedText = [[m_webView selectedDOMRange] toString]; + return wxStringWithNSString( selectedText ); +} + +bool wxWebKitCtrl::CanIncreaseTextSize(){ + if ( !m_webView ) + return false; + + if ([m_webView canMakeTextLarger]) + return true; + else + return false; +} + +void wxWebKitCtrl::IncreaseTextSize(){ if ( !m_webView ) return; - if (CanGetPageSource()){ - [[m_webView mainFrame] loadHTMLString:(NSString*)wxNSStringWithWxString( source ) baseURL:[NSURL URLWithString:wxNSStringWithWxString( baseUrl )]]; + if (CanIncreaseTextSize()) + [m_webView makeTextLarger:(WebView*)m_webView]; +} + +bool wxWebKitCtrl::CanDecreaseTextSize(){ + if ( !m_webView ) + return false; + + if ([m_webView canMakeTextSmaller]) + return true; + else + return false; +} + +void wxWebKitCtrl::DecreaseTextSize(){ + if ( !m_webView ) + return; + + if (CanDecreaseTextSize()) + [m_webView makeTextSmaller:(WebView*)m_webView]; +} + +void wxWebKitCtrl::SetPageSource(const wxString& source, const wxString& baseUrl){ + if ( !m_webView ) + return; + + [[m_webView mainFrame] loadHTMLString:(NSString*)wxNSStringWithWxString( source ) baseURL:[NSURL URLWithString:wxNSStringWithWxString( baseUrl )]]; + +} + +void wxWebKitCtrl::Print(bool showPrompt){ + if ( !m_webView ) + return; + + id view = [[[m_webView mainFrame] frameView] documentView]; + NSPrintOperation *op = [NSPrintOperation printOperationWithView:view printInfo: [NSPrintInfo sharedPrintInfo]]; + if (showPrompt){ + [op setShowsPrintPanel: showPrompt]; + // in my tests, the progress bar always freezes and it stops the whole print operation. + // do not turn this to true unless there is a workaround for the bug. + [op setShowsProgressPanel: false]; } + // Print it. + [op runOperation]; +} + +void wxWebKitCtrl::MakeEditable(bool enable){ + if ( !m_webView ) + return; + + [m_webView setEditable:enable ]; +} + +bool wxWebKitCtrl::IsEditable(){ + if ( !m_webView ) + return false; + + return [m_webView isEditable]; +} + +int wxWebKitCtrl::GetScrollPos(){ + id result = [[m_webView windowScriptObject] evaluateWebScript:@"document.body.scrollTop"]; + return [result intValue]; +} + +void wxWebKitCtrl::SetScrollPos(int pos){ + if ( !m_webView ) + return; + wxString javascript; + javascript.Printf(wxT("document.body.scrollTop = %d;"), pos); + [[m_webView windowScriptObject] evaluateWebScript:(NSString*)wxNSStringWithWxString( javascript )]; +} + +wxString wxWebKitCtrl::RunScript(const wxString& javascript){ + if ( !m_webView ) + return wxEmptyString; + + id result = [[m_webView windowScriptObject] evaluateWebScript:(NSString*)wxNSStringWithWxString( javascript )]; + + NSString* resultAsString; + NSString* className = NSStringFromClass([result class]); + if ([className isEqualToString:@"NSCFNumber"]) + resultAsString = [NSString stringWithFormat:@"%@", result]; + else if ([className isEqualToString:@"NSCFString"]) + resultAsString = result; + else if ([className isEqualToString:@"NSCFBoolean"]){ + if ([result boolValue]) + resultAsString = @"true"; + else + resultAsString = @"false"; + } + else if ([className isEqualToString:@"WebScriptObject"]) + resultAsString = [result stringRepresentation]; + else + return wxString(); // This can happen, see e.g. #12361. + + return wxStringWithNSString( resultAsString ); } void wxWebKitCtrl::OnSize(wxSizeEvent &event){ +#if defined(__WXMAC_) && wxOSX_USE_CARBON // This is a nasty hack because WebKit seems to lose its position when it is embedded // in a control that is not itself the content view for a TLW. // I put it in OnSize because these calcs are not perfect, and in fact are basically @@ -264,146 +711,90 @@ void wxWebKitCtrl::OnSize(wxSizeEvent &event){ // I also left some test debugging print statements as a convenience if a(nother) // problem crops up. - // Let's hope that Tiger fixes this mess... - - int x, y; - x = 0; - y = 0; + wxWindow* tlw = MacGetTopLevelWindow(); - wxWindow* parent = GetParent(); + NSRect frame = [(WebView*)m_webView frame]; + NSRect bounds = [(WebView*)m_webView bounds]; - wxWindow* tlw = MacGetTopLevelWindow(); +#if DEBUG_WEBKIT_SIZING + fprintf(stderr,"Carbon window x=%d, y=%d, width=%d, height=%d\n", GetPosition().x, GetPosition().y, GetSize().x, GetSize().y); + fprintf(stderr, "Cocoa window frame x=%G, y=%G, width=%G, height=%G\n", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); + fprintf(stderr, "Cocoa window bounds x=%G, y=%G, width=%G, height=%G\n", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height); +#endif // This must be the case that Apple tested with, because well, in this one case // we don't need to do anything! It just works. ;) - if (parent == tlw){ + if (GetParent() == tlw){ return; } - while(parent != NULL) - { - if ( parent->IsKindOf( CLASSINFO( wxSplitterWindow ) ) && GetParent()->IsKindOf( CLASSINFO( wxSplitterWindow ) ) ){ - // When parent is not a wxSplitterWindow, we can rely on it's GetPosition() to give us the correct - // coordinates, but when the parent is a wxSplitterWindow, we need to manually calculate - // the sash position of it and any parent wxSplitterWindows into the webkit's position. - wxSplitterWindow* splitter; - splitter = dynamic_cast(parent); - if (splitter->GetSplitMode() == wxSPLIT_HORIZONTAL){ - if (splitter->GetPosition().y > 0) - y += splitter->GetPosition().y; - - if (splitter->GetSashSize() > 0) - y += splitter->GetSashSize(); - - if (splitter->GetSashPosition() > 0) - y += splitter->GetSashPosition(); - } - else{ - if (splitter->GetPosition().x > 0) - x += splitter->GetPosition().x; - - if (splitter->GetSashSize() > 0) - x += splitter->GetSashSize(); - - if (splitter->GetSashPosition() > 0) - x += splitter->GetSashPosition(); - } - } - else{ - if (!parent->IsTopLevel()) { - //printf("Parent: %s\n", parent->GetClassInfo()->GetClassName()); - int plusx = 0; - plusx = parent->GetClientAreaOrigin().x + parent->GetPosition().x; - if (plusx > 0){ - x += plusx; - //printf("Parent: %s Added x: %d\n", parent->GetClassInfo()->GetClassName(), parent->GetClientAreaOrigin().x + parent->GetPosition().x); - } - - int plusy = 0; - plusy = parent->GetClientAreaOrigin().y + parent->GetPosition().y; - if (plusy > 0){ - y += plusy; - //printf("Parent: %s Added y: %d\n", parent->GetClassInfo()->GetClassName(), parent->GetClientAreaOrigin().y + parent->GetPosition().y); - } - else{ - //printf("Parent: %s Origin: %d Position:%d\n", parent->GetClassInfo()->GetClassName(), parent->GetClientAreaOrigin().y, parent->GetPosition().y); - } - - } - else{ - // - x += parent->GetClientAreaOrigin().x; - // calculate the title bar height (26 pixels) into the top offset. - // This becomes important later when we must flip the y coordinate - // to convert to Cocoa's coordinate system. - y += parent->GetClientAreaOrigin().y += 26; - //printf("x: %d, y:%d\n", x, y); - } - //we still need to add the y, because we have to convert/flip coordinates for Cocoa + // since we no longer use parent coordinates, we always want 0,0. + int x = 0; + int y = 0; - if ( parent->IsKindOf( CLASSINFO( wxNotebook ) ) ){ - //Not sure why calcs are off in this one scenario... - y -= 4; - //printf("x: %d, y:%d\n", x, y); - } + HIRect rect; + rect.origin.x = x; + rect.origin.y = y; - if (parent->IsKindOf( CLASSINFO( wxPanel ) ) ){ - // Another strange case. Adding a wxPanel to the parent heirarchy - // causes wxWebKitCtrl's Cocoa y origin to be 4 pixels off - // for some reason, even if the panel has a position and origin of 0. - // This corrects that. Man, I wish I could debug Carbon/HIWebView!! ;) - y -= 4; - } - } +#if DEBUG_WEBKIT_SIZING + printf("Before conversion, origin is: x = %d, y = %d\n", x, y); +#endif - parent = parent->GetParent(); - } + // NB: In most cases, when calling HIViewConvertRect, what people want is to use GetRootControl(), + // and this tripped me up at first. But in fact, what we want is the root view, because we need to + // make the y origin relative to the very top of the window, not its contents, since we later flip + // the y coordinate for Cocoa. + HIViewConvertRect (&rect, GetPeer()->GetControlRef(), + HIViewGetRoot( (WindowRef) MacGetTopLevelWindowRef() ) ); - // Tried using MacWindowToRootWindow both for wxWebKitCtrl and its parent, - // but coordinates were off by a significant amount. - // Am leaving the code here if anyone wants to play with it. + x = (int)rect.origin.x; + y = (int)rect.origin.y; - //int x2, y2 = 0; - //if (GetParent()) - // GetParent()->MacWindowToRootWindow(&x2, &y2); - //printf("x = %d, y = %d\n", x, y); - //printf("x2 = %d, y2 = %d\n", x2, y2); - //x = x2; - //y = y2; +#if DEBUG_WEBKIT_SIZING + printf("Moving Cocoa frame origin to: x = %d, y = %d\n", x, y); +#endif if (tlw){ //flip the y coordinate to convert to Cocoa coordinates - //printf("tlw y: %d, y: %d\n", tlw->GetSize().y, (GetSize().y + y)); y = tlw->GetSize().y - ((GetSize().y) + y); } - //printf("Added to bounds x=%d, y=%d\n", x, y); - NSRect bounds = [m_webView frame]; - bounds.origin.x = x; - bounds.origin.y = y; - [m_webView setFrame:bounds]; +#if DEBUG_WEBKIT_SIZING + printf("y = %d after flipping value\n", y); +#endif + + frame.origin.x = x; + frame.origin.y = y; + [(WebView*)m_webView setFrame:frame]; - //printf("Carbon position x=%d, y=%d\n", GetPosition().x, GetPosition().y); if (IsShown()) [(WebView*)m_webView display]; +#endif event.Skip(); } void wxWebKitCtrl::MacVisibilityChanged(){ - bool isHidden = !IsControlVisible( m_peer->GetControlRef()); +#if defined(__WXMAC__) && wxOSX_USE_CARBON + bool isHidden = !IsControlVisible( GetPeer()->GetControlRef()); if (!isHidden) [(WebView*)m_webView display]; [m_webView setHidden:isHidden]; +#endif } //------------------------------------------------------------ // Listener interfaces //------------------------------------------------------------ +// NB: I'm still tracking this down, but it appears the Cocoa window +// still has these events fired on it while the Carbon control is being +// destroyed. Therefore, we must be careful to check both the existence +// of the Carbon control and the event handler before firing events. + @implementation MyFrameLoadMonitor -- initWithWxWindow: (wxWindow*)inWindow +- initWithWxWindow: (wxWebKitCtrl*)inWindow { [super init]; webKitWindow = inWindow; // non retained @@ -412,65 +803,124 @@ void wxWebKitCtrl::MacVisibilityChanged(){ - (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame { - if (frame == [sender mainFrame]){ + if (webKitWindow && frame == [sender mainFrame]){ NSString *url = [[[[frame provisionalDataSource] request] URL] absoluteString]; wxWebKitStateChangedEvent thisEvent(webKitWindow); thisEvent.SetState(wxWEBKIT_STATE_NEGOTIATING); thisEvent.SetURL( wxStringWithNSString( url ) ); - webKitWindow->GetEventHandler()->ProcessEvent( thisEvent ); + if (webKitWindow->GetEventHandler()) + webKitWindow->GetEventHandler()->ProcessEvent( thisEvent ); } } - (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame { - if (frame == [sender mainFrame]){ + if (webKitWindow && frame == [sender mainFrame]){ NSString *url = [[[[frame dataSource] request] URL] absoluteString]; wxWebKitStateChangedEvent thisEvent(webKitWindow); thisEvent.SetState(wxWEBKIT_STATE_TRANSFERRING); thisEvent.SetURL( wxStringWithNSString( url ) ); - webKitWindow->GetEventHandler()->ProcessEvent( thisEvent ); + if (webKitWindow->GetEventHandler()) + webKitWindow->GetEventHandler()->ProcessEvent( thisEvent ); } } - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame { - if (frame == [sender mainFrame]){ + if (webKitWindow && frame == [sender mainFrame]){ NSString *url = [[[[frame dataSource] request] URL] absoluteString]; wxWebKitStateChangedEvent thisEvent(webKitWindow); thisEvent.SetState(wxWEBKIT_STATE_STOP); thisEvent.SetURL( wxStringWithNSString( url ) ); - webKitWindow->GetEventHandler()->ProcessEvent( thisEvent ); + if (webKitWindow->GetEventHandler()) + webKitWindow->GetEventHandler()->ProcessEvent( thisEvent ); } } - (void)webView:(WebView *)sender didFailLoadWithError:(NSError*) error forFrame:(WebFrame *)frame { - if (frame == [sender mainFrame]){ + wxUnusedVar(error); + + if (webKitWindow && frame == [sender mainFrame]){ NSString *url = [[[[frame dataSource] request] URL] absoluteString]; wxWebKitStateChangedEvent thisEvent(webKitWindow); thisEvent.SetState(wxWEBKIT_STATE_FAILED); thisEvent.SetURL( wxStringWithNSString( url ) ); - webKitWindow->GetEventHandler()->ProcessEvent( thisEvent ); + if (webKitWindow->GetEventHandler()) + webKitWindow->GetEventHandler()->ProcessEvent( thisEvent ); } } - (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError*) error forFrame:(WebFrame *)frame { - if (frame == [sender mainFrame]){ + wxUnusedVar(error); + + if (webKitWindow && frame == [sender mainFrame]){ NSString *url = [[[[frame provisionalDataSource] request] URL] absoluteString]; wxWebKitStateChangedEvent thisEvent(webKitWindow); thisEvent.SetState(wxWEBKIT_STATE_FAILED); thisEvent.SetURL( wxStringWithNSString( url ) ); - webKitWindow->GetEventHandler()->ProcessEvent( thisEvent ); + if (webKitWindow->GetEventHandler()) + webKitWindow->GetEventHandler()->ProcessEvent( thisEvent ); } } - (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame { - if (frame == [sender mainFrame]){ - webKitWindow->SetTitle(wxStringWithNSString( title )); + if (webKitWindow && frame == [sender mainFrame]){ + webKitWindow->SetPageTitle(wxStringWithNSString( title )); } } @end +@implementation MyPolicyDelegate + +- initWithWxWindow: (wxWebKitCtrl*)inWindow +{ + [super init]; + webKitWindow = inWindow; // non retained + return self; +} + +- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener +{ + wxUnusedVar(sender); + wxUnusedVar(frame); + + wxWebKitBeforeLoadEvent thisEvent(webKitWindow); + + // Get the navigation type. + NSNumber *n = [actionInformation objectForKey:WebActionNavigationTypeKey]; + int actionType = [n intValue]; + thisEvent.SetNavigationType( wxNavTypeFromWebNavType(actionType) ); + + NSString *url = [[request URL] absoluteString]; + thisEvent.SetURL( wxStringWithNSString( url ) ); + + if (webKitWindow && webKitWindow->GetEventHandler()) + webKitWindow->GetEventHandler()->ProcessEvent(thisEvent); + + if (thisEvent.IsCancelled()) + [listener ignore]; + else + [listener use]; +} + +- (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id < WebPolicyDecisionListener >)listener +{ + wxUnusedVar(sender); + wxUnusedVar(actionInformation); + wxWebKitNewWindowEvent thisEvent(webKitWindow); + + NSString *url = [[request URL] absoluteString]; + thisEvent.SetURL( wxStringWithNSString( url ) ); + thisEvent.SetTargetName( wxStringWithNSString( frameName ) ); + + if (webKitWindow && webKitWindow->GetEventHandler()) + webKitWindow->GetEventHandler()->ProcessEvent(thisEvent); + + [listener use]; +} +@end + #endif //wxUSE_WEBKIT