+/////////////////////////////////////////////////////////////////////////////\r
+// Name: src/osx/webkit.mm\r
+// Purpose: wxOSXWebKitCtrl - embeddable web kit control,\r
+// OS X implementation of web view component\r
+// Author: Jethro Grassie / Kevin Ollivier / Marianne Gagnon\r
+// Modified by:\r
+// Created: 2004-4-16\r
+// RCS-ID: $Id: webkit.mm 64943 2010-07-13 13:29:58Z VZ $\r
+// Copyright: (c) Jethro Grassie / Kevin Ollivier / Marianne Gagnon\r
+// Licence: wxWindows licence\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+// http://developer.apple.com/mac/library/documentation/Cocoa/Reference/WebKit/Classes/WebView_Class/Reference/Reference.html\r
+\r
+#include "wx/osx/webview.h"\r
+\r
+// For compilers that support precompilation, includes "wx.h".\r
+#include "wx/wxprec.h"\r
+\r
+#ifndef WX_PRECOMP\r
+ #include "wx/wx.h"\r
+#endif\r
+\r
+#if wxHAVE_WEB_BACKEND_OSX_WEBKIT\r
+\r
+#ifdef __WXCOCOA__\r
+#include "wx/cocoa/autorelease.h"\r
+#else\r
+#include "wx/osx/private.h"\r
+\r
+#include <WebKit/WebKit.h>\r
+#include <WebKit/HIWebView.h>\r
+#include <WebKit/CarbonUtils.h>\r
+#endif\r
+\r
+#include <Foundation/NSURLError.h>\r
+\r
+// FIXME: find cleaner way to find the wxWidgets ID of a webview than this hack\r
+#include <map>\r
+std::map<WebView*, wxOSXWebKitCtrl*> wx_webviewctrls;\r
+\r
+#define DEBUG_WEBKIT_SIZING 0\r
+\r
+// ----------------------------------------------------------------------------\r
+// macros\r
+// ----------------------------------------------------------------------------\r
+\r
+IMPLEMENT_DYNAMIC_CLASS(wxOSXWebKitCtrl, wxControl)\r
+\r
+BEGIN_EVENT_TABLE(wxOSXWebKitCtrl, wxControl)\r
+#if defined(__WXMAC__) && wxOSX_USE_CARBON\r
+ EVT_SIZE(wxOSXWebKitCtrl::OnSize)\r
+#endif\r
+END_EVENT_TABLE()\r
+\r
+#if defined(__WXOSX__) && wxOSX_USE_CARBON\r
+\r
+// ----------------------------------------------------------------------------\r
+// Carbon Events handlers\r
+// ----------------------------------------------------------------------------\r
+\r
+// prototype for function in src/osx/carbon/nonownedwnd.cpp\r
+void SetupMouseEvent( wxMouseEvent &wxevent , wxMacCarbonEvent &cEvent );\r
+\r
+static const EventTypeSpec eventList[] =\r
+{\r
+ //{ kEventClassControl, kEventControlTrack } ,\r
+ { kEventClassMouse, kEventMouseUp },\r
+ { kEventClassMouse, kEventMouseDown },\r
+ { kEventClassMouse, kEventMouseMoved },\r
+ { kEventClassMouse, kEventMouseDragged },\r
+\r
+ { kEventClassKeyboard, kEventRawKeyDown } ,\r
+ { kEventClassKeyboard, kEventRawKeyRepeat } ,\r
+ { kEventClassKeyboard, kEventRawKeyUp } ,\r
+ { kEventClassKeyboard, kEventRawKeyModifiersChanged } ,\r
+\r
+ { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } ,\r
+ { kEventClassTextInput, kEventTextInputUpdateActiveInputArea } ,\r
+\r
+#if DEBUG_WEBKIT_SIZING == 1\r
+ { kEventClassControl, kEventControlBoundsChanged } ,\r
+#endif\r
+};\r
+\r
+// mix this in from window.cpp\r
+pascal OSStatus wxMacUnicodeTextEventHandler(EventHandlerCallRef handler,\r
+ EventRef event, void *data) ;\r
+\r
+// NOTE: This is mostly taken from KeyboardEventHandler in toplevel.cpp, but\r
+// that expects the data pointer is a top-level window, so I needed to change\r
+// that in this case. However, once 2.8 is out, we should factor out the common\r
+// logic among the two functions and merge them.\r
+static pascal OSStatus wxWebKitKeyEventHandler(EventHandlerCallRef handler,\r
+ EventRef event, void *data)\r
+{\r
+ OSStatus result = eventNotHandledErr ;\r
+ wxMacCarbonEvent cEvent( event ) ;\r
+\r
+ wxOSXWebKitCtrl* thisWindow = (wxOSXWebKitCtrl*) data ;\r
+ wxWindow* focus = thisWindow ;\r
+\r
+ unsigned char charCode ;\r
+ wxChar uniChar[2] ;\r
+ uniChar[0] = 0;\r
+ uniChar[1] = 0;\r
+\r
+ UInt32 keyCode ;\r
+ UInt32 modifiers ;\r
+ Point point ;\r
+ UInt32 when = EventTimeToTicks( GetEventTime( event ) ) ;\r
+\r
+#if wxUSE_UNICODE\r
+ ByteCount dataSize = 0 ;\r
+ if ( GetEventParameter(event, kEventParamKeyUnicodes, typeUnicodeText,\r
+ NULL, 0 , &dataSize, NULL ) == noErr)\r
+ {\r
+ UniChar buf[2] ;\r
+ int numChars = dataSize / sizeof( UniChar) + 1;\r
+\r
+ UniChar* charBuf = buf ;\r
+\r
+ if ( numChars * 2 > 4 )\r
+ charBuf = new UniChar[ numChars ] ;\r
+ GetEventParameter(event, kEventParamKeyUnicodes, typeUnicodeText, NULL,\r
+ dataSize , NULL , charBuf) ;\r
+ charBuf[ numChars - 1 ] = 0;\r
+\r
+#if SIZEOF_WCHAR_T == 2\r
+ uniChar = charBuf[0] ;\r
+#else\r
+ wxMBConvUTF16 converter ;\r
+ converter.MB2WC( uniChar , (const char*)charBuf , 2 ) ;\r
+#endif\r
+\r
+ if ( numChars * 2 > 4 )\r
+ delete[] charBuf ;\r
+ }\r
+#endif\r
+\r
+ GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL,\r
+ sizeof(char), NULL, &charCode );\r
+ GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL,\r
+ sizeof(UInt32), NULL, &keyCode );\r
+ GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL,\r
+ sizeof(UInt32), NULL, &modifiers );\r
+ GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL,\r
+ sizeof(Point), NULL, &point );\r
+\r
+ UInt32 message = (keyCode << 8) + charCode;\r
+ switch ( GetEventKind( event ) )\r
+ {\r
+ case kEventRawKeyRepeat :\r
+ case kEventRawKeyDown :\r
+ {\r
+ WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;\r
+ WXEVENTHANDLERCALLREF formerHandler =\r
+ wxTheApp->MacGetCurrentEventHandlerCallRef() ;\r
+\r
+ wxTheApp->MacSetCurrentEvent( event , handler ) ;\r
+ if ( /* focus && */ wxTheApp->MacSendKeyDownEvent(\r
+ focus, message, modifiers, when, point.h, point.v, uniChar[0]))\r
+ {\r
+ result = noErr ;\r
+ }\r
+ wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;\r
+ }\r
+ break ;\r
+\r
+ case kEventRawKeyUp :\r
+ if ( /* focus && */ wxTheApp->MacSendKeyUpEvent(\r
+ focus , message , modifiers , when , point.h , point.v , uniChar[0] ) )\r
+ {\r
+ result = noErr ;\r
+ }\r
+ break ;\r
+\r
+ case kEventRawKeyModifiersChanged :\r
+ {\r
+ wxKeyEvent event(wxEVT_KEY_DOWN);\r
+\r
+ event.m_shiftDown = modifiers & shiftKey;\r
+ event.m_controlDown = modifiers & controlKey;\r
+ event.m_altDown = modifiers & optionKey;\r
+ event.m_metaDown = modifiers & cmdKey;\r
+ event.m_x = point.h;\r
+ event.m_y = point.v;\r
+\r
+#if wxUSE_UNICODE\r
+ event.m_uniChar = uniChar[0] ;\r
+#endif\r
+\r
+ event.SetTimestamp(when);\r
+ event.SetEventObject(focus);\r
+\r
+ if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & controlKey )\r
+ {\r
+ event.m_keyCode = WXK_CONTROL ;\r
+ event.SetEventType( ( modifiers & controlKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;\r
+ focus->GetEventHandler()->ProcessEvent( event ) ;\r
+ }\r
+ if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & shiftKey )\r
+ {\r
+ event.m_keyCode = WXK_SHIFT ;\r
+ event.SetEventType( ( modifiers & shiftKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;\r
+ focus->GetEventHandler()->ProcessEvent( event ) ;\r
+ }\r
+ if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & optionKey )\r
+ {\r
+ event.m_keyCode = WXK_ALT ;\r
+ event.SetEventType( ( modifiers & optionKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;\r
+ focus->GetEventHandler()->ProcessEvent( event ) ;\r
+ }\r
+ if ( /* focus && */ (modifiers ^ wxApp::s_lastModifiers ) & cmdKey )\r
+ {\r
+ event.m_keyCode = WXK_COMMAND ;\r
+ event.SetEventType( ( modifiers & cmdKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ;\r
+ focus->GetEventHandler()->ProcessEvent( event ) ;\r
+ }\r
+\r
+ wxApp::s_lastModifiers = modifiers ;\r
+ }\r
+ break ;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return result ;\r
+}\r
+\r
+static pascal OSStatus wxOSXWebKitCtrlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )\r
+{\r
+ OSStatus result = eventNotHandledErr ;\r
+\r
+ wxMacCarbonEvent cEvent( event ) ;\r
+\r
+ ControlRef controlRef ;\r
+ wxOSXWebKitCtrl* thisWindow = (wxOSXWebKitCtrl*) data ;\r
+ wxNonOwnedWindow* tlw = NULL;\r
+ if (thisWindow)\r
+ tlw = thisWindow->MacGetTopLevelWindow();\r
+\r
+ cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;\r
+\r
+ wxWindow* currentMouseWindow = thisWindow ;\r
+\r
+ if ( wxApp::s_captureWindow )\r
+ currentMouseWindow = wxApp::s_captureWindow;\r
+\r
+ switch ( GetEventClass( event ) )\r
+ {\r
+ case kEventClassKeyboard:\r
+ {\r
+ result = wxWebKitKeyEventHandler(handler, event, data);\r
+ break;\r
+ }\r
+\r
+ case kEventClassTextInput:\r
+ {\r
+ result = wxMacUnicodeTextEventHandler(handler, event, data);\r
+ break;\r
+ }\r
+\r
+ case kEventClassMouse:\r
+ {\r
+ switch ( GetEventKind( event ) )\r
+ {\r
+ case kEventMouseDragged :\r
+ case kEventMouseMoved :\r
+ case kEventMouseDown :\r
+ case kEventMouseUp :\r
+ {\r
+ wxMouseEvent wxevent(wxEVT_LEFT_DOWN);\r
+ SetupMouseEvent( wxevent , cEvent ) ;\r
+\r
+ currentMouseWindow->ScreenToClient( &wxevent.m_x , &wxevent.m_y ) ;\r
+ wxevent.SetEventObject( currentMouseWindow ) ;\r
+ wxevent.SetId( currentMouseWindow->GetId() ) ;\r
+\r
+ if ( currentMouseWindow->GetEventHandler()->ProcessEvent(wxevent) )\r
+ {\r
+ result = noErr;\r
+ }\r
+\r
+ break; // this should enable WebKit to fire mouse dragged and mouse up events...\r
+ }\r
+ default :\r
+ break ;\r
+ }\r
+ }\r
+ default:\r
+ break;\r
+ }\r
+\r
+ result = CallNextEventHandler(handler, event);\r
+ return result ;\r
+}\r
+\r
+DEFINE_ONE_SHOT_HANDLER_GETTER( wxOSXWebKitCtrlEventHandler )\r
+\r
+#endif\r
+\r
+//---------------------------------------------------------\r
+// helper functions for NSString<->wxString conversion\r
+//---------------------------------------------------------\r
+\r
+inline wxString wxStringWithNSString(NSString *nsstring)\r
+{\r
+#if wxUSE_UNICODE\r
+ return wxString([nsstring UTF8String], wxConvUTF8);\r
+#else\r
+ return wxString([nsstring lossyCString]);\r
+#endif // wxUSE_UNICODE\r
+}\r
+\r
+inline NSString* wxNSStringWithWxString(const wxString &wxstring)\r
+{\r
+#if wxUSE_UNICODE\r
+ return [NSString stringWithUTF8String: wxstring.mb_str(wxConvUTF8)];\r
+#else\r
+ return [NSString stringWithCString: wxstring.c_str() length:wxstring.Len()];\r
+#endif // wxUSE_UNICODE\r
+}\r
+\r
+inline int wxNavTypeFromWebNavType(int type){\r
+ if (type == WebNavigationTypeLinkClicked)\r
+ return wxWEBKIT_NAV_LINK_CLICKED;\r
+\r
+ if (type == WebNavigationTypeFormSubmitted)\r
+ return wxWEBKIT_NAV_FORM_SUBMITTED;\r
+\r
+ if (type == WebNavigationTypeBackForward)\r
+ return wxWEBKIT_NAV_BACK_NEXT;\r
+\r
+ if (type == WebNavigationTypeReload)\r
+ return wxWEBKIT_NAV_RELOAD;\r
+\r
+ if (type == WebNavigationTypeFormResubmitted)\r
+ return wxWEBKIT_NAV_FORM_RESUBMITTED;\r
+\r
+ return wxWEBKIT_NAV_OTHER;\r
+}\r
+\r
+@interface MyFrameLoadMonitor : NSObject\r
+{\r
+ wxOSXWebKitCtrl* webKitWindow;\r
+}\r
+\r
+- initWithWxWindow: (wxOSXWebKitCtrl*)inWindow;\r
+\r
+@end\r
+\r
+@interface MyPolicyDelegate : NSObject\r
+{\r
+ wxOSXWebKitCtrl* webKitWindow;\r
+}\r
+\r
+- initWithWxWindow: (wxOSXWebKitCtrl*)inWindow;\r
+\r
+@end\r
+\r
+// ----------------------------------------------------------------------------\r
+// creation/destruction\r
+// ----------------------------------------------------------------------------\r
+\r
+bool wxOSXWebKitCtrl::Create(wxWindow *parent,\r
+ wxWindowID winID,\r
+ const wxString& strURL,\r
+ const wxPoint& pos,\r
+ const wxSize& size, long style,\r
+ const wxString& name)\r
+{\r
+ m_busy = false;\r
+ //m_pageTitle = _("Untitled Page");\r
+\r
+ //still needed for wxCocoa??\r
+/*\r
+ int width, height;\r
+ wxSize sizeInstance;\r
+ if (size.x == wxDefaultCoord || size.y == wxDefaultCoord)\r
+ {\r
+ m_parent->GetClientSize(&width, &height);\r
+ sizeInstance.x = width;\r
+ sizeInstance.y = height;\r
+ }\r
+ else\r
+ {\r
+ sizeInstance.x = size.x;\r
+ sizeInstance.y = size.y;\r
+ }\r
+*/\r
+ // now create and attach WebKit view...\r
+#ifdef __WXCOCOA__\r
+ wxControl::Create(parent, m_windowID, pos, sizeInstance, style, name);\r
+ SetSize(pos.x, pos.y, sizeInstance.x, sizeInstance.y);\r
+\r
+ wxTopLevelWindowCocoa *topWin = wxDynamicCast(this, wxTopLevelWindowCocoa);\r
+ NSWindow* nsWin = topWin->GetNSWindow();\r
+ NSRect rect;\r
+ rect.origin.x = pos.x;\r
+ rect.origin.y = pos.y;\r
+ rect.size.width = sizeInstance.x;\r
+ rect.size.height = sizeInstance.y;\r
+ m_webView = (WebView*)[[WebView alloc] initWithFrame:rect\r
+ frameName:@"webkitFrame"\r
+ groupName:@"webkitGroup"];\r
+ SetNSView(m_webView);\r
+ [m_cocoaNSView release];\r
+\r
+ if(m_parent) m_parent->CocoaAddChild(this);\r
+ SetInitialFrameRect(pos,sizeInstance);\r
+#else\r
+ m_macIsUserPane = false;\r
+ wxControl::Create(parent, winID, pos, size, style, wxDefaultValidator, name);\r
+\r
+#if wxOSX_USE_CARBON\r
+ m_peer = new wxMacControl(this);\r
+ WebInitForCarbon();\r
+ HIWebViewCreate( m_peer->GetControlRefAddr() );\r
+\r
+ m_webView = (WebView*) HIWebViewGetWebView( m_peer->GetControlRef() );\r
+\r
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3\r
+ if ( UMAGetSystemVersion() >= 0x1030 )\r
+ HIViewChangeFeatures( m_peer->GetControlRef() , kHIViewIsOpaque , 0 ) ;\r
+#endif\r
+ InstallControlEventHandler(m_peer->GetControlRef(),\r
+ GetwxOSXWebKitCtrlEventHandlerUPP(),\r
+ GetEventTypeCount(eventList), eventList, this,\r
+ (EventHandlerRef *)&m_webKitCtrlEventHandler);\r
+#else\r
+ NSRect r = wxOSXGetFrameForControl( this, pos , size ) ;\r
+ m_webView = [[WebView alloc] initWithFrame:r\r
+ frameName:@"webkitFrame"\r
+ groupName:@"webkitGroup"];\r
+ m_peer = new wxWidgetCocoaImpl( this, m_webView );\r
+#endif\r
+\r
+ wx_webviewctrls[m_webView] = this;\r
+\r
+ MacPostControlCreate(pos, size);\r
+\r
+#if wxOSX_USE_CARBON\r
+ HIViewSetVisible( m_peer->GetControlRef(), true );\r
+#endif\r
+ [m_webView setHidden:false];\r
+\r
+#endif\r
+\r
+ // Register event listener interfaces\r
+ MyFrameLoadMonitor* myFrameLoadMonitor =\r
+ [[MyFrameLoadMonitor alloc] initWithWxWindow: this];\r
+\r
+ [m_webView setFrameLoadDelegate:myFrameLoadMonitor];\r
+\r
+ // this is used to veto page loads, etc.\r
+ MyPolicyDelegate* myPolicyDelegate =\r
+ [[MyPolicyDelegate alloc] initWithWxWindow: this];\r
+\r
+ [m_webView setPolicyDelegate:myPolicyDelegate];\r
+\r
+ InternalLoadURL(strURL);\r
+ return true;\r
+}\r
+\r
+wxOSXWebKitCtrl::~wxOSXWebKitCtrl()\r
+{\r
+ MyFrameLoadMonitor* myFrameLoadMonitor = [m_webView frameLoadDelegate];\r
+ MyPolicyDelegate* myPolicyDelegate = [m_webView policyDelegate];\r
+ [m_webView setFrameLoadDelegate: nil];\r
+ [m_webView setPolicyDelegate: nil];\r
+\r
+ if (myFrameLoadMonitor)\r
+ [myFrameLoadMonitor release];\r
+\r
+ if (myPolicyDelegate)\r
+ [myPolicyDelegate release];\r
+}\r
+\r
+// ----------------------------------------------------------------------------\r
+// public methods\r
+// ----------------------------------------------------------------------------\r
+\r
+void wxOSXWebKitCtrl::InternalLoadURL(const wxString &url)\r
+{\r
+ if( !m_webView )\r
+ return;\r
+\r
+ [[m_webView mainFrame] loadRequest:[NSURLRequest requestWithURL:\r
+ [NSURL URLWithString:wxNSStringWithWxString(url)]]];\r
+}\r
+\r
+bool wxOSXWebKitCtrl::CanGoBack()\r
+{\r
+ if ( !m_webView )\r
+ return false;\r
+\r
+ return [m_webView canGoBack];\r
+}\r
+\r
+bool wxOSXWebKitCtrl::CanGoForward()\r
+{\r
+ if ( !m_webView )\r
+ return false;\r
+\r
+ return [m_webView canGoForward];\r
+}\r
+\r
+void wxOSXWebKitCtrl::GoBack()\r
+{\r
+ if ( !m_webView )\r
+ return;\r
+\r
+ bool result = [(WebView*)m_webView goBack];\r
+\r
+ // TODO: return result (if it also exists in other backends...)\r
+ //return result;\r
+}\r
+\r
+void wxOSXWebKitCtrl::GoForward()\r
+{\r
+ if ( !m_webView )\r
+ return;\r
+\r
+ bool result = [(WebView*)m_webView goForward];\r
+\r
+ // TODO: return result (if it also exists in other backends...)\r
+ //return result;\r
+}\r
+\r
+void wxOSXWebKitCtrl::Reload(wxWebViewReloadFlags flags)\r
+{\r
+ if ( !m_webView )\r
+ return;\r
+\r
+ if (flags & wxWEB_VIEW_RELOAD_NO_CACHE)\r
+ {\r
+ // TODO: test this indeed bypasses the cache\r
+ [[m_webView preferences] setUsesPageCache:NO];\r
+ [[m_webView mainFrame] reload];\r
+ [[m_webView preferences] setUsesPageCache:YES];\r
+ }\r
+ else\r
+ {\r
+ [[m_webView mainFrame] reload];\r
+ }\r
+}\r
+\r
+void wxOSXWebKitCtrl::Stop()\r
+{\r
+ if ( !m_webView )\r
+ return;\r
+\r
+ [[m_webView mainFrame] stopLoading];\r
+}\r
+\r
+bool wxOSXWebKitCtrl::CanGetPageSource()\r
+{\r
+ if ( !m_webView )\r
+ return false;\r
+\r
+ WebDataSource* dataSource = [[m_webView mainFrame] dataSource];\r
+ return ( [[dataSource representation] canProvideDocumentSource] );\r
+}\r
+\r
+wxString wxOSXWebKitCtrl::GetPageSource()\r
+{\r
+\r
+ if (CanGetPageSource())\r
+ {\r
+ WebDataSource* dataSource = [[m_webView mainFrame] dataSource];\r
+ wxASSERT (dataSource != nil);\r
+\r
+ id<WebDocumentRepresentation> representation = [dataSource representation];\r
+ wxASSERT (representation != nil);\r
+\r
+ NSString* source = [representation documentSource];\r
+ if (source == nil)\r
+ {\r
+ return wxEmptyString;\r
+ }\r
+\r
+ return wxStringWithNSString( source );\r
+ }\r
+\r
+ return wxEmptyString;\r
+}\r
+\r
+wxString wxOSXWebKitCtrl::GetSelection()\r
+{\r
+ if ( !m_webView )\r
+ return wxEmptyString;\r
+\r
+ NSString* selectedText = [[m_webView selectedDOMRange] toString];\r
+ return wxStringWithNSString( selectedText );\r
+}\r
+\r
+bool wxOSXWebKitCtrl::CanIncreaseTextSize()\r
+{\r
+ if ( !m_webView )\r
+ return false;\r
+\r
+ if ([m_webView canMakeTextLarger])\r
+ return true;\r
+ else\r
+ return false;\r
+}\r
+\r
+void wxOSXWebKitCtrl::IncreaseTextSize()\r
+{\r
+ if ( !m_webView )\r
+ return;\r
+\r
+ if (CanIncreaseTextSize())\r
+ [m_webView makeTextLarger:(WebView*)m_webView];\r
+}\r
+\r
+bool wxOSXWebKitCtrl::CanDecreaseTextSize()\r
+{\r
+ if ( !m_webView )\r
+ return false;\r
+\r
+ if ([m_webView canMakeTextSmaller])\r
+ return true;\r
+ else\r
+ return false;\r
+}\r
+\r
+void wxOSXWebKitCtrl::DecreaseTextSize()\r
+{\r
+ if ( !m_webView )\r
+ return;\r
+\r
+ if (CanDecreaseTextSize())\r
+ [m_webView makeTextSmaller:(WebView*)m_webView];\r
+}\r
+\r
+void wxOSXWebKitCtrl::Print()\r
+{\r
+\r
+ // TODO: allow specifying the "show prompt" parameter in Print() ?\r
+ bool showPrompt = true;\r
+\r
+ if ( !m_webView )\r
+ return;\r
+\r
+ id view = [[[m_webView mainFrame] frameView] documentView];\r
+ NSPrintOperation *op = [NSPrintOperation printOperationWithView:view\r
+ printInfo: [NSPrintInfo sharedPrintInfo]];\r
+ if (showPrompt)\r
+ {\r
+ [op setShowsPrintPanel: showPrompt];\r
+ // in my tests, the progress bar always freezes and it stops the whole\r
+ // print operation. do not turn this to true unless there is a \r
+ // workaround for the bug.\r
+ [op setShowsProgressPanel: false];\r
+ }\r
+ // Print it.\r
+ [op runOperation];\r
+}\r
+\r
+void wxOSXWebKitCtrl::MakeEditable(bool enable)\r
+{\r
+ if ( !m_webView )\r
+ return;\r
+\r
+ [m_webView setEditable:enable ];\r
+}\r
+\r
+bool wxOSXWebKitCtrl::IsEditable()\r
+{\r
+ if ( !m_webView )\r
+ return false;\r
+\r
+ return [m_webView isEditable];\r
+}\r
+\r
+void wxOSXWebKitCtrl::SetZoomType(wxWebViewZoomType zoomType)\r
+{\r
+ // there is only one supported zoom type at the moment so this setter\r
+ // does nothing beyond checking sanity\r
+ wxASSERT(zoomType == wxWEB_VIEW_ZOOM_TYPE_TEXT);\r
+}\r
+\r
+wxWebViewZoomType wxOSXWebKitCtrl::GetZoomType() const\r
+{\r
+ // for now that's the only one that is supported\r
+ // FIXME: does the default zoom type change depending on webkit versions? :S\r
+ // Then this will be wrong\r
+ return wxWEB_VIEW_ZOOM_TYPE_TEXT;\r
+}\r
+\r
+bool wxOSXWebKitCtrl::CanSetZoomType(wxWebViewZoomType type) const\r
+{\r
+ switch (type)\r
+ {\r
+ // for now that's the only one that is supported\r
+ // TODO: I know recent versions of webkit support layout zoom too,\r
+ // check if we can support it\r
+ case wxWEB_VIEW_ZOOM_TYPE_TEXT:\r
+ return true;\r
+\r
+ default:\r
+ return false;\r
+ }\r
+}\r
+\r
+int wxOSXWebKitCtrl::GetScrollPos()\r
+{\r
+ id result = [[m_webView windowScriptObject]\r
+ evaluateWebScript:@"document.body.scrollTop"];\r
+ return [result intValue];\r
+}\r
+\r
+void wxOSXWebKitCtrl::SetScrollPos(int pos)\r
+{\r
+ if ( !m_webView )\r
+ return;\r
+\r
+ wxString javascript;\r
+ javascript.Printf(wxT("document.body.scrollTop = %d;"), pos);\r
+ [[m_webView windowScriptObject] evaluateWebScript:\r
+ (NSString*)wxNSStringWithWxString( javascript )];\r
+}\r
+\r
+wxString wxOSXWebKitCtrl::GetSelectedText()\r
+{\r
+ NSString* selection = [[m_webView selectedDOMRange] markupString];\r
+ if (!selection) return wxEmptyString;\r
+\r
+ return wxStringWithNSString(selection);\r
+}\r
+\r
+wxString wxOSXWebKitCtrl::RunScript(const wxString& javascript)\r
+{\r
+ if ( !m_webView )\r
+ return wxEmptyString;\r
+\r
+ id result = [[m_webView windowScriptObject] evaluateWebScript:\r
+ (NSString*)wxNSStringWithWxString( javascript )];\r
+\r
+ NSString* resultAsString;\r
+ NSString* className = NSStringFromClass([result class]);\r
+\r
+ if ([className isEqualToString:@"NSCFNumber"])\r
+ {\r
+ resultAsString = [NSString stringWithFormat:@"%@", result];\r
+ }\r
+ else if ([className isEqualToString:@"NSCFString"])\r
+ {\r
+ resultAsString = result;\r
+ }\r
+ else if ([className isEqualToString:@"NSCFBoolean"])\r
+ {\r
+ if ([result boolValue])\r
+ resultAsString = @"true";\r
+ else\r
+ resultAsString = @"false";\r
+ }\r
+ else if ([className isEqualToString:@"WebScriptObject"])\r
+ {\r
+ resultAsString = [result stringRepresentation];\r
+ }\r
+ else\r
+ {\r
+ return wxString();\r
+ }\r
+\r
+ return wxStringWithNSString( resultAsString );\r
+}\r
+\r
+void wxOSXWebKitCtrl::OnSize(wxSizeEvent &event)\r
+{\r
+#if defined(__WXMAC_) && wxOSX_USE_CARBON\r
+ // This is a nasty hack because WebKit seems to lose its position when it is\r
+ // embedded in a control that is not itself the content view for a TLW.\r
+ // I put it in OnSize because these calcs are not perfect, and in fact are\r
+ // basically guesses based on reverse engineering, so it's best to give\r
+ // people the option of overriding OnSize with their own calcs if need be.\r
+ // I also left some test debugging print statements as a convenience if\r
+ // a(nother) problem crops up.\r
+\r
+ wxWindow* tlw = MacGetTopLevelWindow();\r
+\r
+ NSRect frame = [(WebView*)m_webView frame];\r
+ NSRect bounds = [(WebView*)m_webView bounds];\r
+\r
+#if DEBUG_WEBKIT_SIZING\r
+ fprintf(stderr,"Carbon window x=%d, y=%d, width=%d, height=%d\n",\r
+ GetPosition().x, GetPosition().y, GetSize().x, GetSize().y);\r
+ fprintf(stderr, "Cocoa window frame x=%G, y=%G, width=%G, height=%G\n",\r
+ frame.origin.x, frame.origin.y,\r
+ frame.size.width, frame.size.height);\r
+ fprintf(stderr, "Cocoa window bounds x=%G, y=%G, width=%G, height=%G\n",\r
+ bounds.origin.x, bounds.origin.y,\r
+ bounds.size.width, bounds.size.height);\r
+#endif\r
+\r
+ // This must be the case that Apple tested with, because well, in this one case\r
+ // we don't need to do anything! It just works. ;)\r
+ if (GetParent() == tlw) return;\r
+\r
+ // since we no longer use parent coordinates, we always want 0,0.\r
+ int x = 0;\r
+ int y = 0;\r
+\r
+ HIRect rect;\r
+ rect.origin.x = x;\r
+ rect.origin.y = y;\r
+\r
+#if DEBUG_WEBKIT_SIZING\r
+ printf("Before conversion, origin is: x = %d, y = %d\n", x, y);\r
+#endif\r
+\r
+ // NB: In most cases, when calling HIViewConvertRect, what people want is to\r
+ // use GetRootControl(), and this tripped me up at first. But in fact, what\r
+ // we want is the root view, because we need to make the y origin relative\r
+ // to the very top of the window, not its contents, since we later flip\r
+ // the y coordinate for Cocoa.\r
+ HIViewConvertRect (&rect, m_peer->GetControlRef(),\r
+ HIViewGetRoot(\r
+ (WindowRef) MacGetTopLevelWindowRef()\r
+ ));\r
+\r
+ x = (int)rect.origin.x;\r
+ y = (int)rect.origin.y;\r
+\r
+#if DEBUG_WEBKIT_SIZING\r
+ printf("Moving Cocoa frame origin to: x = %d, y = %d\n", x, y);\r
+#endif\r
+\r
+ if (tlw){\r
+ //flip the y coordinate to convert to Cocoa coordinates\r
+ y = tlw->GetSize().y - ((GetSize().y) + y);\r
+ }\r
+\r
+#if DEBUG_WEBKIT_SIZING\r
+ printf("y = %d after flipping value\n", y);\r
+#endif\r
+\r
+ frame.origin.x = x;\r
+ frame.origin.y = y;\r
+ [(WebView*)m_webView setFrame:frame];\r
+\r
+ if (IsShown())\r
+ [(WebView*)m_webView display];\r
+ event.Skip();\r
+#endif\r
+}\r
+\r
+void wxOSXWebKitCtrl::MacVisibilityChanged(){\r
+#if defined(__WXMAC__) && wxOSX_USE_CARBON\r
+ bool isHidden = !IsControlVisible( m_peer->GetControlRef());\r
+ if (!isHidden)\r
+ [(WebView*)m_webView display];\r
+\r
+ [m_webView setHidden:isHidden];\r
+#endif\r
+}\r
+\r
+void wxOSXWebKitCtrl::LoadUrl(const wxString& url)\r
+{\r
+ InternalLoadURL(url);\r
+}\r
+\r
+wxString wxOSXWebKitCtrl::GetCurrentURL()\r
+{\r
+ return wxStringWithNSString([m_webView mainFrameURL]);\r
+}\r
+\r
+wxString wxOSXWebKitCtrl::GetCurrentTitle()\r
+{\r
+ return GetPageTitle();\r
+}\r
+\r
+float wxOSXWebKitCtrl::GetWebkitZoom()\r
+{\r
+ return [m_webView textSizeMultiplier];\r
+}\r
+\r
+void wxOSXWebKitCtrl::SetWebkitZoom(float zoom)\r
+{\r
+ [m_webView setTextSizeMultiplier:zoom];\r
+}\r
+\r
+wxWebViewZoom wxOSXWebKitCtrl::GetZoom()\r
+{\r
+ float zoom = GetWebkitZoom();\r
+\r
+ // arbitrary way to map float zoom to our common zoom enum\r
+ if (zoom <= 0.55)\r
+ {\r
+ return wxWEB_VIEW_ZOOM_TINY;\r
+ }\r
+ else if (zoom > 0.55 && zoom <= 0.85)\r
+ {\r
+ return wxWEB_VIEW_ZOOM_SMALL;\r
+ }\r
+ else if (zoom > 0.85 && zoom <= 1.15)\r
+ {\r
+ return wxWEB_VIEW_ZOOM_MEDIUM;\r
+ }\r
+ else if (zoom > 1.15 && zoom <= 1.45)\r
+ {\r
+ return wxWEB_VIEW_ZOOM_LARGE;\r
+ }\r
+ else if (zoom > 1.45)\r
+ {\r
+ return wxWEB_VIEW_ZOOM_LARGEST;\r
+ }\r
+\r
+ // to shut up compilers, this can never be reached logically\r
+ wxASSERT(false);\r
+ return wxWEB_VIEW_ZOOM_MEDIUM;\r
+}\r
+\r
+void wxOSXWebKitCtrl::SetZoom(wxWebViewZoom zoom)\r
+{\r
+ // arbitrary way to map our common zoom enum to float zoom\r
+ switch (zoom)\r
+ {\r
+ case wxWEB_VIEW_ZOOM_TINY:\r
+ SetWebkitZoom(0.4f);\r
+ break;\r
+\r
+ case wxWEB_VIEW_ZOOM_SMALL:\r
+ SetWebkitZoom(0.7f);\r
+ break;\r
+\r
+ case wxWEB_VIEW_ZOOM_MEDIUM:\r
+ SetWebkitZoom(1.0f);\r
+ break;\r
+\r
+ case wxWEB_VIEW_ZOOM_LARGE:\r
+ SetWebkitZoom(1.3);\r
+ break;\r
+\r
+ case wxWEB_VIEW_ZOOM_LARGEST:\r
+ SetWebkitZoom(1.6);\r
+ break;\r
+\r
+ default:\r
+ wxASSERT(false);\r
+ }\r
+\r
+}\r
+\r
+void wxOSXWebKitCtrl::SetPage(const wxString& src, const wxString& baseUrl)\r
+{\r
+ if ( !m_webView )\r
+ return;\r
+\r
+ [[m_webView mainFrame] loadHTMLString:(NSString*)wxNSStringWithWxString(src)\r
+ baseURL:[NSURL URLWithString:\r
+ wxNSStringWithWxString( baseUrl )]];\r
+}\r
+\r
+//------------------------------------------------------------\r
+// Listener interfaces\r
+//------------------------------------------------------------\r
+\r
+// NB: I'm still tracking this down, but it appears the Cocoa window\r
+// still has these events fired on it while the Carbon control is being\r
+// destroyed. Therefore, we must be careful to check both the existence\r
+// of the Carbon control and the event handler before firing events.\r
+\r
+@implementation MyFrameLoadMonitor\r
+\r
+- initWithWxWindow: (wxOSXWebKitCtrl*)inWindow\r
+{\r
+ [super init];\r
+ webKitWindow = inWindow; // non retained\r
+ return self;\r
+}\r
+\r
+- (void)webView:(WebView *)sender\r
+ didStartProvisionalLoadForFrame:(WebFrame *)frame\r
+{\r
+ wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end());\r
+ wx_webviewctrls[sender]->m_busy = true;\r
+}\r
+\r
+- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame\r
+{\r
+ wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end());\r
+ wx_webviewctrls[sender]->m_busy = true;\r
+\r
+ if (webKitWindow && frame == [sender mainFrame]){\r
+ NSString *url = [[[[frame dataSource] request] URL] absoluteString];\r
+ wxString target = wxStringWithNSString([frame name]);\r
+ wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,\r
+ wx_webviewctrls[sender]->GetId(),\r
+ wxStringWithNSString( url ),\r
+ target, false);\r
+\r
+ if (webKitWindow && webKitWindow->GetEventHandler())\r
+ webKitWindow->GetEventHandler()->ProcessEvent(thisEvent);\r
+ }\r
+}\r
+\r
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame\r
+{\r
+ wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end());\r
+ wx_webviewctrls[sender]->m_busy = false;\r
+\r
+ if (webKitWindow && frame == [sender mainFrame]){\r
+ NSString *url = [[[[frame dataSource] request] URL] absoluteString];\r
+\r
+ wxString target = wxStringWithNSString([frame name]);\r
+ wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_LOADED,\r
+ wx_webviewctrls[sender]->GetId(),\r
+ wxStringWithNSString( url ),\r
+ target, false);\r
+\r
+ if (webKitWindow && webKitWindow->GetEventHandler())\r
+ webKitWindow->GetEventHandler()->ProcessEvent(thisEvent);\r
+ }\r
+}\r
+\r
+wxString nsErrorToWxHtmlError(NSError* error, wxWebNavigationError* out)\r
+{\r
+ *out = wxWEB_NAV_ERR_OTHER;\r
+\r
+ if ([[error domain] isEqualToString:NSURLErrorDomain])\r
+ {\r
+ switch ([error code])\r
+ {\r
+ case NSURLErrorCannotFindHost:\r
+ case NSURLErrorFileDoesNotExist:\r
+ case NSURLErrorRedirectToNonExistentLocation:\r
+ *out = wxWEB_NAV_ERR_NOT_FOUND;\r
+ break;\r
+\r
+ case NSURLErrorResourceUnavailable:\r
+ case NSURLErrorHTTPTooManyRedirects:\r
+ case NSURLErrorDataLengthExceedsMaximum:\r
+ case NSURLErrorBadURL:\r
+ case NSURLErrorFileIsDirectory:\r
+ *out = wxWEB_NAV_ERR_REQUEST;\r
+ break;\r
+\r
+ case NSURLErrorTimedOut:\r
+ case NSURLErrorDNSLookupFailed:\r
+ case NSURLErrorNetworkConnectionLost:\r
+ case NSURLErrorCannotConnectToHost:\r
+ case NSURLErrorNotConnectedToInternet:\r
+ //case NSURLErrorInternationalRoamingOff:\r
+ //case NSURLErrorCallIsActive:\r
+ //case NSURLErrorDataNotAllowed:\r
+ *out = wxWEB_NAV_ERR_CONNECTION;\r
+ break;\r
+\r
+ case NSURLErrorCancelled:\r
+ case NSURLErrorUserCancelledAuthentication:\r
+ *out = wxWEB_NAV_ERR_USER_CANCELLED;\r
+ break;\r
+\r
+ case NSURLErrorCannotDecodeRawData:\r
+ case NSURLErrorCannotDecodeContentData:\r
+ case NSURLErrorBadServerResponse:\r
+ case NSURLErrorCannotParseResponse:\r
+ *out = wxWEB_NAV_ERR_REQUEST;\r
+ break;\r
+\r
+ case NSURLErrorUserAuthenticationRequired:\r
+ case NSURLErrorSecureConnectionFailed:\r
+ case NSURLErrorClientCertificateRequired:\r
+ *out = wxWEB_NAV_ERR_AUTH;\r
+ break;\r
+\r
+ case NSURLErrorNoPermissionsToReadFile:\r
+ *out = wxWEB_NAV_ERR_SECURITY;\r
+ break;\r
+\r
+ case NSURLErrorServerCertificateHasBadDate:\r
+ case NSURLErrorServerCertificateUntrusted:\r
+ case NSURLErrorServerCertificateHasUnknownRoot:\r
+ case NSURLErrorServerCertificateNotYetValid:\r
+ case NSURLErrorClientCertificateRejected:\r
+ *out = wxWEB_NAV_ERR_CERTIFICATE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ wxString message = wxStringWithNSString([error localizedDescription]);\r
+ NSString* detail = [error localizedFailureReason];\r
+ if (detail != NULL)\r
+ {\r
+ message = message + " (" + wxStringWithNSString(detail) + ")";\r
+ }\r
+ return message;\r
+}\r
+\r
+- (void)webView:(WebView *)sender didFailLoadWithError:(NSError*) error\r
+ forFrame:(WebFrame *)frame\r
+{\r
+ wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end());\r
+ wx_webviewctrls[sender]->m_busy = false;\r
+\r
+ if (webKitWindow && frame == [sender mainFrame]){\r
+ NSString *url = [[[[frame dataSource] request] URL] absoluteString];\r
+\r
+ wxWebNavigationError type;\r
+ wxString description = nsErrorToWxHtmlError(error, &type);\r
+ wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_ERROR,\r
+ wx_webviewctrls[sender]->GetId(),\r
+ wxStringWithNSString( url ),\r
+ wxEmptyString, false);\r
+ thisEvent.SetString(description);\r
+ thisEvent.SetInt(type);\r
+\r
+ if (webKitWindow && webKitWindow->GetEventHandler())\r
+ {\r
+ webKitWindow->GetEventHandler()->ProcessEvent(thisEvent);\r
+ }\r
+ }\r
+}\r
+\r
+- (void)webView:(WebView *)sender\r
+ didFailProvisionalLoadWithError:(NSError*)error\r
+ forFrame:(WebFrame *)frame\r
+{\r
+ wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end());\r
+ wx_webviewctrls[sender]->m_busy = false;\r
+\r
+ if (webKitWindow && frame == [sender mainFrame]){\r
+ NSString *url = [[[[frame provisionalDataSource] request] URL]\r
+ absoluteString];\r
+\r
+ wxWebNavigationError type;\r
+ wxString description = nsErrorToWxHtmlError(error, &type);\r
+ wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_ERROR,\r
+ wx_webviewctrls[sender]->GetId(),\r
+ wxStringWithNSString( url ),\r
+ wxEmptyString, false);\r
+ thisEvent.SetString(description);\r
+ thisEvent.SetInt(type);\r
+\r
+ if (webKitWindow && webKitWindow->GetEventHandler())\r
+ webKitWindow->GetEventHandler()->ProcessEvent(thisEvent);\r
+ }\r
+}\r
+\r
+- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title\r
+ forFrame:(WebFrame *)frame\r
+{\r
+ if (webKitWindow && frame == [sender mainFrame])\r
+ {\r
+ webKitWindow->SetPageTitle(wxStringWithNSString( title ));\r
+ }\r
+}\r
+@end\r
+\r
+@implementation MyPolicyDelegate\r
+\r
+- initWithWxWindow: (wxOSXWebKitCtrl*)inWindow\r
+{\r
+ [super init];\r
+ webKitWindow = inWindow; // non retained\r
+ return self;\r
+}\r
+\r
+- (void)webView:(WebView *)sender\r
+ decidePolicyForNavigationAction:(NSDictionary *)actionInformation\r
+ request:(NSURLRequest *)request\r
+ frame:(WebFrame *)frame\r
+ decisionListener:(id<WebPolicyDecisionListener>)listener\r
+{\r
+ //wxUnusedVar(sender);\r
+ wxUnusedVar(frame);\r
+\r
+ wxASSERT(wx_webviewctrls.find(sender) != wx_webviewctrls.end());\r
+ wx_webviewctrls[sender]->m_busy = true;\r
+ NSString *url = [[request URL] absoluteString];\r
+ wxString target = wxStringWithNSString([frame name]);\r
+ wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATING,\r
+ wx_webviewctrls[sender]->GetId(),\r
+ wxStringWithNSString( url ), target, true);\r
+\r
+ if (webKitWindow && webKitWindow->GetEventHandler())\r
+ webKitWindow->GetEventHandler()->ProcessEvent(thisEvent);\r
+\r
+ if (thisEvent.IsVetoed())\r
+ {\r
+ wx_webviewctrls[sender]->m_busy = false;\r
+ [listener ignore];\r
+ }\r
+ else\r
+ {\r
+ [listener use];\r
+ }\r
+}\r
+\r
+- (void)webView:(WebView *)sender \r
+ decidePolicyForNewWindowAction:(NSDictionary *)actionInformation\r
+ request:(NSURLRequest *)request\r
+ newFrameName:(NSString *)frameName\r
+ decisionListener:(id < WebPolicyDecisionListener >)listener\r
+{\r
+ wxUnusedVar(sender);\r
+ wxUnusedVar(actionInformation);\r
+\r
+ [listener ignore];\r
+}\r
+@end\r
+\r
+#endif //wxHAVE_WEB_BACKEND_OSX_WEBKIT\r