| @@ -149,6 +149,7 @@ namespace juce | |||
| #if JUCE_WEB_BROWSER | |||
| bool WebBrowserComponent::pageAboutToLoad (const String&) { return true; } | |||
| void WebBrowserComponent::pageFinishedLoading (const String&) {} | |||
| bool WebBrowserComponent::pageLoadHadNetworkError (const String&) { return true; } | |||
| void WebBrowserComponent::windowCloseRequest() {} | |||
| void WebBrowserComponent::newWindowAttemptingToLoad (const String&) {} | |||
| #endif | |||
| @@ -95,6 +95,18 @@ public: | |||
| /** This callback happens when the browser has finished loading a page. */ | |||
| virtual void pageFinishedLoading (const String& url); | |||
| /** This callback happens when a network error was encountered while | |||
| trying to load a page. | |||
| You can override this method to show some other error page by calling | |||
| goToURL. Return true to allow the browser to carry on to the internal | |||
| browser error page. | |||
| The errorInfo contains some platform dependent string describing the | |||
| error. | |||
| */ | |||
| virtual bool pageLoadHadNetworkError (const String& errorInfo); | |||
| /** This callback occurs when a script or other activity in the browser asks for | |||
| the window to be closed. | |||
| */ | |||
| @@ -180,6 +180,9 @@ public: | |||
| g_signal_connect (webview, "load-changed", | |||
| G_CALLBACK (loadChangedCallback), this); | |||
| g_signal_connect (webview, "load-failed", | |||
| G_CALLBACK (loadFailedCallback), this); | |||
| gtk_widget_show_all (plug); | |||
| unsigned long wID = (unsigned long) gtk_plug_get_id (GTK_PLUG (plug)); | |||
| @@ -350,6 +353,14 @@ public: | |||
| return false; | |||
| } | |||
| void onLoadFailed (GError* error) | |||
| { | |||
| DynamicObject::Ptr params = new DynamicObject; | |||
| params->setProperty ("error", String (error != nullptr ? error->message : "unknown error")); | |||
| CommandReceiver::sendCommand (outChannel, "pageLoadHadNetworkError", var (params)); | |||
| } | |||
| private: | |||
| static gboolean pipeReadyStatic (gint fd, GIOCondition condition, gpointer user) | |||
| { | |||
| @@ -373,6 +384,16 @@ private: | |||
| owner.onLoadChanged (loadEvent); | |||
| } | |||
| static void loadFailedCallback (WebKitWebView*, | |||
| WebKitLoadEvent /*loadEvent*/, | |||
| gchar* /*failing_uri*/, | |||
| GError* error, | |||
| gpointer user) | |||
| { | |||
| GtkChildProcess& owner = *reinterpret_cast<GtkChildProcess*> (user); | |||
| owner.onLoadFailed (error); | |||
| } | |||
| int outChannel; | |||
| CommandReceiver receiver; | |||
| WebKitWebView* webview = nullptr; | |||
| @@ -566,6 +587,7 @@ private: | |||
| else if (cmd == "pageFinishedLoading") owner.pageFinishedLoading (url); | |||
| else if (cmd == "windowCloseRequest") owner.windowCloseRequest(); | |||
| else if (cmd == "newWindowAttemptingToLoad") owner.newWindowAttemptingToLoad (url); | |||
| else if (cmd == "pageLoadHadNetworkError") handlePageLoadHadNetworkError (params); | |||
| threadBlocker.signal(); | |||
| } | |||
| @@ -585,6 +607,14 @@ private: | |||
| } | |||
| } | |||
| void handlePageLoadHadNetworkError (const var& params) | |||
| { | |||
| String error = params.getProperty ("error", "Unknown error"); | |||
| if (owner.pageLoadHadNetworkError (error)) | |||
| goToURL (String ("data:text/plain,") + error, nullptr, nullptr); | |||
| } | |||
| void handleCommand (const String& cmd, const var& params) override | |||
| { | |||
| threadBlocker.reset(); | |||
| @@ -35,6 +35,8 @@ struct DownloadClickDetectorClass : public ObjCClass<NSObject> | |||
| addMethod (@selector (webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:), | |||
| decidePolicyForNewWindowAction, "v@:@@@@@"); | |||
| addMethod (@selector (webView:didFinishLoadForFrame:), didFinishLoadForFrame, "v@:@@"); | |||
| addMethod (@selector (webView:didFailLoadWithError:forFrame:), didFailLoadWithError, "v@:@@@"); | |||
| addMethod (@selector (webView:didFailProvisionalLoadWithError:forFrame:), didFailLoadWithError, "v@:@@@"); | |||
| addMethod (@selector (webView:willCloseFrame:), willCloseFrame, "v@:@@"); | |||
| addMethod (@selector (webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), runOpenPanel, "v@:@@", @encode (BOOL)); | |||
| @@ -78,6 +80,20 @@ private: | |||
| } | |||
| } | |||
| static void didFailLoadWithError (id self, SEL, WebView* sender, NSError* error, WebFrame* frame) | |||
| { | |||
| if ([frame isEqual: [sender mainFrame]]) | |||
| { | |||
| const char* errorString = [[error localizedDescription] UTF8String]; | |||
| bool proceedToErrorPage = getOwner (self)->pageLoadHadNetworkError (errorString); | |||
| // WebKit doesn't have an internal error page, so make a really simple one ourselves | |||
| if (proceedToErrorPage) | |||
| getOwner(self)->goToURL (String ("data:text/plain,") + errorString); | |||
| } | |||
| } | |||
| static void willCloseFrame (id self, SEL, WebView*, WebFrame*) | |||
| { | |||
| getOwner (self)->windowCloseRequest(); | |||
| @@ -173,6 +173,29 @@ private: | |||
| return S_OK; | |||
| } | |||
| if (dispIdMember == DISPID_NAVIGATEERROR) | |||
| { | |||
| int statusCode = pDispParams->rgvarg[1].pvarVal->intVal; | |||
| *pDispParams->rgvarg[0].pboolVal = VARIANT_FALSE; | |||
| // IWebBrowser2 also reports http status codes here, we need | |||
| // report only network erros | |||
| if (statusCode < 0) | |||
| { | |||
| LPTSTR messageBuffer = nullptr; | |||
| size_t size = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | |||
| NULL, statusCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &messageBuffer, 0, NULL); | |||
| String message(messageBuffer, size); | |||
| LocalFree(messageBuffer); | |||
| if (!owner.pageLoadHadNetworkError(message)) | |||
| *pDispParams->rgvarg[0].pboolVal = VARIANT_TRUE; | |||
| } | |||
| return S_OK; | |||
| } | |||
| if (dispIdMember == 263 /*DISPID_WINDOWCLOSING*/) | |||
| { | |||
| owner.windowCloseRequest(); | |||